Skip to content

Latest commit

 

History

History
295 lines (216 loc) · 9.15 KB

File metadata and controls

295 lines (216 loc) · 9.15 KB

ulanzistudio-plugin-sdk-python

English | 简体中文

简介

ulanzistudio-plugin-sdk-python 是 UlanziStudio 插件 SDK 的 Python 版本。它封装了与 UlanziStudio 上位机之间的 WebSocket 连接和事件协议,让 Python 主服务可以用简单的事件回调接收上位机消息,并发送图标、参数、Settings、弹窗等命令。

本 SDK 的事件与方法面参考 UlanziTechnology/plugin-common-node,协议版本对应 Ulanzi JS 插件开发协议 - V3.1.0

manifest.json 配置参考:manifest.zh.md

文件目录

src/ulanzi_api/
├── constants.py     # 事件名常量
├── random_port.py   # 为自建主服务生成随机端口并写入 ws-port.js
├── utils.py         # 插件路径、系统类型、JSON 解析等工具方法
├── ulanzi_api.py    # SDK 主类,封装 WebSocket 与事件收发
└── __init__.py      # 导出 UlanziApi、Utils、RandomPort、Events

安装

pip install websocket-client

如果直接把本仓库放到插件运行环境中使用:

pip install .

导入方式:

from ulanzi_api import UlanziApi, Utils, RandomPort

说明与约定

  1. Python 主服务,例如 app.py,应始终与 UlanziStudio 保持连接,负责插件核心逻辑、接收 action 参数变更并更新图标状态。
  2. Action / 配置项 HTML 页面应保持轻量,只负责配置 UI 和参数交换。
  3. 插件包命名规则:com.ulanzi.{插件名}.ulanziPlugin
  4. 主服务 UUID 必须恰好包含 4 个点分隔片段:com.ulanzi.ulanzistudio.{插件名}
  5. Action UUID 必须超过 4 个片段:com.ulanzi.ulanzistudio.{插件名}.{actionName}
  6. 当配置项页面需要绕过 UlanziStudio,直接连接插件自己的 Python 主服务时,使用 RandomPort 为自建服务生成随机监听端口,并写入 ws-port.js 供配置项页面读取;普通通过 UlanziStudio 通信的插件不需要使用。
  7. 使用 Utils.getPluginPath() 获取以 ulanziPlugin 结尾的插件根目录。

特殊参数:context

同一个 action 可以被分配到多个按键,所以 SDK 会为每个按键实例生成唯一的 context,并附加到收到的消息中。

  • 格式:uuid + '___' + key + '___' + actionid
  • 编码:UD.encodeContext(message)
  • 解码:UD.decodeContext(context) 返回 {"uuid": ..., "key": ..., "actionid": ...}
  • clear 事件,context 会被写入 message["param"] 数组的每一项。

生成随机端口

RandomPort 适用于配置项页面需要自己连接主服务的场景:例如 Python 主服务在本地自建 WebSocket / HTTP 服务,配置项页面需要绕过 UlanziStudio 中转,直接与这个服务交换连接状态、账号信息、实时列表或其他临时数据。此时主服务启动时先调用一次 getPort(),用返回的端口启动自己的服务;RandomPort 会同时把端口写入插件根目录的 ws-port.js,配置项 HTML 页面引入该文件后即可读取 window.__port 并发起连接。

如果配置项与主服务之间的参数同步完全通过 UlanziStudio 的标准事件完成,则不需要使用 RandomPort

from ulanzi_api import RandomPort

random_port = RandomPort()
port = random_port.getPort()  # 生成端口并写入插件根目录 ws-port.js

# 使用这个端口启动插件自己的本地 WebSocket / HTTP 服务,供配置项页面直连
# start_service(host="127.0.0.1", port=port)

在配置项 HTML 中,连接前先引入生成文件:

<script src="../../ws-port.js"></script>
<script>
  const socket = new WebSocket(`ws://127.0.0.1:${window.__port}`);
</script>

注意事项:

  • RandomPort 只负责生成端口并写入 ws-port.js,不会自动创建 WebSocket / HTTP 服务。
  • 请在主服务启动阶段调用一次 getPort(),并在服务监听成功后再让配置项页面连接。
  • 默认端口范围为动态端口区间 49152-65535,用于降低不同插件之间的端口冲突概率;如需限制范围,可通过 RandomPort(min_port=..., max_port=...) 自定义。

连接上位机

由上位机启动时,Python 连接参数从 sys.argv 读取:

  • sys.argv[1] -> 地址,默认 127.0.0.1
  • sys.argv[2] -> 端口,默认 3906
  • sys.argv[3] -> 语言,默认 en
from ulanzi_api import UlanziApi

UD = UlanziApi()


def connected(_):
    print("已连接")


def add(message):
    context = message["context"]
    print("Action 已添加:", context)


def run(message):
    UD.setStateIcon(message["context"], 1, "ON")


