https://github.com/kookxiang/proxy-formatter
format proxy provider list via simple script
https://github.com/kookxiang/proxy-formatter
mihomo proxy-provider shadowsocks surge
Last synced: 4 days ago
JSON representation
format proxy provider list via simple script
- Host: GitHub
- URL: https://github.com/kookxiang/proxy-formatter
- Owner: kookxiang
- License: gpl-3.0
- Created: 2025-07-10T14:21:22.000Z (11 months ago)
- Default Branch: master
- Last Pushed: 2026-05-20T05:18:49.000Z (19 days ago)
- Last Synced: 2026-05-20T08:13:20.605Z (19 days ago)
- Topics: mihomo, proxy-provider, shadowsocks, surge
- Language: Go
- Homepage:
- Size: 219 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Proxy Formatter
一个通过 HTTP 按需生成代理订阅内容的小工具。
它会读取本地配置文件,按顺序执行其中的指令,然后把结果输出成目标格式。目前内置了两类能力:
- 指令:抓取、过滤、改名、改请求头、解析 DNS、检查订阅流量等
- 格式化器:输出为 `clash`、`surge`、`loon` 或 `sing-box` 配置内容
本项目使用 `GPL-3.0` 许可证发布。
## 工作方式
每个配置文件都是一个按行执行的流水线。
- 一行一个指令
- 按出现顺序执行
- 空行会忽略
- 以 `#` 开头的行会被当作注释
- 参数支持双引号,适合包含空格的内容
例如:
```text
# 从远端获取原始订阅
fetch https://example.com/proxies.yaml
# 设置请求头
header User-Agent "Clash.Meta"
# 只保留日本节点
include /日本/
# 给节点名前面加一个标签
prefix Tokyo
# 输出为 Clash 格式
clash
```
## 常见用法
### 过滤并改名
```text
fetch https://example.com/proxies.yaml
include /香港|日本|新加坡/
exclude /剩余流量|即将到期/
emoji
replace IEPL IPLC
suffix Premium
clash
```
### 使用中转代理抓取订阅
```text
proxy http://127.0.0.1:7890
fetch https://example.com/proxies.yaml
proxy
clash
```
`proxy` 不带参数时会清空当前抓取代理设置。
### 自动处理过期或流量耗尽的订阅
```text
fetch https://example.com/proxies.yaml
check-traffic
clash
```
如果响应头中的 `Subscription-Userinfo` 表示订阅已经过期,或者总流量已经用尽,程序会清空原有节点,并注入一个提示原因的占位节点,避免部分客户端因为空列表而报错。
## 支持的指令
下面的指令都会按照配置中的顺序执行。
### fetch
从指定 URL 获取订阅内容,并在本地缓存响应。
说明:
- 支持 YAML 订阅
- 如果 YAML 解析失败,会回退尝试解析为 Base64 订阅
- 当缓存需要刷新时,会重新拉取远端内容
- 如果之前设置过 `proxy` 或 `header`,抓取时会带上这些配置
示例:
```text
fetch https://example.com/proxies.yaml
```
### fetch-external [args...]
执行本机上的第三方命令抓取订阅内容,并读取它的标准输出。
说明:
- 默认禁用,只有启动时显式传入 `-allow-external-script` 才可用
- 输出内容会先按 YAML 解析,失败后回退尝试解析为 Base64 订阅
- 适合对接已有脚本、私有 CLI 或需要特殊认证流程的外部工具
- 这是一个高风险能力,因为规则文件会直接触发本机命令执行
- 如果同时启用在线编辑,用户提交的恶意规则可能借此执行本机命令,因此不推荐与 `-editor` 一起使用
示例:
```text
fetch-external "/usr/local/bin/subfetch" "--format=yaml"
```
### fetch-once
与 `fetch` 类似,但只在本地没有缓存时拉取远端内容;一旦缓存存在,即使缓存可刷新,也优先使用缓存。
这个模式适合你希望手动控制刷新时机的场景。
### add
手动插入节点。
说明:
- JSON 可以是单个 Clash / Mihomo 节点对象
- JSON 也可以是节点数组,或包含 `proxies` 字段的对象
- 非 JSON 内容会按 Base64 解码,解码后支持 YAML / Base64 订阅或 JSON 节点
- 参数如果包含空格,需要用双引号包起来
示例:
```text
add {"name":"Manual","type":"ss","server":"127.0.0.1","port":8388,"cipher":"aes-128-gcm","password":"secret"}
add eyJwcm94aWVzIjpbeyJuYW1lIjoiTWFudWFsIiwidHlwZSI6InNzIiwic2VydmVyIjoiMTI3LjAuMC4xIiwicG9ydCI6ODM4OCwiY2lwaGVyIjoiYWVzLTEyOC1nY20iLCJwYXNzd29yZCI6InNlY3JldCJ9XX0=
```
### extend
继承并执行另一份配置,然后继续执行当前配置。
说明:
- `` 使用和访问配置文件相同的文件名规则:只支持字母、数字、下划线和短横线
- 被继承配置会在同一个执行上下文里运行,因此抓取到的节点、过滤、改名、请求头、代理设置等都会保留
- 被继承配置里的输出格式化器会被跳过,例如 `clash`、`surge`、`loon` 和 `sing-box` 不会写入最终响应
- 每次请求最多允许执行 8 次 `extend`,超过后会报错,避免循环继承
示例:
```text
# base
fetch https://example.com/proxies.yaml
exclude /过期|失效/
emoji
clash
```
```text
# hk
extend base
include 香港
prefix HK
clash
```
### include
只保留命中模式的节点名。
### exclude
移除命中模式的节点名。
模式规则:
- 普通字符串:按包含关系匹配
- `/.../`:按正则表达式匹配
示例:
```text
include 日本
exclude /过期|失效|测试/
```
### emoji
移除节点名称中的国旗 emoji。
示例:
```text
emoji
```
### replace
把节点名称中的所有 `` 替换成 ``。
模式规则:
- 普通字符串:按字面量全文替换
- `/.../`:按正则表达式替换,支持捕获组引用
示例:
```text
replace IEPL IPLC
replace "/^(HK|JP) /" "$1 Premium "
```
### prefix
给节点名称前面添加前缀。实现上这是一个“切换”操作:
- 如果节点名还没有这个前缀,就加上
- 如果已经有这个前缀,就移除
程序会自动在前缀末尾补一个空格。
示例:
```text
prefix HK
```
### suffix
给节点名称后面添加后缀,同样是“切换”操作:
- 如果节点名还没有这个后缀,就加上
- 如果已经有这个后缀,就移除
程序会自动在后缀前面补一个空格。
示例:
```text
suffix Premium
```
### freeze
把当前所有节点标记为冻结。
冻结节点不会再被后续过滤指令移除,但仍然会出现在最终输出中。
这个指令主要适合在同一个配置文件里串联多个订阅源使用:
- 先 `fetch` 第一个网址
- 对这一批节点做过滤、改名等处理
- 执行一次 `freeze`
- 再 `fetch` 下一个网址,并继续处理后面这批节点
这样前一批已经整理好的节点可以被“锁住”,不会被后续针对新订阅的过滤条件误伤。
示例:
```text
fetch https://example.com/a.yaml
include /香港|日本/
prefix A
freeze
fetch https://example.com/b.yaml
include /新加坡|美国/
prefix B
clash
```
### header [value]
设置抓取订阅时使用的请求头。
规则:
- `header `:设置请求头
- `header `:删除该请求头
示例:
```text
header User-Agent "Clash.Meta"
header Authorization "Bearer token"
header Authorization
```
### proxy [address]
设置抓取远程订阅时使用的 HTTP 代理。
规则:
- `proxy http://127.0.0.1:7890`:设置代理
- `proxy`:清空代理
### resolve [dns]
把节点服务器地址解析成 IP,并写回配置。
默认 DNS 参数为 `119.29.29.29`。
行为说明:
- 会优先返回 IPv4
- 对部分 TLS / Reality / WebSocket 相关协议,会在解析前保留原始域名到 `SNI` 或 `ServerName`
- 解析结果会缓存
示例:
```text
resolve
resolve 1.1.1.1
```
### check-traffic
检查远程响应头里的 `Subscription-Userinfo`。
当满足以下任一条件时:
- 订阅已过期
- 上传流量 + 下载流量大于等于总流量
程序会清空当前节点列表,并注入一个本地假的占位节点,节点名会显示为原因,例如“订阅已过期”或“流量已用尽”。
## 输出格式
### clash
把当前节点输出为 Clash / Mihomo 风格的 YAML:
```yaml
proxies:
- name: Example
type: ss
server: 1.2.3.4
port: 443
```
响应头会设置为:
```text
Content-Type: text/yaml; charset=utf-8
```
### surge [version]
把当前节点输出为 Surge `[Proxy]` 段格式。
当前实现只支持部分代理类型;如果遇到未实现的类型,会直接返回错误。
响应头会设置为:
```text
Content-Type: text/plain; charset=utf-8
```
### loon
把当前节点输出为 Loon 节点行格式。
当前实现只支持以下代理类型:
- `Shadowsocks`
- `Trojan`
- `VLESS`
- `VMess`
其中:
- `Shadowsocks` 支持基础格式,以及 `simple-obfs`
- `Trojan` 支持普通 TLS 与 `ws`
- `VLESS` 支持 `tcp`、`ws`、`http`,以及 `reality` 所需的 `public-key` / `short-id`
- `VMess` 支持 `tcp`、`ws`
如果遇到其它代理类型或未覆盖的传输方式,会直接返回错误。
响应头会设置为:
```text
Content-Type: text/plain; charset=utf-8
```
### sing-box [base-config-url]
把当前节点输出为 sing-box 风格的 JSON 配置。
- 不带参数时,会输出一个只包含当前代理节点的最小配置
- 带上 `base-config-url` 时,会先拉取基础配置,再把当前生成的节点合并进原有 `outbounds`
- 如果基础配置里已经存在同名 `tag`,会用当前生成的节点覆盖它
- 如果基础配置里有 `selector` / `urltest`,它们的 `outbounds` 可以写关键词,例如 `HK`、`SG`、`JP`
- 程序会把这些关键词展开成真实节点名,例如节点名里包含 `HK` 的节点会自动加入对应分组
当前实现是一个精简支持集,主要覆盖常见场景:
- `Shadowsocks`:基础格式、`simple-obfs`
- `Trojan`:`tcp`、`ws`
- `VLESS`:`tcp`、`ws`、`http`
查看 sing-box 合并示例
基础配置:
```json
{
"outbounds": [
{
"type": "selector",
"tag": "Proxy",
"outbounds": ["HK", "SG", "DIRECT"]
},
{
"type": "urltest",
"tag": "Auto",
"outbounds": ["HK", "JP"]
}
]
}
```
规则文件:
```text
fetch https://example.com/proxies.yaml
include /香港|新加坡|日本/
emoji
sing-box https://example.com/base-sing-box.json
```
如果当前生成出的节点名称里有:
- `HK IPLC 01`
- `HK IPLC 02`
- `SG Premium`
- `JP Tokyo`
那么合并后:
- `Proxy` 会展开成 `HK IPLC 01`、`HK IPLC 02`、`SG Premium`,同时保留 `DIRECT`
- `Auto` 会展开成 `HK IPLC 01`、`HK IPLC 02`、`JP Tokyo`
响应头会设置为:
```text
Content-Type: application/json; charset=utf-8
```
> [!WARNING]
> `sing-box` 当前实现是一个精简支持集,部分相对少用的协议细节和传输方式已经被收敛。如果你确实需要当前未覆盖的功能,欢迎提交 PR,或提 issue / 直接反馈。
## 部署
### 1. 构建
```bash
go build -trimpath -o proxy-formatter .
```
### 2. 编写配置文件
假设你在配置目录下放了一个 `config.txt`:
```text
fetch https://example.com/proxies.yaml
check-traffic
exclude /过期|失效/
include /香港|日本|新加坡/
emoji
prefix IPLC
clash
```
Loon 输出示例:
```text
fetch https://example.com/proxies.yaml
include /香港|日本/
loon
```
### 3. 启动服务
```bash
./proxy-formatter -dir /path/to/config -cache-dir /path/to/cache -port 15725
```
参数说明:
- `-dir`:配置文件所在目录,默认是当前工作目录
- `-cache-dir`:HTTP 抓取缓存目录,默认是系统临时目录下的 `cache`
- `-allow-external-script`:允许 `fetch-external` 执行第三方命令,默认关闭
- `-editor`:启用在线编辑器,注意需要配合 `-password` 使用
- `-password`:保存配置时需要提供的密码
- `-port`:HTTP 服务端口,默认是 `15725`
### 4. 访问生成结果
如果配置文件名是 `config.txt`,启动后可直接访问:
```text
http://localhost:15725/config.txt
```
程序会读取对应文件,逐行执行配置,并返回最终生成的订阅内容。
如果启用了 `-editor`,也可以直接在首页新建规则:
```text
http://localhost:15725/
```
如果需要重新编辑由编辑器创建的配置,可以访问:
```text
http://localhost:15725/?edit=<配置文件名>
```
保存时需要提供 `-password` 对应的密码。
## 注意事项
- 配置文件是按顺序执行的,指令顺序会直接影响结果
- 如果你需要处理带空格的参数,请使用双引号
- `fetch-once` 不会主动刷新已有缓存
- 启用 `-allow-external-script` 后,规则文件将具备执行本机命令的能力;如果再同时启用 `-editor`,用户提交的恶意规则可能被服务端直接执行,因此不推荐启用在线编辑功能
- `surge` 当前不是全协议覆盖,复杂订阅建议优先用 `clash`
## 系统服务
仓库中附带了 `proxy-formatter.service`,可用于 systemd 部署。
## License
本项目基于 `GNU General Public License v3.0` 发布,详见 [LICENSE](/Users/kookxiang/workspace/proxy-formatter/LICENSE)。