refactor: 继续调整优化部分代码,移除主体代码的所有 unwrap

This commit is contained in:
amtoaer
2025-01-21 17:17:14 +08:00
parent cdc30e1b32
commit 0f25923c52
14 changed files with 101 additions and 67 deletions

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::pin::Pin; use std::pin::Pin;
use anyhow::Result; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bili_sync_entity::*; use bili_sync_entity::*;
use futures::Stream; use futures::Stream;
@@ -90,7 +90,7 @@ impl VideoListModel for collection::Model {
// 将页标记和 tag 写入数据库 // 将页标记和 tag 写入数据库
let mut video_active_model = self.video_model_by_info(&view_info, Some(video_model)); let mut video_active_model = self.video_model_by_info(&view_info, Some(video_model));
video_active_model.single_page = Set(Some(pages.len() == 1)); video_active_model.single_page = Set(Some(pages.len() == 1));
video_active_model.tags = Set(Some(serde_json::to_value(tags).unwrap())); video_active_model.tags = Set(Some(serde_json::to_value(tags)?));
video_active_model.save(&txn).await?; video_active_model.save(&txn).await?;
txn.commit().await?; txn.commit().await?;
} }
@@ -196,7 +196,7 @@ pub(super) async fn collection_from<'a>(
) )
.one(connection) .one(connection)
.await? .await?
.unwrap(), .ok_or(anyhow!("collection not found"))?,
), ),
Box::pin(collection.into_simple_video_stream()), Box::pin(collection.into_simple_video_stream()),
)) ))

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::pin::Pin; use std::pin::Pin;
use anyhow::Result; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bili_sync_entity::*; use bili_sync_entity::*;
use futures::Stream; use futures::Stream;
@@ -87,7 +87,7 @@ impl VideoListModel for favorite::Model {
// 将页标记和 tag 写入数据库 // 将页标记和 tag 写入数据库
let mut video_active_model: video::ActiveModel = video_model.into(); let mut video_active_model: video::ActiveModel = video_model.into();
video_active_model.single_page = Set(Some(pages_info.len() == 1)); video_active_model.single_page = Set(Some(pages_info.len() == 1));
video_active_model.tags = Set(Some(serde_json::to_value(tags).unwrap())); video_active_model.tags = Set(Some(serde_json::to_value(tags)?));
video_active_model.save(&txn).await?; video_active_model.save(&txn).await?;
txn.commit().await?; txn.commit().await?;
} }
@@ -153,7 +153,7 @@ pub(super) async fn favorite_from<'a>(
.filter(favorite::Column::FId.eq(favorite_info.id)) .filter(favorite::Column::FId.eq(favorite_info.id))
.one(connection) .one(connection)
.await? .await?
.unwrap(), .ok_or(anyhow!("favorite not found"))?,
), ),
Box::pin(favorite.into_video_stream()), Box::pin(favorite.into_video_stream()),
)) ))

View File

@@ -65,7 +65,11 @@ pub(super) fn video_with_path(
) -> video::ActiveModel { ) -> video::ActiveModel {
if let Some(fmt_args) = &video_info.to_fmt_args() { if let Some(fmt_args) = &video_info.to_fmt_args() {
video_model.path = Set(Path::new(base_path) video_model.path = Set(Path::new(base_path)
.join(TEMPLATE.path_safe_render("video", fmt_args).unwrap()) .join(
TEMPLATE
.path_safe_render("video", fmt_args)
.expect("template render failed"),
)
.to_string_lossy() .to_string_lossy()
.to_string()); .to_string());
} }

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::pin::Pin; use std::pin::Pin;
use anyhow::Result; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bili_sync_entity::*; use bili_sync_entity::*;
use futures::Stream; use futures::Stream;
@@ -91,7 +91,7 @@ impl VideoListModel for submission::Model {
// 将页标记和 tag 写入数据库 // 将页标记和 tag 写入数据库
let mut video_active_model = self.video_model_by_info(&view_info, Some(video_model)); let mut video_active_model = self.video_model_by_info(&view_info, Some(video_model));
video_active_model.single_page = Set(Some(pages.len() == 1)); video_active_model.single_page = Set(Some(pages.len() == 1));
video_active_model.tags = Set(Some(serde_json::to_value(tags).unwrap())); video_active_model.tags = Set(Some(serde_json::to_value(tags)?));
video_active_model.save(&txn).await?; video_active_model.save(&txn).await?;
txn.commit().await?; txn.commit().await?;
} }
@@ -169,7 +169,7 @@ pub(super) async fn submission_from<'a>(
.filter(submission::Column::UpperId.eq(upper.mid)) .filter(submission::Column::UpperId.eq(upper.mid))
.one(connection) .one(connection)
.await? .await?
.unwrap(), .ok_or(anyhow!("submission not found"))?,
), ),
Box::pin(submission.into_video_stream()), Box::pin(submission.into_video_stream()),
)) ))

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::path::Path; use std::path::Path;
use std::pin::Pin; use std::pin::Pin;
use anyhow::Result; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bili_sync_entity::*; use bili_sync_entity::*;
use futures::Stream; use futures::Stream;
@@ -88,7 +88,7 @@ impl VideoListModel for watch_later::Model {
// 将页标记和 tag 写入数据库 // 将页标记和 tag 写入数据库
let mut video_active_model: video::ActiveModel = video_model.into(); let mut video_active_model: video::ActiveModel = video_model.into();
video_active_model.single_page = Set(Some(pages_info.len() == 1)); video_active_model.single_page = Set(Some(pages_info.len() == 1));
video_active_model.tags = Set(Some(serde_json::to_value(tags).unwrap())); video_active_model.tags = Set(Some(serde_json::to_value(tags)?));
video_active_model.save(&txn).await?; video_active_model.save(&txn).await?;
txn.commit().await?; txn.commit().await?;
} }
@@ -151,7 +151,7 @@ pub(super) async fn watch_later_from<'a>(
.filter(watch_later::Column::Id.eq(1)) .filter(watch_later::Column::Id.eq(1))
.one(connection) .one(connection)
.await? .await?
.unwrap(), .ok_or(anyhow!("watch_later not found"))?,
), ),
Box::pin(watch_later.into_video_stream()), Box::pin(watch_later.into_video_stream()),
)) ))

