壁纸源协议

🎯 协议概述

小树壁纸源协议 v3.0 是一个模块化、高性能的壁纸源配置系统。通过将配置拆分为多个文件并使用不压缩的 TAR 格式打包,实现了快速加载和易维护性。

核心特性

  • 模块化设计:配置文件按功能拆分,便于管理
  • 不压缩 TAR 格式.ltws 格式提供极速加载体验
  • 内置变量系统:支持时间、随机数等动态变量
  • 全面验证:内置字段验证和质量检查
  • 无外部资源:所有图标必须使用 Base64 或外部 URL

📁 文件结构

开发目录结构

    • source.toml
    • config.toml
    • categories.toml
      • example_api.toml
      • another_api.toml
  • 打包后的 .ltws 文件结构

    • source.toml
    • config.toml
    • categories.toml
    • manifest.json
      • example_api.toml
      • another_api.toml

  • 📋 源数据文件 (source.toml) - 完整字段说明

    源数据文件是壁纸源的入口点,定义了基本信息和文件引用。

    必需字段

    scheme = "littletree_wallpaper_source_v3"
    identifier = "com.example.wallpaper_source"
    name = "壁纸源名称"
    version = "1.0.0"
    categories = "categories.toml"
    apis = ["apis/*.toml"]

    完整字段说明

    字段必填类型默认值说明示例
    scheme字符串-协议版本标识"littletree_wallpaper_source_v3"
    identifier字符串-全局唯一标识符"com.example.nature"
    name字符串-壁纸源显示名称"自然壁纸源"
    version字符串-语义化版本"1.0.0"
    categories字符串-分类文件路径"categories.toml"
    apis数组-API 文件匹配模式["apis/*.toml"]
    config字符串"config.toml"配置文件路径"config.toml"
    description字符串""简短描述"提供高质量自然风景壁纸"
    details字符串""详细说明(Markdown)"# 详细说明\n支持 Markdown"
    logo字符串""图标(Base64 或 URL)"data:image/svg+xml;base64,..."
    footer_text字符串""底部文本"© 2025 壁纸源"

    字段详细说明

    1. scheme (必填)

    协议版本标识符,必须是 "littletree_wallpaper_source_v3"

    2. identifier (必填)

    壁纸源的全局唯一标识符,遵循反向域名格式:

    • 格式:com.组织名.源名称
    • 只能包含小写字母、数字、点号和下划线
    • 示例:"com.example.nature", "com.littletree.bing_daily"

    3. name (必填)

    壁纸源的显示名称,在客户端中可见:

    • 建议长度:2-32个字符
    • 支持中文、英文等
    • 示例:"自然壁纸源", "Bing 每日壁纸"

    4. version (必填)

    语义化版本号,格式为 "主版本.次版本.修订号"

    • 主版本:不兼容的API修改
    • 次版本:向下兼容的功能性新增
    • 修订号:向下兼容的问题修正
    • 示例:"1.0.0", "2.1.3"

    5. categories (必填)

    分类定义文件的路径,支持相对路径:

    • 必须指向一个有效的 .toml 文件
    • 示例:"categories.toml", "definitions/categories.toml"

    6. apis (必填)

    API 文件匹配模式列表,支持 glob 模式:

    • 至少包含一个模式
    • 支持多个模式组合
    • 示例:["apis/*.toml"], ["apis/bing.toml", "apis/nature.toml"]

    7. config (可选)

    配置文件路径,默认为 "config.toml"

    • 如果不存在此字段或文件不存在,使用默认配置
    • 支持相对路径
    • 示例:"config.toml", "configs/main.toml"

    8. description (可选)

    壁纸源的简短描述,建议长度≤100字符:

    • 在客户端中显示
    • 简明扼要地说明功能
    • 示例:"提供高质量自然风景壁纸"

    9. details (可选)

    详细的说明文档,支持 Markdown 格式:

    • 更详细的功能介绍
    • 使用说明
    • 更新日志等
    • 示例:
      details = """
      # 自然壁纸源
      
      ## 特性
      - 每日更新高质量壁纸
      - 支持多种分辨率
      - 无版权问题
      
      ## 使用说明
      在设置中选择壁纸源即可使用。
      """

    10. logo (可选)

    壁纸源图标,必须使用 Base64 编码或外部 URL:

    • 不允许本地文件路径
    • 推荐使用 SVG 格式的 Base64 编码
    • 建议尺寸:64×64 或 128×128 像素
    • Base64 示例:"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIzMiIgY3k9IjMyIiByPSIzMCIgZmlsbD0iIzQyYjdkZSIvPjwvc3ZnPgo="
    • URL 示例:"https://example.com/logo.svg"

    11. footer_text (可选)

    显示在壁纸详情页面底部的文本:

    • 可用于版权声明、来源说明等
    • 示例:"© 2025 自然壁纸 | 图片来自 Bing"

    完整示例

    # source.toml
    scheme = "littletree_wallpaper_source_v3"
    identifier = "com.nature.wallpapers"
    name = "自然壁纸源"
    version = "1.0.0"
    
    # 必需的文件引用
    categories = "categories.toml"
    apis = ["apis/*.toml"]
    
    # 可选配置
    config = "config.toml"
    description = "提供高质量自然风景壁纸,每日更新"
    
    # Base64 编码的图标(SVG格式)
    logo = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgc3R5bGU9ImZpbGw6IzQyYjdkZSIvPjwvc3ZnPgo="
    
    # 详细说明(Markdown格式)
    details = """
    # 自然壁纸源
    
    ## 功能特性
    - **每日更新**:每天提供新的自然风景壁纸
    - **多分辨率**:支持 1080p、2K、4K 等分辨率
    - **高质量**:所有图片均经过精选,确保画质
    - **无广告**:纯净的壁纸体验
    
    ## 使用说明
    1. 在客户端中启用本壁纸源
    2. 进入「自然」分类查看壁纸
    3. 点击喜欢的壁纸设置为桌面
    
    ## 更新日志
    ### v1.0.0 (2025-01-15)
    - 初始版本发布
    - 支持自然风景壁纸
    - 添加每日更新功能
    """
    
    footer_text = "© 2025 自然壁纸源 | 发现世界之美"

    注意事项

    1. 标识符唯一性

    identifier 字段必须全局唯一,避免与其他壁纸源冲突。

    2. 文件路径

    所有文件路径都是相对于 source.toml 所在目录:

    my_source/
    ├── source.toml          # 当前文件
    ├── config.toml          # config = "config.toml"
    ├── categories.toml      # categories = "categories.toml"
    └── apis/                # apis = ["apis/*.toml"]
        └── *.toml

    3. 图标规范

    • 不允许logo = "icon.png"(本地文件)
    • 允许logo = "data:image/svg+xml;base64,..."(Base64)
    • 允许logo = "https://example.com/icon.svg"(外部URL)

    4. 版本管理

    遵循语义化版本规范:

    • 1.0.0 → 初始版本
    • 1.0.1 → 修复小问题,向下兼容
    • 1.1.0 → 新增功能,向下兼容
    • 2.0.0 → 重大更新,可能不兼容

    5. 默认值说明

    • config 字段默认值为 "config.toml"
    • 如果配置文件不存在,客户端会使用内置默认配置
    • 其他可选字段默认值为空字符串 ""

    验证规则

    必填字段验证

    # 验证示例
    ☑ scheme 必须是 "littletree_wallpaper_source_v3"
    ☑ identifier 格式正确(com.xxx.xxx)
    ☑ name 长度在 2-32 字符之间
    ☑ version 符合语义化版本格式
    ☑ categories 文件存在
    ☑ apis 数组非空且匹配到至少一个文件

    可选字段验证

    # 验证示例(如果存在)
    ☑ config 文件存在(如果指定)
    ☑ description 长度 ≤ 100 字符
    ☑ logo 是有效的 Base64 或 URL
    ☑ details 是有效的字符串
    ☑ footer_text 长度 ≤ 200 字符

    常见错误

    错误1:缺少必需字段

    # ❌ 错误:缺少 identifier
    scheme = "littletree_wallpaper_source_v3"
    name = "壁纸源"
    # 缺少 identifier 字段
    
    # ✅ 正确:包含所有必需字段
    scheme = "littletree_wallpaper_source_v3"
    identifier = "com.example.source"
    name = "壁纸源"
    version = "1.0.0"
    categories = "categories.toml"
    apis = ["apis/*.toml"]

    错误2:图标使用本地文件

    # ❌ 错误:使用本地文件路径
    logo = "icon.png"  # 不允许
    
    # ✅ 正确:使用 Base64 编码
    logo = "data:image/svg+xml;base64,..."
    
    # ✅ 正确:使用外部 URL
    logo = "https://example.com/icon.svg"

    错误3:版本格式错误

    # ❌ 错误:版本格式不正确
    version = "1.0"      # 缺少修订号
    version = "v1.0.0"   # 包含前缀v
    version = "1.0.0.1"  # 过多部分
    
    # ✅ 正确:语义化版本
    version = "1.0.0"
    version = "2.1.3"

    错误4:标识符格式错误

    # ❌ 错误:标识符格式不正确
    identifier = "my_source"          # 缺少域名部分
    identifier = "com.my source"      # 包含空格
    identifier = "COM.EXAMPLE.SOURCE" # 大写字母
    
    # ✅ 正确:反向域名格式
    identifier = "com.example.source"
    identifier = "com.littletree.bing"

    ⚙️ 配置文件 (config.toml)

    配置文件定义全局请求设置,所有 API 都会继承这些配置。

    请求配置

    [request]
    global_interval_seconds = 3600  # 全局请求间隔(秒),0=不限制
    timeout_seconds = 30           # 请求超时时间(秒)
    max_concurrent = 3             # 最大并发请求数
    skip_ssl_verify = false        # 是否跳过 SSL 验证
    user_agent = "LittleTreeWallpaper/3.0"  # 自定义 User-Agent

    请求头配置

    [request.headers]
    Accept = "application/json"
    Accept-Language = "zh-CN,zh;q=0.9"
    Accept-Encoding = "gzip, deflate"

    重试策略

    [request.retry]
    max_attempts = 3        # 最大重试次数
    backoff_base = 2.0      # 退避基数(指数退避)
    initial_delay_ms = 1000  # 初始延迟(毫秒)

    缓存配置

    [request.cache]
    enabled = true          # 是否启用缓存
    default_ttl_seconds = 300  # 默认缓存时间(秒)
    max_memory_mb = 100     # 最大内存缓存大小(MB)

    说明

    [request.cache] 用于描述客户端在进行网络请求时如何缓存响应数据(是否真正缓存、缓存介质、清理策略等最终由客户端实现决定)。

    • enabled:仅表示“允许/建议启用缓存”的默认开关;客户端可忽略或强制关闭(例如隐私模式/省流模式)。
    • default_ttl_seconds:默认缓存 TTL(秒)。当某个 API 未单独配置 [cache] 或未提供 ttl_seconds 时,可使用该值。
    • max_memory_mb:内存缓存上限(MB)。达到上限后如何淘汰(LRU/按TTL/按大小)由客户端决定。

    优先级(建议)

    当同一个请求同时受多处配置影响时,建议客户端按以下优先级解释:

    1. API 文件中的 [cache](最具体)
    2. 全局 config.toml[request.cache]
    3. 客户端内置默认值(或用户设置)

    内置变量

    [request.variables]
    timestamp = "{{timestamp_ms}}"      # 当前时间戳(毫秒)
    date = "{{date_iso}}"              # 当前日期(ISO格式)
    date_cn = "{{date_cn}}"            # 中文日期
    random = "{{random_string:8}}"     # 8位随机字符串
    random_int = "{{random_int:1:100}}" # 1-100随机整数

    完整示例

    # config.toml
    [request]
    global_interval_seconds = 1800
    timeout_seconds = 20
    max_concurrent = 2
    skip_ssl_verify = false
    user_agent = "MyWallpaperClient/3.0"
    
    [request.headers]
    Accept = "application/json"
    Accept-Language = "zh-CN"
    
    [request.retry]
    max_attempts = 2
    backoff_base = 1.5
    initial_delay_ms = 500
    
    [request.cache]
    enabled = true
    default_ttl_seconds = 600
    
    [request.variables]
    timestamp = "{{timestamp_ms}}"
    date = "{{date_iso}}"
    random = "{{random_string:6}}"

    🗂️ 分类定义文件 (categories.toml)

    分类定义文件组织壁纸的分类结构。

    分类结构

    # 分类模板(可选)
    [template]
    icon = "data:image/svg+xml;base64,..."  # Base64 图标
    category = "默认分类"
    
    # 分类列表
    [[categories]]
    id = "nature"           # 必填:分类唯一标识符
    name = "自然风光"        # 必填:分类显示名称
    category = "风景"        # 必填:一级分类
    subcategory = "自然"     # 可选:二级分类
    icon = "data:image/svg+xml;base64,..."  # 可选:Base64 图标
    description = "自然风景壁纸"  # 可选:分类描述

    层级图标支持(可选)

    允许为每个层级(category/subcategory/subsubcategory)设置独立的图标,提供更一致的视觉体验。

    # 层级图标定义(可选)
    [level_icons]
    # 一级分类图标(按category值匹配)
    [level_icons.category]
    风景 = "data:image/svg+xml;base64,..."
    自然 = "data:image/svg+xml;base64,..."
    二次元 = "data:image/svg+xml;base64,..."
    
    # 二级分类图标(按subcategory值匹配)  
    [level_icons.subcategory]
    山脉 = "data:image/svg+xml;base64,..."
    湖泊 = "data:image/svg+xml;base64,..."
    动漫 = "data:image/svg+xml;base64,..."
    
    # 三级分类图标(按subsubcategory值匹配)
    [level_icons.subsubcategory]
    精选 = "data:image/svg+xml;base64,..."
    热门 = "data:image/svg+xml;base64,..."
    最新 = "data:image/svg+xml;base64,..."

    图标优先级规则

    客户端按以下顺序确定分类显示的图标:

    1. 分类特定图标[[categories]] 中的 icon 字段(最高优先级)
    2. 层级图标[level_icons] 中匹配的图标(按 subsubcategory → subcategory → category 顺序)
    3. 模板默认图标[template] 中的 icon 字段
    4. 系统默认图标:客户端提供的默认图标(最低优先级)

    字段说明

    字段必填说明示例
    id分类唯一标识符(小写字母、数字、下划线)"nature"
    name分类显示名称"自然风光"
    category一级分类"风景"
    subcategory二级分类"自然"
    subsubcategory三级分类"精选"
    icon分类图标(Base64 或 URL)"data:image/svg+xml;base64,..."
    description分类描述"自然风景壁纸"

    分类分组(可选)

    [[category_groups]]
    name = "热门分类"
    category_ids = ["nature", "anime", "abstract"]
    
    [[category_groups]]
    name = "每日更新"
    category_ids = ["daily", "trending"]

    完整示例

    # categories.toml
    [template]
    icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMlptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDhaIiBmaWxsPSIjNjY2Ii8+PC9zdmc+Cg=="
    category = "其他"
    
    [[categories]]
    id = "mountain"
    name = "山脉"
    category = "自然"
    subcategory = "风景"
    icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgM0w0IDIxaDE2TDEyIDNaTTEyIDcuNDQyTDkuMTAyIDE2LjVIMTQuODk2TDEyIDcuNDQyWiIgZmlsbD0iIzQyYjdkZSIvPjwvc3ZnPgo="
    
    [[categories]]
    id = "anime"
    name = "动漫"
    category = "二次元"
    icon = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMlptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDhaIiBmaWxsPSIjRkY2Njk5Ii8+PHBhdGggZD0iTTEyIDE3QzE0Ljc2MTQgMTcgMTcgMTQuNzYxNCAxNyAxMkMxNyA5LjIzODYgMTQuNzYxNCA3IDEyIDdDOS4yMzg2IDcgNyA5LjIzODYgNyAxMkM3IDE0Ljc2MTQgOS4yMzg2IDE3IDEyIDE3WiIgZmlsbD0iI0ZGNjY5OSIvPjwvc3ZnPgo="
    
    # 分类分组
    [[category_groups]]
    name = "自然分类"
    category_ids = ["mountain"]
    
    [[category_groups]]
    name = "动漫分类"
    category_ids = ["anime"]

    📡 API 文件 (apis/*.toml)

    每个 API 文件定义一个壁纸数据源。

    基础结构

    # 基本信息
    name = "API 名称"
    description = "API 功能描述"
    logo = "data:image/svg+xml;base64,..."  # Base64 图标
    
    # 分类绑定(必填)
    categories = ["category_id1", "category_id2"]
    
    # 参数定义
    [[parameters]]
    key = "param_name"
    type = "choice"  # choice, text, boolean
    label = "参数标签"
    default = "默认值"
    choices = ["选项1", "选项2"]  # choice 类型必需
    hidden = false  # 是否在 UI 中隐藏
    
    # 请求配置
    [request]
    url = "https://api.example.com/data?param={{param_name}}"
    method = "GET"  # GET 或 POST
    timeout_seconds = 10  # 覆盖全局配置
    interval_seconds = 3600  # 0=使用全局,-1=不限制
    
    # 响应配置
    [response]
    format = "json"  # json, toml, image_url, image_raw, static_list, static_dict
    type = "multi"  # single, multi
    
    # 字段映射
    [mapping]
    # 单图模式
    image = "/data/url"
    title = "/data/title"
    
    # 多图模式
    items = "/data/list"
    item_mapping = { image = "/url", title = "/name" }

    参数类型详解

    1. 选择类型 (choice)

    [[parameters]]
    key = "resolution"
    type = "choice"
    label = "分辨率"
    default = "1920x1080"
    choices = ["1920x1080", "2560x1440", "3840x2160"]
    description = "选择壁纸分辨率"

    2. 文本类型 (text)

    [[parameters]]
    key = "keyword"
    type = "text"
    label = "搜索关键词"
    default = ""
    placeholder = "输入关键词"
    min_length = 1
    max_length = 100

    3. 布尔类型 (boolean)

    [[parameters]]
    key = "safe_mode"
    type = "boolean"
    label = "安全模式"
    default = true

    4. 隐藏参数

    [[parameters]]
    key = "api_key"
    type = "text"
    default = "ABC123"
    hidden = true  # 不在UI显示,但参与请求

    响应格式

    1. JSON 格式(最常用)

    [response]
    format = "json"
    type = "multi"
    
    [mapping]
    items = "/data/wallpapers"
    item_mapping = { 
        image = "/image_url", 
        title = "/title",
        width = "/width",
        height = "/height"
    }

    2. 静态字典 (static_dict)

    [response]
    format = "static_dict"
    
    [static_dict]
    [[items]]
    image = "https://example.com/wallpaper1.jpg"
    title = "壁纸标题"
    description = "壁纸描述"
    width = 1920
    height = 1080
    
    [[items]]
    image = "https://example.com/wallpaper2.jpg"
    title = "另一个壁纸"

    3. 静态列表 (static_list)

    [response]
    format = "static_list"
    
    [static_list]
    urls = [
        "https://example.com/w1.jpg",
        "https://example.com/w2.jpg",
        "https://example.com/w3.jpg"
    ]

    4. 图片 URL (image_url)

    [response]
    format = "image_url"
    # 响应体应为单行图片URL

    5. 原始图片 (image_raw)

    [response]
    format = "image_raw"
    # 响应体应为原始图片二进制数据

    路径语法

    JSON Pointer 语法

    # 绝对路径
    image = "/data/url"
    
    # 数组索引
    image = "/data/images/0/url"
    
    # 通配符(匹配第一个)
    image = "/data/images/*/url"
    
    # 递归通配符
    image = "/**/image_url"
    
    # 多重路径(按顺序尝试)
    image = ["/images/hd_url", "/images/url", "/url"]

    点号路径语法(用于TOML格式)

    image = "data.url"
    title = "data.wallpaper.title"

    验证配置

    [validation]
    # 必需字段
    required_fields = ["image", "title"]
    
    # 字段格式验证
    field_patterns = [
        { path = "image", regex = "^https?://.+\\.(jpg|png|webp)$" },
        { path = "title", max_length = 100 }
    ]
    
    # 数据质量验证
    quality_rules = [
        { path = "width", min = 1920 },
        { path = "height", min = 1080 }
    ]

    用途

    [validation] 用于定义API 响应数据在映射(mapping/post_process)之后的校验规则,帮助客户端:

    • 过滤掉不完整/不合规的条目(如没有 image
    • 提前发现字段映射错误(路径写错、字段类型不符合预期)
    • 做最基本的数据质量门槛控制(分辨率过小、标题过长等)

    注意:验证规则描述的是“规则本身”。具体失败后是报错、提示、跳过条目还是回退到备用 API,仍由客户端结合其策略决定。

    字段说明

    字段类型说明
    required_fields字符串数组必须存在且非空的字段列表;常用于 imagetitle 等核心字段。
    field_patterns对象数组字段格式/长度等约束;每条规则以 path 指向目标字段,并附带约束条件。
    quality_rules对象数组字段数值质量门槛;常用于 width/height/size 等数值字段。

    field_patterns / quality_rules 单条规则对象支持的键(本协议当前文档示例中出现的键):

    • path(必填):字段路径(与 [mapping] 使用相同的路径语法;如果最终数据是对象则按键名取值)
    • regex(可选):正则表达式(字符串)。建议客户端使用 RE2/PCRE 等实现均可;是否区分大小写由正则本身决定。
    • min_length / max_length(可选):字符串长度约束
    • min / max(可选):数值范围约束

    示例:常见校验

    1. 要求图片必须是 HTTPS 且为常见图片扩展名:
    [validation]
    required_fields = ["image"]
    
    field_patterns = [
      { path = "image", regex = "^https://.+\\.(jpg|jpeg|png|webp)$" }
    ]
    1. 多图模式下,对每个条目要求分辨率不低于 1080p:
    [validation]
    required_fields = ["image", "width", "height"]
    
    quality_rules = [
      { path = "width", min = 1920 },
      { path = "height", min = 1080 }
    ]

    错误处理

    [error_handling]
    # HTTP状态码处理
    http_codes = [
        { code = 429, message = "请求过于频繁", retry_after = 60 },
        { code = 404, message = "内容不存在", fallback = true }
    ]
    
    # 响应处理错误
    on_empty_response = "skip"
    on_mapping_failed = "skip_item"

    用途

    [error_handling] 用于描述当请求/解析/映射出现问题时,客户端应如何处理的建议策略。它不会强制客户端的最终行为,但可让同一壁纸源在不同客户端中表现更一致。

    HTTP 状态码处理(http_codes

    http_codes 是规则数组,客户端在收到对应 HTTP 状态码时可参考执行:

    • code(必填):HTTP 状态码
    • message(可选):面向用户或日志的提示文本
    • retry_after(可选):建议等待秒数后再重试。若响应包含 Retry-After 头,建议客户端优先使用响应头。
    • fallback(可选,布尔):建议允许回退(例如尝试备用 API、返回缓存结果或跳过该 API)

    空响应与映射失败

    • on_empty_response = "skip":当响应体为空(或解析后无有效数据)时,建议“跳过本次结果”(不产生壁纸)。
    • on_mapping_failed = "skip_item":当多图模式下某个条目映射失败时,建议“仅跳过该条目”,其他条目仍可保留。

    备用 API(可选)

    文档后续最佳实践中会用到备用 API。若你需要在协议内显式声明备用 API,可在 [error_handling] 中追加:

    [error_handling]
    fallback_to = "backup_api"  # 指向 apis/backup_api.toml(按文件名基名匹配)

    建议客户端在出现以下情况时考虑使用 fallback_to(若实现支持):

    • 命中 http_codesfallback = true 的规则
    • 连续多次失败且超过 [request.retry] 的重试上限

    缓存配置

    [cache]
    enabled = true
    ttl_seconds = 86400
    key_template = "api_{{param1}}_{{date}}"

    用途

    [cache] 用于定义某个 API 的缓存建议。它通常用于缓存“API 响应”或“解析后的结果列表”,以降低请求频率并提升列表加载速度。

    重要:缓存是否启用、使用内存还是磁盘、是否加密、是否跨设备同步等均由客户端决定。即使 enabled = true,客户端也可以完全不缓存。

    字段说明

    字段类型说明
    enabled布尔是否建议对该 API 启用缓存。
    ttl_seconds整数缓存 TTL(秒)。建议根据更新频率设置:每日更新用 6-24h;小时级用 5-30min。
    key_template字符串缓存键模板。支持使用请求参数与内置变量(如 {{date_iso}} / {{date}} / {{timestamp_ms}} 等),用于区分不同参数组合的缓存。

    建议行为

    • 若 API 文件存在 [cache],建议其优先级高于 config.toml[request.cache]
    • 对于带有动态参数(如地区、关键词)的 API,建议把关键参数写入 key_template,避免缓存互相污染。

    完整 API 示例

    # apis/bing_daily.toml
    name = "Bing 每日壁纸"
    description = "微软Bing每日更新的壁纸"
    logo = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTkgMTJIMTFWN0gxOUMyMC4xMDUgNyAyMSA3Ljg5NSA3IDlWMTlDNyAxOC4xMDUgNy44OTUgMTcgOSAxN0gxN1YxMkgyMFYxOEMyMCAyMC4yMDkgMTguMjA5IDIyIDE2IDIySDhDNS43OTEgMjIgNCAyMC4yMDkgNCAxOFY2QzQgMy43OTEgNS43OTEgMiA4IDJIMTZDMTguMjA5IDIgMjAgMy43OTEgMjAgNlYxMkgxOVoiIGZpbGw9IiM0MmI3ZGUiLz48L3N2Zz4K"
    
    categories = ["daily"]
    
    [[parameters]]
    key = "mkt"
    type = "choice"
    label = "地区"
    default = "zh-CN"
    choices = ["zh-CN", "en-US", "ja-JP"]
    
    [[parameters]]
    key = "n"
    type = "choice"
    label = "数量"
    default = "8"
    choices = ["1", "5", "8", "15"]
    
    [request]
    url = "https://www.bing.com/HPImageArchive.aspx?format=js&n={{n}}&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_template = "bing_{{mkt}}_{{date}}"

    🔧 内置变量系统

    时间变量

    变量说明示例
    {{timestamp_ms}}毫秒时间戳1704067200000
    {{timestamp_s}}秒时间戳1704067200
    {{date_iso}}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_string:8}}aB3dEfG7
    {{random_int:MIN:MAX}}MIN到MAX随机整数{{random_int:1:100}}42
    {{random_hex:N}}N位随机十六进制{{random_hex:6}}a1b2c3

    屏幕变量(由客户端提供)

    变量说明示例
    {{screen_width}}屏幕宽度1920
    {{screen_height}}屏幕高度1080
    {{screen_ratio}}屏幕宽高比1.777

    📦 打包规范

    打包命令

    # 基本用法
    wallpaper-source-pack source_directory output_file.ltws
    
    # 示例
    wallpaper-source-pack ./my_source ./my_source.ltws

    打包验证

    打包工具会验证以下内容:

    1. 必需文件检查

      • source.toml 存在且有效
      • categories.toml 存在且有效
      • apis/ 目录存在且包含至少一个 .toml 文件
    2. 协议版本检查

      • scheme = "littletree_wallpaper_source_v3"
    3. 资源文件检查

      • ⚠️ 发现任何非 .toml 文件时警告
      • ❌ 不允许包含图片、字体等资源文件

    文件处理规则

    文件类型处理方式说明
    source.toml✅ 包含必需文件
    categories.toml✅ 包含必需文件
    apis/*.toml✅ 包含必需文件
    config.toml✅ 包含可选文件
    *.png, *.jpg❌ 排除不允许资源文件
    *.svg, *.ico❌ 排除不允许资源文件
    其他文件❌ 排除仅包含配置文件

    图标处理要求

    所有图标必须使用以下方式之一:

    1. Base64 编码

      logo = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMlptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDhaIiBmaWxsPSIjNDJiN2RlIi8+PC9zdmc+Cg=="
    2. 外部 URL

      logo = "https://example.com/icon.svg"

    清单文件 (manifest.json)

    打包时自动生成:

    {
      "format_version": "1.0",
      "source_schema": "littletree_wallpaper_source_v3",
      "generated_at": "2024-01-15T12:00:00Z",
      "tool_version": "wallpaper-source-pack/1.0.0",
      "files": [
        {
          "path": "source.toml",
          "sha256": "abc123...",
          "size": 1024
        }
      ],
      "metadata": {
        "name": "自然壁纸源",
        "identifier": "com.nature.wallpapers",
        "version": "1.0.0"
      }
    }

    🚀 快速开始

    步骤 1:创建文件结构

    mkdir my_wallpaper_source
    cd my_wallpaper_source
    mkdir apis

    步骤 2:创建配置文件

    source.toml:

    scheme = "littletree_wallpaper_source_v3"
    identifier = "com.my.first_source"
    name = "我的第一个壁纸源"
    version = "1.0.0"
    categories = "categories.toml"
    apis = ["apis/*.toml"]

    categories.toml:

    [[categories]]
    id = "simple"
    name = "简单壁纸"
    category = "示例"

    apis/simple_api.toml:

    name = "简单壁纸"
    categories = ["simple"]
    
    [request]
    url = "https://picsum.photos/1920/1080"
    
    [response]
    format = "image_raw"
    type = "single"

    步骤 3:打包壁纸源

    wallpaper-source-pack ./my_wallpaper_source ./my_wallpaper_source.ltws

    步骤 4:验证打包文件

    wallpaper-source-validate ./my_wallpaper_source.ltws

    ✅ 验证清单

    必需检查项

    • scheme 字段为 littletree_wallpaper_source_v3
    • source.toml 包含所有必需字段
    • categories.toml 包含至少一个分类
    • apis/ 目录包含至少一个 .toml 文件
    • 所有分类 ID 在 API 中正确引用
    • 没有包含资源文件(图片、字体等)
    • 所有图标使用 Base64 或外部 URL

    推荐检查项

    • 设置了合理的请求超时时间
    • 配置了验证规则
    • 配置了错误处理
    • 配置了缓存策略
    • 添加了有意义的描述

    🔧 开发工具

    1. 打包工具

    # 安装
    pip install wallpaper-source-tools
    
    # 使用
    wallpaper-source-pack ./source ./output.ltws
    wallpaper-source-validate ./source.ltws
    wallpaper-source-ls ./source.ltws

    2. 图标转换工具

    # 将图片转换为 Base64
    convert-to-base64 icon.png
    # 输出: data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...

    3. 配置验证工具

    # 验证目录结构
    wallpaper-source-check ./my_source
    
    # 输出:
    # ✅ source.toml: 有效
    # ✅ categories.toml: 包含 3 个分类
    # ✅ apis/: 包含 5 个 API 文件
    # ⚠️  发现本地图标引用,建议转换为 Base64

    📊 性能指标

    操作典型时间内存使用说明
    加载 .ltws 文件10-50ms2-10MB不压缩 TAR 格式
    解析配置5-20ms1-5MBTOML 解析
    初始化 API1-10ms/API可变每个 API 的初始化
    缓存命中<1ms忽略内存缓存

    📞 支持与反馈

    获取帮助

    • 文档:查看完整协议文档
    • 示例:参考官方示例壁纸源
    • 社区:加入开发者社区讨论
    • Issue:在 GitHub 提交问题报告

    报告问题

    遇到问题时,请提供:

    1. 壁纸源配置
    2. 错误信息
    3. 客户端版本
    4. 操作系统信息

    贡献指南

    1. Fork 项目仓库
    2. 创建功能分支
    3. 提交更改
    4. 创建 Pull Request

    🔀 多壁纸源分类合并(可选)

    小树壁纸 Next 客户端可能支持将多个壁纸源的分类合并显示,为用户提供统一的浏览体验。

    重要:是否执行“合并”由客户端决定;source.toml 中的 [merge] 仅用于描述当客户端选择进行合并时,各壁纸源在冲突与优先级上的建议行为。客户端可以忽略或覆盖这些建议。

    声明合并行为(供客户端在合并时参考)

    source.toml 中添加 [merge] 配置节,用于声明当分类发生合并时的行为:

    # source.toml 中的合并配置
    [merge]
    enabled = true                      # 参与合并的建议开关(默认:false;客户端可忽略/覆盖)
    strategy = "same_id"                # 合并策略:same_id(相同ID)、same_name(相同名称)
    priority = 100                      # 合并优先级(0-1000,默认:100)
    metadata_source = "high_priority"   # 元数据来源:high_priority(高优先级源)、first_loaded(最先加载)、last_updated(最后更新)
    allow_metadata_override = true      # 是否允许其他源覆盖本源的分类元数据

    合并策略详解

    1. 相同ID合并(strategy = "same_id"

    • 规则:仅合并具有相同 id 的分类
    • 示例:两个壁纸源都有 id = "nature" 的分类,合并为一个分类
    • 适用场景:标准化分类ID,实现跨源内容聚合

    2. 相同名称合并(strategy = "same_name"

    • 规则:合并具有相同 name 的分类(忽略ID差异)
    • 示例:一个源有 name = "自然风光",另一个源也有 name = "自然风光",合并为一个分类
    • 适用场景:不同源对相同主题使用不同ID但相同名称

    元数据冲突解决

    当多个壁纸源的分类合并时,按以下规则确定显示的元数据:

    1. 优先级规则(metadata_source = "high_priority"

    • 使用 priority 值最高的壁纸源的元数据
    • priority 相同时,使用版本号更高的源
    • 版本号相同时,使用最后加载的源

    2. 加载顺序规则(metadata_source = "first_loaded"

    • 使用最先加载的壁纸源的元数据
    • 简单稳定,但可能不是最优选择

    3. 更新时间规则(metadata_source = "last_updated"

    • 使用最近更新的壁纸源的元数据
    • 适合需要显示最新信息的场景

    合并示例

    源A(优先级:150)

    # categories.toml
    [[categories]]
    id = "nature"
    name = "自然风光"
    category = "风景"
    icon = "data:image/svg+xml;base64,A"
    description = "源A的自然壁纸"

    源B(优先级:100)

    # categories.toml  
    [[categories]]
    id = "nature"
    name = "自然风景"
    category = "自然"
    icon = "data:image/svg+xml;base64,B"
    description = "源B的自然壁纸"

    合并结果(使用 high_priority 策略):

    • 显示名称:“自然风光”(源A,优先级更高)
    • 分类路径:“风景”(源A,优先级更高)
    • 图标:使用源A的图标
    • 描述:“源A的自然壁纸”
    • 壁纸内容:包含源A和源B的所有壁纸

    分类分组合并

    分类分组(category_groups)也会根据合并策略进行合并:

    • 相同名称的分组合并
    • 合并后的分组包含所有源的相关分类
    • 分组元数据使用相同的优先级规则

    注意事项

    1. 性能影响:合并会增加客户端处理复杂度,建议合理设置优先级
    2. 一致性:建议相关壁纸源使用一致的分类命名规范
    3. 测试建议:在启用合并前,测试不同源的兼容性
    4. 用户控制:客户端可能允许用户手动选择合并策略或禁用特定源的合并

    最佳实践

    # 推荐配置
    [merge]
    enabled = true
    strategy = "same_id"                # 更精确的合并
    priority = 100                      # 中等优先级,允许其他源覆盖
    metadata_source = "high_priority"   # 公平的元数据选择
    allow_metadata_override = true      # 允许更好的源提供更优元数据
    
    # 特殊场景:作为基础源(不希望被覆盖)
    [merge]
    enabled = true
    strategy = "same_id"
    priority = 1000                     # 最高优先级,确保元数据不被覆盖
    metadata_source = "high_priority"
    allow_metadata_override = false     # 禁止其他源覆盖

    🎯 最佳实践

    1. 图标处理

    # 推荐:使用 Base64 编码的小图标
    logo = "data:image/svg+xml;base64,..."  # SVG 格式最佳
    
    # 可选:使用外部 CDN
    logo = "https://cdn.example.com/icon.svg"
    
    # 不推荐:大尺寸图片或本地文件
    # logo = "icon.png"  # ❌ 不允许

    2. 性能优化

    # 设置合理的缓存时间
    [cache]
    ttl_seconds = 3600  # 根据更新频率设置
    
    # 使用多图 API 减少请求次数
    [response]
    type = "multi"  # 而不是多次调用单图 API

    3. 错误处理

    # 配置降级策略
    [error_handling]
    fallback_to = "backup_api"  # 引用备用 API
    
    # 设置合理的重试策略
    [request.retry]
    max_attempts = 2  # 避免无限重试

    4. 安全性

    # 使用 HTTPS
    url = "https://api.example.com/data"  # ✅ 推荐
    
    # 隐藏敏感参数
    [[parameters]]
    key = "api_key"
    hidden = true  # 不在 UI 显示

    最后更新: 2025年12月13日
    协议版本: v3.0
    文件格式: .ltws (不压缩 TAR)
    图标要求: Base64 或外部 URL


    本协议文档适用于小树壁纸 Next(Little Tree Wallpaper Next)客户端 v1.0.0 及以上版本

    v3.0

    协议