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:
@@ -20,7 +20,8 @@
|
|||||||
"group-type": "selector",
|
"group-type": "selector",
|
||||||
"sort": "name",
|
"sort": "name",
|
||||||
"sort-type": "asc",
|
"sort-type": "asc",
|
||||||
"output": "./config.json"
|
"output": "./config.json",
|
||||||
|
"user-agent": "自定义 User-Agent"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ func Convert(c *gin.Context) {
|
|||||||
data.SortKey,
|
data.SortKey,
|
||||||
data.SortType,
|
data.SortType,
|
||||||
groupRules,
|
groupRules,
|
||||||
|
data.UserAgent,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ var (
|
|||||||
sortType string
|
sortType string
|
||||||
config string
|
config string
|
||||||
groupRules string
|
groupRules string
|
||||||
|
userAgent string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -40,6 +41,7 @@ func init() {
|
|||||||
convertCmd.Flags().StringVarP(&sortType, "sort-type", "T", "", "sort type, asc or desc")
|
convertCmd.Flags().StringVarP(&sortType, "sort-type", "T", "", "sort type, asc or desc")
|
||||||
convertCmd.Flags().StringVarP(&config, "config", "c", "", "configuration file path")
|
convertCmd.Flags().StringVarP(&config, "config", "c", "", "configuration file path")
|
||||||
convertCmd.Flags().StringVarP(&groupRules, "group-rules", "R", "", "group rules")
|
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)
|
RootCmd.AddCommand(convertCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ func convertRun(cmd *cobra.Command, args []string) {
|
|||||||
sortKey,
|
sortKey,
|
||||||
sortType,
|
sortType,
|
||||||
groupRulesMap,
|
groupRulesMap,
|
||||||
|
userAgent,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Conversion error:", err)
|
fmt.Println("Conversion error:", err)
|
||||||
@@ -152,4 +155,7 @@ func mergeConfig(cfg model.ConvertRequest) {
|
|||||||
if output == "" {
|
if output == "" {
|
||||||
output = cfg.Output
|
output = cfg.Output
|
||||||
}
|
}
|
||||||
|
if userAgent == "" {
|
||||||
|
userAgent = cfg.UserAgent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -36,6 +36,7 @@ func Convert(
|
|||||||
sortKey string,
|
sortKey string,
|
||||||
sortType string,
|
sortType string,
|
||||||
groupRules map[string][]string,
|
groupRules map[string][]string,
|
||||||
|
userAgent string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
result := ""
|
result := ""
|
||||||
var err error
|
var err error
|
||||||
@@ -44,7 +45,7 @@ func Convert(
|
|||||||
groupType = C.TypeSelector
|
groupType = C.TypeSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
outbounds, err := ConvertSubscriptionsToSProxy(subscriptions)
|
outbounds, err := ConvertSubscriptionsToSProxy(subscriptions, userAgent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -104,7 +105,7 @@ func Convert(
|
|||||||
outbounds = AddCountryGroup(outbounds, groupType, sortKey, sortType, groupRules)
|
outbounds = AddCountryGroup(outbounds, groupType, sortKey, sortType, groupRules)
|
||||||
}
|
}
|
||||||
if templatePath != "" {
|
if templatePath != "" {
|
||||||
templateData, err := ReadTemplate(templatePath)
|
templateData, err := ReadTemplate(templatePath, userAgent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -226,12 +227,12 @@ func AddCountryGroup(proxies []model.Outbound, groupType string, sortKey string,
|
|||||||
return append(proxies, groups...)
|
return append(proxies, groups...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadTemplate(template string) (string, error) {
|
func ReadTemplate(template string, userAgent string) (string, error) {
|
||||||
var data string
|
var data string
|
||||||
var err error
|
var err error
|
||||||
isNetworkFile, _ := regexp.MatchString(`^https?://`, template)
|
isNetworkFile, _ := regexp.MatchString(`^https?://`, template)
|
||||||
if isNetworkFile {
|
if isNetworkFile {
|
||||||
data, err = util.Fetch(template, 3)
|
data, err = util.Fetch(template, 3, userAgent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -320,10 +321,10 @@ func ConvertCProxyToSProxy(proxy string) (model.Outbound, error) {
|
|||||||
return model.Outbound{}, errors.New("unknown proxy format")
|
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)
|
proxyList := make([]model.Outbound, 0)
|
||||||
for _, url := range urls {
|
for _, url := range urls {
|
||||||
data, err := util.Fetch(url, 3)
|
data, err := util.Fetch(url, 3, userAgent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ type ConvertRequest struct {
|
|||||||
SortType string `form:"sort-type" json:"sort-type"`
|
SortType string `form:"sort-type" json:"sort-type"`
|
||||||
Output string `json:"output"`
|
Output string `json:"output"`
|
||||||
GroupRules string `form:"group-rules" json:"group-rules"`
|
GroupRules string `form:"group-rules" json:"group-rules"`
|
||||||
|
UserAgent string `form:"user-agent" json:"user-agent"`
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -5,23 +5,31 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Fetch(url string, maxRetryTimes int) (string, error) {
|
func Fetch(url string, maxRetryTimes int, userAgent string) (string, error) {
|
||||||
retryTime := 0
|
retryTime := 0
|
||||||
var err error
|
var err error
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
for retryTime < maxRetryTimes {
|
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 {
|
if err != nil {
|
||||||
retryTime++
|
retryTime++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var data []byte
|
var data []byte
|
||||||
data, err = io.ReadAll(resp.Body)
|
data, err = io.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
retryTime++
|
retryTime++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return string(data), err
|
return string(data), nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user