View File

@@ -7,7 +7,7 @@ pub struct PageAnalyzer {
info: serde_json::Value, info: serde_json::Value,
} }
#[derive(Debug, strum::FromRepr, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, strum::FromRepr, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum VideoQuality { pub enum VideoQuality {
Quality360p = 16, Quality360p = 16,
Quality480p = 32, Quality480p = 32,
@@ -21,7 +21,7 @@ pub enum VideoQuality {
Quality8k = 127, Quality8k = 127,
} }
#[derive(Debug, Clone, Copy, strum::FromRepr, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, strum::FromRepr, PartialEq, Eq, Serialize, Deserialize)]
pub enum AudioQuality { pub enum AudioQuality {
Quality64k = 30216, Quality64k = 30216,
Quality132k = 30232, Quality132k = 30232,
@@ -30,6 +30,18 @@ pub enum AudioQuality {
Quality192k = 30280, Quality192k = 30280,
} }
impl Ord for AudioQuality {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_sort_key().cmp(&other.as_sort_key())
}
}
impl PartialOrd for AudioQuality {
fn partial_cmp(&self, other: &AudioQuality) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl AudioQuality { impl AudioQuality {
#[inline] #[inline]
pub fn as_sort_key(&self) -> isize { pub fn as_sort_key(&self) -> isize {
@@ -41,12 +53,6 @@ impl AudioQuality {
} }
} }
impl PartialOrd<AudioQuality> for AudioQuality {
fn partial_cmp(&self, other: &AudioQuality) -> Option<std::cmp::Ordering> {
self.as_sort_key().partial_cmp(&other.as_sort_key())
}
}
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive(Debug, strum::EnumString, strum::Display, strum::AsRefStr, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, strum::EnumString, strum::Display, strum::AsRefStr, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum VideoCodecs { pub enum VideoCodecs {
@@ -281,7 +287,7 @@ impl PageAnalyzer {
}, },
) => { ) => {
if a_quality != b_quality { if a_quality != b_quality {
return a_quality.partial_cmp(b_quality).unwrap(); return a_quality.cmp(b_quality);
}; };
filter_option filter_option
.codecs .codecs
@@ -294,7 +300,7 @@ impl PageAnalyzer {
.ok_or(anyhow!("no video stream found"))?, .ok_or(anyhow!("no video stream found"))?,
audio: Iterator::max_by(audios.into_iter(), |a, b| match (a, b) { audio: Iterator::max_by(audios.into_iter(), |a, b| match (a, b) {
(Stream::DashAudio { quality: a_quality, .. }, Stream::DashAudio { quality: b_quality, .. }) => { (Stream::DashAudio { quality: a_quality, .. }, Stream::DashAudio { quality: b_quality, .. }) => {
a_quality.partial_cmp(b_quality).unwrap() a_quality.cmp(b_quality)
} }
_ => unreachable!(), _ => unreachable!(),
}), }),

View File

@@ -34,7 +34,7 @@ impl Client {
.connect_timeout(std::time::Duration::from_secs(10)) .connect_timeout(std::time::Duration::from_secs(10))
.read_timeout(std::time::Duration::from_secs(10)) .read_timeout(std::time::Duration::from_secs(10))
.build() .build()
.unwrap(), .expect("failed to build reqwest client"),
) )
} }

View File

@@ -169,37 +169,49 @@ impl<'a> Collection<'a> {
let mut videos = match self.get_videos(page).await { let mut videos = match self.get_videos(page).await {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to get videos of collection {:?} page {}: {}", self.collection, page, e); error!(
"failed to get videos of collection {:?} page {}: {}",
self.collection, page, e
);
break; break;
}, }
}; };
if !videos["data"]["archives"].is_array() { let archives = &mut videos["data"]["archives"];
warn!("no videos found in collection {:?} page {}", self.collection, page); if archives.as_array().is_none_or(|v| v.is_empty()) {
error!("no videos found in collection {:?} page {}", self.collection, page);
break; break;
} }
let videos_info = match serde_json::from_value::<Vec<VideoInfo>>(videos["data"]["archives"].take()) { let videos_info: Vec<VideoInfo> = match serde_json::from_value(archives.take()) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to parse videos of collection {:?} page {}: {}", self.collection, page, e); error!(
"failed to parse videos of collection {:?} page {}: {}",
self.collection, page, e
);
break; break;
}, }
}; };
for video_info in videos_info{ for video_info in videos_info {
yield video_info; yield video_info;
} }
let fields = match self.collection.collection_type{ let page_info = &videos["data"]["page"];
let fields = match self.collection.collection_type {
CollectionType::Series => ["num", "size", "total"], CollectionType::Series => ["num", "size", "total"],
CollectionType::Season => ["page_num", "page_size", "total"], CollectionType::Season => ["page_num", "page_size", "total"],
}; };
let fields = fields.into_iter().map(|f| videos["data"]["page"][f].as_i64()).collect::<Option<Vec<i64>>>().map(|v| (v[0], v[1], v[2])); let values = fields.iter().map(|f| page_info[f].as_i64()).collect::<Vec<Option<i64>>>();
let Some((num, size, total)) = fields else { if let [Some(num), Some(size), Some(total)] = values[..] {
error!("failed to get pages of collection {:?} page {}: {:?}", self.collection, page, fields); if num * size < total {
break; page += 1;
}; continue;
if num * size >= total { }
break; } else {
error!(
"invalid page info of collection {:?} page {}: read {:?} from {}",
self.collection, page, fields, page_info
);
} }
page += 1; break;
} }
} }
} }