def param_from_app(message):
    print("已保存参数:", message.get("param"))


UD.onConnected(connected)
UD.onAdd(add)
UD.onRun(run)
UD.onParamFromApp(param_from_app)
UD.connect("com.ulanzi.ulanzistudio.myplugin")
UD.wait()

connect() 默认启动后台 WebSocket 线程。主服务里可调用 wait() 保持进程运行,也可以传 threaded=False 在当前线程运行 WebSocket 循环。

接收事件

连接事件:

UD.onConnected(lambda message: None)
UD.onClose(lambda message: None)
UD.onError(lambda error: None)

按键事件:

UD.onAdd(lambda message: None)
UD.onRun(lambda message: None)
UD.onKeyDown(lambda message: None)
UD.onKeyUp(lambda message: None)
UD.onSetActive(lambda message: None)
UD.onClear(lambda message: None)

旋钮 / 编码器事件:

UD.onDialDown(lambda message: None)
UD.onDialUp(lambda message: None)
UD.onDialRotate(lambda message: None)
UD.onDialRotateLeft(lambda message: None)
UD.onDialRotateRight(lambda message: None)
UD.onDialRotateHoldLeft(lambda message: None)
UD.onDialRotateHoldRight(lambda message: None)

参数、Settings、跨页面通信与对话框事件:

UD.onParamFromApp(lambda message: None)
UD.onParamFromPlugin(lambda message: None)
UD.onDidReceiveSettings(lambda message: None)
UD.onDidReceiveGlobalSettings(lambda message: None)
UD.onSendToPlugin(lambda message: None)
UD.onSendToPropertyInspector(lambda message: None)
UD.onSelectdialog(lambda message: None)

同时提供 Python 风格别名,例如 on_connectedon_runset_state_iconsend_param_from_plugin

发送事件

设置按键图标:

UD.setStateIcon(context, state, text=None)
UD.setBaseDataIcon(context, data, text=None)
UD.setPathIcon(context, path, text=None)
UD.setGifDataIcon(context, gifdata, text=None)
UD.setGifPathIcon(context, gifpath, text=None)

V3.1 显示内容命令(要求 UlanziStudio 3.3.0 或更高版本):

UD.setState(context, 1)
UD.setImage(
    context,
    {
        "isDefault": True,
        "icons": [
            {"state": 0, "source": "path", "path": "images/off.png"},
            {"state": 1, "source": "base64", "base64": "data:image/png;base64,..."},
        ],
    },
)
UD.setImage(
    context,
    {"isDefault": False, "icons": {"source": "path", "path": "images/result.png"}},
)
UD.setImage(context, {"clear": True})
UD.setTitle(context, "就绪")

每个 icons 项支持 pathbase64stateclear 四种 source;省略 source 时默认使用 path

旋钮反馈:

UD.setFeedbackLayout(context, "$UA1")
UD.setFeedback(
    context,
    {"title": {"text": "就绪"}, "icon": {"value": "Images/new.png"}},
)

只支持内置布局标识。V3.1.0 协议将自定义布局文件标为“待实现”,因此公共库不会封装该分支。

发送参数和透传数据:

UD.sendParamFromPlugin(settings, context=None)
UD.sendToPropertyInspector(settings, context)
UD.sendToPlugin(settings)

Settings 持久化:

UD.setSettings(settings, context=None)
UD.getSettings(context=None)
UD.setGlobalSettings(settings, context=None)
UD.getGlobalSettings(context=None)

系统功能:

UD.toast(msg)
UD.showAlert(context=None)
UD.logMessage(msg, level="info")
UD.hotkey(key)
UD.openUrl(url, local=False, param=None)
UD.openView(url, width=200, height=200, x=None, y=None, param=None)
UD.selectFileDialog(file_filter=None)
UD.selectFolderDialog()

Utils API

Utils 是从 ulanzi_api 导出的单例。

Utils.getPluginPath()
Utils.getSystemType()        # "windows" 或 "mac"
Utils.adaptLanguage("zh-CN") # "zh_CN"
Utils.parseJson('{"a": 1}')
Utils.debounce(fn, wait=150)
Utils.getProperty(obj, "list[0].name", default_value=None)

调试

启动 Ulanzi Studio 时可附加以下参数开启调试。

参数 说明
--log 将日志写入文件
--logLevel 设置日志级别
--pluginLoad 开启插件加载钩子
--webRemoteDebug 启用 HTML 插件的 WebView 远程调试,默认端口 9292
--webRemotePort=<端口> 自定义 WebView 调试端口
--nodeRemoteDebug 启用 Node.js 远程调试;插件同时包含 Node 服务时可用
--doubleClick 启用双击检测

Windows 快捷方式目标示例:

"C:\...\Ulanzi Studio.exe" --log --webRemoteDebug

macOS:

open /Applications/Ulanzi\ Studio.app --args --log --webRemoteDebug