From fc21e35465aaa8adf4b8359d09823f611da01021 Mon Sep 17 00:00:00 2001 From: nitezs Date: Sun, 24 Sep 2023 12:31:12 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20webui=E8=A7=A3=E6=9E=90url=E5=88=B0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/templates/index.html | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/api/templates/index.html b/api/templates/index.html index 3c6d4e7..8ddf9dc 100644 --- a/api/templates/index.html +++ b/api/templates/index.html @@ -54,6 +54,21 @@
+ +
+ +
+ + +
+
+
@@ -248,6 +263,183 @@
+ + + + + + +
+
+

sub2clash

+ 通用订阅链接转 Clash(Meta) 配置工具 + 使用文档 +
+ + +
+ +
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ +
+ + + +
+
+ + + + +
+
+ +
+

+ Powered by + sub2clash +

+

Version {{.Version}}

+
+
+ + diff --git a/api/static/index.js b/api/static/index.js new file mode 100644 index 0000000..2e9d9ea --- /dev/null +++ b/api/static/index.js @@ -0,0 +1,415 @@ +function clearExistingValues() { + // 清除简单输入框和复选框的值 + document.getElementById("endpoint").value = "clash"; + document.getElementById("sub").value = ""; + document.getElementById("proxy").value = ""; + document.getElementById("refresh").checked = false; + document.getElementById("autoTest").checked = false; + document.getElementById("lazy").checked = false; + document.getElementById("template").value = ""; + document.getElementById("sort").value = "nameasc"; + document.getElementById("remove").value = ""; + document.getElementById("apiLink").value = ""; + document.getElementById("apiShortLink").value = ""; + document.getElementById("password").value = ""; + document.getElementById("nodeList").checked = false; + + // 清除由 createRuleProvider, createReplace, 和 createRule 创建的所有额外输入组 + clearInputGroup("ruleProviderGroup"); + clearInputGroup("replaceGroup"); + clearInputGroup("ruleGroup"); +} + +function generateURI() { + const queryParams = []; + + // 获取 API Endpoint + const endpoint = document.getElementById("endpoint").value; + + // 获取并组合订阅链接 + let subLines = document + .getElementById("sub") + .value.split("\n") + .filter((line) => line.trim() !== ""); + let noSub = false; + // 去除 subLines 中空元素 + subLines = subLines.map((item) => { + if (item !== "") { + return item; + } + }); + if (subLines.length > 0) { + queryParams.push(`sub=${encodeURIComponent(subLines.join(","))}`); + } else { + noSub = true; + } + + // 获取并组合节点分享链接 + let proxyLines = document + .getElementById("proxy") + .value.split("\n") + .filter((line) => line.trim() !== ""); + let noProxy = false; + // 去除 proxyLines 中空元素 + proxyLines = proxyLines.map((item) => { + if (item !== "") { + return item; + } + }); + if (proxyLines.length > 0) { + queryParams.push(`proxy=${encodeURIComponent(proxyLines.join(","))}`); + } else { + noProxy = true; + } + if (noSub && noProxy) { + alert("订阅链接和节点分享链接不能同时为空!"); + return ""; + } + // 获取复选框的值 + const refresh = document.getElementById("refresh").checked; + queryParams.push(`refresh=${refresh ? "true" : "false"}`); + const autoTest = document.getElementById("autoTest").checked; + queryParams.push(`autoTest=${autoTest ? "true" : "false"}`); + const lazy = document.getElementById("lazy").checked; + queryParams.push(`lazy=${lazy ? "true" : "false"}`); + const nodeList = document.getElementById("nodeList").checked; + queryParams.push(`nodeList=${nodeList ? "true" : "false"}`); + + // 获取模板链接或名称(如果存在) + const template = document.getElementById("template").value; + if (template.trim() !== "") { + queryParams.push(`template=${encodeURIComponent(template)}`); + } + + // 获取Rule Provider和规则 + const ruleProviders = document.getElementsByName("ruleProvider"); + const rules = document.getElementsByName("rule"); + let providers = []; + for (let i = 0; i < ruleProviders.length / 5; i++) { + let baseIndex = i * 5; + let behavior = ruleProviders[baseIndex].value; + let url = ruleProviders[baseIndex + 1].value; + let group = ruleProviders[baseIndex + 2].value; + let prepend = ruleProviders[baseIndex + 3].value; + let name = ruleProviders[baseIndex + 4].value; + // 是否存在空值 + if ( + behavior.trim() === "" || + url.trim() === "" || + group.trim() === "" || + prepend.trim() === "" || + name.trim() === "" + ) { + alert("Rule Provider 中存在空值,请检查后重试!"); + return ""; + } + providers.push(`[${behavior},${url},${group},${prepend},${name}]`); + } + queryParams.push(`ruleProvider=${encodeURIComponent(providers.join(","))}`); + + let ruleList = []; + for (let i = 0; i < rules.length / 3; i++) { + if (rules[i * 3].value.trim() !== "") { + let rule = rules[i * 3].value; + let prepend = rules[i * 3 + 1].value; + let group = rules[i * 3 + 2].value; + // 是否存在空值 + if (rule.trim() === "" || prepend.trim() === "" || group.trim() === "") { + alert("Rule 中存在空值,请检查后重试!"); + return ""; + } + ruleList.push(`[${rule},${prepend},${group}]`); + } + } + queryParams.push(`rule=${encodeURIComponent(ruleList.join(","))}`); + + // 获取排序策略 + const sort = document.getElementById("sort").value; + queryParams.push(`sort=${sort}`); + + // 获取删除节点的正则表达式 + const remove = document.getElementById("remove").value; + if (remove.trim() !== "") { + queryParams.push(`remove=${encodeURIComponent(remove)}`); + } + + // 获取替换节点名称的正则表达式 + let replaceList = []; + const replaces = document.getElementsByName("replace"); + for (let i = 0; i < replaces.length / 2; i++) { + let replaceStr = `<${replaces[i * 2].value}>`; + let replaceTo = `<${replaces[i * 2 + 1].value}>`; + if (replaceStr.trim() === "") { + alert("重命名设置中存在空值,请检查后重试!"); + return ""; + } + replaceList.push(`[${replaceStr},${replaceTo}]`); + } + queryParams.push(`replace=${encodeURIComponent(replaceList.join(","))}`); + + return `${endpoint}?${queryParams.join("&")}`; +} + +// 将输入框中的 URL 解析为参数 +function parseInputURL() { + // 获取输入框中的 URL + const inputURL = document.getElementById("urlInput").value; + + if (!inputURL) { + alert("请输入有效的链接!"); + return; + } + + let url; + try { + url = new URL(inputURL); + } catch (_) { + alert("无效的链接!"); + return; + } + + // 清除现有的输入框值 + clearExistingValues(); + + // 获取查询参数 + const params = new URLSearchParams(url.search); + + // 分配值到对应的输入框 + const pathSections = url.pathname.split("/"); + const lastSection = pathSections[pathSections.length - 1]; + const clientTypeSelect = document.getElementById("endpoint"); + switch (lastSection.toLowerCase()) { + case "meta": + clientTypeSelect.value = "meta"; + break; + case "clash": + default: + clientTypeSelect.value = "clash"; + break; + } + + if (params.has("sub")) { + document.getElementById("sub").value = decodeURIComponent(params.get("sub")) + .split(",") + .join("\n"); + } + + if (params.has("proxy")) { + document.getElementById("proxy").value = decodeURIComponent( + params.get("proxy"), + ) + .split(",") + .join("\n"); + } + + if (params.has("refresh")) { + document.getElementById("refresh").checked = + params.get("refresh") === "true"; + } + + if (params.has("autoTest")) { + document.getElementById("autoTest").checked = + params.get("autoTest") === "true"; + } + + if (params.has("lazy")) { + document.getElementById("lazy").checked = params.get("lazy") === "true"; + } + + if (params.has("template")) { + document.getElementById("template").value = decodeURIComponent( + params.get("template"), + ); + } + + if (params.has("sort")) { + document.getElementById("sort").value = params.get("sort"); + } + + if (params.has("remove")) { + document.getElementById("remove").value = decodeURIComponent( + params.get("remove"), + ); + } + + if (params.has("replace")) { + parseAndFillReplaceParams(decodeURIComponent(params.get("replace"))); + } + + if (params.has("ruleProvider")) { + parseAndFillRuleProviderParams( + decodeURIComponent(params.get("ruleProvider")), + ); + } + + if (params.has("rule")) { + parseAndFillRuleParams(decodeURIComponent(params.get("rule"))); + } + + if (params.has("nodeList")) { + document.getElementById("nodeList").checked = + params.get("nodeList") === "true"; + } +} + +function clearInputGroup(groupId) { + // 清空第二个之后的child + const group = document.getElementById(groupId); + while (group.children.length > 2) { + group.removeChild(group.lastChild); + } +} + +function parseAndFillReplaceParams(replaceParams) { + const replaceGroup = document.getElementById("replaceGroup"); + let matches; + const regex = /\[(<.*?>),(<.*?>)\]/g; + const str = decodeURIComponent(replaceParams); + while ((matches = regex.exec(str)) !== null) { + const div = createReplace(); + const original = matches[1].slice(1, -1); // Remove < and > + const replacement = matches[2].slice(1, -1); // Remove < and > + + div.children[0].value = original; + div.children[1].value = replacement; + replaceGroup.appendChild(div); + } +} + +function parseAndFillRuleProviderParams(ruleProviderParams) { + const ruleProviderGroup = document.getElementById("ruleProviderGroup"); + let matches; + const regex = /\[(.*?),(.*?),(.*?),(.*?),(.*?)\]/g; + const str = decodeURIComponent(ruleProviderParams); + while ((matches = regex.exec(str)) !== null) { + const div = createRuleProvider(); + div.children[0].value = matches[1]; + div.children[1].value = matches[2]; + div.children[2].value = matches[3]; + div.children[3].value = matches[4]; + div.children[4].value = matches[5]; + ruleProviderGroup.appendChild(div); + } +} + +function parseAndFillRuleParams(ruleParams) { + const ruleGroup = document.getElementById("ruleGroup"); + let matches; + const regex = /\[(.*?),(.*?),(.*?)\]/g; + const str = decodeURIComponent(ruleParams); + while ((matches = regex.exec(str)) !== null) { + const div = createRule(); + div.children[0].value = matches[1]; + div.children[1].value = matches[2]; + div.children[2].value = matches[3]; + ruleGroup.appendChild(div); + } +} + +async function copyToClipboard(elem, e) { + const apiLinkInput = document.querySelector(`#${elem}`).value; + try { + await navigator.clipboard.writeText(apiLinkInput); + let text = e.textContent; + e.addEventListener("mouseout", function () { + e.textContent = text; + }); + e.textContent = "复制成功"; + } catch (err) { + console.error("复制到剪贴板失败:", err); + } +} + +function createRuleProvider() { + const div = document.createElement("div"); + div.classList.add("input-group", "mb-2"); + div.innerHTML = ` + + + + + + + `; + return div; +} + +function createReplace() { + const div = document.createElement("div"); + div.classList.add("input-group", "mb-2"); + div.innerHTML = ` + + + + `; + return div; +} + +function createRule() { + const div = document.createElement("div"); + div.classList.add("input-group", "mb-2"); + div.innerHTML = ` + + + + + `; + return div; +} + +function addRuleProvider() { + const div = createRuleProvider(); + document.getElementById("ruleProviderGroup").appendChild(div); +} + +function addRule() { + const div = createRule(); + document.getElementById("ruleGroup").appendChild(div); +} + +function addReplace() { + const div = createReplace(); + document.getElementById("replaceGroup").appendChild(div); +} + +function removeElement(button) { + button.parentElement.remove(); +} + +function generateURL() { + const apiLink = document.getElementById("apiLink"); + let uri = generateURI(); + if (uri === "") { + return; + } + apiLink.value = `${window.location.origin}${window.location.pathname}${uri}`; +} + +function generateShortLink() { + const apiShortLink = document.getElementById("apiShortLink"); + const password = document.getElementById("password"); + let uri = generateURI(); + if (uri === "") { + return; + } + axios + .post( + "./short", + { + url: uri, + password: password.value.trim(), + }, + { + headers: { + "Content-Type": "application/json", + }, + }, + ) + .then((response) => { + apiShortLink.value = `${window.location.origin}${window.location.pathname}s/${response.data}`; + }) + .catch((error) => { + console.log(error); + alert("生成短链失败,请重试!"); + }); +} diff --git a/api/templates/index.html b/api/templates/index.html deleted file mode 100644 index 8ddf9dc..0000000 --- a/api/templates/index.html +++ /dev/null @@ -1,688 +0,0 @@ - - - - - - sub2clash - - - - - - - - - - - - - - -
-
-

sub2clash

- 通用订阅链接转 Clash(Meta) 配置工具 - 使用文档 -
- - - -
- -
- - -
-
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - - -
- -
- - - -
-
- - - - -
-
- - -
-

- Powered by - sub2clash -

-

Version {{.Version}}

-
-
- - - - diff --git a/model/contry_map.go b/model/country_code_map.go similarity index 100% rename from model/contry_map.go rename to model/country_code_map.go diff --git a/model/proxy.go b/model/proxy.go index 290101d..b6784a9 100644 --- a/model/proxy.go +++ b/model/proxy.go @@ -4,24 +4,6 @@ type SmuxStruct struct { Enabled bool `yaml:"enable"` } -type VmessJson struct { - V string `json:"v"` - Ps string `json:"ps"` - Add string `json:"add"` - Port interface{} `json:"port"` - Id string `json:"id"` - Aid interface{} `json:"aid"` - Scy string `json:"scy"` - Net string `json:"net"` - Type string `json:"type"` - Host string `json:"host"` - Path string `json:"path"` - Tls string `json:"tls"` - Sni string `json:"sni"` - Alpn string `json:"alpn"` - Fp string `json:"fp"` -} - type Proxy struct { Name string `yaml:"name,omitempty"` Server string `yaml:"server,omitempty"` diff --git a/model/proxy_vmess.go b/model/proxy_vmess.go index 5753a3e..f70d41f 100644 --- a/model/proxy_vmess.go +++ b/model/proxy_vmess.go @@ -27,6 +27,24 @@ type WSOptions struct { EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` } +type VmessJson struct { + V string `json:"v"` + Ps string `json:"ps"` + Add string `json:"add"` + Port interface{} `json:"port"` + Id string `json:"id"` + Aid interface{} `json:"aid"` + Scy string `json:"scy"` + Net string `json:"net"` + Type string `json:"type"` + Host string `json:"host"` + Path string `json:"path"` + Tls string `json:"tls"` + Sni string `json:"sni"` + Alpn string `json:"alpn"` + Fp string `json:"fp"` +} + type Vmess struct { Type string `yaml:"type"` Name string `yaml:"name"` diff --git a/model/sub.go b/model/sub.go index 7d255b6..2bab7b7 100644 --- a/model/sub.go +++ b/model/sub.go @@ -12,3 +12,7 @@ type Subscription struct { Rules []string `yaml:"rules,omitempty"` RuleProviders map[string]RuleProvider `yaml:"rule-providers,omitempty,omitempty"` } + +type NodeList struct { + Proxies []Proxy `yaml:"proxies,omitempty"` +} diff --git a/validator/sub.go b/validator/sub.go index aca9116..14e0fff 100644 --- a/validator/sub.go +++ b/validator/sub.go @@ -29,6 +29,7 @@ type SubValidator struct { Replace string `form:"replace" binding:""` ReplaceKeys []string `form:"-" binding:""` ReplaceTo []string `form:"-" binding:""` + NodeListMode bool `form:"nodeList,default=false" binding:""` } type RuleProviderStruct struct { From 6f075ea44e868058ff07fe4a8f26ce26bc0bb4a7 Mon Sep 17 00:00:00 2001 From: nitezs Date: Mon, 25 Sep 2023 23:58:13 +0800 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=B0=86?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E5=90=8D=E7=A7=B0=E6=B7=BB=E5=8A=A0=E5=88=B0?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=90=8D=E4=B8=AD=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20feat:=20=E5=A2=9E=E5=8A=A0=E5=9C=B0=E5=8C=BA=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- API_README.md | 2 +- README.md | 1 + api/controller/default.go | 48 +++++++++++++++++++++++++++++++++------ model/proxy.go | 1 + utils/proxy.go | 9 ++++---- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/API_README.md b/API_README.md index 0959b57..57ed577 100644 --- a/API_README.md +++ b/API_README.md @@ -4,7 +4,7 @@ | Query 参数 | 类型 | 是否必须 | 默认值 | 说明 | |--------------|--------|-------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| sub | string | sub/proxy 至少有一项存在 | - | 订阅链接(可以输入多个,用 `,` 分隔) | +| sub | string | sub/proxy 至少有一项存在 | - | 订阅链接,可以在链接结尾加上`#名称`,来给订阅中的节点加上统一前缀(可以输入多个,用 `,` 分隔) | | proxy | string | sub/proxy 至少有一项存在 | - | 节点分享链接(可以输入多个,用 `,` 分隔) | | refresh | bool | 否 | `false` | 强制刷新配置(默认缓存 5 分钟) | | template | string | 否 | - | 外部模板链接或内部模板名称 | diff --git a/README.md b/README.md index 3d87036..7d3e183 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ - `` 为添加所有节点 - `` 为添加所有国家策略组 +- `<地区二位字母代码>` 为添加指定地区所有节点,例如 `` 将添加所有香港节点 #### 默认模板 diff --git a/api/controller/default.go b/api/controller/default.go index e0eed50..0f2676f 100644 --- a/api/controller/default.go +++ b/api/controller/default.go @@ -58,6 +58,10 @@ func BuildSub(clashType model.ClashType, query validator.SubValidator, template // 加载订阅 for i := range query.Subs { data, err := utils.LoadSubscription(query.Subs[i], query.Refresh) + subName := "" + if strings.Contains(query.Subs[i], "#") { + subName = query.Subs[i][strings.LastIndex(query.Subs[i], "#")+1:] + } if err != nil { logger.Logger.Debug( "load subscription failed", zap.String("url", query.Subs[i]), zap.Error(err), @@ -66,11 +70,12 @@ func BuildSub(clashType model.ClashType, query validator.SubValidator, template } // 解析订阅 err = yaml.Unmarshal(data, &sub) + newProxies := make([]model.Proxy, 0) if err != nil { reg, _ := regexp.Compile("(ssr|ss|vmess|trojan|vless)://") if reg.Match(data) { p := utils.ParseProxy(strings.Split(string(data), "\n")...) - proxyList = append(proxyList, p...) + newProxies = p } else { // 如果无法直接解析,尝试Base64解码 base64, err := parser.DecodeBase64(string(data)) @@ -83,16 +88,28 @@ func BuildSub(clashType model.ClashType, query validator.SubValidator, template return nil, errors.New("加载订阅失败: " + err.Error()) } p := utils.ParseProxy(strings.Split(base64, "\n")...) - proxyList = append(proxyList, p...) + newProxies = p } } else { - proxyList = append(proxyList, sub.Proxies...) + newProxies = sub.Proxies } + if subName != "" { + for i := range newProxies { + newProxies[i].SubName = subName + } + } + proxyList = append(proxyList, newProxies...) } // 添加自定义节点 if len(query.Proxies) != 0 { proxyList = append(proxyList, utils.ParseProxy(query.Proxies...)...) } + // 给节点添加订阅名称 + for i := range proxyList { + if proxyList[i].SubName != "" { + proxyList[i].Name = strings.TrimSpace(proxyList[i].SubName) + " " + strings.TrimSpace(proxyList[i].Name) + } + } // 去掉配置相同的节点 proxies := make(map[string]*model.Proxy) newProxies := make([]model.Proxy, 0, len(proxyList)) @@ -233,11 +250,28 @@ func MergeSubAndTemplate(temp *model.Subscription, sub *model.Subscription) { continue } newProxies := make([]string, 0, len(temp.ProxyGroups[i].Proxies)) + countryGroupMap := make(map[string]model.ProxyGroup) + for _, v := range sub.ProxyGroups { + if v.IsCountryGrop { + countryGroupMap[v.Name] = v + } + } for j := range temp.ProxyGroups[i].Proxies { - if temp.ProxyGroups[i].Proxies[j] == "" { - newProxies = append(newProxies, proxyNames...) - } else if temp.ProxyGroups[i].Proxies[j] == "" { - newProxies = append(newProxies, countryGroupNames...) + reg := regexp.MustCompile("<(.*?)>") + if reg.Match([]byte(temp.ProxyGroups[i].Proxies[j])) { + key := reg.FindStringSubmatch(temp.ProxyGroups[i].Proxies[j])[1] + switch key { + case "all": + newProxies = append(newProxies, proxyNames...) + case "countries": + newProxies = append(newProxies, countryGroupNames...) + default: + if len(key) == 2 { + newProxies = append( + newProxies, countryGroupMap[utils.GetContryName(key)].Proxies..., + ) + } + } } else { newProxies = append(newProxies, temp.ProxyGroups[i].Proxies[j]) } diff --git a/model/proxy.go b/model/proxy.go index b6784a9..a8faee1 100644 --- a/model/proxy.go +++ b/model/proxy.go @@ -44,6 +44,7 @@ type Proxy struct { AuthenticatedLength bool `yaml:"authenticated-length,omitempty"` UDPOverTCP bool `yaml:"udp-over-tcp,omitempty"` UDPOverTCPVersion int `yaml:"udp-over-tcp-version,omitempty"` + SubName string `yaml:"-"` } func (p Proxy) MarshalYAML() (interface{}, error) { diff --git a/utils/proxy.go b/utils/proxy.go index b16f8d8..a6ba7bd 100644 --- a/utils/proxy.go +++ b/utils/proxy.go @@ -8,7 +8,7 @@ import ( "sub2clash/parser" ) -func GetContryName(proxy model.Proxy) string { +func GetContryName(countryKey string) string { // 创建一个切片包含所有的国家映射 countryMaps := []map[string]string{ model.CountryFlag, @@ -25,7 +25,7 @@ func GetContryName(proxy model.Proxy) string { splitChars := []string{"-", "_", " "} key := make([]string, 0) for _, splitChar := range splitChars { - slic := strings.Split(proxy.Name, splitChar) + slic := strings.Split(countryKey, splitChar) for _, v := range slic { if len(v) == 2 { key = append(key, v) @@ -41,12 +41,11 @@ func GetContryName(proxy model.Proxy) string { } } for k, v := range countryMap { - if strings.Contains(proxy.Name, k) { + if strings.Contains(countryKey, k) { return v } } } - return "其他地区" } @@ -62,7 +61,7 @@ func AddProxy( } sub.Proxies = append(sub.Proxies, proxy) haveProxyGroup := false - countryName := GetContryName(proxy) + countryName := GetContryName(proxy.Name) for i := range sub.ProxyGroups { group := &sub.ProxyGroups[i] From edfd70a77d83716d511a9bc1e64f27492f38b15a Mon Sep 17 00:00:00 2001 From: nitezs Date: Wed, 27 Sep 2023 14:54:53 +0800 Subject: [PATCH 6/6] modify --- API_README.md | 1 + README.md | 3 +-- config/config.go | 20 ++++++++++---------- templates/template_meta.yaml | 2 ++ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/API_README.md b/API_README.md index 57ed577..583d1b8 100644 --- a/API_README.md +++ b/API_README.md @@ -15,6 +15,7 @@ | sort | string | 否 | `nameasc` | 国家策略组排序策略,可选值 `nameasc`、`namedesc`、`sizeasc`、`sizedesc` | | replace | string | 否 | - | 通过正则表达式重命名节点,格式 `[,],[,]...` | | remove | string | 否 | - | 通过正则表达式删除节点 | +| nodeList | bool | 否 | `false` | 只输出节点 | | # `/short` diff --git a/README.md b/README.md index 7d3e183..a343498 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ | 变量名 | 说明 | 默认值 | |-----------------------|-----------------------------------------------------------|-----------------------| -| BASE_PATH | 程序运行子路径,例如将服务反代在 `https://example.com/sub` 则此变量值应为 `/sub` | `/` | | PORT | 端口 | `8011` | | META_TEMPLATE | meta 模板文件名 | `template_meta.yaml` | | CLASH_TEMPLATE | clash 模板文件名 | `template_clash.yaml` | @@ -37,7 +36,7 @@ | LOG_LEVEL | 日志等级,可选值 `debug`,`info`,`warn`,`error` | `info` | | SHORT_LINK_LENGTH | 短链长度 | `6` | -### API +### API [API文档](./API_README.md) diff --git a/config/config.go b/config/config.go index 2371992..fe67c6d 100644 --- a/config/config.go +++ b/config/config.go @@ -15,8 +15,8 @@ type Config struct { RequestMaxFileSize int64 CacheExpire int64 LogLevel string - BasePath string - ShortLinkLength int + //BasePath string + ShortLinkLength int } var Default *Config @@ -32,8 +32,8 @@ func LoadConfig() error { Port: 8011, CacheExpire: 60 * 5, LogLevel: "info", - BasePath: "/", - ShortLinkLength: 6, + //BasePath: "/", + ShortLinkLength: 6, } _ = godotenv.Load() if os.Getenv("PORT") != "" { @@ -73,12 +73,12 @@ func LoadConfig() error { if os.Getenv("LOG_LEVEL") != "" { Default.LogLevel = os.Getenv("LOG_LEVEL") } - if os.Getenv("BASE_PATH") != "" { - Default.BasePath = os.Getenv("BASE_PATH") - if Default.BasePath[len(Default.BasePath)-1] != '/' { - Default.BasePath += "/" - } - } + //if os.Getenv("BASE_PATH") != "" { + // Default.BasePath = os.Getenv("BASE_PATH") + // if Default.BasePath[len(Default.BasePath)-1] != '/' { + // Default.BasePath += "/" + // } + //} if os.Getenv("SHORT_LINK_LENGTH") != "" { atoi, err := strconv.Atoi(os.Getenv("SHORT_LINK_LENGTH")) if err != nil { diff --git a/templates/template_meta.yaml b/templates/template_meta.yaml index 8885bf4..5d47b72 100644 --- a/templates/template_meta.yaml +++ b/templates/template_meta.yaml @@ -111,9 +111,11 @@ rules: - GEOSITE,microsoft,Microsoft - GEOSITE,apple,Apple - GEOSITE,netflix,Netflix + - GEOIP,netflix,Netflix - GEOSITE,onedrive,Onedrive - GEOSITE,youtube,Youtube - GEOSITE,telegram,Telegram + - GEOIP,telegram,Telegram - GEOSITE,openai,OpenAI - GEOSITE,bilibili,哔哩哔哩 - GEOSITE,bahamut,巴哈姆特