View File

@@ -95,11 +95,13 @@ nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40
JNrRuoEUXpabUzGB8QIDAQAB JNrRuoEUXpabUzGB8QIDAQAB
-----END PUBLIC KEY-----", -----END PUBLIC KEY-----",
) )
.unwrap(); .expect("fail to decode public key");
let ts = chrono::Local::now().timestamp_millis(); let ts = chrono::Local::now().timestamp_millis();
let data = format!("refresh_{}", ts).into_bytes(); let data = format!("refresh_{}", ts).into_bytes();
let mut rng = rand::rngs::OsRng; let mut rng = rand::rngs::OsRng;
let encrypted = key.encrypt(&mut rng, Oaep::new::<Sha256>(), &data).unwrap(); let encrypted = key
.encrypt(&mut rng, Oaep::new::<Sha256>(), &data)
.expect("fail to encrypt");
hex::encode(encrypted) hex::encode(encrypted)
} }
@@ -161,10 +163,10 @@ JNrRuoEUXpabUzGB8QIDAQAB
_ => unreachable!(), _ => unreachable!(),
} }
} }
if !res["data"]["refresh_token"].is_string() { match res["data"]["refresh_token"].as_str() {
bail!("refresh_token not found"); Some(token) => credential.ac_time_value = token.to_string(),
None => bail!("refresh_token not found"),
} }
credential.ac_time_value = res["data"]["refresh_token"].as_str().unwrap().to_string();
Ok(credential) Ok(credential)
} }
@@ -195,9 +197,9 @@ fn regex_find(pattern: &str, doc: &str) -> Result<String> {
let re = Regex::new(pattern)?; let re = Regex::new(pattern)?;
Ok(re Ok(re
.captures(doc) .captures(doc)
.ok_or(anyhow!("pattern not match"))? .ok_or_else(|| anyhow!("no match found"))?
.get(1) .get(1)
.unwrap() .ok_or_else(|| anyhow!("no capture found"))?
.as_str() .as_str()
.to_string()) .to_string())
} }
@@ -240,7 +242,9 @@ fn _encoded_query<'a>(
.collect(); .collect();
params.push(("wts", timestamp.into())); params.push(("wts", timestamp.into()));
params.sort_by(|a, b| a.0.cmp(b.0)); params.sort_by(|a, b| a.0.cmp(b.0));
let query = serde_urlencoded::to_string(&params).unwrap().replace('+', "%20"); let query = serde_urlencoded::to_string(&params)
.expect("fail to encode query")
.replace('+', "%20");
params.push(("w_rid", format!("{:x}", md5::compute(query.clone() + mixin_key)).into())); params.push(("w_rid", format!("{:x}", md5::compute(query.clone() + mixin_key)).into()));
params params
} }

