diff --git a/.rustfmt.toml b/.rustfmt.toml index 64d94de..9eb3c3b 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,2 +1,3 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" +max_width = 120 diff --git a/migration/src/m20240322_000001_create_table.rs b/migration/src/m20240322_000001_create_table.rs index 099aff8..49caf8f 100644 --- a/migration/src/m20240322_000001_create_table.rs +++ b/migration/src/m20240322_000001_create_table.rs @@ -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(()) } } diff --git a/src/bilibili/analyzer.rs b/src/bilibili/analyzer.rs index cb8250e..26b6a22 100644 --- a/src/bilibili/analyzer.rs +++ b/src/bilibili/analyzer.rs @@ -102,10 +102,7 @@ impl Stream { /// 2. 视频、音频分离,作为 VideoAudio 返回,其中音频流可能不存在(对于无声视频,如 BV1J7411H7KQ) #[derive(Debug)] pub enum BestStream { - VideoAudio { - video: Stream, - audio: Option, - }, + VideoAudio { video: Stream, audio: Option }, 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; } diff --git a/src/bilibili/client.rs b/src/bilibili/client.rs index 3e199ea..a7f3e67 100644 --- a/src/bilibili/client.rs +++ b/src/bilibili/client.rs @@ -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 } diff --git a/src/bilibili/credential.rs b/src/bilibili/credential.rs index fee8df6..0993956 100644 --- a/src/bilibili/credential.rs +++ b/src/bilibili/credential.rs @@ -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::() .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::(), &data).unwrap(); @@ -100,10 +89,7 @@ impl Credential { _ => Err("get csrf failed".into()), }; } - regex_find( - r#"
(.+?)
"#, - res.text().await?.as_str(), - ) + regex_find(r#"
(.+?)
"#, res.text().await?.as_str()) } async fn get_new_credential(&self, client: &Client, csrf: &str) -> Result { @@ -134,10 +120,7 @@ impl Credential { }; let required_cookies = HashSet::from(["SESSDATA", "bili_jct", "DedeUserID"]); let cookies: Vec = 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() { diff --git a/src/bilibili/favorite_list.rs b/src/bilibili/favorite_list.rs index fbf47d6..1299ea1 100644 --- a/src/bilibili/favorite_list.rs +++ b/src/bilibili/favorite_list.rs @@ -49,10 +49,7 @@ impl<'a> FavoriteList<'a> { pub async fn get_info(&self) -> Result { 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 { 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()), diff --git a/src/bilibili/mod.rs b/src/bilibili/mod.rs index 798947b..f6294f3 100644 --- a/src/bilibili/mod.rs +++ b/src/bilibili/mod.rs @@ -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}; diff --git a/src/bilibili/video.rs b/src/bilibili/video.rs index 0a919da..370597a 100644 --- a/src/bilibili/video.rs +++ b/src/bilibili/video.rs @@ -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> { 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? diff --git a/src/core/command.rs b/src/core/command.rs index 5e44c1c..d655e7c 100644 --- a/src/core/command.rs +++ b/src/core/command.rs @@ -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(()) diff --git a/src/core/utils.rs b/src/core/utils.rs index 6428daa..7499955 100644 --- a/src/core/utils.rs +++ b/src/core/utils.rs @@ -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 { +pub async fn handle_favorite_info(info: &FavoriteListInfo, connection: &DatabaseConnection) -> Result { 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> { - let bvids = videos_info - .iter() - .map(|v| v.bvid.clone()) - .collect::>(); + let bvids = videos_info.iter().map(|v| v.bvid.clone()).collect::>(); 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> { - let bvids = videos_info - .iter() - .map(|v| v.bvid.clone()) - .collect::>(); + let bvids = videos_info.iter().map(|v| v.bvid.clone()).collect::>(); 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)) diff --git a/src/downloader.rs b/src/downloader.rs index c79fc0f..fee899a 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -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",