mirror of
https://github.com/crunchy-labs/crunchy-cli.git
synced 2026-01-21 04:02:00 -06:00
Add option to select seasons when season number is duplicated (#199)
This commit is contained in:
parent
d75c04fbb6
commit
fc44b8af8a
10 changed files with 227 additions and 52 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
|
@ -355,6 +355,7 @@ dependencies = [
|
||||||
"crunchyroll-rs",
|
"crunchyroll-rs",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"derive_setters",
|
"derive_setters",
|
||||||
|
"dialoguer",
|
||||||
"dirs",
|
"dirs",
|
||||||
"fs2",
|
"fs2",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
|
|
@ -370,7 +371,6 @@ dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"terminal_size",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -501,6 +501,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dialoguer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"shell-words",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "5.0.1"
|
version = "5.0.1"
|
||||||
|
|
@ -1539,6 +1549,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shell-words"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -1628,16 +1644,6 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "terminal_size"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
|
|
||||||
dependencies = [
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ clap = { version = "4.3", features = ["derive", "string"] }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
crunchyroll-rs = { version = "0.3.6", features = ["dash-stream"] }
|
crunchyroll-rs = { version = "0.3.6", features = ["dash-stream"] }
|
||||||
ctrlc = "3.4"
|
ctrlc = "3.4"
|
||||||
|
dialoguer = { version = "0.10", default-features = false }
|
||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
derive_setters = "0.1"
|
derive_setters = "0.1"
|
||||||
fs2 = "0.4"
|
fs2 = "0.4"
|
||||||
|
|
@ -26,7 +27,6 @@ serde_json = "1.0"
|
||||||
serde_plain = "1.0"
|
serde_plain = "1.0"
|
||||||
shlex = "1.1"
|
shlex = "1.1"
|
||||||
tempfile = "3.6"
|
tempfile = "3.6"
|
||||||
terminal_size = "0.2"
|
|
||||||
tokio = { version = "1.28", features = ["macros", "rt-multi-thread", "time"] }
|
tokio = { version = "1.28", features = ["macros", "rt-multi-thread", "time"] }
|
||||||
sys-locale = "0.3"
|
sys-locale = "0.3"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,10 @@ pub struct Archive {
|
||||||
#[arg(long, default_value_t = false)]
|
#[arg(long, default_value_t = false)]
|
||||||
pub(crate) skip_existing: bool,
|
pub(crate) skip_existing: bool,
|
||||||
|
|
||||||
|
#[arg(help = "Skip any interactive input")]
|
||||||
|
#[arg(short, long, default_value_t = false)]
|
||||||
|
pub(crate) yes: bool,
|
||||||
|
|
||||||
#[arg(help = "Crunchyroll series url(s)")]
|
#[arg(help = "Crunchyroll series url(s)")]
|
||||||
pub(crate) urls: Vec<String>,
|
pub(crate) urls: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +153,7 @@ impl Execute for Archive {
|
||||||
|
|
||||||
for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() {
|
for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() {
|
||||||
let progress_handler = progress!("Fetching series details");
|
let progress_handler = progress!("Fetching series details");
|
||||||
let single_format_collection = ArchiveFilter::new(url_filter, self.clone())
|
let single_format_collection = ArchiveFilter::new(url_filter, self.clone(), !self.yes)
|
||||||
.visit(media_collection)
|
.visit(media_collection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::archive::command::Archive;
|
use crate::archive::command::Archive;
|
||||||
use crate::utils::filter::{real_dedup_vec, Filter};
|
use crate::utils::filter::{real_dedup_vec, Filter};
|
||||||
use crate::utils::format::{Format, SingleFormat, SingleFormatCollection};
|
use crate::utils::format::{Format, SingleFormat, SingleFormatCollection};
|
||||||
|
use crate::utils::interactive_select::{check_for_duplicated_seasons, get_duplicated_seasons};
|
||||||
use crate::utils::parse::UrlFilter;
|
use crate::utils::parse::UrlFilter;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crunchyroll_rs::{Concert, Episode, Locale, Movie, MovieListing, MusicVideo, Season, Series};
|
use crunchyroll_rs::{Concert, Episode, Locale, Movie, MovieListing, MusicVideo, Season, Series};
|
||||||
use log::warn;
|
use log::{info, warn};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
enum Visited {
|
enum Visited {
|
||||||
|
|
@ -16,6 +17,7 @@ enum Visited {
|
||||||
pub(crate) struct ArchiveFilter {
|
pub(crate) struct ArchiveFilter {
|
||||||
url_filter: UrlFilter,
|
url_filter: UrlFilter,
|
||||||
archive: Archive,
|
archive: Archive,
|
||||||
|
interactive_input: bool,
|
||||||
season_episode_count: HashMap<u32, Vec<String>>,
|
season_episode_count: HashMap<u32, Vec<String>>,
|
||||||
season_subtitles_missing: Vec<u32>,
|
season_subtitles_missing: Vec<u32>,
|
||||||
season_sorting: Vec<String>,
|
season_sorting: Vec<String>,
|
||||||
|
|
@ -23,10 +25,11 @@ pub(crate) struct ArchiveFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArchiveFilter {
|
impl ArchiveFilter {
|
||||||
pub(crate) fn new(url_filter: UrlFilter, archive: Archive) -> Self {
|
pub(crate) fn new(url_filter: UrlFilter, archive: Archive, interactive_input: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url_filter,
|
url_filter,
|
||||||
archive,
|
archive,
|
||||||
|
interactive_input,
|
||||||
season_episode_count: HashMap::new(),
|
season_episode_count: HashMap::new(),
|
||||||
season_subtitles_missing: vec![],
|
season_subtitles_missing: vec![],
|
||||||
season_sorting: vec![],
|
season_sorting: vec![],
|
||||||
|
|
@ -71,7 +74,44 @@ impl Filter for ArchiveFilter {
|
||||||
}
|
}
|
||||||
self.visited = Visited::Series
|
self.visited = Visited::Series
|
||||||
}
|
}
|
||||||
Ok(series.seasons().await?)
|
|
||||||
|
let mut seasons = series.seasons().await?;
|
||||||
|
let mut remove_ids = vec![];
|
||||||
|
for season in seasons.iter_mut() {
|
||||||
|
if !self.url_filter.is_season_valid(season.season_number)
|
||||||
|
&& !season
|
||||||
|
.audio_locales
|
||||||
|
.iter()
|
||||||
|
.any(|l| self.archive.audio.contains(l))
|
||||||
|
&& !season
|
||||||
|
.available_versions()
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.any(|l| self.archive.audio.contains(l))
|
||||||
|
{
|
||||||
|
remove_ids.push(season.id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seasons.retain(|s| !remove_ids.contains(&s.id));
|
||||||
|
|
||||||
|
let duplicated_seasons = get_duplicated_seasons(&seasons);
|
||||||
|
if duplicated_seasons.len() > 0 {
|
||||||
|
if self.interactive_input {
|
||||||
|
check_for_duplicated_seasons(&mut seasons);
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"Found duplicated seasons: {}",
|
||||||
|
duplicated_seasons
|
||||||
|
.iter()
|
||||||
|
.map(|d| d.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(seasons)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn visit_season(&mut self, mut season: Season) -> Result<Vec<Episode>> {
|
async fn visit_season(&mut self, mut season: Season) -> Result<Vec<Episode>> {
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,10 @@ pub struct Download {
|
||||||
#[arg(long, default_value_t = false)]
|
#[arg(long, default_value_t = false)]
|
||||||
pub(crate) skip_existing: bool,
|
pub(crate) skip_existing: bool,
|
||||||
|
|
||||||
|
#[arg(help = "Skip any interactive input")]
|
||||||
|
#[arg(short, long, default_value_t = false)]
|
||||||
|
pub(crate) yes: bool,
|
||||||
|
|
||||||
#[arg(help = "Url(s) to Crunchyroll episodes or series")]
|
#[arg(help = "Url(s) to Crunchyroll episodes or series")]
|
||||||
pub(crate) urls: Vec<String>,
|
pub(crate) urls: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +123,7 @@ impl Execute for Download {
|
||||||
|
|
||||||
for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() {
|
for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() {
|
||||||
let progress_handler = progress!("Fetching series details");
|
let progress_handler = progress!("Fetching series details");
|
||||||
let single_format_collection = DownloadFilter::new(url_filter, self.clone())
|
let single_format_collection = DownloadFilter::new(url_filter, self.clone(), !self.yes)
|
||||||
.visit(media_collection)
|
.visit(media_collection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,27 @@
|
||||||
use crate::download::Download;
|
use crate::download::Download;
|
||||||
use crate::utils::filter::Filter;
|
use crate::utils::filter::Filter;
|
||||||
use crate::utils::format::{Format, SingleFormat, SingleFormatCollection};
|
use crate::utils::format::{Format, SingleFormat, SingleFormatCollection};
|
||||||
|
use crate::utils::interactive_select::{check_for_duplicated_seasons, get_duplicated_seasons};
|
||||||
use crate::utils::parse::UrlFilter;
|
use crate::utils::parse::UrlFilter;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use crunchyroll_rs::{Concert, Episode, Movie, MovieListing, MusicVideo, Season, Series};
|
use crunchyroll_rs::{Concert, Episode, Movie, MovieListing, MusicVideo, Season, Series};
|
||||||
use log::{error, warn};
|
use log::{error, info, warn};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub(crate) struct DownloadFilter {
|
pub(crate) struct DownloadFilter {
|
||||||
url_filter: UrlFilter,
|
url_filter: UrlFilter,
|
||||||
download: Download,
|
download: Download,
|
||||||
|
interactive_input: bool,
|
||||||
season_episode_count: HashMap<u32, Vec<String>>,
|
season_episode_count: HashMap<u32, Vec<String>>,
|
||||||
season_subtitles_missing: Vec<u32>,
|
season_subtitles_missing: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DownloadFilter {
|
impl DownloadFilter {
|
||||||
pub(crate) fn new(url_filter: UrlFilter, download: Download) -> Self {
|
pub(crate) fn new(url_filter: UrlFilter, download: Download, interactive_input: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url_filter,
|
url_filter,
|
||||||
download,
|
download,
|
||||||
|
interactive_input,
|
||||||
season_episode_count: HashMap::new(),
|
season_episode_count: HashMap::new(),
|
||||||
season_subtitles_missing: vec![],
|
season_subtitles_missing: vec![],
|
||||||
}
|
}
|
||||||
|
|
@ -43,42 +46,61 @@ impl Filter for DownloadFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seasons = series.seasons().await?;
|
let mut seasons = vec![];
|
||||||
|
for mut season in series.seasons().await? {
|
||||||
|
if !self.url_filter.is_season_valid(season.season_number) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !season
|
||||||
|
.audio_locales
|
||||||
|
.iter()
|
||||||
|
.any(|l| l == &self.download.audio)
|
||||||
|
{
|
||||||
|
if season
|
||||||
|
.available_versions()
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.any(|l| l == &self.download.audio)
|
||||||
|
{
|
||||||
|
season = season
|
||||||
|
.version(vec![self.download.audio.clone()])
|
||||||
|
.await?
|
||||||
|
.remove(0)
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Season {} - '{}' is not available with {} audio",
|
||||||
|
season.season_number,
|
||||||
|
season.title,
|
||||||
|
self.download.audio.clone(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seasons.push(season)
|
||||||
|
}
|
||||||
|
|
||||||
|
let duplicated_seasons = get_duplicated_seasons(&seasons);
|
||||||
|
if duplicated_seasons.len() > 0 {
|
||||||
|
if self.interactive_input {
|
||||||
|
check_for_duplicated_seasons(&mut seasons);
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"Found duplicated seasons: {}",
|
||||||
|
duplicated_seasons
|
||||||
|
.iter()
|
||||||
|
.map(|d| d.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(seasons)
|
Ok(seasons)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn visit_season(&mut self, mut season: Season) -> Result<Vec<Episode>> {
|
async fn visit_season(&mut self, season: Season) -> Result<Vec<Episode>> {
|
||||||
if !self.url_filter.is_season_valid(season.season_number) {
|
|
||||||
return Ok(vec![]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !season
|
|
||||||
.audio_locales
|
|
||||||
.iter()
|
|
||||||
.any(|l| l == &self.download.audio)
|
|
||||||
{
|
|
||||||
if season
|
|
||||||
.available_versions()
|
|
||||||
.await?
|
|
||||||
.iter()
|
|
||||||
.any(|l| l == &self.download.audio)
|
|
||||||
{
|
|
||||||
season = season
|
|
||||||
.version(vec![self.download.audio.clone()])
|
|
||||||
.await?
|
|
||||||
.remove(0)
|
|
||||||
} else {
|
|
||||||
error!(
|
|
||||||
"Season {} - '{}' is not available with {} audio",
|
|
||||||
season.season_number,
|
|
||||||
season.title,
|
|
||||||
self.download.audio.clone(),
|
|
||||||
);
|
|
||||||
return Ok(vec![]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut episodes = season.episodes().await?;
|
let mut episodes = season.episodes().await?;
|
||||||
|
|
||||||
if Format::has_relative_episodes_fmt(&self.download.output) {
|
if Format::has_relative_episodes_fmt(&self.download.output) {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ mod search;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use archive::Archive;
|
pub use archive::Archive;
|
||||||
|
use dialoguer::console::Term;
|
||||||
pub use download::Download;
|
pub use download::Download;
|
||||||
pub use login::Login;
|
pub use login::Login;
|
||||||
pub use search::Search;
|
pub use search::Search;
|
||||||
|
|
@ -168,6 +169,9 @@ pub async fn cli_entrypoint() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// when pressing ctrl-c while interactively choosing seasons the cursor stays hidden, this
|
||||||
|
// line shows it again
|
||||||
|
let _ = Term::stdout().show_cursor();
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
||||||
73
crunchy-cli-core/src/utils/interactive_select.rs
Normal file
73
crunchy-cli-core/src/utils/interactive_select.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
use crate::utils::log::progress_pause;
|
||||||
|
use crunchyroll_rs::Season;
|
||||||
|
use dialoguer::console::Term;
|
||||||
|
use dialoguer::MultiSelect;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
pub fn get_duplicated_seasons(seasons: &Vec<Season>) -> Vec<u32> {
|
||||||
|
let mut season_number_counter = BTreeMap::<u32, u32>::new();
|
||||||
|
for season in seasons {
|
||||||
|
season_number_counter
|
||||||
|
.entry(season.season_number)
|
||||||
|
.and_modify(|c| *c += 1)
|
||||||
|
.or_default();
|
||||||
|
}
|
||||||
|
season_number_counter
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(k, v)| if v > 0 { Some(k) } else { None })
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_for_duplicated_seasons(seasons: &mut Vec<Season>) {
|
||||||
|
let mut as_map = BTreeMap::new();
|
||||||
|
for season in seasons.iter() {
|
||||||
|
as_map
|
||||||
|
.entry(season.season_number)
|
||||||
|
.or_insert(vec![])
|
||||||
|
.push(season)
|
||||||
|
}
|
||||||
|
|
||||||
|
let duplicates: Vec<&Season> = as_map
|
||||||
|
.into_values()
|
||||||
|
.filter(|s| s.len() > 1)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
progress_pause!();
|
||||||
|
let _ = Term::stdout().clear_line();
|
||||||
|
let keep = select(
|
||||||
|
"Duplicated seasons were found. Select the one you want to download (space to select/deselect; enter to continue)",
|
||||||
|
duplicates
|
||||||
|
.iter()
|
||||||
|
.map(|s| format!("Season {} ({})", s.season_number, s.title))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
progress_pause!();
|
||||||
|
|
||||||
|
let mut remove_ids = vec![];
|
||||||
|
for (i, duplicate) in duplicates.into_iter().enumerate() {
|
||||||
|
if !keep.contains(&i) {
|
||||||
|
remove_ids.push(duplicate.id.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seasons.retain(|s| !remove_ids.contains(&s.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select(prompt: &str, input: Vec<String>) -> Vec<usize> {
|
||||||
|
if input.is_empty() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let def: Vec<bool> = (0..input.len()).map(|_| true).collect();
|
||||||
|
|
||||||
|
let selection = MultiSelect::new()
|
||||||
|
.with_prompt(prompt)
|
||||||
|
.items(&input[..])
|
||||||
|
.defaults(&def[..])
|
||||||
|
.clear(false)
|
||||||
|
.report(false)
|
||||||
|
.interact_on(&Term::stdout())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
selection
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||||
use log::{
|
use log::{
|
||||||
info, set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record,
|
info, set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record,
|
||||||
SetLoggerError,
|
SetLoggerError,
|
||||||
|
|
@ -37,6 +37,15 @@ macro_rules! progress {
|
||||||
}
|
}
|
||||||
pub(crate) use progress;
|
pub(crate) use progress;
|
||||||
|
|
||||||
|
macro_rules! progress_pause {
|
||||||
|
() => {
|
||||||
|
{
|
||||||
|
log::info!(target: "progress_pause", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) use progress_pause;
|
||||||
|
|
||||||
macro_rules! tab_info {
|
macro_rules! tab_info {
|
||||||
($($arg:tt)+) => {
|
($($arg:tt)+) => {
|
||||||
if log::max_level() == log::LevelFilter::Debug {
|
if log::max_level() == log::LevelFilter::Debug {
|
||||||
|
|
@ -62,6 +71,7 @@ impl Log for CliLogger {
|
||||||
fn log(&self, record: &Record) {
|
fn log(&self, record: &Record) {
|
||||||
if !self.enabled(record.metadata())
|
if !self.enabled(record.metadata())
|
||||||
|| (record.target() != "progress"
|
|| (record.target() != "progress"
|
||||||
|
&& record.target() != "progress_pause"
|
||||||
&& record.target() != "progress_end"
|
&& record.target() != "progress_end"
|
||||||
&& !record.target().starts_with("crunchy_cli"))
|
&& !record.target().starts_with("crunchy_cli"))
|
||||||
{
|
{
|
||||||
|
|
@ -75,6 +85,16 @@ impl Log for CliLogger {
|
||||||
|
|
||||||
match record.target() {
|
match record.target() {
|
||||||
"progress" => self.progress(record, false),
|
"progress" => self.progress(record, false),
|
||||||
|
"progress_pause" => {
|
||||||
|
let progress = self.progress.lock().unwrap();
|
||||||
|
if let Some(p) = &*progress {
|
||||||
|
p.set_draw_target(if p.is_hidden() {
|
||||||
|
ProgressDrawTarget::stdout()
|
||||||
|
} else {
|
||||||
|
ProgressDrawTarget::hidden()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
"progress_end" => self.progress(record, true),
|
"progress_end" => self.progress(record, true),
|
||||||
_ => {
|
_ => {
|
||||||
if self.progress.lock().unwrap().is_some() {
|
if self.progress.lock().unwrap().is_some() {
|
||||||
|
|
@ -158,6 +178,7 @@ impl CliLogger {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.tick_strings(&["—", "\\", "|", "/", finish_str]),
|
.tick_strings(&["—", "\\", "|", "/", finish_str]),
|
||||||
);
|
);
|
||||||
|
pb.set_draw_target(ProgressDrawTarget::stdout());
|
||||||
pb.enable_steady_tick(Duration::from_millis(200));
|
pb.enable_steady_tick(Duration::from_millis(200));
|
||||||
pb.set_message(msg);
|
pb.set_message(msg);
|
||||||
*progress = Some(pb)
|
*progress = Some(pb)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod download;
|
||||||
pub mod ffmpeg;
|
pub mod ffmpeg;
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
pub mod interactive_select;
|
||||||
pub mod locale;
|
pub mod locale;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue