fix: resolve Netflix detection error

This commit is contained in:
wonfen 2025-03-17 11:57:12 +08:00
parent 105de99d06
commit 70b0f9a03a

View File

@ -4,6 +4,7 @@ use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
use tauri::command; use tauri::command;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@ -453,39 +454,43 @@ async fn check_bahamut_anime(client: &Client) -> UnlockItem {
// 测试 Netflix // 测试 Netflix
async fn check_netflix(client: &Client) -> UnlockItem { async fn check_netflix(client: &Client) -> UnlockItem {
// 首先尝试使用Fast.com API检测Netflix CDN区域
let cdn_result = check_netflix_cdn(client).await;
if cdn_result.status == "Yes" {
return cdn_result;
}
// 如果CDN方法失败尝试传统的内容检测方法
// 测试两个 Netflix 内容 (LEGO Ninjago 和 Breaking Bad) // 测试两个 Netflix 内容 (LEGO Ninjago 和 Breaking Bad)
let url1 = "https://www.netflix.com/title/81280792"; // LEGO Ninjago let url1 = "https://www.netflix.com/title/81280792"; // LEGO Ninjago
let url2 = "https://www.netflix.com/title/70143836"; // Breaking Bad let url2 = "https://www.netflix.com/title/70143836"; // Breaking Bad
let headers = { // 创建简单的请求(不添加太多头部信息)
let mut headers = HeaderMap::new(); let result1 = client.get(url1)
headers.insert( .timeout(std::time::Duration::from_secs(30))
"accept-language", .send().await;
HeaderValue::from_static("en-US,en;q=0.9"),
);
headers.insert("sec-ch-ua-mobile", HeaderValue::from_static("?0"));
headers.insert(
"sec-ch-ua-platform",
HeaderValue::from_static("\"Windows\""),
);
headers.insert("sec-fetch-site", HeaderValue::from_static("none"));
headers.insert("sec-fetch-mode", HeaderValue::from_static("navigate"));
headers.insert("sec-fetch-user", HeaderValue::from_static("?1"));
headers.insert("sec-fetch-dest", HeaderValue::from_static("document"));
headers
};
// 执行第一个请求
let result1 = client.get(url1).headers(headers.clone()).send().await;
// 执行第二个请求
let result2 = client.get(url2).headers(headers.clone()).send().await;
// 检查连接失败情况 // 检查连接失败情况
if result1.is_err() || result2.is_err() { if let Err(e) = &result1 {
eprintln!("Netflix请求错误: {}", e);
return UnlockItem { return UnlockItem {
name: "Netflix".to_string(), name: "Netflix".to_string(),
status: "Failed (Network Connection)".to_string(), status: "Failed".to_string(),
region: None,
check_time: Some(get_local_date_string()),
};
}
// 如果第一个请求成功,尝试第二个请求
let result2 = client.get(url2)
.timeout(std::time::Duration::from_secs(30))
.send().await;
if let Err(e) = &result2 {
eprintln!("Netflix请求错误: {}", e);
return UnlockItem {
name: "Netflix".to_string(),
status: "Failed".to_string(),
region: None, region: None,
check_time: Some(get_local_date_string()), check_time: Some(get_local_date_string()),
}; };
@ -514,21 +519,23 @@ async fn check_netflix(client: &Client) -> UnlockItem {
}; };
} }
if status1 == 200 || status2 == 200 { if status1 == 200 || status1 == 301 || status2 == 200 || status2 == 301 {
// 成功解锁,尝试获取地区信息 // 成功解锁,尝试获取地区信息
match client // 使用Netflix测试内容获取区域
.get("https://www.netflix.com/") let test_url = "https://www.netflix.com/title/80018499";
.headers(headers) match client.get(test_url)
.timeout(std::time::Duration::from_secs(30))
.send() .send()
.await .await
{ {
Ok(response) => { Ok(response) => {
if let Ok(body) = response.text().await { // 检查重定向位置
// 使用正则表达式提取区域代码 if let Some(location) = response.headers().get("location") {
let re = Regex::new(r#""id":"([A-Z]{2})"#).unwrap(); if let Ok(location_str) = location.to_str() {
if let Some(caps) = re.captures(&body) { // 解析位置获取区域
if let Some(region_match) = caps.get(1) { let parts: Vec<&str> = location_str.split('/').collect();
let region_code = region_match.as_str(); if parts.len() >= 4 {
let region_code = parts[3].split('-').next().unwrap_or("unknown");
let emoji = country_code_to_emoji(region_code); let emoji = country_code_to_emoji(region_code);
return UnlockItem { return UnlockItem {
name: "Netflix".to_string(), name: "Netflix".to_string(),
@ -539,32 +546,108 @@ async fn check_netflix(client: &Client) -> UnlockItem {
} }
} }
} }
// 如果无法获取区域信息,仍然返回成功 // 如果没有重定向,假设是美国
let emoji = country_code_to_emoji("us");
UnlockItem { UnlockItem {
name: "Netflix".to_string(), name: "Netflix".to_string(),
status: "Yes".to_string(), status: "Yes".to_string(),
region: None, region: Some(format!("{}{}", emoji, "us")),
check_time: Some(get_local_date_string()), check_time: Some(get_local_date_string()),
} }
} }
Err(_) => UnlockItem { Err(e) => {
eprintln!("获取Netflix区域信息失败: {}", e);
UnlockItem {
name: "Netflix".to_string(), name: "Netflix".to_string(),
status: "Yes".to_string(), status: "Yes (但无法获取区域)".to_string(),
region: None, region: None,
check_time: Some(get_local_date_string()), check_time: Some(get_local_date_string()),
}
}, },
} }
} else { } else {
// 其他未知错误状态 // 其他未知错误状态
UnlockItem { UnlockItem {
name: "Netflix".to_string(), name: "Netflix".to_string(),
status: format!("Failed (Error: {}_{}", status1, status2), status: format!("Failed (状态码: {}_{}", status1, status2),
region: None, region: None,
check_time: Some(get_local_date_string()), check_time: Some(get_local_date_string()),
} }
} }
} }
// 使用Fast.com API检测Netflix CDN区域
async fn check_netflix_cdn(client: &Client) -> UnlockItem {
// Fast.com API URL
let url = "https://api.fast.com/netflix/speedtest/v2?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=5";
let result = client.get(url)
.timeout(std::time::Duration::from_secs(30))
.send().await;
match result {
Ok(response) => {
// 检查状态码
if response.status().as_u16() == 403 {
return UnlockItem {
name: "Netflix".to_string(),
status: "No (IP Banned By Netflix)".to_string(),
region: None,
check_time: Some(get_local_date_string()),
};
}
// 尝试解析响应
match response.json::<serde_json::Value>().await {
Ok(data) => {
// 尝试从数据中提取区域信息
if let Some(targets) = data.get("targets").and_then(|t| t.as_array()) {
if !targets.is_empty() {
if let Some(location) = targets[0].get("location") {
if let Some(country) = location.get("country").and_then(|c| c.as_str()) {
let emoji = country_code_to_emoji(country);
return UnlockItem {
name: "Netflix".to_string(),
status: "Yes".to_string(),
region: Some(format!("{}{}", emoji, country)),
check_time: Some(get_local_date_string()),
};
}
}
}
}
// 如果无法解析区域信息
return UnlockItem {
name: "Netflix".to_string(),
status: "Unknown".to_string(),
region: None,
check_time: Some(get_local_date_string()),
};
}
Err(e) => {
eprintln!("解析Fast.com API响应失败: {}", e);
UnlockItem {
name: "Netflix".to_string(),
status: "Failed (解析错误)".to_string(),
region: None,
check_time: Some(get_local_date_string()),
}
}
}
}
Err(e) => {
eprintln!("Fast.com API请求失败: {}", e);
UnlockItem {
name: "Netflix".to_string(),
status: "Failed (CDN API)".to_string(),
region: None,
check_time: Some(get_local_date_string()),
}
}
}
}
// 测试 Disney+ // 测试 Disney+
async fn check_disney_plus(client: &Client) -> UnlockItem { async fn check_disney_plus(client: &Client) -> UnlockItem {
// Disney+ 不支持 IPv6但这里不做额外检查因为我们使用的是系统默认网络 // Disney+ 不支持 IPv6但这里不做额外检查因为我们使用的是系统默认网络
@ -1072,9 +1155,14 @@ pub async fn get_unlock_items() -> Result<Vec<UnlockItem>, String> {
// 开始检测流媒体解锁状态 // 开始检测流媒体解锁状态
#[command] #[command]
pub async fn check_media_unlock() -> Result<Vec<UnlockItem>, String> { pub async fn check_media_unlock() -> Result<Vec<UnlockItem>, String> {
// 创建一个http客户端 // 创建一个http客户端,增加更多配置
let client = match Client::builder() let client = match Client::builder()
.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") .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) // 接受无效证书防止SSL错误
.danger_accept_invalid_hostnames(true) // 接受无效主机名
.tcp_keepalive(std::time::Duration::from_secs(60)) // TCP keepalive
.connection_verbose(true) // 详细连接信息
.build() { .build() {
Ok(client) => client, Ok(client) => client,
Err(e) => return Err(format!("创建HTTP客户端失败: {}", e)), Err(e) => return Err(format!("创建HTTP客户端失败: {}", e)),