#Clash
背景
最近發現我的 mac 上 spark 客戶端收不到 gmail 了,多方排查發現最終原因是因為我一直使用的 ss 服務商把 iplc 的郵件服務給遮蔽了,只能使用中繼來接收郵件。但是服務商提供的訂閱裡沒有單獨的 mail 規則,意味著要麼放棄 iplc 全盤使用中繼線路,要麼自己改寫規則。
解決方案
但是檢視了 clash 規則之後發現,classh 並沒有實現類似 quan、surge 一樣的節點訂閱與規則分離,這意味著就算我修改了當前規則,每次更新訂閱後又回恢復原狀,還需要再手動修改一次,這顯然是不能接受的,所以寫了個 node 服務來實現這個功能。
先來理清一下思路,實現規則與訂閱分離需要的步驟
- 有一份空的規則檔案
- 有一份節點列表
- 把節點列表的節點填充到規則檔案裡
- 替換掉當前的 clash 的 config 檔案
規則檔案我寫了一個 空規則,有需要的可以直接使用或者按照自己的實際需求更改。
節點列表首先需要你的服務商有提供 clash 的訂閱連結(如果是其他訂閱連結,需要自己改寫程式碼來轉換,或者找現成的訂閱轉換服務轉換為 clash)。
合併的程式碼如下
** 這裡需要注意,clash 最近更新了新版訂閱檔案規則,所以程式碼也有所更新,我的 github 並沒有實時更新(每次更新都要去掉敏感資訊)**
github.com/jinzhuming/clash-trs-ru...
// 引入網路請求模組
const request = require(“request”);
// yml 轉為 json 方便操作
const yaml = require(“js-yaml”);
// cron 定時執行
const schedule = require(“node-schedule”);
// json 轉為 yml
const YAML = require(“json-to-pretty-yaml”);
// rxjs 相關
const { forkJoin, of, Observable } = require(“rxjs”);
const fs = require(“fs”);
const { map } = require(“rxjs/operators”);
// 訂閱地址
const url = “www.xxoo.com/list”;
const getRules = () => {
// 獲取節點資訊
forkJoin(
new Observable(function (observer) {
request(url, function (error, response, body) {
if (error) {
observer.error();
} else {
observer.next(body);
}
observer.complete();
});
// 轉換為 json
}).pipe(map((proxiesConfigYml) => yaml.load(proxiesConfigYml))),
// 獲取空的規則檔案,如果是網路規則,自行 寫 request,forkjoin 會合並兩個資料
of(require(“./rule.json”)),
)
.pipe(
// 這裡可以做一些規則轉換操作,比如修改名稱,新增 icon,或者過濾節點
map(([proxiesConfigJson, rules]) => ({
…rules,
proxies: proxiesConfigJson.proxies
.filter((item) => !item.name.includes(“專線”) || !item.name.includes(“01”) || !item.name.includes(“日本”))
})),
// 這裡把過濾好的節點給寫入到 rules 的 proxy-groups 裡,同時對節點進行一個分組歸類效果,把指定地區的節點新增到各自的分類,還可以把節點新增到自己定義的 select 裡,按需操作即可
map((rules) => ({
…rules,
[“proxy-groups”]: rules[“proxy-groups”].map((item) => {
if (item.name === “Proxies”) {
return {
…item,
proxies: [“HK”, “SG”, “JP”, “US”, “TW”].concat(rules.proxies.map((proxy) => proxy.name)),
};
}
if (item.name === “HK”) {
return {
…item,
proxies:
rules.proxies.filter((proxy) => proxy.name.includes(“香港”)).map((proxy) => proxy.name),
};
}
if (item.name === “SG”) {
return {
…item,
proxies:
rules.proxies.filter((proxy) => proxy.name.includes(“新加坡”)).map((proxy) => proxy.name),
};
}
if (item.name === “JP”) {
return {
…item,
proxies:
rules.proxies.filter((proxy) => proxy.name.includes(“日本”)).map((proxy) => proxy.name),
};
}
if (item.name === “US”) {
return {
…item,
proxies:
rules.proxies.filter((proxy) => proxy.name.includes(“美國”)).map((proxy) => proxy.name),
};
}
if (item.name === “TW”) {
return {
…item,
proxies:
rules.proxies.filter((proxy) => proxy.name.includes(“臺灣”)).map((proxy) => proxy.name),
};
}
if (item.name === “Mail”) {
return {
…item,
proxies: rules.proxies.filter((proxy) => proxy.name.includes(“中繼”)).map((proxy) => proxy.name),
};
}
return item;
}),
})),
)
.subscribe((rules) => {
// 把我們轉換好的節點重新生成為 yml,然後寫入到 clash 的 config 目錄裡
const newRulesFile = YAML.stringify(rules);
fs.readFile(“/Users / 你的使用者名稱 /.config/clash/rules.yaml”, “utf-8”, (err, data) => {
// 判斷一下如果沒有發生變化就不替換了
if (data === newRulesFile) {
console.log(“相同不觸發替換”);
} else {
fs.writeFile(“/Users/jinzhuming/.config/clash/rules.yaml”, newRulesFile, () => {});
}
});
});
};
這樣就完成了基本的節點規則分離效果,接下來需要把服務設定為定時任務以及開機啟動,這樣每次開機都會自動啟動服務,在指定的時間更新節點資訊
定時啟動
// 根據 cron 設定執行時間,每天 13 點 30 分執行一次更新
const scheduleCronstyle = () => {
schedule.scheduleJob(“30 13 1 * * *”, () => {
getRules();
});
};
// 啟動服務的時候立即執行一次
getRules();
scheduleCronstyle();
開機啟動
- 寫一個 .startup.sh,然後在 偏好設定 - 使用者與群組 - 啟動項裡新增進這個檔案,每次開機就會自動執行命令
- pm2 維持服務
cd ~/ 服務所在資料夾 && pm2 start index.js —name ssRules
這樣就完成了最基本的節點訂閱和規則訂閱分離效果,自行改寫的訂閱連結也不會再因為更新而被覆蓋掉。目前已經穩定跑了幾個月了,需要什麼規則自己加,再也不依賴服務商了
本作品採用《CC 協議》,轉載必須註明作者和本文連結