小树壁纸源协议 v4.0

小树壁纸源协议 v4.0

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 = "自然の壁紙" }

    客户端会根据当前系统语言选择最匹配的文本;若没有完全匹配,则回退到第一个可用的语言值或直接使用字符串。

    descriptiondetails

    description 用于简短介绍,details 允许更丰富的 Markdown 格式说明。
    Markdown 中若需插入图片,应使用 Base64 数据 URI:

    ![图标](data:image/svg+xml;base64,PHN2Zy...)

    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 方法,支持 GETPOSTPUT
    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字符串参数类型:choicetextboolean
    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字符串-响应格式:jsonhtmlrawbinary
    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字符串-分页策略:offsetcursorlink_headerselector
    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"

    客户端行为:

    1. start_value 开始,发出第一次请求(用该值替换 {{page}})。
    2. 每次请求后递增 increment,继续请求下一页。
    3. 当响应为空、条目数 < 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 = ""             # 首次请求使用的游标值(若为空则不带该参数)

    客户端行为:

    1. initial_cursor 非空,首次请求携带该值。
    2. 每次请求后,从响应按 cursor_path 提取游标。
    3. 将游标值作为 {{cursor}} 替换到请求中,继续下一页。
    4. 当游标为空或达到 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 元素的 innerHTMLhtml:div | html
    clean去除多余空白和换行html:span | text | clean
    求值顺序与优先级

    表达式从左到右求值,运算符优先级(由高到低):

    1. 路径访问 . / [0] / [*] / ..
    2. 过滤 [?()]
    3. 管道 |
    4. 回退 ||
    5. 默认值 || "字符串"(与回退相同运算符)

    建议使用括号(())明确优先级,但目前表达式语法暂不支持括号分组,请依靠合理的链式顺序书写。

    错误与容错

    当路径表达式中某一步失败(如属性不存在)时:

    • 若无默认值,该字段值为 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(必填):验证失败时的操作,可选 skipwarnignore

    多条约束独立评估,若同一字段有多个约束,只需一个失败即触发对应操作。


    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 状态码时的行为:skipfallbackretry
    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

    打包工具将执行以下操作:

    1. 验证 source.ltconf 的语法和必填字段
    2. 确认没有本地二进制文件被引用(图标等请使用 Base64 或 URL)
    3. 生成 manifest.json,包含每个文件的 SHA-256 哈希和尺寸
    4. (可选)通过私钥对清单进行 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.ltws

    3. 验证

    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


    v4.0
    正式发布

    最后更新:2026年5月
    协议版本:v4.0
    文件格式.ltws (不压缩 TAR)
    适用客户端:小树壁纸 Next v2.0.0 及以上