style: 将最大行宽设置为 120
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Module"
|
||||
max_width = 120
|
||||
|
||||
@@ -18,12 +18,7 @@ impl MigrationTrait for Migration {
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Favorite::FId)
|
||||
.unique_key()
|
||||
.unsigned()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Favorite::FId).unique_key().unsigned().not_null())
|
||||
.col(ColumnDef::new(Favorite::Name).string().not_null())
|
||||
.col(ColumnDef::new(Favorite::Path).string().not_null())
|
||||
.col(ColumnDef::new(Favorite::Enabled).boolean().not_null())
|
||||
@@ -61,12 +56,7 @@ impl MigrationTrait for Migration {
|
||||
.col(ColumnDef::new(Video::Ctime).timestamp().not_null())
|
||||
.col(ColumnDef::new(Video::Pubtime).timestamp().not_null())
|
||||
.col(ColumnDef::new(Video::Favtime).timestamp().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Video::Handled)
|
||||
.boolean()
|
||||
.default(false)
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Video::Handled).boolean().default(false).not_null())
|
||||
.col(ColumnDef::new(Video::Valid).boolean().not_null())
|
||||
.col(ColumnDef::new(Video::Tags).json_binary())
|
||||
.col(ColumnDef::new(Video::SinglePage).boolean())
|
||||
@@ -137,12 +127,8 @@ impl MigrationTrait for Migration {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Favorite::Table).to_owned())
|
||||
.await?;
|
||||
manager
|
||||
.drop_table(Table::drop().table(Video::Table).to_owned())
|
||||
.await?;
|
||||
manager
|
||||
.drop_table(Table::drop().table(Page::Table).to_owned())
|
||||
.await?;
|
||||
manager.drop_table(Table::drop().table(Video::Table).to_owned()).await?;
|
||||
manager.drop_table(Table::drop().table(Page::Table).to_owned()).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,10 +102,7 @@ impl Stream {
|
||||
/// 2. 视频、音频分离,作为 VideoAudio 返回,其中音频流可能不存在(对于无声视频,如 BV1J7411H7KQ)
|
||||
#[derive(Debug)]
|
||||
pub enum BestStream {
|
||||
VideoAudio {
|
||||
video: Stream,
|
||||
audio: Option<Stream>,
|
||||
},
|
||||
VideoAudio { video: Stream, audio: Option<Stream> },
|
||||
Mixed(Stream),
|
||||
}
|
||||
|
||||
@@ -158,12 +155,10 @@ impl PageAnalyzer {
|
||||
let dolby_data = self.info["dash"]["dolby"].take();
|
||||
for video_data in videos_data.as_array().unwrap().iter() {
|
||||
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)
|
||||
.ok_or("invalid video stream quality")?;
|
||||
let video_stream_quality = VideoQuality::from_repr(video_data["id"].as_u64().unwrap() as usize)
|
||||
.ok_or("invalid video stream quality")?;
|
||||
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::QualityHdr
|
||||
&& (video_stream_quality < filter_option.video_min_quality
|
||||
@@ -197,8 +192,7 @@ impl PageAnalyzer {
|
||||
if audios_data.is_array() {
|
||||
for audio_data in audios_data.as_array().unwrap().iter() {
|
||||
let audio_stream_url = audio_data["baseUrl"].as_str().unwrap().to_string();
|
||||
let audio_stream_quality =
|
||||
AudioQuality::from_repr(audio_data["id"].as_u64().unwrap() as usize);
|
||||
let audio_stream_quality = AudioQuality::from_repr(audio_data["id"].as_u64().unwrap() as usize);
|
||||
let Some(audio_stream_quality) = audio_stream_quality else {
|
||||
continue;
|
||||
};
|
||||
@@ -217,8 +211,7 @@ impl PageAnalyzer {
|
||||
// 允许 hires 且存在 flac 音频流才会进来
|
||||
let flac_stream_url = flac_data["audio"]["baseUrl"].as_str().unwrap().to_string();
|
||||
let flac_stream_quality =
|
||||
AudioQuality::from_repr(flac_data["audio"]["id"].as_u64().unwrap() as usize)
|
||||
.unwrap();
|
||||
AudioQuality::from_repr(flac_data["audio"]["id"].as_u64().unwrap() as usize).unwrap();
|
||||
streams.push(Stream::DashAudio {
|
||||
url: flac_stream_url,
|
||||
quality: flac_stream_quality,
|
||||
@@ -231,8 +224,7 @@ impl PageAnalyzer {
|
||||
let dolby_stream_data = dolby_stream_data.unwrap();
|
||||
let dolby_stream_url = dolby_stream_data["baseUrl"].as_str().unwrap().to_string();
|
||||
let dolby_stream_quality =
|
||||
AudioQuality::from_repr(dolby_stream_data["id"].as_u64().unwrap() as usize)
|
||||
.unwrap();
|
||||
AudioQuality::from_repr(dolby_stream_data["id"].as_u64().unwrap() as usize).unwrap();
|
||||
streams.push(Stream::DashAudio {
|
||||
url: dolby_stream_url,
|
||||
quality: dolby_stream_quality,
|
||||
@@ -249,9 +241,8 @@ impl PageAnalyzer {
|
||||
return Ok(BestStream::Mixed(streams.into_iter().next().unwrap()));
|
||||
}
|
||||
// 将视频流和音频流拆分,分别做排序
|
||||
let (mut video_streams, mut audio_streams): (Vec<_>, Vec<_>) = streams
|
||||
.into_iter()
|
||||
.partition(|s| matches!(s, Stream::DashVideo { .. }));
|
||||
let (mut video_streams, mut audio_streams): (Vec<_>, Vec<_>) =
|
||||
streams.into_iter().partition(|s| matches!(s, Stream::DashVideo { .. }));
|
||||
// 因为该处的排序与筛选选项有关,因此不能在外面实现 PartialOrd trait,只能在这里写闭包
|
||||
video_streams.sort_by(|a, b| match (a, b) {
|
||||
(
|
||||
@@ -291,14 +282,7 @@ impl PageAnalyzer {
|
||||
_ => unreachable!(),
|
||||
});
|
||||
audio_streams.sort_by(|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, .. }) => {
|
||||
if a_quality == &AudioQuality::QualityDolby && !filter_option.no_dolby_audio {
|
||||
return std::cmp::Ordering::Greater;
|
||||
}
|
||||
|
||||
@@ -11,27 +11,20 @@ impl Client {
|
||||
// 正常访问 api 所必须的 header,作为默认 header 添加到每个请求中
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.insert(
|
||||
header::USER_AGENT,
|
||||
header::HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.54"));
|
||||
header::USER_AGENT,
|
||||
header::HeaderValue::from_static(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.54",
|
||||
),
|
||||
);
|
||||
headers.insert(
|
||||
header::REFERER,
|
||||
header::HeaderValue::from_static("https://www.bilibili.com"),
|
||||
);
|
||||
Self(
|
||||
reqwest::Client::builder()
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
Self(reqwest::Client::builder().default_headers(headers).build().unwrap())
|
||||
}
|
||||
|
||||
// a wrapper of reqwest::Client::request to add credential to the request
|
||||
pub fn request(
|
||||
&self,
|
||||
method: Method,
|
||||
url: &str,
|
||||
credential: Option<&Credential>,
|
||||
) -> reqwest::RequestBuilder {
|
||||
pub fn request(&self, method: Method, url: &str, credential: Option<&Credential>) -> reqwest::RequestBuilder {
|
||||
let mut req = self.0.request(method, url);
|
||||
// 如果有 credential,会将其转换成 cookie 添加到请求的 header 中
|
||||
if let Some(credential) = credential {
|
||||
@@ -39,14 +32,8 @@ impl Client {
|
||||
.header(header::COOKIE, format!("SESSDATA={}", credential.sessdata))
|
||||
.header(header::COOKIE, format!("bili_jct={}", credential.bili_jct))
|
||||
.header(header::COOKIE, format!("buvid3={}", credential.buvid3))
|
||||
.header(
|
||||
header::COOKIE,
|
||||
format!("DedeUserID={}", credential.dedeuserid),
|
||||
)
|
||||
.header(
|
||||
header::COOKIE,
|
||||
format!("ac_time_value={}", credential.ac_time_value),
|
||||
);
|
||||
.header(header::COOKIE, format!("DedeUserID={}", credential.dedeuserid))
|
||||
.header(header::COOKIE, format!("ac_time_value={}", credential.ac_time_value));
|
||||
}
|
||||
req
|
||||
}
|
||||
|
||||
@@ -21,13 +21,7 @@ pub struct Credential {
|
||||
}
|
||||
|
||||
impl Credential {
|
||||
pub fn new(
|
||||
sessdata: String,
|
||||
bili_jct: String,
|
||||
buvid3: String,
|
||||
dedeuserid: String,
|
||||
ac_time_value: String,
|
||||
) -> Self {
|
||||
pub fn new(sessdata: String, bili_jct: String, buvid3: String, dedeuserid: String, ac_time_value: String) -> Self {
|
||||
Self {
|
||||
sessdata,
|
||||
bili_jct,
|
||||
@@ -49,9 +43,7 @@ impl Credential {
|
||||
.await?
|
||||
.json::<serde_json::Value>()
|
||||
.await?;
|
||||
res["refresh"]
|
||||
.as_bool()
|
||||
.ok_or("check refresh failed".into())
|
||||
res["refresh"].as_bool().ok_or("check refresh failed".into())
|
||||
}
|
||||
|
||||
pub async fn refresh(&mut self, client: &Client) -> Result<()> {
|
||||
@@ -74,10 +66,7 @@ impl Credential {
|
||||
-----END PUBLIC KEY-----",
|
||||
)
|
||||
.unwrap();
|
||||
let ts = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis();
|
||||
let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis();
|
||||
let data = format!("refresh_{}", ts).into_bytes();
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
let encrypted = key.encrypt(&mut rng, Oaep::new::<Sha256>(), &data).unwrap();
|
||||
@@ -100,10 +89,7 @@ impl Credential {
|
||||
_ => Err("get csrf failed".into()),
|
||||
};
|
||||
}
|
||||
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())
|
||||
}
|
||||
|
||||
async fn get_new_credential(&self, client: &Client, csrf: &str) -> Result<Credential> {
|
||||
@@ -134,10 +120,7 @@ impl Credential {
|
||||
};
|
||||
let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]);
|
||||
let cookies: Vec<Cookie> = Cookie::split_parse_encoded(set_cookie)
|
||||
.filter(|x| {
|
||||
x.as_ref()
|
||||
.is_ok_and(|x| required_cookies.contains(x.name()))
|
||||
})
|
||||
.filter(|x| x.as_ref().is_ok_and(|x| required_cookies.contains(x.name())))
|
||||
.map(|x| x.unwrap())
|
||||
.collect();
|
||||
if cookies.len() != required_cookies.len() {
|
||||
|
||||
@@ -49,10 +49,7 @@ impl<'a> FavoriteList<'a> {
|
||||
pub async fn get_info(&self) -> Result<FavoriteListInfo> {
|
||||
let mut res = self
|
||||
.client
|
||||
.request(
|
||||
reqwest::Method::GET,
|
||||
"https://api.bilibili.com/x/v3/fav/folder/info",
|
||||
)
|
||||
.request(reqwest::Method::GET, "https://api.bilibili.com/x/v3/fav/folder/info")
|
||||
.query(&[("media_id", &self.fid)])
|
||||
.send()
|
||||
.await?
|
||||
@@ -64,10 +61,7 @@ impl<'a> FavoriteList<'a> {
|
||||
async fn get_videos(&self, page: u32) -> Result<Value> {
|
||||
let res = self
|
||||
.client
|
||||
.request(
|
||||
reqwest::Method::GET,
|
||||
"https://api.bilibili.com/x/v3/fav/resource/list",
|
||||
)
|
||||
.request(reqwest::Method::GET, "https://api.bilibili.com/x/v3/fav/resource/list")
|
||||
.query(&[
|
||||
("media_id", self.fid.as_str()),
|
||||
("pn", &page.to_string()),
|
||||
|
||||
@@ -4,9 +4,7 @@ mod credential;
|
||||
mod favorite_list;
|
||||
mod video;
|
||||
|
||||
pub use analyzer::{
|
||||
AudioQuality, BestStream, FilterOption, PageAnalyzer, VideoCodecs, VideoQuality,
|
||||
};
|
||||
pub use analyzer::{AudioQuality, BestStream, FilterOption, PageAnalyzer, VideoCodecs, VideoQuality};
|
||||
pub use client::{BiliClient, Client};
|
||||
pub use credential::Credential;
|
||||
pub use favorite_list::{FavoriteList, FavoriteListInfo, VideoInfo};
|
||||
|
||||
@@ -8,10 +8,9 @@ static MASK_CODE: u64 = 2251799813685247;
|
||||
static XOR_CODE: u64 = 23442827791579;
|
||||
static BASE: u64 = 58;
|
||||
static DATA: &[char] = &[
|
||||
'F', 'c', 'w', 'A', 'P', 'N', 'K', 'T', 'M', 'u', 'g', '3', 'G', 'V', '5', 'L', 'j', '7', 'E',
|
||||
'J', 'n', 'H', 'p', 'W', 's', 'x', '4', 't', 'b', '8', 'h', 'a', 'Y', 'e', 'v', 'i', 'q', 'B',
|
||||
'z', '6', 'r', 'k', 'C', 'y', '1', '2', 'm', 'U', 'S', 'D', 'Q', 'X', '9', 'R', 'd', 'o', 'Z',
|
||||
'f',
|
||||
'F', 'c', 'w', 'A', 'P', 'N', 'K', 'T', 'M', 'u', 'g', '3', 'G', 'V', '5', 'L', 'j', '7', 'E', 'J', 'n', 'H', 'p',
|
||||
'W', 's', 'x', '4', 't', 'b', '8', 'h', 'a', 'Y', 'e', 'v', 'i', 'q', 'B', 'z', '6', 'r', 'k', 'C', 'y', '1', '2',
|
||||
'm', 'U', 'S', 'D', 'Q', 'X', '9', 'R', 'd', 'o', 'Z', 'f',
|
||||
];
|
||||
|
||||
pub struct Video<'a> {
|
||||
@@ -64,10 +63,7 @@ impl<'a> Video<'a> {
|
||||
pub async fn get_tags(&self) -> Result<Vec<Tag>> {
|
||||
let mut res = self
|
||||
.client
|
||||
.request(
|
||||
Method::GET,
|
||||
"https://api.bilibili.com/x/web-interface/view/detail/tag",
|
||||
)
|
||||
.request(Method::GET, "https://api.bilibili.com/x/web-interface/view/detail/tag")
|
||||
.query(&[("aid", &self.aid), ("bvid", &self.bvid)])
|
||||
.send()
|
||||
.await?
|
||||
|
||||
@@ -18,9 +18,7 @@ use tokio::sync::Semaphore;
|
||||
use super::status::Status;
|
||||
use super::utils::{unhandled_videos_pages, ModelWrapper, NFOMode, NFOSerializer};
|
||||
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::Result;
|
||||
|
||||
@@ -32,11 +30,7 @@ struct Context<'a> {
|
||||
pid: &'a str,
|
||||
}
|
||||
|
||||
pub async fn process_favorite(
|
||||
bili_client: &BiliClient,
|
||||
fid: &str,
|
||||
connection: &DatabaseConnection,
|
||||
) -> Result<()> {
|
||||
pub async fn process_favorite(bili_client: &BiliClient, fid: &str, connection: &DatabaseConnection) -> Result<()> {
|
||||
let favorite_model = refresh_favorite(bili_client, fid, connection).await?;
|
||||
download_favorite(bili_client, favorite_model, connection).await?;
|
||||
Ok(())
|
||||
@@ -60,8 +54,7 @@ pub async fn refresh_favorite(
|
||||
.iter()
|
||||
.any(|v| exist_labels.contains(&(v.bvid.clone(), v.fav_time.naive_utc())));
|
||||
create_videos(&videos_info, &favorite_model, connection).await?;
|
||||
let unrefreshed_video_models =
|
||||
filter_videos(&videos_info, &favorite_model, true, true, connection).await?;
|
||||
let unrefreshed_video_models = filter_videos(&videos_info, &favorite_model, true, true, connection).await?;
|
||||
if !unrefreshed_video_models.is_empty() {
|
||||
for video_model in unrefreshed_video_models {
|
||||
let bili_video = Video::new(bili_client, video_model.bvid.clone());
|
||||
@@ -177,10 +170,9 @@ pub async fn download_page(
|
||||
)
|
||||
} else {
|
||||
(
|
||||
base_path.join("Season 1").join(format!(
|
||||
"{} - S01E{:2}-thumb.jpg",
|
||||
&base_name, page_model.pid
|
||||
)),
|
||||
base_path
|
||||
.join("Season 1")
|
||||
.join(format!("{} - S01E{:2}-thumb.jpg", &base_name, page_model.pid)),
|
||||
base_path
|
||||
.join("Season 1")
|
||||
.join(format!("{} - S01E{:2}.mp4", &base_name, page_model.pid)),
|
||||
@@ -206,12 +198,7 @@ pub async fn download_page(
|
||||
downloader,
|
||||
video_path,
|
||||
)),
|
||||
Box::pin(generate_nfo(
|
||||
seprate_status[2],
|
||||
video_model,
|
||||
&page_model,
|
||||
nfo_path,
|
||||
)),
|
||||
Box::pin(generate_nfo(seprate_status[2], video_model, &page_model, nfo_path)),
|
||||
];
|
||||
let results = futures::future::join_all(tasks).await;
|
||||
status.update_status(&results);
|
||||
@@ -277,15 +264,9 @@ pub async fn download_video(
|
||||
page_path.with_extension("tmp_video"),
|
||||
page_path.with_extension("tmp_audio"),
|
||||
);
|
||||
downloader
|
||||
.fetch(video_stream.url(), &tmp_video_path)
|
||||
.await?;
|
||||
downloader
|
||||
.fetch(audio_stream.url(), &tmp_audio_path)
|
||||
.await?;
|
||||
downloader
|
||||
.merge(&tmp_video_path, &tmp_audio_path, &page_path)
|
||||
.await?;
|
||||
downloader.fetch(video_stream.url(), &tmp_video_path).await?;
|
||||
downloader.fetch(audio_stream.url(), &tmp_audio_path).await?;
|
||||
downloader.merge(&tmp_video_path, &tmp_audio_path, &page_path).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -29,10 +29,7 @@ pub enum ModelWrapper<'a> {
|
||||
pub struct NFOSerializer<'a>(pub ModelWrapper<'a>, pub NFOMode);
|
||||
|
||||
/// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象
|
||||
pub async fn handle_favorite_info(
|
||||
info: &FavoriteListInfo,
|
||||
connection: &DatabaseConnection,
|
||||
) -> Result<favorite::Model> {
|
||||
pub async fn handle_favorite_info(info: &FavoriteListInfo, connection: &DatabaseConnection) -> Result<favorite::Model> {
|
||||
favorite::Entity::insert(favorite::ActiveModel {
|
||||
f_id: Set(info.id),
|
||||
name: Set(info.title.to_string()),
|
||||
@@ -65,10 +62,7 @@ pub async fn exist_labels(
|
||||
favorite_model: &favorite::Model,
|
||||
connection: &DatabaseConnection,
|
||||
) -> Result<HashSet<(String, DateTime)>> {
|
||||
let bvids = videos_info
|
||||
.iter()
|
||||
.map(|v| v.bvid.clone())
|
||||
.collect::<Vec<String>>();
|
||||
let bvids = videos_info.iter().map(|v| v.bvid.clone()).collect::<Vec<String>>();
|
||||
let exist_labels = video::Entity::find()
|
||||
.filter(
|
||||
video::Column::FavoriteId
|
||||
@@ -138,10 +132,7 @@ pub async fn filter_videos(
|
||||
only_no_page: bool,
|
||||
connection: &DatabaseConnection,
|
||||
) -> Result<Vec<video::Model>> {
|
||||
let bvids = videos_info
|
||||
.iter()
|
||||
.map(|v| v.bvid.clone())
|
||||
.collect::<Vec<String>>();
|
||||
let bvids = videos_info.iter().map(|v| v.bvid.clone()).collect::<Vec<String>>();
|
||||
let mut condition = video::Column::FavoriteId
|
||||
.eq(favorite_model.id)
|
||||
.and(video::Column::Bvid.is_in(bvids))
|
||||
@@ -152,10 +143,7 @@ pub async fn filter_videos(
|
||||
if only_no_page {
|
||||
condition = condition.and(video::Column::SinglePage.is_null());
|
||||
}
|
||||
Ok(video::Entity::find()
|
||||
.filter(condition)
|
||||
.all(connection)
|
||||
.await?)
|
||||
Ok(video::Entity::find().filter(condition).all(connection).await?)
|
||||
}
|
||||
/// 创建视频的所有分 P
|
||||
pub async fn create_video_pages(
|
||||
@@ -228,17 +216,10 @@ impl<'a> NFOSerializer<'a> {
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("plot")
|
||||
.write_text_content_async(BytesText::new(&format!(
|
||||
r#"![CDATA[{}]]"#,
|
||||
&v.intro
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("outline")
|
||||
.write_empty_async()
|
||||
.write_text_content_async(BytesText::new(&format!(r#"![CDATA[{}]]"#, &v.intro)))
|
||||
.await
|
||||
.unwrap();
|
||||
writer.create_element("outline").write_empty_async().await.unwrap();
|
||||
writer
|
||||
.create_element("title")
|
||||
.write_text_content_async(BytesText::new(&v.name))
|
||||
@@ -249,9 +230,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("name")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.upper_id.to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.upper_id.to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
@@ -265,9 +244,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("year")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.pubtime.format("%Y").to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.pubtime.format("%Y").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
if let Some(tags) = &v.tags {
|
||||
@@ -288,9 +265,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("aired")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.pubtime.format("%Y-%m-%d").to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.pubtime.format("%Y-%m-%d").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(writer)
|
||||
@@ -304,17 +279,10 @@ impl<'a> NFOSerializer<'a> {
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("plot")
|
||||
.write_text_content_async(BytesText::new(&format!(
|
||||
r#"![CDATA[{}]]"#,
|
||||
&v.intro
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("outline")
|
||||
.write_empty_async()
|
||||
.write_text_content_async(BytesText::new(&format!(r#"![CDATA[{}]]"#, &v.intro)))
|
||||
.await
|
||||
.unwrap();
|
||||
writer.create_element("outline").write_empty_async().await.unwrap();
|
||||
writer
|
||||
.create_element("title")
|
||||
.write_text_content_async(BytesText::new(&v.name))
|
||||
@@ -325,9 +293,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("name")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.upper_id.to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.upper_id.to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
@@ -341,9 +307,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("year")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.pubtime.format("%Y").to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.pubtime.format("%Y").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
if let Some(tags) = &v.tags {
|
||||
@@ -364,9 +328,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("aired")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.pubtime.format("%Y-%m-%d").to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.pubtime.format("%Y-%m-%d").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(writer)
|
||||
@@ -378,16 +340,8 @@ impl<'a> NFOSerializer<'a> {
|
||||
writer
|
||||
.create_element("person")
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("plot")
|
||||
.write_empty_async()
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("outline")
|
||||
.write_empty_async()
|
||||
.await
|
||||
.unwrap();
|
||||
writer.create_element("plot").write_empty_async().await.unwrap();
|
||||
writer.create_element("outline").write_empty_async().await.unwrap();
|
||||
writer
|
||||
.create_element("lockdata")
|
||||
.write_text_content_async(BytesText::new("false"))
|
||||
@@ -395,9 +349,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("dateadded")
|
||||
.write_text_content_async(BytesText::new(
|
||||
&v.pubtime.format("%Y-%m-%d").to_string(),
|
||||
))
|
||||
.write_text_content_async(BytesText::new(&v.pubtime.format("%Y-%m-%d").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
@@ -419,16 +371,8 @@ impl<'a> NFOSerializer<'a> {
|
||||
writer
|
||||
.create_element("episodedetails")
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
writer
|
||||
.create_element("plot")
|
||||
.write_empty_async()
|
||||
.await
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("outline")
|
||||
.write_empty_async()
|
||||
.await
|
||||
.unwrap();
|
||||
writer.create_element("plot").write_empty_async().await.unwrap();
|
||||
writer.create_element("outline").write_empty_async().await.unwrap();
|
||||
writer
|
||||
.create_element("title")
|
||||
.write_text_content_async(BytesText::new(&p.name))
|
||||
|
||||
@@ -24,24 +24,14 @@ impl Downloader {
|
||||
fs::create_dir_all(parent).await?;
|
||||
}
|
||||
let mut file = File::create(path).await?;
|
||||
let mut res = self
|
||||
.client
|
||||
.request(Method::GET, url, None)
|
||||
.send()
|
||||
.await?
|
||||
.bytes_stream();
|
||||
let mut res = self.client.request(Method::GET, url, None).send().await?.bytes_stream();
|
||||
while let Some(item) = res.next().await {
|
||||
io::copy(&mut item?.as_ref(), &mut file).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn merge(
|
||||
&self,
|
||||
video_path: &Path,
|
||||
audio_path: &Path,
|
||||
output_path: &Path,
|
||||
) -> Result<()> {
|
||||
pub async fn merge(&self, video_path: &Path, audio_path: &Path, output_path: &Path) -> Result<()> {
|
||||
let output = tokio::process::Command::new("ffmpeg")
|
||||
.args([
|
||||
"-i",
|
||||
|
||||
Reference in New Issue
Block a user