refactor: extract media unlock checker crate

This commit is contained in:
Tunglies
2026-08-04 11:37:54 +08:00
parent 544c47c634
commit a8275b20b7
19 changed files with 160 additions and 117 deletions
Generated
+16 -1
View File
@@ -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"
+6
View File
@@ -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"] }
@@ -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
+113
View File
@@ -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<UnlockItem>;
fn spawn_unlock_check<F, Fut>(tasks: &mut JoinSet<UnlockResults>, client: Arc<Client>, check: F)
where
F: FnOnce(Arc<Client>) -> Fut + Send + 'static,
Fut: Future<Output = UnlockResults> + Send + 'static,
{
tasks.spawn(async move { check(client).await });
}
fn single_result(item: UnlockItem) -> UnlockResults {
vec![item]
}
pub async fn check_media_unlock() -> Result<Vec<UnlockItem>, 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)
}
@@ -1,5 +1,4 @@
use chrono::Local;
use rust_iso3166;
pub fn get_local_date_string() -> String {
let now = Local::now();
+4 -4
View File
@@ -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"
+3 -111
View File
@@ -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<UnlockItem>;
fn spawn_unlock_check<F, Fut>(tasks: &mut JoinSet<UnlockResults>, client: Arc<Client>, check: F)
where
F: FnOnce(Arc<Client>) -> Fut + Send + 'static,
Fut: Future<Output = UnlockResults> + 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<Vec<UnlockItem>, String> {
Ok(types::default_unlock_items())
Ok(clash_verge_media_unlock::default_unlock_items())
}
#[command]
pub async fn check_media_unlock() -> Result<Vec<UnlockItem>, 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
}