fix(clash): inject default Proxy/Auto only when a custom group references them (#1151)
Some checks are pending
Release S-UI / build-frontend (push) Waiting to run
Release S-UI / build-386 (push) Blocked by required conditions
Release S-UI / build-amd64 (push) Blocked by required conditions
Release S-UI / build-armv5 (push) Blocked by required conditions
Release S-UI / build-armv6 (push) Blocked by required conditions
Release S-UI / build-armv7 (push) Blocked by required conditions
Release S-UI / build-arm64 (push) Blocked by required conditions
Release S-UI / build-s390x (push) Blocked by required conditions
Build S-UI for Windows / build-frontend (push) Waiting to run
Build S-UI for Windows / build-windows-amd64 (push) Blocked by required conditions
Build S-UI for Windows / build-windows-arm64 (push) Blocked by required conditions

* fix(clash): inject default Proxy/Auto only when a custom group references them

Refines the proxy-group injection logic so default Proxy/Auto groups
are only injected when needed, rather than skipping injection entirely
when custom groups exist (#1110) or always injecting unconditionally
(#1066).

Two-part condition:
1. No group named Proxy already exists (user-defined Proxy is respected)
2. At least one existing group references Proxy in its proxies list

When injection is needed, defaults are prepended before custom groups.
Also avoids injecting a duplicate Auto group when the user already
defines one.

Added hasGroupNamed helper and comprehensive tests (15 cases) covering
nil/empty/custom/no-ref/duplicate-Auto scenarios.

* chore(clash): drop test file before merge

---------

Co-authored-by: Alireza Ahmadi <alireza7@gmail.com>
This commit is contained in:
phj233 2026-06-29 00:38:39 +08:00 • committed by GitHub
parent b7931a9bbe
commit 3b81e7656f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -389,14 +389,50 @@ func (s *ClashService) ConvertToClashMeta(outbounds *[]map[string]interface{}, b
output["proxies"] = proxies
}
if pg, ok := output["proxy-groups"].([]interface{}); !ok || len(pg) == 0 {
// Inject default Proxy + Auto unless user already has "Proxy", or
// no custom group references it (fully custom config: don't inject).
pgSlice, _ := output["proxy-groups"].([]interface{})
inject := !hasGroupNamed(pgSlice, "Proxy")
if inject && len(pgSlice) > 0 {
inject = false
for _, item := range pgSlice {
if g, ok := item.(map[string]interface{}); ok {
if proxies, ok := g["proxies"].([]interface{}); ok {
for _, p := range proxies {
if name, ok := p.(string); ok && name == "Proxy" {
inject = true
break
}
}
}
}
if inject {
break
}
}
}
if inject {
var proxyGroups []map[string]interface{}
if err := yaml.Unmarshal([]byte(ProxyGroups), &proxyGroups); err != nil {
logger.Error(err.Error())
return "", err
}
proxyGroups[1]["proxies"] = proxyTags
proxyGroups[0]["proxies"] = append([]string{proxyGroups[1]["name"].(string)}, proxyTags...)
output["proxy-groups"] = proxyGroups
// Don't inject a duplicate "Auto" if the user already defines one.
if hasGroupNamed(pgSlice, "Auto") {
proxyGroups = proxyGroups[:1]
proxyGroups[0]["proxies"] = proxyTags
}
if pg, ok := output["proxy-groups"].([]interface{}); ok {
for _, item := range pg {
if g, ok := item.(map[string]interface{}); ok {
proxyGroups = append(proxyGroups, g)
}
}
output["proxy-groups"] = proxyGroups
} else {
output["proxy-groups"] = proxyGroups
}
}
result, err := yaml.Marshal(output)
@ -405,3 +441,22 @@ func (s *ClashService) ConvertToClashMeta(outbounds *[]map[string]interface{}, b
}
return string(result), nil
}
// hasGroupNamed checks whether a "proxy-groups" interface{} slice contains a group with the given name.
// Used to avoid injecting duplicate "Proxy" / "Auto" default groups when the user already defined their own.
func hasGroupNamed(pg interface{}, name string) bool {
list, ok := pg.([]interface{})
if !ok {
return false
}
for _, item := range list {
group, ok := item.(map[string]interface{})
if !ok {
continue
}
if gname, ok := group["name"].(string); ok && gname == name {
return true
}
}
return false
}