Files
sub-provider/docs/ini改造方案.md
riglen 05e0355e14 step1
2026-04-21 15:47:09 +08:00

16 KiB
Raw Blame History

可以。下面这份就是一版 “类 ACL4SSR 风格 INI/CONF 配置整体说明”,你可以直接丢给 Codex。 它刻意 不引入 YAML,只保留高密度、行导向、声明式的写法。你现在贴的配置本身已经在用 [custom]ruleset=custom_proxy_group=enable_rule_generator=trueoverwrite_original_rules=true 这套思路subconverter 现有 ACL4SSR 相关配置和外部配置 gist 里也能看到同类结构,甚至有把公共规则和公共分组拆出去再导入的写法。 (GitHub)


sub-provider 类 ACL4SSR 风格 INI 配置说明(草案)

1. 目标

将 sub-provider 的配置设计为一种 ACL4SSR-like 的高密度 INI/CONF DSL,用于:

  • 管理订阅源
  • 定义节点选择器
  • 定义代理组
  • 注册规则模块
  • 选择输出 profile
  • 生成完整 Clash/Mihomo YAML

这里的重点不是兼容标准 INI 解析器,而是:

保留 INI 的可读感 + ACL4SSR 的高密度声明风格 + 方便 Python 自定义解析


2. 设计原则

2.1 保留 ACL4SSR 的使用习惯

沿用这些核心心智模型:

  • ruleset = 规则模块 -> 目标策略组
  • group = 策略组定义
  • selector = 节点筛选器
  • source = 订阅源
  • profile = 输出方案

2.2 高密度、行导向

每一条配置尽量一行表达一个对象,方便:

  • 快速编辑
  • 批量复制
  • diff
  • 注释开关
  • 手工维护

2.3 规则正文与配置分离

  • *.list 文件只保存规则主体
  • 目标策略组由配置指定
  • 生成器负责最终拼接

2.4 不追求严格标准 INI

原因:

  • 标准 INI 不擅长重复 key
  • 不擅长表达列表对象
  • 不擅长表达高密度分组语法

因此这里定义的是:

INI-like / CONF-like 自定义配置格式


3. 文件组织

推荐结构:

config/
  base.conf
  profiles/
    default.conf
    lite.conf
    media.conf

rules/
  modules/
    Riglen.list
    LocalAreaNetwork.list
    UnBan.list
    BanAD.list
    BanProgramAD.list
    Google.list
    GoogleCN.list
    SteamCN.list
    Bing.list
    OneDrive.list
    Microsoft.list
    Apple.list
    Telegram.list
    AI.list
    OpenAi.list
    YouTube.list
    Netflix.list
    ProxyMedia.list
    ProxyGFWlist.list
    Pt.list
    ChinaDomain.list
    ChinaCompanyIp.list
    Download.list

