最近正在使用Wox,这个软件还挺高效的,而且还能自己编写一些插件,这里打算自己写点插件用用.
Wox官网
Plugin (wox.one)插件,此外官方也提供了编写文档,编写插件 · GitBook (wox.one)提供Python和C#两种优秀的语言编写方案。我这里就使用Python写了.
首先需要做的是创建新的虚拟环境作隔离,一般使用python自带的venv
或者virtualenv
,当然也有比较新的pipenv
和被认为比较重的Anaconda
,后两者也是包管理器,功能比较多。
以下是创建虚拟环境的代码示例:
使用 virtualenv:1
2
3
4
5
6
7
8
9
10
11
12
13
14# 安装 virtualenv
pip install virtualenv
# 创建名为 myenv 的虚拟环境
virtualenv myenv
# 激活虚拟环境(Windows 平台)
myenv\Scripts\activate.bat
# 激活虚拟环境(Linux 和 Mac 平台)
source myenv/bin/activate
# 退出虚拟环境
deactivate
使用 venv:1
2
3
4
5
6
7
8# 创建名为 myenv 的虚拟环境
python3 -m venv myenv
# 激活虚拟环境
source myenv/bin/activate
# 退出虚拟环境
deactivate
这一步还是很重要的,环境不能乱。
项目结构
可以看看官方案例以及其他插件的目录结构
在创建Wox的时候,用户必须在插件的根目录方式一个名为plugin.json
的文件。该文件中包含了该插件的一些基本信息。
plugin.json
的格式如下: 请在粘贴下面代码的时候移除其中的注释
重点是触发词ActionKeyword
以及IcoPath
插件图标,ID
需要一个32位不与其他插件重复的随机数,自己生成即可。1
2
3
4
5
6
7
8
9
10
11
12{
"ID":"D2D2C23B084D411DB66FE0C79D6C2A6H", //插件ID,32位的UUID
"ActionKeyword":"wpm", //插件默认的触发关键字
"Name":"WPM", //插件名字
"Description":"Wox Package Management", //插件介绍
"Author":"qianlifeng", //作者
"Version":"1.0.0", //插件版本,必须是x.x.x的格式
"Language":"csharp", //插件语言,目前支持csharp,python
"Website":"http://www.getwox.com", //插件网站或者个人网站
"IcoPath": "Images\\pic.png", //插件图标,路径是相对插件根目录的路径
"ExecuteFileName":"PluginManagement.dll" //执行文件入口,如果是C#插件则填写DLL路径,如果是pyhton则填写python文件路径
}
然后就是主文件以及插件图标文件
Python开发
Wox自带了一个打包的Python及其标准库,所以使用Python插件的用户不必自己再安装Python环境。同时,Wox还打包了requests和beautifulsoup4两个库, 方便用户进行网络访问与解析。
基础
使用Python开发需要有一个类继承Wox,注意这个东西并不需要pip下载,是Wox自带的运行时,包括requests和BeautifulSoup4,而其他的第三方包需要自己下载.下载Wox时有一个full-installer包含python解释器,自己可以设置Python解释器文件夹路径为环境变量,一般下载Python时选择加入环境变量即可。
继承Wox类后关键要继承的方法是query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51import requests
from bs4 import BeautifulSoup
import webbrowser
from wox import Wox,WoxAPI
#用户写的Python类必须继承Wox类 https://github.com/qianlifeng/Wox/blob/master/PythonHome/wox.py
#这里的Wox基类做了一些工作,简化了与Wox通信的步骤。
class Main(Wox):
def request(self,url):
#如果用户配置了代理,那么可以在这里设置。这里的self.proxy来自Wox封装好的对象
if self.proxy and self.proxy.get("enabled") and self.proxy.get("server"):
proxies = {
"http":"http://{}:{}".format(self.proxy.get("server"),self.proxy.get("port")),
"https":"http://{}:{}".format(self.proxy.get("server"),self.proxy.get("port"))}
return requests.get(url,proxies = proxies)
else:
return requests.get(url)
#必须有一个query方法,用户执行查询的时候会自动调用query方法
def query(self,key):
r = self.request('https://news.ycombinator.com/')
bs = BeautifulSoup(r.text)
results = []
for i in bs.select(".comhead"):
title = i.previous_sibling.text
url = i.previous_sibling["href"]
results.append({
"Title": title ,
"SubTitle":title,
"IcoPath":"Images/app.ico",
"JsonRPCAction":{
#这里除了自已定义的方法,还可以调用Wox的API。调用格式如下:Wox.xxxx方法名
#方法名字可以从这里查阅https://github.com/qianlifeng/Wox/blob/master/Wox.Plugin/IPublicAPI.cs 直接同名方法即可
"method": "openUrl",
#参数必须以数组的形式传过去
"parameters":[url],
#是否隐藏窗口
"dontHideAfterAction":True
}
})
return results
def openUrl(self,url):
webbrowser.open(url)
WoxAPI.change_query(url)
#以下代码是必须的
if __name__ == "__main__":
Main()
上面这个例子就很典型,每次在Wox中输入就会调用query方法,其需要返回一个列表,列表中每一项内容如下1
2
3
4
5
6
7
8
9
10{
"Title": title ,
"SubTitle":title,
"IcoPath":"Images/app.ico",
"JsonRPCAction":{
"method": "openUrl",
"parameters":[url],
"dontHideAfterAction":True
}
}
其中,拿一个翻译插件来说,Title就是要点,SubTitle就是翻译结果,icoPath是左边图标的路径,我测试了必须使用本地文件,而JsonRPCAction就是按Enter键或鼠标左击后的响应,method就是触发的方法,可以自己写,也可以用wox.pyWox/wox.py at master · Wox-launcher/Wox · GitHub中的WoxAPI方法,parameters就是参数,要求传入一个列表.dontHideAfterAction
表示点击之后Wox会不会隐藏.
此外还有个有意思的方法就是context_menu
1
2
3
4
5def context_menu(self, data):
"""
optional context menu entries for a result
"""
return []
就是鼠标右击或者Shift+Enter后的响应,需要注意的是,重载的必须是context_menu(self, data)
,不能确少data参数,这个data可以在query方法中返回的结果里设置ContextData
如下
比如我在Context menu里添加一项去我的博客看看
,下面两项是默认的.
所以query
和context_menu
返回的结果就是展示的结果项目。
错误处理
日志
像对于这种插件的开发个人认为是比较累的,debug比较麻烦,不能在终端直接显示,不像一般的客户端或者Web开发,所以日志还是很重要的,主要使用Python自带的logging模块.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 日志记录
class Logger:
def __init__(self):
filename = os.path.join(os.path.dirname(__file__), 'log.txt')
logging.basicConfig(level=logging.DEBUG, filename=filename, filemode='a',
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
self.logger = logging.getLogger()
def debug(self, msg):
self.logger.debug(msg)
def info(self, msg):
self.logger.info(msg)
def error(self, msg):
self.logger.error(msg)
使用时初始化Logger,再掉用实例方法输出信息到文件.
显示项目
Wox插件机制叫做JSON-RPC 2.0 Specification (jsonrpc.org),利用这种方法将要展示的信息发给Wox并显示出来.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18def query(self, key):
self.results = []
logger = Logger()
logger.info("-------------info--------------")
args = key.split()
length = len(args)
if length == 0:
self.results.append(
self.add_item("有道智云翻译(正在开发中)", "需要配置key", 'Images/zhiyun.png', "configyoudao", "zy"))
self.results.append(
self.add_item("使用有道翻译免费版本", "暂只支持中英互译", 'Images/youdao.png', "freetrans", "yd"))
self.results.append(self.add_item("使用百度翻译", "需要配置key", 'Images/bd.png', "configbaidu", "bd"))
self.results.append(self.add_item("重载插件", "重新加载插件", 'Images/pic.jpg', "reload"))
return self.results
return self.results
这是我写的部分代码,可以看到返回了一个列表,展示出来就是下面样子的
可以通过显示项目的方法debug.
响应方法
1 | def openUrl(self, url): |
在返回的项目中,JsonRPCAction
的method就填方法名,可以写在一个类中,可以使用WoxAPI改变query也就是搜索的字符串,此外还有其他方法,注意,我测试的发现show_msg已经无法正常使用了
JsonRPCAction
的parameters传入的列表就对应method中的参数,比如传[1,2],而method中就可以使用method(a,b)来接收,当然也可以使用method(*para)用一个元组接收.
更新到Wox扩展
目前代码已经传到Github上,Wox本身有一个扩展库.
B站直播信息查看
由于平时会看看直播,找到了一个关于B站接口的项目GitHub - SocialSisterYi/bilibili-API-collect: 哔哩哔哩-API收集整理【不断更新中….】
利用其中的一些接口使用Wox快速看看某个直播是不是在直播.
目前打算的方法是让用户填写配置信息,让用户填好Cookie后,直接调用请求查看关注的正在直播的用户.
用户在web上登陆后,在配置文件中config.json
中写SESSDATA
然后调用接口即可.
主要注意两点,一个是在JSONRPC里不要轻易调用原本类里东西.比如我写了个Logger
类,并在Main
类里实例化了这个类,并增加了searchall
方法,通过JsonRPCAction
调用.1
2
3
4
5
6
7
8
9
10
11
12def add_item(self, title, subtitle, icopath, method, *parameters):
item = {
"Title": title,
"SubTitle": subtitle,
"IcoPath": icopath,
"JsonRPCAction": {
"method": method,
"parameters": parameters,
"dontHideAfterAction": True,
},
}
return item
在这里的searchall
方法里是不能使用logger
输出日志的.1
2
3
4
5
6
7self.results.append(
self.add_item("BiliLive", "查看自己关注的正在直播的主播", 'Images/pic.png',"searchall","all")
self.results.append(
self.add_item("Config Cookie", "配置你的Cookie", 'Images/cookie.png', "openviewer"))
self.results.append(
self.add_item("reload", "刷新重载插件", 'Images/pic.png', "reload"))
return self.results
总结
- Python编写插件相关资料比较少,C#要多一点
- 可以参考这个文件的代码,还是不错的Wox/Plugins/HelloWorldPython at master · Wox-launcher/Wox · GitHub
- 可以看看我的翻译插件,支持免费中英互译,也支持百度的有一定免费额度的API翻译,支持多种语言
- 如果向上传给别人用,需要压缩整个文件夹然后改后缀名为woxHow to create
.wox
· Issue #2199 · Wox-launcher/Wox (github.com) - 最后我在Wox的plugin上上传了这两个插件,欢迎star以及下载使用!