小树壁纸源协议 v4.0
🎯 协议概述
小树壁纸源协议 v4.0 是一个声明式、单文件、管道化的壁纸源配置系统,专为 小树壁纸 Next 客户端设计。
通过一个结构化配置文件(source.ltconf)描述壁纸源的全部行为,并打包为不压缩的 TAR 格式(.ltws),实现即开即用、零歧义的加载体验。
核心特性
- 单文件配置:整个壁纸源的定义集中在一个
source.ltconf文件中,结构清晰、易于维护 - 管道式处理:数据获取流程分解为可自由组合的阶段:请求 → 解析 → 映射 → 后处理 → 验证
- 统一路径表达式:一套简洁语法同时查询 JSON 和提取 HTML 内容,支持过滤、变换、默认值
- 原生分页支持:内置偏移量、游标、Link 头、选择器等多种分页策略,自动合并多页结果
- HTML 网页抓取:通过 CSS 选择器将静态网页转换为结构化的壁纸数据
- 智能缓存控制:精细的缓存 TTL 与键模板,提升加载速度与离线体验
- 图标灵活管理:推荐使用 Base64 内联图标以获得最佳性能,也兼容外部 URL
- 安全防护增强:支持源完整性签名、敏感参数隐藏、响应大小限制
📁 文件结构
推荐开发目录
- source.ltconf
- source.ltconf.sig
source.ltconf:唯一配置文件,包含壁纸源的全部定义source.ltconf.sig(可选):Ed25519 签名文件,用于客户端校验完整性
打包后的 .ltws 结构
- source.ltconf
- manifest.json
- signature.sig
.ltws 为不压缩的 TAR 包,内部仅包含以下文件:
source.ltconf:壁纸源定义文件manifest.json:打包时自动生成的清单文件,包含文件哈希和元数据signature.sig(可选):Ed25519 签名
严格禁止将图片、字体等二进制资源文件直接打包进 .ltws。所有图像资源应通过 Base64 数据 URI 内联在配置中,或使用外部 URL 引用。
📋 主配置文件 source.ltconf
一个完整的 source.ltconf 文件由四个顶级区块组成:
[meta] # 元信息与展示
[config] # 全局请求与运行时配置
[categories] # 分类体系
[[apis]] # 数据接口数组(可定义多个)以下逐一详述各个区块的字段与用法。
🔖 [meta] – 源元信息
定义壁纸源的基本身份、展示属性与国际化文本。
字段一览
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
scheme | ✅ | 字符串 | - | 固定为 "littletree_wallpaper_source_v4" |
identifier | ✅ | 字符串 | - | 全局唯一反向域名标识,只能包含小写字母、数字、点和下划线 |
name | ✅ | 字符串或多语言映射 | - | 源显示名称 |
version | ✅ | 字符串 | - | 语义化版本号,格式 主.次.修订 |
description | ❌ | 字符串或多语言映射 | "" | 简短描述,建议 ≤100 字符 |
details | ❌ | 字符串 | "" | 详细说明,支持 Markdown,内嵌图片请使用 Base64 |
logo | ❌ | 字符串 | "" | 源图标,可使用 Base64 数据 URI 或外部 URL;推荐 Base64 |
footer_text | ❌ | 字符串或多语言映射 | "" | 底部文案,展示于客户端界面底部 |
详细说明
scheme
协议版本标识,必须严格等于 "littletree_wallpaper_source_v4"。
identifier
唯一标识,遵循反向域名风格:com.组织名.源名称。
只能使用小写字母、数字、点(.)和下划线(_)。
示例:"com.example.nature"、"net.littletree.bing_daily"。
name 与多语言文本
name 可以是一个简单字符串:
name = "自然壁纸"也可以是一个键值对表,支持多语言:
name = { en = "Nature Wallpapers", zh = "自然壁纸", ja = "自然の壁紙" }客户端会根据当前系统语言选择最匹配的文本;若没有完全匹配,则回退到第一个可用的语言值或直接使用字符串。
description 和 details
description 用于简短介绍,details 允许更丰富的 Markdown 格式说明。
Markdown 中若需插入图片,应使用 Base64 数据 URI:
logo
强烈推荐使用 Base64 编码的 SVG 图标,可以获得完全离线、零延迟的显示效果,且不会泄露用户隐私。
logo = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCI+PGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMzAiIGZpbGw9IiM0MmI3ZGUiLz48L3N2Zz4="协议同时接受外部 URL,但需注意网络可用性:
logo = "https://cdn.example.com/icon.svg"footer_text
底部文案,常用来声明版权或来源:
footer_text = "© 2025 自然壁纸 | 图片来自 Bing"完整示例
[meta]
scheme = "littletree_wallpaper_source_v4"
identifier = "com.nature.wallpapers"
name = { en = "Nature Wallpapers", zh = "自然壁纸" }
version = "1.0.0"
description = "探索来自世界各地的自然风光壁纸"
logo = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgZmlsbD0iIzQyYjdkZSIvPjwvc3ZnPg=="
footer_text = "© 2025 Nature Wallpapers"⚙️ [config] – 全局配置
全局请求与运行时行为设置。所有数据接口([[apis]])都会继承这里的配置,并可在接口级别按需覆盖。
完整配置结构
[config]
global_interval_seconds = 3600
timeout_seconds = 30
max_concurrent = 3
skip_ssl_verify = false
user_agent = "LittleTreeWallpaper/4.0"
max_response_size_mb = 10
[config.headers]
Accept = "application/json"
Accept-Language = "zh-CN,zh;q=0.9"
[config.retry]
max_attempts = 3
backoff_base = 2.0
initial_delay_ms = 1000
[config.cache]
enabled = true
default_ttl_seconds = 300
max_memory_mb = 100字段说明
请求控制
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
global_interval_seconds | 整数 | ❌ | 0 | 同一接口两次请求的最小间隔(秒),0 表示不限制 |
timeout_seconds | 整数 | ❌ | 30 | 默认的 HTTP 请求超时时间(秒) |
max_concurrent | 整数 | ❌ | 3 | 全局最大并发请求数 |
skip_ssl_verify | 布尔 | ❌ | false | 是否跳过 SSL 证书验证,除非调试,不建议开启 |
user_agent | 字符串 | ❌ | "LittleTreeWallpaper/4.0" | 自定义 User-Agent 头 |
max_response_size_mb | 整数 | ❌ | 10 | 单个响应体允许的最大体积(MB),超出后中断下载 |
默认请求头 [config.headers]
可在此表内定义任何 HTTP 头,它们将附加到所有接口请求中。
接口级别的 headers 配置会覆盖此处同名的值。
[config.headers]
Accept = "application/json"
Accept-Language = "zh-CN,zh;q=0.9"
Authorization = "Bearer token-example" # 如有需要重试策略 [config.retry]
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
max_attempts | 整数 | ❌ | 2 | 最大重试次数(不含首次请求) |
backoff_base | 浮点数 | ❌ | 2.0 | 指数退避的基数,第 n 次重试延迟为 initial_delay_ms * (backoff_base ^ n) |
initial_delay_ms | 整数 | ❌ | 1000 | 首次重试前的等待时间(毫秒) |
缓存配置 [config.cache]
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
enabled | 布尔 | ❌ | true | 是否建议客户端启用全局缓存。最终由客户端决定是否真正缓存 |
default_ttl_seconds | 整数 | ❌ | 300 | 当接口未单独指定 TTL 时,使用的默认缓存时间(秒) |
max_memory_mb | 整数 | ❌ | 100 | 建议客户端为当前源分配的最大内存缓存量(MB) |
缓存配置的优先级:接口级 [apis.cache] > 全局 [config.cache] > 客户端内置默认值。
🗂 [categories] – 分类体系
分类体系以字典形式定义在 [categories] 表中,键为分类的唯一 id,支持任意深度的父子层级。
分类定义字段
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
name | ✅ | 字符串或多语言映射 | - | 分类显示名称 |
icon | ❌ | 字符串 | "" | 分类图标,建议 Base64 编码 |
description | ❌ | 字符串或多语言映射 | "" | 分类简短描述 |
parent | ❌ | 字符串 | "" | 父分类 id,留空则为顶级分类 |
构建分类树
分类通过 parent 字段建立层级关系。顶级分类不填 parent 或设为空字符串。
[categories.nature]
name = "自然"
icon = "data:image/svg+xml;base64,..."
[categories.mountain]
name = "山脉"
icon = "data:image/svg+xml;base64,..."
parent = "nature"
[categories.lake]
name = "湖泊"
icon = "data:image/svg+xml;base64,..."
parent = "nature"客户端将依据 parent 构建分类树。当一个 API 绑定到子分类(如 mountain)时,该 API 提供的壁纸将同时显示在父分类(nature)中。
注意事项
- 分类
id只能包含小写字母、数字和下划线 - 避免循环引用(A 的 parent 是 B,B 的 parent 是 A),客户端检测到循环时会忽略该分类
- 图标建议使用 Base64 以获得最佳加载体验,也可使用外部 URL
📡 [[apis]] – 数据接口
一个壁纸源可以包含一个或多个数据接口。每个 [[apis]] 是一个独立的壁纸获取单元,包含请求、响应解析、映射、验证等完整流程。
顶层字段
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
name | ✅ | 字符串 | 接口名称(显示给用户) |
category | ✅ | 字符串 | 绑定的分类 id(必须在 [categories] 中定义) |
description | ❌ | 字符串 | 接口简要描述 |
logo | ❌ | 字符串 | 接口图标(Base64 或 URL) |
以下详细说明各个子表。
1. 请求配置 [apis.request]
定义 HTTP 请求的具体细节,支持模板变量。
[apis.request]
url = "https://api.example.com/wallpapers?page={{page}}&size=20"
method = "GET"
body = ""
timeout_seconds = 15
interval_seconds = 3600
headers = { Referer = "https://api.example.com" }字段说明
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
url | ✅ | 字符串 | - | 请求 URL,可包含 {{变量}} 模板 |
method | ❌ | 字符串 | "GET" | HTTP 方法,支持 GET、POST、PUT 等 |
body | ❌ | 字符串 | "" | 请求体,支持模板变量,通常用于 POST 请求 |
timeout_seconds | ❌ | 整数 | 继承 [config] | 该接口的请求超时(秒) |
interval_seconds | ❌ | 整数 | 继承 [config] | 该接口的最小请求间隔(秒),-1 表示不受任何限制 |
headers | ❌ | 表 | 继承 [config.headers] | 额外的请求头,会覆盖全局同名字段 |
模板变量
URL 和 body 中可以使用内置变量、用户参数、分页变量,格式为 {{变量名}}。
例如 {{n}}、{{mkt}}、{{page}} 等,必须在 [[apis.parameters]] 或分页配置中定义。
2. 用户参数 [[apis.parameters]]
声明该接口需要的用户自定义参数,这些参数会显示在客户端 UI 供用户调整,然后注入到请求中。
[[apis.parameters]]
key = "resolution"
type = "choice"
label = "分辨率"
default = "1920x1080"
choices = ["1920x1080", "2560x1440", "3840x2160"]
description = "选择壁纸下载分辨率"
[[apis.parameters]]
key = "keyword"
type = "text"
label = "搜索关键词"
default = "nature"
placeholder = "输入英文关键词"
min_length = 2
max_length = 50
[[apis.parameters]]
key = "api_key"
type = "text"
default = "secret123"
hidden = true参数字段
| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
key | ✅ | 字符串 | 参数名,对应模板中的变量名 |
type | ✅ | 字符串 | 参数类型:choice、text、boolean |
label | ❌ | 字符串 | UI 中显示的标签,未提供时使用 key |
default | ❌ | 对应类型 | 默认值 |
choices | ❌(choice 时必填) | 字符串数组 | 可选项列表 |
placeholder | ❌ | 字符串 | 文本输入框的占位提示 |
min_length | ❌ | 整数 | 文本最小长度 |
max_length | ❌ | 整数 | 文本最大长度 |
hidden | ❌ | 布尔,默认 false | 是否对用户隐藏(参数仍会参与模板填充) |
description | ❌ | 字符串 | 参数说明 |
hidden = true 的参数不会在 UI 展示,但仍会以 default 值注入模板。适用于 API 密钥等不希望用户看到的变量。注意:这些值仍以明文存储在配置文件中。
3. 响应格式 [apis.response]
[apis.response]
format = "json"
charset = "utf-8"| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
format | ✅ | 字符串 | - | 响应格式:json、html、raw、binary |
charset | ❌ | 字符串 | 来自响应头 | 字符编码,当响应头未提供时使用此值 |
json:将响应体解析为 JSON 对象/数组,后续使用路径表达式提取html:将响应体解析为 HTML DOM,后续使用html:前缀的 CSS 选择器提取raw:响应体即为壁纸图片的二进制数据,无需映射,直接作为最终壁纸binary:原始二进制,可自行在后续映射中处理(通常用于非图片直链场景)
4. 分页配置 [apis.pagination]
V4 原生支持自动翻页,客户端将按策略连续请求,并将所有页面的结果合并为一个列表。
[apis.pagination]
strategy = "offset"
max_pages = 10
page_size = 20
concurrency = 1
delay_ms = 200
merge_results = true通用字段
| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
strategy | ✅ | 字符串 | - | 分页策略:offset、cursor、link_header、selector |
max_pages | ❌ | 整数 | 1 | 最大翻页数,防止无限循环 |
page_size | ❌ | 整数 | 20 | 每页数量提示(可用于参数注入或限制) |
concurrency | ❌ | 整数 | 1 | 分页请求的并发数,建议保持 1 |
delay_ms | ❌ | 整数 | 200 | 分页请求之间的最小延迟(毫秒) |
merge_results | ❌ | 布尔 | true | 是否将所有页的条目合并为单一列表,再进行映射;设为 false 将保持按页分割的结构 |
策略类型详解
(a) offset – 偏移量/页码分页
请求时通过变量递增页码或偏移量。
[apis.pagination]
strategy = "offset"
param_name = "page" # 参数名,将作为 {{page}} 变量
start_value = 1 # 起始值
increment = 1 # 每次递增的量在请求 URL 中使用 {{page}} 变量:
url = "https://example.com/data?p={{page}}&limit=20"客户端行为:
- 从
start_value开始,发出第一次请求(用该值替换{{page}})。 - 每次请求后递增
increment,继续请求下一页。 - 当响应为空、条目数 <
page_size或达到max_pages时停止。
(b) cursor – 游标分页
下一页的标识包含在上一页的响应体中。
[apis.pagination]
strategy = "cursor"
cursor_path = "$.next_cursor" # 从响应中提取游标的路径表达式
cursor_param = "cursor" # 下一次请求的参数名,变为 {{cursor}} 变量
cursor_in = "query" # 游标放置的位置:query / header / body
stop_on_missing = true # 若 cursor_path 无值,停止翻页
initial_cursor = "" # 首次请求使用的游标值(若为空则不带该参数)客户端行为:
- 若
initial_cursor非空,首次请求携带该值。 - 每次请求后,从响应按
cursor_path提取游标。 - 将游标值作为
{{cursor}}替换到请求中,继续下一页。 - 当游标为空或达到
max_pages停止。
(c) link_header – HTTP Link 头分页
无需额外配置,客户端自动解析响应头中符合 RFC 5988 的 Link 头,提取 rel="next" 的 URL 作为下一页请求。
[apis.pagination]
strategy = "link_header"
max_pages = 10(d) selector – HTML 页面选择器分页
专用于 format = "html" 的场景,通过 CSS 选择器提取“下一页”的链接。
[apis.pagination]
strategy = "selector"
next_selector = "a.next-page" # 定位“下一页”链接的 CSS 选择器
attr = "href" # 提取哪个属性作为链接,默认为 "href"
stop_on_missing = true客户端将提取的链接作为完整的请求 URL(若为相对路径则自动补全),发起下一次请求。
5. 映射 [apis.mapping]
映射阶段将原始响应数据转换为壁纸条目列表。核心是使用路径表达式从 JSON 或 HTML 中提取字段。
[apis.mapping]
items = "$.images[*]"
fields = {
image = "$.url | prepend('https://example.com')",
title = "$.copyright || '未知'"
}items:一个路径表达式,指定如何获取条目列表。如果响应本身就是一个数组,可以写$或$.data.list[*]。fields:键值对,键为最终壁纸的字段名,值为路径表达式,用于从每个条目中提取对应数据。
路径表达式完整指南
路径表达式是 v4 数据提取的核心,统一适用于 JSON 和 HTML 响应。
基本语法
| 语法元素 | 说明 | 示例 |
|---|---|---|
$ | 根节点 | $.data – 访问根下的 data 属性 |
.key | 访问对象属性 | $.name |
[index] | 访问数组元素,index 可负数 | $.items[0],$.items[-1] |
[start:end] | 数组切片,半开区间 | $.items[0:5] |
[*] | 数组所有元素通配 | $.images[*] |
..key | 递归搜索所有层的 key | $..url – 查找所有 url 字段 |
[?(@.condition)] | 条件过滤 | $.items[?(@.width > 1920)] |
|| | 多重回退,依次尝试直到获得有效值 | $.hd_url || $.sd_url |
|| "默认值" | 默认值,当左侧无效时使用 | $.title || "无标题" |
| func | 管道函数,对左侧结果应用函数 | $.url | prepend("https:") |
html:selector | 指定 HTML 模式,使用 CSS 选择器 | html:div.wallpaper img |
条件过滤
条件过滤放在数组表达式之后,使用 [?()] 包裹。支持比较运算符、逻辑运算符和正则匹配:
- 比较:
==,!=,<,>,<=,>= - 逻辑:
&&,||,! - 正则:
=~,后跟正则表达式(用单引号包裹)
示例:
$.items[?(@.category == "wallpaper" && @.width >= 1920)]
$.items[?(@.url =~ '^https://')]HTML 选择器
当 [apis.response].format = "html" 时,路径表达式需以 html: 开头,后面是 CSS 选择器。
选择器在条目范围内查找元素(items 已限定容器)。
提取属性:
html:img.wallpaper | attr(src)提取文本:
html:h2.title | text提取内部HTML:
html:div.description | html内置管道函数
管道函数可以链式调用,从左到右依次处理。
| 函数 | 参数 | 说明 | 示例 |
|---|---|---|---|
prepend(prefix) | 字符串 | 在前添加字符串 | $.url | prepend("https://") |
append(suffix) | 字符串 | 在后添加字符串 | $.url | append("?w=1920") |
replace(pattern, replacement) | 两个字符串 | 正则替换 | $.url | replace("http:","https:") |
regexExtract(pattern) | 字符串 | 正则提取第一个捕获组 | $.url | regexExtract("/(\\d+)/") |
toInt | 无 | 转换为整数 | $.width | toInt |
toFloat | 无 | 转换为浮点数 | $.size | toFloat |
truncate(length) | 整数 | 截断字符串 | $.title | truncate(20) |
dateFormat(format) | 字符串 | 按格式格式化日期(需配合日期解析) | $.date | dateFormat("YYYY-MM-DD") |
attr(name) | 字符串 | 取 DOM 元素的指定属性 | html:img | attr(data-src) |
text | 无 | 提取 DOM 元素的文本内容 | html:h2 | text |
html | 无 | 提取 DOM 元素的 innerHTML | html:div | html |
clean | 无 | 去除多余空白和换行 | html:span | text | clean |
求值顺序与优先级
表达式从左到右求值,运算符优先级(由高到低):
- 路径访问
./[0]/[*]/.. - 过滤
[?()] - 管道
| - 回退
|| - 默认值
|| "字符串"(与回退相同运算符)
建议使用括号(())明确优先级,但目前表达式语法暂不支持括号分组,请依靠合理的链式顺序书写。
错误与容错
当路径表达式中某一步失败(如属性不存在)时:
- 若无默认值,该字段值为
null,最终可能触发验证跳过该条目 ||回退机制可以捕获null并尝试下一个路径- 客户端的
path_strict模式(由客户端设置)可能让任何路径错误直接中断处理并可记录日志
6. 后处理 [apis.post_process]
在映射完成,所有条目提取完毕后,可对列表进行全局过滤,或为每个条目合并固定字段。
[apis.post_process]
filter = "$..[?(@.width >= 1920)]"
merge = { source = "Bing", copyright = "© Microsoft" }filter:使用条件表达式过滤条目列表,语法与路径过滤一致,但针对的是已完成映射的最终列表。merge:一个键值表,为每个条目添加或覆盖固定字段。这常用于标注数据来源或附加静态信息。
filter 可选,如果没有需要过滤的,可省略整个 post_process 块。
7. 验证规则 [apis.validation]
验证规则在映射和后处理之后执行,确保数据质量。可以为不同情况指定 skip(丢弃)、warn(警告但保留)或 ignore(忽略)。
[apis.validation]
required_fields = ["image", "title"]
[[apis.validation.constraints]]
path = "$.image"
regex = "^https://"
min_length = 10
max_length = 2000
action = "skip"
[[apis.validation.constraints]]
path = "$.width"
min = 1920
action = "warn"字段说明
required_fields:字符串数组,指定哪些字段必须存在且非空。缺失的条目将被丢弃。constraints:一个规则数组,每条规则包含:path(必填):要检查的字段路径(相对于条目)regex(可选):正则表达式,字段值必须匹配min_length/max_length(可选):字符串长度限制min/max(可选):数值范围限制action(必填):验证失败时的操作,可选skip、warn、ignore
多条约束独立评估,若同一字段有多个约束,只需一个失败即触发对应操作。
8. 错误处理 [apis.error_handling]
定义当请求或映射出现异常时的应对策略。
[apis.error_handling]
on_http_4xx = "skip"
on_http_5xx = "retry"
on_empty_response = "skip"
on_mapping_failure = "skip_item"
fallback_api = "bing_backup"| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
on_http_4xx | ❌ | 字符串 | "skip" | 收到 4xx 状态码时的行为:skip、fallback、retry |
on_http_5xx | ❌ | 字符串 | "retry" | 收到 5xx 状态码时的行为 |
on_empty_response | ❌ | 字符串 | "skip" | 响应体为空时的行为 |
on_mapping_failure | ❌ | 字符串 | "skip_item" | 多图映射中单个条目映射失败时的行为:skip_item 丢弃单个条目;skip 丢弃整个接口结果 |
fallback_api | ❌ | 字符串 | 无 | 当前接口失败时,备用接口的名称([[apis]].name),必须存在于同一源内 |
fallback_api 允许定义降级数据源,当主接口连续失败(或命中 fallback 策略)时,客户端可尝试请求备用接口。
9. 接口级缓存 [apis.cache]
用于为特定接口设置独立的缓存策略,优先级高于 [config.cache]。
[apis.cache]
enabled = true
ttl_seconds = 43200
key_template = "bing_{{mkt}}_{{date_iso}}"| 字段 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
enabled | ❌ | 布尔 | 继承全局 | 是否建议启用缓存 |
ttl_seconds | ❌ | 整数 | 继承全局 | 缓存时间(秒) |
key_template | ❌ | 字符串 | 接口名称 | 缓存键模板,可包含请求参数和内置变量 |
构建唯一的缓存键非常重要,以防止不同参数组合的缓存互相污染。
示例:"bing_{{mkt}}_{{date_iso}}",确保不同地区和日期的结果独立缓存。
🔧 内置变量系统
变量以 {{变量名}} 格式嵌入到配置的字符串中(如 URL、请求体、缓存键等),在请求时由客户端替换为实际值。
时间变量
| 变量 | 输出示例 |
|---|---|
{{timestamp_ms}} | 1704067200000 |
{{timestamp_s}} | 1704067200 |
{{date_iso}} | 2024-01-01 |
{{date_cn}} | 2024年01月01日 |
{{year}} | 2024 |
{{month}} | 01 |
{{day}} | 01 |
{{hour}} | 12 |
{{minute}} | 30 |
{{second}} | 45 |
随机与屏幕
| 变量 | 说明 |
|---|---|
{{random_string:N}} | 生成长度为 N 的随机字符串 |
{{random_int:MIN:MAX}} | 生成 [MIN, MAX] 范围内的随机整数 |
{{random_hex:N}} | 生成长度为 N 的随机十六进制字符串 |
{{screen_width}} | 设备屏幕宽度(客户端提供) |
{{screen_height}} | 设备屏幕高度 |
{{screen_ratio}} | 屏幕宽高比(宽度/高度) |
分页变量(自动注册)
根据分页策略,以下变量将自动可用,无需在 [[apis.parameters]] 中定义:
| 变量 | 适用策略 | 说明 |
|---|---|---|
{{page}} | offset | 当前页码,从 start_value 开始递增 |
{{offset}} | offset | 当前偏移量 |
{{cursor}} | cursor | 当前游标值 |
📦 打包与签名
打包命令
# 假设当前目录包含 source.ltconf
wallpaper-source-pack . my_source.ltws打包工具将执行以下操作:
- 验证
source.ltconf的语法和必填字段 - 确认没有本地二进制文件被引用(图标等请使用 Base64 或 URL)
- 生成
manifest.json,包含每个文件的 SHA-256 哈希和尺寸 - (可选)通过私钥对清单进行 Ed25519 签名,生成
signature.sig
manifest.json 示例
{
"format_version": "4.0",
"source_schema": "littletree_wallpaper_source_v4",
"generated_at": "2024-01-15T12:00:00Z",
"tool_version": "wallpaper-source-pack/4.0.0",
"files": [
{
"path": "source.ltconf",
"sha256": "abc123def456...",
"size": 2048
}
],
"metadata": {
"name": "自然壁纸源",
"identifier": "com.nature.wallpapers",
"version": "1.0.0"
},
"signature": {
"algorithm": "Ed25519",
"value": "base64_signature..."
}
}客户端可以依据此签名验证源文件是否完整且未被篡改。
🚀 快速开始
1. 编写 source.ltconf
[meta]
scheme = "littletree_wallpaper_source_v4"
identifier = "com.example.first"
name = "我的第一个壁纸源"
version = "1.0.0"
logo = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i..."
[categories.featured]
name = "精选"
[[apis]]
name = "Lorem Picsum"
category = "featured"
[apis.request]
url = "https://picsum.photos/1920/1080"
[apis.response]
format = "raw"2. 打包
wallpaper-source-pack . ./my_source.ltws3. 验证
wallpaper-source-validate my_source.ltws✅ 验证清单
在发布壁纸源之前,请对照检查:
-
meta.scheme固定为"littletree_wallpaper_source_v4" -
meta.identifier唯一且符合反向域名格式 - 至少包含一个分类(
[categories]中至少有一项) - 至少定义一个
[[apis]] - 所有 API 的
category值在[categories]中存在 - 图标字段(
logo、分类icon)使用有效 Base64 数据 URI 或可访问的外部 URL - 路径表达式语法正确,管道函数拼写无误
- 如果使用分页,变量名与模板中的引用一致
- 缓存键模板不包含可能泄露用户隐私的原始数据
- 敏感参数已标记
hidden = true(尽管仍为明文存储)
🛡️ 安全与最佳实践
- 图标:强烈推荐 Base64 内联 SVG,无外部依赖;如果必须使用外部 URL,请确保链接长期有效且为 HTTPS
- 请求安全:在验证规则中强制
image字段匹配^https://,避免中间人攻击 - 敏感参数:通过
hidden = true隐藏密钥,但请注意配置仍以明文存储;未来版本可能支持加密参数 - 速率控制:合理设置
interval_seconds与分页delay_ms,避免对源站造成压力或被封禁 - 响应限制:设置
max_response_size_mb,防止意外下载恶意极大文件 - 签名验证:客户端可校验
signature.sig,确保源包未被篡改
📌 更多资源
图标转换工具
# 将本地图片转换为 Base64 数据 URI
convert-to-base64 icon.png
# 输出: data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...配置文件生成
你可以从零开始手写,也可以使用社区提供的交互式生成工具(即将推出),帮助快速构建 source.ltconf。
最后更新:2026年5月
协议版本:v4.0
文件格式:.ltws (不压缩 TAR)
适用客户端:小树壁纸 Next v2.0.0 及以上