feat(sub): auto-detect subscription format by User-Agent (Updated) (#5826)

* feat(settings): add subscription format controls

* feat(sub): auto-detect subscription formats

* fix(xray): validate balancer regexes before save

* Revert "fix(xray): validate balancer regexes before save"

This reverts commit 8a208ce71b.

* doc(endpoints): align indent spaces

* doc(settings): improve error message formatting in validateSubUserAgentRegex

- Use NewErrorf with proper formatting instead of NewError with string concatenation
- Add comment explaining the rationale for returning original pattern value
- This preserves the intentional design where empty input is stored as empty
  in the DB and inherited as the runtime default at read time

---------

Co-authored-by: Tomilla <5007859+Tomilla@users.noreply.github.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
Tomi lla
2026-07-14 19:01:40 +08:00
committed by GitHub
parent f2b17397f4
commit 129f50d92a
40 changed files with 1588 additions and 89 deletions
+54 -5
View File
@@ -89,6 +89,31 @@ func (s *Server) initRouter() (*gin.Engine, error) {
return nil, err
}
subClashAutoDetect, err := s.settingService.GetSubClashAutoDetect()
if err != nil {
subClashAutoDetect = false
}
subJsonAutoDetect, err := s.settingService.GetSubJsonAutoDetect()
if err != nil {
subJsonAutoDetect = false
}
subJsonAlwaysArray, err := s.settingService.GetSubJsonAlwaysArray()
if err != nil {
subJsonAlwaysArray = false
}
subJsonUserAgentRegex, err := s.settingService.GetSubJsonUserAgentRegex()
if err != nil {
subJsonUserAgentRegex = service.DefaultSubJsonUserAgentRegex
}
subClashUserAgentRegex, err := s.settingService.GetSubClashUserAgentRegex()
if err != nil {
subClashUserAgentRegex = service.DefaultSubClashUserAgentRegex
}
// Set base_path based on LinksPath for template rendering
// Ensure LinksPath ends with "/" for proper asset URL generation
basePath := LinksPath
@@ -239,11 +264,35 @@ func (s *Server) initRouter() (*gin.Engine, error) {
g := engine.Group("/")
s.sub = NewSUBController(
g, LinksPath, JsonPath, ClashPath, subJsonEnable, subClashEnable, Encrypt, RemarkTemplate, SubUpdates,
SubJsonMux, SubJsonRules, SubJsonFinalMask, SubClashEnableRouting, SubClashRules, SubTitle, SubSupportUrl,
SubProfileUrl, SubAnnounce, SubEnableRouting, SubRoutingRules, SubHideSettings,
SubIncyEnableRouting, SubIncyRoutingRules)
s.sub = NewSUBController(g,
WithSUBPath(LinksPath),
WithSUBJsonPath(JsonPath),
WithSUBClashPath(ClashPath),
WithSUBClashAutoDetect(subClashAutoDetect),
WithSUBClashUserAgentRegex(subClashUserAgentRegex),
WithSUBJsonAutoDetect(subJsonAutoDetect),
WithSUBJsonUserAgentRegex(subJsonUserAgentRegex),
WithSUBJsonAlwaysArray(subJsonAlwaysArray),
WithSUBJsonEnabled(subJsonEnable),
WithSUBClashEnabled(subClashEnable),
WithSUBEncryption(Encrypt),
WithSUBRemarkTemplate(RemarkTemplate),
WithSUBUpdateInterval(SubUpdates),
WithSUBJsonMux(SubJsonMux),
WithSUBJsonRules(SubJsonRules),
WithSUBJsonFinalMask(SubJsonFinalMask),
WithSUBClashEnableRouting(SubClashEnableRouting),
WithSUBClashRules(SubClashRules),
WithSUBTitle(SubTitle),
WithSUBSupportURL(SubSupportUrl),
WithSUBProfileURL(SubProfileUrl),
WithSUBAnnounce(SubAnnounce),
WithSUBEnableRouting(SubEnableRouting),
WithSUBRoutingRules(SubRoutingRules),
WithSUBHideSettings(SubHideSettings),
WithSUBIncyEnableRouting(SubIncyEnableRouting),
WithSUBIncyRoutingRules(SubIncyRoutingRules),
)
return engine, nil
}