diff --git a/crates/bili_sync/src/adapter/collection.rs b/crates/bili_sync/src/adapter/collection.rs index 5c3d6e7..93e294e 100644 --- a/crates/bili_sync/src/adapter/collection.rs +++ b/crates/bili_sync/src/adapter/collection.rs @@ -20,12 +20,11 @@ use crate::utils::status::Status; pub async fn collection_from<'a>( collection_item: &'a CollectionItem, - mixin_key: &'a str, path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, ) -> Result<(Box, Pin + 'a>>)> { - let collection = Collection::new(bili_client, collection_item, mixin_key); + let collection = Collection::new(bili_client, collection_item); let collection_info = collection.get_info().await?; collection::Entity::insert(collection::ActiveModel { s_id: Set(collection_info.sid), diff --git a/crates/bili_sync/src/adapter/mod.rs b/crates/bili_sync/src/adapter/mod.rs index 6faf5a4..92e796f 100644 --- a/crates/bili_sync/src/adapter/mod.rs +++ b/crates/bili_sync/src/adapter/mod.rs @@ -17,13 +17,8 @@ use watch_later::watch_later_from; use crate::bilibili::{BiliClient, CollectionItem, VideoInfo}; pub enum Args<'a> { - Favorite { - fid: &'a str, - }, - Collection { - collection_item: &'a CollectionItem, - mixin_key: &'a str, - }, + Favorite { fid: &'a str }, + Collection { collection_item: &'a CollectionItem }, WatchLater, } @@ -35,10 +30,7 @@ pub async fn video_list_from<'a>( ) -> Result<(Box, Pin + 'a>>)> { match args { Args::Favorite { fid } => favorite_from(fid, path, bili_client, connection).await, - Args::Collection { - collection_item, - mixin_key, - } => collection_from(collection_item, mixin_key, path, bili_client, connection).await, + Args::Collection { collection_item } => collection_from(collection_item, path, bili_client, connection).await, Args::WatchLater => watch_later_from(path, bili_client, connection).await, } } diff --git a/crates/bili_sync/src/bilibili/client.rs b/crates/bili_sync/src/bilibili/client.rs index 37ab29c..e2d83a1 100644 --- a/crates/bili_sync/src/bilibili/client.rs +++ b/crates/bili_sync/src/bilibili/client.rs @@ -87,15 +87,6 @@ impl BiliClient { CONFIG.save() } - /// 检查凭据是否已设置且有效 - pub async fn is_login(&self) -> Result<()> { - let credential = CONFIG.credential.load(); - let Some(credential) = credential.as_deref() else { - bail!("no credential found"); - }; - credential.is_login(&self.client).await - } - /// 获取 wbi img,用于生成请求签名 pub async fn wbi_img(&self) -> Result { let credential = CONFIG.credential.load(); diff --git a/crates/bili_sync/src/bilibili/collection.rs b/crates/bili_sync/src/bilibili/collection.rs index 9f5dadf..dd788bf 100644 --- a/crates/bili_sync/src/bilibili/collection.rs +++ b/crates/bili_sync/src/bilibili/collection.rs @@ -1,9 +1,9 @@ #![allow(dead_code)] -use std::borrow::Cow; use std::fmt::{Display, Formatter}; -use anyhow::{bail, Result}; +use anyhow::Result; +use arc_swap::access::Access; use async_stream::stream; use futures::Stream; use reqwest::Method; @@ -11,7 +11,7 @@ use serde::Deserialize; use serde_json::Value; use crate::bilibili::credential::encoded_query; -use crate::bilibili::{BiliClient, Validate, VideoInfo}; +use crate::bilibili::{BiliClient, Validate, VideoInfo, MIXIN_KEY}; #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub enum CollectionType { @@ -58,7 +58,6 @@ pub struct CollectionItem { pub struct Collection<'a> { client: &'a BiliClient, collection: &'a CollectionItem, - mixin_key: Cow<'a, str>, } #[derive(Debug, PartialEq)] @@ -97,24 +96,8 @@ impl<'de> Deserialize<'de> for CollectionInfo { } impl<'a> Collection<'a> { - pub async fn build(client: &'a BiliClient, collection: &'a CollectionItem) -> Result { - let wbi_img = client.wbi_img().await?; - let Some(mixin_key) = wbi_img.into_mixin_key() else { - bail!("failed to get mixin key"); - }; - Ok(Self { - client, - collection, - mixin_key: Cow::Owned(mixin_key), - }) - } - - pub fn new(client: &'a BiliClient, collection: &'a CollectionItem, mixin_key: &'a str) -> Self { - Self { - client, - collection, - mixin_key: Cow::Borrowed(mixin_key), - } + pub fn new(client: &'a BiliClient, collection: &'a CollectionItem) -> Self { + Self { client, collection } } pub async fn get_info(&self) -> Result { @@ -140,7 +123,6 @@ impl<'a> Collection<'a> { async fn get_videos(&self, page: i32) -> Result { let page = page.to_string(); - let mixin_key = self.mixin_key.as_ref(); let (url, query) = match self.collection.collection_type { CollectionType::Series => ( "https://api.bilibili.com/x/series/archives", @@ -153,7 +135,7 @@ impl<'a> Collection<'a> { ("pn", page.as_str()), ("ps", "30"), ], - mixin_key, + MIXIN_KEY.load().as_ref().unwrap(), ), ), CollectionType::Season => ( @@ -166,7 +148,7 @@ impl<'a> Collection<'a> { ("page_num", page.as_str()), ("page_size", "30"), ], - mixin_key, + MIXIN_KEY.load().as_ref().unwrap(), ), ), }; diff --git a/crates/bili_sync/src/bilibili/credential.rs b/crates/bili_sync/src/bilibili/credential.rs index 326b1e7..c0f830a 100644 --- a/crates/bili_sync/src/bilibili/credential.rs +++ b/crates/bili_sync/src/bilibili/credential.rs @@ -67,24 +67,6 @@ impl Credential { res["data"]["refresh"].as_bool().ok_or(anyhow!("check refresh failed")) } - /// 需要使用一个需要鉴权的接口来检查是否登录 - /// 此处使用查看用户状态数的接口,该接口返回内容少,请求成本低 - pub async fn is_login(&self, client: &Client) -> Result<()> { - client - .request( - Method::GET, - "https://api.bilibili.com/x/web-interface/nav/stat", - Some(self), - ) - .send() - .await? - .error_for_status()? - .json::() - .await? - .validate()?; - Ok(()) - } - pub async fn refresh(&self, client: &Client) -> Result { let correspond_path = Self::get_correspond_path(); let csrf = self.get_refresh_csrf(client, correspond_path).await?; diff --git a/crates/bili_sync/src/bilibili/mod.rs b/crates/bili_sync/src/bilibili/mod.rs index 63bafb0..65e5a53 100644 --- a/crates/bili_sync/src/bilibili/mod.rs +++ b/crates/bili_sync/src/bilibili/mod.rs @@ -1,5 +1,8 @@ +use std::sync::Arc; + pub use analyzer::{BestStream, FilterOption}; use anyhow::{bail, Result}; +use arc_swap::ArcSwapOption; use chrono::serde::ts_seconds; use chrono::{DateTime, Utc}; pub use client::{BiliClient, Client}; @@ -9,6 +12,7 @@ pub use danmaku::DanmakuOption; pub use error::BiliError; pub use favorite_list::FavoriteList; use favorite_list::Upper; +use once_cell::sync::Lazy; pub use video::{Dimension, PageInfo, Video}; pub use watch_later::WatchLater; @@ -22,6 +26,12 @@ mod favorite_list; mod video; mod watch_later; +static MIXIN_KEY: Lazy> = Lazy::new(Default::default); + +pub(crate) fn set_global_mixin_key(key: String) { + MIXIN_KEY.store(Some(Arc::new(key))); +} + pub(crate) trait Validate { type Output; @@ -130,7 +140,7 @@ mod tests { sid: "387214".to_string(), collection_type: CollectionType::Series, }; - let collection = Collection::build(&bili_client, &collection_item).await.unwrap(); + let collection = Collection::new(&bili_client, &collection_item); let stream = collection.into_simple_video_stream(); pin_mut!(stream); assert!(matches!(stream.next().await, Some(VideoInfo::Simple { .. }))); diff --git a/crates/bili_sync/src/bilibili/video.rs b/crates/bili_sync/src/bilibili/video.rs index 3ac460b..d1e29a7 100644 --- a/crates/bili_sync/src/bilibili/video.rs +++ b/crates/bili_sync/src/bilibili/video.rs @@ -4,6 +4,8 @@ use futures::TryStreamExt; use prost::Message; use reqwest::Method; +use super::credential::encoded_query; +use super::MIXIN_KEY; use crate::bilibili::analyzer::PageAnalyzer; use crate::bilibili::client::BiliClient; use crate::bilibili::danmaku::{DanmakuElem, DanmakuWriter, DmSegMobileReply}; @@ -140,14 +142,17 @@ impl<'a> Video<'a> { let mut res = self .client .request(Method::GET, "https://api.bilibili.com/x/player/wbi/playurl") - .query(&[ - ("avid", self.aid.as_str()), - ("cid", page.cid.to_string().as_str()), - ("qn", "127"), - ("otype", "json"), - ("fnval", "4048"), - ("fourk", "1"), - ]) + .query(&encoded_query( + vec![ + ("avid", self.aid.as_str()), + ("cid", page.cid.to_string().as_str()), + ("qn", "127"), + ("otype", "json"), + ("fnval", "4048"), + ("fourk", "1"), + ], + MIXIN_KEY.load().as_ref().unwrap(), + )) .send() .await? .error_for_status()? diff --git a/crates/bili_sync/src/main.rs b/crates/bili_sync/src/main.rs index 0c3205a..3d1f618 100644 --- a/crates/bili_sync/src/main.rs +++ b/crates/bili_sync/src/main.rs @@ -31,57 +31,49 @@ async fn main() { let bili_client = BiliClient::new(); let watch_later_config = &CONFIG.watch_later; loop { - if let Err(e) = bili_client.is_login().await { - error!("检查登录状态时遇到错误:{e},等待下一轮执行"); - time::sleep(Duration::from_secs(CONFIG.interval)).await; - continue; - } - if anchor != chrono::Local::now().date_naive() { - if let Err(e) = bili_client.check_refresh().await { - error!("检查刷新 Credential 遇到错误:{e},等待下一轮执行"); - time::sleep(Duration::from_secs(CONFIG.interval)).await; - continue; + 'inner: { + match bili_client.wbi_img().await.map(|wbi_img| wbi_img.into_mixin_key()) { + Ok(Some(mixin_key)) => bilibili::set_global_mixin_key(mixin_key), + Ok(_) => { + error!("获取 mixin key 失败,无法进行 wbi 签名,等待下一轮执行"); + break 'inner; + } + Err(e) => { + error!("获取 mixin key 时遇到错误:{e},等待下一轮执行"); + break 'inner; + } + }; + if anchor != chrono::Local::now().date_naive() { + if let Err(e) = bili_client.check_refresh().await { + error!("检查刷新 Credential 遇到错误:{e},等待下一轮执行"); + break 'inner; + } + anchor = chrono::Local::now().date_naive(); } - anchor = chrono::Local::now().date_naive(); - } - for (fid, path) in &CONFIG.favorite_list { - if let Err(e) = process_video_list(Args::Favorite { fid }, &bili_client, path, &connection).await { - error!("处理收藏夹 {fid} 时遇到非预期的错误:{e}"); - } - } - info!("所有收藏夹处理完毕"); - match bili_client.wbi_img().await.map(|wbi_img| wbi_img.into_mixin_key()) { - Ok(Some(mixin_key)) => { - for (collection_item, path) in &CONFIG.collection_list { - if let Err(e) = process_video_list( - Args::Collection { - collection_item, - mixin_key: &mixin_key, - }, - &bili_client, - path, - &connection, - ) - .await - { - error!("处理合集 {collection_item:?} 时遇到非预期的错误:{e}"); - } + for (fid, path) in &CONFIG.favorite_list { + if let Err(e) = process_video_list(Args::Favorite { fid }, &bili_client, path, &connection).await { + error!("处理收藏夹 {fid} 时遇到非预期的错误:{e}"); } } - _ => { - error!("获取 mixin key 失败,无法进行 wbi 签名,跳过本轮合集处理"); + info!("所有收藏夹处理完毕"); + for (collection_item, path) in &CONFIG.collection_list { + if let Err(e) = + process_video_list(Args::Collection { collection_item }, &bili_client, path, &connection).await + { + error!("处理合集 {collection_item:?} 时遇到非预期的错误:{e}"); + } } - } - info!("所有合集处理完毕"); - if watch_later_config.enabled { - if let Err(e) = - process_video_list(Args::WatchLater, &bili_client, &watch_later_config.path, &connection).await - { - error!("处理稍后再看时遇到非预期的错误:{e}"); + info!("所有合集处理完毕"); + if watch_later_config.enabled { + if let Err(e) = + process_video_list(Args::WatchLater, &bili_client, &watch_later_config.path, &connection).await + { + error!("处理稍后再看时遇到非预期的错误:{e}"); + } } + info!("稍后再看处理完毕"); + info!("本轮任务执行完毕,等待下一轮执行"); } - info!("稍后再看处理完毕"); - info!("本轮任务执行完毕,等待下一轮执行"); - tokio::time::sleep(std::time::Duration::from_secs(CONFIG.interval)).await; + time::sleep(Duration::from_secs(CONFIG.interval)).await; } }