mirror of
https://github.com/nitezs/sub2sing-box.git
synced 2024-12-23 15:24:42 -05:00
update
This commit is contained in:
parent
665da8fc45
commit
daa3ab6867
@ -13,5 +13,5 @@ Flags:
|
||||
-o, --output string output file path
|
||||
-p, --proxy strings common proxies
|
||||
-s, --subscription strings subscription urls
|
||||
-t, --template string path of template file
|
||||
-t, --template string template file path
|
||||
```
|
114
cmd/convert.go
114
cmd/convert.go
@ -15,6 +15,8 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
//TODO: 过滤、去重、分组、排序
|
||||
|
||||
var convertCmd = &cobra.Command{
|
||||
Use: "convert",
|
||||
Long: "Convert common proxy to sing-box proxy",
|
||||
@ -24,63 +26,57 @@ var convertCmd = &cobra.Command{
|
||||
proxies, _ := cmd.Flags().GetStringSlice("proxy")
|
||||
template, _ := cmd.Flags().GetString("template")
|
||||
output, _ := cmd.Flags().GetString("output")
|
||||
if template == "" {
|
||||
proxyList, err := ConvertSubscriptionsToSProxy(subscriptions)
|
||||
result := ""
|
||||
var err error
|
||||
|
||||
proxyList, err := ConvertSubscriptionsToSProxy(subscriptions)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for _, proxy := range proxies {
|
||||
p, err := ConvertCProxyToSProxy(proxy)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for _, p := range proxies {
|
||||
result, err := ConvertCProxyToSProxy(p)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
proxyList = append(proxyList, result)
|
||||
}
|
||||
result, err := json.Marshal(proxyList)
|
||||
proxyList = append(proxyList, p)
|
||||
}
|
||||
|
||||
if template != "" {
|
||||
result, err = MergeTemplate(proxyList, template)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if output != "" {
|
||||
err = os.WriteFile(output, result, 0666)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
fmt.Println(string(result))
|
||||
}
|
||||
} else {
|
||||
config, err := ConvertWithTemplate(subscriptions, proxies, template)
|
||||
r, err := json.Marshal(proxyList)
|
||||
result = string(r)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
data, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
if output != "" {
|
||||
err = os.WriteFile(output, data, 0666)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
}
|
||||
|
||||
if output != "" {
|
||||
err = os.WriteFile(output, []byte(result), 0666)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
fmt.Println(string(result))
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
convertCmd.Flags().StringSliceP("subscription", "s", []string{}, "subscription urls")
|
||||
convertCmd.Flags().StringSliceP("proxy", "p", []string{}, "common proxies")
|
||||
convertCmd.Flags().StringP("template", "t", "", "path of template file")
|
||||
convertCmd.Flags().StringP("template", "t", "", "template file path")
|
||||
convertCmd.Flags().StringP("output", "o", "", "output file path")
|
||||
convertCmd.Flags().StringP("filter", "f", "", "outbound tag filter (support regex)")
|
||||
RootCmd.AddCommand(convertCmd)
|
||||
}
|
||||
|
||||
@ -101,44 +97,31 @@ func Convert(urls []string, proxies []string) ([]model.Proxy, error) {
|
||||
return proxyList, nil
|
||||
}
|
||||
|
||||
func ConvertWithTemplate(urls []string, proxies []string, template string) (model.Config, error) {
|
||||
proxyList := make([]model.Proxy, 0)
|
||||
newProxies, err := ConvertSubscriptionsToSProxy(urls)
|
||||
newOutboundTagList := make([]string, 0)
|
||||
if err != nil {
|
||||
return model.Config{}, err
|
||||
}
|
||||
proxyList = append(proxyList, newProxies...)
|
||||
for _, p := range proxies {
|
||||
proxy, err := ConvertCProxyToSProxy(p)
|
||||
if err != nil {
|
||||
return model.Config{}, err
|
||||
}
|
||||
proxyList = append(proxyList, proxy)
|
||||
}
|
||||
func MergeTemplate(proxies []model.Proxy, template string) (string, error) {
|
||||
config, err := ReadTemplate(template)
|
||||
proxyTags := make([]string, 0)
|
||||
if err != nil {
|
||||
return model.Config{}, err
|
||||
return "", err
|
||||
}
|
||||
ps, err := json.Marshal(proxyList)
|
||||
for _, p := range proxies {
|
||||
proxyTags = append(proxyTags, p.Tag)
|
||||
}
|
||||
ps, err := json.Marshal(&proxies)
|
||||
fmt.Print(string(ps))
|
||||
if err != nil {
|
||||
return model.Config{}, err
|
||||
return "", err
|
||||
}
|
||||
var newOutbounds []model.Outbound
|
||||
err = json.Unmarshal(ps, &newOutbounds)
|
||||
if err != nil {
|
||||
return model.Config{}, err
|
||||
return "", err
|
||||
}
|
||||
for _, outbound := range newOutbounds {
|
||||
newOutboundTagList = append(newOutboundTagList, outbound.Tag)
|
||||
}
|
||||
config.Outbounds = append(config.Outbounds, newOutbounds...)
|
||||
for i, outbound := range config.Outbounds {
|
||||
if outbound.Type == "urltest" || outbound.Type == "selector" {
|
||||
var parsedOutbound []string = make([]string, 0)
|
||||
for _, o := range outbound.Outbounds {
|
||||
if o == "<all-proxy-tags>" {
|
||||
parsedOutbound = append(parsedOutbound, newOutboundTagList...)
|
||||
parsedOutbound = append(parsedOutbound, proxyTags...)
|
||||
} else {
|
||||
parsedOutbound = append(parsedOutbound, o)
|
||||
}
|
||||
@ -146,7 +129,12 @@ func ConvertWithTemplate(urls []string, proxies []string, template string) (mode
|
||||
config.Outbounds[i].Outbounds = parsedOutbound
|
||||
}
|
||||
}
|
||||
return config, nil
|
||||
config.Outbounds = append(config.Outbounds, newOutbounds...)
|
||||
data, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func ConvertCProxyToSProxy(proxy string) (model.Proxy, error) {
|
||||
@ -180,13 +168,11 @@ func FetchSubscription(url string, maxRetryTime int) (string, error) {
|
||||
for retryTime < maxRetryTime {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
retryTime++
|
||||
continue
|
||||
}
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
retryTime++
|
||||
continue
|
||||
}
|
||||
@ -200,12 +186,10 @@ func ConvertSubscriptionsToSProxy(urls []string) ([]model.Proxy, error) {
|
||||
for _, url := range urls {
|
||||
data, err := FetchSubscription(url, 3)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
proxy, err := DecodeBase64(data)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
proxies := strings.Split(proxy, "\n")
|
||||
|
@ -91,7 +91,7 @@ type DNSRule struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
||||
IPVersion int `json:"ip_version,omitempty"`
|
||||
QueryType Listable[uint16] `json:"query_type,omitempty"`
|
||||
QueryType Listable[string] `json:"query_type,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
AuthUser Listable[string] `json:"auth_user,omitempty"`
|
||||
Protocol Listable[string] `json:"protocol,omitempty"`
|
||||
@ -126,7 +126,7 @@ type DNSRule struct {
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet string `json:"client_subnet,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Rules Listable[DNSRule] `json:"rules,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
package model
|
||||
|
||||
type Hysteria struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
Up string `json:"up,omitempty"`
|
||||
|
@ -6,8 +6,6 @@ type Hysteria2Obfs struct {
|
||||
}
|
||||
|
||||
type Hysteria2 struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
type Proxy struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Shadowsocks `json:"-"`
|
||||
VMess `json:"-"`
|
||||
VLESS `json:"-"`
|
||||
@ -20,57 +21,71 @@ func (p *Proxy) MarshalJSON() ([]byte, error) {
|
||||
case "shadowsocks":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Shadowsocks
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
Shadowsocks: p.Shadowsocks,
|
||||
})
|
||||
case "vmess":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
VMess
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
VMess: p.VMess,
|
||||
})
|
||||
case "vless":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
VLESS
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
VLESS: p.VLESS,
|
||||
})
|
||||
case "trojan":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Trojan
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
Trojan: p.Trojan,
|
||||
})
|
||||
case "tuic":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
TUIC
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
TUIC: p.TUIC,
|
||||
})
|
||||
case "hysteria":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Hysteria
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
Hysteria: p.Hysteria,
|
||||
})
|
||||
case "hysteria2":
|
||||
return json.Marshal(&struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Hysteria2
|
||||
}{
|
||||
Type: p.Type,
|
||||
Tag: p.Tag,
|
||||
Hysteria2: p.Hysteria2,
|
||||
})
|
||||
default:
|
||||
|
@ -1,7 +1,6 @@
|
||||
package model
|
||||
|
||||
type Shadowsocks struct {
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
Method string `json:"method"`
|
||||
|
@ -1,8 +1,6 @@
|
||||
package model
|
||||
|
||||
type Trojan struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
Password string `json:"password"`
|
||||
|
@ -1,8 +1,6 @@
|
||||
package model
|
||||
|
||||
type TUIC struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
|
@ -1,8 +1,6 @@
|
||||
package model
|
||||
|
||||
type VLESS struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
UUID string `json:"uuid"`
|
||||
|
@ -19,8 +19,6 @@ type VmessJson struct {
|
||||
}
|
||||
|
||||
type VMess struct {
|
||||
Type string `json:"type"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Server string `json:"server"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
UUID string `json:"uuid"`
|
||||
|
@ -63,8 +63,8 @@ func ParseHysteria(proxy string) (model.Proxy, error) {
|
||||
}
|
||||
result := model.Proxy{
|
||||
Type: "hysteria",
|
||||
Tag: remarks,
|
||||
Hysteria: model.Hysteria{
|
||||
Tag: remarks,
|
||||
Server: host,
|
||||
ServerPort: uint16(port),
|
||||
Up: upmbps,
|
||||
|
@ -36,8 +36,8 @@ func ParseHysteria2(proxy string) (model.Proxy, error) {
|
||||
network := params.Get("network")
|
||||
result := model.Proxy{
|
||||
Type: "hysteria2",
|
||||
Tag: remarks,
|
||||
Hysteria2: model.Hysteria2{
|
||||
Tag: remarks,
|
||||
Server: server,
|
||||
ServerPort: uint16(port),
|
||||
Password: password,
|
||||
|
@ -50,14 +50,10 @@ func ParseShadowsocks(proxy string) (model.Proxy, error) {
|
||||
method := credentials[0]
|
||||
password := credentials[1]
|
||||
server := strings.TrimSpace(serverAndPort[0])
|
||||
// params, err := url.ParseQuery(proxy)
|
||||
// if err != nil {
|
||||
// return model.Proxy{}, err
|
||||
// }
|
||||
result := model.Proxy{
|
||||
Type: "shadowsocks",
|
||||
Tag: remarks,
|
||||
Shadowsocks: model.Shadowsocks{
|
||||
Tag: remarks,
|
||||
Method: method,
|
||||
Password: password,
|
||||
Server: server,
|
||||
|
@ -40,8 +40,8 @@ func ParseTrojan(proxy string) (model.Proxy, error) {
|
||||
password := strings.TrimSpace(parts[0])
|
||||
result := model.Proxy{
|
||||
Type: "trojan",
|
||||
Tag: remarks,
|
||||
Trojan: model.Trojan{
|
||||
Tag: remarks,
|
||||
Server: server,
|
||||
ServerPort: uint16(port),
|
||||
Password: password,
|
||||
|
@ -48,15 +48,13 @@ func ParseVless(proxy string) (model.Proxy, error) {
|
||||
}
|
||||
server := strings.TrimSpace(serverAndPort[0])
|
||||
uuid := strings.TrimSpace(parts[0])
|
||||
network := params.Get("type")
|
||||
result := model.Proxy{
|
||||
Type: "vless",
|
||||
Tag: remarks,
|
||||
VLESS: model.VLESS{
|
||||
Tag: remarks,
|
||||
Server: server,
|
||||
ServerPort: uint16(port),
|
||||
UUID: uuid,
|
||||
Network: network,
|
||||
Flow: params.Get("flow"),
|
||||
},
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ func ParseVmess(proxy string) (model.Proxy, error) {
|
||||
|
||||
result := model.Proxy{
|
||||
Type: "vmess",
|
||||
Tag: name,
|
||||
VMess: model.VMess{
|
||||
Tag: name,
|
||||
Server: vmess.Add,
|
||||
ServerPort: uint16(port),
|
||||
UUID: vmess.Id,
|
||||
|
@ -161,7 +161,7 @@
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "手动切换",
|
||||
"tag": "节点选择",
|
||||
"outbounds": ["<all-proxy-tags>", "direct"],
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
@ -175,35 +175,35 @@
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Microsoft",
|
||||
"outbounds": ["节点选择", "手动切换", "<all-proxy-tags>", "direct"],
|
||||
"outbounds": ["节点选择", "<all-proxy-tags>", "direct"],
|
||||
"default": "节点选择",
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Bilibili",
|
||||
"outbounds": ["节点选择", "手动切换", "<all-proxy-tags>", "direct"],
|
||||
"outbounds": ["节点选择", "<all-proxy-tags>", "direct"],
|
||||
"default": "节点选择",
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Games(全球)",
|
||||
"outbounds": ["节点选择", "手动切换", "<all-proxy-tags>", "direct"],
|
||||
"outbounds": ["节点选择", "<all-proxy-tags>", "direct"],
|
||||
"default": "节点选择",
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Games(中国)",
|
||||
"outbounds": ["节点选择", "手动切换", "<all-proxy-tags>", "direct"],
|
||||
"outbounds": ["节点选择", "<all-proxy-tags>", "direct"],
|
||||
"default": "节点选择",
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Bahamut",
|
||||
"outbounds": ["节点选择", "手动切换", "<all-proxy-tags>", "direct"],
|
||||
"outbounds": ["节点选择", "<all-proxy-tags>", "direct"],
|
||||
"default": "节点选择",
|
||||
"interrupt_exist_connections": true
|
||||
},
|
||||
@ -228,7 +228,7 @@
|
||||
"clash_api": {
|
||||
"external_controller": "127.0.0.1:9090",
|
||||
"external_ui": "./ui",
|
||||
"external_ui_download_detour": "手动切换"
|
||||
"external_ui_download_detour": "节点选择"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user