mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-09-05 23:49:53 +08:00
chore: 全盘使用 anyhow::Result
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Result};
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
pub struct PageAnalyzer {
|
pub struct PageAnalyzer {
|
||||||
info: serde_json::Value,
|
info: serde_json::Value,
|
||||||
}
|
}
|
||||||
@@ -161,14 +160,14 @@ impl PageAnalyzer {
|
|||||||
.as_array()
|
.as_array()
|
||||||
.ok_or_else(|| -> Result<serde_json::Value> {
|
.ok_or_else(|| -> Result<serde_json::Value> {
|
||||||
error!("video data is not an array: {:?}", self.info);
|
error!("video data is not an array: {:?}", self.info);
|
||||||
Err("invalid video data".into())
|
Err(anyhow!("invalid video data"))
|
||||||
})
|
})
|
||||||
.unwrap_or(&Vec::new())
|
.unwrap_or(&Vec::new())
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
let video_stream_url = video_data["baseUrl"].as_str().unwrap().to_string();
|
let video_stream_url = video_data["baseUrl"].as_str().unwrap().to_string();
|
||||||
let video_stream_quality = VideoQuality::from_repr(video_data["id"].as_u64().unwrap() as usize)
|
let video_stream_quality = VideoQuality::from_repr(video_data["id"].as_u64().unwrap() as usize)
|
||||||
.ok_or("invalid video stream quality")?;
|
.ok_or(anyhow!("invalid video stream quality"))?;
|
||||||
if (video_stream_quality == VideoQuality::QualityHdr && filter_option.no_hdr)
|
if (video_stream_quality == VideoQuality::QualityHdr && filter_option.no_hdr)
|
||||||
|| (video_stream_quality == VideoQuality::QualityDolby && filter_option.no_dolby_video)
|
|| (video_stream_quality == VideoQuality::QualityDolby && filter_option.no_dolby_video)
|
||||||
|| (video_stream_quality != VideoQuality::QualityDolby
|
|| (video_stream_quality != VideoQuality::QualityDolby
|
||||||
@@ -306,7 +305,7 @@ impl PageAnalyzer {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
});
|
});
|
||||||
if video_streams.is_empty() {
|
if video_streams.is_empty() {
|
||||||
return Err("no stream found".into());
|
bail!("no video stream found");
|
||||||
}
|
}
|
||||||
Ok(BestStream::VideoAudio {
|
Ok(BestStream::VideoAudio {
|
||||||
video: video_streams.remove(video_streams.len() - 1),
|
video: video_streams.remove(video_streams.len() - 1),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use anyhow::Result;
|
||||||
use reqwest::{header, Method};
|
use reqwest::{header, Method};
|
||||||
|
|
||||||
use crate::bilibili::Credential;
|
use crate::bilibili::Credential;
|
||||||
use crate::config::CONFIG;
|
use crate::config::CONFIG;
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
// 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求
|
// 一个对 reqwest::Client 的简单封装,用于 Bilibili 请求
|
||||||
pub struct Client(reqwest::Client);
|
pub struct Client(reqwest::Client);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Result};
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{header, Method};
|
use reqwest::{header, Method};
|
||||||
@@ -9,7 +10,6 @@ use rsa::{Oaep, RsaPublicKey};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::bilibili::Client;
|
use crate::bilibili::Client;
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Credential {
|
pub struct Credential {
|
||||||
@@ -43,7 +43,7 @@ impl Credential {
|
|||||||
.await?
|
.await?
|
||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await?;
|
.await?;
|
||||||
res["data"]["refresh"].as_bool().ok_or("check refresh failed".into())
|
res["data"]["refresh"].as_bool().ok_or(anyhow!("check refresh failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn refresh(&mut self, client: &Client) -> Result<()> {
|
pub async fn refresh(&mut self, client: &Client) -> Result<()> {
|
||||||
@@ -85,8 +85,8 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|||||||
.await?;
|
.await?;
|
||||||
if !res.status().is_success() {
|
if !res.status().is_success() {
|
||||||
return match res.status().as_u16() {
|
return match res.status().as_u16() {
|
||||||
404 => Err("correspond path is wrong or expired".into()),
|
404 => Err(anyhow!("correspond path is wrong or expired")),
|
||||||
_ => Err("get csrf failed".into()),
|
_ => Err(anyhow!("get csrf failed")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
regex_find(r#"<div id="1-name">(.+?)</div>"#, res.text().await?.as_str())
|
regex_find(r#"<div id="1-name">(.+?)</div>"#, res.text().await?.as_str())
|
||||||
@@ -122,7 +122,7 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|||||||
.filter(|x| required_cookies.contains(x.name()))
|
.filter(|x| required_cookies.contains(x.name()))
|
||||||
.collect();
|
.collect();
|
||||||
if cookies.len() != required_cookies.len() {
|
if cookies.len() != required_cookies.len() {
|
||||||
return Err("not all required cookies found".into());
|
bail!("not all required cookies found");
|
||||||
}
|
}
|
||||||
for cookie in cookies {
|
for cookie in cookies {
|
||||||
match cookie.name() {
|
match cookie.name() {
|
||||||
@@ -134,7 +134,7 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|||||||
}
|
}
|
||||||
let json = res.json::<serde_json::Value>().await?;
|
let json = res.json::<serde_json::Value>().await?;
|
||||||
if !json["data"]["refresh_token"].is_string() {
|
if !json["data"]["refresh_token"].is_string() {
|
||||||
return Err("refresh_token not found".into());
|
bail!("refresh_token not found");
|
||||||
}
|
}
|
||||||
credential.ac_time_value = json["data"]["refresh_token"].as_str().unwrap().to_string();
|
credential.ac_time_value = json["data"]["refresh_token"].as_str().unwrap().to_string();
|
||||||
Ok(credential)
|
Ok(credential)
|
||||||
@@ -157,7 +157,7 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await?;
|
.await?;
|
||||||
if res["code"] != 0 {
|
if res["code"] != 0 {
|
||||||
return Err(format!("confirm refresh failed: {}", res["message"]).into());
|
bail!("confirm refresh failed: {}", res["message"]);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ 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("pattern not match")?
|
.ok_or(anyhow!("pattern not match"))?
|
||||||
.get(1)
|
.get(1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_str()
|
.as_str()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use chrono::serde::ts_seconds;
|
use chrono::serde::ts_seconds;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
@@ -5,7 +6,6 @@ use futures_core::stream::Stream;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::bilibili::BiliClient;
|
use crate::bilibili::BiliClient;
|
||||||
use crate::Result;
|
|
||||||
pub struct FavoriteList<'a> {
|
pub struct FavoriteList<'a> {
|
||||||
client: &'a BiliClient,
|
client: &'a BiliClient,
|
||||||
fid: String,
|
fid: String,
|
||||||
@@ -75,7 +75,7 @@ impl<'a> FavoriteList<'a> {
|
|||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await?;
|
.await?;
|
||||||
if res["code"] != 0 {
|
if res["code"] != 0 {
|
||||||
return Err(format!("get favorite videos failed: {}", res["message"]).into());
|
bail!("get favorite videos failed: {}", res["message"]);
|
||||||
}
|
}
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
|
|
||||||
use crate::bilibili::analyzer::PageAnalyzer;
|
use crate::bilibili::analyzer::PageAnalyzer;
|
||||||
use crate::bilibili::client::BiliClient;
|
use crate::bilibili::client::BiliClient;
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
static MASK_CODE: u64 = 2251799813685247;
|
static MASK_CODE: u64 = 2251799813685247;
|
||||||
static XOR_CODE: u64 = 23442827791579;
|
static XOR_CODE: u64 = 23442827791579;
|
||||||
@@ -89,7 +89,7 @@ impl<'a> Video<'a> {
|
|||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await?;
|
.await?;
|
||||||
if res["code"] != 0 {
|
if res["code"] != 0 {
|
||||||
return Err(format!("get page analyzer failed: {}", res["message"]).into());
|
bail!("get page analyzer failed: {}", res["message"]);
|
||||||
}
|
}
|
||||||
Ok(PageAnalyzer::new(res["data"].take()))
|
Ok(PageAnalyzer::new(res["data"].take()))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -2,12 +2,12 @@ use std::collections::HashMap;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::bilibili::{Credential, FilterOption};
|
use crate::bilibili::{Credential, FilterOption};
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
pub static CONFIG: Lazy<Mutex<Config>> = Lazy::new(|| {
|
pub static CONFIG: Lazy<Mutex<Config>> = Lazy::new(|| {
|
||||||
let config = Config::new();
|
let config = Config::new();
|
||||||
@@ -75,7 +75,7 @@ impl Config {
|
|||||||
|
|
||||||
fn load() -> Result<Self> {
|
fn load() -> Result<Self> {
|
||||||
let config_path = dirs::config_dir()
|
let config_path = dirs::config_dir()
|
||||||
.ok_or("No config path found")?
|
.ok_or(anyhow!("No config path found"))?
|
||||||
.join("bili-sync")
|
.join("bili-sync")
|
||||||
.join("config.toml");
|
.join("config.toml");
|
||||||
let config_content = std::fs::read_to_string(config_path)?;
|
let config_content = std::fs::read_to_string(config_path)?;
|
||||||
@@ -84,7 +84,7 @@ impl Config {
|
|||||||
|
|
||||||
pub fn save(&self) -> Result<()> {
|
pub fn save(&self) -> Result<()> {
|
||||||
let config_path = dirs::config_dir()
|
let config_path = dirs::config_dir()
|
||||||
.ok_or("No config path found")?
|
.ok_or(anyhow!("No config path found"))?
|
||||||
.join("bili-sync")
|
.join("bili-sync")
|
||||||
.join("config.toml");
|
.join("config.toml");
|
||||||
if let Some(parent) = config_path.parent() {
|
if let Some(parent) = config_path.parent() {
|
||||||
|
|||||||
+2
-2
@@ -2,6 +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, Result};
|
||||||
use dirs::config_dir;
|
use dirs::config_dir;
|
||||||
use entity::{favorite, page, video};
|
use entity::{favorite, page, video};
|
||||||
use filenamify::filenamify;
|
use filenamify::filenamify;
|
||||||
@@ -21,7 +22,6 @@ use super::utils::{unhandled_videos_pages, ModelWrapper, NFOMode, NFOSerializer,
|
|||||||
use crate::bilibili::{BestStream, BiliClient, FavoriteList, FilterOption, PageInfo, Video};
|
use crate::bilibili::{BestStream, BiliClient, FavoriteList, FilterOption, PageInfo, Video};
|
||||||
use crate::core::utils::{create_video_pages, create_videos, exist_labels, filter_videos, handle_favorite_info};
|
use crate::core::utils::{create_video_pages, create_videos, exist_labels, filter_videos, handle_favorite_info};
|
||||||
use crate::downloader::Downloader;
|
use crate::downloader::Downloader;
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
/// 处理某个收藏夹,首先刷新收藏夹信息,然后下载收藏夹中未下载成功的视频
|
/// 处理某个收藏夹,首先刷新收藏夹信息,然后下载收藏夹中未下载成功的视频
|
||||||
pub async fn process_favorite(
|
pub async fn process_favorite(
|
||||||
@@ -234,7 +234,7 @@ pub async fn dispatch_download_page(
|
|||||||
&video_model.bvid, page_model.pid, &page_status
|
&video_model.bvid, page_model.pid, &page_status
|
||||||
);
|
);
|
||||||
if final_result.is_ok() && page_status.should_run().iter().any(|x| *x) {
|
if final_result.is_ok() && page_status.should_run().iter().any(|x| *x) {
|
||||||
final_result = Err("Some page item download failed".into());
|
final_result = Err(anyhow!("Some page item download failed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
+5
-3
@@ -1,6 +1,6 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
static STATUS_MAX_RETRY: u32 = 0b100;
|
static STATUS_MAX_RETRY: u32 = 0b100;
|
||||||
static STATUS_OK: u32 = 0b111;
|
static STATUS_OK: u32 = 0b111;
|
||||||
@@ -203,6 +203,8 @@ impl From<PageStatus> for u32 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -210,11 +212,11 @@ mod test {
|
|||||||
let mut status = Status::new(0);
|
let mut status = Status::new(0);
|
||||||
assert_eq!(status.should_run(3), vec![true, true, true]);
|
assert_eq!(status.should_run(3), vec![true, true, true]);
|
||||||
for count in 1..=3 {
|
for count in 1..=3 {
|
||||||
status.update_status(&[Err("".into()), Ok(()), Ok(())]);
|
status.update_status(&[Err(anyhow!("")), Ok(()), Ok(())]);
|
||||||
assert_eq!(status.should_run(3), vec![true, false, false]);
|
assert_eq!(status.should_run(3), vec![true, false, false]);
|
||||||
assert_eq!(u32::from(status.clone()), 0b111_111_000 + count);
|
assert_eq!(u32::from(status.clone()), 0b111_111_000 + count);
|
||||||
}
|
}
|
||||||
status.update_status(&[Err("".into()), Ok(()), Ok(())]);
|
status.update_status(&[Err(anyhow!("")), Ok(()), Ok(())]);
|
||||||
assert_eq!(status.should_run(3), vec![false, false, false]);
|
assert_eq!(status.should_run(3), vec![false, false, false]);
|
||||||
assert_eq!(u32::from(status), 0b111_111_100 | Status::handled());
|
assert_eq!(u32::from(status), 0b111_111_100 | Status::handled());
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,7 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use entity::*;
|
use entity::*;
|
||||||
use filenamify::filenamify;
|
use filenamify::filenamify;
|
||||||
use migration::OnConflict;
|
use migration::OnConflict;
|
||||||
@@ -17,7 +18,6 @@ use tokio::io::AsyncWriteExt;
|
|||||||
use super::status::Status;
|
use super::status::Status;
|
||||||
use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo};
|
use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo};
|
||||||
use crate::config::CONFIG;
|
use crate::config::CONFIG;
|
||||||
use crate::Result;
|
|
||||||
|
|
||||||
pub static TEMPLATE: Lazy<handlebars::Handlebars> = Lazy::new(|| {
|
pub static TEMPLATE: Lazy<handlebars::Handlebars> = Lazy::new(|| {
|
||||||
let mut handlebars = handlebars::Handlebars::new();
|
let mut handlebars = handlebars::Handlebars::new();
|
||||||
|
|||||||
+2
-3
@@ -1,10 +1,9 @@
|
|||||||
|
use anyhow::{anyhow, Result};
|
||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
use sea_orm::{Database, DatabaseConnection};
|
use sea_orm::{Database, DatabaseConnection};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
use crate::Result;
|
|
||||||
pub async fn database_connection() -> Result<DatabaseConnection> {
|
pub async fn database_connection() -> Result<DatabaseConnection> {
|
||||||
let config_dir = dirs::config_dir().ok_or("No config path found")?;
|
let config_dir = dirs::config_dir().ok_or(anyhow!("No config path found"))?;
|
||||||
let target = config_dir.join("bili-sync").join("data.sqlite");
|
let target = config_dir.join("bili-sync").join("data.sqlite");
|
||||||
if let Some(parent) = target.parent() {
|
if let Some(parent) = target.parent() {
|
||||||
fs::create_dir_all(parent).await?;
|
fs::create_dir_all(parent).await?;
|
||||||
|
|||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use reqwest::Method;
|
use reqwest::Method;
|
||||||
use tokio::fs::{self, File};
|
use tokio::fs::{self, File};
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
|
|
||||||
use crate::bilibili::Client;
|
use crate::bilibili::Client;
|
||||||
use crate::Result;
|
|
||||||
pub struct Downloader {
|
pub struct Downloader {
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
@@ -46,8 +46,8 @@ impl Downloader {
|
|||||||
.await?;
|
.await?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
return match String::from_utf8(output.stderr) {
|
return match String::from_utf8(output.stderr) {
|
||||||
Ok(err) => Err(err.into()),
|
Ok(err) => Err(anyhow!(err)),
|
||||||
_ => Err("ffmpeg error".into()),
|
_ => Err(anyhow!("ffmpeg error")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let _ = fs::remove_file(video_path).await;
|
let _ = fs::remove_file(video_path).await;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
use std::error;
|
|
||||||
|
|
||||||
pub mod bilibili;
|
pub mod bilibili;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod downloader;
|
pub mod downloader;
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user