1
0
mirror of https://github.com/bestnite/sub2sing-box.git synced 2026-06-08 16:04:43 +00:00

feat: add custom User-Agent support for subscription and template requests

Add --user-agent / -u CLI flag and user-agent config field to allow
customizing the User-Agent header when fetching subscriptions and
remote templates. This is useful for providers that require a specific
UA to access their subscription links.

Closes #23
This commit is contained in:
2026-05-23 18:41:55 +10:00
parent b63662347a
commit 2a98e7c1f0
6 changed files with 28 additions and 10 deletions
+2 -1
View File
@@ -20,7 +20,8 @@
"group-type": "selector",
"sort": "name",
"sort-type": "asc",
"output": "./config.json"
"output": "./config.json",
"user-agent": "自定义 User-Agent"
}
```
+1
View File
@@ -57,6 +57,7 @@ func Convert(c *gin.Context) {
data.SortKey,
data.SortType,
groupRules,
data.UserAgent,
)
if err != nil {
c.JSON(400, gin.H{
+6
View File
@@ -25,6 +25,7 @@ var (
sortType string
config string
groupRules string
userAgent string
)
func init() {
@@ -40,6 +41,7 @@ func init() {
convertCmd.Flags().StringVarP(&sortType, "sort-type", "T", "", "sort type, asc or desc")
convertCmd.Flags().StringVarP(&config, "config", "c", "", "configuration file path")
convertCmd.Flags().StringVarP(&groupRules, "group-rules", "R", "", "group rules")
convertCmd.Flags().StringVarP(&userAgent, "user-agent", "u", "", "custom User-Agent for fetching subscriptions and remote templates")
RootCmd.AddCommand(convertCmd)
}
@@ -71,6 +73,7 @@ func convertRun(cmd *cobra.Command, args []string) {
sortKey,
sortType,
groupRulesMap,
userAgent,
)
if err != nil {
fmt.Println("Conversion error:", err)
@@ -152,4 +155,7 @@ func mergeConfig(cfg model.ConvertRequest) {
if output == "" {
output = cfg.Output
}
if userAgent == "" {
userAgent = cfg.UserAgent
}
}
+7 -6
View File
@@ -36,6 +36,7 @@ func Convert(
sortKey string,
sortType string,
groupRules map[string][]string,
userAgent string,
) (string, error) {
result := ""
var err error
@@ -44,7 +45,7 @@ func Convert(
groupType = C.TypeSelector
}
outbounds, err := ConvertSubscriptionsToSProxy(subscriptions)
outbounds, err := ConvertSubscriptionsToSProxy(subscriptions, userAgent)
if err != nil {
return "", err
}
@@ -104,7 +105,7 @@ func Convert(
outbounds = AddCountryGroup(outbounds, groupType, sortKey, sortType, groupRules)
}
if templatePath != "" {
templateData, err := ReadTemplate(templatePath)
templateData, err := ReadTemplate(templatePath, userAgent)
if err != nil {
return "", err
}
@@ -226,12 +227,12 @@ func AddCountryGroup(proxies []model.Outbound, groupType string, sortKey string,
return append(proxies, groups...)
}
func ReadTemplate(template string) (string, error) {
func ReadTemplate(template string, userAgent string) (string, error) {
var data string
var err error
isNetworkFile, _ := regexp.MatchString(`^https?://`, template)
if isNetworkFile {
data, err = util.Fetch(template, 3)
data, err = util.Fetch(template, 3, userAgent)
if err != nil {
return "", err
}
@@ -320,10 +321,10 @@ func ConvertCProxyToSProxy(proxy string) (model.Outbound, error) {
return model.Outbound{}, errors.New("unknown proxy format")
}
func ConvertSubscriptionsToSProxy(urls []string) ([]model.Outbound, error) {
func ConvertSubscriptionsToSProxy(urls []string, userAgent string) ([]model.Outbound, error) {
proxyList := make([]model.Outbound, 0)
for _, url := range urls {
data, err := util.Fetch(url, 3)
data, err := util.Fetch(url, 3, userAgent)
if err != nil {
return nil, err
}
+1
View File
@@ -12,4 +12,5 @@ type ConvertRequest struct {
SortType string `form:"sort-type" json:"sort-type"`
Output string `json:"output"`
GroupRules string `form:"group-rules" json:"group-rules"`
UserAgent string `form:"user-agent" json:"user-agent"`
}
+11 -3
View File
@@ -5,23 +5,31 @@ import (
"net/http"
)
func Fetch(url string, maxRetryTimes int) (string, error) {
func Fetch(url string, maxRetryTimes int, userAgent string) (string, error) {
retryTime := 0
var err error
var resp *http.Response
for retryTime < maxRetryTimes {
resp, err = http.Get(url)
req, reqErr := http.NewRequest("GET", url, nil)
if reqErr != nil {
return "", reqErr
}
if userAgent != "" {
req.Header.Set("User-Agent", userAgent)
}
resp, err = http.DefaultClient.Do(req)
if err != nil {
retryTime++
continue
}
var data []byte
data, err = io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
retryTime++
continue
}
return string(data), err
return string(data), nil
}
return "", err
}