工作流
工作流是 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)对数据进行简单的处理和转换。
{{ title }}
{{ results[0].url }}
{{ content | xpath_first('//title/text()') }}Kaloscope 扩展的过滤器覆盖了字符串处理、JSONPath、XPath、正则提取、时间格式化和路径处理等多种操作,足够应对大多数索引与刮削场景。
自定义过滤器
在 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_first | JSONPath 查询,返回第一个匹配值。参数:expr(JSONPath 表达式) | {{ data | jsonpath_first('$.items[*].title') }} |
jsonpath_all | JSONPath 查询,返回全部匹配列表。参数:expr(JSONPath 表达式) | {{ data | jsonpath_all('$.items[*].title') }} |
jsonpath | JSONPath 查询。参数:expr(JSONPath 表达式);limit(可选,默认 'auto',可传 'first'/'all'/整数) | {{ data | jsonpath('$.items[*].title', 'all') }} |
| XPath | ||
xpath_first | XPath 查询,返回第一个匹配值。参数:expr(XPath 表达式) | {{ html | xpath_first('//title/text()') }} |
xpath_all | XPath 查询,返回全部匹配列表。参数:expr(XPath 表达式) | {{ html | xpath_all('//a/@href') }} |
xpath | XPath 查询。参数: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') }} |
| 编码与路径 | ||
b64decode | Base64 解码,返回文本字符串 | {{ token | b64decode }} |
b64encode | Base64 编码,返回编码后的字符串 | {{ password | b64encode }} |
parent_path | 取父级目录。参数:levels(层数,默认 1);resolve(先转绝对路径,默认 false) | {{ path | parent_path(2, true) }} |
| 中文转换 | ||
s2t | 简体转繁体 | {{ title | s2t }} |
t2s | 繁体转简体 | {{ title | t2s }} |
特殊参数说明
jsonpath、xpath 和 regex 这三个过滤器的 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 %} |