From 27a5dadf8688bc7e9d9d50f7696020cfad3e62c4 Mon Sep 17 00:00:00 2001 From: fangsy Date: Sat, 1 Feb 2025 22:05:49 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=94=AF=E6=8C=81CFW=E7=9A=84YAML=20parser?= =?UTF-8?q?s=E5=8A=9F=E8=83=BD(prepend-proxies,prepend-proxy-groups,prepen?= =?UTF-8?q?d-rules),=E5=9C=A8=E8=AE=A2=E9=98=85=E9=93=BE=E6=8E=A5=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0parsers=3DYmlUrl(URLEncoded)=E5=8D=B3=E5=8F=AF?= =?UTF-8?q?=E9=80=82=E7=94=A8parsers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/golang/native/config/fetch.go | 117 +++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/core/src/main/golang/native/config/fetch.go b/core/src/main/golang/native/config/fetch.go index ba08ebccbd..1e1ac4dc30 100644 --- a/core/src/main/golang/native/config/fetch.go +++ b/core/src/main/golang/native/config/fetch.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "fmt" + "github.com/metacubex/mihomo/log" + "gopkg.in/yaml.v3" "io" "net/http" U "net/url" @@ -34,6 +36,36 @@ func openUrl(ctx context.Context, url string) (io.ReadCloser, error) { return response.Body, nil } +func openUrlAsString(ctx context.Context, url string) (string, error) { + body, requestErr := openUrl(ctx, url) + + if requestErr != nil { + return "", requestErr + } + + // 读取所有数据并转换为byte数组 + data, err := io.ReadAll(body) + defer body.Close() + if err != nil { + return "", err + } + // 将数据转为字符串 + content := string(data) + return content, nil +} + +func openUrlAsYaml(ctx context.Context, url string) (map[string]interface{}, error) { + content, _ := openUrlAsString(ctx, url) + // 定义一个结构体来存储 YAML 解析结果 + var config map[string]interface{} // 假设 config 是一个 map + // 解析 YAML 内容 + err := yaml.Unmarshal([]byte(content), &config) + if err != nil { + return nil, err + } + return config, nil +} + func openContent(url string) (io.ReadCloser, error) { return app.OpenContent(url) } @@ -60,6 +92,14 @@ func fetch(url *U.URL, file string) error { defer reader.Close() + data, err := io.ReadAll(reader) + if err != nil { + return err + } + content := string(data) + parsedContent := applyParsers(ctx, content, url) + log.Debugln("最终subscribe:%s", parsedContent) + _ = os.MkdirAll(P.Dir(file), 0700) f, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600) @@ -69,7 +109,7 @@ func fetch(url *U.URL, file string) error { defer f.Close() - _, err = io.Copy(f, reader) + _, err = f.WriteString(parsedContent) if err != nil { _ = os.Remove(file) } @@ -77,6 +117,81 @@ func fetch(url *U.URL, file string) error { return err } +func applyParsers(ctx context.Context, subscribeOriginalStr string, subscribeUrl *U.URL) string { + if !subscribeUrl.Query().Has("parsers") { + log.Debugln("需要处理parsers") + return subscribeOriginalStr + } + + // 定义一个结构体来存储 YAML 解析结果 + var subscribe map[string]interface{} + + // 解析 YAML 内容 + err := yaml.Unmarshal([]byte(subscribeOriginalStr), &subscribe) + if err != nil { + // 如果解析出错,返回错误信息作为字符串 + log.Debugln("failed to parse YAML: %v", err) + return fmt.Sprintf("failed to parse YAML: %v", err) + } + + var parsersUrl = subscribeUrl.Query().Get("parsers") + log.Debugln("找到parsersURL: %s", parsersUrl) + parsersContainerYml, parsersErr := openUrlAsYaml(ctx, parsersUrl) + if parsersErr != nil { + log.Debugln("拉取parsers失败: %v", parsersErr) + return subscribeOriginalStr + } + + parsersContainer, parsersContainerExist := parsersContainerYml["parsers"].(map[string]interface{}) + if !parsersContainerExist { + log.Debugln("parsers容器中不存在parsers节点") + return subscribeOriginalStr + } + + parsers, parsersExist := parsersContainer["yaml"].(map[string]interface{}) + if !parsersExist { + log.Debugln("parsers容器中不存在yaml节点") + return subscribeOriginalStr + } + + subscribe = prependArr(subscribe, "proxies", parsers, "prepend-proxies") + subscribe = prependArr(subscribe, "proxy-groups", parsers, "prepend-proxy-groups") + subscribe = prependArr(subscribe, "rules", parsers, "prepend-rules") + + // 将解析后的数据结构转回 YAML 格式的字符串 + yamlBytes, err := yaml.Marshal(subscribe) + if err != nil { + log.Debugln("failed to marshal YAML: %v", err) + return fmt.Sprintf("failed to marshal YAML: %v", err) + } + + // 返回解析后的 YAML 字符串 + return string(yamlBytes) +} + +func prependArr(subscribe map[string]interface{}, subscribeKey string, parsers map[string]interface{}, parserKey string) map[string]interface{} { + // 处理prepend-rules + if arrToPrepend, arrToPrependExist := parsers[parserKey].([]interface{}); arrToPrependExist { + log.Debugln("parses找到%s", parserKey) + // 提取 originalArr 字段 + if originalArr, originalArrExist := subscribe[subscribeKey].([]interface{}); originalArrExist { + log.Debugln("subscribe找到%s", subscribeKey) + // 将新的规则添加到 originalArr 数组的头部 + log.Debugln("subscribe原始%s:%v", subscribeKey, originalArr) + originalArr = append(arrToPrepend, originalArr...) + // 更新 subscribe 中的 originalArr 字段 + subscribe[subscribeKey] = originalArr + log.Debugln("subscribe编辑后%s:%v", subscribeKey, subscribe[subscribeKey]) + } else { + subscribe[subscribeKey] = arrToPrepend + log.Debugln("subscribe编辑后%s:%v", subscribeKey, subscribe[subscribeKey]) + } + } else { + log.Debugln("parses未找到%s", parserKey) + } + return subscribe +} + func FetchAndValid( path string, url string, From e6848776469f30696db29b167c5f7e7c00039a2b Mon Sep 17 00:00:00 2001 From: fangsy Date: Sat, 1 Feb 2025 22:15:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=8F=98=E6=9B=B4Build=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58a65bc9cb..5cc436f234 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Feature of [Clash.Meta](https://github.com/MetaCubeX/Clash.Meta) 5. Build ```bash - ./gradlew app:assembleMeta-AlphaRelease + ./gradlew app:assembleAlphaRelease ``` ### Automation From c71524248e81efccae5ca9c52f9889c7b7050a3f Mon Sep 17 00:00:00 2001 From: fsygk Date: Tue, 10 Feb 2026 22:56:25 +0800 Subject: [PATCH 3/3] replace keystore --- release.keystore | Bin 2723 -> 2674 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/release.keystore b/release.keystore index dbbba6310746a073595731838719a2760b396f0c..90632298de99ed04a2d79bf934a1a14f344ba061 100644 GIT binary patch delta 2527 zcmV<52_W{P74j4!FoFth0s#Xsf(jT02`Yw2hW8Bt2LYgh3JC;)3I#BN3IUNKF9kp_ zf(1O2_XQvn4#4(?rOZ3nq-$G!CGR%~tpvWplPd-!f5*{jTI{mZMVcBxwSsF&wFH6$ z(12^EZhct?(m}3-HnX~^<+NEo@)D9z+L$CWX%h@UL&>W`Vi9wFAbq2zncAGGCM+?F zQG%fv6T75%M|_^rG-=ENyt(rL3;6FS= zu`I7!k7=(HNI*a%hw{Q&I0aL`PE|d(QH=Zp>hUp&Gxg4@KH|)mv@zP z_0g62hoLo>q}mZ#-$;4IS~JhnNQ~upZPls^Rb)^!Ho}o;+}lhNh`$AYcTB2HysP zAPb#M_?2fjaF+Ng=x!@-7_;b6kJY}sHt`^dPOyP^+z0o5!XtO(M@C9mDfnU5^1_r% zbf-%%awt;Mf;&h4YIHc;WG`Q#%&w5qvu!?*>+@9L@dbGoUgYDS?cY7ne^Y&t=+OE^ z*4ewk*?uf#Rj1JthV*j@{a)CEfC>zPXKjmo4AgIzUeVM={kbyu+f$Bn&Ctnqk3rue|=5#-YlJ_EybA2#IiLkr8@``h!LIDWxX=WmOc8r#YMqx zZJeJjV2Vd`pI1(n?m4W9h)>5m5cfmPXVjlhyyA+PW=VqW>Sm#DsV~LUc+8&(dAMT* z*sHA}ma~NQa5{gj{>@0&ZxHVNiyZ_A!&*XMymI9HZD}5AH_grwHj(6HGBWFck&~ zDuzgg_YDCF6fp=MNCp670BrzaFd+sBDuzgg_YDCF6)_Y95>#nzWgsy(H!wFdH8V6b zF*GtTf&@_p2`Yw2hW8Bt2L_;m1VS)^1U>=*05F0CHtl&c+U?+6+X6q6{QNf zD7UDAIbHQ=g20RQyU>3@>>^+2q+(tfpOwzkbE%6l8P2K^0f@G#UpT6gj<%olDb+_v zjbd^NEug>?da?DmBn2ZU-UfduS+l0{i%nQ;qW&YXMYMm_GSW#=0zd9NDS4+1u)iUsN55T#LET8_JWt$o( zRa*4S(#wBa_nk_ECY#8LcMFR1mN8p!f9~vrK9Ijy6~vpbw&+ybDv-{~Ymo;$7^Qwo zD36T&y>-!FA;V<0S0GSAX92(aw{&ZOBnM zytsdQ(TMrTaZg}|1PwEXaEG1%Mu>>cwc5u%0?MS}$BTz$cCLF-xKKv`iT)|X_+XXA z@XEYl>9A%_#7w%F!7ybf;1Z1>N%LslBYh97`Q*$Vs8=rQF7&cU^V^h1%YX1CEP19&bt32844KcI}c~J?6YaXA3Fz{Y0F4;J5zuA zA_y&+qNC9O71OfpC00bZ?8>pOQvAYyA7{4~3VB{;vbQN=@ p>dpVMd7Lu6bk&hi1Qa0IJ?7SIxqU;Ec+*>bp8-Go=4}E3ClEil!pZ;u delta 2576 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