说明

  • base.conf:全局配置、源、选择器、组定义、模块注册、内置规则
  • profiles/*.conf:不同输出方案
  • rules/modules/*.list:规则正文

4. 基础语法

4.1 注释

支持两种注释:

; 这是注释
# 这也是注释

4.2 空行

空行忽略。

4.3 键值形式

基本格式:

key = value

左右空格允许存在,解析时应 trim。

4.4 重复 key

允许重复 key。 例如:

source = ...
source = ...
selector = ...
selector = ...
group = ...
group = ...
module = ...
module = ...

解析器应将这类 key 视为“多条记录”,而不是覆盖。

4.5 大小写

建议:

  • 指令名小写
  • 值区分大小写
  • 策略组名、规则内容、正则表达式保持原样

5. 支持的指令

本方案定义以下核心指令:

  • listen
  • output_dir
  • cache_dir
  • mode
  • allow_lan
  • log_level
  • ipv6
  • append_userinfo_header
  • userinfo_source_policy

以及对象型指令:

  • source =
  • selector =
  • group =
  • module =
  • builtin =

profile 内支持:

  • name =
  • enabled =
  • sources =
  • include_modules =
  • exclude_modules =
  • include_builtins =
  • override_policy =
  • prepend_rule =
  • append_rule =

6. base.conf 说明

6.1 全局标量配置

示例

listen = 0.0.0.0:3000
output_dir = ./output
cache_dir = ./data/cache
mode = rule
allow_lan = true
log_level = info
ipv6 = false
append_userinfo_header = true
userinfo_source_policy = first_enabled_source

含义

  • listen:监听地址
  • output_dir:生成结果输出目录
  • cache_dir:缓存目录
  • modeClash 模式,通常为 rule
  • allow_lan:是否允许局域网访问
  • log_level:日志级别
  • ipv6:是否开启 IPv6
  • append_userinfo_header:是否透传订阅流量头
  • userinfo_source_policy:多源时如何选取订阅信息头

6.2 source 指令

目标

定义订阅输入源。

格式

source = key,type,value,enabled=true,cache_ttl=1800

示例

source = airport_main,url,https://example.com/sub?token=xxxx,enabled=true,cache_ttl=1800
source = local_links,file,./data/local_links.txt,enabled=false

字段说明

  • 第 1 列:key
  • 第 2 列:type
  • 第 3 列:value
  • 后续:可选命名参数

支持类型

  • url:远程订阅链接
  • file:本地文件
  • inline:内联文本
  • base64base64 内容

建议解析规则

前三列固定,后续按 k=v 解析。


6.3 selector 指令

目标

定义节点筛选器,供代理组复用。

格式

selector = key,regex

示例

selector = all,.*
selector = hk,(港|HK|hk|Hong Kong|HongKong|hongkong)
selector = jp,(日本|东京|大阪|JP|Japan)
selector = us,(美|洛杉矶|西雅图|US|United States)
selector = netflix,(NF|奈飞|解锁|Netflix|NETFLIX|Media)

含义

  • key:选择器名
  • regex:匹配节点名的正则表达式

约定

后续在 group 指令中通过 @selector_key 引用。


6.4 group 指令

这是整个 DSL 的核心。 它保留 ACL4SSR 风格的高密度分组写法。你的示例里已经大量使用 custom_proxy_group= 这种反引号分隔格式。 现有 subconverter 相关 ACL4SSR 配置里也是同类写法。(GitHub)

格式

group = 组名`类型`参数1`参数2`参数3...

成员约定

  • []组名:引用已有组
  • []DIRECT:内置 DIRECT
  • []REJECT:内置 REJECT
  • @selector_key:引用 selector 动态筛节点
  • .*:兼容保留写法,可映射为全部节点

示例

group = 🚀 节点选择`select`[]♻️ 自动选择`[]🇭🇰 香港节点`[]🇯🇵 日本节点`[]🚀 手动切换`[]DIRECT
group = 🚀 手动切换`select`@all
group = ♻️ 自动选择`url-test`@all`http://www.gstatic.com/generate_204`300,,50
group = 🇭🇰 香港节点`url-test`@hk`http://www.gstatic.com/generate_204`300,,50
group = 🇯🇵 日本节点`url-test`@jp`http://www.gstatic.com/generate_204`300,,50
group = 🎥 奈飞节点`select`@netflix
group = 🐟 漏网之鱼`select`[]DIRECT`[]🚀 节点选择`[]♻️ 自动选择

解析规则建议

select

group = 组名`select`成员1`成员2`成员3...

url-test

group = 组名`url-test`@selector`测试URL`间隔,,容差

fallback

group = 组名`fallback`@selector`测试URL`间隔,,容差

load-balance

group = 组名`load-balance`@selector`测试URL`间隔,,容差

设计建议

不要再继续沿用 custom_proxy_group= 这个旧名字。 内部 DSL 里直接统一为:

group = ...

这样更短,也更像你自己的项目语法。


6.5 module 指令

目标

注册规则模块。

格式

module = key,path,policy,order,enabled

示例

module = riglen,./rules/modules/Riglen.list,🚀 节点选择,10,true
module = lan,./rules/modules/LocalAreaNetwork.list,🎯 全球直连,20,true
module = banad,./rules/modules/BanAD.list,🛑 广告拦截,40,true
module = apple,./rules/modules/Apple.list,🍎 苹果服务,80,true
module = ai,./rules/modules/AI.list,💬 Ai平台,100,true
module = openai,./rules/modules/OpenAi.list,💬 Ai平台,101,true

字段说明

  • key:模块唯一标识
  • path:规则文件路径
  • policy:默认策略组
  • order:排序
  • enabled:默认是否启用

规则文件约定

规则文件只保存规则主体,不含目标策略组。

例如 OpenAi.list

DOMAIN-SUFFIX,openai.com
DOMAIN-SUFFIX,chatgpt.com
DOMAIN-SUFFIX,oaistatic.com

生成时补成:

DOMAIN-SUFFIX,openai.com,💬 Ai平台

6.6 builtin 指令

目标

定义不来自 .list 文件的内置规则。

格式

builtin = key,type,value,policy,order,enabled

示例

builtin = geoip_cn,GEOIP,CN,🎯 全球直连,9000,true
builtin = final,FINAL,,🐟 漏网之鱼,9999,true

映射规则

  • GEOIP + CN + 🎯 全球直连 -> GEOIP,CN,🎯 全球直连
  • FINAL + 🐟 漏网之鱼 -> MATCH,🐟 漏网之鱼

说明

这里保留了 ACL4SSR 配置里 []GEOIP,CN[]FINAL 这种内置规则思想,只是换成更适合你项目的数据化声明。你的现有配置里已经有这两类用法。 (GitHub)


7. profile 配置说明

每个 profile 一个文件,放在 config/profiles/ 下。


7.1 基本字段

示例

name = 默认完整配置
enabled = true

sources = airport_main
include_modules = riglen,lan,unban,banad,apple,telegram,ai,openai
exclude_modules =
include_builtins = geoip_cn,final

含义

  • nameprofile 名称
  • enabled:是否启用
  • sources:本 profile 使用哪些订阅源
  • include_modules:启用哪些模块
  • exclude_modules:从启用列表中排除哪些模块
  • include_builtins:启用哪些内置规则

7.2 override_policy 指令

目标

覆盖模块默认策略组。

格式

override_policy = module_key,new_policy

示例

override_policy = apple,🚀 节点选择
override_policy = ai,💬 Ai平台

含义

例如某模块默认是 🍎 苹果服务,某 profile 想改成 🚀 节点选择,就在 profile 里覆盖。


7.3 prepend_rule / append_rule 指令

目标

给特定 profile 注入自定义规则。

示例

prepend_rule = DOMAIN-SUFFIX,internal.example.com,DIRECT
append_rule = DOMAIN-SUFFIX,test.example.com,🚀 节点选择

含义

  • prepend_rule:插在 rules 最前
  • append_rule:插在 builtin 之前或之后,由实现约定

建议

MATCH / FINAL 仍应最后输出。


8. 解析器行为规范

8.1 base.conf

解析器应支持:

  • 普通标量键值
  • 多条 source
  • 多条 selector
  • 多条 group
  • 多条 module
  • 多条 builtin

8.2 profile.conf

解析器应支持:

  • 普通标量键值
  • 多条 override_policy
  • 多条 prepend_rule
  • 多条 append_rule

8.3 字段 trim

建议默认:

  • 去掉左右空白
  • 不改动组名内部空格
  • 不改动正则原文

8.4 布尔值

支持:

  • true/false
  • yes/no
  • 1/0

内部统一成布尔值。

8.5 列表字段

例如:

sources = airport_main,local_links
include_modules = apple,ai,openai

按逗号切分trim 后转数组。

8.6 module/source 的 CSV 解析

建议用 Python csv 模块解析逗号分隔,而不是简单 split(","),避免后续扩展时出问题。

8.7 group 的反引号解析

建议:

  1. 去掉前缀 group =
  2. 按反引号 ` 分段
  3. 第一段为组名
  4. 第二段为类型
  5. 后续段按组类型解释

9. 生成流程规范

生成器处理顺序建议如下:

第 1 步:加载 base.conf

构建:

  • 源表
  • selector 表
  • group 定义表
  • module 注册表
  • builtin 注册表

第 2 步:加载指定 profile.conf

得到:

  • 使用哪些源
  • 启用哪些模块
  • 启用哪些 builtin
  • policy override
  • prepend/append 规则

第 3 步:拉取并解析节点

  • 拉 URL 订阅
  • 读本地文件
  • 统一解析为节点对象
  • 去重 / 重命名 / 过滤

第 4 步:按 selector 构建节点集合

例如:

  • hk -> 匹配香港节点
  • us -> 匹配美国节点
  • all -> 全部节点

第 5 步:构建 proxy-groups

解析 group = ... 指令,生成最终组定义。

第 6 步:构建 rules

  1. 按模块顺序加载 .list
  2. 对每行规则补上目标 policy
  3. 应用 override_policy
  4. 加入 prepend_rule
  5. 加入 builtin
  6. 加入 append_rule
  7. 确保 FINAL/MATCH 最后

第 7 步:渲染完整 YAML

这里是生成器内部输出,不需要在配置层暴露 YAML 结构给用户。


10. 错误处理建议

以下情况应报错并指出行号:

  • 未知指令
  • group 语法不合法
  • module 路径不存在
  • profile 引用了不存在的 source
  • profile 引用了不存在的 module
  • override_policy 指向未知模块
  • @selector_key 未定义
  • builtin 类型不支持

以下情况可仅 warning

  • selector 匹配不到节点
  • group 最终成员为空
  • 模块文件为空
  • 规则重复

11. 兼容性策略建议

11.1 兼容旧 ACL4SSR 心智模型

虽然这是你自己的 DSL但建议

  • 注释继续支持 ;
  • 保留 ruleset -> policy 的思想
  • 保留高密度 group 行语法
  • 保留 GEOIP / FINAL 的 builtin 概念

11.2 不必兼容旧关键字原样

内部不建议继续沿用:

  • ruleset=
  • custom_proxy_group=

建议统一改成更短的:

  • module =
  • group =

这样语义更清晰:

  • module 是规则模块注册
  • group 是代理组定义

12. 最小示例

12.1 base.conf

listen = 0.0.0.0:3000
mode = rule
allow_lan = true
log_level = info

source = airport_main,url,https://example.com/sub?token=xxxx,enabled=true,cache_ttl=1800

selector = all,.*
selector = hk,(港|HK|hk|Hong Kong|HongKong|hongkong)
selector = us,(美|US|United States)

group = 🚀 节点选择`select`[]♻️ 自动选择`[]🇭🇰 香港节点`[]🇺🇲 美国节点`[]DIRECT
group = ♻️ 自动选择`url-test`@all`http://www.gstatic.com/generate_204`300,,50
group = 🇭🇰 香港节点`url-test`@hk`http://www.gstatic.com/generate_204`300,,50
group = 🇺🇲 美国节点`url-test`@us`http://www.gstatic.com/generate_204`300,,150
group = 🐟 漏网之鱼`select`[]DIRECT`[]🚀 节点选择

module = apple,./rules/modules/Apple.list,🍎 苹果服务,80,true
module = openai,./rules/modules/OpenAi.list,💬 Ai平台,100,true

builtin = geoip_cn,GEOIP,CN,🎯 全球直连,9000,true
builtin = final,FINAL,,🐟 漏网之鱼,9999,true

12.2 profiles/default.conf

name = 默认完整配置
enabled = true

sources = airport_main
include_modules = apple,openai
exclude_modules =
include_builtins = geoip_cn,final

override_policy = apple,🚀 节点选择
prepend_rule = DOMAIN-SUFFIX,internal.example.com,DIRECT

13. 给 Codex 的实现要求

你可以直接把下面这段交给 Codex

请为 sub-provider 设计并实现一套类 ACL4SSR 风格的 INI/CONF 配置系统,不要引入 YAML 配置层。

目标:
- 使用高密度、行导向、声明式配置
- 保留 ACL4SSR 的使用习惯,但不要求 100% 兼容其原始关键字
- 规则正文继续使用 rules/modules/*.list
- 配置文件负责声明:
  - source
  - selector
  - group
  - module
  - builtin
  - profile

要求:
1. base.conf 负责全局配置、source、selector、group、module、builtin。
2. profiles/*.conf 负责具体输出 profile。
3. group 使用反引号分隔的 ACL4SSR-like 语法。
4. module 指向规则文件路径和默认策略组。
5. builtin 用于表达 GEOIP、FINAL 这类内置规则。
6. 生成器读取这些 conf 文件后,生成完整 Clash/Mihomo YAML。
7. 不要接数据库,不要做面板。
8. 解析器要能给出清晰的行号错误提示。
9. profile 支持 override_policy、prepend_rule、append_rule。
10. 先实现最小可用版本,再逐步扩展。

14. 最终结论

你现在最适合的路线,就是:

规则正文继续放 .list 配置层改成类 ACL4SSR 风格的 .conf Python 写一个轻量 parser + generator 最终输出完整 YAML

这条路最顺,也最符合你现在的使用习惯。