跳转到内容

工作流 ​

工作流是 Kaloscope 实现自动化的基础。无论是搜资源、站点登录、自动追更、生成 NFO,还是定时抓取,背后其实都在跑工作流。

每个工作流由若干节点和连接它们的边组成。执行时,引擎会从入口节点出发,沿着连线依次执行各节点,直到走到出口节点或流程结束。每次执行都会新建一个相互隔离的上下文,节点之间就靠这个上下文来共享和传递数据。

workflow-graphs

生命周期 ​

除了在画布上手动拖拽节点,你也可以让 AI 助手或外部 MCP 客户端帮忙起草、修改、校验和试运行工作流。不过不管怎么改,保存到草稿后都必须由管理员手动点击「发布」,新版本才会正式启用。

状态说明
草稿新建或编辑后尚未发布的状态,不会参与任何实际任务
已发布正式生效的版本,可以被索引器、下载计划或定时任务绑定并触发
有更新已发布后又做了修改;在重新发布之前,系统仍旧沿用上一个已发布版本

编辑器结构 ​

  • 节点面板(左侧):按类型分组展示可用节点,直接拖进画布就能用
  • 画布(中央):放置节点、拉线连接句柄、调整布局
  • 小地图(右下):浏览整个流程的缩略图,方便在复杂流程里快速定位和缩放
  • 工具栏(右上):提供适应视图、撤销、重做、保存、发布等常用操作
workflow-complex

工作流节点 ​

节点分为「开始」「结束」「通用」和「控制」四组。编辑不同类别的工作流时,左侧只会显示这个分类下可用的节点。

开始 / 结束 ​

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

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

通用 ​

节点名称说明
HTTP 请求发送 HTTP 请求,支持选择客户端和超时时间,请求头和请求体支持 Jinja2 模板
保存文本将 Jinja2 模板渲染结果写入文件,路径必须位于某个媒体库目录下,支持不同的写入模式
设置变量将 Jinja2 模板渲染出的 JSON 键值对合并到当前上下文,供后续节点引用
脚本运行 Python 或 JavaScript 代码,通过约定的 execute 函数与引擎交互
缓存数据持久保存当前工作流的本地变量,支持有效期,在下次执行时载入
AI调用已配置模型,输出文本或经过 JSON Schema 校验的对象,见 AI 节点

HTTP 请求设置 ​

「HTTP 请求」节点默认使用 httpx 发请求,如果遇到对 TLS 指纹或反爬较严的站点,也可切换为 curl_cffi(会模拟 Chrome 浏览器指纹)。超时时间以秒为单位,默认 30,最小 1,按接口响应速度调整就行。

请求地址、请求头和请求体都支持模板;拿到响应后,可通过「格式化」字段转成 JSON 对象并合入当前上下文。两种客户端均按网络设置里的规则匹配代理;不过要注意,httpx 支持通过 X-Hishel-* 请求头配置 HTTP 缓存,curl_cffi 不走这套缓存逻辑,而且 User-Agent 等浏览器指纹相关请求头也会由客户端自行生成。

缓存数据 ​

「缓存数据」节点用来把数据存成当前工作流私有的本地变量,下次运行同一工作流时自动载入,很适合用来记分页游标、接口临时令牌或最近处理到的位置。

字段说明
键缓存变量名,支持模板,最长 64 个字符
有效期(秒)0 表示永不过期;过期值在后续执行时清理,不再载入
值支持 Jinja2 模板,渲染后的文本将持久保存

同一个工作流里写入相同的键会覆盖旧值,不同工作流之间的缓存互相独立。另外,写入缓存不会改变这一次运行中的上下文;如果当前流程后面马上要用新值,记得另外加一个「设置变量」节点。

控制 ​

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

条件和循环节点会直接保留单个模板表达式的数据类型。比如 {{ results }} 可直接作为列表拿去循环,{{ count > 0 }} 可直接用来做布尔判断,{{ 3 }} 则会循环三次。注意如果只写 results 而不加双花括号,引擎会把它当作普通文本而不是变量;需要设默认值时可以写成 {{ results | default([]) }}。

执行上下文 ​

每次触发流程时,引擎都会新建一个独立的上下文,节点通过模板字段从里面读取数据。上下文初始包含以下四部分内容:

来源说明
系统变量当前 Kaloscope 版本等内置变量,例如 ks_version
全局变量在「全局变量」里统一维护的键值对;加密变量会在注入上下文前自动解密
本地变量作用域限定在当前工作流的持久变量,由「缓存数据」节点写入;未过期的值会在下次执行时载入
启动参数触发流程时传入的参数,会直接合并到上下文;在定时调度「开始」节点里还可通过 params 引用原始参数

运行期间,上下文里还会自动出现几个以 $ 开头的特殊变量,用来传递数据或查看循环状态:

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

循环节点会把当前遍历到的元素,按节点里填的变量名注入上下文。比如变量名填为 item 时,循环体内就能用 {{ item }} 取到当前元素;遍历字典时会逐个返回 (key, value) 键值对,遍历整数时则按 range(n) 遍历。

模板字段 ​

绝大多数节点字段都支持 Jinja2 模板语法,除了直接读取上下文和全局变量,还能搭配过滤器(filter)清洗和转换数据。

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

Kaloscope 扩展的过滤器覆盖了 JSONPath、XPath、正则提取、时间格式化、字符串、URL 和路径处理等多种操作,大多数索引和刮削场景不用写脚本就能搞定。

自定义过滤器 ​

在 Jinja2 里,过滤器用来把前一个表达式的结果传给处理函数,常见写法是 {{ 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') }}
size将字节数格式化为可读大小{{ total_size | size }}
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') }}
编码、URL 与路径
b64decodeBase64 解码,返回文本字符串{{ token | b64decode }}
b64encodeBase64 编码,返回编码后的字符串{{ password | b64encode }}
quoteURL 百分号编码{{ keyword | quote }}
query_param追加查询参数;如果同名参数已存在则保持原 URL 不变{{ url | query_param('lang=zh-CN') }}
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 %}

基于 GPLv3 开源协议发布