From a8275b20b73bd95a9d38b96c73770a897cf40b8f Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:37:54 +0800 Subject: [PATCH] refactor: extract media unlock checker crate --- Cargo.lock | 17 ++- Cargo.toml | 6 + crates/clash-verge-media-unlock/Cargo.toml | 18 +++ .../clash-verge-media-unlock/src}/bahamut.rs | 0 .../clash-verge-media-unlock/src}/bilibili.rs | 0 .../clash-verge-media-unlock/src}/chatgpt.rs | 0 .../clash-verge-media-unlock/src}/claude.rs | 0 .../src}/disney_plus.rs | 0 .../clash-verge-media-unlock/src}/gemini.rs | 0 crates/clash-verge-media-unlock/src/lib.rs | 113 +++++++++++++++++ .../clash-verge-media-unlock/src}/netflix.rs | 0 .../src}/prime_video.rs | 0 .../clash-verge-media-unlock/src}/spotify.rs | 0 .../clash-verge-media-unlock/src}/tiktok.rs | 0 .../clash-verge-media-unlock/src}/types.rs | 0 .../clash-verge-media-unlock/src}/utils.rs | 1 - .../clash-verge-media-unlock/src}/youtube.rs | 0 src-tauri/Cargo.toml | 8 +- src-tauri/src/cmd/media_unlock_checker/mod.rs | 114 +----------------- 19 files changed, 160 insertions(+), 117 deletions(-) create mode 100644 crates/clash-verge-media-unlock/Cargo.toml rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/bahamut.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/bilibili.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/chatgpt.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/claude.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/disney_plus.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/gemini.rs (100%) create mode 100644 crates/clash-verge-media-unlock/src/lib.rs rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/netflix.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/prime_video.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/spotify.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/tiktok.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/types.rs (100%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/utils.rs (99%) rename {src-tauri/src/cmd/media_unlock_checker => crates/clash-verge-media-unlock/src}/youtube.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e97694e11..91774f84c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1118,6 +1118,7 @@ dependencies = [ "clash-verge-i18n", "clash-verge-limiter", "clash-verge-logging", + "clash-verge-media-unlock", "clash-verge-signal", "clash_verge_logger", "clash_verge_service_ipc", @@ -1146,7 +1147,6 @@ dependencies = [ "reqwest 0.13.4", "reqwest_dav", "runas", - "rust_iso3166", "rustls", "scopeguard", "serde", @@ -1217,6 +1217,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "clash-verge-media-unlock" +version = "0.1.0" +dependencies = [ + "chrono", + "clash-verge-logging", + "log", + "regex", + "reqwest 0.13.4", + "rust_iso3166", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "clash-verge-signal" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 8efea70ae..e35d2c63f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "src-tauri", "crates/clash-verge-draft", + "crates/clash-verge-media-unlock", "crates/clash-verge-logging", "crates/clash-verge-signal", "crates/tauri-plugin-clash-verge-sysinfo", @@ -47,6 +48,7 @@ split-debuginfo = "unpacked" [workspace.dependencies] clash-verge-draft = { path = "crates/clash-verge-draft" } +clash-verge-media-unlock = { path = "crates/clash-verge-media-unlock" } clash-verge-logging = { path = "crates/clash-verge-logging" } clash-verge-signal = { path = "crates/clash-verge-signal" } clash-verge-i18n = { path = "crates/clash-verge-i18n" } @@ -57,6 +59,7 @@ tauri = { version = "2.11.5" } tauri-plugin-clipboard-manager = "2.3.2" parking_lot = { version = "0.12.5", features = ["hardware-lock-elision"] } anyhow = "1.0.104" +chrono = "0.4.45" criterion = { version = "0.8.2", features = ["async_tokio"] } tokio = { version = "1.53.1", features = [ "rt-multi-thread", @@ -66,6 +69,9 @@ tokio = { version = "1.53.1", features = [ ] } flexi_logger = "0.31.9" log = "0.4.33" +regex = "1.13.1" +reqwest = { version = "0.13.4", features = ["json", "cookies", "gzip", "rustls", "form"] } +rust_iso3166 = "0.2.0" smartstring = { version = "1.0.1" } compact_str = { version = "0.10.0", features = ["serde"] } diff --git a/crates/clash-verge-media-unlock/Cargo.toml b/crates/clash-verge-media-unlock/Cargo.toml new file mode 100644 index 000000000..b59f171c9 --- /dev/null +++ b/crates/clash-verge-media-unlock/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "clash-verge-media-unlock" +version = "0.1.0" +edition = "2024" + +[dependencies] +clash-verge-logging = { workspace = true } +chrono = { workspace = true } +log = { workspace = true } +regex = { workspace = true } +reqwest = { workspace = true } +rust_iso3166 = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +tokio = { workspace = true } + +[lints] +workspace = true diff --git a/src-tauri/src/cmd/media_unlock_checker/bahamut.rs b/crates/clash-verge-media-unlock/src/bahamut.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/bahamut.rs rename to crates/clash-verge-media-unlock/src/bahamut.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/bilibili.rs b/crates/clash-verge-media-unlock/src/bilibili.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/bilibili.rs rename to crates/clash-verge-media-unlock/src/bilibili.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/chatgpt.rs b/crates/clash-verge-media-unlock/src/chatgpt.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/chatgpt.rs rename to crates/clash-verge-media-unlock/src/chatgpt.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/claude.rs b/crates/clash-verge-media-unlock/src/claude.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/claude.rs rename to crates/clash-verge-media-unlock/src/claude.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/disney_plus.rs b/crates/clash-verge-media-unlock/src/disney_plus.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/disney_plus.rs rename to crates/clash-verge-media-unlock/src/disney_plus.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/gemini.rs b/crates/clash-verge-media-unlock/src/gemini.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/gemini.rs rename to crates/clash-verge-media-unlock/src/gemini.rs diff --git a/crates/clash-verge-media-unlock/src/lib.rs b/crates/clash-verge-media-unlock/src/lib.rs new file mode 100644 index 000000000..3abcf7b5a --- /dev/null +++ b/crates/clash-verge-media-unlock/src/lib.rs @@ -0,0 +1,113 @@ +use std::{future::Future, sync::Arc}; + +use reqwest::Client; +use tokio::task::JoinSet; + +use clash_verge_logging::{Type, logging}; + +mod bahamut; +mod bilibili; +mod chatgpt; +mod claude; +mod disney_plus; +mod gemini; +mod netflix; +mod prime_video; +mod spotify; +mod tiktok; +mod types; +mod utils; +mod youtube; + +pub use types::{UnlockItem, default_unlock_items}; + +use bahamut::check_bahamut_anime; +use bilibili::{check_bilibili_china_mainland, check_bilibili_hk_mc_tw}; +use chatgpt::check_chatgpt_combined; +use claude::check_claude; +use disney_plus::check_disney_plus; +use gemini::check_gemini; +use netflix::check_netflix; +use prime_video::check_prime_video; +use spotify::check_spotify; +use tiktok::check_tiktok; +use youtube::check_youtube_premium; + +type UnlockResults = Vec; + +fn spawn_unlock_check(tasks: &mut JoinSet, client: Arc, check: F) +where + F: FnOnce(Arc) -> Fut + Send + 'static, + Fut: Future + Send + 'static, +{ + tasks.spawn(async move { check(client).await }); +} + +fn single_result(item: UnlockItem) -> UnlockResults { + vec![item] +} + +pub async fn check_media_unlock() -> Result, String> { + let client = match Client::builder() + .use_rustls_tls() + .user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36") + .timeout(std::time::Duration::from_secs(30)) + .danger_accept_invalid_certs(true) + .danger_accept_invalid_hostnames(true) + .tcp_keepalive(std::time::Duration::from_secs(60)) + .connection_verbose(true) + .build() { + Ok(client) => client, + Err(e) => return Err(format!("创建HTTP客户端失败: {e}")), + }; + + let mut tasks = JoinSet::new(); + let client_arc = Arc::new(client); + + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_bilibili_china_mainland(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_bilibili_hk_mc_tw(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + check_chatgpt_combined(&client).await + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_claude(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_gemini(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_youtube_premium(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_bahamut_anime(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_netflix(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_disney_plus(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_spotify(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_tiktok(&client).await) + }); + spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { + single_result(check_prime_video(&client).await) + }); + + let mut results = Vec::new(); + while let Some(res) = tasks.join_next().await { + match res { + Ok(items) => results.extend(items), + Err(e) => logging!(error, Type::Network, "任务执行失败: {e}"), + } + } + + Ok(results) +} diff --git a/src-tauri/src/cmd/media_unlock_checker/netflix.rs b/crates/clash-verge-media-unlock/src/netflix.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/netflix.rs rename to crates/clash-verge-media-unlock/src/netflix.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/prime_video.rs b/crates/clash-verge-media-unlock/src/prime_video.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/prime_video.rs rename to crates/clash-verge-media-unlock/src/prime_video.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/spotify.rs b/crates/clash-verge-media-unlock/src/spotify.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/spotify.rs rename to crates/clash-verge-media-unlock/src/spotify.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/tiktok.rs b/crates/clash-verge-media-unlock/src/tiktok.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/tiktok.rs rename to crates/clash-verge-media-unlock/src/tiktok.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/types.rs b/crates/clash-verge-media-unlock/src/types.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/types.rs rename to crates/clash-verge-media-unlock/src/types.rs diff --git a/src-tauri/src/cmd/media_unlock_checker/utils.rs b/crates/clash-verge-media-unlock/src/utils.rs similarity index 99% rename from src-tauri/src/cmd/media_unlock_checker/utils.rs rename to crates/clash-verge-media-unlock/src/utils.rs index 0308b7dc0..9f63768cb 100644 --- a/src-tauri/src/cmd/media_unlock_checker/utils.rs +++ b/crates/clash-verge-media-unlock/src/utils.rs @@ -1,5 +1,4 @@ use chrono::Local; -use rust_iso3166; pub fn get_local_date_string() -> String { let now = Local::now(); diff --git a/src-tauri/src/cmd/media_unlock_checker/youtube.rs b/crates/clash-verge-media-unlock/src/youtube.rs similarity index 100% rename from src-tauri/src/cmd/media_unlock_checker/youtube.rs rename to crates/clash-verge-media-unlock/src/youtube.rs diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d45e85da8..c90f76c15 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -32,6 +32,7 @@ tauri-build = { version = "2.6.3", features = [] } [dependencies] clash-verge-draft = { workspace = true } +clash-verge-media-unlock = { workspace = true } clash-verge-logging = { workspace = true } clash-verge-signal = { workspace = true } clash-verge-i18n = { workspace = true } @@ -61,12 +62,12 @@ warp = { version = "0.4.3", features = ["server"] } open = "5.4.0" dunce = "1.0.5" nanoid = "0.5" -chrono = "0.4.45" +chrono = { workspace = true } boa_engine = "0.21.1" once_cell = { version = "1.21.4", features = ["parking_lot"] } percent-encoding = "2.3.2" -reqwest = { version = "0.13.4", features = ["json", "cookies", "gzip", "rustls", "form"] } -regex = "1.13.1" +reqwest = { workspace = true } +regex = { workspace = true } sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs", branch = "main", features = [ "guard", ] } @@ -101,7 +102,6 @@ arc-swap = "1.9.2" tokio-rustls = "0.26.4" rustls = { version = "0.23.43", features = ["ring"] } webpki-roots = "1.0.9" -rust_iso3166 = "0.2.0" # Use the git repo until the next release after v2.0.0. dark-light = { git = "https://github.com/rust-dark-light/dark-light" } bytes = "1.12.1" diff --git a/src-tauri/src/cmd/media_unlock_checker/mod.rs b/src-tauri/src/cmd/media_unlock_checker/mod.rs index 42dd252d9..33ca1d92e 100644 --- a/src-tauri/src/cmd/media_unlock_checker/mod.rs +++ b/src-tauri/src/cmd/media_unlock_checker/mod.rs @@ -1,120 +1,12 @@ -use std::{future::Future, sync::Arc}; - -use reqwest::Client; +pub use clash_verge_media_unlock::UnlockItem; use tauri::command; -use tokio::task::JoinSet; - -use clash_verge_logging::{Type, logging}; - -mod bahamut; -mod bilibili; -mod chatgpt; -mod claude; -mod disney_plus; -mod gemini; -mod netflix; -mod prime_video; -mod spotify; -mod tiktok; -mod types; -mod utils; -mod youtube; - -pub use types::UnlockItem; - -use bahamut::check_bahamut_anime; -use bilibili::{check_bilibili_china_mainland, check_bilibili_hk_mc_tw}; -use chatgpt::check_chatgpt_combined; -use claude::check_claude; -use disney_plus::check_disney_plus; -use gemini::check_gemini; -use netflix::check_netflix; -use prime_video::check_prime_video; -use spotify::check_spotify; -use tiktok::check_tiktok; -use youtube::check_youtube_premium; - -type UnlockResults = Vec; - -fn spawn_unlock_check(tasks: &mut JoinSet, client: Arc, check: F) -where - F: FnOnce(Arc) -> Fut + Send + 'static, - Fut: Future + Send + 'static, -{ - tasks.spawn(async move { check(client).await }); -} - -fn single_result(item: UnlockItem) -> UnlockResults { - vec![item] -} #[command] pub async fn get_unlock_items() -> Result, String> { - Ok(types::default_unlock_items()) + Ok(clash_verge_media_unlock::default_unlock_items()) } #[command] pub async fn check_media_unlock() -> Result, String> { - let client = match Client::builder() - .use_rustls_tls() - .user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36") - .timeout(std::time::Duration::from_secs(30)) - .danger_accept_invalid_certs(true) - .danger_accept_invalid_hostnames(true) - .tcp_keepalive(std::time::Duration::from_secs(60)) - .connection_verbose(true) - .build() { - Ok(client) => client, - Err(e) => return Err(format!("创建HTTP客户端失败: {e}")), - }; - - let mut tasks = JoinSet::new(); - let client_arc = Arc::new(client); - - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_bilibili_china_mainland(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_bilibili_hk_mc_tw(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - check_chatgpt_combined(&client).await - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_claude(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_gemini(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_youtube_premium(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_bahamut_anime(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_netflix(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_disney_plus(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_spotify(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_tiktok(&client).await) - }); - spawn_unlock_check(&mut tasks, Arc::clone(&client_arc), |client| async move { - single_result(check_prime_video(&client).await) - }); - - let mut results = Vec::new(); - while let Some(res) = tasks.join_next().await { - match res { - Ok(items) => results.extend(items), - Err(e) => logging!(error, Type::Network, "任务执行失败: {e}"), - } - } - - Ok(results) + clash_verge_media_unlock::check_media_unlock().await }