diff --git a/.gitea/workflows/generate-rules.yml b/.gitea/workflows/generate-rules.yml index 801766239..fcb2b6bf5 100644 --- a/.gitea/workflows/generate-rules.yml +++ b/.gitea/workflows/generate-rules.yml @@ -25,13 +25,13 @@ jobs: - name: Prepare config shell: bash run: | - if [ -f config.toml ]; then - echo "Use existing config.toml" - elif [ -f config.json ]; then - echo "Use existing config.json" - elif [ -f config.example.toml ]; then - cp config.example.toml config.toml - echo "Generated config.toml from example" + if [ -f configs/config.toml ]; then + echo "Use existing configs/config.toml" + elif [ -f configs/config.json ]; then + echo "Use existing configs/config.json" + elif [ -f configs/examples/config.example.toml ]; then + cp configs/examples/config.example.toml configs/config.toml + echo "Generated configs/config.toml from example" else echo "No config file found" >&2 exit 1 @@ -43,9 +43,9 @@ jobs: UPSTREAM_REF: ${{ vars.UPSTREAM_REF }} run: | UPSTREAM_REF="${UPSTREAM_REF:-master}" - bash scripts/sync_surge_full.sh - if [ -f config.toml ]; then - python3 main.py --config config.toml + bash tools/sync_surge_full.sh + if [ -f configs/config.toml ]; then + python3 src/rulegen.py --config configs/config.toml else - python3 main.py --config config.json + python3 src/rulegen.py --config configs/config.json fi diff --git a/.gitea/workflows/repo-manage-daily.yml b/.gitea/workflows/repo-manage-daily.yml index 0621b2205..8e117dea9 100644 --- a/.gitea/workflows/repo-manage-daily.yml +++ b/.gitea/workflows/repo-manage-daily.yml @@ -30,13 +30,13 @@ jobs: - name: Prepare config shell: bash run: | - if [ -f config.toml ]; then - echo "Use existing config.toml" - elif [ -f config.json ]; then - echo "Use existing config.json" - elif [ -f config.example.toml ]; then - cp config.example.toml config.toml - echo "Generated config.toml from example" + if [ -f configs/config.toml ]; then + echo "Use existing configs/config.toml" + elif [ -f configs/config.json ]; then + echo "Use existing configs/config.json" + elif [ -f configs/examples/config.example.toml ]; then + cp configs/examples/config.example.toml configs/config.toml + echo "Generated configs/config.toml from example" else echo "No config file found" >&2 exit 1 @@ -49,11 +49,11 @@ jobs: run: | set -euo pipefail UPSTREAM_REF="${UPSTREAM_REF:-master}" - bash scripts/sync_surge_full.sh - if [ -f config.toml ]; then - python3 main.py --config config.toml + bash tools/sync_surge_full.sh + if [ -f configs/config.toml ]; then + python3 src/rulegen.py --config configs/config.toml else - python3 main.py --config config.json + python3 src/rulegen.py --config configs/config.json fi - name: Commit and push builder updates diff --git a/.gitignore b/.gitignore index 68c467f7f..563d1c0e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ __pycache__/ *.pyc -config.toml -upstream/ +configs/config.toml +data/upstream/ diff --git a/README.md b/README.md index 3c55ad499..3a4efd6ce 100644 --- a/README.md +++ b/README.md @@ -1,135 +1,28 @@ # shunt-rules -基于 **Surge 单源** 的规则生成器: +基于 **Surge 单源** 的规则生成器,统一输出 `Surge / Loon / Clash / Mihomo` 四种格式。 -1. 同步上游 `ios_rule_script` 的 `rule/Surge` 到本地缓存 -2. 本地按分类做合并去重 -3. 统一生成多端兼容规则 +## 目标 -当前输出目录: - -- `dist/surge/.list` -- `dist/loon/.list` -- `dist/clash/.yaml` -- `dist/mihomo/.yaml` - -## 设计原则 - -- 上游只用 `Surge` 源,不直接拉 `Clash` 源 -- `Clash`/`Mihomo` 均由 Surge 规则转换生成 -- 本地先合并再转换,避免依赖远端即时拼接 - -## 运行环境 - -- Python 3.11+(推荐,支持 TOML 配置) -- Python 3.10(可用 JSON 配置) - -## 快速开始 - -```bash -cd /Users/yuan/Desktop/workspaces/docker/pve/shunt-rules -``` - -1. 同步上游 Surge 全量源到本地缓存: - -```bash -bash scripts/sync_surge_full.sh -``` - -2. 生成全部分类规则: - -```bash -python3 main.py --config config.json -``` - -3. 只生成指定分类: - -```bash -python3 main.py --config config.json --names Apple,YouTube -``` - -## 配置说明 - -默认配置文件:`config.json`(已启用本地源模式)。 - -### `source` 关键字段 - -- `mode` - - `local`:从本地缓存读取(推荐) - - `gitea`:从 Gitea API 直接读取 -- `local_root`:本地缓存根目录(默认 `upstream`) -- `root`:规则目录(默认 `rule/Surge`) -- `filename_pattern`:分类主文件模板(默认 `{name}.list`) -- `include_categories`:仅生成白名单分类 -- `exclude_categories`:排除分类(默认排除仅聚合目录) - -### `output` 关键字段 - -- `dir`:输出目录(默认 `dist`) -- `clash_no_resolve`:Clash 的 `IP-CIDR/IP-CIDR6` 是否追加 `no-resolve` -- `mihomo_no_resolve`:Mihomo 的 `IP-CIDR/IP-CIDR6` 是否追加 `no-resolve` - -## 本地合并规则(核心) - -每个分类优先按以下顺序合并去重: - -1. `.list` -2. `_Domain.list` -3. `_Resolve.list` - -如果某分类不完整,会自动回退到: - -- `_All.list` -- `_Domain.list` -- `_Resolve.list` -- `.list` - -另外,`*_Domain.list` 中无前缀的裸域名会自动规范化为 `DOMAIN-SUFFIX,`。 - -## 多端转换策略 - -- `surge`:保留合并后的 Surge 规则 -- `loon`:与 Surge 规则兼容输出 -- `clash`:YAML provider 输出,类型适配: - - 跳过:`USER-AGENT`、`URL-REGEX` - - 映射:`DEST-PORT -> DST-PORT` -- `mihomo`:YAML provider 输出,规则与 Clash 同步适配 - -## 自动化 - -### 1) 全仓库自动管理(推荐) - -文件:`.gitea/workflows/repo-manage-daily.yml` - -- 触发:每天一次(`cron: 5 2 * * *`,UTC)+ 手动触发 -- 流程: - 1. 同步上游 Surge 源 - 2. 生成 `dist/` 规则 - 3. 自动提交并推送当前仓库变更 - -需要配置: - -- `vars.UPSTREAM_REF`(可选,默认 `master`) - -### 2) 手动生成工作流(备用) - -文件:`.gitea/workflows/generate-rules.yml` - -- 触发:手动触发 -- 流程:同步上游并生成规则(不自动发布) +- 上游仅使用 `ios_rule_script` 的 `rule/Surge` +- 本地先合并与去重,再做多端格式转换 +- 输出规则可直接用于常见代理客户端 ## 目录结构 ```text shunt-rules/ -├── main.py -├── config.json -├── config.example.toml -├── config.example.json -├── scripts/ -│ └── sync_surge_full.sh -├── upstream/ # 本地上游缓存(自动生成,默认忽略) -│ └── rule/Surge/... +├── src/ +│ └── rulegen.py # 主程序入口 +├── tools/ +│ └── sync_surge_full.sh # 同步上游 Surge 源到本地缓存 +├── configs/ +│ ├── config.json # 默认配置(本地缓存模式) +│ └── examples/ +│ ├── config.example.json +│ └── config.example.toml +├── data/ +│ └── upstream/ # 本地上游缓存(自动生成,默认忽略) ├── dist/ │ ├── surge/ │ ├── loon/ @@ -139,3 +32,96 @@ shunt-rules/ ├── repo-manage-daily.yml └── generate-rules.yml ``` + +## 运行环境 + +- Python 3.11+(推荐,支持 TOML 配置) +- Python 3.10(可用 JSON 配置) + +## 快速开始 + +在仓库根目录执行: + +1. 同步上游 Surge 源到本地缓存 + +```bash +bash tools/sync_surge_full.sh +``` + +2. 生成全部分类规则 + +```bash +python3 src/rulegen.py --config configs/config.json +``` + +3. 只生成指定分类 + +```bash +python3 src/rulegen.py --config configs/config.json --names Apple,YouTube +``` + +## 输出路径 + +- `dist/surge/.list` +- `dist/loon/.list` +- `dist/clash/.yaml` +- `dist/mihomo/.yaml` + +## 配置说明 + +默认配置:`configs/config.json` + +`source` 关键字段: + +- `mode`:数据源模式,支持 `local`(本地缓存,推荐)和 `gitea`(通过 Gitea API) +- `local_root`:本地缓存根目录(默认 `data/upstream`) +- `root`:规则目录(默认 `rule/Surge`) +- `filename_pattern`:分类主文件模板(默认 `{name}.list`) +- `include_categories`:仅生成白名单分类 +- `exclude_categories`:排除分类 + +`output` 关键字段: + +- `dir`:输出目录(默认 `dist`) +- `clash_no_resolve`:Clash 的 `IP-CIDR/IP-CIDR6` 是否追加 `no-resolve` +- `mihomo_no_resolve`:Mihomo 的 `IP-CIDR/IP-CIDR6` 是否追加 `no-resolve` + +## 本地合并规则 + +每个分类优先按以下顺序合并去重: + +1. `.list` +2. `_Domain.list` +3. `_Resolve.list` + +若上述文件不存在,会自动回退到: + +1. `_All.list` +2. `_Domain.list` +3. `_Resolve.list` +4. `.list` + +另外,`*_Domain.list` 中的裸域名会自动规范化为 `DOMAIN-SUFFIX,`。 + +## 多端转换策略 + +- `surge`:保留合并后的 Surge 规则 +- `loon`:与 Surge 规则兼容输出 +- `clash`:YAML provider 输出(跳过 `USER-AGENT`、`URL-REGEX`,并将 `DEST-PORT` 转为 `DST-PORT`) +- `mihomo`:YAML provider 输出,转换策略与 Clash 一致 + +## 自动化工作流 + +`repo-manage-daily.yml`: + +- 每天自动执行(UTC `5 2 * * *`)或手动触发 +- 执行同步、生成规则、自动提交推送 + +`generate-rules.yml`: + +- 手动触发 +- 执行同步与生成,不自动发布 + +可选变量: + +- `vars.UPSTREAM_REF`(默认 `master`) diff --git a/config.json b/configs/config.json similarity index 93% rename from config.json rename to configs/config.json index 5e408a5bb..9f2e5350f 100644 --- a/config.json +++ b/configs/config.json @@ -15,7 +15,7 @@ "Assassin'sCreed" ], "mode": "local", - "local_root": "upstream" + "local_root": "data/upstream" }, "output": { "dir": "dist", diff --git a/config.example.json b/configs/examples/config.example.json similarity index 92% rename from config.example.json rename to configs/examples/config.example.json index 502d76882..56791688b 100644 --- a/config.example.json +++ b/configs/examples/config.example.json @@ -8,7 +8,7 @@ }, "source": { "mode": "local", - "local_root": "upstream", + "local_root": "data/upstream", "root": "rule/Surge", "filename_pattern": "{name}.list", "include_categories": [], diff --git a/config.example.toml b/configs/examples/config.example.toml similarity index 95% rename from config.example.toml rename to configs/examples/config.example.toml index e58976aec..07350d3db 100644 --- a/config.example.toml +++ b/configs/examples/config.example.toml @@ -9,7 +9,7 @@ token_env = "GITEA_TOKEN" # mode=gitea: read source via Gitea API # mode=local: read source from local filesystem cache (recommended with sync script) mode = "local" -local_root = "upstream" +local_root = "data/upstream" # Usually this is where Surge source rules are stored. root = "rule/Surge" filename_pattern = "{name}.list" diff --git a/main.py b/src/rulegen.py similarity index 99% rename from main.py rename to src/rulegen.py index 16fbb84ba..1bcd14f2e 100644 --- a/main.py +++ b/src/rulegen.py @@ -472,7 +472,7 @@ def build_one_category(client: GiteaClient, cfg: Config, name: str, base_out: Pa def parse_args() -> argparse.Namespace: p = argparse.ArgumentParser(description="Generate Surge/Loon/Clash/Mihomo rules from Gitea source repo.") - p.add_argument("--config", default="config.toml", help="Path to config TOML file") + p.add_argument("--config", default="configs/config.toml", help="Path to config JSON/TOML file") p.add_argument("--names", default="", help="Comma-separated category names, e.g. YouTube,Netflix") return p.parse_args() diff --git a/scripts/sync_surge_full.sh b/tools/sync_surge_full.sh similarity index 90% rename from scripts/sync_surge_full.sh rename to tools/sync_surge_full.sh index 39d53e1d3..f0e5511a7 100755 --- a/scripts/sync_surge_full.sh +++ b/tools/sync_surge_full.sh @@ -5,7 +5,7 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TMP_DIR="$(mktemp -d)" UPSTREAM_REPO_URL="${UPSTREAM_REPO_URL:-https://github.com/blackmatrix7/ios_rule_script.git}" UPSTREAM_REF="${UPSTREAM_REF:-master}" -TARGET_DIR="${ROOT_DIR}/upstream" +TARGET_DIR="${ROOT_DIR}/data/upstream" cleanup() { rm -rf "$TMP_DIR" @@ -25,7 +25,7 @@ UPSTREAM_DATE="$(git -C "$TMP_DIR/upstream" show -s --date=iso --format=%cd HEAD cat > "$TARGET_DIR/README.md" <