从 v3 迁移到 v4

从 v3 迁移到 v4

迁移指南
v3 → v4


🎯 为什么要迁移?

小树壁纸源协议 v4 是一次重大设计升级,从多文件、多语法的分散配置,进化为单文件、统一管道、内置分页与 HTML 抓取的声明式系统。主要收益包括:

  • 更简洁的维护:一个 source.ltconf 代替多个 TOML 文件
  • 更强大的提取能力:统一的路径表达式同时处理 JSON 和 HTML
  • 更少的重复代码:分页、过滤、变换全部内建
  • 更清晰的数据流:请求 → 映射 → 后处理 → 验证,一步到位

本指南将列出 v3 与 v4 的关键差异,并提供迁移步骤和转换示例。


🔄 主要差异速览

方面v3v4
文件结构多个文件:source.toml, config.toml, categories.toml, apis/*.toml单一文件 source.ltconf,所有内容集中定义
配置入口source.toml 指向其他文件四个顶级表:[meta], [config], [categories], [[apis]]
分类定义数组 [[categories]],含 idcategorysubcategory字典 [categories],键为 id,值含 nameparent 等,支持树形层级
路径语法JSON Pointer(/data/url),通配符 ***,点号路径统一路径表达式:$.data.url、过滤 [?()]、回退 `
HTML 支持通过 html: 前缀,使用 CSS 选择器提取,处理静态网页
分页需手动模拟原生内置:offsetcursorlink_headerselector 策略
响应格式json, toml, image_url, image_raw, static_list, static_dict简化为 json, html, raw, binarystatic_*raw + 管道或直接映射替代
后处理仅简单键值替换支持列表级 filter 过滤(用路径条件)和 merge 合并固定字段
验证required_fields + field_patterns + quality_rulesrequired_fields + constraints 数组,每条可设定 skip/warn/ignore
错误处理复杂的 http_codes 数组简化为 on_http_4xxon_http_5xx 等枚举,辅以 fallback_api
合并(merge)源级 [merge] 配置分类合并策略移除,由客户端自行决定合并行为
图标允许 Base64 或外部 URL(无强制)推荐 Base64,仍接受外部 URL
签名支持 Ed25519 已签名的 .sig 文件,客户端可验证完整性

🧭 迁移步骤

步骤 1:创建单一配置文件

在原壁纸源目录(包含 source.toml 等)旁边新建一个 source.ltconf

将下列内容整合进去:

  • source.toml 的元信息 → [meta]
  • config.toml 的全局设定 → [config]
  • categories.toml 的分类 → [categories]
  • 每个 apis/*.toml[[apis]] 数组元素

步骤 2:重写分类定义

v3 写法

# categories.toml
[[categories]]
id = "nature"
name = "自然风光"
category = "风景"
subcategory = "自然"
icon = "..."

v4 写法

[categories.nature]
name = "自然风光"
icon = "..."
parent = "landscape"   # 如有父级

如果以前有三级分类(category/subcategory/subsubcategory),在 v4 中用 parent 建立链:

[categories.scenery]
name = "风景"

[categories.nature]
name = "自然"
parent = "scenery"

[categories.mountain]
name = "山脉"
parent = "nature"

API 直接绑定到最具体的分类即可。

步骤 3:转换 API 定义

将每个 API 文件的内容移到 [[apis]] 下,并调整以下部分:

a. 请求与参数

基本不变,但要注意 interval_secondstimeout_seconds 等字段现在在 [apis.request] 中,不再需要单独的 request 子表包裹(但 v4 仍为 [apis.request],结构一致)。

b. 响应格式

  • format = "json" 保持不变
  • format = "image_url" → 请改为 format = "raw",它原本就是图片直链
  • format = "image_raw"format = "raw"
  • format = "static_list"static_dict" → 不再支持。若为少量静态壁纸,可直接在其他字段中映射;若为大量静态数据,建议改用 raw 或使用一个 JSON API 替换,或稍后用后处理的 merge 字段添加。

c. 映射(最重要更改)

v3 使用 JSON Pointer 语法:

[mapping]
items = "/data/images"
item_mapping = { image = "/url", title = "/copyright" }
[post_process]
image = "https://www.bing.com{{image}}"

v4 使用统一路径表达式:

[apis.mapping]
items = "$.data.images[*]"
fields = {
    image = "$.url | prepend('https://www.bing.com')",
    title = "$.copyright"
}

转换规则:

  • 去掉前导 /,换成 $.,可以视作 $.data.images
  • 若原路径含有数组索引 /0,改为 [0]
  • 通配符 * 变为 [*]
  • 递归通配符 ** 变为 ..
  • 多重路径 ["/hd_url", "/url"] 变为 $.hd_url || $.url
  • 后处理的简单拼接改为管道函数 prepend, append, replace 等。

d. 验证

原来的 required_fields 可以直接保留。
field_patternsquality_rules 合并为 [[apis.validation.constraints]],每条加入 action

v3 的

[validation]
required_fields = ["image"]
field_patterns = [
  { path = "image", regex = "^https?://" }
]
quality_rules = [
  { path = "width", min = 1920 }
]

v4 的

[apis.validation]
required_fields = ["image"]
[[apis.validation.constraints]]
path = "$.image"
regex = "^https?://"
action = "skip"
[[apis.validation.constraints]]
path = "$.width"
min = 1920
action = "warn"

e. 错误处理

v3 的 http_codes 数组改为 v4 的策略枚举:

# v3
[error_handling]
http_codes = [
  { code = 429, message = "Too many requests", retry_after = 60 },
  { code = 404, message = "Not found", fallback = true }
]

v4 中通常可用更简洁的映射:

[apis.error_handling]
on_http_4xx = "skip"    # 404 属于 4xx,可统一定义
on_http_5xx = "retry"
# 若需对特定状态码精细控制,目前 v4 不支持,建议用 fallback_api 或其他重试机制替代
fallback_api = "backup_api"

f. 缓存

v3 的 API 缓存字段 (ttl_seconds, key) 在 v4 中迁移为 [apis.cache] 下的 ttl_secondskey_template

g. 新增分页

如果原本的手动分页或未分页,可以按需要添加 [apis.pagination]。参考前文分页章节。

h. HTML 抓取迁移

如果原本通过复杂的后处理解析 HTML,现在可以直接使用 format = "html" 和 CSS 选择器映射,大幅简化。


📦 示例:完整迁移一个 API

v3 原始配置(Bing 每日壁纸)

# apis/bing.toml
name = "Bing 每日壁纸"
description = "微软Bing每日更新的壁纸"
logo = "data:image/svg+xml;base64,PHN2Zy..."
categories = ["daily"]

[[parameters]]
key = "mkt"
type = "choice"
label = "地区"
default = "zh-CN"
choices = ["zh-CN", "en-US", "ja-JP"]

[request]
url = "https://www.bing.com/HPImageArchive.aspx?format=js&n=8&mkt={{mkt}}&ts={{timestamp_ms}}"
method = "GET"
timeout_seconds = 15
interval_seconds = 3600

[request.headers]
Referer = "https://www.bing.com"

[response]
format = "json"
type = "multi"

[mapping]
items = "/images"
item_mapping = { image = "/url", title = "/copyright", startdate = "/startdate" }

[post_process]
image = "https://www.bing.com{{image}}"

[validation]
required_fields = ["image"]

[error_handling]
http_codes = [
  { code = 429, message = "请求过于频繁", retry_after = 300 }
]

[cache]
enabled = true
ttl_seconds = 43200
key = "bing_{{mkt}}_{{date}}"

v4 转换后(放在 [[apis]] 中)

[[apis]]
name = "Bing 每日壁纸"
description = "微软Bing每日更新的壁纸"
logo = "data:image/svg+xml;base64,PHN2Zy..."
category = "daily"

[[apis.parameters]]
key = "mkt"
type = "choice"
label = "地区"
default = "zh-CN"
choices = ["zh-CN", "en-US", "ja-JP"]

[apis.request]
url = "https://www.bing.com/HPImageArchive.aspx?format=js&n=8&mkt={{mkt}}&ts={{timestamp_ms}}"
method = "GET"
timeout_seconds = 15
interval_seconds = 3600
headers = { Referer = "https://www.bing.com" }

[apis.response]
format = "json"

[apis.mapping]
items = "$.images[*]"
fields = {
    image = "$.url | prepend('https://www.bing.com')",
    title = "$.copyright",
    date  = "$.startdate"
}

[apis.validation]
required_fields = ["image"]
[[apis.validation.constraints]]
path = "$.image"
regex = "^https://"
action = "skip"

[apis.error_handling]
on_http_429 = "retry"   # 如果仍需要单独处理 429,可保留,但 v4 建议统一用 on_http_4xx;此处仅示例

[apis.cache]
enabled = true
ttl_seconds = 43200
key_template = "bing_{{mkt}}_{{date_iso}}"

🧰 自动化迁移工具

官方将提供命令行工具 migrate-v3-to-v4,可以读取 v3 项目目录并生成 v4 的 source.ltconf 文件。使用方法:

# 将 v3 源目录转换为 v4 单文件
migrate-v3-to-v4 ./my_v3_source ./my_v4_source/source.ltconf

工具会自动处理:

  • 合并文件
  • 转换路径语法
  • 重写分类为字典结构
  • static_list/static_dict 展开为内建映射(若能直接提取为字段,否则转为 raw 并警告)
  • 提示不再支持的字段(如 merge 配置)并给予建议

注意:工具生成的配置可能需要手动微调,特别是特殊后处理逻辑。


⚠️ 需要注意的不兼容点

  • static_liststatic_dict 不再支持:请改用简单的 raw 格式或直接提供 JSON API;若必须静态嵌入少量壁纸,可通过后处理 merge 注入固定字段。
  • 源级合并 (merge) 被移除:如果之前依赖此功能,需要在客户端侧调整,或通过分类设计达成类似效果。
  • TOML 响应格式不再支持:如果此前使用 format = "toml",请将数据源改为 JSON 或 HTML。
  • 层级图标 (level_icons) 不再需要:现在图标直接绑定到每个分类条目,若需要按分类层级显示图标,可将图标分别赋给每个分类。

✅ 迁移后验证

  1. 打包新源:
    wallpaper-source-pack ./my_v4_source ./my_v4_source.ltws
  2. 验证:
    wallpaper-source-validate my_v4_source.ltws
  3. 在客户端加载测试,确认壁纸正常拉取、分类正确显示。

迁移完成
享受 v4 的简洁与强大