Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #1

Merged
merged 8 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 49 additions & 17 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Build and Push to GHCR

on:
push:
branches:
- dev
tags:
- '*'
workflow_dispatch:
Expand All @@ -11,21 +13,51 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}:latest
- name: Check out code
uses: actions/checkout@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set tag name
id: set_tag
run: |
if [[ $GITHUB_REF == refs/heads/* ]]; then
echo "::set-output name=tag::$(echo $GITHUB_REF | cut -d'/' -f3)"
else
echo "::set-output name=tag::${{ github.ref_name }}"
fi

- name: Check if triggered by tag
id: check_tag
run: |
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "::set-output name=triggered_by_tag::true"
else
echo "::set-output name=triggered_by_tag::false"
fi

- name: Build and push Docker image for dev branch
if: steps.check_tag.outputs.triggered_by_tag == 'false'
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}:${{ steps.set_tag.outputs.tag }}

- name: Build and push Docker image for tags
if: steps.check_tag.outputs.triggered_by_tag == 'true'
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.set_tag.outputs.tag }}
ghcr.io/${{ github.repository }}:latest

3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o sub2clash

FROM alpine:latest

# 设置工作目录
WORKDIR /app

# 从 builder 镜像中复制出编译好的二进制文件
COPY --from=builder /app/sub2clash /app/sub2clash

Expand Down
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,17 @@

获取 Clash/Clash.Meta 配置链接

| Query 参数 | 类型 | 是否必须 | 说明 |
|--------------|--------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| sub | string | sub/proxy 至少有一项存在 | 订阅链接(可以输入多个,用 `,` 分隔) |
| proxy | string | sub/proxy 至少有一项存在 | 节点分享链接(可以输入多个,用 `,` 分隔) |
| refresh | bool | 否(默认 `false`) | 强制刷新配置(默认缓存 5 分钟) |
| template | string | 否 | 外部模板 |
| ruleProvider | string | 否 | 格式 `[Behavior,Url,Group,Prepend],[Behavior,Url,Group,Prepend],...`,其中 `Group` 是该规则集所走的策略组名,`Prepend` 为 bool 类型,如果为 `true` 规则将被添加到规则列表顶部,否则添加到规则列表底部(会调整到MATCH规则之前) |
| rule | string | 否 | 格式 `[Rule,Prepend],[Rule,Prepend]...`,其中 `Prepend` 为 bool 类型,如果为 `true` 规则将被添加到规则列表顶部,否则添加到规则列表底部(会调整到MATCH规则之前) |
| autoTest | bool | 否(默认 `false`) | 指定国家策略组是否自动测速 |
| lazy | bool | 否(默认 `false`) | 自动测速是否启用 lazy |
| Query 参数 | 类型 | 是否必须 | 默认值 | 说明 |
|--------------|--------|-------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| sub | string | sub/proxy 至少有一项存在 | - | 订阅链接(可以输入多个,用 `,` 分隔) |
| proxy | string | sub/proxy 至少有一项存在 | - | 节点分享链接(可以输入多个,用 `,` 分隔) |
| refresh | bool | 否 | `false` | 强制刷新配置(默认缓存 5 分钟) |
| template | string | 否 | - | 外部模板链接或内部模板名称 |
| ruleProvider | string | 否 | - | 格式 `[Behavior,Url,Group,Prepend,Name],[Behavior,Url,Group,Prepend,Name]...`,其中 `Group` 是该规则集所走的策略组名,`Prepend` 为 bool 类型,如果为 `true` 规则将被添加到规则列表顶部,否则添加到规则列表底部(会调整到MATCH规则之前) |
| rule | string | 否 | - | 格式 `[Rule,Prepend],[Rule,Prepend]...`,其中 `Prepend` 为 bool 类型,如果为 `true` 规则将被添加到规则列表顶部,否则添加到规则列表底部(会调整到MATCH规则之前) |
| autoTest | bool | 否 | `false` | 指定国家策略组是否自动测速 |
| lazy | bool | 否 | `false` | 自动测速是否启用 lazy |
| sort | string | 否 | `nameasc` | 国家策略组排序策略,可选值 `nameasc`、`namedesc`、`sizeasc`、`sizedesc` |

## 默认模板

Expand All @@ -63,3 +64,4 @@

## TODO

- [ ] 可视化面板
57 changes: 51 additions & 6 deletions api/controller/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"errors"
"gopkg.in/yaml.v3"
"net/url"
"regexp"
"strings"
"sub2clash/model"
Expand All @@ -17,13 +18,16 @@ func BuildSub(query validator.SubQuery, template string) (
*model.Subscription, error,
) {
// 定义变量
var externalTemplate = query.Template != ""
var temp *model.Subscription
var sub *model.Subscription
var err error
var templateBytes []byte
// 加载模板
if !externalTemplate {
if query.Template != "" {
template = query.Template
}
_, err = url.ParseRequestURI(template)
if err != nil {
templateBytes, err = utils.LoadTemplate(template)
if err != nil {
return nil, errors.New("加载模板失败: " + err.Error())
Expand Down Expand Up @@ -63,10 +67,14 @@ func BuildSub(query validator.SubQuery, template string) (
} else {
proxyList = sub.Proxies
}
utils.AddProxy(temp, query.AutoTest, query.Lazy, proxyList...)
utils.AddProxy(sub, query.AutoTest, query.Lazy, query.Sort, proxyList...)
}
// 处理自定义代理
utils.AddProxy(temp, query.AutoTest, query.Lazy, utils.ParseProxy(query.Proxies...)...)
utils.AddProxy(
sub, query.AutoTest, query.Lazy, query.Sort,
utils.ParseProxy(query.Proxies...)...,
)
MergeSubAndTemplate(temp, sub)
// 处理自定义规则
for _, v := range query.Rules {
if v.Prepend {
Expand All @@ -88,13 +96,50 @@ func BuildSub(query validator.SubQuery, template string) (
}
if v.Prepend {
utils.PrependRuleProvider(
temp, name, v.Group, provider,
temp, v.Name, v.Group, provider,
)
} else {
utils.AppenddRuleProvider(
temp, name, v.Group, provider,
temp, v.Name, v.Group, provider,
)
}
}
return temp, nil
}

func MergeSubAndTemplate(temp *model.Subscription, sub *model.Subscription) {
// 只合并节点、策略组
// 统计所有国家策略组名称
var countryGroupNames []string
for _, proxyGroup := range sub.ProxyGroups {
if proxyGroup.IsCountryGrop {
countryGroupNames = append(
countryGroupNames, proxyGroup.Name,
)
}
}
// 将订阅中的节点添加到模板中
temp.Proxies = append(temp.Proxies, sub.Proxies...)
// 将订阅中的策略组添加到模板中
skipGroups := []string{"全球直连", "广告拦截", "手动切换"}
for i := range temp.ProxyGroups {
skip := false
for _, v := range skipGroups {
if strings.Contains(temp.ProxyGroups[i].Name, v) {
if v == "手动切换" {
proxies := make([]string, 0, len(sub.Proxies))
for _, p := range sub.Proxies {
proxies = append(proxies, p.Name)
}
temp.ProxyGroups[i].Proxies = proxies
}
skip = true
continue
}
}
if !skip {
temp.ProxyGroups[i].Proxies = append(temp.ProxyGroups[i].Proxies, countryGroupNames...)
}
}
temp.ProxyGroups = append(temp.ProxyGroups, sub.ProxyGroups...)
}
58 changes: 58 additions & 0 deletions model/proxy_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package model

import (
"golang.org/x/text/collate"
"golang.org/x/text/language"
)

type ProxyGroup struct {
Name string `yaml:"name,omitempty"`
Type string `yaml:"type,omitempty"`
Proxies []string `yaml:"proxies,omitempty"`
IsCountryGrop bool `yaml:"-"`
Url string `yaml:"url,omitempty"`
Interval int `yaml:"interval,omitempty"`
Tolerance int `yaml:"tolerance,omitempty"`
Lazy bool `yaml:"lazy"`
Size int `yaml:"-"`
}

type ProxyGroupsSortByName []ProxyGroup
type ProxyGroupsSortBySize []ProxyGroup

func (p ProxyGroupsSortByName) Len() int {
return len(p)
}
func (p ProxyGroupsSortBySize) Len() int {
return len(p)
}

func (p ProxyGroupsSortByName) Less(i, j int) bool {
// 定义一组备选语言:首选英语,其次中文
tags := []language.Tag{
language.English,
language.Chinese,
}
matcher := language.NewMatcher(tags)

// 假设我们的请求语言是 "zh"(中文),则使用匹配器找到最佳匹配的语言
bestMatch, _, _ := matcher.Match(language.Make("zh"))
// 使用最佳匹配的语言进行排序
c := collate.New(bestMatch)

return c.CompareString(p[i].Name, p[j].Name) < 0
}

func (p ProxyGroupsSortBySize) Less(i, j int) bool {
if p[i].Size == p[j].Size {
return p[i].Name < p[j].Name
}
return p[i].Size < p[j].Size
}

func (p ProxyGroupsSortByName) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func (p ProxyGroupsSortBySize) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
11 changes: 0 additions & 11 deletions model/sub.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,6 @@ type Subscription struct {
RuleProviders map[string]RuleProvider `yaml:"rule-providers,omitempty,omitempty"`
}

type ProxyGroup struct {
Name string `yaml:"name,omitempty"`
Type string `yaml:"type,omitempty"`
Proxies []string `yaml:"proxies,omitempty"`
IsCountryGrop bool `yaml:"-"`
Url string `yaml:"url,omitempty"`
Interval int `yaml:"interval,omitempty"`
Tolerance int `yaml:"tolerance,omitempty"`
Lazy bool `yaml:"lazy"`
}

type RuleProvider struct {
Type string `yaml:"type,omitempty"`
Behavior string `yaml:"behavior,omitempty"`
Expand Down
7 changes: 3 additions & 4 deletions templates/template_meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,12 @@ proxy-groups:
rules:
- GEOSITE,private,全球直连
- GEOIP,private,全球直连
- GEOSITE,category-ads-all,广告拦截
- GEOSITE,CN,全球直连
- GEOIP,CN,全球直连
- GEOSITE,biliintl,哔哩哔哩
- GEOSITE,bilibili,哔哩哔哩
- GEOSITE,bahamut,巴哈姆特
- GEOSITE,CN,全球直连
- GEOIP,CN,全球直连
- GEOSITE,category-games,游戏平台
- GEOSITE,geolocation-!cn,节点选择
- GEOIP,ad,广告拦截
- GEOSITE,category-ads-all,广告拦截
- MATCH,漏网之鱼
Loading
Loading