从 v3 迁移到 v4
🎯 为什么要迁移?
小树壁纸源协议 v4 是一次重大设计升级,从多文件、多语法的分散配置,进化为单文件、统一管道、内置分页与 HTML 抓取的声明式系统。主要收益包括:
- 更简洁的维护:一个
source.ltconf代替多个 TOML 文件 - 更强大的提取能力:统一的路径表达式同时处理 JSON 和 HTML
- 更少的重复代码:分页、过滤、变换全部内建
- 更清晰的数据流:请求 → 映射 → 后处理 → 验证,一步到位
本指南将列出 v3 与 v4 的关键差异,并提供迁移步骤和转换示例。
🔄 主要差异速览
| 方面 | v3 | v4 |
|---|---|---|
| 文件结构 | 多个文件:source.toml, config.toml, categories.toml, apis/*.toml | 单一文件 source.ltconf,所有内容集中定义 |
| 配置入口 | source.toml 指向其他文件 | 四个顶级表:[meta], [config], [categories], [[apis]] |
| 分类定义 | 数组 [[categories]],含 id、category、subcategory 等 | 字典 [categories],键为 id,值含 name、parent 等,支持树形层级 |
| 路径语法 | JSON Pointer(/data/url),通配符 *、**,点号路径 | 统一路径表达式:$.data.url、过滤 [?()]、回退 ` |
| HTML 支持 | 无 | 通过 html: 前缀,使用 CSS 选择器提取,处理静态网页 |
| 分页 | 需手动模拟 | 原生内置:offset、cursor、link_header、selector 策略 |
| 响应格式 | json, toml, image_url, image_raw, static_list, static_dict | 简化为 json, html, raw, binary;static_* 由 raw + 管道或直接映射替代 |
| 后处理 | 仅简单键值替换 | 支持列表级 filter 过滤(用路径条件)和 merge 合并固定字段 |
| 验证 | required_fields + field_patterns + quality_rules | required_fields + constraints 数组,每条可设定 skip/warn/ignore |
| 错误处理 | 复杂的 http_codes 数组 | 简化为 on_http_4xx、on_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_seconds、timeout_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_patterns 和 quality_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_seconds 和 key_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_list和static_dict不再支持:请改用简单的raw格式或直接提供 JSON API;若必须静态嵌入少量壁纸,可通过后处理merge注入固定字段。- 源级合并 (
merge) 被移除:如果之前依赖此功能,需要在客户端侧调整,或通过分类设计达成类似效果。 - TOML 响应格式不再支持:如果此前使用
format = "toml",请将数据源改为 JSON 或 HTML。 - 层级图标 (
level_icons) 不再需要:现在图标直接绑定到每个分类条目,若需要按分类层级显示图标,可将图标分别赋给每个分类。
✅ 迁移后验证
- 打包新源:
wallpaper-source-pack ./my_v4_source ./my_v4_source.ltws - 验证:
wallpaper-source-validate my_v4_source.ltws - 在客户端加载测试,确认壁纸正常拉取、分类正确显示。