使用Python编写Wox插件

最近正再使用Wox,这个软件还挺高效的,而且还能自己编写一些插件,这里打算自己写点插件用用.

Wox官网

Plugin (wox.one)插件,此外官方也提供了编写文档,编写插件 · GitBook (wox.one)提供Python和C#两种优秀的语言编写方案。我这里就使用Python写了.

首先需要做的是创建新的虚拟环境作隔离,一般使用python自带的venv或者virtualenv,当然也有比较新的pipenv和被认为比较重的Anaconda,后两者也是包管理器,功能比较多。

以下是创建虚拟环境的代码示例:

使用 virtualenv:

# 安装 virtualenv
pip install virtualenv

# 创建名为 myenv 的虚拟环境
virtualenv myenv

# 激活虚拟环境(Windows 平台)
myenv\Scripts\activate.bat

# 激活虚拟环境(Linux 和 Mac 平台)
source myenv/bin/activate

# 退出虚拟环境
deactivate

使用 venv:

# 创建名为 myenv 的虚拟环境
python3 -m venv myenv

# 激活虚拟环境
source myenv/bin/activate

# 退出虚拟环境
deactivate

这一步还是很重要的,环境不能乱。

项目结构

可以看看官方案例以及其他插件的目录结构

image-20230520114456394

在创建Wox的时候,用户必须在插件的根目录方式一个名为plugin.json的文件。该文件中包含了该插件的一些基本信息。

plugin.json的格式如下: 请在粘贴下面代码的时候移除其中的注释

重点是触发词ActionKeyword以及IcoPath插件图标,ID需要一个32位不与其他插件重复的随机数,自己生成即可。

{
  "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

import 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方法,其需要返回一个列表,列表中每一项内容如下

{
        "Title": title ,
        "SubTitle":title,
        "IcoPath":"Images/app.ico",
        "JsonRPCAction":{
          "method": "openUrl",  
          "parameters":[url],
          "dontHideAfterAction":True
        }
      }
image-20230521171823745

其中,拿一个翻译插件来说,Title就是要点,SubTitle就是翻译结果,icoPath是左边图标的路径,我测试了必须使用本地文件,而JsonRPCAction就是按Enter键或鼠标左击后的响应,method就是触发的方法,可以自己写,也可以用wox.pyWox/wox.py at master · Wox-launcher/Wox · GitHub中的WoxAPI方法,parameters就是参数,要求传入一个列表.dontHideAfterAction表示点击之后Wox会不会隐藏.

此外还有个有意思的方法就是context_menu

def context_menu(self, data):
    """
    optional context menu entries for a result
    """
    return []

就是鼠标右击或者Shift+Enter后的响应。

所以querycontext_menu返回的结果就是展示的结果项目。

错误处理

日志

像对于这种插件的开发个人认为是比较累的,debug比较麻烦,不能在终端直接显示,不像一般的客户端或者Web开发,所以日志还是很重要的,主要使用Python自带的logging模块.

# 日志记录
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并显示出来.

def 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

这是我写的部分代码,可以看到返回了一个列表,展示出来就是下面样子的

image-20230521172551777

可以通过显示项目的方法debug.

响应方法

def openUrl(self, url):
    webbrowser.open(url)
    WoxAPI.change_query(url, False)

在返回的项目中,JsonRPCAction的method就填方法名,可以写在一个类中,可以使用WoxAPI改变query也就是搜索的字符串,此外还有其他方法,注意,我测试的发现show_msg已经无法正常使用了

<img src="https://upload-images.jianshu.io/upload_images/28541803-6efbf468912bccf2.png" alt="image-20230521173212739" style="zoom:50%;" />

JsonRPCAction的parameters传入的列表就对应method中的参数,比如传[1,2],而method中就可以使用method(a,b)来接收,当然也可以使用method(*para)用一个元组接收.

image-20230521174809680

总结

  1. Python编写插件相关资料比较少,C#要多一点
  2. 可以参考这个文件的代码,还是不错的Wox/Plugins/HelloWorldPython at master · Wox-launcher/Wox · GitHub
  3. 可以看看我的翻译插件,支持免费中英互译,也支持百度的有一定免费额度的API翻译,支持多种语言


    image-20230521173938835

    image-20230521174103179

参考文献

  1. [要不我们还是用回 virtualenv/venv 和 pip 吧 ](https://zhuanlan.zhihu.com/p/81568689#:~:text=virtualenv :Python 虚拟环境管理工具。 venv :Python 标准库内置的虚拟环境管理工具,Python 3.3 加入,Python,开始作为管理虚拟环境的推荐工具,用法类似 virtualenv。 如果你使用 Python 3,推荐使用 venv 来替代 virtualenv。)
  2. Wox/wox.py at master · Wox-launcher/Wox · GitHub

本文由mdnice多平台发布

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容