mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-08-25 02:00:30 +08:00
refactor: 继续调整优化部分代码,移除主体代码的所有 unwrap
This commit is contained in:
@@ -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()),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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()),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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()),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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!(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(¶ms).unwrap().replace('+', "%20");
|
let query = serde_urlencoded::to_string(¶ms)
|
||||||
|
.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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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"))
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user