feat: print error message

This commit is contained in:
ThetaDev 2024-08-10 01:46:18 +02:00
parent 9da3b25be2
commit 8f16e5ba6e
No known key found for this signature in database
GPG key ID: E319D3C5148D65B6

View file

@ -1,7 +1,12 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(clippy::todo, clippy::dbg_macro)] #![warn(clippy::todo, clippy::dbg_macro)]
use std::{path::PathBuf, str::FromStr, time::Duration}; use std::{
path::PathBuf,
str::FromStr,
sync::{atomic::AtomicUsize, Arc},
time::Duration,
};
use clap::{Parser, Subcommand, ValueEnum}; use clap::{Parser, Subcommand, ValueEnum};
use futures::stream::{self, StreamExt}; use futures::stream::{self, StreamExt};
@ -177,6 +182,7 @@ enum Commands {
#[clap(long)] #[clap(long)]
music: Option<MusicSearchCategory>, music: Option<MusicSearchCategory>,
}, },
/// Get a YouTube visitor data cookie
Vdata, Vdata,
} }
@ -437,7 +443,7 @@ async fn download_videos(
parallel: usize, parallel: usize,
client_type: Option<PlayerType>, client_type: Option<PlayerType>,
multi: MultiProgress, multi: MultiProgress,
) { ) -> anyhow::Result<()> {
// Indicatif setup // Indicatif setup
let main = multi.add(ProgressBar::new( let main = multi.add(ProgressBar::new(
videos.len().try_into().unwrap_or_default(), videos.len().try_into().unwrap_or_default(),
@ -451,11 +457,14 @@ async fn download_videos(
); );
main.tick(); main.tick();
let n_failed = Arc::new(AtomicUsize::default());
stream::iter(videos) stream::iter(videos)
.for_each_concurrent(parallel, |video| { .for_each_concurrent(parallel, |video| {
let dl = dl.clone(); let dl = dl.clone();
let main = main.clone(); let main = main.clone();
let id = video.id().to_owned(); let id = video.id().to_owned();
let n_failed = n_failed.clone();
let mut q = target.apply(dl.video(video)); let mut q = target.apply(dl.video(video));
if let Some(client_type) = client_type { if let Some(client_type) = client_type {
@ -466,12 +475,20 @@ async fn download_videos(
if let Err(e) = q.download().await { if let Err(e) = q.download().await {
if !matches!(e, DownloadError::Exists(_)) { if !matches!(e, DownloadError::Exists(_)) {
tracing::error!("[{id}]: {e}"); tracing::error!("[{id}]: {e}");
n_failed.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
} }
} else {
main.inc(1);
} }
main.inc(1);
} }
}) })
.await; .await;
let n_failed = n_failed.load(std::sync::atomic::Ordering::Relaxed);
if n_failed > 0 {
anyhow::bail!("{n_failed} downloads failed");
}
Ok(())
} }
/// Stderr writer that suspends the progress bars before printing logs /// Stderr writer that suspends the progress bars before printing logs
@ -498,6 +515,14 @@ impl std::io::Write for ProgWriter {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
if let Err(e) = run().await {
println!("{}", "Error:".red().bold());
println!("{}", e);
std::process::exit(1);
}
}
async fn run() -> anyhow::Result<()> {
let cli = Cli::parse(); let cli = Cli::parse();
let multi = MultiProgress::new(); let multi = MultiProgress::new();
@ -527,7 +552,7 @@ async fn main() {
if let Some(country) = cli.country { if let Some(country) = cli.country {
rp = rp.country(Country::from_str(&country.to_ascii_uppercase()).expect("invalid country")); rp = rp.country(Country::from_str(&country.to_ascii_uppercase()).expect("invalid country"));
} }
let rp = rp.build().unwrap(); let rp = rp.build()?;
match cli.command { match cli.command {
Commands::Download { Commands::Download {
@ -541,7 +566,7 @@ async fn main() {
client_type, client_type,
pot, pot,
} => { } => {
let url_target = rp.query().resolve_string(&id, false).await.unwrap(); let url_target = rp.query().resolve_string(&id, false).await?;
let mut filter = StreamFilter::new(); let mut filter = StreamFilter::new();
if let Some(res) = resolution { if let Some(res) = resolution {
@ -570,12 +595,8 @@ async fn main() {
} }
UrlTarget::Channel { id } => { UrlTarget::Channel { id } => {
target.assert_dir(); target.assert_dir();
let mut channel = rp.query().channel_videos(id).await.unwrap(); let mut channel = rp.query().channel_videos(id).await?;
channel channel.content.extend_limit(&rp.query(), limit).await?;
.content
.extend_limit(&rp.query(), limit)
.await
.unwrap();
let videos = channel let videos = channel
.content .content
.items .items
@ -583,17 +604,13 @@ async fn main() {
.take(limit) .take(limit)
.map(|v| DownloadVideo::from_entity(&v)) .map(|v| DownloadVideo::from_entity(&v))
.collect(); .collect();
download_videos(&dl, videos, &target, parallel, client_type, multi).await; download_videos(&dl, videos, &target, parallel, client_type, multi).await?;
} }
UrlTarget::Playlist { id } => { UrlTarget::Playlist { id } => {
target.assert_dir(); target.assert_dir();
let videos = if music { let videos = if music {
let mut playlist = rp.query().music_playlist(id).await.unwrap(); let mut playlist = rp.query().music_playlist(id).await?;
playlist playlist.tracks.extend_limit(&rp.query(), limit).await?;
.tracks
.extend_limit(&rp.query(), limit)
.await
.unwrap();
playlist playlist
.tracks .tracks
.items .items
@ -602,12 +619,8 @@ async fn main() {
.map(|v| DownloadVideo::from_track(&v)) .map(|v| DownloadVideo::from_track(&v))
.collect() .collect()
} else { } else {
let mut playlist = rp.query().playlist(id).await.unwrap(); let mut playlist = rp.query().playlist(id).await?;
playlist playlist.videos.extend_limit(&rp.query(), limit).await?;
.videos
.extend_limit(&rp.query(), limit)
.await
.unwrap();
playlist playlist
.videos .videos
.items .items
@ -616,18 +629,18 @@ async fn main() {
.map(|v| DownloadVideo::from_entity(&v)) .map(|v| DownloadVideo::from_entity(&v))
.collect() .collect()
}; };
download_videos(&dl, videos, &target, parallel, client_type, multi).await; download_videos(&dl, videos, &target, parallel, client_type, multi).await?;
} }
UrlTarget::Album { id } => { UrlTarget::Album { id } => {
target.assert_dir(); target.assert_dir();
let album = rp.query().music_album(id).await.unwrap(); let album = rp.query().music_album(id).await?;
let videos = album let videos = album
.tracks .tracks
.into_iter() .into_iter()
.take(limit) .take(limit)
.map(|v| DownloadVideo::from_track(&v)) .map(|v| DownloadVideo::from_track(&v))
.collect(); .collect();
download_videos(&dl, videos, &target, parallel, client_type, multi).await; download_videos(&dl, videos, &target, parallel, client_type, multi).await?;
} }
} }
} }
@ -644,15 +657,15 @@ async fn main() {
player, player,
client_type, client_type,
} => { } => {
let target = rp.query().resolve_string(&id, false).await.unwrap(); let target = rp.query().resolve_string(&id, false).await?;
match target { match target {
UrlTarget::Video { id, .. } => { UrlTarget::Video { id, .. } => {
if lyrics { if lyrics {
let details = rp.query().music_details(&id).await.unwrap(); let details = rp.query().music_details(&id).await?;
match details.lyrics_id { match details.lyrics_id {
Some(lyrics_id) => { Some(lyrics_id) => {
let lyrics = rp.query().music_lyrics(lyrics_id).await.unwrap(); let lyrics = rp.query().music_lyrics(lyrics_id).await?;
if txt { if txt {
println!("{}\n\n{}", lyrics.body, lyrics.footer); println!("{}\n\n{}", lyrics.body, lyrics.footer);
} else { } else {
@ -662,7 +675,7 @@ async fn main() {
None => eprintln!("no lyrics found"), None => eprintln!("no lyrics found"),
} }
} else if music { } else if music {
let details = rp.query().music_details(&id).await.unwrap(); let details = rp.query().music_details(&id).await?;
if txt { if txt {
if details.track.is_video { if details.track.is_video {
println!("[MV]"); println!("[MV]");
@ -696,26 +709,20 @@ async fn main() {
rp.query().player_from_client(&id, client_type.into()).await rp.query().player_from_client(&id, client_type.into()).await
} else { } else {
rp.query().player(&id).await rp.query().player(&id).await
} }?;
.unwrap();
print_data(&player, format, pretty); print_data(&player, format, pretty);
} else { } else {
let mut details = rp.query().video_details(&id).await.unwrap(); let mut details = rp.query().video_details(&id).await?;
match comments { match comments {
Some(CommentsOrder::Top) => { Some(CommentsOrder::Top) => {
details details.top_comments.extend_limit(rp.query(), limit).await?;
.top_comments
.extend_limit(rp.query(), limit)
.await
.unwrap();
} }
Some(CommentsOrder::Latest) => { Some(CommentsOrder::Latest) => {
details details
.latest_comments .latest_comments
.extend_limit(rp.query(), limit) .extend_limit(rp.query(), limit)
.await .await?;
.unwrap();
} }
None => {} None => {}
} }
@ -793,7 +800,7 @@ async fn main() {
} }
UrlTarget::Channel { id } => { UrlTarget::Channel { id } => {
if music { if music {
let artist = rp.query().music_artist(&id, true).await.unwrap(); let artist = rp.query().music_artist(&id, true).await?;
if txt { if txt {
anstream::println!( anstream::println!(
"{}\n{} [{}]", "{}\n{} [{}]",
@ -853,13 +860,9 @@ async fn main() {
_ => unreachable!(), _ => unreachable!(),
}; };
let mut channel = let mut channel =
rp.query().channel_videos_tab(&id, video_tab).await.unwrap(); rp.query().channel_videos_tab(&id, video_tab).await?;
channel channel.content.extend_limit(rp.query(), limit).await?;
.content
.extend_limit(rp.query(), limit)
.await
.unwrap();
if txt { if txt {
anstream::print!( anstream::print!(
@ -881,7 +884,7 @@ async fn main() {
} }
} }
ChannelTab::Playlists => { ChannelTab::Playlists => {
let channel = rp.query().channel_playlists(&id).await.unwrap(); let channel = rp.query().channel_playlists(&id).await?;
if txt { if txt {
anstream::println!( anstream::println!(
@ -901,7 +904,7 @@ async fn main() {
} }
} }
ChannelTab::Info => { ChannelTab::Info => {
let info = rp.query().channel_info(&id).await.unwrap(); let info = rp.query().channel_info(&id).await?;
if txt { if txt {
anstream::println!( anstream::println!(
@ -937,12 +940,8 @@ async fn main() {
} }
UrlTarget::Playlist { id } => { UrlTarget::Playlist { id } => {
if music { if music {
let mut playlist = rp.query().music_playlist(&id).await.unwrap(); let mut playlist = rp.query().music_playlist(&id).await?;
playlist playlist.tracks.extend_limit(rp.query(), limit).await?;
.tracks
.extend_limit(rp.query(), limit)
.await
.unwrap();
if txt { if txt {
anstream::println!( anstream::println!(
"{}\n{} [{}]\n{} {}", "{}\n{} [{}]\n{} {}",
@ -966,12 +965,8 @@ async fn main() {
print_data(&playlist, format, pretty); print_data(&playlist, format, pretty);
} }
} else { } else {
let mut playlist = rp.query().playlist(&id).await.unwrap(); let mut playlist = rp.query().playlist(&id).await?;
playlist playlist.videos.extend_limit(rp.query(), limit).await?;
.videos
.extend_limit(rp.query(), limit)
.await
.unwrap();
if txt { if txt {
anstream::println!( anstream::println!(
"{}\n{} [{}]\n{} {}", "{}\n{} [{}]\n{} {}",
@ -1000,7 +995,7 @@ async fn main() {
} }
} }
UrlTarget::Album { id } => { UrlTarget::Album { id } => {
let album = rp.query().music_album(&id).await.unwrap(); let album = rp.query().music_album(&id).await?;
if txt { if txt {
anstream::print!( anstream::print!(
"{}\n{} [{}] ({:?}", "{}\n{} [{}] ({:?}",
@ -1043,8 +1038,8 @@ async fn main() {
} => match music { } => match music {
None => match channel { None => match channel {
Some(channel) => { Some(channel) => {
rustypipe::validate::channel_id(&channel).unwrap(); rustypipe::validate::channel_id(&channel)?;
let res = rp.query().channel_search(&channel, &query).await.unwrap(); let res = rp.query().channel_search(&channel, &query).await?;
print_data(&res, format, pretty); print_data(&res, format, pretty);
} }
None => { None => {
@ -1056,9 +1051,8 @@ async fn main() {
let mut res = rp let mut res = rp
.query() .query()
.search_filter::<YouTubeItem, _>(&query, &filter) .search_filter::<YouTubeItem, _>(&query, &filter)
.await .await?;
.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap();
if txt { if txt {
if let Some(corr) = res.corrected_query { if let Some(corr) = res.corrected_query {
@ -1071,27 +1065,27 @@ async fn main() {
} }
}, },
Some(MusicSearchCategory::All) => { Some(MusicSearchCategory::All) => {
let res = rp.query().music_search_main(&query).await.unwrap(); let res = rp.query().music_search_main(&query).await?;
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
Some(MusicSearchCategory::Tracks) => { Some(MusicSearchCategory::Tracks) => {
let mut res = rp.query().music_search_tracks(&query).await.unwrap(); let mut res = rp.query().music_search_tracks(&query).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
Some(MusicSearchCategory::Videos) => { Some(MusicSearchCategory::Videos) => {
let mut res = rp.query().music_search_videos(&query).await.unwrap(); let mut res = rp.query().music_search_videos(&query).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
Some(MusicSearchCategory::Artists) => { Some(MusicSearchCategory::Artists) => {
let mut res = rp.query().music_search_artists(&query).await.unwrap(); let mut res = rp.query().music_search_artists(&query).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
Some(MusicSearchCategory::Albums) => { Some(MusicSearchCategory::Albums) => {
let mut res = rp.query().music_search_albums(&query).await.unwrap(); let mut res = rp.query().music_search_albums(&query).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
Some(MusicSearchCategory::PlaylistsYtm | MusicSearchCategory::PlaylistsCommunity) => { Some(MusicSearchCategory::PlaylistsYtm | MusicSearchCategory::PlaylistsCommunity) => {
@ -1101,15 +1095,15 @@ async fn main() {
&query, &query,
music == Some(MusicSearchCategory::PlaylistsCommunity), music == Some(MusicSearchCategory::PlaylistsCommunity),
) )
.await .await?;
.unwrap(); res.items.extend_limit(rp.query(), limit).await?;
res.items.extend_limit(rp.query(), limit).await.unwrap();
print_music_search(&res, format, pretty, txt); print_music_search(&res, format, pretty, txt);
} }
}, },
Commands::Vdata => { Commands::Vdata => {
let vd = rp.query().get_visitor_data().await.unwrap(); let vd = rp.query().get_visitor_data().await?;
println!("{vd}"); println!("{vd}");
} }
}; };
Ok(())
} }