diff --git a/src/main.rs b/src/main.rs index 0d7a626f..d9a72737 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,246 +1,246 @@ -use actix_files::Files; -use actix_governor::{Governor, GovernorConfigBuilder}; -use actix_web::http::header::ContentType; -use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; -use async_channel::{Receiver, Sender}; -use biliroaming_rust_server::mods::config::load_biliconfig; -use biliroaming_rust_server::mods::get_bili_res::{ - errorurl_reg, get_playurl_background, get_search, get_season, get_subtitle_th, -}; -use biliroaming_rust_server::mods::pub_api::get_api_accesskey; -use biliroaming_rust_server::mods::push::send_report; -use biliroaming_rust_server::mods::rate_limit::BiliUserToken; -use biliroaming_rust_server::mods::tools::{redir_playurl_request, update_server}; -use biliroaming_rust_server::mods::types::{BiliConfig, SendData}; -use deadpool_redis::{Config, Pool, Runtime}; -use futures::join; -use std::fs; -use std::path::Path; -use std::sync::Arc; - -#[get("/")] -async fn hello() -> impl Responder { - match fs::read_to_string("./web/index.html") { - Ok(value) => { - return HttpResponse::Ok() - .content_type(ContentType::html()) - .body(value); - } - Err(_) => { - return HttpResponse::Ok() - .content_type(ContentType::html()) - .body(r#"200 OK

BiliRoaming-Rust-Server

[online] 200 OK


