mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-27 16:22:11 +08:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0498ba3e4f | ||
|
|
f39644ee6b | ||
|
|
488f022c05 | ||
|
|
eefd025806 |
@@ -75,7 +75,7 @@ jobs:
|
|||||||
if: steps.check_frontend.outputs.frontend == 'true'
|
if: steps.check_frontend.outputs.frontend == 'true'
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
|
|
||||||
- name: Run TypeScript typecheck
|
- name: Run tsrs typecheck
|
||||||
if: steps.check_frontend.outputs.frontend == 'true'
|
if: steps.check_frontend.outputs.frontend == 'true'
|
||||||
run: pnpm typecheck
|
run: pnpm typecheck
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
- 修复通过 URL 导入订阅时,即使导入的订阅并非当前使用的订阅,也会重新加载当前配置
|
- 修复通过 URL 导入订阅时,即使导入的订阅并非当前使用的订阅,也会重新加载当前配置
|
||||||
- 修复 首页 网站测速失败后卡片一直显示测试中
|
- 修复 首页 网站测速失败后卡片一直显示测试中
|
||||||
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
|
- 修复 代理 页展开分组后不显示最新测速结果,需切换节点才刷新
|
||||||
|
- 修复 代理 在全局模式下无法展开节点组
|
||||||
|
|
||||||
**🐧 Linux**
|
**🐧 Linux**
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@
|
|||||||
<summary><strong> ✨ 新增功能 </strong></summary>
|
<summary><strong> ✨ 新增功能 </strong></summary>
|
||||||
|
|
||||||
- 新增虚拟网卡设置的「DNS 模式」选项,支持配置 mihomo 系统 DNS 行为
|
- 新增虚拟网卡设置的「DNS 模式」选项,支持配置 mihomo 系统 DNS 行为
|
||||||
|
- 新增「IP 信息」自动刷新开关,关闭后仍可手动刷新
|
||||||
|
- 新增 Muse AI 解锁检测,针对 Muse AI 特有的 Cloudflare 人机验证增加「Risky」状态标记
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ mod chatgpt;
|
|||||||
mod claude;
|
mod claude;
|
||||||
mod disney_plus;
|
mod disney_plus;
|
||||||
mod gemini;
|
mod gemini;
|
||||||
|
mod muse;
|
||||||
mod netflix;
|
mod netflix;
|
||||||
mod prime_video;
|
mod prime_video;
|
||||||
mod spotify;
|
mod spotify;
|
||||||
@@ -30,6 +31,7 @@ enum UnlockCheck {
|
|||||||
ChatGptWeb,
|
ChatGptWeb,
|
||||||
Claude,
|
Claude,
|
||||||
Gemini,
|
Gemini,
|
||||||
|
MuseAi,
|
||||||
YouTubePremium,
|
YouTubePremium,
|
||||||
BahamutAnime,
|
BahamutAnime,
|
||||||
Netflix,
|
Netflix,
|
||||||
@@ -46,6 +48,7 @@ impl UnlockCheck {
|
|||||||
Self::ChatGptWeb,
|
Self::ChatGptWeb,
|
||||||
Self::Claude,
|
Self::Claude,
|
||||||
Self::Gemini,
|
Self::Gemini,
|
||||||
|
Self::MuseAi,
|
||||||
Self::YouTubePremium,
|
Self::YouTubePremium,
|
||||||
Self::BahamutAnime,
|
Self::BahamutAnime,
|
||||||
Self::Netflix,
|
Self::Netflix,
|
||||||
@@ -66,6 +69,7 @@ impl UnlockCheck {
|
|||||||
Self::ChatGptWeb => chatgpt::CHATGPT_WEB_NAME,
|
Self::ChatGptWeb => chatgpt::CHATGPT_WEB_NAME,
|
||||||
Self::Claude => claude::CLAUDE_NAME,
|
Self::Claude => claude::CLAUDE_NAME,
|
||||||
Self::Gemini => gemini::GEMINI_NAME,
|
Self::Gemini => gemini::GEMINI_NAME,
|
||||||
|
Self::MuseAi => muse::MUSE_AI_NAME,
|
||||||
Self::YouTubePremium => youtube::YOUTUBE_PREMIUM_NAME,
|
Self::YouTubePremium => youtube::YOUTUBE_PREMIUM_NAME,
|
||||||
Self::BahamutAnime => bahamut::BAHAMUT_ANIME_NAME,
|
Self::BahamutAnime => bahamut::BAHAMUT_ANIME_NAME,
|
||||||
Self::Netflix => netflix::NETFLIX_NAME,
|
Self::Netflix => netflix::NETFLIX_NAME,
|
||||||
@@ -83,6 +87,7 @@ impl UnlockCheck {
|
|||||||
Self::ChatGptWeb => chatgpt::check_chatgpt(client).await,
|
Self::ChatGptWeb => chatgpt::check_chatgpt(client).await,
|
||||||
Self::Claude => claude::check_claude(client).await,
|
Self::Claude => claude::check_claude(client).await,
|
||||||
Self::Gemini => gemini::check_gemini(client).await,
|
Self::Gemini => gemini::check_gemini(client).await,
|
||||||
|
Self::MuseAi => muse::check_muse_ai(client).await,
|
||||||
Self::YouTubePremium => youtube::check_youtube_premium(client).await,
|
Self::YouTubePremium => youtube::check_youtube_premium(client).await,
|
||||||
Self::BahamutAnime => bahamut::check_bahamut_anime(client).await,
|
Self::BahamutAnime => bahamut::check_bahamut_anime(client).await,
|
||||||
Self::Netflix => netflix::check_netflix(client).await,
|
Self::Netflix => netflix::check_netflix(client).await,
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
use crate::utils::{classify_restricted_status, get_trace_location};
|
||||||
|
|
||||||
|
use super::UnlockItem;
|
||||||
|
|
||||||
|
pub(crate) const MUSE_AI_NAME: &str = "Muse AI";
|
||||||
|
|
||||||
|
const MUSE_URL: &str = "https://muse.ai";
|
||||||
|
const CLOUDFLARE_TRACE_URL: &str = "https://www.cloudflare.com/cdn-cgi/trace";
|
||||||
|
|
||||||
|
// The aymh ("Are You a Human") gateway answers plain HTTP requests with a
|
||||||
|
// generic Meta error page that always contains the Facebook logo asset.
|
||||||
|
const AYMH_ERROR_MARKERS: &[&str] = &["Sorry, something went wrong", "static.facebook.com/images/logos"];
|
||||||
|
|
||||||
|
pub(super) async fn check_muse_ai(client: &Client) -> UnlockItem {
|
||||||
|
// muse.ai itself is served by Vercel, so resolve the exit region through
|
||||||
|
// the generic Cloudflare trace endpoint instead of a service-specific one.
|
||||||
|
let region = get_trace_location(client, CLOUDFLARE_TRACE_URL)
|
||||||
|
.await
|
||||||
|
.map(|code| code.trim().to_ascii_uppercase())
|
||||||
|
.map(|code| UnlockItem::region_label(&code));
|
||||||
|
|
||||||
|
let Ok(response) = client.get(MUSE_URL).send().await else {
|
||||||
|
return UnlockItem::checked(MUSE_AI_NAME, "Failed (Network Connection)", region);
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = response.status();
|
||||||
|
let landed_on_aymh = response.url().host_str() == Some("auth.muse.ai");
|
||||||
|
let body = response.text().await.unwrap_or_default();
|
||||||
|
|
||||||
|
// Every region is redirected to the aymh anti-bot gateway before the app
|
||||||
|
// loads, and a non-browser HTTP client cannot finish the JavaScript
|
||||||
|
// challenge. It returns the Meta error page, so reaching this point only
|
||||||
|
// proves the exit can connect to Muse's auth infrastructure; availability
|
||||||
|
// cannot be verified over plain HTTP and is reported as `Risky`.
|
||||||
|
let behind_anti_bot = landed_on_aymh || AYMH_ERROR_MARKERS.iter().any(|marker| body.contains(marker));
|
||||||
|
|
||||||
|
let result = if behind_anti_bot {
|
||||||
|
"Risky"
|
||||||
|
} else if status.is_success() {
|
||||||
|
"Yes"
|
||||||
|
} else {
|
||||||
|
classify_restricted_status(status).unwrap_or("Failed")
|
||||||
|
};
|
||||||
|
|
||||||
|
UnlockItem::checked(MUSE_AI_NAME, result, region)
|
||||||
|
}
|
||||||
+3
-2
@@ -14,7 +14,7 @@
|
|||||||
"build:fast": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build -- --profile fast-release",
|
"build:fast": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build -- --profile fast-release",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"web:dev": "vite",
|
"web:dev": "vite",
|
||||||
"web:build": "tsc --noEmit && vite build",
|
"web:build": "tsrs -p . --noEmit && vite build",
|
||||||
"web:serve": "vite preview",
|
"web:serve": "vite preview",
|
||||||
"prebuild": "node scripts/prebuild.mjs",
|
"prebuild": "node scripts/prebuild.mjs",
|
||||||
"updater": "node scripts/updater.mjs",
|
"updater": "node scripts/updater.mjs",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"i18n:types": "node scripts/generate-i18n-keys.mjs",
|
"i18n:types": "node scripts/generate-i18n-keys.mjs",
|
||||||
"gen:contract": "node scripts/gen-contract.mjs",
|
"gen:contract": "node scripts/gen-contract.mjs",
|
||||||
"arch:check": "node scripts/check-architecture.mjs listen emit invoke",
|
"arch:check": "node scripts/check-architecture.mjs listen emit invoke",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsrs -p . --noEmit",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
"knip:check": "knip",
|
"knip:check": "knip",
|
||||||
@@ -128,6 +128,7 @@
|
|||||||
"sass": "^1.104.1",
|
"sass": "^1.104.1",
|
||||||
"tar": "^7.5.22",
|
"tar": "^7.5.22",
|
||||||
"terser": "^5.51.2",
|
"terser": "^5.51.2",
|
||||||
|
"tsrs": "0.20.0-ts7.1.0-beta",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"typescript-eslint": "^8.70.0",
|
"typescript-eslint": "^8.70.0",
|
||||||
"vite": "^8.3.0",
|
"vite": "^8.3.0",
|
||||||
|
|||||||
Generated
+88
-3
@@ -416,6 +416,9 @@ importers:
|
|||||||
terser:
|
terser:
|
||||||
specifier: ^5.51.2
|
specifier: ^5.51.2
|
||||||
version: 5.51.2
|
version: 5.51.2
|
||||||
|
tsrs:
|
||||||
|
specifier: 0.20.0-ts7.1.0-beta
|
||||||
|
version: 0.20.0-ts7.1.0-beta
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
@@ -2218,6 +2221,52 @@ packages:
|
|||||||
'@tauri-apps/plugin-updater@2.14.0':
|
'@tauri-apps/plugin-updater@2.14.0':
|
||||||
resolution: {integrity: sha512-gdylJ9tger4hkyOn24QZd6MNOKVo2Eh53iw5th2Qj1vKTR/+u4PIwJWuiis5hohYvobn6iOvlnALfrqIPSzh7Q==}
|
resolution: {integrity: sha512-gdylJ9tger4hkyOn24QZd6MNOKVo2Eh53iw5th2Qj1vKTR/+u4PIwJWuiis5hohYvobn6iOvlnALfrqIPSzh7Q==}
|
||||||
|
|
||||||
|
'@tsrs/darwin-arm64@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-mhHj8QGUmdJDBvJEnMXx5P/jvAKXYU3hy/z3qxrWBo8XHlbLES32PgC0ZpTRbJA960ReTpVqqvCOYaC6EL32/Q==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tsrs/darwin-x64@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-CsRUnyYRLrhmChS7ol7LgmdqMXTu+mVlDU+7JgbW8RpkJRGLZ/zgEDEOeD8qrndt8rpP9oW1T1SJ36HSzB3/sg==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tsrs/linux-arm64-gnu@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-VNwpdI/iICwQMMlS/MoSZCvKFByEn2+g7D0HREWG+3r3GRayXgbLv8iaNSHKT3QGcu8pXr3lH9170ghJQi2zRg==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tsrs/linux-arm64-musl@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-cXnqPpmj5gzeGi4u1OV0ctd5df5t4ivwyeToCa4pBrKtjYodu0EeAo5Y76SHbJwggbiA1gzEJVj1vvuciQm5mQ==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tsrs/linux-x64-gnu@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-jlhJSrO9lxNh0TF5EU1i+Frok5sRWsBvCuQhmdqMZKIN2pSHsDZl3CSmKUsJ4tNr50np9USCPpkkxwby2Eiqhg==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tsrs/linux-x64-musl@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-pestGEPplhEPzIERc7zwuQ5zhh9ZwMSvAPNQy5TM0je/QuaizmM1zKoPYJ4NiaPzLh2M25HtP4HcpumTqmF3KQ==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tsrs/win32-x64@0.20.0-ts7.1.0-beta':
|
||||||
|
resolution: {integrity: sha512-sstxBfhjjOSYvSHFfSmROau2oGAVNLwAnj+H0h+ywLo7N7ueFKIDk14HAkIYa/F9iVboiICCpHDY/pmBO71sSg==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@tybys/wasm-util@0.10.4':
|
'@tybys/wasm-util@0.10.4':
|
||||||
resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==}
|
resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==}
|
||||||
|
|
||||||
@@ -4770,6 +4819,11 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tsrs@0.20.0-ts7.1.0-beta:
|
||||||
|
resolution: {integrity: sha512-8NifAn2tcna3t/nluu1yFvp0fYE28vElDpnD4jiWik69+MDjiHgxdjH8sUYUEFmf/2hl6QIE5ExVGpJzQbBDPw==}
|
||||||
|
engines: {node: '>=16.20.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
tunnel@0.0.6:
|
tunnel@0.0.6:
|
||||||
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
||||||
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
|
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
|
||||||
@@ -6882,6 +6936,27 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tauri-apps/api': 2.12.4
|
'@tauri-apps/api': 2.12.4
|
||||||
|
|
||||||
|
'@tsrs/darwin-arm64@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/darwin-x64@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/linux-arm64-gnu@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/linux-arm64-musl@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/linux-x64-gnu@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/linux-x64-musl@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tsrs/win32-x64@0.20.0-ts7.1.0-beta':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@tybys/wasm-util@0.10.4':
|
'@tybys/wasm-util@0.10.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
@@ -7222,7 +7297,7 @@ snapshots:
|
|||||||
|
|
||||||
'@wdio/globals@9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))':
|
'@wdio/globals@9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
expect-webdriverio: 6.1.0(@wdio/globals@9.31.3)(@wdio/logger@10.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
expect-webdriverio: 6.1.0(@wdio/globals@9.31.3)(@wdio/logger@9.29.1)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
||||||
webdriverio: 10.1.0(supports-color@7.2.0)(yauzl@2.10.0)
|
webdriverio: 10.1.0(supports-color@7.2.0)(yauzl@2.10.0)
|
||||||
|
|
||||||
'@wdio/logger@10.1.0':
|
'@wdio/logger@10.1.0':
|
||||||
@@ -8206,11 +8281,11 @@ snapshots:
|
|||||||
|
|
||||||
expect-type@1.4.0: {}
|
expect-type@1.4.0: {}
|
||||||
|
|
||||||
expect-webdriverio@6.1.0(@wdio/globals@9.31.3)(@wdio/logger@10.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0)):
|
expect-webdriverio@6.1.0(@wdio/globals@9.31.3)(@wdio/logger@9.29.1)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/snapshot': 4.1.11
|
'@vitest/snapshot': 4.1.11
|
||||||
'@wdio/globals': 9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
'@wdio/globals': 9.31.3(expect-webdriverio@6.1.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
|
||||||
'@wdio/logger': 10.1.0
|
'@wdio/logger': 9.29.1
|
||||||
deep-eql: 5.0.2
|
deep-eql: 5.0.2
|
||||||
expect: 30.5.2
|
expect: 30.5.2
|
||||||
jest-matcher-utils: 30.5.2
|
jest-matcher-utils: 30.5.2
|
||||||
@@ -9865,6 +9940,16 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tsrs@0.20.0-ts7.1.0-beta:
|
||||||
|
optionalDependencies:
|
||||||
|
'@tsrs/darwin-arm64': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/darwin-x64': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/linux-arm64-gnu': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/linux-arm64-musl': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/linux-x64-gnu': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/linux-x64-musl': 0.20.0-ts7.1.0-beta
|
||||||
|
'@tsrs/win32-x64': 0.20.0-ts7.1.0-beta
|
||||||
|
|
||||||
tunnel@0.0.6: {}
|
tunnel@0.0.6: {}
|
||||||
|
|
||||||
type-check@0.4.0:
|
type-check@0.4.0:
|
||||||
|
|||||||
@@ -10,3 +10,11 @@ allowBuilds:
|
|||||||
unrs-resolver: true
|
unrs-resolver: true
|
||||||
minimumReleaseAgeExclude:
|
minimumReleaseAgeExclude:
|
||||||
- dayjs@1.11.21
|
- dayjs@1.11.21
|
||||||
|
- "@tsrs/darwin-arm64@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/darwin-x64@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/linux-arm64-gnu@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/linux-arm64-musl@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/linux-x64-gnu@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/linux-x64-musl@0.20.0-ts7.1.0-beta"
|
||||||
|
- "@tsrs/win32-x64@0.20.0-ts7.1.0-beta"
|
||||||
|
- tsrs@0.20.0-ts7.1.0-beta
|
||||||
|
|||||||
@@ -79,6 +79,13 @@
|
|||||||
"matchPackageNames": ["typescript"],
|
"matchPackageNames": ["typescript"],
|
||||||
"allowedVersions": "<7.0.0 || >=7.1.0"
|
"allowedVersions": "<7.0.0 || >=7.1.0"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Review tsrs bumps alone; the version encodes the pinned TypeScript release",
|
||||||
|
"matchPackageNames": ["tsrs", "/^@tsrs//"],
|
||||||
|
"groupName": "tsrs",
|
||||||
|
"rangeStrategy": "pin",
|
||||||
|
"automerge": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Prevent project from supply chain attack",
|
"description": "Prevent project from supply chain attack",
|
||||||
"matchDatasources": ["npm"],
|
"matchDatasources": ["npm"],
|
||||||
|
|||||||
@@ -4,10 +4,19 @@ import {
|
|||||||
VisibilityOffOutlined,
|
VisibilityOffOutlined,
|
||||||
VisibilityOutlined,
|
VisibilityOutlined,
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import { Box, Button, IconButton, Skeleton, Typography } from '@mui/material'
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
FormControlLabel,
|
||||||
|
IconButton,
|
||||||
|
Skeleton,
|
||||||
|
Switch,
|
||||||
|
Typography,
|
||||||
|
} from '@mui/material'
|
||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||||
import { useEffect } from 'foxact/use-abortable-effect'
|
import { useEffect } from 'foxact/use-abortable-effect'
|
||||||
import { useIntersection } from 'foxact/use-intersection'
|
import { useIntersection } from 'foxact/use-intersection'
|
||||||
|
import { useLocalStorage } from 'foxact/use-local-storage'
|
||||||
import type { XOR } from 'foxts/ts-xor'
|
import type { XOR } from 'foxts/ts-xor'
|
||||||
import {
|
import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
@@ -99,9 +108,13 @@ const IPInfoCardContainer = forwardRef<HTMLElement, React.PropsWithChildren>(
|
|||||||
export const IpInfoCard = () => {
|
export const IpInfoCard = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [showIp, setShowIp] = useState(false)
|
const [showIp, setShowIp] = useState(false)
|
||||||
|
const [autoRefresh, setAutoRefresh] = useLocalStorage(
|
||||||
|
'ip-info-auto-refresh',
|
||||||
|
true,
|
||||||
|
)
|
||||||
const appWindow = useMemo(() => getCurrentWebviewWindow(), [])
|
const appWindow = useMemo(() => getCurrentWebviewWindow(), [])
|
||||||
|
|
||||||
// Once intersected, refreshes stay enabled until unmount.
|
// Once intersected, the card stays eligible for refresh until unmount.
|
||||||
const [containerRef, hasIntersected, _resetIntersected] = useIntersection({
|
const [containerRef, hasIntersected, _resetIntersected] = useIntersection({
|
||||||
rootMargin: '0px',
|
rootMargin: '0px',
|
||||||
})
|
})
|
||||||
@@ -151,6 +164,8 @@ export const IpInfoCard = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!autoRefresh) return
|
||||||
|
|
||||||
let timer: number | null = null
|
let timer: number | null = null
|
||||||
|
|
||||||
// Prefer DOM intersection state; Tauri visibility is unreliable on some platforms.
|
// Prefer DOM intersection state; Tauri visibility is unreliable on some platforms.
|
||||||
@@ -190,7 +205,7 @@ export const IpInfoCard = () => {
|
|||||||
if (timer != null) clearInterval(timer)
|
if (timer != null) clearInterval(timer)
|
||||||
document.removeEventListener('visibilitychange', onVisibilityChange)
|
document.removeEventListener('visibilitychange', onVisibilityChange)
|
||||||
}
|
}
|
||||||
}, [hasIntersected])
|
}, [autoRefresh, hasIntersected])
|
||||||
|
|
||||||
const toggleShowIp = useCallback(() => {
|
const toggleShowIp = useCallback(() => {
|
||||||
setShowIp((prev) => !prev)
|
setShowIp((prev) => !prev)
|
||||||
@@ -364,12 +379,25 @@ export const IpInfoCard = () => {
|
|||||||
fontSize: '0.7rem',
|
fontSize: '0.7rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="caption">
|
<FormControlLabel
|
||||||
{t('home.components.ipInfo.labels.autoRefresh')}
|
sx={{ m: 0 }}
|
||||||
{countdown.type === 'countdown'
|
control={
|
||||||
? `: ${countdown.remainingSeconds}s`
|
<Switch
|
||||||
: '...'}
|
size="small"
|
||||||
</Typography>
|
checked={autoRefresh}
|
||||||
|
onChange={(_, checked) => setAutoRefresh(checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<Typography variant="caption">
|
||||||
|
{t('home.components.ipInfo.labels.autoRefresh')}
|
||||||
|
{autoRefresh &&
|
||||||
|
(countdown.type === 'countdown'
|
||||||
|
? `: ${countdown.remainingSeconds}s`
|
||||||
|
: '...')}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
variant="caption"
|
variant="caption"
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ function NormalProxyGroups(props: { mode: string }) {
|
|||||||
/>
|
/>
|
||||||
</DragDropProvider>
|
</DragDropProvider>
|
||||||
|
|
||||||
{mode === 'rule' && (
|
{(mode === 'rule' || mode === 'global') && (
|
||||||
<ProxyGroupNavigator
|
<ProxyGroupNavigator
|
||||||
proxyGroupNames={proxyGroupNames}
|
proxyGroupNames={proxyGroupNames}
|
||||||
onGroupLocation={handleGroupLocationByName}
|
onGroupLocation={handleGroupLocationByName}
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ export const useRenderList = (
|
|||||||
if (!proxyView) return []
|
if (!proxyView) return []
|
||||||
if (isChainMode)
|
if (isChainMode)
|
||||||
return selectedGroup ? [selectedGroup] : [CHAIN_DELAY_GROUP]
|
return selectedGroup ? [selectedGroup] : [CHAIN_DELAY_GROUP]
|
||||||
return mode === 'rule' || mode === 'script'
|
return mode === 'rule' || mode === 'global'
|
||||||
? proxyView.groups.map(({ name }) => name)
|
? proxyView.groups.map(({ name }) => name)
|
||||||
: proxyView.global
|
: proxyView.global
|
||||||
? [proxyView.global.name]
|
? [proxyView.global.name]
|
||||||
@@ -257,7 +257,7 @@ export const useRenderList = (
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRule = mode === 'rule' || mode === 'script'
|
const useRule = mode === 'rule' || mode === 'global'
|
||||||
const renderGroups = useRule
|
const renderGroups = useRule
|
||||||
? proxyView.groups
|
? proxyView.groups
|
||||||
: proxyView.global === null
|
: proxyView.global === null
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
"risky": "غير مؤكد",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"disallowedIsp": "Disallowed ISP",
|
"disallowedIsp": "Disallowed ISP",
|
||||||
"originalsOnly": "Originals Only",
|
"originalsOnly": "Originals Only",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Unterstützt",
|
"yes": "Unterstützt",
|
||||||
"no": "Nicht unterstützt",
|
"no": "Nicht unterstützt",
|
||||||
"failed": "Test fehlgeschlagen",
|
"failed": "Test fehlgeschlagen",
|
||||||
|
"risky": "Ungewiss",
|
||||||
"completed": "Prüfung abgeschlossen",
|
"completed": "Prüfung abgeschlossen",
|
||||||
"disallowedIsp": "Nicht zugelassener Internetdienstanbieter",
|
"disallowedIsp": "Nicht zugelassener Internetdienstanbieter",
|
||||||
"originalsOnly": "Nur Original",
|
"originalsOnly": "Nur Original",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
"risky": "Risky",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"disallowedIsp": "Disallowed ISP",
|
"disallowedIsp": "Disallowed ISP",
|
||||||
"originalsOnly": "Originals Only",
|
"originalsOnly": "Originals Only",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Soportado",
|
"yes": "Soportado",
|
||||||
"no": "No soportado",
|
"no": "No soportado",
|
||||||
"failed": "Prueba fallida",
|
"failed": "Prueba fallida",
|
||||||
|
"risky": "Dudoso",
|
||||||
"completed": "Detección completada",
|
"completed": "Detección completada",
|
||||||
"disallowedIsp": "Proveedor de servicios de Internet no permitido",
|
"disallowedIsp": "Proveedor de servicios de Internet no permitido",
|
||||||
"originalsOnly": "Solo originales",
|
"originalsOnly": "Solo originales",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
"risky": "نامشخص",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"disallowedIsp": "Disallowed ISP",
|
"disallowedIsp": "Disallowed ISP",
|
||||||
"originalsOnly": "Originals Only",
|
"originalsOnly": "Originals Only",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
"risky": "Tidak pasti",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"disallowedIsp": "Disallowed ISP",
|
"disallowedIsp": "Disallowed ISP",
|
||||||
"originalsOnly": "Originals Only",
|
"originalsOnly": "Originals Only",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "サポートする",
|
"yes": "サポートする",
|
||||||
"no": "サポートしない",
|
"no": "サポートしない",
|
||||||
"failed": "テストに失敗しました。",
|
"failed": "テストに失敗しました。",
|
||||||
|
"risky": "要確認",
|
||||||
"completed": "検査完了",
|
"completed": "検査完了",
|
||||||
"disallowedIsp": "許可されていないインターネットサービスプロバイダー",
|
"disallowedIsp": "許可されていないインターネットサービスプロバイダー",
|
||||||
"originalsOnly": "オリジナルのみ",
|
"originalsOnly": "オリジナルのみ",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "예",
|
"yes": "예",
|
||||||
"no": "아니오",
|
"no": "아니오",
|
||||||
"failed": "실패",
|
"failed": "실패",
|
||||||
|
"risky": "확인 필요",
|
||||||
"completed": "완료",
|
"completed": "완료",
|
||||||
"disallowedIsp": "허용되지 않는 ISP",
|
"disallowedIsp": "허용되지 않는 ISP",
|
||||||
"originalsOnly": "오리지널만",
|
"originalsOnly": "오리지널만",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Sim",
|
"yes": "Sim",
|
||||||
"no": "Não",
|
"no": "Não",
|
||||||
"failed": "Falhou",
|
"failed": "Falhou",
|
||||||
|
"risky": "Incerto",
|
||||||
"completed": "Concluído",
|
"completed": "Concluído",
|
||||||
"disallowedIsp": "ISP não permitido",
|
"disallowedIsp": "ISP não permitido",
|
||||||
"originalsOnly": "Somente originais",
|
"originalsOnly": "Somente originais",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Да",
|
"yes": "Да",
|
||||||
"no": "Нет",
|
"no": "Нет",
|
||||||
"failed": "Ошибка",
|
"failed": "Ошибка",
|
||||||
|
"risky": "Неясно",
|
||||||
"completed": "Завершено",
|
"completed": "Завершено",
|
||||||
"disallowedIsp": "Провайдер заблокирован",
|
"disallowedIsp": "Провайдер заблокирован",
|
||||||
"originalsOnly": "Только Originals",
|
"originalsOnly": "Только Originals",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Evet",
|
"yes": "Evet",
|
||||||
"no": "Hayır",
|
"no": "Hayır",
|
||||||
"failed": "Başarısız",
|
"failed": "Başarısız",
|
||||||
|
"risky": "Belirsiz",
|
||||||
"completed": "Tamamlandı",
|
"completed": "Tamamlandı",
|
||||||
"disallowedIsp": "İzin Verilmeyen ISP",
|
"disallowedIsp": "İzin Verilmeyen ISP",
|
||||||
"originalsOnly": "Yalnızca Orijinaller",
|
"originalsOnly": "Yalnızca Orijinaller",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
"risky": "Билгесез",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"disallowedIsp": "Disallowed ISP",
|
"disallowedIsp": "Disallowed ISP",
|
||||||
"originalsOnly": "Originals Only",
|
"originalsOnly": "Originals Only",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "支持",
|
"yes": "支持",
|
||||||
"no": "不支持",
|
"no": "不支持",
|
||||||
"failed": "测试失败",
|
"failed": "测试失败",
|
||||||
|
"risky": "存疑",
|
||||||
"completed": "检测完成",
|
"completed": "检测完成",
|
||||||
"disallowedIsp": "不允许的 ISP",
|
"disallowedIsp": "不允许的 ISP",
|
||||||
"originalsOnly": "仅限原创",
|
"originalsOnly": "仅限原创",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"yes": "支援",
|
"yes": "支援",
|
||||||
"no": "不支援",
|
"no": "不支援",
|
||||||
"failed": "測試失敗",
|
"failed": "測試失敗",
|
||||||
|
"risky": "存疑",
|
||||||
"completed": "檢測完成",
|
"completed": "檢測完成",
|
||||||
"disallowedIsp": "不允許的網際網路服務供應商",
|
"disallowedIsp": "不允許的網際網路服務供應商",
|
||||||
"originalsOnly": "僅限原創",
|
"originalsOnly": "僅限原創",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const STATUS_LABEL_KEYS: Record<string, string> = {
|
|||||||
Yes: 'tests.statuses.test.yes',
|
Yes: 'tests.statuses.test.yes',
|
||||||
No: 'tests.statuses.test.no',
|
No: 'tests.statuses.test.no',
|
||||||
Failed: 'tests.statuses.test.failed',
|
Failed: 'tests.statuses.test.failed',
|
||||||
|
Risky: 'tests.statuses.test.risky',
|
||||||
Completed: 'tests.statuses.test.completed',
|
Completed: 'tests.statuses.test.completed',
|
||||||
'Disallowed ISP': 'tests.statuses.test.disallowedIsp',
|
'Disallowed ISP': 'tests.statuses.test.disallowedIsp',
|
||||||
'Originals Only': 'tests.statuses.test.originalsOnly',
|
'Originals Only': 'tests.statuses.test.originalsOnly',
|
||||||
@@ -196,7 +197,7 @@ const UnlockPage = () => {
|
|||||||
if (status === 'Pending') return 'default'
|
if (status === 'Pending') return 'default'
|
||||||
if (status === 'Yes') return 'success'
|
if (status === 'Yes') return 'success'
|
||||||
if (status === 'No') return 'error'
|
if (status === 'No') return 'error'
|
||||||
if (status === 'Soon') return 'warning'
|
if (status === 'Soon' || status === 'Risky') return 'warning'
|
||||||
if (status.includes('Failed')) return 'error'
|
if (status.includes('Failed')) return 'error'
|
||||||
if (status === 'Completed') return 'info'
|
if (status === 'Completed') return 'info'
|
||||||
if (
|
if (
|
||||||
@@ -222,7 +223,8 @@ const UnlockPage = () => {
|
|||||||
const getStatusBorderColor = (status: string) => {
|
const getStatusBorderColor = (status: string) => {
|
||||||
if (status === 'Yes') return theme.palette.success.main
|
if (status === 'Yes') return theme.palette.success.main
|
||||||
if (status === 'No') return theme.palette.error.main
|
if (status === 'No') return theme.palette.error.main
|
||||||
if (status === 'Soon') return theme.palette.warning.main
|
if (status === 'Soon' || status === 'Risky')
|
||||||
|
return theme.palette.warning.main
|
||||||
if (status.includes('Failed')) return theme.palette.error.main
|
if (status.includes('Failed')) return theme.palette.error.main
|
||||||
if (status === 'Completed') return theme.palette.info.main
|
if (status === 'Completed') return theme.palette.info.main
|
||||||
return theme.palette.divider
|
return theme.palette.divider
|
||||||
|
|||||||
Reference in New Issue
Block a user