跳转到内容

工作流

工作流是 Kaloscope 的自动化基础,负责将对外部站点或本地文件系统的操作封装成可复用的执行单元。资源搜索、站点认证、下载计划、NFO 生成和定时任务,本质上都是工作流在运行。

一个工作流由若干节点和连接它们的组成。执行时,引擎从入口节点出发,沿边依次调用各节点,直到到达出口节点或流程结束。每次执行都会创建一个独立的上下文,节点之间通过上下文共享和传递数据。

生命周期

状态说明
草稿新建或编辑后未发布的状态,不参与任何实际功能
已发布可被索引器、下载计划或定时任务绑定并触发
有更新已发布后又做了修改,旧版本仍在生效,重新发布后才会切换到新版本

编辑器结构

  • 节点(左侧):按类型分组展示所有可用节点,拖入画布即可使用
  • 画布(中央):放置节点、连接句柄、调整布局
  • 小地图(右下):整体流程概览,支持快速定位和缩放
  • 工具栏(右上):适应视图、撤销、重做、保存、发布等操作

工作流节点

节点按功能分为四组:开始、结束、通用和控制。不同分类的工作流只会显示对应分类下可用的节点。

开始 / 结束

同一工作流内只能使用同一类别的开始和结束节点。

节点名称分类方向说明
搜索 API网络搜索开始接收关键词和分页参数,配置展示样式和全局搜索选项
搜索 API网络搜索结束将搜索结果格式化为标准 JSON 返回
认证 API网络搜索开始配置登录方式和 Cookie 参数
认证 API网络搜索结束输出认证结果,成功后自动持久化 Cookie
详情 API网络搜索开始配置媒体类型和视频封装格式
详情 API网络搜索结束将详情数据格式化为标准 JSON 返回
首页 API网络搜索开始配置首页看板数据的来源和展示样式
首页 API网络搜索结束将首页看板数据格式化为分组 JSON 列表返回
开始资源入库开始接收入库参数,判断对应 NFO 文件已存在时中止流程
电影资源入库结束生成电影元数据 NFO 文件
电视剧资源入库结束生成电视剧元数据 NFO 文件
剧集资源入库结束生成剧集元数据 NFO 文件
开始定时调度开始接收启动参数,渲染后合并到上下文
结束定时调度结束标记流程结束,可选立即取消其它节点

通用

节点名称说明
HTTP 请求发送 HTTP 请求,支持 GET / POST 等方法,请求头和请求体均支持 Jinja2 模板
保存文本将 Jinja2 模板渲染结果写入文件,路径必须位于某个媒体库目录下,支持不同的写入模式
设置变量将 Jinja2 模板渲染出的 JSON 键值对合并到当前上下文,供后续节点引用
脚本执行 Python 或 JavaScript 代码,通过约定的 execute 函数与引擎交互

控制

节点名称说明
条件对表达式求值,结果为真走「条件成立」分支,否则走「条件不成立」分支
循环遍历可迭代对象的每个元素,每次迭代时将当前元素以指定变量名注入到上下文
合并等待来自多个上游分支的输入达到指定数量后再继续,支持配置最大等待数量和超时时间

执行上下文

每次流程执行时,引擎会创建一个独立的上下文对象,节点通过模板字段访问其中的数据。上下文的初始内容由以下来源合并而成:

来源说明
全局变量在「全局变量」中维护的键值对,加密变量会在注入前自动解密
本地变量作用域限定在当前工作流的持久变量,可在多次执行之间保留状态
启动参数触发流程时传入的参数,在定时调度「开始」节点中可通过 params 引用

上下文在运行过程中还会注入以 $ 开头的特殊变量,供节点间传递数据和控制流程使用:

变量名说明
$retval出口节点返回给调用方的值
$loop当前循环迭代的变量对象
$index当前循环迭代的下标

模板字段

大多数节点字段支持 Jinja2 模板语法,可以直接引用上下文数据和全局变量,也可以在模板中使用过滤器(filter)对数据进行简单的处理和转换。

jinja
{{ title }}
{{ results[0].url }}
{{ content | xpath_first('//title/text()') }}

Kaloscope 扩展的过滤器覆盖了字符串处理、JSONPathXPath、正则提取、时间格式化和路径处理等多种操作,足够应对大多数索引与刮削场景。

