diff --git a/.gitignore b/.gitignore index 937e8d8..c60f928 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ dist template.json .idea -test \ No newline at end of file +test +sub2sing-box.json +config.json \ No newline at end of file diff --git a/api/handler/convert.go b/api/handler/convert.go index 8e7d970..5fbdaf9 100644 --- a/api/handler/convert.go +++ b/api/handler/convert.go @@ -2,8 +2,8 @@ package handler import ( "encoding/json" - "sub2sing-box/api/model" "sub2sing-box/common" + "sub2sing-box/model" "sub2sing-box/util" "github.com/gin-gonic/gin" diff --git a/cmd/convert.go b/cmd/convert.go index 9bf8bf1..35a1ae7 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -1,35 +1,42 @@ package cmd import ( + "encoding/json" "fmt" "os" + "path/filepath" "sub2sing-box/common" + "sub2sing-box/model" "github.com/spf13/cobra" ) -var subscriptions []string -var proxies []string -var template string -var output string -var delete string -var rename map[string]string -var group bool -var groupType string -var sortKey string -var sortType string +var ( + subscriptions []string + proxies []string + template string + output string + delete string + rename map[string]string + group bool + groupType string + sortKey string + sortType string + config string +) func init() { - convertCmd.Flags().StringSliceVarP(&subscriptions, "subscription", "s", []string{}, "subscription urls") - convertCmd.Flags().StringSliceVarP(&proxies, "proxy", "p", []string{}, "common proxies") + convertCmd.Flags().StringSliceVarP(&subscriptions, "subscription", "s", nil, "subscription URLs") + convertCmd.Flags().StringSliceVarP(&proxies, "proxy", "p", nil, "common proxies") convertCmd.Flags().StringVarP(&template, "template", "t", "", "template file path") convertCmd.Flags().StringVarP(&output, "output", "o", "", "output file path") convertCmd.Flags().StringVarP(&delete, "delete", "d", "", "delete proxy with regex") - convertCmd.Flags().StringToStringVarP(&rename, "rename", "r", map[string]string{}, "rename proxy with regex") + convertCmd.Flags().StringToStringVarP(&rename, "rename", "r", nil, "rename proxy with regex") convertCmd.Flags().BoolVarP(&group, "group", "g", false, "group proxies by country") convertCmd.Flags().StringVarP(&groupType, "group-type", "G", "selector", "group type, selector or urltest") convertCmd.Flags().StringVarP(&sortKey, "sort", "S", "tag", "sort key, tag or num") convertCmd.Flags().StringVarP(&sortType, "sort-type", "T", "asc", "sort type, asc or desc") + convertCmd.Flags().StringVarP(&config, "config", "c", "", "config file path") RootCmd.AddCommand(convertCmd) } @@ -37,32 +44,95 @@ var convertCmd = &cobra.Command{ Use: "convert", Long: "Convert common proxy to sing-box proxy", Short: "Convert common proxy to sing-box proxy", - Run: func(cmd *cobra.Command, args []string) { - result := "" - var err error - result, err = common.Convert( - subscriptions, - proxies, - template, - delete, - rename, - group, - groupType, - sortKey, - sortType, - ) + Run: convertRun, +} + +func convertRun(cmd *cobra.Command, args []string) { + loadConfig() + result, err := common.Convert( + subscriptions, + proxies, + template, + delete, + rename, + group, + groupType, + sortKey, + sortType, + ) + if err != nil { + fmt.Println("Conversion error:", err) + return + } + if output != "" { + err = os.WriteFile(output, []byte(result), 0666) if err != nil { - fmt.Println(err) + fmt.Println("Error writing to file:", err) return } - if output != "" { - err = os.WriteFile(output, []byte(result), 0666) - if err != nil { - fmt.Println(err) + fmt.Println("Config has been saved in:", output) + } else { + fmt.Println(result) + } +} + +func loadConfig() { + if config == "" { + if wd, err := os.Getwd(); err == nil { + config = filepath.Join(wd, "sub2sing-box.json") + if _, err := os.Stat(config); os.IsNotExist(err) { return } } else { - fmt.Println(string(result)) + fmt.Println("Error getting working directory:", err) + return } - }, + } + + bytes, err := os.ReadFile(config) + if err != nil { + fmt.Println("Error reading config file:", err) + return + } + + var cfg model.ConvertRequest + if err := json.Unmarshal(bytes, &cfg); err != nil { + fmt.Println("Error parsing config JSON:", err) + return + } + + mergeConfig(cfg) +} + +func mergeConfig(cfg model.ConvertRequest) { + if len(subscriptions) == 0 { + subscriptions = cfg.Subscriptions + } + if len(proxies) == 0 { + proxies = cfg.Proxies + } + if template == "" { + template = cfg.Template + } + if delete == "" { + delete = cfg.Delete + } + if len(rename) == 0 { + rename = cfg.Rename + } + if !group { + group = cfg.Group + } + if groupType == "" { + groupType = cfg.GroupType + } + if sortKey == "" { + sortKey = cfg.SortKey + } + if sortType == "" { + sortType = cfg.SortType + } + if output == "" { + output = cfg.Output + } } diff --git a/common/convert.go b/common/convert.go index d243dfe..b763c89 100644 --- a/common/convert.go +++ b/common/convert.go @@ -176,8 +176,9 @@ func MergeTemplate(outbounds []model.Outbound, template string) (string, error) } } else { if !strings.Contains(template, string(filepath.Separator)) { - if _, err := os.Stat(template); os.IsNotExist(err) { - template = filepath.Join("templates", template) + path := filepath.Join("templates", template) + if _, err := os.Stat(path); err == nil { + template = path } } config, err = ReadTemplate(template) diff --git a/api/model/convert.go b/model/convert.go similarity index 92% rename from api/model/convert.go rename to model/convert.go index 58e51fe..081ccce 100644 --- a/api/model/convert.go +++ b/model/convert.go @@ -10,4 +10,5 @@ type ConvertRequest struct { GroupType string `form:"group-type" json:"group-type"` SortKey string `form:"sort" json:"sort"` SortType string `form:"sort-type" json:"sort-type"` + Output string `json:"output"` } diff --git a/templates/tun-fakeip.json b/templates/tun-fakeip.json index d5f57e5..a4a4047 100644 --- a/templates/tun-fakeip.json +++ b/templates/tun-fakeip.json @@ -191,9 +191,7 @@ "sniff_override_destination": true, "strict_route": true, "type": "tun", - "stack": "mixed", - "inet4_route_exclude_address": ["100.64.0.0/10"], - "inet6_route_exclude_address": ["fd7a:115c:a1e0::/48"] + "stack": "mixed" } ], "outbounds": [ diff --git a/util/fetch.go b/util/fetch.go index c2cd15c..89f9eb1 100644 --- a/util/fetch.go +++ b/util/fetch.go @@ -8,13 +8,15 @@ import ( func Fetch(url string, maxRetryTimes int) (string, error) { retryTime := 0 var err error + var resp *http.Response for retryTime < maxRetryTimes { - resp, err := http.Get(url) + resp, err = http.Get(url) if err != nil { retryTime++ continue } - data, err := io.ReadAll(resp.Body) + var data []byte + data, err = io.ReadAll(resp.Body) if err != nil { retryTime++ continue