View File

@@ -71,23 +71,25 @@ impl<'a> FavoriteList<'a> {
Err(e) => { Err(e) => {
error!("failed to get videos of favorite {} page {}: {}", self.fid, page, e); error!("failed to get videos of favorite {} page {}: {}", self.fid, page, e);
break; break;
}, }
}; };
if !videos["data"]["medias"].is_array() { let medias = &mut videos["data"]["medias"];
warn!("no medias found in favorite {} page {}", self.fid, page); if medias.as_array().is_none_or(|v| v.is_empty()) {
error!("no medias found in favorite {} page {}", self.fid, page);
break; break;
} }
let videos_info = match serde_json::from_value::<Vec<VideoInfo>>(videos["data"]["medias"].take()) { let videos_info: Vec<VideoInfo> = match serde_json::from_value(medias.take()) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to parse videos of favorite {} page {}: {}", self.fid, page, e); error!("failed to parse videos of favorite {} page {}: {}", self.fid, page, e);
break; break;
}, }
}; };
for video_info in videos_info{ for video_info in videos_info {
yield video_info; yield video_info;
} }
if videos["data"]["has_more"].is_boolean() && videos["data"]["has_more"].as_bool().unwrap(){ let has_more = &videos["data"]["has_more"];
if has_more.as_bool().is_some_and(|v| v) {
page += 1; page += 1;
continue; continue;
} }

View File

@@ -66,23 +66,25 @@ impl<'a> Submission<'a> {
Err(e) => { Err(e) => {
error!("failed to get videos of upper {} page {}: {}", self.upper_id, page, e); error!("failed to get videos of upper {} page {}: {}", self.upper_id, page, e);
break; break;
}, }
}; };
if !videos["data"]["list"]["vlist"].is_array() { let vlist = &mut videos["data"]["list"]["vlist"];
warn!("no medias found in upper {} page {}", self.upper_id, page); if vlist.as_array().is_none_or(|v| v.is_empty()) {
error!("no medias found in upper {} page {}", self.upper_id, page);
break; break;
} }
let videos_info = match serde_json::from_value::<Vec<VideoInfo>>(videos["data"]["list"]["vlist"].take()) { let videos_info: Vec<VideoInfo> = match serde_json::from_value(vlist.take()) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to parse videos of upper {} page {}: {}", self.upper_id, page, e); error!("failed to parse videos of upper {} page {}: {}", self.upper_id, page, e);
break; break;
}, }
}; };
for video_info in videos_info{ for video_info in videos_info {
yield video_info; yield video_info;
} }
if videos["data"]["page"]["count"].is_i64() && videos["data"]["page"]["count"].as_i64().unwrap() > (page * 30) as i64 { let count = &videos["data"]["page"]["count"];
if count.as_i64().is_some_and(|v| v > (page * 30) as i64) {
page += 1; page += 1;
continue; continue;
} }

View File

@@ -172,7 +172,7 @@ fn bvid_to_aid(bvid: &str) -> u64 {
(bvid[4], bvid[7]) = (bvid[7], bvid[4]); (bvid[4], bvid[7]) = (bvid[7], bvid[4]);
let mut tmp = 0u64; let mut tmp = 0u64;
for char in bvid.into_iter().skip(3) { for char in bvid.into_iter().skip(3) {
let idx = DATA.iter().position(|&x| x == char).unwrap(); let idx = DATA.iter().position(|&x| x == char).expect("invalid bvid");
tmp = tmp * BASE + idx as u64; tmp = tmp * BASE + idx as u64;
} }
(tmp & MASK_CODE) ^ XOR_CODE (tmp & MASK_CODE) ^ XOR_CODE

View File

@@ -22,8 +22,12 @@ pub static TEMPLATE: Lazy<handlebars::Handlebars> = Lazy::new(|| {
} }
}); });
handlebars.register_helper("truncate", Box::new(truncate)); handlebars.register_helper("truncate", Box::new(truncate));
handlebars.path_safe_register("video", &CONFIG.video_name).unwrap(); handlebars
handlebars.path_safe_register("page", &CONFIG.page_name).unwrap(); .path_safe_register("video", &CONFIG.video_name)
.expect("failed to register video template");
handlebars
.path_safe_register("page", &CONFIG.page_name)
.expect("failed to register page template");
handlebars handlebars
}); });

View File

@@ -1,7 +1,7 @@
macro_rules! regex { macro_rules! regex {
($re:literal $(,)?) => {{ ($re:literal $(,)?) => {{
static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new(); static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
RE.get_or_init(|| regex::Regex::new($re).unwrap()) RE.get_or_init(|| regex::Regex::new($re).expect("invalid regex"))
}}; }};
} }