自定义过滤器

在 Jinja2 中,过滤器(filter)用于把前一个表达式的结果继续传给一个处理函数,常见写法是 {{ value | filter_name(arg1, arg2) }}。除了 Jinja2 内置过滤器,Kaloscope 还扩展了下面这些实用的自定义过滤器:

名称用途示例
字符串
trim去除首尾字符,递归处理列表/字典。参数:chars(可选,默认空白){{ title | trim }}
ltrim去除左侧字符,递归处理列表/字典。参数:chars(可选,默认空白){{ title | ltrim('[') }}
rtrim去除右侧字符,递归处理列表/字典。参数:chars(可选,默认空白){{ title | rtrim(']') }}
json_escape按 JSON 规则转义字符串{{ keyword | json_escape }}
prefix添加前缀。参数:prefix(前缀字符串);strict(可选,默认 true 表示值或前缀为空时返回空字符串,传 false 始终拼接){{ id | prefix('/detail/') }}
suffix添加后缀。参数:suffix(后缀字符串);strict(可选,默认 true 表示值或后缀为空时返回空字符串,传 false 始终拼接){{ filename | suffix('.nfo') }}
JSONPath
jsonpath_firstJSONPath 查询,返回第一个匹配值。参数:expr(JSONPath 表达式){{ data | jsonpath_first('$.items[*].title') }}
jsonpath_allJSONPath 查询,返回全部匹配列表。参数:expr(JSONPath 表达式){{ data | jsonpath_all('$.items[*].title') }}
jsonpathJSONPath 查询。参数:expr(JSONPath 表达式);limit(可选,默认 'auto',可传 'first'/'all'/整数){{ data | jsonpath('$.items[*].title', 'all') }}
XPath
xpath_firstXPath 查询,返回第一个匹配值。参数:expr(XPath 表达式){{ html | xpath_first('//title/text()') }}
xpath_allXPath 查询,返回全部匹配列表。参数:expr(XPath 表达式){{ html | xpath_all('//a/@href') }}
xpathXPath 查询。参数:expr(XPath 表达式);limit(可选,默认 'auto',可传 'first'/'all'/整数){{ html | xpath('//img/@src', 'first') }}
正则
regex_first正则匹配,返回第一个捕获组。参数:expr(正则表达式){{ text | regex_first('id=(\d+)') }}
regex_all正则匹配,返回所有捕获组列表。参数:expr(正则表达式){{ text | regex_all('href="([^"]+)"') }}
regex正则匹配。参数:expr(正则表达式);limit(可选,默认 'auto',可传 'first'/'all'/整数){{ text | regex('id=(\d+)') }}
时间与日期
strftime格式化时间。参数:format(可选,默认 '%Y-%m-%d %H:%M:%S');tz(可选,时区偏移小时数){{ ts | strftime('%Y-%m-%d', 8) }}
year提取年份。参数:tz(可选,时区偏移小时数){{ publish_time | year(8) }}
duration转为可读时长(MM:SS/HH:MM:SS)。参数:unit(可选,默认 'milliseconds',可传 'seconds'/'minutes'{{ seconds | duration('seconds') }}
编码与路径
b64decodeBase64 解码,返回文本字符串{{ token | b64decode }}
b64encodeBase64 编码,返回编码后的字符串{{ password | b64encode }}
parent_path取父级目录。参数:levels(层数,默认 1);resolve(先转绝对路径,默认 false{{ path | parent_path(2, true) }}
中文转换
s2t简体转繁体{{ title | s2t }}
t2s繁体转简体{{ title | t2s }}

特殊参数说明

jsonpathxpathregex 这三个过滤器的 limit 参数默认为 'auto',表示无匹配时返回 None,单个匹配时直接返回该值,多个匹配时返回列表。

自定义测试

在 Jinja2 中,测试(test)用于判断一个值是否满足某个条件,常见写法是 {% if value is test_name %}。除了 Jinja2 内置测试,Kaloscope 还扩展了下面两个与文件系统相关的自定义测试:

名称用途示例
file判断路径是否是已存在的文件{% if nfo_path is file %}...{% endif %}
dir判断路径是否是已存在的目录{% if lib_dir is dir %}...{% endif %}

基于 GPLv3 开源协议发布