Powered by BiliRoaming-Rust-Server
"#) - } - } -} - -async fn web_default(req: HttpRequest) -> impl Responder { - let path = format!("{}", req.path()); - let res_type = if let Some(value) = errorurl_reg(&path).await { - value - } else { - return HttpResponse::Ok() - .content_type(ContentType::json()) - .insert_header(("From", "biliroaming-rust-server")) - .insert_header(("Access-Control-Allow-Origin", "https://www.bilibili.com")) - .insert_header(("Access-Control-Allow-Credentials", "true")) - .insert_header(("Access-Control-Allow-Methods", "GET")) - .body("{\"code\":-404,\"message\":\"请检查填入的服务器地址是否有效\"}"); - }; - match res_type { - 1 => redir_playurl_request(&req, true, false).await, - 2 => redir_playurl_request(&req, false, false).await, - 3 => redir_playurl_request(&req, true, true).await, - 4 => get_search(&req, true, false).await, - 5 => get_search(&req, false, false).await, - 6 => get_search(&req, true, true).await, - 7 => get_season(&req, true, true).await, - 8 => get_subtitle_th(&req, false, true).await, - _ => { - println!("[Error] 未预期的行为 match res_type"); - HttpResponse::Ok() - .content_type(ContentType::json()) - .insert_header(("From", "biliroaming-rust-server")) - .insert_header(("Access-Control-Allow-Origin", "https://www.bilibili.com")) - .insert_header(("Access-Control-Allow-Credentials", "true")) - .insert_header(("Access-Control-Allow-Methods", "GET")) - .body("{\"code\":-500,\"message\":\"未预期的行为\"}") - } - } -} - -#[get("/donate")] -async fn donate(req: HttpRequest) -> impl Responder { - let (_, config, _) = req - .app_data::<(Pool, BiliConfig, Arc>)>() - .unwrap(); - return HttpResponse::Found() - .insert_header(("Location", &config.donate_url[..])) - .body(""); -} - -#[get("/pgc/player/api/playurl")] -async fn zhplayurl_app(req: HttpRequest) -> impl Responder { - redir_playurl_request(&req, true, false).await -} - -#[get("/pgc/player/web/playurl")] -async fn zhplayurl_web(req: HttpRequest) -> impl Responder { - redir_playurl_request(&req, false, false).await -} - -#[get("/intl/gateway/v2/ogv/playurl")] -async fn thplayurl_app(req: HttpRequest) -> impl Responder { - redir_playurl_request(&req, true, true).await -} - -#[get("/x/v2/search/type")] -async fn zhsearch_app(req: HttpRequest) -> impl Responder { - get_search(&req, true, false).await -} - -#[get("/x/web-interface/search/type")] -async fn zhsearch_web(req: HttpRequest) -> impl Responder { - get_search(&req, false, false).await -} - -#[get("/intl/gateway/v2/app/search/type")] -async fn thsearch_app(req: HttpRequest) -> impl Responder { - get_search(&req, true, true).await //emmmm 油猴脚本也用的这个 -} - -#[get("/intl/gateway/v2/ogv/view/app/season")] -async fn thseason_app(req: HttpRequest) -> impl Responder { - get_season(&req, true, true).await -} - -#[get("/intl/gateway/v2/app/subtitle")] -async fn thsubtitle_web(req: HttpRequest) -> impl Responder { - get_subtitle_th(&req, false, true).await -} - -#[get("/api/accesskey")] -async fn api_accesskey(req: HttpRequest) -> impl Responder { - get_api_accesskey(&req).await -} - -fn main() -> std::io::Result<()> { - println!("你好喵~"); - let mut config_type: Option<&str> = None; - let config_suffix = ["json", "yml"]; - for suffix in config_suffix { - if Path::new(&format!("config.{suffix}")).exists() { - config_type = Some(suffix); - } - } - let config = match load_biliconfig(config_type) { - Ok(value) => value, - Err(value) => { - println!("{value}"); - std::process::exit(78); - } - }; - ctrlc::set_handler(move || { - //目前来看这个已经没用了,但以防万一卡死,还是留着好了 - println!("\n已关闭 biliroaming_rust_server"); - std::process::exit(0); - }) - .unwrap(); - - //fs::write("config.example.yml", serde_yaml::to_string(&config).unwrap()).unwrap(); //Debug 方便生成示例配置 - - let mut anti_speedtest_cfg = config.clone(); - let woker_num = config.woker_num; - let port = config.port.clone(); - - if config.auto_update { - update_server(config.auto_close.clone()); - } - - let (s, r): (Sender, Receiver) = async_channel::bounded(120); - let bilisender = Arc::new(s); - // let bilisender_live = bilisender.clone(); - let anti_speedtest_redis_cfg = Config::from_url(&config.redis); - let pool_background = anti_speedtest_redis_cfg - .create_pool(Some(Runtime::Tokio1)) - .unwrap(); - let web_background = async move { - //a thread try to update cache - // println!("[Debug] spawn web_background"); - // if bilisender_live.is_closed() { - // println!("[Error] channel was closed"); - // } - let mut report_config = anti_speedtest_cfg.report_config.clone(); - if anti_speedtest_cfg.report_open { - match report_config.init() { - Ok(_) => (), - Err(value) => { - println!("{}", value); - anti_speedtest_cfg.report_open = false; - }, - } - } - loop { - let receive_data = match r.recv().await { - Ok(it) => it, - _ => { - println!("[Debug] failed to receive data"); - break; - } - }; - // println!("[Debug] r:{}",r.len()); - match receive_data { - SendData::Playurl(value) => { - match get_playurl_background(&pool_background, &value, &anti_speedtest_cfg) - .await - { - Ok(_) => (), - Err(value) => println!("{value}"), - }; - } - SendData::Health(value) => { - if let Err(_) = send_report(&pool_background, &report_config, &value).await - { - println!("[Error] failed to send health report"); - } - } - } - } - //println!("[Debug] exit web_background"); - }; - - let rate_limit_conf = GovernorConfigBuilder::default() - .per_second(3) - .burst_size(20) - .key_extractor(BiliUserToken) - .finish() - .unwrap(); - - let web_main = HttpServer::new(move || { - let rediscfg = Config::from_url(&config.redis); - let pool = rediscfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - App::new() - .app_data((pool, config.clone(), bilisender.clone())) - .wrap(Governor::new(&rate_limit_conf)) - .service(hello) - .service(zhplayurl_app) - .service(zhplayurl_web) - .service(thplayurl_app) - .service(zhsearch_app) - .service(zhsearch_web) - .service(thsearch_app) - .service(thseason_app) - .service(thsubtitle_web) - .service(api_accesskey) - .service(donate) - .service(Files::new("/", "./web/").index_file("index.html")) - .default_service(web::route().to(web_default)) - }) - .bind(("0.0.0.0", port)) - .unwrap() - .workers(woker_num) - .keep_alive(None) - .run(); - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { join!(web_background, web_main).1 }) -} +use actix_files::Files; +use actix_governor::{Governor, GovernorConfigBuilder}; +use actix_web::http::header::ContentType; +use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use async_channel::{Receiver, Sender}; +use biliroaming_rust_server::mods::config::load_biliconfig; +use biliroaming_rust_server::mods::get_bili_res::{ + errorurl_reg, get_playurl_background, get_search, get_season, get_subtitle_th, +}; +use biliroaming_rust_server::mods::pub_api::get_api_accesskey; +use biliroaming_rust_server::mods::push::send_report; +use biliroaming_rust_server::mods::rate_limit::BiliUserToken; +use biliroaming_rust_server::mods::tools::{redir_playurl_request, update_server}; +use biliroaming_rust_server::mods::types::{BiliConfig, SendData}; +use deadpool_redis::{Config, Pool, Runtime}; +use futures::join; +use std::fs; +use std::path::Path; +use std::sync::Arc; + +#[get("/")] +async fn hello() -> impl Responder { + match fs::read_to_string("./web/index.html") { + Ok(value) => { + return HttpResponse::Ok() + .content_type(ContentType::html()) + .body(value); + } + Err(_) => { + return HttpResponse::Ok() + .content_type(ContentType::html()) + .body(r#"200 OK

