mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-09-07 08:27:21 +08:00
refactor: 使用 context 代替 ok_or 和 ok_or_else
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::{anyhow, Result};
|
use anyhow::{Context, 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;
|
||||||
@@ -196,7 +196,7 @@ pub(super) async fn collection_from<'a>(
|
|||||||
)
|
)
|
||||||
.one(connection)
|
.one(connection)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(anyhow!("collection not found"))?,
|
.context("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::{anyhow, Result};
|
use anyhow::{Context, 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;
|
||||||
@@ -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?
|
||||||
.ok_or(anyhow!("favorite not found"))?,
|
.context("favorite not found")?,
|
||||||
),
|
),
|
||||||
Box::pin(favorite.into_video_stream()),
|
Box::pin(favorite.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::{anyhow, Result};
|
use anyhow::{Context, 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;
|
||||||
@@ -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?
|
||||||
.ok_or(anyhow!("submission not found"))?,
|
.context("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::{anyhow, Result};
|
use anyhow::{Context, 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;
|
||||||
@@ -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?
|
||||||
.ok_or(anyhow!("watch_later not found"))?,
|
.context("watch_later not found")?,
|
||||||
),
|
),
|
||||||
Box::pin(watch_later.into_video_stream()),
|
Box::pin(watch_later.into_video_stream()),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::bilibili::error::BiliError;
|
use crate::bilibili::error::BiliError;
|
||||||
@@ -160,7 +160,7 @@ impl PageAnalyzer {
|
|||||||
return Ok(vec![Stream::Flv(
|
return Ok(vec![Stream::Flv(
|
||||||
self.info["durl"][0]["url"]
|
self.info["durl"][0]["url"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.ok_or(anyhow!("invalid flv stream"))?
|
.context("invalid flv stream")?
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ impl PageAnalyzer {
|
|||||||
return Ok(vec![Stream::Html5Mp4(
|
return Ok(vec![Stream::Html5Mp4(
|
||||||
self.info["durl"][0]["url"]
|
self.info["durl"][0]["url"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.ok_or(anyhow!("invalid html5 mp4 stream"))?
|
.context("invalid html5 mp4 stream")?
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ impl PageAnalyzer {
|
|||||||
return Ok(vec![Stream::EpositeTryMp4(
|
return Ok(vec![Stream::EpositeTryMp4(
|
||||||
self.info["durl"][0]["url"]
|
self.info["durl"][0]["url"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.ok_or(anyhow!("invalid episode try mp4 stream"))?
|
.context("invalid episode try mp4 stream")?
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ impl PageAnalyzer {
|
|||||||
) else {
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let quality = VideoQuality::from_repr(quality as usize).ok_or(anyhow!("invalid video stream quality"))?;
|
let quality = VideoQuality::from_repr(quality as usize).context("invalid video stream quality")?;
|
||||||
// 从视频流的 codecs 字段中获取编码格式,此处并非精确匹配而是判断包含,比如 codecs 是 av1.42c01e,需要匹配为 av1
|
// 从视频流的 codecs 字段中获取编码格式,此处并非精确匹配而是判断包含,比如 codecs 是 av1.42c01e,需要匹配为 av1
|
||||||
let Some(codecs) = [VideoCodecs::HEV, VideoCodecs::AVC, VideoCodecs::AV1]
|
let Some(codecs) = [VideoCodecs::HEV, VideoCodecs::AVC, VideoCodecs::AV1]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -221,8 +221,7 @@ impl PageAnalyzer {
|
|||||||
let (Some(url), Some(quality)) = (audio["baseUrl"].as_str(), audio["id"].as_u64()) else {
|
let (Some(url), Some(quality)) = (audio["baseUrl"].as_str(), audio["id"].as_u64()) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let quality =
|
let quality = AudioQuality::from_repr(quality as usize).context("invalid audio stream quality")?;
|
||||||
AudioQuality::from_repr(quality as usize).ok_or(anyhow!("invalid audio stream quality"))?;
|
|
||||||
if quality < filter_option.audio_min_quality || quality > filter_option.audio_max_quality {
|
if quality < filter_option.audio_min_quality || quality > filter_option.audio_max_quality {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -237,7 +236,7 @@ impl PageAnalyzer {
|
|||||||
let (Some(url), Some(quality)) = (flac["baseUrl"].as_str(), flac["id"].as_u64()) else {
|
let (Some(url), Some(quality)) = (flac["baseUrl"].as_str(), flac["id"].as_u64()) else {
|
||||||
bail!("invalid flac stream");
|
bail!("invalid flac stream");
|
||||||
};
|
};
|
||||||
let quality = AudioQuality::from_repr(quality as usize).ok_or(anyhow!("invalid flac stream quality"))?;
|
let quality = AudioQuality::from_repr(quality as usize).context("invalid flac stream quality")?;
|
||||||
if quality >= filter_option.audio_min_quality && quality <= filter_option.audio_max_quality {
|
if quality >= filter_option.audio_min_quality && quality <= filter_option.audio_max_quality {
|
||||||
streams.push(Stream::DashAudio {
|
streams.push(Stream::DashAudio {
|
||||||
url: url.to_string(),
|
url: url.to_string(),
|
||||||
@@ -250,8 +249,7 @@ impl PageAnalyzer {
|
|||||||
let (Some(url), Some(quality)) = (dolby_audio["baseUrl"].as_str(), dolby_audio["id"].as_u64()) else {
|
let (Some(url), Some(quality)) = (dolby_audio["baseUrl"].as_str(), dolby_audio["id"].as_u64()) else {
|
||||||
bail!("invalid dolby audio stream");
|
bail!("invalid dolby audio stream");
|
||||||
};
|
};
|
||||||
let quality =
|
let quality = AudioQuality::from_repr(quality as usize).context("invalid dolby audio stream quality")?;
|
||||||
AudioQuality::from_repr(quality as usize).ok_or(anyhow!("invalid dolby audio stream quality"))?;
|
|
||||||
if quality >= filter_option.audio_min_quality && quality <= filter_option.audio_max_quality {
|
if quality >= filter_option.audio_min_quality && quality <= filter_option.audio_max_quality {
|
||||||
streams.push(Stream::DashAudio {
|
streams.push(Stream::DashAudio {
|
||||||
url: url.to_string(),
|
url: url.to_string(),
|
||||||
@@ -267,7 +265,7 @@ impl PageAnalyzer {
|
|||||||
if self.is_flv_stream() || self.is_html5_mp4_stream() || self.is_episode_try_mp4_stream() {
|
if self.is_flv_stream() || self.is_html5_mp4_stream() || self.is_episode_try_mp4_stream() {
|
||||||
// 按照 streams 中的假设,符合这三种情况的流只有一个,直接取
|
// 按照 streams 中的假设,符合这三种情况的流只有一个,直接取
|
||||||
return Ok(BestStream::Mixed(
|
return Ok(BestStream::Mixed(
|
||||||
streams.into_iter().next().ok_or(anyhow!("no stream found"))?,
|
streams.into_iter().next().context("no stream found")?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let (videos, audios): (Vec<Stream>, Vec<Stream>) =
|
let (videos, audios): (Vec<Stream>, Vec<Stream>) =
|
||||||
@@ -297,7 +295,7 @@ impl PageAnalyzer {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
.ok_or(anyhow!("no video stream found"))?,
|
.context("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.cmp(b_quality)
|
a_quality.cmp(b_quality)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{Context, Result};
|
||||||
use leaky_bucket::RateLimiter;
|
use leaky_bucket::RateLimiter;
|
||||||
use reqwest::{header, Method};
|
use reqwest::{header, Method};
|
||||||
|
|
||||||
@@ -109,9 +109,7 @@ impl BiliClient {
|
|||||||
/// 获取 wbi img,用于生成请求签名
|
/// 获取 wbi img,用于生成请求签名
|
||||||
pub async fn wbi_img(&self) -> Result<WbiImg> {
|
pub async fn wbi_img(&self) -> Result<WbiImg> {
|
||||||
let credential = CONFIG.credential.load();
|
let credential = CONFIG.credential.load();
|
||||||
let Some(credential) = credential.as_deref() else {
|
let credential = credential.as_deref().context("no credential found")?;
|
||||||
bail!("no credential found");
|
|
||||||
};
|
|
||||||
credential.wbi_img(&self.client).await
|
credential.wbi_img(&self.client).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{header, Method};
|
use reqwest::{header, Method};
|
||||||
@@ -74,7 +74,7 @@ impl Credential {
|
|||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await?
|
.await?
|
||||||
.validate()?;
|
.validate()?;
|
||||||
res["data"]["refresh"].as_bool().ok_or(anyhow!("check refresh failed"))
|
res["data"]["refresh"].as_bool().context("check refresh failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn refresh(&self, client: &Client) -> Result<Self> {
|
pub async fn refresh(&self, client: &Client) -> Result<Self> {
|
||||||
@@ -152,9 +152,10 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|||||||
.filter_map(|x| Cookie::parse(x).ok())
|
.filter_map(|x| Cookie::parse(x).ok())
|
||||||
.filter(|x| required_cookies.contains(x.name()))
|
.filter(|x| required_cookies.contains(x.name()))
|
||||||
.collect();
|
.collect();
|
||||||
if cookies.len() != required_cookies.len() {
|
ensure!(
|
||||||
bail!("not all required cookies found");
|
cookies.len() == required_cookies.len(),
|
||||||
}
|
"not all required cookies found"
|
||||||
|
);
|
||||||
for cookie in cookies {
|
for cookie in cookies {
|
||||||
match cookie.name() {
|
match cookie.name() {
|
||||||
"SESSDATA" => credential.sessdata = cookie.value().to_string(),
|
"SESSDATA" => credential.sessdata = cookie.value().to_string(),
|
||||||
@@ -197,9 +198,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_else(|| anyhow!("no match found"))?
|
.context("no match found")?
|
||||||
.get(1)
|
.get(1)
|
||||||
.ok_or_else(|| anyhow!("no capture found"))?
|
.context("no capture found")?
|
||||||
.as_str()
|
.as_str()
|
||||||
.to_string())
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use analyzer::{BestStream, FilterOption};
|
pub use analyzer::{BestStream, FilterOption};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, ensure, Result};
|
||||||
use arc_swap::ArcSwapOption;
|
use arc_swap::ArcSwapOption;
|
||||||
use chrono::serde::ts_seconds;
|
use chrono::serde::ts_seconds;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
@@ -49,9 +49,7 @@ impl Validate for serde_json::Value {
|
|||||||
(Some(code), Some(msg)) => (code, msg),
|
(Some(code), Some(msg)) => (code, msg),
|
||||||
_ => bail!("no code or message found"),
|
_ => bail!("no code or message found"),
|
||||||
};
|
};
|
||||||
if code != 0 {
|
ensure!(code == 0, BiliError::RequestFailed(code, msg.to_owned()));
|
||||||
bail!(BiliError::RequestFailed(code, msg.to_owned()));
|
|
||||||
}
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{ensure, Result};
|
||||||
use futures::stream::FuturesUnordered;
|
use futures::stream::FuturesUnordered;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
@@ -130,13 +130,12 @@ impl<'a> Video<'a> {
|
|||||||
.error_for_status()?;
|
.error_for_status()?;
|
||||||
let headers = std::mem::take(res.headers_mut());
|
let headers = std::mem::take(res.headers_mut());
|
||||||
let content_type = headers.get("content-type");
|
let content_type = headers.get("content-type");
|
||||||
if content_type.is_none_or(|v| v != "application/octet-stream") {
|
ensure!(
|
||||||
bail!(
|
content_type.is_some_and(|v| v == "application/octet-stream"),
|
||||||
"unexpected content type: {:?}, body: {:?}",
|
"unexpected content type: {:?}, body: {:?}",
|
||||||
content_type,
|
content_type,
|
||||||
res.text().await
|
res.text().await
|
||||||
);
|
);
|
||||||
}
|
|
||||||
Ok(DmSegMobileReply::decode(res.bytes().await?)?.elems)
|
Ok(DmSegMobileReply::decode(res.bytes().await?)?.elems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use bili_sync_entity::*;
|
use bili_sync_entity::*;
|
||||||
use futures::stream::{FuturesOrdered, FuturesUnordered};
|
use futures::stream::{FuturesOrdered, FuturesUnordered};
|
||||||
use futures::{Future, Stream, StreamExt};
|
use futures::{Future, Stream, StreamExt};
|
||||||
@@ -151,18 +151,15 @@ pub async fn download_video_pages(
|
|||||||
upper_path: &Path,
|
upper_path: &Path,
|
||||||
upper_mutex: &(Mutex<()>, Mutex<()>),
|
upper_mutex: &(Mutex<()>, Mutex<()>),
|
||||||
) -> Result<video::ActiveModel> {
|
) -> Result<video::ActiveModel> {
|
||||||
let permit = semaphore.acquire().await;
|
let _permit = semaphore.acquire().await.context("acquire semaphore failed")?;
|
||||||
if let Err(e) = permit {
|
|
||||||
bail!(e);
|
|
||||||
}
|
|
||||||
let mut status = VideoStatus::new(video_model.download_status);
|
let mut status = VideoStatus::new(video_model.download_status);
|
||||||
let seprate_status = status.should_run();
|
let seprate_status = status.should_run();
|
||||||
let base_path = Path::new(&video_model.path);
|
let base_path = Path::new(&video_model.path);
|
||||||
let upper_id = video_model.upper_id.to_string();
|
let upper_id = video_model.upper_id.to_string();
|
||||||
let base_upper_path = upper_path
|
let base_upper_path = upper_path
|
||||||
.join(upper_id.chars().next().ok_or(anyhow!("upper_id is empty"))?.to_string())
|
.join(upper_id.chars().next().context("upper_id is empty")?.to_string())
|
||||||
.join(upper_id);
|
.join(upper_id);
|
||||||
let is_single_page = video_model.single_page.ok_or(anyhow!("single_page is null"))?;
|
let is_single_page = video_model.single_page.context("single_page is null")?;
|
||||||
// 对于单页视频,page 的下载已经足够
|
// 对于单页视频,page 的下载已经足够
|
||||||
// 对于多页视频,page 下载仅包含了分集内容,需要额外补上视频的 poster 的 tvshow.nfo
|
// 对于多页视频,page 下载仅包含了分集内容,需要额外补上视频的 poster 的 tvshow.nfo
|
||||||
let tasks: Vec<Pin<Box<dyn Future<Output = Result<()>>>>> = vec![
|
let tasks: Vec<Pin<Box<dyn Future<Output = Result<()>>>>> = vec![
|
||||||
@@ -308,7 +305,7 @@ pub async fn download_page(
|
|||||||
}
|
}
|
||||||
let mut status = PageStatus::new(page_model.download_status);
|
let mut status = PageStatus::new(page_model.download_status);
|
||||||
let seprate_status = status.should_run();
|
let seprate_status = status.should_run();
|
||||||
let is_single_page = video_model.single_page.ok_or(anyhow!("single_page is null"))?;
|
let is_single_page = video_model.single_page.context("single_page is null")?;
|
||||||
let base_path = Path::new(&video_model.path);
|
let base_path = Path::new(&video_model.path);
|
||||||
let base_name = TEMPLATE.path_safe_render(
|
let base_name = TEMPLATE.path_safe_render(
|
||||||
"page",
|
"page",
|
||||||
@@ -428,7 +425,7 @@ pub async fn fetch_page_poster(
|
|||||||
if !should_run {
|
if !should_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let single_page = video_model.single_page.ok_or(anyhow!("single_page is null"))?;
|
let single_page = video_model.single_page.context("single_page is null")?;
|
||||||
let url = if single_page {
|
let url = if single_page {
|
||||||
// 单页视频直接用视频的封面
|
// 单页视频直接用视频的封面
|
||||||
video_model.cover.as_str()
|
video_model.cover.as_str()
|
||||||
@@ -516,7 +513,7 @@ pub async fn generate_page_nfo(
|
|||||||
if !should_run {
|
if !should_run {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let single_page = video_model.single_page.ok_or(anyhow!("single_page is null"))?;
|
let single_page = video_model.single_page.context("single_page is null")?;
|
||||||
let nfo_serializer = if single_page {
|
let nfo_serializer = if single_page {
|
||||||
NFOSerializer(ModelWrapper::Video(video_model), NFOMode::MOVIE)
|
NFOSerializer(ModelWrapper::Video(video_model), NFOMode::MOVIE)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user