feat add clash yaml convert (#3916)

* docs(agents): add AI agent guidance documentation

* feat(sub): add Clash/Mihomo YAML subscription service

Add SubClashService to convert subscription links to Clash/Mihomo
YAML format for direct client compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(sub): integrate Clash YAML endpoint into subscription system

- Add Clash route handler in SUBController
- Update BuildURLs to include Clash URL
- Pass Clash settings through subscription pipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(web): add Clash settings to entity and service

- Add SubClashEnable, SubClashPath, SubClashURI fields
- Add getter methods for Clash configuration
- Set default Clash path to /clash/ and enable by default

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ui): add Clash settings to subscription panels

- Add Clash enable switch in general subscription settings
- Add Clash path/URI configuration in formats panel
- Display Clash QR code on subscription page
- Rename JSON tab to "Formats" for clarity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(js): add Clash support to frontend models

- Add subClashEnable, subClashPath, subClashURI to AllSetting
- Generate and display Clash QR code on subscription page
- Handle Clash URL in subscription data binding

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
zhuzn
2026-04-20 04:26:13 +08:00
committed by GitHub
parent 1e3b366fba
commit d580086361
13 changed files with 596 additions and 61 deletions

View File

@@ -1031,6 +1031,7 @@ type PageData struct {
TotalByte int64
SubUrl string
SubJsonUrl string
SubClashUrl string
Result []string
}
@@ -1080,29 +1081,25 @@ func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string,
// BuildURLs constructs absolute subscription and JSON subscription URLs for a given subscription ID.
// It prioritizes configured URIs, then individual settings, and finally falls back to request-derived components.
func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
// Input validation
func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subClashPath, subId string) (subURL, subJsonURL, subClashURL string) {
if subId == "" {
return "", ""
return "", "", ""
}
// Get configured URIs first (highest priority)
configuredSubURI, _ := s.settingService.GetSubURI()
configuredSubJsonURI, _ := s.settingService.GetSubJsonURI()
configuredSubClashURI, _ := s.settingService.GetSubClashURI()
// Determine base scheme and host (cached to avoid duplicate calls)
var baseScheme, baseHostWithPort string
if configuredSubURI == "" || configuredSubJsonURI == "" {
if configuredSubURI == "" || configuredSubJsonURI == "" || configuredSubClashURI == "" {
baseScheme, baseHostWithPort = s.getBaseSchemeAndHost(scheme, hostWithPort)
}
// Build subscription URL
subURL = s.buildSingleURL(configuredSubURI, baseScheme, baseHostWithPort, subPath, subId)
// Build JSON subscription URL
subJsonURL = s.buildSingleURL(configuredSubJsonURI, baseScheme, baseHostWithPort, subJsonPath, subId)
subClashURL = s.buildSingleURL(configuredSubClashURI, baseScheme, baseHostWithPort, subClashPath, subId)
return subURL, subJsonURL
return subURL, subJsonURL, subClashURL
}
// getBaseSchemeAndHost determines the base scheme and host from settings or falls back to request values
@@ -1149,7 +1146,7 @@ func (s *SubService) joinPathWithID(basePath, subId string) string {
// BuildPageData parses header and prepares the template view model.
// BuildPageData constructs page data for rendering the subscription information page.
func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL string, basePath string) PageData {
func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL, subClashURL string, basePath string) PageData {
download := common.FormatTraffic(traffic.Down)
upload := common.FormatTraffic(traffic.Up)
total := "∞"
@@ -1183,6 +1180,7 @@ func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray
TotalByte: traffic.Total,
SubUrl: subURL,
SubJsonUrl: subJsonURL,
SubClashUrl: subClashURL,
Result: subs,
}
}