BiliRoaming-Rust-Server

[online] 200 OK


Powered by BiliRoaming-Rust-Server
"#) + } + } +} + +async fn web_default(req: HttpRequest) -> impl Responder { + let path = format!("{}", req.path()); + let res_type = if let Some(value) = errorurl_reg(&path).await { + value + } else { + return HttpResponse::Ok() + .content_type(ContentType::json()) + .insert_header(("From", "biliroaming-rust-server")) + .insert_header(("Access-Control-Allow-Origin", "https://www.bilibili.com")) + .insert_header(("Access-Control-Allow-Credentials", "true")) + .insert_header(("Access-Control-Allow-Methods", "GET")) + .body("{\"code\":-404,\"message\":\"请检查填入的服务器地址是否有效\"}"); + }; + match res_type { + 1 => redir_playurl_request(&req, true, false).await, + 2 => redir_playurl_request(&req, false, false).await, + 3 => redir_playurl_request(&req, true, true).await, + 4 => get_search(&req, true, false).await, + 5 => get_search(&req, false, false).await, + 6 => get_search(&req, true, true).await, + 7 => get_season(&req, true, true).await, + 8 => get_subtitle_th(&req, false, true).await, + _ => { + println!("[Error] 未预期的行为 match res_type"); + HttpResponse::Ok() + .content_type(ContentType::json()) + .insert_header(("From", "biliroaming-rust-server")) + .insert_header(("Access-Control-Allow-Origin", "https://www.bilibili.com")) + .insert_header(("Access-Control-Allow-Credentials", "true")) + .insert_header(("Access-Control-Allow-Methods", "GET")) + .body("{\"code\":-500,\"message\":\"未预期的行为\"}") + } + } +} + +#[get("/donate")] +async fn donate(req: HttpRequest) -> impl Responder { + let (_, config, _) = req + .app_data::<(Pool, BiliConfig, Arc>)>() + .unwrap(); + return HttpResponse::Found() + .insert_header(("Location", &config.donate_url[..])) + .body(""); +} + +#[get("/pgc/player/api/playurl")] +async fn zhplayurl_app(req: HttpRequest) -> impl Responder { + redir_playurl_request(&req, true, false).await +} + +#[get("/pgc/player/web/playurl")] +async fn zhplayurl_web(req: HttpRequest) -> impl Responder { + redir_playurl_request(&req, false, false).await +} + +#[get("/intl/gateway/v2/ogv/playurl")] +async fn thplayurl_app(req: HttpRequest) -> impl Responder { + redir_playurl_request(&req, true, true).await +} + +#[get("/x/v2/search/type")] +async fn zhsearch_app(req: HttpRequest) -> impl Responder { + get_search(&req, true, false).await +} + +#[get("/x/web-interface/search/type")] +async fn zhsearch_web(req: HttpRequest) -> impl Responder { + get_search(&req, false, false).await +} + +#[get("/intl/gateway/v2/app/search/type")] +async fn thsearch_app(req: HttpRequest) -> impl Responder { + get_search(&req, true, true).await //emmmm 油猴脚本也用的这个 +} + +#[get("/intl/gateway/v2/ogv/view/app/season")] +async fn thseason_app(req: HttpRequest) -> impl Responder { + get_season(&req, true, true).await +} + +#[get("/intl/gateway/v2/app/subtitle")] +async fn thsubtitle_web(req: HttpRequest) -> impl Responder { + get_subtitle_th(&req, false, true).await +} + +#[get("/api/accesskey")] +async fn api_accesskey(req: HttpRequest) -> impl Responder { + get_api_accesskey(&req).await +} + +fn main() -> std::io::Result<()> { + println!("你好喵~"); + let mut config_type: Option<&str> = None; + let config_suffix = ["json", "yml"]; + for suffix in config_suffix { + if Path::new(&format!("config.{suffix}")).exists() { + config_type = Some(suffix); + } + } + let config = match load_biliconfig(config_type) { + Ok(value) => value, + Err(value) => { + println!("{value}"); + std::process::exit(78); + } + }; + ctrlc::set_handler(move || { + //目前来看这个已经没用了,但以防万一卡死,还是留着好了 + println!("\n已关闭 biliroaming_rust_server"); + std::process::exit(0); + }) + .unwrap(); + + //fs::write("config.example.yml", serde_yaml::to_string(&config).unwrap()).unwrap(); //Debug 方便生成示例配置 + + let mut anti_speedtest_cfg = config.clone(); + let woker_num = config.woker_num; + let port = config.port.clone(); + + if config.auto_update { + update_server(config.auto_close.clone()); + } + + let (s, r): (Sender, Receiver) = async_channel::bounded(120); + let bilisender = Arc::new(s); + // let bilisender_live = bilisender.clone(); + let anti_speedtest_redis_cfg = Config::from_url(&config.redis); + let pool_background = anti_speedtest_redis_cfg + .create_pool(Some(Runtime::Tokio1)) + .unwrap(); + let web_background = async move { + //a thread try to update cache + // println!("[Debug] spawn web_background"); + // if bilisender_live.is_closed() { + // println!("[Error] channel was closed"); + // } + let mut report_config = anti_speedtest_cfg.report_config.clone(); + if anti_speedtest_cfg.report_open { + match report_config.init() { + Ok(_) => (), + Err(value) => { + println!("{}", value); + anti_speedtest_cfg.report_open = false; + }, + } + } + loop { + let receive_data = match r.recv().await { + Ok(it) => it, + _ => { + //println!("[Debug] failed to receive data"); + break; + } + }; + //println!("[Debug] r:{}",r.len()); + match receive_data { + SendData::Playurl(value) => { + match get_playurl_background(&pool_background, &value, &anti_speedtest_cfg) + .await + { + Ok(_) => (), + Err(value) => println!("{value}"), + }; + } + SendData::Health(value) => { + if let Err(_) = send_report(&pool_background, &report_config, &value).await + { + println!("[Error] failed to send health report"); + } + } + } + } + //println!("[Debug] exit web_background"); + }; + + let rate_limit_conf = GovernorConfigBuilder::default() + .per_second(3) + .burst_size(20) + .key_extractor(BiliUserToken) + .finish() + .unwrap(); + + let web_main = HttpServer::new(move || { + let rediscfg = Config::from_url(&config.redis); + let pool = rediscfg.create_pool(Some(Runtime::Tokio1)).unwrap(); + App::new() + .app_data((pool, config.clone(), bilisender.clone())) + .wrap(Governor::new(&rate_limit_conf)) + .service(hello) + .service(zhplayurl_app) + .service(zhplayurl_web) + .service(thplayurl_app) + .service(zhsearch_app) + .service(zhsearch_web) + .service(thsearch_app) + .service(thseason_app) + .service(thsubtitle_web) + .service(api_accesskey) + .service(donate) + .service(Files::new("/", "./web/").index_file("index.html")) + .default_service(web::route().to(web_default)) + }) + .bind(("0.0.0.0", port)) + .unwrap() + .workers(woker_num) + .keep_alive(None) + .run(); + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async { join!(web_background, web_main).1 }) +} diff --git a/src/mods/get_bili_res.rs b/src/mods/get_bili_res.rs index a52580e0..56e7d553 100644 --- a/src/mods/get_bili_res.rs +++ b/src/mods/get_bili_res.rs @@ -17,35 +17,6 @@ use qstring::QString; use serde_json::{self, json}; use std::sync::Arc; -// 储存规范: -//查询数据+地区(1位)+类型(2位)+版本(2位) -//查询数据 a asscesskey -// e epid -// c cid -// v is_vip -// t is_tv -//地区 cn 1 -// hk 2 -// tw 3 -// th 4 -// default 2 -//类型 app playurl 01 -// app search 02 -// app subtitle 03 -// app season 04 -// user_info 05 -// user_cerinfo 06 -// web playurl 07 -// web search 08 -// web subtitle 09 -// web season 10 -// resign_info 11 -// api 12 -// health 13 eg. 0141301 = playurl th health ver.1 -// ep_area 14 -//版本 :用于处理版本更新后导致的格式变更 -// now 01 - pub async fn get_playurl( req: &HttpRequest, is_app: bool, @@ -1372,10 +1343,103 @@ pub async fn get_season(req: &HttpRequest, _is_app: bool, _is_th: bool) -> HttpR } }; let season_remake = move || async move { - if config.th_app_season_sub_open || config.aid_replace_open { + if config.th_app_season_sub_open { let mut body_data_json: serde_json::Value = serde_json::from_str(&body_data).unwrap(); - + let season_id: Option; + let is_result: bool; + match &body_data_json["result"] { + serde_json::Value::Object(value) => { + is_result = true; + season_id = Some(value["season_id"].as_u64().unwrap()); + } + serde_json::Value::Null => { + is_result = false; + match &body_data_json["data"] { + serde_json::Value::Null => { + season_id = None; + } + serde_json::Value::Object(value) => { + season_id = Some(value["season_id"].as_u64().unwrap()); + } + _ => { + season_id = None; + } + } + } + _ => { + is_result = false; + season_id = None; + } + } + + match season_id { + None => { + return body_data; + } + Some(_) => (), + } + + let sub_replace_str = match async_getwebpage( + &format!("{}{}", &config.th_app_season_sub_api, season_id.unwrap()), + &false, + "", + &user_agent, + "", + ) + .await + { + Ok(value) => value, + Err(_) => { + return body_data; + } + }; + let sub_replace_json: serde_json::Value = + if let Ok(value) = serde_json::from_str(&sub_replace_str) { + value + } else { + return body_data; + }; + match sub_replace_json["code"].as_i64().unwrap_or(233) { + 0 => { + if body_data_json["result"]["modules"] + .as_array_mut() + .unwrap() + .len() + == 0 + { + return body_data; + } + } + _ => { + return body_data; + } + } + let mut index_of_replace_json = 0; + let len_of_replace_json = sub_replace_json["data"].as_array().unwrap().len(); + while index_of_replace_json < len_of_replace_json { + let ep: usize = sub_replace_json["data"][index_of_replace_json]["ep"] + .as_u64() + .unwrap() as usize; + let key = sub_replace_json["data"][index_of_replace_json]["key"] + .as_str() + .unwrap(); + let lang = sub_replace_json["data"][index_of_replace_json]["lang"] + .as_str() + .unwrap(); + let url = sub_replace_json["data"][index_of_replace_json]["url"] + .as_str() + .unwrap(); + if is_result { + let element = format!("{{\"id\":{index_of_replace_json},\"key\":\"{key}\",\"title\":\"[非官方] {lang} {}\",\"url\":\"https://{url}\"}}",config.th_app_season_sub_name); + body_data_json["result"]["modules"][0]["data"]["episodes"][ep]["subtitles"] + .as_array_mut() + .unwrap() + .insert(0, serde_json::from_str(&element).unwrap()); + } + index_of_replace_json += 1; + } + if config.aid_replace_open { let len_of_episodes = body_data_json["result"]["modules"][0]["data"] ["episodes"] @@ -1391,102 +1455,6 @@ pub async fn get_season(req: &HttpRequest, _is_app: bool, _is_th: bool) -> HttpR index += 1; } } - - if config.th_app_season_sub_open { - let season_id: Option; - let is_result: bool; - match &body_data_json["result"] { - serde_json::Value::Object(value) => { - is_result = true; - season_id = Some(value["season_id"].as_u64().unwrap()); - } - serde_json::Value::Null => { - is_result = false; - match &body_data_json["data"] { - serde_json::Value::Null => { - season_id = None; - } - serde_json::Value::Object(value) => { - season_id = Some(value["season_id"].as_u64().unwrap()); - } - _ => { - season_id = None; - } - } - } - _ => { - is_result = false; - season_id = None; - } - } - - match season_id { - None => { - return body_data; - } - Some(_) => (), - } - - let sub_replace_str = match async_getwebpage( - &format!("{}{}", &config.th_app_season_sub_api, season_id.unwrap()), - &false, - "", - &user_agent, - "", - ) - .await - { - Ok(value) => value, - Err(_) => { - return body_data; - } - }; - let sub_replace_json: serde_json::Value = - if let Ok(value) = serde_json::from_str(&sub_replace_str) { - value - } else { - return body_data; - }; - match sub_replace_json["code"].as_i64().unwrap_or(233) { - 0 => { - if body_data_json["result"]["modules"] - .as_array_mut() - .unwrap() - .len() - == 0 - { - return body_data; - } - } - _ => { - return body_data; - } - } - let mut index_of_replace_json = 0; - let len_of_replace_json = sub_replace_json["data"].as_array().unwrap().len(); - while index_of_replace_json < len_of_replace_json { - let ep: usize = sub_replace_json["data"][index_of_replace_json]["ep"] - .as_u64() - .unwrap() as usize; - let key = sub_replace_json["data"][index_of_replace_json]["key"] - .as_str() - .unwrap(); - let lang = sub_replace_json["data"][index_of_replace_json]["lang"] - .as_str() - .unwrap(); - let url = sub_replace_json["data"][index_of_replace_json]["url"] - .as_str() - .unwrap(); - if is_result { - let element = format!("{{\"id\":{index_of_replace_json},\"key\":\"{key}\",\"title\":\"[非官方] {lang} {}\",\"url\":\"https://{url}\"}}",config.th_app_season_sub_name); - body_data_json["result"]["modules"][0]["data"]["episodes"][ep]["subtitles"] - .as_array_mut() - .unwrap() - .insert(0, serde_json::from_str(&element).unwrap()); - } - index_of_replace_json += 1; - } - } let body_data = body_data_json.to_string(); return body_data; diff --git a/src/mods/request.rs b/src/mods/request.rs index d1b8a1ca..85d84dc3 100644 --- a/src/mods/request.rs +++ b/src/mods/request.rs @@ -45,8 +45,8 @@ pub fn getwebpage( .unwrap(); match transfer.perform() { Ok(()) => (), - Err(_value) => { - // println!("[Debug] getwebpage error -> {}", value); // 不必要 + Err(value) => { + println!("getwebpage error -> {}", value); return Err(()); } }