diff --git a/api/apiHandler.go b/api/apiHandler.go index 1405076..5c73cd1 100644 --- a/api/apiHandler.go +++ b/api/apiHandler.go @@ -48,6 +48,8 @@ func (a *APIHandler) postHandler(c *gin.Context) { a.ApiService.RestartSb(c) case "linkConvert": a.ApiService.LinkConvert(c) + case "subConvert": + a.ApiService.SubConvert(c) case "importdb": a.ApiService.ImportDb(c) case "addToken": diff --git a/api/apiService.go b/api/apiService.go index 2f02793..75911eb 100644 --- a/api/apiService.go +++ b/api/apiService.go @@ -330,6 +330,12 @@ func (a *ApiService) LinkConvert(c *gin.Context) { jsonObj(c, result, err) } +func (a *ApiService) SubConvert(c *gin.Context) { + link := c.Request.FormValue("link") + result, err := util.GetExternalSub(link) + jsonObj(c, result, err) +} + func (a *ApiService) ImportDb(c *gin.Context) { file, _, err := c.Request.FormFile("db") if err != nil { diff --git a/api/apiV2Handler.go b/api/apiV2Handler.go index 6eb08bf..8961d08 100644 --- a/api/apiV2Handler.go +++ b/api/apiV2Handler.go @@ -49,6 +49,8 @@ func (a *APIv2Handler) postHandler(c *gin.Context) { a.ApiService.RestartSb(c) case "linkConvert": a.ApiService.LinkConvert(c) + case "subConvert": + a.ApiService.SubConvert(c) case "importdb": a.ApiService.ImportDb(c) default: diff --git a/sub/linkService.go b/sub/linkService.go index 20c38e5..90b7ebc 100644 --- a/sub/linkService.go +++ b/sub/linkService.go @@ -1,10 +1,7 @@ package sub import ( - "crypto/tls" "encoding/json" - "io" - "net/http" "strings" "github.com/alireza0/s-ui/logger" @@ -32,7 +29,8 @@ func (s *LinkService) GetLinks(linkJson *json.RawMessage, types string, clientIn case "external": result = append(result, link.Uri) case "sub": - result = append(result, s.getExternalSub(link.Uri)...) + subLinks := util.GetExternalLink(link.Uri) + result = append(result, strings.Split(subLinks, "\n")...) case "local": if types == "all" { result = append(result, s.addClientInfo(link.Uri, clientInfo)) @@ -74,31 +72,3 @@ func (s *LinkService) addClientInfo(uri string, clientInfo string) string { return uri + clientInfo } } - -func (s *LinkService) getExternalSub(url string) []string { - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - client := &http.Client{Transport: tr} - - // Make the HTTP request - response, err := client.Get(url) - if err != nil { - logger.Warning("sub: Error making HTTP request:", err) - return nil - } - defer response.Body.Close() - - // Read the response body - body, err := io.ReadAll(response.Body) - if err != nil { - logger.Warning("sub: Error reading response body:", err) - return nil - } - - // Convert if the content is Base64 encoded - links := util.StrOrBase64Encoded(string(body)) - return strings.Split(links, "\n") - -} diff --git a/util/subToJson.go b/util/subToJson.go new file mode 100644 index 0000000..88cb31d --- /dev/null +++ b/util/subToJson.go @@ -0,0 +1,97 @@ +package util + +import ( + "crypto/tls" + "encoding/json" + "io" + "net/http" + "strings" + + "github.com/alireza0/s-ui/logger" + "github.com/alireza0/s-ui/util/common" +) + +func GetExternalLink(url string) string { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + client := &http.Client{Transport: tr} + + response, err := client.Get(url) + if err != nil { + logger.Warning("sub: Error making HTTP request:", err) + return "" + } + defer response.Body.Close() + + body, err := io.ReadAll(response.Body) + if err != nil { + logger.Warning("sub: Error reading response body:", err) + return "" + } + + data := StrOrBase64Encoded(string(body)) + return data +} + +func GetExternalSub(url string) ([]map[string]interface{}, error) { + var err error + var result []map[string]interface{} + + if len(url) == 0 { + return nil, common.NewError("no url") + } + + data := GetExternalLink(url) + if len(data) == 0 { + return nil, common.NewError("no result") + } + + // if the data is a JSON object + if strings.HasPrefix(data, "{") && strings.HasSuffix(data, "}") { + var jsonData map[string]interface{} + err = json.Unmarshal([]byte(data), &jsonData) + if err != nil { + logger.Warning("sub: Error unmarshalling JSON:", err) + return nil, err + } + outbounds, ok := jsonData["outbounds"].([]any) + if !ok { + logger.Warning("sub: Error getting outbounds:", err) + return nil, err + } + for _, outbound := range outbounds { + outboundMap, ok := outbound.(map[string]interface{}) + if ok && len(outboundMap) > 0 { + oType, _ := outboundMap["type"].(string) + switch oType { + case "urltest": + case "direct": + case "selector": + case "block": + continue + default: + result = append(result, outboundMap) + } + } + } + if len(result) == 0 { + return nil, common.NewError("no result") + } + return result, nil + } else { + // if data is a text + links := strings.Split(data, "\n") + for _, link := range links { + linkToJson, _, err := GetOutbound(link, 0) + if err == nil { + result = append(result, *linkToJson) + } + } + } + if len(result) == 0 { + return nil, common.NewError("no result") + } + return result, nil +}