mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-08-28 19:47:54 +08:00
feat: 支持获取我的收藏夹、收藏的视频合集与关注的 up 主 (#349)
This commit is contained in:
@@ -0,0 +1,119 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use reqwest::Method;
|
||||||
|
|
||||||
|
use crate::bilibili::{BiliClient, Validate};
|
||||||
|
use crate::config::CONFIG;
|
||||||
|
pub struct Me<'a> {
|
||||||
|
client: &'a BiliClient,
|
||||||
|
mid: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Me<'a> {
|
||||||
|
pub fn new(client: &'a BiliClient) -> Self {
|
||||||
|
Self {
|
||||||
|
client,
|
||||||
|
mid: Self::my_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_created_favorites(&self) -> Result<Option<Vec<FavoriteItem>>> {
|
||||||
|
let mut resp = self
|
||||||
|
.client
|
||||||
|
.request(Method::GET, "https://api.bilibili.com/x/v3/fav/folder/created/list-all")
|
||||||
|
.await
|
||||||
|
.query(&[("up_mid", &self.mid)])
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?
|
||||||
|
.json::<serde_json::Value>()
|
||||||
|
.await?
|
||||||
|
.validate()?;
|
||||||
|
Ok(serde_json::from_value(resp["data"]["list"].take())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_followed_collections(&self, page: i32) -> Result<Collections> {
|
||||||
|
let mut resp = self
|
||||||
|
.client
|
||||||
|
.request(Method::GET, "https://api.bilibili.com/x/v3/fav/folder/collected/list")
|
||||||
|
.await
|
||||||
|
.query(&[
|
||||||
|
("up_mid", self.mid.as_ref()),
|
||||||
|
("pn", page.to_string().as_ref()),
|
||||||
|
("ps", "20"),
|
||||||
|
("platform", "web"),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?
|
||||||
|
.json::<serde_json::Value>()
|
||||||
|
.await?
|
||||||
|
.validate()?;
|
||||||
|
Ok(serde_json::from_value(resp["data"].take())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_followed_uppers(&self, page: i32) -> Result<FollowedUppers> {
|
||||||
|
let mut resp = self
|
||||||
|
.client
|
||||||
|
.request(Method::GET, "https://api.bilibili.com/x/relation/followings")
|
||||||
|
.await
|
||||||
|
.query(&[
|
||||||
|
("vmid", self.mid.as_ref()),
|
||||||
|
("pn", page.to_string().as_ref()),
|
||||||
|
("ps", "20"),
|
||||||
|
])
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.error_for_status()?
|
||||||
|
.json::<serde_json::Value>()
|
||||||
|
.await?
|
||||||
|
.validate()?;
|
||||||
|
Ok(serde_json::from_value(resp["data"].take())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_id() -> String {
|
||||||
|
CONFIG
|
||||||
|
.credential
|
||||||
|
.load()
|
||||||
|
.as_deref()
|
||||||
|
.map(|c| c.dedeuserid.clone())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct FavoriteItem {
|
||||||
|
pub title: String,
|
||||||
|
pub media_count: i64,
|
||||||
|
pub fid: i64,
|
||||||
|
pub mid: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct CollectionItem {
|
||||||
|
pub id: i64,
|
||||||
|
pub mid: i64,
|
||||||
|
pub state: i32,
|
||||||
|
pub title: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct Collections {
|
||||||
|
pub count: i64,
|
||||||
|
pub list: Option<Vec<CollectionItem>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct FollowedUppers {
|
||||||
|
pub total: i64,
|
||||||
|
pub list: Vec<FollowedUpper>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)]
|
||||||
|
pub struct FollowedUpper {
|
||||||
|
pub mid: i64,
|
||||||
|
pub uname: String,
|
||||||
|
pub face: String,
|
||||||
|
pub sign: String,
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub use analyzer::VideoCodecs;
|
|
||||||
pub use analyzer::{BestStream, FilterOption};
|
pub use analyzer::{BestStream, FilterOption};
|
||||||
use anyhow::{Result, bail, ensure};
|
use anyhow::{Result, bail, ensure};
|
||||||
use arc_swap::ArcSwapOption;
|
use arc_swap::ArcSwapOption;
|
||||||
@@ -26,6 +24,7 @@ mod credential;
|
|||||||
mod danmaku;
|
mod danmaku;
|
||||||
mod error;
|
mod error;
|
||||||
mod favorite_list;
|
mod favorite_list;
|
||||||
|
mod me;
|
||||||
mod submission;
|
mod submission;
|
||||||
mod subtitle;
|
mod subtitle;
|
||||||
mod video;
|
mod video;
|
||||||
|
|||||||
@@ -38,10 +38,12 @@ pub static ARGS: Lazy<Args> = Lazy::new(Args::parse);
|
|||||||
pub static CONFIG_DIR: Lazy<PathBuf> =
|
pub static CONFIG_DIR: Lazy<PathBuf> =
|
||||||
Lazy::new(|| dirs::config_dir().expect("No config path found").join("bili-sync"));
|
Lazy::new(|| dirs::config_dir().expect("No config path found").join("bili-sync"));
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
fn load_config() -> Config {
|
fn load_config() -> Config {
|
||||||
|
if cfg!(test) {
|
||||||
|
return Config::load(&CONFIG_DIR.join("test_config.toml")).unwrap_or(Config::test_default());
|
||||||
|
}
|
||||||
info!("开始加载配置文件..");
|
info!("开始加载配置文件..");
|
||||||
let config = Config::load().unwrap_or_else(|err| {
|
let config = Config::load(&CONFIG_DIR.join("config.toml")).unwrap_or_else(|err| {
|
||||||
if err
|
if err
|
||||||
.downcast_ref::<std::io::Error>()
|
.downcast_ref::<std::io::Error>()
|
||||||
.is_none_or(|e| e.kind() != std::io::ErrorKind::NotFound)
|
.is_none_or(|e| e.kind() != std::io::ErrorKind::NotFound)
|
||||||
@@ -58,36 +60,3 @@ fn load_config() -> Config {
|
|||||||
info!("配置文件检查通过");
|
info!("配置文件检查通过");
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn load_config() -> Config {
|
|
||||||
use crate::bilibili::{FilterOption, VideoCodecs};
|
|
||||||
|
|
||||||
let credential = match (
|
|
||||||
std::env::var("TEST_SESSDATA"),
|
|
||||||
std::env::var("TEST_BILI_JCT"),
|
|
||||||
std::env::var("TEST_BUVID3"),
|
|
||||||
std::env::var("TEST_DEDEUSERID"),
|
|
||||||
std::env::var("TEST_AC_TIME_VALUE"),
|
|
||||||
) {
|
|
||||||
(Ok(sessdata), Ok(bili_jct), Ok(buvid3), Ok(dedeuserid), Ok(ac_time_value)) => {
|
|
||||||
Some(std::sync::Arc::new(crate::bilibili::Credential {
|
|
||||||
sessdata,
|
|
||||||
bili_jct,
|
|
||||||
buvid3,
|
|
||||||
dedeuserid,
|
|
||||||
ac_time_value,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
Config {
|
|
||||||
credential: arc_swap::ArcSwapOption::from(credential),
|
|
||||||
cdn_sorting: true,
|
|
||||||
filter_option: FilterOption {
|
|
||||||
codecs: vec![VideoCodecs::HEV, VideoCodecs::AV1, VideoCodecs::AVC],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -105,10 +105,8 @@ impl Config {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
fn load(path: &Path) -> Result<Self> {
|
||||||
fn load() -> Result<Self> {
|
let config_content = std::fs::read_to_string(path)?;
|
||||||
let config_path = CONFIG_DIR.join("config.toml");
|
|
||||||
let config_content = std::fs::read_to_string(config_path)?;
|
|
||||||
Ok(toml::from_str(&config_content)?)
|
Ok(toml::from_str(&config_content)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +127,6 @@ impl Config {
|
|||||||
params
|
params
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
pub fn check(&self) {
|
pub fn check(&self) {
|
||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
let video_sources = self.as_video_sources();
|
let video_sources = self.as_video_sources();
|
||||||
@@ -184,4 +181,11 @@ impl Config {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn test_default() -> Self {
|
||||||
|
Self {
|
||||||
|
cdn_sorting: true,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use tokio::io::{AsyncWriteExt, BufWriter};
|
|||||||
|
|
||||||
use crate::config::{CONFIG, NFOTimeType};
|
use crate::config::{CONFIG, NFOTimeType};
|
||||||
|
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum NFO<'a> {
|
pub enum NFO<'a> {
|
||||||
Movie(Movie<'a>),
|
Movie(Movie<'a>),
|
||||||
TVShow(TVShow<'a>),
|
TVShow(TVShow<'a>),
|
||||||
|
|||||||
Reference in New Issue
Block a user