From 7c3bbfc1737ecdaf291d25ca817f1d35eccd21e3 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 4 Dec 2022 18:54:19 +0100
Subject: [PATCH 001/395] Wait until buffer is empty when downloading
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 0bf6b45..758636d 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -169,7 +169,7 @@ pub async fn download_segments(
data_pos += 1;
}
- if *count.lock().unwrap() >= total_segments {
+ if *count.lock().unwrap() >= total_segments && buf.is_empty() {
break;
}
}
From 285d27772c10b288022bda19f4b027505f96c284 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 4 Dec 2022 18:54:22 +0100
Subject: [PATCH 002/395] Add manually .ass file editing to fix #32
---
crunchy-cli-core/src/cli/archive.rs | 108 ++++++++++++++++++++++------
1 file changed, 86 insertions(+), 22 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index d4b0a5d..d586725 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -8,6 +8,7 @@ use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
use crate::Execute;
use anyhow::{bail, Result};
+use chrono::{NaiveTime, Timelike};
use crunchyroll_rs::media::{Resolution, StreamSubtitle};
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
use log::{debug, error, info};
@@ -113,7 +114,12 @@ impl Execute for Archive {
fn pre_check(&self) -> Result<()> {
if !has_ffmpeg() {
bail!("FFmpeg is needed to run this command")
- } else if PathBuf::from(&self.output).extension().unwrap_or_default().to_string_lossy() != "mkv" {
+ } else if PathBuf::from(&self.output)
+ .extension()
+ .unwrap_or_default()
+ .to_string_lossy()
+ != "mkv"
+ {
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
@@ -276,9 +282,18 @@ impl Execute for Archive {
}
}
+ let (primary_video, _) = video_paths.get(0).unwrap();
+ let primary_video_length = get_video_length(primary_video.to_path_buf()).unwrap();
for subtitle in subtitles {
- subtitle_paths
- .push((download_subtitle(&self, subtitle.clone()).await?, subtitle))
+ subtitle_paths.push((
+ download_subtitle(
+ &self,
+ subtitle.clone(),
+ primary_video_length
+ )
+ .await?,
+ subtitle,
+ ))
}
generate_mkv(&self, path, video_paths, audio_paths, subtitle_paths)?
@@ -403,15 +418,20 @@ async fn download_video(ctx: &Context, format: &Format, only_audio: bool) -> Res
Ok(path)
}
-async fn download_subtitle(archive: &Archive, subtitle: StreamSubtitle) -> Result {
+async fn download_subtitle(
+ archive: &Archive,
+ subtitle: StreamSubtitle,
+ max_length: NaiveTime,
+) -> Result {
let tempfile = tempfile(".ass")?;
let (mut file, path) = tempfile.into_parts();
let mut buf = vec![];
subtitle.write_to(&mut buf).await?;
if !archive.no_subtitle_optimizations {
- buf = fix_subtitle(buf)
+ buf = fix_subtitle_look_and_feel(buf)
}
+ buf = fix_subtitle_length(buf, max_length);
file.write_all(buf.as_slice())?;
@@ -421,7 +441,7 @@ async fn download_subtitle(archive: &Archive, subtitle: StreamSubtitle) -> Resul
/// Add `ScaledBorderAndShadows: yes` to subtitles; without it they look very messy on some video
/// players. See [crunchy-labs/crunchy-cli#66](https://github.com/crunchy-labs/crunchy-cli/issues/66)
/// for more information.
-fn fix_subtitle(raw: Vec) -> Vec {
+fn fix_subtitle_look_and_feel(raw: Vec) -> Vec {
let mut script_info = false;
let mut new = String::new();
@@ -439,6 +459,62 @@ fn fix_subtitle(raw: Vec) -> Vec {
new.into_bytes()
}
+/// Fix the length of subtitles to a specified maximum amount. This is required because sometimes
+/// subtitles have an unnecessary entry long after the actual video ends with artificially extends
+/// the video length on some video players. To prevent this, the video length must be hard set. See
+/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
+/// information.
+fn fix_subtitle_length(raw: Vec, max_length: NaiveTime) -> Vec {
+ let re =
+ Regex::new(r#"^Dialogue:\s\d+,(?P\d+:\d+:\d+\.\d+),(?P\d+:\d+:\d+\.\d+),"#)
+ .unwrap();
+
+ // chrono panics if we try to format NaiveTime with `%2f` and the nano seconds has more than 2
+ // digits so them have to be reduced manually to avoid the panic
+ fn format_naive_time(native_time: NaiveTime) -> String {
+ let formatted_time = native_time.format("%f").to_string();
+ format!("{}.{}", native_time.format("%T"), if formatted_time.len() <= 2 {
+ native_time.format("%2f").to_string()
+ } else {
+ formatted_time.split_at(2).0.parse().unwrap()
+ })
+ }
+
+ let length_as_string = format_naive_time(max_length);
+ let mut new = String::new();
+
+ for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
+ if let Some(capture) = re.captures(line) {
+ let start = capture.name("start").map_or(NaiveTime::default(), |s| {
+ NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
+ });
+ let end = capture.name("end").map_or(NaiveTime::default(), |s| {
+ NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
+ });
+
+ if start > max_length {
+ continue
+ } else if end > max_length {
+ new.push_str(re.replace(
+ line,
+ format!(
+ "Dialogue: {},{},",
+ format_naive_time(start),
+ &length_as_string
+ ),
+ ).to_string().as_str())
+ } else {
+ new.push_str(line)
+ }
+ } else {
+ new.push_str(line)
+ }
+ new.push('\n')
+ }
+
+ new.into_bytes()
+}
+
fn generate_mkv(
archive: &Archive,
target: PathBuf,
@@ -450,8 +526,6 @@ fn generate_mkv(
let mut maps = vec![];
let mut metadata = vec![];
- let mut video_length = (0, 0, 0, 0);
-
for (i, (video_path, format)) in video_paths.iter().enumerate() {
input.extend(["-i".to_string(), video_path.to_string_lossy().to_string()]);
maps.extend(["-map".to_string(), i.to_string()]);
@@ -471,11 +545,6 @@ fn generate_mkv(
format!("-metadata:s:a:{}", i),
format!("title={}", format.audio.to_human_readable()),
]);
-
- let vid_len = get_video_length(video_path.to_path_buf())?;
- if vid_len > video_length {
- video_length = vid_len
- }
}
for (i, (audio_path, format)) in audio_paths.iter().enumerate() {
input.extend(["-i".to_string(), audio_path.to_string_lossy().to_string()]);
@@ -552,11 +621,11 @@ fn generate_mkv(
/// Get the length of a video. This is required because sometimes subtitles have an unnecessary entry
/// long after the actual video ends with artificially extends the video length on some video players.
-/// To prevent this, the video length must be hard set with ffmpeg. See
+/// To prevent this, the video length must be hard set. See
/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
/// information.
-fn get_video_length(path: PathBuf) -> Result<(u32, u32, u32, u32)> {
- let video_length = Regex::new(r"Duration:\s?(\d+):(\d+):(\d+).(\d+),")?;
+fn get_video_length(path: PathBuf) -> Result {
+ let video_length = Regex::new(r"Duration:\s(?P\d+:\d+:\d+\.\d+),")?;
let ffmpeg = Command::new("ffmpeg")
.stdout(Stdio::null())
@@ -567,10 +636,5 @@ fn get_video_length(path: PathBuf) -> Result<(u32, u32, u32, u32)> {
let ffmpeg_output = String::from_utf8(ffmpeg.stderr)?;
let caps = video_length.captures(ffmpeg_output.as_str()).unwrap();
- Ok((
- caps[1].parse()?,
- caps[2].parse()?,
- caps[3].parse()?,
- caps[4].parse()?,
- ))
+ Ok(NaiveTime::parse_from_str(caps.name("time").unwrap().as_str(), "%H:%M:%S%.f").unwrap())
}
From 342cf23ae00e62c243e1907f602878c8f80209da Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 4 Dec 2022 18:57:54 +0100
Subject: [PATCH 003/395] Remove if condition from ci
---
.github/workflows/ci.yml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3900976..eddc7b2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,7 +9,6 @@ on:
jobs:
build-nix:
- if: github.ref == 'refs/heads/master'
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -77,7 +76,6 @@ jobs:
if-no-files-found: error
build-windows:
- if: github.ref == 'refs/heads/master'
runs-on: windows-latest
steps:
- name: Checkout
From faadd89fffb1832126de5bfdf89dc421409535bf Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 4 Dec 2022 18:54:19 +0100
Subject: [PATCH 004/395] Wait until buffer is empty when downloading
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 0bf6b45..758636d 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -169,7 +169,7 @@ pub async fn download_segments(
data_pos += 1;
}
- if *count.lock().unwrap() >= total_segments {
+ if *count.lock().unwrap() >= total_segments && buf.is_empty() {
break;
}
}
From c383b4d3076585931d441ad81299b7bb0449cfd9 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 4 Dec 2022 19:10:43 +0100
Subject: [PATCH 005/395] Fix filename generation if file already exists
---
crunchy-cli-core/src/utils/os.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index 92e4e9f..4919c08 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -42,7 +42,11 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
i += 1;
let ext = path.extension().unwrap().to_string_lossy();
- let filename = path.file_stem().unwrap().to_string_lossy();
+ let mut filename = path.file_stem().unwrap().to_str().unwrap();
+
+ if filename.ends_with(&format!(" ({})", i-1)) {
+ filename = filename.strip_suffix(&format!(" ({})", i-1)).unwrap();
+ }
path.set_file_name(format!("{} ({}).{}", filename, i, ext))
}
From 4cd46f19ac46077c11b494c26e858ce9e9b1140e Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 6 Dec 2022 22:02:13 +0100
Subject: [PATCH 006/395] Fix high ffmpeg cpu consuming with archive
---
crunchy-cli-core/src/cli/archive.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index d586725..f44c21a 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -8,7 +8,7 @@ use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
use crate::Execute;
use anyhow::{bail, Result};
-use chrono::{NaiveTime, Timelike};
+use chrono::NaiveTime;
use crunchyroll_rs::media::{Resolution, StreamSubtitle};
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
use log::{debug, error, info};
@@ -402,7 +402,9 @@ async fn download_video(ctx: &Context, format: &Format, only_audio: bool) -> Res
.stdout(Stdio::null())
.stderr(Stdio::piped())
.arg("-y")
- .args(["-f", "mpegts", "-i", "pipe:"])
+ .args(["-f", "mpegts"])
+ .args(["-i", "pipe:"])
+ .args(["-c", "copy"])
.args(if only_audio { vec!["-vn"] } else { vec![] })
.arg(path.to_str().unwrap())
.spawn()?;
From 91f8a82ca48f8cf288e974724656735a965c6d04 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 00:39:32 +0100
Subject: [PATCH 007/395] Fmt
---
crunchy-cli-core/src/cli/download.rs | 7 ++++++-
crunchy-cli-core/src/lib.rs | 4 +++-
crunchy-cli-core/src/utils/os.rs | 4 +++-
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index b0d0ffa..df48d54 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -68,7 +68,12 @@ impl Execute for Download {
fn pre_check(&self) -> Result<()> {
if has_ffmpeg() {
debug!("FFmpeg detected")
- } else if PathBuf::from(&self.output).extension().unwrap_or_default().to_string_lossy() != "ts" {
+ } else if PathBuf::from(&self.output)
+ .extension()
+ .unwrap_or_default()
+ .to_string_lossy()
+ != "ts"
+ {
bail!("File extension is not '.ts'. If you want to use a custom file format, please install ffmpeg")
}
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index c895d51..e8cd52a 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -16,7 +16,9 @@ pub use cli::{archive::Archive, download::Download, login::Login};
#[async_trait::async_trait(?Send)]
trait Execute {
- fn pre_check(&self) -> Result<()> { Ok(()) }
+ fn pre_check(&self) -> Result<()> {
+ Ok(())
+ }
async fn execute(self, ctx: Context) -> Result<()>;
}
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index 92e4e9f..e5c00ac 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -51,5 +51,7 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
/// Sanitizes the given path to not contain any invalid file character.
pub fn sanitize_file(path: PathBuf) -> PathBuf {
- path.with_file_name(sanitize_filename::sanitize(path.file_name().unwrap().to_string_lossy()))
+ path.with_file_name(sanitize_filename::sanitize(
+ path.file_name().unwrap().to_string_lossy(),
+ ))
}
From 6832c69eaa5edb93c9218f26b18435fe7676d1bd Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 01:08:47 +0100
Subject: [PATCH 008/395] Add ffmpeg encode presets
---
crunchy-cli-core/src/cli/archive.rs | 204 ++++++++++++++++++++++++----
1 file changed, 174 insertions(+), 30 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index f44c21a..a6e6d4e 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -26,13 +26,145 @@ pub enum MergeBehavior {
Video,
}
-fn parse_merge_behavior(s: &str) -> Result {
- Ok(match s.to_lowercase().as_str() {
- "auto" => MergeBehavior::Auto,
- "audio" => MergeBehavior::Audio,
- "video" => MergeBehavior::Video,
- _ => return Err(format!("'{}' is not a valid merge behavior", s)),
- })
+impl MergeBehavior {
+ fn parse(s: &str) -> Result {
+ Ok(match s.to_lowercase().as_str() {
+ "auto" => MergeBehavior::Auto,
+ "audio" => MergeBehavior::Audio,
+ "video" => MergeBehavior::Video,
+ _ => return Err(format!("'{}' is not a valid merge behavior", s)),
+ })
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum FFmpegPreset {
+ Nvidia,
+
+ Av1,
+ H265,
+ H264,
+}
+
+impl ToString for FFmpegPreset {
+ fn to_string(&self) -> String {
+ match self {
+ &FFmpegPreset::Nvidia => "nvidia",
+ &FFmpegPreset::Av1 => "av1",
+ &FFmpegPreset::H265 => "h265",
+ &FFmpegPreset::H264 => "h264",
+ }
+ .to_string()
+ }
+}
+
+impl FFmpegPreset {
+ fn all() -> Vec {
+ vec![
+ FFmpegPreset::Nvidia,
+ FFmpegPreset::Av1,
+ FFmpegPreset::H265,
+ FFmpegPreset::H264,
+ ]
+ }
+
+ fn description(self) -> String {
+ match self {
+ FFmpegPreset::Nvidia => "If you're have a nvidia card, use hardware / gpu accelerated video processing if available",
+ FFmpegPreset::Av1 => "Encode the video(s) with the av1 codec. Hardware acceleration is currently not possible with this",
+ FFmpegPreset::H265 => "Encode the video(s) with the h265 codec",
+ FFmpegPreset::H264 => "Encode the video(s) with the h264 codec"
+ }.to_string()
+ }
+
+ fn parse(s: &str) -> Result {
+ Ok(match s.to_lowercase().as_str() {
+ "nvidia" => FFmpegPreset::Nvidia,
+ "av1" => FFmpegPreset::Av1,
+ "h265" | "h.265" | "hevc" => FFmpegPreset::H265,
+ "h264" | "h.264" => FFmpegPreset::H264,
+ _ => return Err(format!("'{}' is not a valid ffmpeg preset", s)),
+ })
+ }
+
+ fn ffmpeg_presets(mut presets: Vec) -> Result<(Vec, Vec)> {
+ fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool {
+ if let Some(i) = presets.iter().position(|p| p == &preset) {
+ presets.remove(i);
+ true
+ } else {
+ false
+ }
+ }
+
+ let nvidia = preset_check_remove(&mut presets, FFmpegPreset::Nvidia);
+ if presets.len() > 1 {
+ bail!(
+ "Can only use one video codec, {} found: {}",
+ presets.len(),
+ presets
+ .iter()
+ .map(|p| p.to_string())
+ .collect::>()
+ .join(", ")
+ )
+ }
+
+ let (mut input, mut output) = (vec![], vec![]);
+ for preset in presets {
+ if nvidia {
+ match preset {
+ FFmpegPreset::Av1 => bail!("Hardware acceleration preset ('nvidia') is not available in combination with the 'av1' preset"),
+ FFmpegPreset::H265 => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "hevc_nvenc"]);
+ }
+ FFmpegPreset::H264 => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "h264_nvenc"]);
+ }
+ _ => ()
+ }
+ } else {
+ match preset {
+ FFmpegPreset::Av1 => {
+ output.extend(["-c:v", "libaom-av1"]);
+ }
+ FFmpegPreset::H265 => {
+ output.extend(["-c:v", "libx265"]);
+ }
+ FFmpegPreset::H264 => {
+ output.extend(["-c:v", "libx264"]);
+ }
+ _ => (),
+ }
+ }
+ }
+
+ if input.is_empty() && output.is_empty() {
+ let mut new_presets = vec![];
+ if nvidia {
+ new_presets.push(FFmpegPreset::Nvidia)
+ }
+
+ if !new_presets.is_empty() {
+ return FFmpegPreset::ffmpeg_presets(new_presets);
+ } else {
+ output.extend(["-c", "copy"])
+ }
+ } else {
+ if output.is_empty() {
+ output.extend(["-c", "copy"])
+ } else {
+ output.extend(["-c:a", "copy", "-c:s", "copy"])
+ }
+ }
+
+ Ok((
+ input.into_iter().map(|i| i.to_string()).collect(),
+ output.into_iter().map(|o| o.to_string()).collect(),
+ ))
+ }
}
#[derive(Debug, clap::Parser)]
@@ -88,9 +220,14 @@ pub struct Archive {
Valid options are 'audio' (stores one video and all other languages as audio only), 'video' (stores the video + audio for every language) and 'auto' (detects if videos differ in length: if so, behave like 'video' else like 'audio')"
)]
#[arg(short, long, default_value = "auto")]
- #[arg(value_parser = parse_merge_behavior)]
+ #[arg(value_parser = MergeBehavior::parse)]
merge: MergeBehavior,
+ #[arg(help = format!("Presets for audio converting. Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ #[arg(long)]
+ #[arg(value_parser = FFmpegPreset::parse)]
+ ffmpeg_preset: Vec,
+
#[arg(
help = "Set which subtitle language should be set as default / auto shown when starting a video"
)]
@@ -122,6 +259,7 @@ impl Execute for Archive {
{
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
+ let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
Ok(())
}
@@ -286,12 +424,7 @@ impl Execute for Archive {
let primary_video_length = get_video_length(primary_video.to_path_buf()).unwrap();
for subtitle in subtitles {
subtitle_paths.push((
- download_subtitle(
- &self,
- subtitle.clone(),
- primary_video_length
- )
- .await?,
+ download_subtitle(&self, subtitle.clone(), primary_video_length).await?,
subtitle,
))
}
@@ -475,11 +608,15 @@ fn fix_subtitle_length(raw: Vec, max_length: NaiveTime) -> Vec {
// digits so them have to be reduced manually to avoid the panic
fn format_naive_time(native_time: NaiveTime) -> String {
let formatted_time = native_time.format("%f").to_string();
- format!("{}.{}", native_time.format("%T"), if formatted_time.len() <= 2 {
- native_time.format("%2f").to_string()
- } else {
- formatted_time.split_at(2).0.parse().unwrap()
- })
+ format!(
+ "{}.{}",
+ native_time.format("%T"),
+ if formatted_time.len() <= 2 {
+ native_time.format("%2f").to_string()
+ } else {
+ formatted_time.split_at(2).0.parse().unwrap()
+ }
+ )
}
let length_as_string = format_naive_time(max_length);
@@ -495,16 +632,20 @@ fn fix_subtitle_length(raw: Vec, max_length: NaiveTime) -> Vec {
});
if start > max_length {
- continue
+ continue;
} else if end > max_length {
- new.push_str(re.replace(
- line,
- format!(
- "Dialogue: {},{},",
- format_naive_time(start),
- &length_as_string
- ),
- ).to_string().as_str())
+ new.push_str(
+ re.replace(
+ line,
+ format!(
+ "Dialogue: {},{},",
+ format_naive_time(start),
+ &length_as_string
+ ),
+ )
+ .to_string()
+ .as_str(),
+ )
} else {
new.push_str(line)
}
@@ -579,7 +720,11 @@ fn generate_mkv(
]);
}
+ let (input_presets, output_presets) =
+ FFmpegPreset::ffmpeg_presets(archive.ffmpeg_preset.clone())?;
+
let mut command_args = vec!["-y".to_string()];
+ command_args.extend(input_presets);
command_args.extend(input);
command_args.extend(maps);
command_args.extend(metadata);
@@ -599,9 +744,8 @@ fn generate_mkv(
command_args.extend(["-disposition:s:0".to_string(), "0".to_string()])
}
+ command_args.extend(output_presets);
command_args.extend([
- "-c".to_string(),
- "copy".to_string(),
"-f".to_string(),
"matroska".to_string(),
target.to_string_lossy().to_string(),
From 1b1756a0ae3684d1d7e1282f5cd347a144c9e449 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 15:12:01 +0100
Subject: [PATCH 009/395] Add long help to ffmpeg preset
---
crunchy-cli-core/src/cli/archive.rs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index a6e6d4e..057e7a8 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -223,7 +223,12 @@ pub struct Archive {
#[arg(value_parser = MergeBehavior::parse)]
merge: MergeBehavior,
- #[arg(help = format!("Presets for audio converting. Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ #[arg(help = format!("Presets for audio converting. \
+ Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ #[arg(help = format!("Presets for audio converting. \
+ Generally used to minify the file size with keeping (nearly) the same quality. \
+ It is recommended to only use this if you archive videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
+ Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
#[arg(long)]
#[arg(value_parser = FFmpegPreset::parse)]
ffmpeg_preset: Vec,
From 933d217b63d89666001b557c3777607c3fd8b315 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 20:08:44 +0100
Subject: [PATCH 010/395] Add pre_check checking
---
crunchy-cli-core/src/lib.rs | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index c895d51..2e0cf4d 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -152,18 +152,28 @@ pub async fn cli_entrypoint() {
.unwrap();
debug!("Created ctrl-c handler");
- let result = match cli.command {
- Command::Archive(archive) => archive.execute(ctx).await,
- Command::Download(download) => download.execute(ctx).await,
+ match cli.command {
+ Command::Archive(archive) => execute_executor(archive,ctx).await,
+ Command::Download(download) => execute_executor(download, ctx).await,
Command::Login(login) => {
if login.remove {
- Ok(())
+ return;
} else {
- login.execute(ctx).await
+ execute_executor(login, ctx).await
}
}
};
- if let Err(err) = result {
+}
+
+/// Cannot be done in the main function. I wanted to return `dyn` [`Execute`] from the match but had to
+/// box it which then conflicts with [`Execute::execute`] which consumes `self`
+async fn execute_executor(executor: impl Execute, ctx: Context) {
+ if let Err(err) = executor.pre_check() {
+ error!("Misconfigurations detected: {}", err);
+ std::process::exit(1)
+ }
+
+ if let Err(err) = executor.execute(ctx).await {
error!("a unexpected error occurred: {}", err);
std::process::exit(1)
}
From ce5672588e6f04f43b789356cb7b552851a44d4b Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 19:47:03 +0100
Subject: [PATCH 011/395] Update dependencies
---
Cargo.lock | 140 ++++++++++++++++++++++++++++++------
crunchy-cli-core/Cargo.lock | 140 ++++++++++++++++++++++++++++++------
crunchy-cli-core/Cargo.toml | 2 +-
3 files changed, 239 insertions(+), 43 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 108a431..f3a24bb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -139,7 +139,7 @@ dependencies = [
"num-integer",
"num-traits",
"serde",
- "time",
+ "time 0.1.45",
"wasm-bindgen",
"winapi",
]
@@ -303,13 +303,14 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#7644b24864608c059d702db8b373be81ffcec643"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
dependencies = [
"aes",
"cbc",
"chrono",
"crunchyroll-rs-internal",
"curl-sys",
+ "dash-mpd",
"http",
"isahc",
"m3u8-rs",
@@ -325,7 +326,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#7644b24864608c059d702db8b373be81ffcec643"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
dependencies = [
"darling",
"quote",
@@ -463,10 +464,26 @@ dependencies = [
]
[[package]]
-name = "data-encoding"
-version = "2.3.2"
+name = "dash-mpd"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
+checksum = "d6a181b3a4a1ef2cb4dd72f2a85e36a2e54445b8b9513635d3fad23e9b9a7c4c"
+dependencies = [
+ "chrono",
+ "log",
+ "quick-xml",
+ "regex",
+ "serde",
+ "serde_with",
+ "thiserror",
+ "xattr",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "dirs"
@@ -691,6 +708,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "http"
version = "0.2.8"
@@ -810,6 +833,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
+ "serde",
]
[[package]]
@@ -1077,9 +1101,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "openssl"
-version = "0.10.43"
+version = "0.10.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
+checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566"
dependencies = [
"bitflags",
"cfg-if",
@@ -1118,9 +1142,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
-version = "0.9.78"
+version = "0.9.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
+checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4"
dependencies = [
"autocfg",
"cc",
@@ -1227,6 +1251,16 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "quick-xml"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
[[package]]
name = "quote"
version = "1.0.21"
@@ -1327,9 +1361,9 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]]
name = "rustix"
-version = "0.36.4"
+version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
+checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
@@ -1423,18 +1457,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.148"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
+checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.148"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
+checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
dependencies = [
"proc-macro2",
"quote",
@@ -1464,6 +1498,34 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_with"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap",
+ "serde",
+ "serde_json",
+ "serde_with_macros",
+ "time 0.3.17",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "signal-hook"
version = "0.3.14"
@@ -1624,6 +1686,33 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "time"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+
+[[package]]
+name = "time-macros"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
+dependencies = [
+ "time-core",
+]
+
[[package]]
name = "tinyvec"
version = "1.6.0"
@@ -1641,9 +1730,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.22.0"
+version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
+checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
dependencies = [
"autocfg",
"bytes",
@@ -1654,7 +1743,7 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio-macros",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -1749,9 +1838,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typenum"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicode-bidi"
@@ -2055,3 +2144,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
+
+[[package]]
+name = "xattr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
+dependencies = [
+ "libc",
+]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index d0f951a..1e9c6d4 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -139,7 +139,7 @@ dependencies = [
"num-integer",
"num-traits",
"serde",
- "time",
+ "time 0.1.45",
"wasm-bindgen",
"winapi",
]
@@ -271,13 +271,14 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#7644b24864608c059d702db8b373be81ffcec643"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
dependencies = [
"aes",
"cbc",
"chrono",
"crunchyroll-rs-internal",
"curl-sys",
+ "dash-mpd",
"http",
"isahc",
"m3u8-rs",
@@ -293,7 +294,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#7644b24864608c059d702db8b373be81ffcec643"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
dependencies = [
"darling",
"quote",
@@ -431,10 +432,26 @@ dependencies = [
]
[[package]]
-name = "data-encoding"
-version = "2.3.2"
+name = "dash-mpd"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
+checksum = "d6a181b3a4a1ef2cb4dd72f2a85e36a2e54445b8b9513635d3fad23e9b9a7c4c"
+dependencies = [
+ "chrono",
+ "log",
+ "quick-xml",
+ "regex",
+ "serde",
+ "serde_with",
+ "thiserror",
+ "xattr",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "dirs"
@@ -659,6 +676,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "http"
version = "0.2.8"
@@ -778,6 +801,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
+ "serde",
]
[[package]]
@@ -1045,9 +1069,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "openssl"
-version = "0.10.43"
+version = "0.10.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
+checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566"
dependencies = [
"bitflags",
"cfg-if",
@@ -1086,9 +1110,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
-version = "0.9.78"
+version = "0.9.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
+checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4"
dependencies = [
"autocfg",
"cc",
@@ -1195,6 +1219,16 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "quick-xml"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
[[package]]
name = "quote"
version = "1.0.21"
@@ -1289,9 +1323,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.36.4"
+version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
+checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
@@ -1385,18 +1419,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.148"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
+checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.148"
+version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
+checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
dependencies = [
"proc-macro2",
"quote",
@@ -1426,6 +1460,34 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_with"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap",
+ "serde",
+ "serde_json",
+ "serde_with_macros",
+ "time 0.3.17",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "signal-hook"
version = "0.3.14"
@@ -1580,6 +1642,33 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "time"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
+
+[[package]]
+name = "time-macros"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
+dependencies = [
+ "time-core",
+]
+
[[package]]
name = "tinyvec"
version = "1.6.0"
@@ -1597,9 +1686,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.22.0"
+version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
+checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
dependencies = [
"autocfg",
"bytes",
@@ -1610,7 +1699,7 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio-macros",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -1705,9 +1794,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typenum"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "unicode-bidi"
@@ -2011,3 +2100,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
+
+[[package]]
+name = "xattr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
+dependencies = [
+ "libc",
+]
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index a1d898e..da794d3 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -13,7 +13,7 @@ anyhow = "1.0"
async-trait = "0.1"
clap = { version = "4.0", features = ["derive", "string"] }
chrono = "0.4"
-crunchyroll-rs = { git = "https://github.com/crunchy-labs/crunchyroll-rs", default-features = false, features = ["stream", "parse"] }
+crunchyroll-rs = { git = "https://github.com/crunchy-labs/crunchyroll-rs", default-features = false, features = ["parse", "hls-stream", "dash-stream"] }
ctrlc = "3.2"
dirs = "4.0"
isahc = { git = "https://github.com/sagebind/isahc", rev = "c39f6f8" }
From 2e4e897dc1fa44801a02b553239eb5903f9b991a Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 7 Dec 2022 20:22:20 +0100
Subject: [PATCH 012/395] Fix only nvidia preset stack overflow
---
crunchy-cli-core/src/cli/archive.rs | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 057e7a8..e0b4513 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -11,7 +11,7 @@ use anyhow::{bail, Result};
use chrono::NaiveTime;
use crunchyroll_rs::media::{Resolution, StreamSubtitle};
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
-use log::{debug, error, info};
+use log::{debug, error, info, warn};
use regex::Regex;
use std::collections::BTreeMap;
use std::io::Write;
@@ -114,7 +114,7 @@ impl FFmpegPreset {
for preset in presets {
if nvidia {
match preset {
- FFmpegPreset::Av1 => bail!("Hardware acceleration preset ('nvidia') is not available in combination with the 'av1' preset"),
+ FFmpegPreset::Av1 => bail!("'nvidia' hardware acceleration preset is not available in combination with the 'av1' codec preset"),
FFmpegPreset::H265 => {
input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
output.extend(["-c:v", "hevc_nvenc"]);
@@ -142,16 +142,7 @@ impl FFmpegPreset {
}
if input.is_empty() && output.is_empty() {
- let mut new_presets = vec![];
- if nvidia {
- new_presets.push(FFmpegPreset::Nvidia)
- }
-
- if !new_presets.is_empty() {
- return FFmpegPreset::ffmpeg_presets(new_presets);
- } else {
- output.extend(["-c", "copy"])
- }
+ output.extend(["-c", "copy"])
} else {
if output.is_empty() {
output.extend(["-c", "copy"])
@@ -265,6 +256,11 @@ impl Execute for Archive {
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
+ // check if the only given preset is FFmpegPreset::Nvidia. This checking is not done in
+ // FFmpegPreset::ffmpeg_presets since the warning it emits would print twice
+ if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia {
+ warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
+ }
Ok(())
}
From a32d3aef87e62c98935b07abc36effc3413ae645 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 00:12:25 +0100
Subject: [PATCH 013/395] Update dependencies
---
Cargo.lock | 67 ++++++++++++++++++++++++----
crunchy-cli-core/Cargo.lock | 67 ++++++++++++++++++++++++----
crunchy-cli-core/Cargo.toml | 3 ++
crunchy-cli-core/src/cli/archive.rs | 2 +-
crunchy-cli-core/src/cli/download.rs | 8 ++--
5 files changed, 124 insertions(+), 23 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index f3a24bb..fc5d0d0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -86,6 +86,18 @@ dependencies = [
"generic-array",
]
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "lazy_static",
+ "memchr",
+ "regex-automata",
+ "serde",
+]
+
[[package]]
name = "bumpalo"
version = "3.11.1"
@@ -285,6 +297,7 @@ dependencies = [
"chrono",
"clap",
"crunchyroll-rs",
+ "csv",
"ctrlc",
"dirs",
"isahc",
@@ -293,6 +306,8 @@ dependencies = [
"regex",
"rustls-native-certs",
"sanitize-filename",
+ "serde",
+ "serde_json",
"signal-hook",
"sys-locale",
"tempfile",
@@ -303,7 +318,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
dependencies = [
"aes",
"cbc",
@@ -326,7 +341,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
dependencies = [
"darling",
"quote",
@@ -343,6 +358,28 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "csv"
+version = "1.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+dependencies = [
+ "bstr",
+ "csv-core",
+ "itoa 0.4.8",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "ctrlc"
version = "3.2.3"
@@ -722,7 +759,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
dependencies = [
"bytes",
"fnv",
- "itoa",
+ "itoa 1.0.4",
]
[[package]]
@@ -763,7 +800,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
- "itoa",
+ "itoa 1.0.4",
"pin-project-lite",
"socket2",
"tokio",
@@ -867,9 +904,9 @@ dependencies = [
[[package]]
name = "ipnet"
-version = "2.5.1"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
+checksum = "ec947b7a4ce12e3b87e353abae7ce124d025b6c7d6c5aea5cc0bcf92e9510ded"
[[package]]
name = "is-terminal"
@@ -911,6 +948,12 @@ dependencies = [
"waker-fn",
]
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
[[package]]
name = "itoa"
version = "1.0.4"
@@ -1301,6 +1344,12 @@ dependencies = [
"regex-syntax",
]
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+
[[package]]
name = "regex-syntax"
version = "0.6.28"
@@ -1481,7 +1530,7 @@ version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
- "itoa",
+ "itoa 1.0.4",
"ryu",
"serde",
]
@@ -1493,7 +1542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa",
+ "itoa 1.0.4",
"ryu",
"serde",
]
@@ -1692,7 +1741,7 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [
- "itoa",
+ "itoa 1.0.4",
"serde",
"time-core",
"time-macros",
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 1e9c6d4..93c7522 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -86,6 +86,18 @@ dependencies = [
"generic-array",
]
+[[package]]
+name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "lazy_static",
+ "memchr",
+ "regex-automata",
+ "serde",
+]
+
[[package]]
name = "bumpalo"
version = "3.11.1"
@@ -253,6 +265,7 @@ dependencies = [
"chrono",
"clap",
"crunchyroll-rs",
+ "csv",
"ctrlc",
"dirs",
"isahc",
@@ -261,6 +274,8 @@ dependencies = [
"regex",
"rustls-native-certs",
"sanitize-filename",
+ "serde",
+ "serde_json",
"signal-hook",
"sys-locale",
"tempfile",
@@ -271,7 +286,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
dependencies = [
"aes",
"cbc",
@@ -294,7 +309,7 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#50f9ad65f65affcc5839af565d425b9cd678b73a"
+source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
dependencies = [
"darling",
"quote",
@@ -311,6 +326,28 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "csv"
+version = "1.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+dependencies = [
+ "bstr",
+ "csv-core",
+ "itoa 0.4.8",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "ctrlc"
version = "3.2.3"
@@ -690,7 +727,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
dependencies = [
"bytes",
"fnv",
- "itoa",
+ "itoa 1.0.4",
]
[[package]]
@@ -731,7 +768,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
- "itoa",
+ "itoa 1.0.4",
"pin-project-lite",
"socket2",
"tokio",
@@ -835,9 +872,9 @@ dependencies = [
[[package]]
name = "ipnet"
-version = "2.5.1"
+version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
+checksum = "ec947b7a4ce12e3b87e353abae7ce124d025b6c7d6c5aea5cc0bcf92e9510ded"
[[package]]
name = "is-terminal"
@@ -879,6 +916,12 @@ dependencies = [
"waker-fn",
]
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
[[package]]
name = "itoa"
version = "1.0.4"
@@ -1269,6 +1312,12 @@ dependencies = [
"regex-syntax",
]
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+
[[package]]
name = "regex-syntax"
version = "0.6.28"
@@ -1443,7 +1492,7 @@ version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
- "itoa",
+ "itoa 1.0.4",
"ryu",
"serde",
]
@@ -1455,7 +1504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa",
+ "itoa 1.0.4",
"ryu",
"serde",
]
@@ -1648,7 +1697,7 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [
- "itoa",
+ "itoa 1.0.4",
"serde",
"time-core",
"time-macros",
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index da794d3..84fdcf2 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -14,6 +14,7 @@ async-trait = "0.1"
clap = { version = "4.0", features = ["derive", "string"] }
chrono = "0.4"
crunchyroll-rs = { git = "https://github.com/crunchy-labs/crunchyroll-rs", default-features = false, features = ["parse", "hls-stream", "dash-stream"] }
+csv = "1.1"
ctrlc = "3.2"
dirs = "4.0"
isahc = { git = "https://github.com/sagebind/isahc", rev = "c39f6f8" }
@@ -21,6 +22,8 @@ log = { version = "0.4", features = ["std"] }
num_cpus = "1.13"
regex = "1.6"
sanitize-filename = "0.4"
+serde = "1.0"
+serde_json = "1.0"
signal-hook = "0.3"
tempfile = "3.3"
terminal_size = "0.2"
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index d4b0a5d..626a4f0 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -341,7 +341,7 @@ async fn formats_from_series(
}
let streams = episode.streams().await?;
- let streaming_data = streams.streaming_data(None).await?;
+ let streaming_data = streams.hls_streaming_data(None).await?;
let Some(stream) = find_resolution(streaming_data, &archive.resolution) else {
bail!(
"Resolution ({}x{}) is not available for episode {} ({}) of season {} ({}) of {}",
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index b0d0ffa..393e45a 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -352,9 +352,9 @@ async fn format_from_episode(
);
return Ok(None);
}
- streams.streaming_data(Some(subtitle.clone())).await?
+ streams.hls_streaming_data(Some(subtitle.clone())).await?
} else {
- streams.streaming_data(None).await?
+ streams.hls_streaming_data(None).await?
};
let Some(stream) = find_resolution(streaming_data, &download.resolution) else {
@@ -400,9 +400,9 @@ async fn format_from_movie(
error!("Movie {} has no {} subtitles", movie.title, subtitle);
return Ok(None);
}
- streams.streaming_data(Some(subtitle.clone())).await?
+ streams.hls_streaming_data(Some(subtitle.clone())).await?
} else {
- streams.streaming_data(None).await?
+ streams.hls_streaming_data(None).await?
};
streaming_data.sort_by(|a, b| a.resolution.width.cmp(&b.resolution.width).reverse());
From 54018f977325f6f5a04ff273e0f09a90126f5d5d Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 01:37:37 +0100
Subject: [PATCH 014/395] Fmt
---
crunchy-cli-core/src/cli/download.rs | 7 ++++++-
crunchy-cli-core/src/lib.rs | 10 +++++++---
crunchy-cli-core/src/utils/os.rs | 8 +++++---
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 393e45a..ddf45b3 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -68,7 +68,12 @@ impl Execute for Download {
fn pre_check(&self) -> Result<()> {
if has_ffmpeg() {
debug!("FFmpeg detected")
- } else if PathBuf::from(&self.output).extension().unwrap_or_default().to_string_lossy() != "ts" {
+ } else if PathBuf::from(&self.output)
+ .extension()
+ .unwrap_or_default()
+ .to_string_lossy()
+ != "ts"
+ {
bail!("File extension is not '.ts'. If you want to use a custom file format, please install ffmpeg")
}
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 2e0cf4d..92a076f 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -12,11 +12,13 @@ use std::{env, fs};
mod cli;
mod utils;
-pub use cli::{archive::Archive, download::Download, login::Login};
+pub use cli::{archive::Archive, download::Download, login::Login, search::Search};
#[async_trait::async_trait(?Send)]
trait Execute {
- fn pre_check(&self) -> Result<()> { Ok(()) }
+ fn pre_check(&self) -> Result<()> {
+ Ok(())
+ }
async fn execute(self, ctx: Context) -> Result<()>;
}
@@ -57,6 +59,7 @@ enum Command {
Archive(Archive),
Download(Download),
Login(Login),
+ Search(Search),
}
#[derive(Debug, Parser)]
@@ -153,7 +156,7 @@ pub async fn cli_entrypoint() {
debug!("Created ctrl-c handler");
match cli.command {
- Command::Archive(archive) => execute_executor(archive,ctx).await,
+ Command::Archive(archive) => execute_executor(archive, ctx).await,
Command::Download(download) => execute_executor(download, ctx).await,
Command::Login(login) => {
if login.remove {
@@ -162,6 +165,7 @@ pub async fn cli_entrypoint() {
execute_executor(login, ctx).await
}
}
+ Command::Search(search) => execute_executor(search, ctx).await,
};
}
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index 4919c08..c6e262e 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -44,8 +44,8 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
let ext = path.extension().unwrap().to_string_lossy();
let mut filename = path.file_stem().unwrap().to_str().unwrap();
- if filename.ends_with(&format!(" ({})", i-1)) {
- filename = filename.strip_suffix(&format!(" ({})", i-1)).unwrap();
+ if filename.ends_with(&format!(" ({})", i - 1)) {
+ filename = filename.strip_suffix(&format!(" ({})", i - 1)).unwrap();
}
path.set_file_name(format!("{} ({}).{}", filename, i, ext))
@@ -55,5 +55,7 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
/// Sanitizes the given path to not contain any invalid file character.
pub fn sanitize_file(path: PathBuf) -> PathBuf {
- path.with_file_name(sanitize_filename::sanitize(path.file_name().unwrap().to_string_lossy()))
+ path.with_file_name(sanitize_filename::sanitize(
+ path.file_name().unwrap().to_string_lossy(),
+ ))
}
From c4540ada50fe0de6660c50a82dc166f4d5b26183 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 01:40:19 +0100
Subject: [PATCH 015/395] Remove unwanted ffmpeg output when check if available
---
crunchy-cli-core/src/utils/os.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index c6e262e..abdf151 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -1,12 +1,12 @@
use log::debug;
use std::io::ErrorKind;
use std::path::PathBuf;
-use std::process::Command;
+use std::process::{Command, Stdio};
use std::{env, io};
use tempfile::{Builder, NamedTempFile};
pub fn has_ffmpeg() -> bool {
- if let Err(e) = Command::new("ffmpeg").spawn() {
+ if let Err(e) = Command::new("ffmpeg").stderr(Stdio::null()).spawn() {
if ErrorKind::NotFound != e.kind() {
debug!(
"unknown error occurred while checking if ffmpeg exists: {}",
From 985ec2ade9d8c1ee36bbb8730035183dd33b8215 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 01:57:14 +0100
Subject: [PATCH 016/395] Remove search command (wrong commit oops)
---
crunchy-cli-core/src/lib.rs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 92a076f..a13ac2f 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -12,7 +12,7 @@ use std::{env, fs};
mod cli;
mod utils;
-pub use cli::{archive::Archive, download::Download, login::Login, search::Search};
+pub use cli::{archive::Archive, download::Download, login::Login};
#[async_trait::async_trait(?Send)]
trait Execute {
@@ -59,7 +59,6 @@ enum Command {
Archive(Archive),
Download(Download),
Login(Login),
- Search(Search),
}
#[derive(Debug, Parser)]
@@ -165,7 +164,6 @@ pub async fn cli_entrypoint() {
execute_executor(login, ctx).await
}
}
- Command::Search(search) => execute_executor(search, ctx).await,
};
}
From 2f7e992a6ea9ab591e4e089843a81ce00d0f1f9f Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 14:04:43 +0100
Subject: [PATCH 017/395] Move ffmpeg presets to utils
---
crunchy-cli-core/src/cli/archive.rs | 129 +---------------------------
crunchy-cli-core/src/cli/utils.rs | 123 +++++++++++++++++++++++++-
2 files changed, 125 insertions(+), 127 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index e0b4513..3fa7b3c 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution};
+use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -37,127 +37,6 @@ impl MergeBehavior {
}
}
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum FFmpegPreset {
- Nvidia,
-
- Av1,
- H265,
- H264,
-}
-
-impl ToString for FFmpegPreset {
- fn to_string(&self) -> String {
- match self {
- &FFmpegPreset::Nvidia => "nvidia",
- &FFmpegPreset::Av1 => "av1",
- &FFmpegPreset::H265 => "h265",
- &FFmpegPreset::H264 => "h264",
- }
- .to_string()
- }
-}
-
-impl FFmpegPreset {
- fn all() -> Vec {
- vec![
- FFmpegPreset::Nvidia,
- FFmpegPreset::Av1,
- FFmpegPreset::H265,
- FFmpegPreset::H264,
- ]
- }
-
- fn description(self) -> String {
- match self {
- FFmpegPreset::Nvidia => "If you're have a nvidia card, use hardware / gpu accelerated video processing if available",
- FFmpegPreset::Av1 => "Encode the video(s) with the av1 codec. Hardware acceleration is currently not possible with this",
- FFmpegPreset::H265 => "Encode the video(s) with the h265 codec",
- FFmpegPreset::H264 => "Encode the video(s) with the h264 codec"
- }.to_string()
- }
-
- fn parse(s: &str) -> Result {
- Ok(match s.to_lowercase().as_str() {
- "nvidia" => FFmpegPreset::Nvidia,
- "av1" => FFmpegPreset::Av1,
- "h265" | "h.265" | "hevc" => FFmpegPreset::H265,
- "h264" | "h.264" => FFmpegPreset::H264,
- _ => return Err(format!("'{}' is not a valid ffmpeg preset", s)),
- })
- }
-
- fn ffmpeg_presets(mut presets: Vec) -> Result<(Vec, Vec)> {
- fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool {
- if let Some(i) = presets.iter().position(|p| p == &preset) {
- presets.remove(i);
- true
- } else {
- false
- }
- }
-
- let nvidia = preset_check_remove(&mut presets, FFmpegPreset::Nvidia);
- if presets.len() > 1 {
- bail!(
- "Can only use one video codec, {} found: {}",
- presets.len(),
- presets
- .iter()
- .map(|p| p.to_string())
- .collect::>()
- .join(", ")
- )
- }
-
- let (mut input, mut output) = (vec![], vec![]);
- for preset in presets {
- if nvidia {
- match preset {
- FFmpegPreset::Av1 => bail!("'nvidia' hardware acceleration preset is not available in combination with the 'av1' codec preset"),
- FFmpegPreset::H265 => {
- input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "hevc_nvenc"]);
- }
- FFmpegPreset::H264 => {
- input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "h264_nvenc"]);
- }
- _ => ()
- }
- } else {
- match preset {
- FFmpegPreset::Av1 => {
- output.extend(["-c:v", "libaom-av1"]);
- }
- FFmpegPreset::H265 => {
- output.extend(["-c:v", "libx265"]);
- }
- FFmpegPreset::H264 => {
- output.extend(["-c:v", "libx264"]);
- }
- _ => (),
- }
- }
- }
-
- if input.is_empty() && output.is_empty() {
- output.extend(["-c", "copy"])
- } else {
- if output.is_empty() {
- output.extend(["-c", "copy"])
- } else {
- output.extend(["-c:a", "copy", "-c:s", "copy"])
- }
- }
-
- Ok((
- input.into_iter().map(|i| i.to_string()).collect(),
- output.into_iter().map(|o| o.to_string()).collect(),
- ))
- }
-}
-
#[derive(Debug, clap::Parser)]
#[clap(about = "Archive a video")]
#[command(arg_required_else_help(true))]
@@ -214,9 +93,9 @@ pub struct Archive {
#[arg(value_parser = MergeBehavior::parse)]
merge: MergeBehavior,
- #[arg(help = format!("Presets for audio converting. \
+ #[arg(help = format!("Presets for video converting. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
- #[arg(help = format!("Presets for audio converting. \
+ #[arg(help = format!("Presets for video converting. \
Generally used to minify the file size with keeping (nearly) the same quality. \
It is recommended to only use this if you archive videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
@@ -256,8 +135,6 @@ impl Execute for Archive {
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
- // check if the only given preset is FFmpegPreset::Nvidia. This checking is not done in
- // FFmpegPreset::ffmpeg_presets since the warning it emits would print twice
if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia {
warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
}
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 758636d..9b817e4 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -1,5 +1,5 @@
use crate::utils::context::Context;
-use anyhow::Result;
+use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
use isahc::AsyncReadResponseExt;
use log::{debug, LevelFilter};
@@ -183,3 +183,124 @@ pub async fn download_segments(
Ok(())
}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum FFmpegPreset {
+ Nvidia,
+
+ Av1,
+ H265,
+ H264,
+}
+
+impl ToString for FFmpegPreset {
+ fn to_string(&self) -> String {
+ match self {
+ &FFmpegPreset::Nvidia => "nvidia",
+ &FFmpegPreset::Av1 => "av1",
+ &FFmpegPreset::H265 => "h265",
+ &FFmpegPreset::H264 => "h264",
+ }
+ .to_string()
+ }
+}
+
+impl FFmpegPreset {
+ pub(crate) fn all() -> Vec {
+ vec![
+ FFmpegPreset::Nvidia,
+ FFmpegPreset::Av1,
+ FFmpegPreset::H265,
+ FFmpegPreset::H264,
+ ]
+ }
+
+ pub(crate) fn description(self) -> String {
+ match self {
+ FFmpegPreset::Nvidia => "If you're have a nvidia card, use hardware / gpu accelerated video processing if available",
+ FFmpegPreset::Av1 => "Encode the video(s) with the av1 codec. Hardware acceleration is currently not possible with this",
+ FFmpegPreset::H265 => "Encode the video(s) with the h265 codec",
+ FFmpegPreset::H264 => "Encode the video(s) with the h264 codec"
+ }.to_string()
+ }
+
+ pub(crate) fn parse(s: &str) -> Result {
+ Ok(match s.to_lowercase().as_str() {
+ "nvidia" => FFmpegPreset::Nvidia,
+ "av1" => FFmpegPreset::Av1,
+ "h265" | "h.265" | "hevc" => FFmpegPreset::H265,
+ "h264" | "h.264" => FFmpegPreset::H264,
+ _ => return Err(format!("'{}' is not a valid ffmpeg preset", s)),
+ })
+ }
+
+ pub(crate) fn ffmpeg_presets(mut presets: Vec) -> Result<(Vec, Vec)> {
+ fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool {
+ if let Some(i) = presets.iter().position(|p| p == &preset) {
+ presets.remove(i);
+ true
+ } else {
+ false
+ }
+ }
+
+ let nvidia = preset_check_remove(&mut presets, FFmpegPreset::Nvidia);
+ if presets.len() > 1 {
+ bail!(
+ "Can only use one video codec, {} found: {}",
+ presets.len(),
+ presets
+ .iter()
+ .map(|p| p.to_string())
+ .collect::>()
+ .join(", ")
+ )
+ }
+
+ let (mut input, mut output) = (vec![], vec![]);
+ for preset in presets {
+ if nvidia {
+ match preset {
+ FFmpegPreset::Av1 => bail!("'nvidia' hardware acceleration preset is not available in combination with the 'av1' codec preset"),
+ FFmpegPreset::H265 => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "hevc_nvenc"]);
+ }
+ FFmpegPreset::H264 => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "h264_nvenc"]);
+ }
+ _ => ()
+ }
+ } else {
+ match preset {
+ FFmpegPreset::Av1 => {
+ output.extend(["-c:v", "libaom-av1"]);
+ }
+ FFmpegPreset::H265 => {
+ output.extend(["-c:v", "libx265"]);
+ }
+ FFmpegPreset::H264 => {
+ output.extend(["-c:v", "libx264"]);
+ }
+ _ => (),
+ }
+ }
+ }
+
+ if input.is_empty() && output.is_empty() {
+ output.extend(["-c", "copy"])
+ } else {
+ if output.is_empty() {
+ output.extend(["-c", "copy"])
+ } else {
+ output.extend(["-c:a", "copy", "-c:s", "copy"])
+ }
+ }
+
+ Ok((
+ input.into_iter().map(|i| i.to_string()).collect(),
+ output.into_iter().map(|o| o.to_string()).collect(),
+ ))
+ }
+}
From f0de4509c50ab40ca3c451dd61d8b483631a51f6 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 14:09:19 +0100
Subject: [PATCH 018/395] Add ffmpeg presets to download
---
crunchy-cli-core/src/cli/download.rs | 34 ++++++++++++++++++++++------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index df48d54..de536dc 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution};
+use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -12,7 +12,7 @@ use crunchyroll_rs::media::{Resolution, VariantData};
use crunchyroll_rs::{
Episode, Locale, Media, MediaCollection, Movie, MovieListing, Season, Series,
};
-use log::{debug, error, info};
+use log::{debug, error, info, warn};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
@@ -59,6 +59,16 @@ pub struct Download {
#[arg(value_parser = crate::utils::clap::clap_parse_resolution)]
resolution: Resolution,
+ #[arg(help = format!("Presets for video converting. \
+ Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ #[arg(help = format!("Presets for video converting. \
+ Generally used to minify the file size with keeping (nearly) the same quality. \
+ It is recommended to only use this if you download videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
+ Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ #[arg(long)]
+ #[arg(value_parser = FFmpegPreset::parse)]
+ ffmpeg_preset: Vec,
+
#[arg(help = "Url(s) to Crunchyroll episodes or series")]
urls: Vec,
}
@@ -75,6 +85,13 @@ impl Execute for Download {
!= "ts"
{
bail!("File extension is not '.ts'. If you want to use a custom file format, please install ffmpeg")
+ } else if !self.ffmpeg_preset.is_empty() {
+ bail!("FFmpeg is required to use (ffmpeg) presets")
+ }
+
+ let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
+ if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia {
+ warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
}
Ok(())
@@ -211,8 +228,8 @@ impl Execute for Download {
tab_info!("Resolution: {}", format.stream.resolution);
tab_info!("FPS: {:.2}", format.stream.fps);
- if path.extension().unwrap_or_default().to_string_lossy() != "ts" {
- download_ffmpeg(&ctx, format.stream, path.as_path()).await?;
+ if path.extension().unwrap_or_default().to_string_lossy() != "ts" || !self.ffmpeg_preset.is_empty() {
+ download_ffmpeg(&ctx, &self, format.stream, path.as_path()).await?;
} else if path.to_str().unwrap() == "-" {
let mut stdout = std::io::stdout().lock();
download_segments(&ctx, &mut stdout, None, format.stream).await?;
@@ -227,15 +244,18 @@ impl Execute for Download {
}
}
-async fn download_ffmpeg(ctx: &Context, variant_data: VariantData, target: &Path) -> Result<()> {
+async fn download_ffmpeg(ctx: &Context, download: &Download, variant_data: VariantData, target: &Path) -> Result<()> {
+ let (input_presets, output_presets) =
+ FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
+
let ffmpeg = Command::new("ffmpeg")
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::piped())
.arg("-y")
+ .args(input_presets)
.args(["-f", "mpegts", "-i", "pipe:"])
- .args(["-safe", "0"])
- .args(["-c", "copy"])
+ .args(output_presets)
.arg(target.to_str().unwrap())
.spawn()?;
From 01e2603e845f7f495ebbd3ad44b678975df03fef Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 14:21:52 +0100
Subject: [PATCH 019/395] Update ffmpeg preset command help
---
crunchy-cli-core/src/cli/archive.rs | 4 ++--
crunchy-cli-core/src/cli/download.rs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 3fa7b3c..8d95968 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -93,9 +93,9 @@ pub struct Archive {
#[arg(value_parser = MergeBehavior::parse)]
merge: MergeBehavior,
- #[arg(help = format!("Presets for video converting. \
+ #[arg(help = format!("Presets for video converting. Can be used multiple times. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
- #[arg(help = format!("Presets for video converting. \
+ #[arg(long_help = format!("Presets for video converting. Can be used multiple times. \
Generally used to minify the file size with keeping (nearly) the same quality. \
It is recommended to only use this if you archive videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index de536dc..edd58cc 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -59,9 +59,9 @@ pub struct Download {
#[arg(value_parser = crate::utils::clap::clap_parse_resolution)]
resolution: Resolution,
- #[arg(help = format!("Presets for video converting. \
+ #[arg(help = format!("Presets for video converting. Can be used multiple times. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
- #[arg(help = format!("Presets for video converting. \
+ #[arg(long_help = format!("Presets for video converting. Can be used multiple times. \
Generally used to minify the file size with keeping (nearly) the same quality. \
It is recommended to only use this if you download videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
From a5e60ea6b710f2fba403606b512e05a6a96d0721 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 15:10:53 +0100
Subject: [PATCH 020/395] Add generating file cli output
---
crunchy-cli-core/src/cli/archive.rs | 4 +++-
crunchy-cli-core/src/cli/download.rs | 8 ++++++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index e8a5ca2..f9bb6a5 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -307,7 +307,9 @@ impl Execute for Archive {
))
}
- generate_mkv(&self, path, video_paths, audio_paths, subtitle_paths)?
+ let _progess_handler = progress!("Generating mkv");
+ generate_mkv(&self, path, video_paths, audio_paths, subtitle_paths)?;
+ info!("Mkv generated")
}
}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index f90355b..b7093aa 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -248,7 +248,7 @@ async fn download_ffmpeg(ctx: &Context, download: &Download, variant_data: Varia
let (input_presets, output_presets) =
FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
- let ffmpeg = Command::new("ffmpeg")
+ let mut ffmpeg = Command::new("ffmpeg")
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::piped())
@@ -259,7 +259,11 @@ async fn download_ffmpeg(ctx: &Context, download: &Download, variant_data: Varia
.arg(target.to_str().unwrap())
.spawn()?;
- download_segments(ctx, &mut ffmpeg.stdin.unwrap(), None, variant_data).await?;
+ download_segments(ctx, &mut ffmpeg.stdin.take().unwrap(), None, variant_data).await?;
+
+ let _progress_handler = progress!("Generating output file");
+ ffmpeg.wait()?;
+ info!("Output file generated");
Ok(())
}
From 578e5ea5b7cc927147e77b983fa54bcb5c4daa79 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 8 Dec 2022 18:32:38 +0100
Subject: [PATCH 021/395] Update version
---
Cargo.lock | 4 ++--
Cargo.toml | 2 +-
crunchy-cli-core/Cargo.lock | 2 +-
crunchy-cli-core/Cargo.toml | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index fc5d0d0..a31d2fa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -277,7 +277,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.1"
+version = "3.0.0-dev.3"
dependencies = [
"chrono",
"clap",
@@ -290,7 +290,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.1"
+version = "3.0.0-dev.3"
dependencies = [
"anyhow",
"async-trait",
diff --git a/Cargo.toml b/Cargo.toml
index 1b815c6..a853f11 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.1"
+version = "3.0.0-dev.3"
edition = "2021"
[features]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 93c7522..43acaea 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -258,7 +258,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.1"
+version = "3.0.0-dev.3"
dependencies = [
"anyhow",
"async-trait",
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 84fdcf2..bc34907 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.1"
+version = "3.0.0-dev.3"
edition = "2021"
[features]
From b814529aa21b455686bb6c34d10caa4e95a34cd6 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 9 Dec 2022 16:33:34 +0100
Subject: [PATCH 022/395] Add anonymous login
---
crunchy-cli-core/src/lib.rs | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index a13ac2f..d669b64 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -81,9 +81,8 @@ struct Verbosity {
#[derive(Debug, Parser)]
struct LoginMethod {
- #[arg(help = "Login with credentials (username or email and password)")]
#[arg(
- long_help = "Login with credentials (username or email and password). Must be provided as user:password"
+ help = "Login with credentials (username or email and password). Must be provided as user:password"
)]
#[arg(long)]
credentials: Option,
@@ -93,6 +92,9 @@ struct LoginMethod {
)]
#[arg(long)]
etp_rt: Option,
+ #[arg(help = "Login anonymously / without an account")]
+ #[arg(long, default_value_t = false)]
+ anonymous: bool,
}
pub async fn cli_entrypoint() {
@@ -190,8 +192,12 @@ async fn crunchyroll_session(cli: &Cli) -> Result {
let mut builder = Crunchyroll::builder();
builder.locale(cli.lang.clone().unwrap_or_else(system_locale));
+ let login_methods_count = cli.login_method.credentials.is_some() as u8
+ + cli.login_method.etp_rt.is_some() as u8
+ + cli.login_method.anonymous as u8;
+
let _progress_handler = progress!("Logging in");
- if cli.login_method.credentials.is_none() && cli.login_method.etp_rt.is_none() {
+ if login_methods_count == 0 {
if let Some(login_file_path) = cli::login::login_file_path() {
if login_file_path.exists() {
let session = fs::read_to_string(login_file_path)?;
@@ -207,9 +213,9 @@ async fn crunchyroll_session(cli: &Cli) -> Result {
bail!("Could not read stored session ('{}')", session)
}
}
- bail!("Please use a login method ('--credentials' or '--etp_rt')")
- } else if cli.login_method.credentials.is_some() && cli.login_method.etp_rt.is_some() {
- bail!("Please use only one login method ('--credentials' or '--etp_rt')")
+ bail!("Please use a login method ('--credentials', '--etp-rt' or '--anonymous')")
+ } else if login_methods_count > 1 {
+ bail!("Please use only one login method ('--credentials', '--etp-rt' or '--anonymous')")
}
let crunchy = if let Some(credentials) = &cli.login_method.credentials {
@@ -220,6 +226,8 @@ async fn crunchyroll_session(cli: &Cli) -> Result {
}
} else if let Some(etp_rt) = &cli.login_method.etp_rt {
builder.login_with_etp_rt(etp_rt).await?
+ } else if cli.login_method.anonymous {
+ builder.login_anonymously().await?
} else {
bail!("should never happen")
};
From db3697c37269f15635e7410c3c964b73245263d0 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 11 Dec 2022 23:03:25 +0100
Subject: [PATCH 023/395] Add anonymous login examples to the README
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index f62c988..6785579 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,11 @@ You can pass your account via credentials (username & password) or refresh token
- ```shell
$ crunchy --credentials "user:password"
```
+- Anonymous
+ - Login without an account at all is also possible.
+ - ```shell
+ $ crunchy --anonymous
+ ```
### Login
@@ -89,6 +94,7 @@ $ crunchy --etp-rt "abcd1234-zyxw-9876-98zy-a1b2c3d4e5f6" login
```
Once set, you do not need to provide `--etp-rt` / `--credentials` anymore when using the cli.
+This does not work if you've using this with `--anonymous`.
### Download
From 52ee0c48e1fa595827614fc55f3867441e68e8a8 Mon Sep 17 00:00:00 2001
From: bytedream
Date: Tue, 13 Dec 2022 08:51:37 +0100
Subject: [PATCH 024/395] Fix resolution ...p parsing
---
crunchy-cli-core/src/utils/parse.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/utils/parse.rs b/crunchy-cli-core/src/utils/parse.rs
index fbfea35..eb1b19f 100644
--- a/crunchy-cli-core/src/utils/parse.rs
+++ b/crunchy-cli-core/src/utils/parse.rs
@@ -148,7 +148,7 @@ pub fn parse_resolution(mut resolution: String) -> Result {
height: u64::MIN,
})
} else if resolution.ends_with('p') {
- let without_p = resolution.as_str()[0..resolution.len() - 2]
+ let without_p = resolution.as_str()[0..resolution.len() - 1]
.parse()
.map_err(|_| anyhow!("Could not parse resolution"))?;
Ok(Resolution {
From f254df3bb3cfb1bb474b6521af3c3bdfb549053a Mon Sep 17 00:00:00 2001
From: bytedream
Date: Fri, 16 Dec 2022 08:50:11 +0100
Subject: [PATCH 025/395] Fix ci badge
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f62c988..c41f2a6 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ A [Rust](https://www.rust-lang.org/) written cli client for [Crunchyroll](https:
-
+
From cc9342cd0acb8809410ae6b42953690ce4bc76bb Mon Sep 17 00:00:00 2001
From: bytedream
Date: Fri, 16 Dec 2022 10:09:41 +0100
Subject: [PATCH 026/395] Update dependencies
---
.github/workflows/ci.yml | 75 +---
Cargo.lock | 506 +++++++++------------------
Cargo.toml | 16 +-
build.rs | 3 -
crunchy-cli-core/Cargo.lock | 505 ++++++++++----------------
crunchy-cli-core/Cargo.toml | 17 +-
crunchy-cli-core/src/cli/archive.rs | 6 +-
crunchy-cli-core/src/cli/download.rs | 6 +-
crunchy-cli-core/src/cli/utils.rs | 7 +-
9 files changed, 373 insertions(+), 768 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index eddc7b2..caef473 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,9 +16,15 @@ jobs:
- os: ubuntu-latest
toolchain: x86_64-unknown-linux-musl
platform: linux
+ ext:
+ - os: windows-latest
+ toolchain: x86_64-pc-windows-gnu
+ platform: windows
+ ext: .exe
- os: macos-latest
toolchain: x86_64-apple-darwin
platform: darwin
+ ext:
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -58,74 +64,7 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: crunchy-cli_${{ matrix.platform }}
- path: ./target/release/crunchy-cli
- if-no-files-found: error
-
- - name: Upload manpages artifact
- uses: actions/upload-artifact@v3
- with:
- name: manpages
- path: ./target/release/manpages
- if-no-files-found: error
-
- - name: Upload completions artifact
- uses: actions/upload-artifact@v3
- with:
- name: completions
- path: ./target/release/completions
- if-no-files-found: error
-
- build-windows:
- runs-on: windows-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - run: vcpkg integrate install
-
- - name: Install OpenSSL
- run: vcpkg install openssl:x64-windows-static-md
-
- - name: Set env variables
- shell: bash
- run: echo "CFLAGS=-I$(echo $VCPKG_INSTALLATION_ROOT)\packages\openssl_x64-windows-static-md\include" >> $GITHUB_ENV
-
- - name: Cargo cache # https://github.com/actions/cache/blob/main/examples.md#rust---cargo
- uses: actions/cache@v3
- with:
- path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
- target/
- key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-
- - name: Install toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- target: x86_64-pc-windows-msvc
- default: true
-
- - name: Test
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: --release --all-features
-
- - name: Build
- uses: actions-rs/cargo@v1
- with:
- command: build
- args: --release --all-features
-
- - name: Upload binary artifact
- uses: actions/upload-artifact@v3
- with:
- name: crunchy-cli_windows
- path: ./target/release/crunchy-cli.exe
+ path: ./target/release/crunchy-cli${{ matrix.ext }}
if-no-files-found: error
- name: Upload manpages artifact
diff --git a/Cargo.lock b/Cargo.lock
index a31d2fa..15acee9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -37,17 +37,6 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
-[[package]]
-name = "async-channel"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
-dependencies = [
- "concurrent-queue",
- "event-listener",
- "futures-core",
-]
-
[[package]]
name = "async-trait"
version = "0.1.59"
@@ -110,15 +99,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
-[[package]]
-name = "castaway"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
-dependencies = [
- "rustversion",
-]
-
[[package]]
name = "cbc"
version = "0.1.2"
@@ -130,9 +110,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.77"
+version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
@@ -233,12 +213,30 @@ dependencies = [
]
[[package]]
-name = "concurrent-queue"
-version = "2.0.0"
+name = "cookie"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
+checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
dependencies = [
- "crossbeam-utils",
+ "percent-encoding",
+ "time 0.3.17",
+ "version_check",
+]
+
+[[package]]
+name = "cookie_store"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e4b6aa369f41f5faa04bb80c9b1f4216ea81646ed6124d76ba5c49a7aafd9cd"
+dependencies = [
+ "cookie",
+ "idna 0.2.3",
+ "log",
+ "publicsuffix",
+ "serde",
+ "serde_json",
+ "time 0.3.17",
+ "url",
]
[[package]]
@@ -266,15 +264,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "crunchy-cli"
version = "3.0.0-dev.3"
@@ -284,7 +273,6 @@ dependencies = [
"clap_complete",
"clap_mangen",
"crunchy-cli-core",
- "static_vcruntime",
"tokio",
]
@@ -300,11 +288,9 @@ dependencies = [
"csv",
"ctrlc",
"dirs",
- "isahc",
"log",
"num_cpus",
"regex",
- "rustls-native-certs",
"sanitize-filename",
"serde",
"serde_json",
@@ -317,31 +303,32 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5032be36dc6c4757af4f28152659e7a772b48f6925f0e0ac81b5c384e291314"
dependencies = [
"aes",
"cbc",
"chrono",
"crunchyroll-rs-internal",
- "curl-sys",
- "dash-mpd",
"http",
- "isahc",
"m3u8-rs",
"regex",
"reqwest",
+ "rustls",
"serde",
"serde_json",
"serde_urlencoded",
"smart-default",
"tokio",
+ "webpki-roots",
]
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e4aa1f09fd76f44329455abfac35e22c654ac782e93bc8a7d3ee1be27509f4"
dependencies = [
"darling",
"quote",
@@ -382,43 +369,12 @@ dependencies = [
[[package]]
name = "ctrlc"
-version = "3.2.3"
+version = "3.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173"
+checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
dependencies = [
"nix",
- "winapi",
-]
-
-[[package]]
-name = "curl"
-version = "0.4.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
-dependencies = [
- "curl-sys",
- "libc",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "socket2",
- "winapi",
-]
-
-[[package]]
-name = "curl-sys"
-version = "0.4.59+curl-7.86.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407"
-dependencies = [
- "cc",
- "libc",
- "libnghttp2-sys",
- "libz-sys",
- "openssl-sys",
- "pkg-config",
- "vcpkg",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -500,28 +456,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "dash-mpd"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6a181b3a4a1ef2cb4dd72f2a85e36a2e54445b8b9513635d3fad23e9b9a7c4c"
-dependencies = [
- "chrono",
- "log",
- "quick-xml",
- "regex",
- "serde",
- "serde_with",
- "thiserror",
- "xattr",
-]
-
-[[package]]
-name = "data-encoding"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
-
[[package]]
name = "dirs"
version = "4.0.0"
@@ -572,12 +506,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "event-listener"
-version = "2.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
-
[[package]]
name = "fastrand"
version = "1.8.0"
@@ -638,16 +566,6 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
-[[package]]
-name = "futures-lite"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
-dependencies = [
- "futures-core",
- "pin-project-lite",
-]
-
[[package]]
name = "futures-sink"
version = "0.3.25"
@@ -745,12 +663,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
[[package]]
name = "http"
version = "0.2.8"
@@ -809,6 +721,19 @@ dependencies = [
"want",
]
+[[package]]
+name = "hyper-rustls"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
+dependencies = [
+ "http",
+ "hyper",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+]
+
[[package]]
name = "hyper-tls"
version = "0.5.0"
@@ -852,6 +777,17 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+[[package]]
+name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
[[package]]
name = "idna"
version = "0.3.0"
@@ -870,7 +806,6 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
- "serde",
]
[[package]]
@@ -904,9 +839,9 @@ dependencies = [
[[package]]
name = "ipnet"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec947b7a4ce12e3b87e353abae7ce124d025b6c7d6c5aea5cc0bcf92e9510ded"
+checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "is-terminal"
@@ -920,34 +855,6 @@ dependencies = [
"windows-sys 0.42.0",
]
-[[package]]
-name = "isahc"
-version = "1.7.0"
-source = "git+https://github.com/sagebind/isahc?rev=c39f6f8#c39f6f85aaa1f36c5857064c6c3c80f4d307d863"
-dependencies = [
- "async-channel",
- "castaway",
- "crossbeam-utils",
- "curl",
- "curl-sys",
- "data-encoding",
- "encoding_rs",
- "event-listener",
- "futures-io",
- "futures-lite",
- "http",
- "httpdate",
- "log",
- "mime",
- "once_cell",
- "polling",
- "sluice",
- "tracing",
- "tracing-futures",
- "url",
- "waker-fn",
-]
-
[[package]]
name = "itoa"
version = "0.4.8"
@@ -981,28 +888,6 @@ version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
-[[package]]
-name = "libnghttp2-sys"
-version = "0.1.7+1.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "libz-sys"
-version = "1.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
-]
-
[[package]]
name = "link-cplusplus"
version = "1.0.7"
@@ -1014,9 +899,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "log"
@@ -1037,6 +922,12 @@ dependencies = [
"nom",
]
+[[package]]
+name = "matches"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
+
[[package]]
name = "memchr"
version = "2.5.0"
@@ -1087,14 +978,14 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.25.1"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
+checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
dependencies = [
- "autocfg",
"bitflags",
"cfg-if",
"libc",
+ "static_assertions",
]
[[package]]
@@ -1174,15 +1065,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-[[package]]
-name = "openssl-src"
-version = "111.24.0+1.1.1s"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "openssl-sys"
version = "0.9.79"
@@ -1192,7 +1074,6 @@ dependencies = [
"autocfg",
"cc",
"libc",
- "openssl-src",
"pkg-config",
"vcpkg",
]
@@ -1209,26 +1090,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
-[[package]]
-name = "pin-project"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -1247,20 +1108,6 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
-[[package]]
-name = "polling"
-version = "2.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748"
-dependencies = [
- "autocfg",
- "cfg-if",
- "libc",
- "log",
- "wepoll-ffi",
- "windows-sys 0.42.0",
-]
-
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1285,6 +1132,12 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
[[package]]
name = "proc-macro2"
version = "1.0.47"
@@ -1295,13 +1148,19 @@ dependencies = [
]
[[package]]
-name = "quick-xml"
-version = "0.26.0"
+name = "psl-types"
+version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
+checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
+
+[[package]]
+name = "publicsuffix"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
dependencies = [
- "memchr",
- "serde",
+ "idna 0.3.0",
+ "psl-types",
]
[[package]]
@@ -1373,6 +1232,8 @@ checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [
"base64",
"bytes",
+ "cookie",
+ "cookie_store",
"encoding_rs",
"futures-core",
"futures-util",
@@ -1380,6 +1241,7 @@ dependencies = [
"http",
"http-body",
"hyper",
+ "hyper-rustls",
"hyper-tls",
"ipnet",
"js-sys",
@@ -1389,19 +1251,39 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
+ "proc-macro-hack",
+ "rustls",
+ "rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
+ "tokio-rustls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
+ "webpki-roots",
"winreg",
]
+[[package]]
+name = "ring"
+version = "0.16.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
+dependencies = [
+ "cc",
+ "libc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
[[package]]
name = "roff"
version = "0.2.1"
@@ -1423,15 +1305,15 @@ dependencies = [
]
[[package]]
-name = "rustls-native-certs"
-version = "0.6.2"
+name = "rustls"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
+checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
dependencies = [
- "openssl-probe",
- "rustls-pemfile",
- "schannel",
- "security-framework",
+ "log",
+ "ring",
+ "sct",
+ "webpki",
]
[[package]]
@@ -1443,12 +1325,6 @@ dependencies = [
"base64",
]
-[[package]]
-name = "rustversion"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
-
[[package]]
name = "ryu"
version = "1.0.11"
@@ -1481,6 +1357,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
+[[package]]
+name = "sct"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
[[package]]
name = "security-framework"
version = "2.7.0"
@@ -1506,18 +1392,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
+checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
+checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
dependencies = [
"proc-macro2",
"quote",
@@ -1547,34 +1433,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "serde_with"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
-dependencies = [
- "base64",
- "chrono",
- "hex",
- "indexmap",
- "serde",
- "serde_json",
- "serde_with_macros",
- "time 0.3.17",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "signal-hook"
version = "0.3.14"
@@ -1603,17 +1461,6 @@ dependencies = [
"autocfg",
]
-[[package]]
-name = "sluice"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5"
-dependencies = [
- "async-channel",
- "futures-core",
- "futures-io",
-]
-
[[package]]
name = "smart-default"
version = "0.6.0"
@@ -1636,10 +1483,16 @@ dependencies = [
]
[[package]]
-name = "static_vcruntime"
-version = "2.0.0"
+name = "spin"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "954e3e877803def9dc46075bf4060147c55cd70db97873077232eae0269dc89b"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
@@ -1816,6 +1669,17 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "tokio-rustls"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
+dependencies = [
+ "rustls",
+ "tokio",
+ "webpki",
+]
+
[[package]]
name = "tokio-util"
version = "0.7.4"
@@ -1843,23 +1707,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
- "log",
"pin-project-lite",
- "tracing-attributes",
"tracing-core",
]
-[[package]]
-name = "tracing-attributes"
-version = "0.1.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "tracing-core"
version = "0.1.30"
@@ -1869,16 +1720,6 @@ dependencies = [
"once_cell",
]
-[[package]]
-name = "tracing-futures"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
-dependencies = [
- "pin-project",
- "tracing",
-]
-
[[package]]
name = "try-lock"
version = "0.2.3"
@@ -1918,6 +1759,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
[[package]]
name = "url"
version = "2.3.1"
@@ -1925,7 +1772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
- "idna",
+ "idna 0.3.0",
"percent-encoding",
]
@@ -1941,12 +1788,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-[[package]]
-name = "waker-fn"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
-
[[package]]
name = "want"
version = "0.3.0"
@@ -2046,12 +1887,22 @@ dependencies = [
]
[[package]]
-name = "wepoll-ffi"
-version = "0.1.2"
+name = "webpki"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
+checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
- "cc",
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.22.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
+dependencies = [
+ "webpki",
]
[[package]]
@@ -2193,12 +2044,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
-
-[[package]]
-name = "xattr"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
-dependencies = [
- "libc",
-]
diff --git a/Cargo.toml b/Cargo.toml
index a853f11..b2af93c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,17 +4,8 @@ authors = ["Crunchy Labs Maintainers"]
version = "3.0.0-dev.3"
edition = "2021"
-[features]
-default = ["static-curl"]
-
-# Embed a static curl library into the binary instead of just linking it.
-static-curl = ["crunchy-cli-core/static-curl"]
-# Embed a static tls library into the binary instead of just linking it.
-# has no effect on Windows, always activated there.
-static-ssl = ["crunchy-cli-core/static-ssl"]
-
[dependencies]
-tokio = { version = "1.22", features = ["macros", "rt-multi-thread", "time"], default-features = false }
+tokio = { version = "1.23", features = ["macros", "rt-multi-thread", "time"], default-features = false }
crunchy-cli-core = { path = "./crunchy-cli-core" }
@@ -26,10 +17,7 @@ clap_mangen = "0.2"
# The static-* features must be used here since build dependency features cannot be manipulated from the features
# specified in this Cargo.toml [features].
-crunchy-cli-core = { path = "./crunchy-cli-core", features = ["static-curl"] }
-
-[target.'cfg(all(windows, target_env = "msvc"))'.build-dependencies]
-static_vcruntime = "2.0"
+crunchy-cli-core = { path = "./crunchy-cli-core" }
[profile.release]
strip = true
diff --git a/build.rs b/build.rs
index 927f4dd..1e4d71f 100644
--- a/build.rs
+++ b/build.rs
@@ -3,9 +3,6 @@ use clap_complete::shells;
use std::path::{Path, PathBuf};
fn main() -> std::io::Result<()> {
- #[cfg(all(windows, target_env = "msvc"))]
- static_vcruntime::metabuild();
-
// note that we're using an anti-pattern here / violate the rust conventions. build script are
// not supposed to write outside of 'OUT_DIR'. to have the generated files in the build "root"
// (the same directory where the output binary lives) is much simpler than in 'OUT_DIR' since
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 43acaea..aba7b4a 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -37,17 +37,6 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
-[[package]]
-name = "async-channel"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
-dependencies = [
- "concurrent-queue",
- "event-listener",
- "futures-core",
-]
-
[[package]]
name = "async-trait"
version = "0.1.59"
@@ -110,15 +99,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
-[[package]]
-name = "castaway"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
-dependencies = [
- "rustversion",
-]
-
[[package]]
name = "cbc"
version = "0.1.2"
@@ -130,9 +110,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.77"
+version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
@@ -214,12 +194,30 @@ dependencies = [
]
[[package]]
-name = "concurrent-queue"
-version = "2.0.0"
+name = "cookie"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
+checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
dependencies = [
- "crossbeam-utils",
+ "percent-encoding",
+ "time 0.3.17",
+ "version_check",
+]
+
+[[package]]
+name = "cookie_store"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e4b6aa369f41f5faa04bb80c9b1f4216ea81646ed6124d76ba5c49a7aafd9cd"
+dependencies = [
+ "cookie",
+ "idna 0.2.3",
+ "log",
+ "publicsuffix",
+ "serde",
+ "serde_json",
+ "time 0.3.17",
+ "url",
]
[[package]]
@@ -247,15 +245,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "crunchy-cli-core"
version = "3.0.0-dev.3"
@@ -268,11 +257,9 @@ dependencies = [
"csv",
"ctrlc",
"dirs",
- "isahc",
"log",
"num_cpus",
"regex",
- "rustls-native-certs",
"sanitize-filename",
"serde",
"serde_json",
@@ -285,31 +272,32 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5032be36dc6c4757af4f28152659e7a772b48f6925f0e0ac81b5c384e291314"
dependencies = [
"aes",
"cbc",
"chrono",
"crunchyroll-rs-internal",
- "curl-sys",
- "dash-mpd",
"http",
- "isahc",
"m3u8-rs",
"regex",
"reqwest",
+ "rustls",
"serde",
"serde_json",
"serde_urlencoded",
"smart-default",
"tokio",
+ "webpki-roots",
]
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.1.0"
-source = "git+https://github.com/crunchy-labs/crunchyroll-rs#86fb8307a531aedec708dd1c8c88b76bcf2a8c38"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e4aa1f09fd76f44329455abfac35e22c654ac782e93bc8a7d3ee1be27509f4"
dependencies = [
"darling",
"quote",
@@ -350,43 +338,12 @@ dependencies = [
[[package]]
name = "ctrlc"
-version = "3.2.3"
+version = "3.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d91974fbbe88ec1df0c24a4f00f99583667a7e2e6272b2b92d294d81e462173"
+checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
dependencies = [
"nix",
- "winapi",
-]
-
-[[package]]
-name = "curl"
-version = "0.4.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
-dependencies = [
- "curl-sys",
- "libc",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "socket2",
- "winapi",
-]
-
-[[package]]
-name = "curl-sys"
-version = "0.4.59+curl-7.86.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407"
-dependencies = [
- "cc",
- "libc",
- "libnghttp2-sys",
- "libz-sys",
- "openssl-sys",
- "pkg-config",
- "vcpkg",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -468,28 +425,6 @@ dependencies = [
"syn",
]
-[[package]]
-name = "dash-mpd"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6a181b3a4a1ef2cb4dd72f2a85e36a2e54445b8b9513635d3fad23e9b9a7c4c"
-dependencies = [
- "chrono",
- "log",
- "quick-xml",
- "regex",
- "serde",
- "serde_with",
- "thiserror",
- "xattr",
-]
-
-[[package]]
-name = "data-encoding"
-version = "2.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
-
[[package]]
name = "dirs"
version = "4.0.0"
@@ -540,12 +475,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "event-listener"
-version = "2.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
-
[[package]]
name = "fastrand"
version = "1.8.0"
@@ -606,16 +535,6 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
-[[package]]
-name = "futures-lite"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
-dependencies = [
- "futures-core",
- "pin-project-lite",
-]
-
[[package]]
name = "futures-sink"
version = "0.3.25"
@@ -713,12 +632,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
[[package]]
name = "http"
version = "0.2.8"
@@ -777,6 +690,19 @@ dependencies = [
"want",
]
+[[package]]
+name = "hyper-rustls"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
+dependencies = [
+ "http",
+ "hyper",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+]
+
[[package]]
name = "hyper-tls"
version = "0.5.0"
@@ -820,6 +746,17 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+[[package]]
+name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
[[package]]
name = "idna"
version = "0.3.0"
@@ -838,7 +775,6 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
- "serde",
]
[[package]]
@@ -872,9 +808,9 @@ dependencies = [
[[package]]
name = "ipnet"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec947b7a4ce12e3b87e353abae7ce124d025b6c7d6c5aea5cc0bcf92e9510ded"
+checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "is-terminal"
@@ -888,34 +824,6 @@ dependencies = [
"windows-sys 0.42.0",
]
-[[package]]
-name = "isahc"
-version = "1.7.0"
-source = "git+https://github.com/sagebind/isahc?rev=c39f6f8#c39f6f85aaa1f36c5857064c6c3c80f4d307d863"
-dependencies = [
- "async-channel",
- "castaway",
- "crossbeam-utils",
- "curl",
- "curl-sys",
- "data-encoding",
- "encoding_rs",
- "event-listener",
- "futures-io",
- "futures-lite",
- "http",
- "httpdate",
- "log",
- "mime",
- "once_cell",
- "polling",
- "sluice",
- "tracing",
- "tracing-futures",
- "url",
- "waker-fn",
-]
-
[[package]]
name = "itoa"
version = "0.4.8"
@@ -949,28 +857,6 @@ version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
-[[package]]
-name = "libnghttp2-sys"
-version = "0.1.7+1.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "libz-sys"
-version = "1.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
-]
-
[[package]]
name = "link-cplusplus"
version = "1.0.7"
@@ -982,9 +868,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "log"
@@ -1005,6 +891,12 @@ dependencies = [
"nom",
]
+[[package]]
+name = "matches"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
+
[[package]]
name = "memchr"
version = "2.5.0"
@@ -1055,14 +947,14 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.25.1"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
+checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
dependencies = [
- "autocfg",
"bitflags",
"cfg-if",
"libc",
+ "static_assertions",
]
[[package]]
@@ -1142,15 +1034,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-[[package]]
-name = "openssl-src"
-version = "111.24.0+1.1.1s"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "openssl-sys"
version = "0.9.79"
@@ -1160,7 +1043,6 @@ dependencies = [
"autocfg",
"cc",
"libc",
- "openssl-src",
"pkg-config",
"vcpkg",
]
@@ -1177,26 +1059,6 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
-[[package]]
-name = "pin-project"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -1215,20 +1077,6 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
-[[package]]
-name = "polling"
-version = "2.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748"
-dependencies = [
- "autocfg",
- "cfg-if",
- "libc",
- "log",
- "wepoll-ffi",
- "windows-sys 0.42.0",
-]
-
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1253,6 +1101,12 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
[[package]]
name = "proc-macro2"
version = "1.0.47"
@@ -1263,13 +1117,19 @@ dependencies = [
]
[[package]]
-name = "quick-xml"
-version = "0.26.0"
+name = "psl-types"
+version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
+checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
+
+[[package]]
+name = "publicsuffix"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
dependencies = [
- "memchr",
- "serde",
+ "idna 0.3.0",
+ "psl-types",
]
[[package]]
@@ -1341,6 +1201,8 @@ checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [
"base64",
"bytes",
+ "cookie",
+ "cookie_store",
"encoding_rs",
"futures-core",
"futures-util",
@@ -1348,6 +1210,7 @@ dependencies = [
"http",
"http-body",
"hyper",
+ "hyper-rustls",
"hyper-tls",
"ipnet",
"js-sys",
@@ -1357,19 +1220,39 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
+ "proc-macro-hack",
+ "rustls",
+ "rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
+ "tokio-rustls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
+ "webpki-roots",
"winreg",
]
+[[package]]
+name = "ring"
+version = "0.16.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
+dependencies = [
+ "cc",
+ "libc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
[[package]]
name = "rustix"
version = "0.36.5"
@@ -1385,15 +1268,15 @@ dependencies = [
]
[[package]]
-name = "rustls-native-certs"
-version = "0.6.2"
+name = "rustls"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
+checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
dependencies = [
- "openssl-probe",
- "rustls-pemfile",
- "schannel",
- "security-framework",
+ "log",
+ "ring",
+ "sct",
+ "webpki",
]
[[package]]
@@ -1405,12 +1288,6 @@ dependencies = [
"base64",
]
-[[package]]
-name = "rustversion"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
-
[[package]]
name = "ryu"
version = "1.0.11"
@@ -1443,6 +1320,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
+[[package]]
+name = "sct"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+dependencies = [
+ "ring",
+ "untrusted",
+]
+
[[package]]
name = "security-framework"
version = "2.7.0"
@@ -1468,18 +1355,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
+checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.149"
+version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
+checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
dependencies = [
"proc-macro2",
"quote",
@@ -1509,34 +1396,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "serde_with"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef"
-dependencies = [
- "base64",
- "chrono",
- "hex",
- "indexmap",
- "serde",
- "serde_json",
- "serde_with_macros",
- "time 0.3.17",
-]
-
-[[package]]
-name = "serde_with_macros"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa"
-dependencies = [
- "darling",
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "signal-hook"
version = "0.3.14"
@@ -1565,17 +1424,6 @@ dependencies = [
"autocfg",
]
-[[package]]
-name = "sluice"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5"
-dependencies = [
- "async-channel",
- "futures-core",
- "futures-io",
-]
-
[[package]]
name = "smart-default"
version = "0.6.0"
@@ -1597,6 +1445,18 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
[[package]]
name = "strsim"
version = "0.10.0"
@@ -1772,6 +1632,17 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "tokio-rustls"
+version = "0.23.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
+dependencies = [
+ "rustls",
+ "tokio",
+ "webpki",
+]
+
[[package]]
name = "tokio-util"
version = "0.7.4"
@@ -1799,23 +1670,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
- "log",
"pin-project-lite",
- "tracing-attributes",
"tracing-core",
]
-[[package]]
-name = "tracing-attributes"
-version = "0.1.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
[[package]]
name = "tracing-core"
version = "0.1.30"
@@ -1825,16 +1683,6 @@ dependencies = [
"once_cell",
]
-[[package]]
-name = "tracing-futures"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
-dependencies = [
- "pin-project",
- "tracing",
-]
-
[[package]]
name = "try-lock"
version = "0.2.3"
@@ -1874,6 +1722,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
[[package]]
name = "url"
version = "2.3.1"
@@ -1881,7 +1735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
- "idna",
+ "idna 0.3.0",
"percent-encoding",
]
@@ -1897,12 +1751,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-[[package]]
-name = "waker-fn"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
-
[[package]]
name = "want"
version = "0.3.0"
@@ -2002,12 +1850,22 @@ dependencies = [
]
[[package]]
-name = "wepoll-ffi"
-version = "0.1.2"
+name = "webpki"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
+checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
- "cc",
+ "ring",
+ "untrusted",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "0.22.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
+dependencies = [
+ "webpki",
]
[[package]]
@@ -2149,12 +2007,3 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
-
-[[package]]
-name = "xattr"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
-dependencies = [
- "libc",
-]
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index bc34907..bd04867 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -4,35 +4,26 @@ authors = ["Crunchy Labs Maintainers"]
version = "3.0.0-dev.3"
edition = "2021"
-[features]
-static-curl = ["crunchyroll-rs/static-curl"]
-static-ssl = ["crunchyroll-rs/static-ssl"]
-
[dependencies]
anyhow = "1.0"
async-trait = "0.1"
clap = { version = "4.0", features = ["derive", "string"] }
chrono = "0.4"
-crunchyroll-rs = { git = "https://github.com/crunchy-labs/crunchyroll-rs", default-features = false, features = ["parse", "hls-stream", "dash-stream"] }
+crunchyroll-rs = "0.2"
csv = "1.1"
ctrlc = "3.2"
dirs = "4.0"
-isahc = { git = "https://github.com/sagebind/isahc", rev = "c39f6f8" }
log = { version = "0.4", features = ["std"] }
-num_cpus = "1.13"
-regex = "1.6"
+num_cpus = "1.14"
+regex = "1.7"
sanitize-filename = "0.4"
serde = "1.0"
serde_json = "1.0"
signal-hook = "0.3"
tempfile = "3.3"
terminal_size = "0.2"
-tokio = { version = "1.21", features = ["macros", "rt-multi-thread", "time"] }
+tokio = { version = "1.23", features = ["macros", "rt-multi-thread", "time"] }
sys-locale = "0.2"
-[target.'cfg(all(windows, target_env = "msvc"))'.dependencies]
-isahc = { git = "https://github.com/sagebind/isahc", rev = "c39f6f8", features = ["data-encoding"] }
-rustls-native-certs = "0.6"
-
[build-dependencies]
chrono = "0.4"
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index f9bb6a5..5aabbd8 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -332,7 +332,7 @@ async fn formats_from_series(
.locale
.clone()
.into_iter()
- .filter(|l| !season.iter().any(|s| &s.metadata.audio_locale == l))
+ .filter(|l| !season.iter().any(|s| s.metadata.audio_locales.contains(l)))
.collect::>();
for not_present in not_present_audio {
error!(
@@ -346,7 +346,7 @@ async fn formats_from_series(
// remove all seasons with the wrong audio for the current iterated season number
seasons.retain(|s| {
s.metadata.season_number != season.first().unwrap().metadata.season_number
- || archive.locale.contains(&s.metadata.audio_locale)
+ || archive.locale.iter().any(|l| s.metadata.audio_locales.contains(l))
})
}
@@ -355,7 +355,7 @@ async fn formats_from_series(
BTreeMap::new();
for season in series.seasons().await? {
if !url_filter.is_season_valid(season.metadata.season_number)
- || !archive.locale.contains(&season.metadata.audio_locale)
+ || !archive.locale.iter().any(|l| season.metadata.audio_locales.contains(l))
{
continue;
}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index b7093aa..31f8cda 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -290,7 +290,7 @@ async fn formats_from_series(
// check if the current iterated season has the specified audio language
if !season
.iter()
- .any(|s| s.metadata.audio_locale == download.audio)
+ .any(|s| s.metadata.audio_locales.contains(&download.audio))
{
error!(
"Season {} of series {} is not available with {} audio",
@@ -303,7 +303,7 @@ async fn formats_from_series(
// remove all seasons with the wrong audio for the current iterated season number
seasons.retain(|s| {
s.metadata.season_number != season.first().unwrap().metadata.season_number
- || s.metadata.audio_locale == download.audio
+ || s.metadata.audio_locales.contains(&download.audio)
})
}
@@ -322,7 +322,7 @@ async fn formats_from_season(
season: Media,
url_filter: &UrlFilter,
) -> Result>> {
- if season.metadata.audio_locale != download.audio {
+ if !season.metadata.audio_locales.contains(&download.audio) {
error!(
"Season {} ({}) is not available with {} audio",
season.metadata.season_number, season.title, download.audio
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 9b817e4..a64057a 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -1,7 +1,6 @@
use crate::utils::context::Context;
use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
-use isahc::AsyncReadResponseExt;
use log::{debug, LevelFilter};
use std::borrow::{Borrow, BorrowMut};
use std::collections::BTreeMap;
@@ -26,7 +25,7 @@ pub fn find_resolution(
}
pub async fn download_segments(
- _ctx: &Context,
+ ctx: &Context,
writer: &mut impl Write,
message: Option,
variant_data: VariantData,
@@ -34,7 +33,7 @@ pub async fn download_segments(
let segments = variant_data.segments().await?;
let total_segments = segments.len();
- let client = Arc::new(variant_data.download_client());
+ let client = Arc::new(ctx.crunchy.client());
let count = Arc::new(Mutex::new(0));
let amount = Arc::new(Mutex::new(0));
@@ -132,7 +131,7 @@ pub async fn download_segments(
let thread_count = count.clone();
join_set.spawn(async move {
for (i, segment) in thread_segments.into_iter().enumerate() {
- let mut response = thread_client.get_async(&segment.url).await?;
+ let response = thread_client.get(&segment.url).send().await?;
let mut buf = response.bytes().await?.to_vec();
*thread_amount.lock().unwrap() += buf.len();
From d49f2d8eaa9c2a3b88224c3504a5fd2b3013615e Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Fri, 16 Dec 2022 17:09:52 +0200
Subject: [PATCH 027/395] add minimal .gitignore (#83)
* add .gitignore
* more ignore
* newline
* readd .lock
Co-authored-by: Alexandru.Dracea
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 .gitignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5bb2fd7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/.idea
+/target
+/.vscode
From 03fe0c6f01d08ed11e9dde70b622ee655214ce5e Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 16 Dec 2022 21:57:26 +0100
Subject: [PATCH 028/395] Add additional command
---
.github/workflows/ci.yml | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index caef473..3ddf65d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,7 +8,7 @@ on:
workflow_dispatch:
jobs:
- build-nix:
+ build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -16,20 +16,23 @@ jobs:
- os: ubuntu-latest
toolchain: x86_64-unknown-linux-musl
platform: linux
+ command: sudo apt install -y musl
ext:
- os: windows-latest
toolchain: x86_64-pc-windows-gnu
platform: windows
+ command:
ext: .exe
- os: macos-latest
toolchain: x86_64-apple-darwin
platform: darwin
+ command:
ext:
steps:
- name: Checkout
uses: actions/checkout@v3
- - name: Cargo cache # https://github.com/actions/cache/blob/main/examples.md#rust---cargo
+ - name: Cargo cache
uses: actions/cache@v3
with:
path: |
@@ -48,6 +51,9 @@ jobs:
target: ${{ matrix.toolchain }}
default: true
+ - name: Additional command
+ run: ${{ matrix.command }}
+
- name: Test
uses: actions-rs/cargo@v1
with:
From 2451e33639c7449fd5958e6caf4b04099cb2c43f Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 16 Dec 2022 22:07:54 +0100
Subject: [PATCH 029/395] Fix ubuntu musl package
---
.github/workflows/ci.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3ddf65d..fbb064e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
- os: ubuntu-latest
toolchain: x86_64-unknown-linux-musl
platform: linux
- command: sudo apt install -y musl
+ command: sudo apt install -y musl-tools
ext:
- os: windows-latest
toolchain: x86_64-pc-windows-gnu
@@ -43,6 +43,9 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ - name: Additional command
+ run: ${{ matrix.command }}
+
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
@@ -51,9 +54,6 @@ jobs:
target: ${{ matrix.toolchain }}
default: true
- - name: Additional command
- run: ${{ matrix.command }}
-
- name: Test
uses: actions-rs/cargo@v1
with:
From 306019d8b88cc5a1e7fb8a05428c1c80714f3dac Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 16 Dec 2022 23:28:30 +0100
Subject: [PATCH 030/395] Fix linux ci
---
.github/workflows/ci.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fbb064e..0a2047f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -44,6 +44,7 @@ jobs:
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Additional command
+ if: matrix.command != ''
run: ${{ matrix.command }}
- name: Install toolchain
@@ -53,6 +54,7 @@ jobs:
toolchain: stable
target: ${{ matrix.toolchain }}
default: true
+ overwrite: true
- name: Test
uses: actions-rs/cargo@v1
From 5de4a83e5deeab68d9d05b5bb1f400849d400e89 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sat, 17 Dec 2022 17:13:56 +0100
Subject: [PATCH 031/395] Change rust actions used
---
.github/workflows/ci.yml | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0a2047f..eb4c0c0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,17 +16,14 @@ jobs:
- os: ubuntu-latest
toolchain: x86_64-unknown-linux-musl
platform: linux
- command: sudo apt install -y musl-tools
ext:
- os: windows-latest
toolchain: x86_64-pc-windows-gnu
platform: windows
- command:
ext: .exe
- os: macos-latest
toolchain: x86_64-apple-darwin
platform: darwin
- command:
ext:
steps:
- name: Checkout
@@ -43,48 +40,39 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- - name: Additional command
- if: matrix.command != ''
- run: ${{ matrix.command }}
+ - name: Install system dependencies
+ if: matrix.platform == 'linux'
+ run: sudo apt-get install musl-tools
- name: Install toolchain
- uses: actions-rs/toolchain@v1
+ uses: dtolnay/rust-toolchain@stable
with:
- profile: minimal
toolchain: stable
target: ${{ matrix.toolchain }}
- default: true
- overwrite: true
- name: Test
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: --release --all-features
+ run: cargo test --release --all-features --target ${{ matrix.toolchain }}
- name: Build
- uses: actions-rs/cargo@v1
- with:
- command: build
- args: --release --all-features
+ run: cargo build --release --all-features --target ${{ matrix.toolchain }}
- name: Upload binary artifact
uses: actions/upload-artifact@v3
with:
name: crunchy-cli_${{ matrix.platform }}
- path: ./target/release/crunchy-cli${{ matrix.ext }}
+ path: ./target/${{ matrix.toolchain }}/release/crunchy-cli${{ matrix.ext }}
if-no-files-found: error
- name: Upload manpages artifact
uses: actions/upload-artifact@v3
with:
name: manpages
- path: ./target/release/manpages
+ path: ./target/${{ matrix.toolchain }}/release/manpages
if-no-files-found: error
- name: Upload completions artifact
uses: actions/upload-artifact@v3
with:
name: completions
- path: ./target/release/completions
+ path: ./target/${{ matrix.toolchain }}/release/completions
if-no-files-found: error
From 4f107d8cf24854b94615ab4917f9f99b0fbcec29 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 18 Dec 2022 12:51:36 +0100
Subject: [PATCH 032/395] Update version and dependencies
---
Cargo.lock | 94 ++++++++++++++++++-------------------
Cargo.toml | 2 +-
crunchy-cli-core/Cargo.lock | 92 ++++++++++++++++++------------------
crunchy-cli-core/Cargo.toml | 2 +-
4 files changed, 95 insertions(+), 95 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 15acee9..f205883 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,15 +33,15 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.66"
+version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
+checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6"
[[package]]
name = "async-trait"
-version = "0.1.59"
+version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
+checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
dependencies = [
"proc-macro2",
"quote",
@@ -214,9 +214,9 @@ dependencies = [
[[package]]
name = "cookie"
-version = "0.16.1"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [
"percent-encoding",
"time 0.3.17",
@@ -266,7 +266,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.3"
+version = "3.0.0-dev.4"
dependencies = [
"chrono",
"clap",
@@ -278,7 +278,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.3"
+version = "3.0.0-dev.4"
dependencies = [
"anyhow",
"async-trait",
@@ -379,9 +379,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
+checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -391,9 +391,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
+checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0"
dependencies = [
"cc",
"codespan-reporting",
@@ -406,15 +406,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
+checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
+checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49"
dependencies = [
"proc-macro2",
"quote",
@@ -671,7 +671,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.4",
+ "itoa 1.0.5",
]
[[package]]
@@ -712,7 +712,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
- "itoa 1.0.4",
+ "itoa 1.0.5",
"pin-project-lite",
"socket2",
"tokio",
@@ -863,9 +863,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "js-sys"
@@ -890,9 +890,9 @@ checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "link-cplusplus"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
+checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
@@ -1140,9 +1140,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f"
dependencies = [
"unicode-ident",
]
@@ -1165,9 +1165,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8"
dependencies = [
"proc-macro2",
]
@@ -1327,9 +1327,9 @@ dependencies = [
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "sanitize-filename"
@@ -1353,9 +1353,9 @@ dependencies = [
[[package]]
name = "scratch"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
+checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
@@ -1392,18 +1392,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.150"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
+checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.150"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
+checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
dependencies = [
"proc-macro2",
"quote",
@@ -1412,11 +1412,11 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.89"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
+checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf"
dependencies = [
- "itoa 1.0.4",
+ "itoa 1.0.5",
"ryu",
"serde",
]
@@ -1428,7 +1428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa 1.0.4",
+ "itoa 1.0.5",
"ryu",
"serde",
]
@@ -1502,9 +1502,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.105"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
+checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b"
dependencies = [
"proc-macro2",
"quote",
@@ -1559,18 +1559,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1594,7 +1594,7 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [
- "itoa 1.0.4",
+ "itoa 1.0.5",
"serde",
"time-core",
"time-macros",
@@ -1740,9 +1740,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-normalization"
diff --git a/Cargo.toml b/Cargo.toml
index b2af93c..f5f988b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.3"
+version = "3.0.0-dev.4"
edition = "2021"
[dependencies]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index aba7b4a..a85defe 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -33,15 +33,15 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.66"
+version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
+checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6"
[[package]]
name = "async-trait"
-version = "0.1.59"
+version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
+checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
dependencies = [
"proc-macro2",
"quote",
@@ -195,9 +195,9 @@ dependencies = [
[[package]]
name = "cookie"
-version = "0.16.1"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
dependencies = [
"percent-encoding",
"time 0.3.17",
@@ -247,7 +247,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.3"
+version = "3.0.0-dev.4"
dependencies = [
"anyhow",
"async-trait",
@@ -348,9 +348,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
+checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -360,9 +360,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
+checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0"
dependencies = [
"cc",
"codespan-reporting",
@@ -375,15 +375,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
+checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.83"
+version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
+checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49"
dependencies = [
"proc-macro2",
"quote",
@@ -640,7 +640,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.4",
+ "itoa 1.0.5",
]
[[package]]
@@ -681,7 +681,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
- "itoa 1.0.4",
+ "itoa 1.0.5",
"pin-project-lite",
"socket2",
"tokio",
@@ -832,9 +832,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
-version = "1.0.4"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "js-sys"
@@ -859,9 +859,9 @@ checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "link-cplusplus"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
+checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
@@ -1109,9 +1109,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
-version = "1.0.47"
+version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f"
dependencies = [
"unicode-ident",
]
@@ -1134,9 +1134,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8"
dependencies = [
"proc-macro2",
]
@@ -1290,9 +1290,9 @@ dependencies = [
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "sanitize-filename"
@@ -1316,9 +1316,9 @@ dependencies = [
[[package]]
name = "scratch"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
+checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
@@ -1355,18 +1355,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.150"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
+checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.150"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
+checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
dependencies = [
"proc-macro2",
"quote",
@@ -1375,11 +1375,11 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.89"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
+checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf"
dependencies = [
- "itoa 1.0.4",
+ "itoa 1.0.5",
"ryu",
"serde",
]
@@ -1391,7 +1391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa 1.0.4",
+ "itoa 1.0.5",
"ryu",
"serde",
]
@@ -1465,9 +1465,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.105"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
+checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b"
dependencies = [
"proc-macro2",
"quote",
@@ -1522,18 +1522,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.37"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1557,7 +1557,7 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
dependencies = [
- "itoa 1.0.4",
+ "itoa 1.0.5",
"serde",
"time-core",
"time-macros",
@@ -1703,9 +1703,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
-version = "1.0.5"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-normalization"
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index bd04867..6dccd4d 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.3"
+version = "3.0.0-dev.4"
edition = "2021"
[dependencies]
From 4bfc6f22e111ff53b6ad73811bbab692b938331c Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 18 Dec 2022 13:50:20 +0100
Subject: [PATCH 033/395] Fix discord link
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 21f84a6..8008de2 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,8 @@ A [Rust](https://www.rust-lang.org/) written cli client for [Crunchyroll](https:
-
-
+
+
From 67bbc00d87c3fd5c0f64f6ae537a331bc5b54702 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 18 Dec 2022 15:03:16 +0100
Subject: [PATCH 034/395] Add pre-release notice
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 8008de2..bf57145 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,10 @@ A [Rust](https://www.rust-lang.org/) written cli client for [Crunchyroll](https:
> We are in no way affiliated with, maintained, authorized, sponsored, or officially associated with Crunchyroll LLC or any of its subsidiaries or affiliates.
> The official Crunchyroll website can be found at https://crunchyroll.com/.
+> This README belongs to the _master_ branch which is currently under heavy development towards the next major version (3.0).
+> It is mostly stable but some issues may still occur.
+> If you do not want to use an under-development / pre-release version, head over to the _[golang](https://github.com/crunchy-labs/crunchy-cli/tree/golang)_ branch which contains the EOL but last stable version (and documentation for it).
+
## ✨ Features
- Download single videos and entire series from [Crunchyroll](https://www.crunchyroll.com).
From 8bb2c9c7501cf4382d3b0117d55e4f6c7b42d93a Mon Sep 17 00:00:00 2001
From: bytedream
Date: Mon, 19 Dec 2022 15:22:45 +0100
Subject: [PATCH 035/395] Fix file name sanitizing
---
crunchy-cli-core/src/cli/archive.rs | 1 +
crunchy-cli-core/src/cli/download.rs | 1 +
crunchy-cli-core/src/utils/format.rs | 31 ++++++++++++++++++----------
crunchy-cli-core/src/utils/os.rs | 9 +-------
4 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 5aabbd8..a551bd1 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -237,6 +237,7 @@ impl Execute for Archive {
}
.to_string(),
primary,
+ true,
)),
);
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 31f8cda..e13d3f0 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -209,6 +209,7 @@ impl Execute for Download {
}
.to_string(),
&format,
+ true,
)),
);
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index 3dd7f74..b111dce 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -63,15 +63,24 @@ impl Format {
}
}
-pub fn format_string(s: String, format: &Format) -> String {
- s.replace("{title}", &format.title)
- .replace("{series_name}", &format.series_name)
- .replace("{season_name}", &format.season_title)
- .replace("{audio}", &format.audio.to_string())
- .replace("{resolution}", &format.stream.resolution.to_string())
- .replace("{season_number}", &format.season_number.to_string())
- .replace("{episode_number}", &format.number.to_string())
- .replace("{series_id}", &format.series_id)
- .replace("{season_id}", &format.season_id)
- .replace("{episode_id}", &format.id)
+/// Formats the given string if it has specific pattern in it. It's possible to sanitize it which
+/// removes characters which can cause failures if the output string is used as a file name.
+pub fn format_string(s: String, format: &Format, sanitize: bool) -> String {
+ let sanitize_func = if sanitize {
+ |s: &str| sanitize_filename::sanitize(s)
+ } else {
+ // converting this to a string is actually unnecessary
+ |s: &str| s.to_string()
+ };
+
+ s.replace("{title}", &sanitize_func(&format.title))
+ .replace("{series_name}", &sanitize_func(&format.series_name))
+ .replace("{season_name}", &sanitize_func(&format.season_title))
+ .replace("{audio}", &sanitize_func(&format.audio.to_string()))
+ .replace("{resolution}", &sanitize_func(&format.stream.resolution.to_string()))
+ .replace("{season_number}", &sanitize_func(&format.season_number.to_string()))
+ .replace("{episode_number}", &sanitize_func(&format.number.to_string()))
+ .replace("{series_id}", &sanitize_func(&format.series_id))
+ .replace("{season_id}", &sanitize_func(&format.season_id))
+ .replace("{episode_id}", &sanitize_func(&format.id))
}
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index abdf151..01d0f89 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -50,12 +50,5 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
path.set_file_name(format!("{} ({}).{}", filename, i, ext))
}
- sanitize_file(path)
-}
-
-/// Sanitizes the given path to not contain any invalid file character.
-pub fn sanitize_file(path: PathBuf) -> PathBuf {
- path.with_file_name(sanitize_filename::sanitize(
- path.file_name().unwrap().to_string_lossy(),
- ))
+ path
}
From af9aca4d0cfc3608369507766d63ca3e40fe449a Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Mon, 19 Dec 2022 18:35:37 +0200
Subject: [PATCH 036/395] Add padding
---
crunchy-cli-core/src/cli/archive.rs | 22 ++++++++++++----------
crunchy-cli-core/src/cli/download.rs | 22 ++++++++++++----------
crunchy-cli-core/src/utils/format.rs | 23 ++++++++++++++++++++---
3 files changed, 44 insertions(+), 23 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index a551bd1..6e56e81 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -58,16 +58,18 @@ pub struct Archive {
#[arg(help = "Name of the output file")]
#[arg(long_help = "Name of the output file.\
If you use one of the following pattern they will get replaced:\n \
- {title} → Title of the video\n \
- {series_name} → Name of the series\n \
- {season_name} → Name of the season\n \
- {audio} → Audio language of the video\n \
- {resolution} → Resolution of the video\n \
- {season_number} → Number of the season\n \
- {episode_number} → Number of the episode\n \
- {series_id} → ID of the series\n \
- {season_id} → ID of the season\n \
- {episode_id} → ID of the episode")]
+ {title} → Title of the video\n \
+ {series_name} → Name of the series\n \
+ {season_name} → Name of the season\n \
+ {audio} → Audio language of the video\n \
+ {resolution} → Resolution of the video\n \
+ {padded_season_number} → Number of the season padded to double digits\n \
+ {season_number} → Number of the season\n \
+ {padded_episode_number} → Number of the episode padded to double digits\n \
+ {episode_number} → Number of the episode\n \
+ {series_id} → ID of the series\n \
+ {season_id} → ID of the season\n \
+ {episode_id} → ID of the episode")]
#[arg(short, long, default_value = "{title}.mkv")]
output: String,
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index e13d3f0..4e4eb3c 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -36,16 +36,18 @@ pub struct Download {
#[arg(help = "Name of the output file")]
#[arg(long_help = "Name of the output file.\
If you use one of the following pattern they will get replaced:\n \
- {title} → Title of the video\n \
- {series_name} → Name of the series\n \
- {season_name} → Name of the season\n \
- {audio} → Audio language of the video\n \
- {resolution} → Resolution of the video\n \
- {season_number} → Number of the season\n \
- {episode_number} → Number of the episode\n \
- {series_id} → ID of the series\n \
- {season_id} → ID of the season\n \
- {episode_id} → ID of the episode")]
+ {title} → Title of the video\n \
+ {series_name} → Name of the series\n \
+ {season_name} → Name of the season\n \
+ {audio} → Audio language of the video\n \
+ {resolution} → Resolution of the video\n \
+ {padded_season_number} → Number of the season padded to double digits\n \
+ {season_number} → Number of the season\n \
+ {padded_episode_number} → Number of the episode padded to double digits\n \
+ {episode_number} → Number of the episode\n \
+ {series_id} → ID of the series\n \
+ {season_id} → ID of the season\n \
+ {episode_id} → ID of the episode")]
#[arg(short, long, default_value = "{title}.ts")]
output: String,
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index b111dce..c463ea8 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -77,9 +77,26 @@ pub fn format_string(s: String, format: &Format, sanitize: bool) -> String {
.replace("{series_name}", &sanitize_func(&format.series_name))
.replace("{season_name}", &sanitize_func(&format.season_title))
.replace("{audio}", &sanitize_func(&format.audio.to_string()))
- .replace("{resolution}", &sanitize_func(&format.stream.resolution.to_string()))
- .replace("{season_number}", &sanitize_func(&format.season_number.to_string()))
- .replace("{episode_number}", &sanitize_func(&format.number.to_string()))
+ .replace(
+ "{resolution}",
+ &sanitize_func(&format.stream.resolution.to_string()),
+ )
+ .replace(
+ "{padded_season_number}",
+ &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
+ )
+ .replace(
+ "{season_number}",
+ &sanitize_func(&format.season_number.to_string()),
+ )
+ .replace(
+ "{padded_episode_number}",
+ &sanitize_func(&format!("{:0>2}", format.number.to_string())),
+ )
+ .replace(
+ "{episode_number}",
+ &sanitize_func(&format.number.to_string()),
+ )
.replace("{series_id}", &sanitize_func(&format.series_id))
.replace("{season_id}", &sanitize_func(&format.season_id))
.replace("{episode_id}", &sanitize_func(&format.id))
From 17fa045c32e103a13535a819dad4da6b6731347a Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 22 Dec 2022 14:45:56 +0100
Subject: [PATCH 037/395] Use library for progress
---
Cargo.lock | 130 ++++++++++++++++++---------
crunchy-cli-core/Cargo.lock | 130 ++++++++++++++++++---------
crunchy-cli-core/Cargo.toml | 1 +
crunchy-cli-core/src/cli/archive.rs | 33 ++++---
crunchy-cli-core/src/cli/download.rs | 28 +++---
crunchy-cli-core/src/cli/log.rs | 130 +++++++--------------------
crunchy-cli-core/src/cli/utils.rs | 127 +++++++++-----------------
crunchy-cli-core/src/lib.rs | 6 +-
crunchy-cli-core/src/utils/log.rs | 17 +++-
9 files changed, 307 insertions(+), 295 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index f205883..a7432c8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,9 +33,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "async-trait"
@@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.0.29"
+version = "4.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
+checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2"
dependencies = [
"bitflags",
"clap_derive",
@@ -212,6 +212,20 @@ dependencies = [
"unicode-width",
]
+[[package]]
+name = "console"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "terminal_size 0.1.17",
+ "unicode-width",
+ "winapi",
+]
+
[[package]]
name = "cookie"
version = "0.16.2"
@@ -288,6 +302,7 @@ dependencies = [
"csv",
"ctrlc",
"dirs",
+ "indicatif",
"log",
"num_cpus",
"regex",
@@ -297,7 +312,7 @@ dependencies = [
"signal-hook",
"sys-locale",
"tempfile",
- "terminal_size",
+ "terminal_size 0.2.3",
"tokio",
]
@@ -379,9 +394,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0"
+checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -391,9 +406,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0"
+checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
dependencies = [
"cc",
"codespan-reporting",
@@ -406,15 +421,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4"
+checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49"
+checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
dependencies = [
"proc-macro2",
"quote",
@@ -476,6 +491,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
[[package]]
name = "encoding_rs"
version = "0.8.31"
@@ -645,15 +666,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "hermit-abi"
version = "0.2.6"
@@ -808,6 +820,18 @@ dependencies = [
"hashbrown",
]
+[[package]]
+name = "indicatif"
+version = "0.17.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4295cbb7573c16d310e99e713cf9e75101eb190ab31fccd35f2d2691b4352b19"
+dependencies = [
+ "console",
+ "number_prefix",
+ "portable-atomic",
+ "unicode-width",
+]
+
[[package]]
name = "inout"
version = "0.1.3"
@@ -845,11 +869,11 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "is-terminal"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
+checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
- "hermit-abi 0.2.6",
+ "hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys 0.42.0",
@@ -1019,14 +1043,20 @@ dependencies = [
[[package]]
name = "num_cpus"
-version = "1.14.0"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
- "hermit-abi 0.1.19",
+ "hermit-abi",
"libc",
]
+[[package]]
+name = "number_prefix"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
+
[[package]]
name = "once_cell"
version = "1.16.0"
@@ -1035,9 +1065,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "openssl"
-version = "0.10.44"
+version = "0.10.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566"
+checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1"
dependencies = [
"bitflags",
"cfg-if",
@@ -1067,9 +1097,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
-version = "0.9.79"
+version = "0.9.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4"
+checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
dependencies = [
"autocfg",
"cc",
@@ -1108,6 +1138,12 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+[[package]]
+name = "portable-atomic"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92"
+
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1134,15 +1170,15 @@ dependencies = [
[[package]]
name = "proc-macro-hack"
-version = "0.5.19"
+version = "0.5.20+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
-version = "1.0.48"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
@@ -1165,9 +1201,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.22"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -1412,9 +1448,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.90"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa 1.0.5",
"ryu",
@@ -1502,9 +1538,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.106"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@@ -1547,6 +1583,16 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "terminal_size"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "terminal_size"
version = "0.2.3"
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index a85defe..8347aa7 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -33,9 +33,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6"
+checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "async-trait"
@@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.0.29"
+version = "4.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
+checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2"
dependencies = [
"bitflags",
"clap_derive",
@@ -193,6 +193,20 @@ dependencies = [
"unicode-width",
]
+[[package]]
+name = "console"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "terminal_size 0.1.17",
+ "unicode-width",
+ "winapi",
+]
+
[[package]]
name = "cookie"
version = "0.16.2"
@@ -257,6 +271,7 @@ dependencies = [
"csv",
"ctrlc",
"dirs",
+ "indicatif",
"log",
"num_cpus",
"regex",
@@ -266,7 +281,7 @@ dependencies = [
"signal-hook",
"sys-locale",
"tempfile",
- "terminal_size",
+ "terminal_size 0.2.3",
"tokio",
]
@@ -348,9 +363,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27874566aca772cb515af4c6e997b5fe2119820bca447689145e39bb734d19a0"
+checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -360,9 +375,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7bb951f2523a49533003656a72121306b225ec16a49a09dc6b0ba0d6f3ec3c0"
+checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
dependencies = [
"cc",
"codespan-reporting",
@@ -375,15 +390,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be778b6327031c1c7b61dd2e48124eee5361e6aa76b8de93692f011b08870ab4"
+checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.84"
+version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b8a2b87662fe5a0a0b38507756ab66aff32638876a0866e5a5fc82ceb07ee49"
+checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
dependencies = [
"proc-macro2",
"quote",
@@ -445,6 +460,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
[[package]]
name = "encoding_rs"
version = "0.8.31"
@@ -614,15 +635,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "hermit-abi"
version = "0.2.6"
@@ -777,6 +789,18 @@ dependencies = [
"hashbrown",
]
+[[package]]
+name = "indicatif"
+version = "0.17.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4295cbb7573c16d310e99e713cf9e75101eb190ab31fccd35f2d2691b4352b19"
+dependencies = [
+ "console",
+ "number_prefix",
+ "portable-atomic",
+ "unicode-width",
+]
+
[[package]]
name = "inout"
version = "0.1.3"
@@ -814,11 +838,11 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "is-terminal"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
+checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
- "hermit-abi 0.2.6",
+ "hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys 0.42.0",
@@ -988,14 +1012,20 @@ dependencies = [
[[package]]
name = "num_cpus"
-version = "1.14.0"
+version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
- "hermit-abi 0.1.19",
+ "hermit-abi",
"libc",
]
+[[package]]
+name = "number_prefix"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
+
[[package]]
name = "once_cell"
version = "1.16.0"
@@ -1004,9 +1034,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "openssl"
-version = "0.10.44"
+version = "0.10.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d971fd5722fec23977260f6e81aa67d2f22cadbdc2aa049f1022d9a3be1566"
+checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1"
dependencies = [
"bitflags",
"cfg-if",
@@ -1036,9 +1066,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
-version = "0.9.79"
+version = "0.9.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5454462c0eced1e97f2ec09036abc8da362e66802f66fd20f86854d9d8cbcbc4"
+checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
dependencies = [
"autocfg",
"cc",
@@ -1077,6 +1107,12 @@ version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+[[package]]
+name = "portable-atomic"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92"
+
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -1103,15 +1139,15 @@ dependencies = [
[[package]]
name = "proc-macro-hack"
-version = "0.5.19"
+version = "0.5.20+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
-version = "1.0.48"
+version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f"
+checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
@@ -1134,9 +1170,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.22"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@@ -1375,9 +1411,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.90"
+version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf"
+checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa 1.0.5",
"ryu",
@@ -1465,9 +1501,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.106"
+version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b"
+checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@@ -1510,6 +1546,16 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "terminal_size"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "terminal_size"
version = "0.2.3"
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 6dccd4d..780716f 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -13,6 +13,7 @@ crunchyroll-rs = "0.2"
csv = "1.1"
ctrlc = "3.2"
dirs = "4.0"
+indicatif = "0.17"
log = { version = "0.4", features = ["std"] }
num_cpus = "1.14"
regex = "1.7"
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 6e56e81..b5244f7 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution};
+use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -137,7 +137,9 @@ impl Execute for Archive {
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
- if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia {
+ if self.ffmpeg_preset.len() == 1
+ && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia
+ {
warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
}
@@ -148,20 +150,20 @@ impl Execute for Archive {
let mut parsed_urls = vec![];
for (i, url) in self.urls.iter().enumerate() {
- let _progress_handler = progress!("Parsing url {}", i + 1);
+ let progress_handler = progress!("Parsing url {}", i + 1);
match parse_url(&ctx.crunchy, url.clone(), true).await {
Ok((media_collection, url_filter)) => {
parsed_urls.push((media_collection, url_filter));
- info!("Parsed url {}", i + 1)
+ progress_handler.stop(format!("Parsed url {}", i + 1))
}
Err(e) => bail!("url {} could not be parsed: {}", url, e),
}
}
for (i, (media_collection, url_filter)) in parsed_urls.into_iter().enumerate() {
+ let progress_handler = progress!("Fetching series details");
let archive_formats = match media_collection {
MediaCollection::Series(series) => {
- let _progress_handler = progress!("Fetching series details");
formats_from_series(&self, series, &url_filter).await?
}
MediaCollection::Season(_) => bail!("Archiving a season is not supported"),
@@ -171,10 +173,13 @@ impl Execute for Archive {
};
if archive_formats.is_empty() {
- info!("Skipping url {} (no matching episodes found)", i + 1);
+ progress_handler.stop(format!(
+ "Skipping url {} (no matching episodes found)",
+ i + 1
+ ));
continue;
}
- info!("Loaded series information for url {}", i + 1);
+ progress_handler.stop(format!("Loaded series information for url {}", i + 1));
if log::max_level() == log::Level::Debug {
let seasons = sort_formats_after_seasons(
@@ -310,9 +315,9 @@ impl Execute for Archive {
))
}
- let _progess_handler = progress!("Generating mkv");
+ let progess_handler = progress!("Generating mkv");
generate_mkv(&self, path, video_paths, audio_paths, subtitle_paths)?;
- info!("Mkv generated")
+ progess_handler.stop("Mkv generated")
}
}
@@ -349,7 +354,10 @@ async fn formats_from_series(
// remove all seasons with the wrong audio for the current iterated season number
seasons.retain(|s| {
s.metadata.season_number != season.first().unwrap().metadata.season_number
- || archive.locale.iter().any(|l| s.metadata.audio_locales.contains(l))
+ || archive
+ .locale
+ .iter()
+ .any(|l| s.metadata.audio_locales.contains(l))
})
}
@@ -358,7 +366,10 @@ async fn formats_from_series(
BTreeMap::new();
for season in series.seasons().await? {
if !url_filter.is_season_valid(season.metadata.season_number)
- || !archive.locale.iter().any(|l| season.metadata.audio_locales.contains(l))
+ || !archive
+ .locale
+ .iter()
+ .any(|l| season.metadata.audio_locales.contains(l))
{
continue;
}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 4e4eb3c..d8a4ada 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, FFmpegPreset, find_resolution};
+use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -92,7 +92,9 @@ impl Execute for Download {
}
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
- if self.ffmpeg_preset.len() == 1 && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia {
+ if self.ffmpeg_preset.len() == 1
+ && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia
+ {
warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
}
@@ -103,18 +105,18 @@ impl Execute for Download {
let mut parsed_urls = vec![];
for (i, url) in self.urls.iter().enumerate() {
- let _progress_handler = progress!("Parsing url {}", i + 1);
+ let progress_handler = progress!("Parsing url {}", i + 1);
match parse_url(&ctx.crunchy, url.clone(), true).await {
Ok((media_collection, url_filter)) => {
parsed_urls.push((media_collection, url_filter));
- info!("Parsed url {}", i + 1)
+ progress_handler.stop(format!("Parsed url {}", i + 1))
}
Err(e) => bail!("url {} could not be parsed: {}", url, e),
}
}
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 formats = match media_collection {
MediaCollection::Series(series) => {
debug!("Url {} is series ({})", i + 1, series.title);
@@ -156,11 +158,10 @@ impl Execute for Download {
};
let Some(formats) = formats else {
- info!("Skipping url {} (no matching episodes found)", i + 1);
+ progress_handler.stop(format!("Skipping url {} (no matching episodes found)", i + 1));
continue;
};
- info!("Loaded series information for url {}", i + 1);
- drop(_progress_handler);
+ progress_handler.stop(format!("Loaded series information for url {}", i + 1));
if log::max_level() == log::Level::Debug {
let seasons = sort_formats_after_seasons(formats.clone());
@@ -231,7 +232,9 @@ impl Execute for Download {
tab_info!("Resolution: {}", format.stream.resolution);
tab_info!("FPS: {:.2}", format.stream.fps);
- if path.extension().unwrap_or_default().to_string_lossy() != "ts" || !self.ffmpeg_preset.is_empty() {
+ if path.extension().unwrap_or_default().to_string_lossy() != "ts"
+ || !self.ffmpeg_preset.is_empty()
+ {
download_ffmpeg(&ctx, &self, format.stream, path.as_path()).await?;
} else if path.to_str().unwrap() == "-" {
let mut stdout = std::io::stdout().lock();
@@ -247,7 +250,12 @@ impl Execute for Download {
}
}
-async fn download_ffmpeg(ctx: &Context, download: &Download, variant_data: VariantData, target: &Path) -> Result<()> {
+async fn download_ffmpeg(
+ ctx: &Context,
+ download: &Download,
+ variant_data: VariantData,
+ target: &Path,
+) -> Result<()> {
let (input_presets, output_presets) =
FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
diff --git a/crunchy-cli-core/src/cli/log.rs b/crunchy-cli-core/src/cli/log.rs
index d1f0225..377685b 100644
--- a/crunchy-cli-core/src/cli/log.rs
+++ b/crunchy-cli-core/src/cli/log.rs
@@ -1,106 +1,17 @@
+use indicatif::{ProgressBar, ProgressStyle};
use log::{
set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError,
};
use std::io::{stdout, Write};
-use std::sync::{mpsc, Mutex};
+use std::sync::Mutex;
use std::thread;
-use std::thread::JoinHandle;
use std::time::Duration;
-struct CliProgress {
- handler: JoinHandle<()>,
- sender: mpsc::SyncSender<(String, Level)>,
-}
-
-impl CliProgress {
- fn new(record: &Record) -> Self {
- let (tx, rx) = mpsc::sync_channel(1);
-
- let init_message = format!("{}", record.args());
- let init_level = record.level();
- let handler = thread::spawn(move || {
- #[cfg(not(windows))]
- let ok = '✔';
- #[cfg(windows)]
- // windows does not support all unicode characters by default in their consoles, so
- // we're using this (square root?) symbol instead. microsoft.
- let ok = '√';
- let states = ["-", "\\", "|", "/"];
-
- let mut old_message = init_message.clone();
- let mut latest_info_message = init_message;
- let mut old_level = init_level;
- for i in 0.. {
- let (msg, level) = match rx.try_recv() {
- Ok(payload) => payload,
- Err(e) => match e {
- mpsc::TryRecvError::Empty => (old_message.clone(), old_level),
- mpsc::TryRecvError::Disconnected => break,
- },
- };
-
- // clear last line
- // prefix (2), space (1), state (1), space (1), message(n)
- let _ = write!(stdout(), "\r {}", " ".repeat(old_message.len()));
-
- if old_level != level || old_message != msg {
- if old_level <= Level::Warn {
- let _ = writeln!(stdout(), "\r:: • {}", old_message);
- } else if old_level == Level::Info && level <= Level::Warn {
- let _ = writeln!(stdout(), "\r:: → {}", old_message);
- } else if level == Level::Info {
- latest_info_message = msg.clone();
- }
- }
-
- let _ = write!(
- stdout(),
- "\r:: {} {}",
- states[i / 2 % states.len()],
- if level == Level::Info {
- &msg
- } else {
- &latest_info_message
- }
- );
- let _ = stdout().flush();
-
- old_message = msg;
- old_level = level;
-
- thread::sleep(Duration::from_millis(100));
- }
-
- // clear last line
- // prefix (2), space (1), state (1), space (1), message(n)
- let _ = write!(stdout(), "\r {}", " ".repeat(old_message.len()));
- let _ = writeln!(stdout(), "\r:: {} {}", ok, old_message);
- let _ = stdout().flush();
- });
-
- Self {
- handler,
- sender: tx,
- }
- }
-
- fn send(&self, record: &Record) {
- let _ = self
- .sender
- .send((format!("{}", record.args()), record.level()));
- }
-
- fn stop(self) {
- drop(self.sender);
- let _ = self.handler.join();
- }
-}
-
#[allow(clippy::type_complexity)]
pub struct CliLogger {
all: bool,
level: LevelFilter,
- progress: Mutex>,
+ progress: Mutex >,
}
impl Log for CliLogger {
@@ -127,7 +38,7 @@ impl Log for CliLogger {
"progress_end" => self.progress(record, true),
_ => {
if self.progress.lock().unwrap().is_some() {
- self.progress(record, false);
+ self.progress(record, false)
} else if record.level() > Level::Warn {
self.normal(record)
} else {
@@ -182,13 +93,34 @@ impl CliLogger {
}
fn progress(&self, record: &Record, stop: bool) {
- let mut progress_option = self.progress.lock().unwrap();
- if stop && progress_option.is_some() {
- progress_option.take().unwrap().stop()
- } else if let Some(p) = &*progress_option {
- p.send(record);
+ let mut progress = self.progress.lock().unwrap();
+
+ let msg = format!("{}", record.args());
+ if stop && progress.is_some() {
+ if msg.is_empty() {
+ progress.take().unwrap().finish()
+ } else {
+ progress.take().unwrap().finish_with_message(msg)
+ }
+ } else if let Some(p) = &*progress {
+ p.println(format!(":: → {}", msg))
} else {
- *progress_option = Some(CliProgress::new(record))
+ #[cfg(not(windows))]
+ let finish_str = "✔";
+ #[cfg(windows)]
+ // windows does not support all unicode characters by default in their consoles, so
+ // we're using this (square root?) symbol instead. microsoft.
+ let finish_str = "√";
+
+ let pb = ProgressBar::new_spinner();
+ pb.set_style(
+ ProgressStyle::with_template(":: {spinner} {msg}")
+ .unwrap()
+ .tick_strings(&["-", "\\", "|", "/", finish_str]),
+ );
+ pb.enable_steady_tick(Duration::from_millis(200));
+ pb.set_message(msg);
+ *progress = Some(pb)
}
}
}
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index a64057a..6045ce4 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -1,13 +1,12 @@
use crate::utils::context::Context;
use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
+use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use log::{debug, LevelFilter};
use std::borrow::{Borrow, BorrowMut};
use std::collections::BTreeMap;
-use std::io;
use std::io::Write;
use std::sync::{mpsc, Arc, Mutex};
-use std::time::Duration;
use tokio::task::JoinSet;
pub fn find_resolution(
@@ -35,78 +34,25 @@ pub async fn download_segments(
let client = Arc::new(ctx.crunchy.client());
let count = Arc::new(Mutex::new(0));
- let amount = Arc::new(Mutex::new(0));
- // only print progress when log level is info
- let output_handler = if log::max_level() == LevelFilter::Info {
- let output_count = count.clone();
- let output_amount = amount.clone();
- Some(tokio::spawn(async move {
- let sleep_time_ms = 100;
- let iter_per_sec = 1000f64 / sleep_time_ms as f64;
+ let progress = if log::max_level() == LevelFilter::Info {
+ let estimated_file_size = (variant_data.bandwidth / 8)
+ * segments
+ .iter()
+ .map(|s| s.length.unwrap_or_default().as_secs())
+ .sum::();
- let mut bytes_start = 0f64;
- let mut speed = 0f64;
- let mut percentage = 0f64;
-
- while *output_count.lock().unwrap() < total_segments || percentage < 100f64 {
- let tmp_amount = *output_amount.lock().unwrap() as f64;
-
- let tmp_speed = (tmp_amount - bytes_start) / 1024f64 / 1024f64;
- if *output_count.lock().unwrap() < 3 {
- speed = tmp_speed;
- } else {
- let (old_speed_ratio, new_speed_ratio) = if iter_per_sec <= 1f64 {
- (0f64, 1f64)
- } else {
- (1f64 - (1f64 / iter_per_sec), (1f64 / iter_per_sec))
- };
-
- // calculate the average download speed "smoother"
- speed = (speed * old_speed_ratio) + (tmp_speed * new_speed_ratio);
- }
-
- percentage =
- (*output_count.lock().unwrap() as f64 / total_segments as f64) * 100f64;
-
- let size = terminal_size::terminal_size()
- .unwrap_or((terminal_size::Width(60), terminal_size::Height(0)))
- .0
- .0 as usize;
-
- // there is a offset of 1 "length" (idk how to describe it), so removing 1 from
- // `progress_available` would fill the terminal width completely. on multiple
- // systems there is a bug that printing until the end of the line causes a newline
- // even though technically there shouldn't be one. on my tests, this only happens on
- // windows and mac machines and (at the addressed environments) only with release
- // builds. so maybe an unwanted optimization?
- let progress_available = size
- - if let Some(msg) = &message {
- 35 + msg.len()
- } else {
- 34
- };
- let progress_done_count =
- (progress_available as f64 * (percentage / 100f64)).ceil() as usize;
- let progress_to_do_count = progress_available - progress_done_count;
-
- let _ = write!(
- io::stdout(),
- "\r:: {}{:>5.1} MiB {:>5.2} MiB/s [{}{}] {:>3}%",
- message.clone().map_or("".to_string(), |msg| msg + " "),
- tmp_amount / 1024f64 / 1024f64,
- speed * iter_per_sec,
- "#".repeat(progress_done_count),
- "-".repeat(progress_to_do_count),
- percentage as usize
- );
-
- bytes_start = tmp_amount;
-
- tokio::time::sleep(Duration::from_millis(sleep_time_ms)).await;
- }
- println!()
- }))
+ let progress = ProgressBar::new(estimated_file_size)
+ .with_style(
+ ProgressStyle::with_template(
+ ":: {msg}{bytes:>10} {bytes_per_sec:>12} [{wide_bar}] {percent:>3}%",
+ )
+ .unwrap()
+ .progress_chars("##-"),
+ )
+ .with_message(message.map(|m| m + " ").unwrap_or_default())
+ .with_finish(ProgressFinish::Abandon);
+ Some(progress)
} else {
None
};
@@ -116,7 +62,7 @@ pub async fn download_segments(
for _ in 0..cpus {
segs.push(vec![])
}
- for (i, segment) in segments.into_iter().enumerate() {
+ for (i, segment) in segments.clone().into_iter().enumerate() {
segs[i - ((i / cpus) * cpus)].push(segment);
}
@@ -127,15 +73,12 @@ pub async fn download_segments(
let thread_client = client.clone();
let thread_sender = sender.clone();
let thread_segments = segs.remove(0);
- let thread_amount = amount.clone();
let thread_count = count.clone();
join_set.spawn(async move {
for (i, segment) in thread_segments.into_iter().enumerate() {
let response = thread_client.get(&segment.url).send().await?;
let mut buf = response.bytes().await?.to_vec();
- *thread_amount.lock().unwrap() += buf.len();
-
buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
debug!(
"Downloaded and decrypted segment {} ({})",
@@ -155,13 +98,28 @@ pub async fn download_segments(
let mut buf: BTreeMap> = BTreeMap::new();
loop {
// is always `Some` because `sender` does not get dropped when all threads are finished
- let data = receiver.recv().unwrap();
+ let (pos, bytes) = receiver.recv().unwrap();
- if data_pos == data.0 {
- writer.write_all(data.1.borrow())?;
+ if let Some(p) = &progress {
+ let progress_len = p.length().unwrap();
+ let estimated_segment_len = (variant_data.bandwidth / 8)
+ * segments
+ .get(pos)
+ .unwrap()
+ .length
+ .unwrap_or_default()
+ .as_secs();
+ let bytes_len = bytes.len() as u64;
+
+ p.set_length(progress_len - estimated_segment_len + bytes_len);
+ p.inc(bytes_len)
+ }
+
+ if data_pos == pos {
+ writer.write_all(bytes.borrow())?;
data_pos += 1;
} else {
- buf.insert(data.0, data.1);
+ buf.insert(pos, bytes);
}
while let Some(b) = buf.remove(&data_pos) {
writer.write_all(b.borrow())?;
@@ -176,9 +134,6 @@ pub async fn download_segments(
while let Some(joined) = join_set.join_next().await {
joined??
}
- if let Some(handler) = output_handler {
- handler.await?
- }
Ok(())
}
@@ -200,7 +155,7 @@ impl ToString for FFmpegPreset {
&FFmpegPreset::H265 => "h265",
&FFmpegPreset::H264 => "h264",
}
- .to_string()
+ .to_string()
}
}
@@ -233,7 +188,9 @@ impl FFmpegPreset {
})
}
- pub(crate) fn ffmpeg_presets(mut presets: Vec) -> Result<(Vec, Vec)> {
+ pub(crate) fn ffmpeg_presets(
+ mut presets: Vec,
+ ) -> Result<(Vec, Vec)> {
fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool {
if let Some(i) = presets.iter().position(|p| p == &preset) {
presets.remove(i);
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index d669b64..00699e4 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -6,7 +6,7 @@ use anyhow::bail;
use anyhow::Result;
use clap::{Parser, Subcommand};
use crunchyroll_rs::{Crunchyroll, Locale};
-use log::{debug, error, info, LevelFilter};
+use log::{debug, error, LevelFilter};
use std::{env, fs};
mod cli;
@@ -196,7 +196,7 @@ async fn crunchyroll_session(cli: &Cli) -> Result {
+ cli.login_method.etp_rt.is_some() as u8
+ cli.login_method.anonymous as u8;
- let _progress_handler = progress!("Logging in");
+ let progress_handler = progress!("Logging in");
if login_methods_count == 0 {
if let Some(login_file_path) = cli::login::login_file_path() {
if login_file_path.exists() {
@@ -232,7 +232,7 @@ async fn crunchyroll_session(cli: &Cli) -> Result {
bail!("should never happen")
};
- info!("Logged in");
+ progress_handler.stop("Logged in");
Ok(crunchy)
}
diff --git a/crunchy-cli-core/src/utils/log.rs b/crunchy-cli-core/src/utils/log.rs
index b9fa939..24fed5d 100644
--- a/crunchy-cli-core/src/utils/log.rs
+++ b/crunchy-cli-core/src/utils/log.rs
@@ -1,10 +1,21 @@
use log::info;
-pub struct ProgressHandler;
+pub struct ProgressHandler {
+ pub(crate) stopped: bool,
+}
impl Drop for ProgressHandler {
fn drop(&mut self) {
- info!(target: "progress_end", "")
+ if !self.stopped {
+ info!(target: "progress_end", "")
+ }
+ }
+}
+
+impl ProgressHandler {
+ pub(crate) fn stop>(mut self, msg: S) {
+ self.stopped = true;
+ info!(target: "progress_end", "{}", msg.as_ref())
}
}
@@ -12,7 +23,7 @@ macro_rules! progress {
($($arg:tt)+) => {
{
log::info!(target: "progress", $($arg)+);
- $crate::utils::log::ProgressHandler{}
+ $crate::utils::log::ProgressHandler{stopped: false}
}
}
}
From 2c3bd78fc1a03450d792733820dddf0d8da92368 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 27 Dec 2022 20:37:45 +0100
Subject: [PATCH 038/395] Leave special files untouched from renaming
---
crunchy-cli-core/src/utils/os.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index 01d0f89..e3320fb 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -37,6 +37,12 @@ pub fn tempfile>(suffix: S) -> io::Result {
/// Check if the given path exists and rename it until the new (renamed) file does not exist.
pub fn free_file(mut path: PathBuf) -> PathBuf {
+ // if path is not a file and not a dir it's probably a pipe on linux which reguarly is intended
+ // and thus does not need to be renamed. what it is on windows ¯\_(ツ)_/¯
+ if !path.is_file() && !path.is_dir() {
+ return path;
+ }
+
let mut i = 0;
while path.exists() {
i += 1;
From c37e2495e1e66d9ee7a5d17d3570dcb5f081e137 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 27 Dec 2022 20:49:53 +0100
Subject: [PATCH 039/395] Create output parent directory if it doesn't exists
(#91)
---
crunchy-cli-core/src/cli/archive.rs | 7 +++++++
crunchy-cli-core/src/cli/download.rs | 13 +++++++++++++
2 files changed, 20 insertions(+)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index b5244f7..70240cf 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -647,6 +647,13 @@ fn generate_mkv(
debug!("ffmpeg {}", command_args.join(" "));
+ // create parent directory if it does not exist
+ if let Some(parent) = target.parent() {
+ if !parent.exists() {
+ std::fs::create_dir_all(parent)?
+ }
+ }
+
let ffmpeg = Command::new("ffmpeg")
.stdout(Stdio::null())
.stderr(Stdio::piped())
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index d8a4ada..99da758 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -240,6 +240,12 @@ impl Execute for Download {
let mut stdout = std::io::stdout().lock();
download_segments(&ctx, &mut stdout, None, format.stream).await?;
} else {
+ // create parent directory if it does not exist
+ if let Some(parent) = path.parent() {
+ if !parent.exists() {
+ std::fs::create_dir_all(parent)?
+ }
+ }
let mut file = File::options().create(true).write(true).open(&path)?;
download_segments(&ctx, &mut file, None, format.stream).await?
}
@@ -259,6 +265,13 @@ async fn download_ffmpeg(
let (input_presets, output_presets) =
FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
+ // create parent directory if it does not exist
+ if let Some(parent) = target.parent() {
+ if !parent.exists() {
+ std::fs::create_dir_all(parent)?
+ }
+ }
+
let mut ffmpeg = Command::new("ffmpeg")
.stdin(Stdio::piped())
.stdout(Stdio::null())
From 14f42833cb5257e0f9ef10f4b243c0ec51cbf28e Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 27 Dec 2022 22:59:35 +0100
Subject: [PATCH 040/395] Fix output to special file (pipes etc.)
---
crunchy-cli-core/src/cli/archive.rs | 9 +++++++--
crunchy-cli-core/src/cli/download.rs | 27 ++++++++++++++++++++++-----
crunchy-cli-core/src/utils/os.rs | 13 +++++++++----
3 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 70240cf..e3d5520 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -3,7 +3,7 @@ use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
-use crate::utils::os::{free_file, has_ffmpeg, tempfile};
+use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
use crate::Execute;
@@ -133,6 +133,7 @@ impl Execute for Archive {
.unwrap_or_default()
.to_string_lossy()
!= "mkv"
+ && !is_special_file(PathBuf::from(&self.output))
{
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
@@ -251,7 +252,11 @@ impl Execute for Archive {
info!(
"Downloading {} to '{}'",
primary.title,
- path.to_str().unwrap()
+ if is_special_file(&path) {
+ path.to_str().unwrap()
+ } else {
+ path.file_name().unwrap().to_str().unwrap()
+ }
);
tab_info!(
"Episode: S{:02}E{:02}",
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 99da758..0411a5e 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -3,7 +3,7 @@ use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
-use crate::utils::os::{free_file, has_ffmpeg};
+use crate::utils::os::{free_file, has_ffmpeg, is_special_file};
use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
use crate::Execute;
@@ -219,7 +219,11 @@ impl Execute for Download {
info!(
"Downloading {} to '{}'",
format.title,
- path.file_name().unwrap().to_str().unwrap()
+ if is_special_file(&path) {
+ path.to_str().unwrap()
+ } else {
+ path.file_name().unwrap().to_str().unwrap()
+ }
);
tab_info!("Episode: S{:02}E{:02}", format.season_number, format.number);
tab_info!("Audio: {}", format.audio);
@@ -232,9 +236,9 @@ impl Execute for Download {
tab_info!("Resolution: {}", format.stream.resolution);
tab_info!("FPS: {:.2}", format.stream.fps);
- if path.extension().unwrap_or_default().to_string_lossy() != "ts"
- || !self.ffmpeg_preset.is_empty()
- {
+ let extension = path.extension().unwrap_or_default().to_string_lossy();
+
+ if (!extension.is_empty() && extension != "ts") || !self.ffmpeg_preset.is_empty() {
download_ffmpeg(&ctx, &self, format.stream, path.as_path()).await?;
} else if path.to_str().unwrap() == "-" {
let mut stdout = std::io::stdout().lock();
@@ -279,6 +283,19 @@ async fn download_ffmpeg(
.arg("-y")
.args(input_presets)
.args(["-f", "mpegts", "-i", "pipe:"])
+ .args(
+ if target
+ .extension()
+ .unwrap_or_default()
+ .to_string_lossy()
+ .is_empty()
+ {
+ vec!["-f", "mpegts"]
+ } else {
+ vec![]
+ }
+ .as_slice(),
+ )
.args(output_presets)
.arg(target.to_str().unwrap())
.spawn()?;
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index e3320fb..d2d4c3c 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -1,6 +1,6 @@
use log::debug;
use std::io::ErrorKind;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{env, io};
use tempfile::{Builder, NamedTempFile};
@@ -37,9 +37,8 @@ pub fn tempfile>(suffix: S) -> io::Result {
/// Check if the given path exists and rename it until the new (renamed) file does not exist.
pub fn free_file(mut path: PathBuf) -> PathBuf {
- // if path is not a file and not a dir it's probably a pipe on linux which reguarly is intended
- // and thus does not need to be renamed. what it is on windows ¯\_(ツ)_/¯
- if !path.is_file() && !path.is_dir() {
+ // if it's a special file does not rename it
+ if is_special_file(&path) {
return path;
}
@@ -58,3 +57,9 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
}
path
}
+
+/// Check if the given path is a special file. On Linux this is probably a pipe and on Windows
+/// ¯\_(ツ)_/¯
+pub fn is_special_file>(path: P) -> bool {
+ path.as_ref().exists() && !path.as_ref().is_file() && !path.as_ref().is_dir()
+}
From c5940a240c8b2a6c39d6b3033ea6b5f6ee761335 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 28 Dec 2022 02:18:17 +0100
Subject: [PATCH 041/395] Slightly change download process to be more verbose
in error situations
---
crunchy-cli-core/src/cli/utils.rs | 37 ++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 6045ce4..1f6bf40 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -93,13 +93,16 @@ pub async fn download_segments(
Ok(())
});
}
+ // drop the sender already here so it does not outlive all (download) threads which are the only
+ // real consumers of it
+ drop(sender);
+ // this is the main loop which writes the data. it uses a BTreeMap as a buffer as the write
+ // happens synchronized. the download consist of multiple segments. the map keys are representing
+ // the segment number and the values the corresponding bytes
let mut data_pos = 0usize;
let mut buf: BTreeMap> = BTreeMap::new();
- loop {
- // is always `Some` because `sender` does not get dropped when all threads are finished
- let (pos, bytes) = receiver.recv().unwrap();
-
+ for (pos, bytes) in receiver.iter() {
if let Some(p) = &progress {
let progress_len = p.length().unwrap();
let estimated_segment_len = (variant_data.bandwidth / 8)
@@ -115,26 +118,44 @@ pub async fn download_segments(
p.inc(bytes_len)
}
+ // check if the currently sent bytes are the next in the buffer. if so, write them directly
+ // to the target without first adding them to the buffer.
+ // if not, add them to the buffer
if data_pos == pos {
writer.write_all(bytes.borrow())?;
data_pos += 1;
} else {
buf.insert(pos, bytes);
}
+ // check if the buffer contains the next segment(s)
while let Some(b) = buf.remove(&data_pos) {
writer.write_all(b.borrow())?;
data_pos += 1;
}
-
- if *count.lock().unwrap() >= total_segments && buf.is_empty() {
- break;
- }
}
+ // write the remaining buffer, if existent
+ while let Some(b) = buf.remove(&data_pos) {
+ writer.write_all(b.borrow())?;
+ data_pos += 1;
+ }
+
+ // if any error has occured while downloading it gets returned here. maybe a little late, if one
+ // out of, for example 12, threads has the error
while let Some(joined) = join_set.join_next().await {
joined??
}
+ if !buf.is_empty() {
+ bail!(
+ "Download buffer is not empty. Remaining segments: {}",
+ buf.into_keys()
+ .map(|k| k.to_string())
+ .collect::>()
+ .join(", ")
+ )
+ }
+
Ok(())
}
From 240e5563a3db767fccccfe523af74a8d862f5da0 Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Wed, 28 Dec 2022 15:44:45 +0200
Subject: [PATCH 042/395] Add error handling and retry attempts
Handles cases where the segments fail to download and sometimes get stuck by introducing a timeout and retrying on failure.
---
crunchy-cli-core/src/cli/utils.rs | 51 +++++++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 1f6bf40..3d14318 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -76,8 +76,55 @@ pub async fn download_segments(
let thread_count = count.clone();
join_set.spawn(async move {
for (i, segment) in thread_segments.into_iter().enumerate() {
- let response = thread_client.get(&segment.url).send().await?;
- let mut buf = response.bytes().await?.to_vec();
+ let response_res = thread_client
+ .get(&segment.url)
+ .timeout(Duration::from_secs(60u64))
+ .send()
+ .await;
+ let verfified_response = match response_res {
+ Ok(x) => x,
+ Err(y) => panic!("This is likely a netowrking error: {}", y),
+ };
+ let possible_error_in_response = verfified_response.bytes().await;
+ let mut buf = if let Ok(r) = possible_error_in_response {
+ r.to_vec()
+ } else {
+ debug!(
+ "Segment Failed to download: {}, retrying.",
+ num + (i * cpus)
+ );
+ let mut resp = thread_client
+ .get(&segment.url)
+ .timeout(Duration::from_secs(60u64))
+ .send()
+ .await
+ .unwrap()
+ .bytes()
+ .await;
+ if resp.is_err() {
+ let mut retry_ctr = 1;
+ loop {
+ debug!(
+ "Segment Failed to download: {}, retry {}.",
+ num + (i * cpus),
+ retry_ctr
+ );
+ resp = thread_client
+ .get(&segment.url)
+ .timeout(Duration::from_secs(60u64))
+ .send()
+ .await
+ .unwrap()
+ .bytes()
+ .await;
+ if resp.is_ok() {
+ break;
+ }
+ retry_ctr += 1;
+ }
+ }
+ resp.unwrap().to_vec()
+ };
buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
debug!(
From 8a3c0132e7e0ec4206d001670fd062bcf9673052 Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Wed, 28 Dec 2022 15:59:55 +0200
Subject: [PATCH 043/395] Update utils.rs
---
crunchy-cli-core/src/cli/utils.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 3d14318..afc431f 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -3,7 +3,8 @@ use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use log::{debug, LevelFilter};
-use std::borrow::{Borrow, BorrowMut};
+use std::borrow::Borrow;
+use std::time::Duration;
use std::collections::BTreeMap;
use std::io::Write;
use std::sync::{mpsc, Arc, Mutex};
From c2ae622d01c1913ff51264858a4c6b0f28353690 Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Wed, 28 Dec 2022 16:01:55 +0200
Subject: [PATCH 044/395] Update utils.rs
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index afc431f..cd45859 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -3,7 +3,7 @@ use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use log::{debug, LevelFilter};
-use std::borrow::Borrow;
+use std::borrow::{Borrow, BorrowMut};
use std::time::Duration;
use std::collections::BTreeMap;
use std::io::Write;
From d0681c7f6cc01caa684b39f30c459a20d5f09c24 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 28 Dec 2022 15:18:12 +0100
Subject: [PATCH 045/395] Simplify retry segment download
---
crunchy-cli-core/src/cli/utils.rs | 62 ++++++++++---------------------
1 file changed, 19 insertions(+), 43 deletions(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index cd45859..7c32e86 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -4,10 +4,10 @@ use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use log::{debug, LevelFilter};
use std::borrow::{Borrow, BorrowMut};
-use std::time::Duration;
use std::collections::BTreeMap;
use std::io::Write;
use std::sync::{mpsc, Arc, Mutex};
+use std::time::Duration;
use tokio::task::JoinSet;
pub fn find_resolution(
@@ -77,54 +77,30 @@ pub async fn download_segments(
let thread_count = count.clone();
join_set.spawn(async move {
for (i, segment) in thread_segments.into_iter().enumerate() {
- let response_res = thread_client
- .get(&segment.url)
- .timeout(Duration::from_secs(60u64))
- .send()
- .await;
- let verfified_response = match response_res {
- Ok(x) => x,
- Err(y) => panic!("This is likely a netowrking error: {}", y),
- };
- let possible_error_in_response = verfified_response.bytes().await;
- let mut buf = if let Ok(r) = possible_error_in_response {
- r.to_vec()
- } else {
- debug!(
- "Segment Failed to download: {}, retrying.",
- num + (i * cpus)
- );
- let mut resp = thread_client
+ let mut retry_count = 0;
+ let mut buf = loop {
+ let response = thread_client
.get(&segment.url)
- .timeout(Duration::from_secs(60u64))
+ .timeout(Duration::from_secs(10))
.send()
.await
- .unwrap()
- .bytes()
- .await;
- if resp.is_err() {
- let mut retry_ctr = 1;
- loop {
- debug!(
- "Segment Failed to download: {}, retry {}.",
- num + (i * cpus),
- retry_ctr
- );
- resp = thread_client
- .get(&segment.url)
- .timeout(Duration::from_secs(60u64))
- .send()
- .await
- .unwrap()
- .bytes()
- .await;
- if resp.is_ok() {
- break;
+ .unwrap();
+
+ match response.bytes().await {
+ Ok(b) => break b.to_vec(),
+ Err(e) => {
+ if e.is_body() {
+ if retry_count == 5 {
+ panic!("Max retry count reached ({}), multiple errors occured while receiving segment {}: {}", retry_count, num + (i * cpus), e)
+ }
+ debug!("Failed to download segment {}. Retrying ({} out of 5 retries left)", num + (i * cpus), 5 - retry_count)
+ } else {
+ panic!("{}", e)
}
- retry_ctr += 1;
}
}
- resp.unwrap().to_vec()
+
+ retry_count += 1;
};
buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
From 7115c5546d1c71c496c26b82d85b2f1aaf114aca Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 28 Dec 2022 15:25:10 +0100
Subject: [PATCH 046/395] Show error message on segment download retry
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 7c32e86..e2bbc63 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -93,7 +93,7 @@ pub async fn download_segments(
if retry_count == 5 {
panic!("Max retry count reached ({}), multiple errors occured while receiving segment {}: {}", retry_count, num + (i * cpus), e)
}
- debug!("Failed to download segment {}. Retrying ({} out of 5 retries left)", num + (i * cpus), 5 - retry_count)
+ debug!("Failed to download segment {} ({}). Retrying, {} out of 5 retries left", num + (i * cpus), e, 5 - retry_count)
} else {
panic!("{}", e)
}
From b8e46099f9035c609b376c2cfa1b0d28719564c9 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 28 Dec 2022 15:35:38 +0100
Subject: [PATCH 047/395] Re-increase segment request timeout
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index e2bbc63..841dbef 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -81,7 +81,7 @@ pub async fn download_segments(
let mut buf = loop {
let response = thread_client
.get(&segment.url)
- .timeout(Duration::from_secs(10))
+ .timeout(Duration::from_secs(60))
.send()
.await
.unwrap();
From 03db38b31ce85f7264fe90d259c09e7ad3ee8679 Mon Sep 17 00:00:00 2001
From: ByteDream <63594396+ByteDream@users.noreply.github.com>
Date: Wed, 28 Dec 2022 15:45:33 +0100
Subject: [PATCH 048/395] Add debug segment percentage (#93)
* Fix file extension unwrap panic
* Change log output name from crunchy_cli_core to crunchy_cli
* Add percentage output
---
crunchy-cli-core/src/cli/log.rs | 5 +++--
crunchy-cli-core/src/cli/utils.rs | 8 ++++++--
crunchy-cli-core/src/utils/os.rs | 4 ++--
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/crunchy-cli-core/src/cli/log.rs b/crunchy-cli-core/src/cli/log.rs
index 377685b..3f63eb0 100644
--- a/crunchy-cli-core/src/cli/log.rs
+++ b/crunchy-cli-core/src/cli/log.rs
@@ -75,8 +75,9 @@ impl CliLogger {
// replace the 'progress' prefix if this function is invoked via 'progress!'
record
.target()
- .replacen("progress", "crunchy_cli", 1)
- .replacen("progress_end", "crunchy_cli", 1),
+ .replacen("crunchy_cli_core", "crunchy_cli", 1)
+ .replacen("progress_end", "crunchy_cli", 1)
+ .replacen("progress", "crunchy_cli", 1),
format!("{:?}", thread::current().id())
.replace("ThreadId(", "")
.replace(')', ""),
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 6045ce4..4c8c10e 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -80,14 +80,18 @@ pub async fn download_segments(
let mut buf = response.bytes().await?.to_vec();
buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
+
+ let mut c = thread_count.lock().unwrap();
debug!(
- "Downloaded and decrypted segment {} ({})",
+ "Downloaded and decrypted segment [{}/{} {:.2}%] {}",
num + (i * cpus),
+ total_segments,
+ ((*c + 1) as f64 / total_segments as f64) * 100f64,
segment.url
);
thread_sender.send((num + (i * cpus), buf))?;
- *thread_count.lock().unwrap() += 1;
+ *c += 1;
}
Ok(())
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index d2d4c3c..a7b3fbf 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -46,8 +46,8 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
while path.exists() {
i += 1;
- let ext = path.extension().unwrap().to_string_lossy();
- let mut filename = path.file_stem().unwrap().to_str().unwrap();
+ let ext = path.extension().unwrap_or_default().to_string_lossy();
+ let mut filename = path.file_stem().unwrap_or_default().to_str().unwrap();
if filename.ends_with(&format!(" ({})", i - 1)) {
filename = filename.strip_suffix(&format!(" ({})", i - 1)).unwrap();
From 0c139420165e412516313d612124dd62fe2b117f Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 2 Jan 2023 17:53:54 +0100
Subject: [PATCH 049/395] Update dependencies
---
Cargo.lock | 69 ++++++++++++++++---------------------
crunchy-cli-core/Cargo.lock | 61 ++++++++++++++------------------
2 files changed, 56 insertions(+), 74 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index a7432c8..8221757 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.0.30"
+version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"bitflags",
"clap_derive",
@@ -163,9 +163,9 @@ dependencies = [
[[package]]
name = "clap_complete"
-version = "4.0.6"
+version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da"
+checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [
"clap",
]
@@ -194,9 +194,9 @@ dependencies = [
[[package]]
name = "clap_mangen"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e503c3058af0a0854668ea01db55c622482a080092fede9dd2e00a00a9436504"
+checksum = "904eb24d05ad587557e0f484ddce5c737c30cf81372badb16d13e41c4b8340b1"
dependencies = [
"clap",
"roff",
@@ -214,16 +214,15 @@ dependencies = [
[[package]]
name = "console"
-version = "0.15.2"
+version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+checksum = "5556015fe3aad8b968e5d4124980fbe2f6aaee7aeec6b749de1faaa2ca5d0a4c"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
- "terminal_size 0.1.17",
"unicode-width",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -312,21 +311,23 @@ dependencies = [
"signal-hook",
"sys-locale",
"tempfile",
- "terminal_size 0.2.3",
+ "terminal_size",
"tokio",
]
[[package]]
name = "crunchyroll-rs"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5032be36dc6c4757af4f28152659e7a772b48f6925f0e0ac81b5c384e291314"
+checksum = "5ea0bc79ecd9fafc95c6049d0b38e0e00c8d4665314ae3ee675db67b622ce3b7"
dependencies = [
"aes",
+ "async-trait",
"cbc",
"chrono",
"crunchyroll-rs-internal",
"http",
+ "lazy_static",
"m3u8-rs",
"regex",
"reqwest",
@@ -341,9 +342,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e4aa1f09fd76f44329455abfac35e22c654ac782e93bc8a7d3ee1be27509f4"
+checksum = "66be957a34f7498e4bc324af67c58bb7ace299c214c9353281545f92dbc45d78"
dependencies = [
"darling",
"quote",
@@ -908,9 +909,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.138"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "link-cplusplus"
@@ -1014,9 +1015,9 @@ dependencies = [
[[package]]
name = "nom"
-version = "7.1.1"
+version = "7.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
dependencies = [
"memchr",
"minimal-lexical",
@@ -1059,9 +1060,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "openssl"
@@ -1140,9 +1141,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "portable-atomic"
-version = "0.3.18"
+version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92"
+checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b"
[[package]]
name = "proc-macro-error"
@@ -1328,9 +1329,9 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]]
name = "rustix"
-version = "0.36.5"
+version = "0.36.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
+checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
dependencies = [
"bitflags",
"errno",
@@ -1428,18 +1429,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.151"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.151"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -1583,16 +1584,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "terminal_size"
-version = "0.1.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
-dependencies = [
- "libc",
- "winapi",
-]
-
[[package]]
name = "terminal_size"
version = "0.2.3"
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 8347aa7..6a805d3 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.0.30"
+version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2"
+checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"bitflags",
"clap_derive",
@@ -195,16 +195,15 @@ dependencies = [
[[package]]
name = "console"
-version = "0.15.2"
+version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
+checksum = "5556015fe3aad8b968e5d4124980fbe2f6aaee7aeec6b749de1faaa2ca5d0a4c"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
- "terminal_size 0.1.17",
"unicode-width",
- "winapi",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -281,21 +280,23 @@ dependencies = [
"signal-hook",
"sys-locale",
"tempfile",
- "terminal_size 0.2.3",
+ "terminal_size",
"tokio",
]
[[package]]
name = "crunchyroll-rs"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5032be36dc6c4757af4f28152659e7a772b48f6925f0e0ac81b5c384e291314"
+checksum = "5ea0bc79ecd9fafc95c6049d0b38e0e00c8d4665314ae3ee675db67b622ce3b7"
dependencies = [
"aes",
+ "async-trait",
"cbc",
"chrono",
"crunchyroll-rs-internal",
"http",
+ "lazy_static",
"m3u8-rs",
"regex",
"reqwest",
@@ -310,9 +311,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e4aa1f09fd76f44329455abfac35e22c654ac782e93bc8a7d3ee1be27509f4"
+checksum = "66be957a34f7498e4bc324af67c58bb7ace299c214c9353281545f92dbc45d78"
dependencies = [
"darling",
"quote",
@@ -877,9 +878,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.138"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "link-cplusplus"
@@ -983,9 +984,9 @@ dependencies = [
[[package]]
name = "nom"
-version = "7.1.1"
+version = "7.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c"
dependencies = [
"memchr",
"minimal-lexical",
@@ -1028,9 +1029,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "openssl"
@@ -1109,9 +1110,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "portable-atomic"
-version = "0.3.18"
+version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81bdd679d533107e090c2704a35982fc06302e30898e63ffa26a81155c012e92"
+checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b"
[[package]]
name = "proc-macro-error"
@@ -1291,9 +1292,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.36.5"
+version = "0.36.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
+checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
dependencies = [
"bitflags",
"errno",
@@ -1391,18 +1392,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.151"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.151"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -1546,16 +1547,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "terminal_size"
-version = "0.1.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
-dependencies = [
- "libc",
- "winapi",
-]
-
[[package]]
name = "terminal_size"
version = "0.2.3"
From fae5d699331fcb9ced5856f0ab521982edc0fb76 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 2 Jan 2023 17:56:50 +0100
Subject: [PATCH 050/395] Apply stabilizations fixes (#89)
---
crunchy-cli-core/src/lib.rs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 00699e4..4f2ce32 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -189,8 +189,9 @@ async fn create_ctx(cli: &Cli) -> Result {
}
async fn crunchyroll_session(cli: &Cli) -> Result {
- let mut builder = Crunchyroll::builder();
- builder.locale(cli.lang.clone().unwrap_or_else(system_locale));
+ let mut builder = Crunchyroll::builder()
+ .locale(cli.lang.clone().unwrap_or_else(system_locale))
+ .stabilization_locales(true);
let login_methods_count = cli.login_method.credentials.is_some() as u8
+ cli.login_method.etp_rt.is_some() as u8
From 3c3b7b65662e4f315ff34634d2c7b92a2445a212 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 3 Jan 2023 01:24:17 +0100
Subject: [PATCH 051/395] Fix panic on specific filenames
---
crunchy-cli-core/src/utils/os.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index d2d4c3c..a7b3fbf 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -46,8 +46,8 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
while path.exists() {
i += 1;
- let ext = path.extension().unwrap().to_string_lossy();
- let mut filename = path.file_stem().unwrap().to_str().unwrap();
+ let ext = path.extension().unwrap_or_default().to_string_lossy();
+ let mut filename = path.file_stem().unwrap_or_default().to_str().unwrap();
if filename.ends_with(&format!(" ({})", i - 1)) {
filename = filename.strip_suffix(&format!(" ({})", i - 1)).unwrap();
From b365bda5dca57754a383bdb3de0484f600c9697c Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 3 Jan 2023 01:28:42 +0100
Subject: [PATCH 052/395] Fix download threads to properly return errors
---
crunchy-cli-core/src/cli/utils.rs | 93 ++++++++++++++++++-------------
1 file changed, 53 insertions(+), 40 deletions(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 841dbef..99d4f67 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -74,47 +74,56 @@ pub async fn download_segments(
let thread_client = client.clone();
let thread_sender = sender.clone();
let thread_segments = segs.remove(0);
- let thread_count = count.clone();
join_set.spawn(async move {
- for (i, segment) in thread_segments.into_iter().enumerate() {
- let mut retry_count = 0;
- let mut buf = loop {
- let response = thread_client
- .get(&segment.url)
- .timeout(Duration::from_secs(60))
- .send()
- .await
- .unwrap();
+ let after_download_sender = thread_sender.clone();
- match response.bytes().await {
- Ok(b) => break b.to_vec(),
- Err(e) => {
- if e.is_body() {
- if retry_count == 5 {
- panic!("Max retry count reached ({}), multiple errors occured while receiving segment {}: {}", retry_count, num + (i * cpus), e)
+ // the download process is encapsulated in its own function. this is done to easily
+ // catch errors which get returned with `...?` and `bail!(...)` and that the thread
+ // itself can report that an error has occured
+ let download = || async move {
+ for (i, segment) in thread_segments.into_iter().enumerate() {
+ let mut retry_count = 0;
+ let mut buf = loop {
+ let response = thread_client
+ .get(&segment.url)
+ .timeout(Duration::from_secs(60))
+ .send()
+ .await?;
+
+ match response.bytes().await {
+ Ok(b) => break b.to_vec(),
+ Err(e) => {
+ if e.is_body() {
+ if retry_count == 5 {
+ bail!("Max retry count reached ({}), multiple errors occured while receiving segment {}: {}", retry_count, num + (i * cpus), e)
+ }
+ debug!("Failed to download segment {} ({}). Retrying, {} out of 5 retries left", num + (i * cpus), e, 5 - retry_count)
+ } else {
+ bail!("{}", e)
}
- debug!("Failed to download segment {} ({}). Retrying, {} out of 5 retries left", num + (i * cpus), e, 5 - retry_count)
- } else {
- panic!("{}", e)
}
}
- }
- retry_count += 1;
- };
+ retry_count += 1;
+ };
- buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
- debug!(
- "Downloaded and decrypted segment {} ({})",
- num + (i * cpus),
- segment.url
- );
- thread_sender.send((num + (i * cpus), buf))?;
+ buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
+ debug!(
+ "Downloaded and decrypted segment {} ({})",
+ num + (i * cpus),
+ segment.url
+ );
+ thread_sender.send((num as i32 + (i * cpus) as i32, buf))?;
+ }
+ Ok(())
+ };
- *thread_count.lock().unwrap() += 1;
+ let result = download().await;
+ if result.is_err() {
+ after_download_sender.send((-1 as i32, vec![]))?;
}
- Ok(())
+ result
});
}
// drop the sender already here so it does not outlive all (download) threads which are the only
@@ -124,14 +133,19 @@ pub async fn download_segments(
// this is the main loop which writes the data. it uses a BTreeMap as a buffer as the write
// happens synchronized. the download consist of multiple segments. the map keys are representing
// the segment number and the values the corresponding bytes
- let mut data_pos = 0usize;
- let mut buf: BTreeMap> = BTreeMap::new();
+ let mut data_pos = 0;
+ let mut buf: BTreeMap> = BTreeMap::new();
for (pos, bytes) in receiver.iter() {
+ // if the position is lower than 0, an error occured in the sending download thread
+ if pos < 0 {
+ break
+ }
+
if let Some(p) = &progress {
let progress_len = p.length().unwrap();
let estimated_segment_len = (variant_data.bandwidth / 8)
* segments
- .get(pos)
+ .get(pos as usize)
.unwrap()
.length
.unwrap_or_default()
@@ -158,18 +172,17 @@ pub async fn download_segments(
}
}
+ // if any error has occured while downloading it gets returned here
+ while let Some(joined) = join_set.join_next().await {
+ joined??
+ }
+
// write the remaining buffer, if existent
while let Some(b) = buf.remove(&data_pos) {
writer.write_all(b.borrow())?;
data_pos += 1;
}
- // if any error has occured while downloading it gets returned here. maybe a little late, if one
- // out of, for example 12, threads has the error
- while let Some(joined) = join_set.join_next().await {
- joined??
- }
-
if !buf.is_empty() {
bail!(
"Download buffer is not empty. Remaining segments: {}",
From 29c6129e6efbb18a1ac1ae7cbbc46893e4870603 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 3 Jan 2023 14:50:12 +0100
Subject: [PATCH 053/395] Update dependencies & version
---
Cargo.lock | 16 ++++++++--------
Cargo.toml | 2 +-
crunchy-cli-core/Cargo.lock | 14 +++++++-------
crunchy-cli-core/Cargo.toml | 2 +-
crunchy-cli-core/src/lib.rs | 2 +-
5 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8221757..a564687 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -214,9 +214,9 @@ dependencies = [
[[package]]
name = "console"
-version = "0.15.3"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5556015fe3aad8b968e5d4124980fbe2f6aaee7aeec6b749de1faaa2ca5d0a4c"
+checksum = "c9b6515d269224923b26b5febea2ed42b2d5f2ce37284a4dd670fedd6cb8347a"
dependencies = [
"encode_unicode",
"lazy_static",
@@ -279,7 +279,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.4"
+version = "3.0.0-dev.5"
dependencies = [
"chrono",
"clap",
@@ -291,7 +291,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.4"
+version = "3.0.0-dev.5"
dependencies = [
"anyhow",
"async-trait",
@@ -317,9 +317,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea0bc79ecd9fafc95c6049d0b38e0e00c8d4665314ae3ee675db67b622ce3b7"
+checksum = "f8ec300b509afbd8977f71cd7feb7d0f20d38d8e38976b7fcd51f6128cbdefe6"
dependencies = [
"aes",
"async-trait",
@@ -342,9 +342,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66be957a34f7498e4bc324af67c58bb7ace299c214c9353281545f92dbc45d78"
+checksum = "10d4b870818d5ce0993d70271bf803dbfbcc8a3a0fa7398b182f5f4b4e88509d"
dependencies = [
"darling",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index f5f988b..c67d599 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.4"
+version = "3.0.0-dev.5"
edition = "2021"
[dependencies]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 6a805d3..37ee2c3 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -195,9 +195,9 @@ dependencies = [
[[package]]
name = "console"
-version = "0.15.3"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5556015fe3aad8b968e5d4124980fbe2f6aaee7aeec6b749de1faaa2ca5d0a4c"
+checksum = "c9b6515d269224923b26b5febea2ed42b2d5f2ce37284a4dd670fedd6cb8347a"
dependencies = [
"encode_unicode",
"lazy_static",
@@ -260,7 +260,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.4"
+version = "3.0.0-dev.5"
dependencies = [
"anyhow",
"async-trait",
@@ -286,9 +286,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ea0bc79ecd9fafc95c6049d0b38e0e00c8d4665314ae3ee675db67b622ce3b7"
+checksum = "f8ec300b509afbd8977f71cd7feb7d0f20d38d8e38976b7fcd51f6128cbdefe6"
dependencies = [
"aes",
"async-trait",
@@ -311,9 +311,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66be957a34f7498e4bc324af67c58bb7ace299c214c9353281545f92dbc45d78"
+checksum = "10d4b870818d5ce0993d70271bf803dbfbcc8a3a0fa7398b182f5f4b4e88509d"
dependencies = [
"darling",
"quote",
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 780716f..e61031b 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.4"
+version = "3.0.0-dev.5"
edition = "2021"
[dependencies]
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 4f2ce32..52a4da1 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -189,7 +189,7 @@ async fn create_ctx(cli: &Cli) -> Result {
}
async fn crunchyroll_session(cli: &Cli) -> Result {
- let mut builder = Crunchyroll::builder()
+ let builder = Crunchyroll::builder()
.locale(cli.lang.clone().unwrap_or_else(system_locale))
.stabilization_locales(true);
From d0a8103e3def5a45c84bf7eafe2c8b43f8c7b98d Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 4 Jan 2023 00:12:13 +0100
Subject: [PATCH 054/395] Update dependencies & version
---
Cargo.lock | 12 ++++++------
Cargo.toml | 2 +-
crunchy-cli-core/Cargo.lock | 10 +++++-----
crunchy-cli-core/Cargo.toml | 4 ++--
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index a564687..8da4e30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -279,7 +279,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.5"
+version = "3.0.0-dev.6"
dependencies = [
"chrono",
"clap",
@@ -291,7 +291,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.5"
+version = "3.0.0-dev.6"
dependencies = [
"anyhow",
"async-trait",
@@ -317,9 +317,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8ec300b509afbd8977f71cd7feb7d0f20d38d8e38976b7fcd51f6128cbdefe6"
+checksum = "dd742baacdfbf9caca8656262ac2397c334928ccd65fb332c95ee8e8b8d9223d"
dependencies = [
"aes",
"async-trait",
@@ -342,9 +342,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10d4b870818d5ce0993d70271bf803dbfbcc8a3a0fa7398b182f5f4b4e88509d"
+checksum = "aadb66f2b5cdcc8b82f095aec6ca92ca4abb30016a13916f2358cf7bfd8a1997"
dependencies = [
"darling",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index c67d599..76ed950 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.5"
+version = "3.0.0-dev.6"
edition = "2021"
[dependencies]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 37ee2c3..af1086a 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -260,7 +260,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.5"
+version = "3.0.0-dev.6"
dependencies = [
"anyhow",
"async-trait",
@@ -286,9 +286,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8ec300b509afbd8977f71cd7feb7d0f20d38d8e38976b7fcd51f6128cbdefe6"
+checksum = "dd742baacdfbf9caca8656262ac2397c334928ccd65fb332c95ee8e8b8d9223d"
dependencies = [
"aes",
"async-trait",
@@ -311,9 +311,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10d4b870818d5ce0993d70271bf803dbfbcc8a3a0fa7398b182f5f4b4e88509d"
+checksum = "aadb66f2b5cdcc8b82f095aec6ca92ca4abb30016a13916f2358cf7bfd8a1997"
dependencies = [
"darling",
"quote",
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index e61031b..566b8c4 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.5"
+version = "3.0.0-dev.6"
edition = "2021"
[dependencies]
@@ -15,7 +15,7 @@ ctrlc = "3.2"
dirs = "4.0"
indicatif = "0.17"
log = { version = "0.4", features = ["std"] }
-num_cpus = "1.14"
+num_cpus = "1.15"
regex = "1.7"
sanitize-filename = "0.4"
serde = "1.0"
From 7726287859482f508dc584be405db7022ee31b22 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 4 Jan 2023 01:28:14 +0100
Subject: [PATCH 055/395] :)
---
Cargo.lock | 8 ++++----
crunchy-cli-core/Cargo.lock | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8da4e30..eb7c6a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -317,9 +317,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd742baacdfbf9caca8656262ac2397c334928ccd65fb332c95ee8e8b8d9223d"
+checksum = "184d0c725a09aec815316cbf41a2f362008ecb0e8c8e3b6b9930d01a89b5df21"
dependencies = [
"aes",
"async-trait",
@@ -342,9 +342,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aadb66f2b5cdcc8b82f095aec6ca92ca4abb30016a13916f2358cf7bfd8a1997"
+checksum = "5f3c82e1766339727fc2c10d66d0c4f001b1cf42e2993f9d93997b610f408776"
dependencies = [
"darling",
"quote",
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index af1086a..b5dd8a1 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -286,9 +286,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd742baacdfbf9caca8656262ac2397c334928ccd65fb332c95ee8e8b8d9223d"
+checksum = "184d0c725a09aec815316cbf41a2f362008ecb0e8c8e3b6b9930d01a89b5df21"
dependencies = [
"aes",
"async-trait",
@@ -311,9 +311,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aadb66f2b5cdcc8b82f095aec6ca92ca4abb30016a13916f2358cf7bfd8a1997"
+checksum = "5f3c82e1766339727fc2c10d66d0c4f001b1cf42e2993f9d93997b610f408776"
dependencies = [
"darling",
"quote",
From 404aa496e157162c35c3b5bf983cbc43c8689676 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Thu, 5 Jan 2023 22:28:23 +0100
Subject: [PATCH 056/395] Fix subtitle look and feel typo
---
crunchy-cli-core/src/cli/archive.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index e3d5520..3910d24 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -481,7 +481,7 @@ fn fix_subtitle_look_and_feel(raw: Vec) -> Vec {
for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
if line.trim().starts_with('[') && script_info {
- new.push_str("ScaledBorderAndShadows: yes\n");
+ new.push_str("ScaledBorderAndShadow: yes\n");
script_info = false
} else if line.trim() == "[Script Info]" {
script_info = true
From 892407d1f069b1dfcaa71c4eeca1c942ff40872c Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 6 Jan 2023 00:03:57 +0100
Subject: [PATCH 057/395] Fix --default-subtitle causing no such file error
(#98)
---
crunchy-cli-core/src/cli/archive.rs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 3910d24..3eb92a7 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -632,10 +632,10 @@ fn generate_mkv(
if let Some(default_subtitle) = &archive.default_subtitle {
// if `--default_subtitle ` is given set the default subtitle to the given locale
if let Some(position) = subtitle_paths
- .into_iter()
- .position(|s| &s.1.locale == default_subtitle)
+ .iter()
+ .position(|(_, subtitle)| &subtitle.locale == default_subtitle)
{
- command_args.push(format!("-disposition:s:{}", position))
+ command_args.extend([format!("-disposition:s:{}", position), "default".to_string()])
} else {
command_args.extend(["-disposition:s:0".to_string(), "0".to_string()])
}
From 06fd9a7a98989aa4a2c84c120b96b0477f9cf150 Mon Sep 17 00:00:00 2001
From: Hannes Braun
Date: Wed, 4 Jan 2023 22:09:31 +0100
Subject: [PATCH 058/395] Archive subtitles of all versions of an episode
---
crunchy-cli-core/src/cli/archive.rs | 95 +++++++++++++++++++-------
crunchy-cli-core/src/utils/mod.rs | 1 +
crunchy-cli-core/src/utils/subtitle.rs | 11 +++
3 files changed, 82 insertions(+), 25 deletions(-)
create mode 100644 crunchy-cli-core/src/utils/subtitle.rs
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 3eb92a7..8259ab3 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -6,6 +6,7 @@ use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
+use crate::utils::subtitle::Subtitle;
use crate::Execute;
use anyhow::{bail, Result};
use chrono::NaiveTime;
@@ -232,7 +233,7 @@ impl Execute for Archive {
}
}
- for (formats, subtitles) in archive_formats {
+ for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
let mut path = PathBuf::from(&self.output);
@@ -276,13 +277,14 @@ impl Execute for Archive {
"Subtitle: {}",
subtitles
.iter()
+ .filter(|s| s.primary) // Don't print subtitles of non-primary streams. They might get removed depending on the merge behavior.
.map(|s| {
if let Some(default) = &self.default_subtitle {
- if default == &s.locale {
+ if default == &s.stream_subtitle.locale {
return format!("{} (primary)", default);
}
}
- s.locale.to_string()
+ s.stream_subtitle.locale.to_string()
})
.collect::>()
.join(", ")
@@ -309,13 +311,23 @@ impl Execute for Archive {
} else {
video_paths.push((path, additional))
}
+
+ // Remove subtitles of deleted video
+ if only_audio {
+ subtitles.retain(|s| s.episode_id != additional.id);
+ }
}
let (primary_video, _) = video_paths.get(0).unwrap();
let primary_video_length = get_video_length(primary_video.to_path_buf()).unwrap();
for subtitle in subtitles {
subtitle_paths.push((
- download_subtitle(&self, subtitle.clone(), primary_video_length).await?,
+ download_subtitle(
+ &self,
+ subtitle.stream_subtitle.clone(),
+ primary_video_length,
+ )
+ .await?,
subtitle,
))
}
@@ -334,7 +346,7 @@ async fn formats_from_series(
archive: &Archive,
series: Media,
url_filter: &UrlFilter,
-) -> Result, Vec)>> {
+) -> Result, Vec)>> {
let mut seasons = series.seasons().await?;
// filter any season out which does not contain the specified audio languages
@@ -367,8 +379,8 @@ async fn formats_from_series(
}
#[allow(clippy::type_complexity)]
- let mut result: BTreeMap, Vec)>> =
- BTreeMap::new();
+ let mut result: BTreeMap, Vec)>> = BTreeMap::new();
+ let mut primary_season = true;
for season in series.seasons().await? {
if !url_filter.is_season_valid(season.metadata.season_number)
|| !archive
@@ -402,20 +414,26 @@ async fn formats_from_series(
)
};
- let (ref mut formats, _) = result
+ let (ref mut formats, subtitles) = result
.entry(season.metadata.season_number)
.or_insert_with(BTreeMap::new)
.entry(episode.metadata.episode_number)
- .or_insert_with(|| {
- let subtitles: Vec = archive
- .subtitle
- .iter()
- .filter_map(|l| streams.subtitles.get(l).cloned())
- .collect();
- (vec![], subtitles)
- });
+ .or_insert_with(|| (vec![], vec![]));
+ subtitles.extend(archive.subtitle.iter().filter_map(|l| {
+ let stream_subtitle = streams.subtitles.get(l).cloned()?;
+ let subtitle = Subtitle {
+ stream_subtitle,
+ audio_locale: episode.metadata.audio_locale.clone(),
+ episode_id: episode.id.clone(),
+ forced: !episode.metadata.is_subbed,
+ primary: primary_season,
+ };
+ Some(subtitle)
+ }));
formats.push(Format::new_from_episode(episode, stream));
}
+
+ primary_season = false;
}
Ok(result.into_values().flat_map(|v| v.into_values()).collect())
@@ -562,11 +580,12 @@ fn generate_mkv(
target: PathBuf,
video_paths: Vec<(TempPath, &Format)>,
audio_paths: Vec<(TempPath, &Format)>,
- subtitle_paths: Vec<(TempPath, StreamSubtitle)>,
+ subtitle_paths: Vec<(TempPath, Subtitle)>,
) -> Result<()> {
let mut input = vec![];
let mut maps = vec![];
let mut metadata = vec![];
+ let mut dispositions = vec![vec![]; subtitle_paths.len()];
for (i, (video_path, format)) in video_paths.iter().enumerate() {
input.extend(["-i".to_string(), video_path.to_string_lossy().to_string()]);
@@ -611,12 +630,26 @@ fn generate_mkv(
]);
metadata.extend([
format!("-metadata:s:s:{}", i),
- format!("language={}", subtitle.locale),
+ format!("language={}", subtitle.stream_subtitle.locale),
]);
metadata.extend([
format!("-metadata:s:s:{}", i),
- format!("title={}", subtitle.locale.to_human_readable()),
+ format!(
+ "title={}",
+ subtitle.stream_subtitle.locale.to_human_readable()
+ + if !subtitle.primary {
+ format!(" [Video: {}]", subtitle.audio_locale.to_human_readable())
+ } else {
+ "".to_string()
+ }
+ .as_str()
+ ),
]);
+
+ // mark forced subtitles
+ if subtitle.forced {
+ dispositions[i].push("forced");
+ }
}
let (input_presets, output_presets) =
@@ -633,16 +666,28 @@ fn generate_mkv(
// if `--default_subtitle ` is given set the default subtitle to the given locale
if let Some(position) = subtitle_paths
.iter()
- .position(|(_, subtitle)| &subtitle.locale == default_subtitle)
+ .position(|(_, subtitle)| &subtitle.stream_subtitle.locale == default_subtitle)
{
- command_args.extend([format!("-disposition:s:{}", position), "default".to_string()])
- } else {
- command_args.extend(["-disposition:s:0".to_string(), "0".to_string()])
+ dispositions[position].push("default");
}
- } else {
- command_args.extend(["-disposition:s:0".to_string(), "0".to_string()])
}
+ let disposition_args: Vec = dispositions
+ .iter()
+ .enumerate()
+ .flat_map(|(i, d)| {
+ vec![
+ format!("-disposition:s:{}", i),
+ if !d.is_empty() {
+ d.join("+")
+ } else {
+ "0".to_string()
+ },
+ ]
+ })
+ .collect();
+ command_args.extend(disposition_args);
+
command_args.extend(output_presets);
command_args.extend([
"-f".to_string(),
diff --git a/crunchy-cli-core/src/utils/mod.rs b/crunchy-cli-core/src/utils/mod.rs
index 5f7a5d2..3b15a89 100644
--- a/crunchy-cli-core/src/utils/mod.rs
+++ b/crunchy-cli-core/src/utils/mod.rs
@@ -6,3 +6,4 @@ pub mod log;
pub mod os;
pub mod parse;
pub mod sort;
+pub mod subtitle;
diff --git a/crunchy-cli-core/src/utils/subtitle.rs b/crunchy-cli-core/src/utils/subtitle.rs
new file mode 100644
index 0000000..86b9359
--- /dev/null
+++ b/crunchy-cli-core/src/utils/subtitle.rs
@@ -0,0 +1,11 @@
+use crunchyroll_rs::media::StreamSubtitle;
+use crunchyroll_rs::Locale;
+
+#[derive(Clone)]
+pub struct Subtitle {
+ pub stream_subtitle: StreamSubtitle,
+ pub audio_locale: Locale,
+ pub episode_id: String,
+ pub forced: bool,
+ pub primary: bool,
+}
From 7588621f345e5b699985bda9a84cba2226151341 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sat, 7 Jan 2023 16:02:51 +0100
Subject: [PATCH 059/395] Add interactive input to choose season on duplicated
season numbers (#55, #82)
---
crunchy-cli-core/src/cli/archive.rs | 14 +++-
crunchy-cli-core/src/cli/download.rs | 12 ++-
crunchy-cli-core/src/cli/utils.rs | 106 ++++++++++++++++++++++++++-
3 files changed, 128 insertions(+), 4 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 8259ab3..2c952d6 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
+use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, find_multiple_seasons_with_same_number, interactive_season_choosing};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -120,6 +120,10 @@ pub struct Archive {
#[arg(long)]
no_subtitle_optimizations: bool,
+ #[arg(help = "Ignore interactive input")]
+ #[arg(short, long, default_value_t = false)]
+ yes: bool,
+
#[arg(help = "Crunchyroll series url(s)")]
urls: Vec,
}
@@ -378,10 +382,16 @@ async fn formats_from_series(
})
}
+ if !archive.yes && !find_multiple_seasons_with_same_number(&seasons).is_empty() {
+ info!(target: "progress_end", "Fetched seasons");
+ seasons = interactive_season_choosing(seasons);
+ info!(target: "progress", "Fetching series details")
+ }
+
#[allow(clippy::type_complexity)]
let mut result: BTreeMap, Vec)>> = BTreeMap::new();
let mut primary_season = true;
- for season in series.seasons().await? {
+ for season in seasons {
if !url_filter.is_season_valid(season.metadata.season_number)
|| !archive
.locale
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 0411a5e..8da833a 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,5 +1,5 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset};
+use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, interactive_season_choosing, find_multiple_seasons_with_same_number};
use crate::utils::context::Context;
use crate::utils::format::{format_string, Format};
use crate::utils::log::progress;
@@ -71,6 +71,10 @@ pub struct Download {
#[arg(value_parser = FFmpegPreset::parse)]
ffmpeg_preset: Vec,
+ #[arg(help = "Ignore interactive input")]
+ #[arg(short, long, default_value_t = false)]
+ yes: bool,
+
#[arg(help = "Url(s) to Crunchyroll episodes or series")]
urls: Vec,
}
@@ -348,6 +352,12 @@ async fn formats_from_series(
})
}
+ if !download.yes && !find_multiple_seasons_with_same_number(&seasons).is_empty() {
+ info!(target: "progress_end", "Fetched seasons");
+ seasons = interactive_season_choosing(seasons);
+ info!(target: "progress", "Fetching series details")
+ }
+
let mut formats = vec![];
for season in seasons {
if let Some(fmts) = formats_from_season(download, season, url_filter).await? {
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 26d939c..fde1d08 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -5,9 +5,11 @@ use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use log::{debug, LevelFilter};
use std::borrow::{Borrow, BorrowMut};
use std::collections::BTreeMap;
-use std::io::Write;
+use std::io::{BufRead, Write};
use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
+use crunchyroll_rs::{Media, Season};
+use regex::Regex;
use tokio::task::JoinSet;
pub fn find_resolution(
@@ -327,3 +329,105 @@ impl FFmpegPreset {
))
}
}
+
+pub(crate) fn find_multiple_seasons_with_same_number(seasons: &Vec>) -> Vec {
+ let mut seasons_map: BTreeMap = BTreeMap::new();
+ for season in seasons {
+ if let Some(s) = seasons_map.get_mut(&season.metadata.season_number) {
+ *s += 1;
+ } else {
+ seasons_map.insert(season.metadata.season_number, 1);
+ }
+ }
+
+ seasons_map
+ .into_iter()
+ .filter_map(|(k, v)| if v > 1 { Some(k) } else { None })
+ .collect()
+}
+
+pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec> {
+ let input_regex =
+ Regex::new(r"((?P\d+)|(?P\d+)-(?P\d+)?)(\s|$)").unwrap();
+
+ let mut seasons_map: BTreeMap>> = BTreeMap::new();
+ for season in seasons {
+ if let Some(s) = seasons_map.get_mut(&season.metadata.season_number) {
+ s.push(season);
+ } else {
+ seasons_map.insert(season.metadata.season_number, vec![season]);
+ }
+ }
+
+ for (num, season_vec) in seasons_map.iter_mut() {
+ if season_vec.len() == 1 {
+ continue;
+ }
+ println!(":: Found multiple seasons for season number {}", num);
+ println!(":: Select the number of the seasons you want to download (eg \"1 2 4\", \"1-3\", \"1-3 5\"):");
+ for (i, season) in season_vec.iter().enumerate() {
+ println!(":: \t{}. {}", i + 1, season.title)
+ }
+ let mut stdout = std::io::stdout();
+ let _ = write!(stdout, ":: => ");
+ let _ = stdout.flush();
+ let mut user_input = String::new();
+ std::io::stdin().lock()
+ .read_line(&mut user_input)
+ .expect("cannot open stdin");
+
+ let mut nums = vec![];
+ for capture in input_regex.captures_iter(&user_input) {
+ if let Some(single) = capture.name("single") {
+ nums.push(single.as_str().parse().unwrap());
+ } else {
+ let range_from = capture.name("range_from");
+ let range_to = capture.name("range_to");
+
+ // input is '-' which means use all seasons
+ if range_from.is_none() && range_to.is_none() {
+ nums = vec![];
+ break;
+ }
+ let from = range_from
+ .map(|f| f.as_str().parse::().unwrap() - 1)
+ .unwrap_or(usize::MIN);
+ let to = range_from
+ .map(|f| f.as_str().parse::().unwrap() - 1)
+ .unwrap_or(usize::MAX);
+
+ nums.extend(
+ season_vec
+ .iter()
+ .enumerate()
+ .filter_map(|(i, _)| {
+ if i >= from && i <= to {
+ Some(i)
+ } else {
+ None
+ }
+ })
+ .collect::>(),
+ )
+ }
+ }
+ nums.dedup();
+
+ if !nums.is_empty() {
+ let mut remove_count = 0;
+ for i in 0..season_vec.len() - 1 {
+ if !nums.contains(&i) {
+ season_vec.remove(i - remove_count);
+ remove_count += 1
+ }
+ }
+ }
+ }
+
+ seasons_map
+ .into_values()
+ .into_iter()
+ .flatten()
+ .collect::>>()
+}
+
From b991614dc38e8d36ffb2026a91429e0c686fc855 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sat, 7 Jan 2023 17:14:47 +0100
Subject: [PATCH 060/395] Fix output and download order on duplicated seasons
---
crunchy-cli-core/src/utils/sort.rs | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/crunchy-cli-core/src/utils/sort.rs b/crunchy-cli-core/src/utils/sort.rs
index 089fe18..21df74e 100644
--- a/crunchy-cli-core/src/utils/sort.rs
+++ b/crunchy-cli-core/src/utils/sort.rs
@@ -30,8 +30,11 @@ pub fn sort_formats_after_seasons(formats: Vec) -> Vec> {
let mut as_map = BTreeMap::new();
for format in formats {
- as_map.entry(format.season_number).or_insert_with(Vec::new);
- as_map.get_mut(&format.season_number).unwrap().push(format);
+ // the season title is used as key instead of season number to distinguish duplicated season
+ // numbers which are actually two different seasons; season id is not used as this somehow
+ // messes up ordering when duplicated seasons exist
+ as_map.entry(format.season_title.clone()).or_insert_with(Vec::new);
+ as_map.get_mut(&format.season_title).unwrap().push(format);
}
let mut sorted = as_map
@@ -41,7 +44,7 @@ pub fn sort_formats_after_seasons(formats: Vec) -> Vec> {
values
})
.collect::>>();
- sorted.sort_by(|a, b| a[0].series_id.cmp(&b[0].series_id));
+ sorted.sort_by(|a, b| a[0].season_number.cmp(&b[0].season_number));
sorted
}
From b65c0e9dfdefb49add0294e136912729ae308ee4 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 8 Jan 2023 17:44:31 +0100
Subject: [PATCH 061/395] Update dependencies & version
---
Cargo.lock | 32 ++++++++++++++++----------------
Cargo.toml | 4 ++--
crunchy-cli-core/Cargo.lock | 30 +++++++++++++++---------------
crunchy-cli-core/Cargo.toml | 4 ++--
4 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index eb7c6a3..7177ac1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -39,9 +39,9 @@ checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "async-trait"
-version = "0.1.60"
+version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
+checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282"
dependencies = [
"proc-macro2",
"quote",
@@ -279,7 +279,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.6"
+version = "3.0.0-dev.7"
dependencies = [
"chrono",
"clap",
@@ -291,7 +291,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.6"
+version = "3.0.0-dev.7"
dependencies = [
"anyhow",
"async-trait",
@@ -395,9 +395,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
+checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -407,9 +407,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
+checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70"
dependencies = [
"cc",
"codespan-reporting",
@@ -422,15 +422,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
+checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
+checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5"
dependencies = [
"proc-macro2",
"quote",
@@ -1669,9 +1669,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.23.0"
+version = "1.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
+checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
dependencies = [
"autocfg",
"bytes",
@@ -1759,9 +1759,9 @@ dependencies = [
[[package]]
name = "try-lock"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
diff --git a/Cargo.toml b/Cargo.toml
index 76ed950..ec8e4ef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.6"
+version = "3.0.0-dev.7"
edition = "2021"
[dependencies]
-tokio = { version = "1.23", features = ["macros", "rt-multi-thread", "time"], default-features = false }
+tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time"], default-features = false }
crunchy-cli-core = { path = "./crunchy-cli-core" }
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index b5dd8a1..4b1a723 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -39,9 +39,9 @@ checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "async-trait"
-version = "0.1.60"
+version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
+checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282"
dependencies = [
"proc-macro2",
"quote",
@@ -260,7 +260,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.6"
+version = "3.0.0-dev.7"
dependencies = [
"anyhow",
"async-trait",
@@ -364,9 +364,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
+checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -376,9 +376,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
+checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70"
dependencies = [
"cc",
"codespan-reporting",
@@ -391,15 +391,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
+checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.85"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
+checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5"
dependencies = [
"proc-macro2",
"quote",
@@ -1632,9 +1632,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.23.0"
+version = "1.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46"
+checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
dependencies = [
"autocfg",
"bytes",
@@ -1722,9 +1722,9 @@ dependencies = [
[[package]]
name = "try-lock"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 566b8c4..a3ae301 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.6"
+version = "3.0.0-dev.7"
edition = "2021"
[dependencies]
@@ -23,7 +23,7 @@ serde_json = "1.0"
signal-hook = "0.3"
tempfile = "3.3"
terminal_size = "0.2"
-tokio = { version = "1.23", features = ["macros", "rt-multi-thread", "time"] }
+tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time"] }
sys-locale = "0.2"
[build-dependencies]
From 13f54c0da636e7093d347bba5c126f8e895ebfe1 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 8 Jan 2023 18:06:37 +0100
Subject: [PATCH 062/395] Fix interactive season choosing activation on url
filter excluded seasons
---
crunchy-cli-core/src/cli/archive.rs | 5 ++++-
crunchy-cli-core/src/cli/download.rs | 11 +++++++----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 2c952d6..b9b7de0 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -379,7 +379,10 @@ async fn formats_from_series(
.locale
.iter()
.any(|l| s.metadata.audio_locales.contains(l))
- })
+ });
+ // remove seasons which match the url filter. this is mostly done to not trigger the
+ // interactive season choosing when dupilcated seasons are excluded by the filter
+ seasons.retain(|s| url_filter.is_season_valid(s.metadata.season_number))
}
if !archive.yes && !find_multiple_seasons_with_same_number(&seasons).is_empty() {
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 8da833a..25c1262 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -349,7 +349,10 @@ async fn formats_from_series(
seasons.retain(|s| {
s.metadata.season_number != season.first().unwrap().metadata.season_number
|| s.metadata.audio_locales.contains(&download.audio)
- })
+ });
+ // remove seasons which match the url filter. this is mostly done to not trigger the
+ // interactive season choosing when dupilcated seasons are excluded by the filter
+ seasons.retain(|s| url_filter.is_season_valid(s.metadata.season_number))
}
if !download.yes && !find_multiple_seasons_with_same_number(&seasons).is_empty() {
@@ -373,14 +376,14 @@ async fn formats_from_season(
season: Media,
url_filter: &UrlFilter,
) -> Result>> {
- if !season.metadata.audio_locales.contains(&download.audio) {
+ if !url_filter.is_season_valid(season.metadata.season_number) {
+ return Ok(None);
+ } else if !season.metadata.audio_locales.contains(&download.audio) {
error!(
"Season {} ({}) is not available with {} audio",
season.metadata.season_number, season.title, download.audio
);
return Ok(None);
- } else if !url_filter.is_season_valid(season.metadata.season_number) {
- return Ok(None);
}
let mut formats = vec![];
From 4b33ef02c61d1ce8b60900785868a3445f779e90 Mon Sep 17 00:00:00 2001
From: bytedream
Date: Mon, 9 Jan 2023 10:27:28 +0100
Subject: [PATCH 063/395] Fix output formatting for full path (#101)
---
crunchy-cli-core/src/cli/archive.rs | 20 ++++++--------------
crunchy-cli-core/src/cli/download.rs | 20 ++++++--------------
crunchy-cli-core/src/utils/format.rs | 9 ++++++---
3 files changed, 18 insertions(+), 31 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index b9b7de0..f9a6a04 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,7 +1,7 @@
use crate::cli::log::tab_info;
use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, find_multiple_seasons_with_same_number, interactive_season_choosing};
use crate::utils::context::Context;
-use crate::utils::format::{format_string, Format};
+use crate::utils::format::{Format, format_path};
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -240,19 +240,11 @@ impl Execute for Archive {
for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
- let mut path = PathBuf::from(&self.output);
- path = free_file(
- path.with_file_name(format_string(
- if let Some(fname) = path.file_name() {
- fname.to_str().unwrap()
- } else {
- "{title}.mkv"
- }
- .to_string(),
- primary,
- true,
- )),
- );
+ let path = free_file(format_path(if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }.into(), &primary, true));
info!(
"Downloading {} to '{}'",
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 25c1262..a7ed773 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,7 +1,7 @@
use crate::cli::log::tab_info;
use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, interactive_season_choosing, find_multiple_seasons_with_same_number};
use crate::utils::context::Context;
-use crate::utils::format::{format_string, Format};
+use crate::utils::format::{Format, format_path};
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -206,19 +206,11 @@ impl Execute for Download {
}
for format in formats {
- let mut path = PathBuf::from(&self.output);
- path = free_file(
- path.with_file_name(format_string(
- if let Some(fname) = path.file_name() {
- fname.to_str().unwrap()
- } else {
- "{title}.ts"
- }
- .to_string(),
- &format,
- true,
- )),
- );
+ let path = free_file(format_path(if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }.into(), &format, true));
info!(
"Downloading {} to '{}'",
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index c463ea8..ee48e2a 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -1,3 +1,4 @@
+use std::path::PathBuf;
use crunchyroll_rs::media::VariantData;
use crunchyroll_rs::{Episode, Locale, Media, Movie};
use std::time::Duration;
@@ -65,7 +66,7 @@ impl Format {
/// Formats the given string if it has specific pattern in it. It's possible to sanitize it which
/// removes characters which can cause failures if the output string is used as a file name.
-pub fn format_string(s: String, format: &Format, sanitize: bool) -> String {
+pub fn format_path(path: PathBuf, format: &Format, sanitize: bool) -> PathBuf {
let sanitize_func = if sanitize {
|s: &str| sanitize_filename::sanitize(s)
} else {
@@ -73,7 +74,9 @@ pub fn format_string(s: String, format: &Format, sanitize: bool) -> String {
|s: &str| s.to_string()
};
- s.replace("{title}", &sanitize_func(&format.title))
+ let as_string = path.to_string_lossy().to_string();
+
+ PathBuf::from(as_string.replace("{title}", &sanitize_func(&format.title))
.replace("{series_name}", &sanitize_func(&format.series_name))
.replace("{season_name}", &sanitize_func(&format.season_title))
.replace("{audio}", &sanitize_func(&format.audio.to_string()))
@@ -99,5 +102,5 @@ pub fn format_string(s: String, format: &Format, sanitize: bool) -> String {
)
.replace("{series_id}", &sanitize_func(&format.series_id))
.replace("{season_id}", &sanitize_func(&format.season_id))
- .replace("{episode_id}", &sanitize_func(&format.id))
+ .replace("{episode_id}", &sanitize_func(&format.id)))
}
From 12be16417ffdd0bda87b9c06aaf7f50d5454b178 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 16:55:10 +0100
Subject: [PATCH 064/395] Fix interactive season choosing false-positive
triggering
---
Cargo.lock | 85 +++++++---------------------
crunchy-cli-core/Cargo.lock | 85 +++++++---------------------
crunchy-cli-core/Cargo.toml | 1 +
crunchy-cli-core/src/cli/archive.rs | 31 +++++-----
crunchy-cli-core/src/cli/download.rs | 22 ++++---
crunchy-cli-core/src/cli/utils.rs | 67 ++++++++++++++++------
crunchy-cli-core/src/utils/format.rs | 59 ++++++++++---------
crunchy-cli-core/src/utils/sort.rs | 4 +-
8 files changed, 157 insertions(+), 197 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 7177ac1..77e1342 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -222,7 +222,7 @@ dependencies = [
"lazy_static",
"libc",
"unicode-width",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -302,6 +302,7 @@ dependencies = [
"ctrlc",
"dirs",
"indicatif",
+ "lazy_static",
"log",
"num_cpus",
"regex",
@@ -390,7 +391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
dependencies = [
"nix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -859,14 +860,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
name = "ipnet"
-version = "2.7.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
+checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]]
name = "is-terminal"
@@ -877,7 +878,7 @@ dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -980,7 +981,7 @@ dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1231,9 +1232,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.7.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
@@ -1338,7 +1339,7 @@ dependencies = [
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1380,12 +1381,11 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.20"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
+checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
- "lazy_static",
- "windows-sys 0.36.1",
+ "windows-sys",
]
[[package]]
@@ -1591,7 +1591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1682,7 +1682,7 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio-macros",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1973,19 +1973,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-[[package]]
-name = "windows-sys"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
-dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
-]
-
[[package]]
name = "windows-sys"
version = "0.42.0"
@@ -1993,12 +1980,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.0",
- "windows_i686_gnu 0.42.0",
- "windows_i686_msvc 0.42.0",
- "windows_x86_64_gnu 0.42.0",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
"windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.0",
+ "windows_x86_64_msvc",
]
[[package]]
@@ -2007,48 +1994,24 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
-
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
-
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
@@ -2061,12 +2024,6 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 4b1a723..5bdabf0 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -203,7 +203,7 @@ dependencies = [
"lazy_static",
"libc",
"unicode-width",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -271,6 +271,7 @@ dependencies = [
"ctrlc",
"dirs",
"indicatif",
+ "lazy_static",
"log",
"num_cpus",
"regex",
@@ -359,7 +360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1631ca6e3c59112501a9d87fd86f21591ff77acd31331e8a73f8d80a65bbdd71"
dependencies = [
"nix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -828,14 +829,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
name = "ipnet"
-version = "2.7.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
+checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]]
name = "is-terminal"
@@ -846,7 +847,7 @@ dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -949,7 +950,7 @@ dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1200,9 +1201,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.7.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
@@ -1301,7 +1302,7 @@ dependencies = [
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1343,12 +1344,11 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.20"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
+checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
- "lazy_static",
- "windows-sys 0.36.1",
+ "windows-sys",
]
[[package]]
@@ -1554,7 +1554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1645,7 +1645,7 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio-macros",
- "windows-sys 0.42.0",
+ "windows-sys",
]
[[package]]
@@ -1936,19 +1936,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-[[package]]
-name = "windows-sys"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
-dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
-]
-
[[package]]
name = "windows-sys"
version = "0.42.0"
@@ -1956,12 +1943,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.0",
- "windows_i686_gnu 0.42.0",
- "windows_i686_msvc 0.42.0",
- "windows_x86_64_gnu 0.42.0",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
"windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.0",
+ "windows_x86_64_msvc",
]
[[package]]
@@ -1970,48 +1957,24 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
-
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
-
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
@@ -2024,12 +1987,6 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index a3ae301..5bda1db 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -14,6 +14,7 @@ csv = "1.1"
ctrlc = "3.2"
dirs = "4.0"
indicatif = "0.17"
+lazy_static = "1.4"
log = { version = "0.4", features = ["std"] }
num_cpus = "1.15"
regex = "1.7"
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index f9a6a04..7a96c05 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,7 +1,10 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, find_multiple_seasons_with_same_number, interactive_season_choosing};
+use crate::cli::utils::{
+ download_segments, find_multiple_seasons_with_same_number, find_resolution,
+ interactive_season_choosing, FFmpegPreset,
+};
use crate::utils::context::Context;
-use crate::utils::format::{Format, format_path};
+use crate::utils::format::{format_path, Format};
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -240,11 +243,16 @@ impl Execute for Archive {
for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
- let path = free_file(format_path(if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }.into(), &primary, true));
+ let path = free_file(format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ &primary,
+ true,
+ ));
info!(
"Downloading {} to '{}'",
@@ -387,15 +395,6 @@ async fn formats_from_series(
let mut result: BTreeMap, Vec)>> = BTreeMap::new();
let mut primary_season = true;
for season in seasons {
- if !url_filter.is_season_valid(season.metadata.season_number)
- || !archive
- .locale
- .iter()
- .any(|l| season.metadata.audio_locales.contains(l))
- {
- continue;
- }
-
for episode in season.episodes().await? {
if !url_filter.is_episode_valid(
episode.metadata.episode_number,
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index a7ed773..bdca291 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,7 +1,10 @@
use crate::cli::log::tab_info;
-use crate::cli::utils::{download_segments, find_resolution, FFmpegPreset, interactive_season_choosing, find_multiple_seasons_with_same_number};
+use crate::cli::utils::{
+ download_segments, find_multiple_seasons_with_same_number, find_resolution,
+ interactive_season_choosing, FFmpegPreset,
+};
use crate::utils::context::Context;
-use crate::utils::format::{Format, format_path};
+use crate::utils::format::{format_path, Format};
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -206,11 +209,16 @@ impl Execute for Download {
}
for format in formats {
- let path = free_file(format_path(if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }.into(), &format, true));
+ let path = free_file(format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ &format,
+ true,
+ ));
info!(
"Downloading {} to '{}'",
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index fde1d08..bc19b07 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -1,15 +1,16 @@
use crate::utils::context::Context;
use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
+use crunchyroll_rs::{Media, Season};
use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
+use lazy_static::lazy_static;
use log::{debug, LevelFilter};
+use regex::Regex;
use std::borrow::{Borrow, BorrowMut};
use std::collections::BTreeMap;
use std::io::{BufRead, Write};
use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
-use crunchyroll_rs::{Media, Season};
-use regex::Regex;
use tokio::task::JoinSet;
pub fn find_resolution(
@@ -111,7 +112,7 @@ pub async fn download_segments(
};
buf = VariantSegment::decrypt(buf.borrow_mut(), segment.key)?.to_vec();
-
+
let mut c = thread_count.lock().unwrap();
debug!(
"Downloaded and decrypted segment [{}/{} {:.2}%] {}",
@@ -120,14 +121,14 @@ pub async fn download_segments(
((*c + 1) as f64 / total_segments as f64) * 100f64,
segment.url
);
-
+
thread_sender.send((num as i32 + (i * cpus) as i32, buf))?;
-
+
*c += 1;
}
Ok(())
};
-
+
let result = download().await;
if result.is_err() {
@@ -149,7 +150,7 @@ pub async fn download_segments(
for (pos, bytes) in receiver.iter() {
// if the position is lower than 0, an error occured in the sending download thread
if pos < 0 {
- break
+ break;
}
if let Some(p) = &progress {
@@ -330,6 +331,10 @@ impl FFmpegPreset {
}
}
+lazy_static! {
+ static ref DUPLICATED_SEASONS_MULTILANG_REGEX: Regex = Regex::new(r"(-castilian|-english|-english-in|-french|-german|-hindi|-italian|-portuguese|-russian|-spanish)$").unwrap();
+}
+
pub(crate) fn find_multiple_seasons_with_same_number(seasons: &Vec>) -> Vec {
let mut seasons_map: BTreeMap = BTreeMap::new();
for season in seasons {
@@ -342,7 +347,25 @@ pub(crate) fn find_multiple_seasons_with_same_number(seasons: &Vec
seasons_map
.into_iter()
- .filter_map(|(k, v)| if v > 1 { Some(k) } else { None })
+ .filter_map(|(k, v)| {
+ if v > 1 {
+ // check if the different seasons are actual the same but with different dub languages
+ let mut multilang_season_vec: Vec = seasons
+ .iter()
+ .map(|s| {
+ DUPLICATED_SEASONS_MULTILANG_REGEX
+ .replace(s.slug_title.trim_end_matches("-dub"), "")
+ .to_string()
+ })
+ .collect();
+ multilang_season_vec.dedup();
+
+ if multilang_season_vec.len() > 1 {
+ return Some(k);
+ }
+ }
+ None
+ })
.collect()
}
@@ -363,6 +386,22 @@ pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec = season_vec
+ .iter()
+ .map(|s| {
+ DUPLICATED_SEASONS_MULTILANG_REGEX
+ .replace(s.slug_title.trim_end_matches("-dub"), "")
+ .to_string()
+ })
+ .collect();
+ multilang_season_vec.dedup();
+
+ if multilang_season_vec.len() == 1 {
+ continue;
+ }
+
println!(":: Found multiple seasons for season number {}", num);
println!(":: Select the number of the seasons you want to download (eg \"1 2 4\", \"1-3\", \"1-3 5\"):");
for (i, season) in season_vec.iter().enumerate() {
@@ -372,7 +411,8 @@ pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec ");
let _ = stdout.flush();
let mut user_input = String::new();
- std::io::stdin().lock()
+ std::io::stdin()
+ .lock()
.read_line(&mut user_input)
.expect("cannot open stdin");
@@ -400,13 +440,7 @@ pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec= from && i <= to {
- Some(i)
- } else {
- None
- }
- })
+ .filter_map(|(i, _)| if i >= from && i <= to { Some(i) } else { None })
.collect::>(),
)
}
@@ -430,4 +464,3 @@ pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec>>()
}
-
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index ee48e2a..035a61c 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -1,6 +1,6 @@
-use std::path::PathBuf;
use crunchyroll_rs::media::VariantData;
use crunchyroll_rs::{Episode, Locale, Media, Movie};
+use std::path::PathBuf;
use std::time::Duration;
#[derive(Clone)]
@@ -76,31 +76,34 @@ pub fn format_path(path: PathBuf, format: &Format, sanitize: bool) -> PathBuf {
let as_string = path.to_string_lossy().to_string();
- PathBuf::from(as_string.replace("{title}", &sanitize_func(&format.title))
- .replace("{series_name}", &sanitize_func(&format.series_name))
- .replace("{season_name}", &sanitize_func(&format.season_title))
- .replace("{audio}", &sanitize_func(&format.audio.to_string()))
- .replace(
- "{resolution}",
- &sanitize_func(&format.stream.resolution.to_string()),
- )
- .replace(
- "{padded_season_number}",
- &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
- )
- .replace(
- "{season_number}",
- &sanitize_func(&format.season_number.to_string()),
- )
- .replace(
- "{padded_episode_number}",
- &sanitize_func(&format!("{:0>2}", format.number.to_string())),
- )
- .replace(
- "{episode_number}",
- &sanitize_func(&format.number.to_string()),
- )
- .replace("{series_id}", &sanitize_func(&format.series_id))
- .replace("{season_id}", &sanitize_func(&format.season_id))
- .replace("{episode_id}", &sanitize_func(&format.id)))
+ PathBuf::from(
+ as_string
+ .replace("{title}", &sanitize_func(&format.title))
+ .replace("{series_name}", &sanitize_func(&format.series_name))
+ .replace("{season_name}", &sanitize_func(&format.season_title))
+ .replace("{audio}", &sanitize_func(&format.audio.to_string()))
+ .replace(
+ "{resolution}",
+ &sanitize_func(&format.stream.resolution.to_string()),
+ )
+ .replace(
+ "{padded_season_number}",
+ &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
+ )
+ .replace(
+ "{season_number}",
+ &sanitize_func(&format.season_number.to_string()),
+ )
+ .replace(
+ "{padded_episode_number}",
+ &sanitize_func(&format!("{:0>2}", format.number.to_string())),
+ )
+ .replace(
+ "{episode_number}",
+ &sanitize_func(&format.number.to_string()),
+ )
+ .replace("{series_id}", &sanitize_func(&format.series_id))
+ .replace("{season_id}", &sanitize_func(&format.season_id))
+ .replace("{episode_id}", &sanitize_func(&format.id)),
+ )
}
diff --git a/crunchy-cli-core/src/utils/sort.rs b/crunchy-cli-core/src/utils/sort.rs
index 21df74e..9f8d81c 100644
--- a/crunchy-cli-core/src/utils/sort.rs
+++ b/crunchy-cli-core/src/utils/sort.rs
@@ -33,7 +33,9 @@ pub fn sort_formats_after_seasons(formats: Vec) -> Vec> {
// the season title is used as key instead of season number to distinguish duplicated season
// numbers which are actually two different seasons; season id is not used as this somehow
// messes up ordering when duplicated seasons exist
- as_map.entry(format.season_title.clone()).or_insert_with(Vec::new);
+ as_map
+ .entry(format.season_title.clone())
+ .or_insert_with(Vec::new);
as_map.get_mut(&format.season_title).unwrap().push(format);
}
From 29845ba6e53ce877d85aca47db840c52835fa61b Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 17:26:04 +0100
Subject: [PATCH 065/395] Re-order instructions
---
crunchy-cli-core/src/cli/archive.rs | 8 +++---
crunchy-cli-core/src/cli/download.rs | 10 +++++--
crunchy-cli-core/src/utils/format.rs | 43 +++++++++++++++-------------
crunchy-cli-core/src/utils/sort.rs | 2 +-
4 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 7a96c05..1de0997 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -208,7 +208,7 @@ impl Execute for Archive {
format.stream.resolution,
format.stream.fps,
format.season_number,
- format.number,
+ format.episode_number,
)
}
}
@@ -234,7 +234,7 @@ impl Execute for Archive {
format.stream.resolution,
format.stream.fps,
format.season_number,
- format.number
+ format.episode_number
)
}
}
@@ -266,7 +266,7 @@ impl Execute for Archive {
tab_info!(
"Episode: S{:02}E{:02}",
primary.season_number,
- primary.number
+ primary.episode_number
);
tab_info!(
"Audio: {} (primary), {}",
@@ -318,7 +318,7 @@ impl Execute for Archive {
// Remove subtitles of deleted video
if only_audio {
- subtitles.retain(|s| s.episode_id != additional.id);
+ subtitles.retain(|s| s.episode_id != additional.episode_id);
}
}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index bdca291..14f9503 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -182,7 +182,7 @@ impl Execute for Download {
format.stream.resolution,
format.stream.fps,
format.season_number,
- format.number,
+ format.episode_number,
)
}
}
@@ -202,7 +202,7 @@ impl Execute for Download {
format.stream.resolution,
format.stream.fps,
format.season_number,
- format.number
+ format.episode_number
)
}
}
@@ -229,7 +229,11 @@ impl Execute for Download {
path.file_name().unwrap().to_str().unwrap()
}
);
- tab_info!("Episode: S{:02}E{:02}", format.season_number, format.number);
+ tab_info!(
+ "Episode: S{:02}E{:02}",
+ format.season_number,
+ format.episode_number
+ );
tab_info!("Audio: {}", format.audio);
tab_info!(
"Subtitles: {}",
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index 035a61c..5570960 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -5,10 +5,9 @@ use std::time::Duration;
#[derive(Clone)]
pub struct Format {
- pub id: String,
pub title: String,
pub description: String,
- pub number: u32,
+
pub audio: Locale,
pub duration: Duration,
@@ -20,15 +19,17 @@ pub struct Format {
pub season_id: String,
pub season_title: String,
pub season_number: u32,
+
+ pub episode_id: String,
+ pub episode_number: f32,
}
impl Format {
pub fn new_from_episode(episode: Media, stream: VariantData) -> Self {
Self {
- id: episode.id,
title: episode.title,
description: episode.description,
- number: episode.metadata.episode_number,
+
audio: episode.metadata.audio_locale,
duration: episode.metadata.duration.to_std().unwrap(),
@@ -40,15 +41,17 @@ impl Format {
season_id: episode.metadata.season_id,
season_title: episode.metadata.season_title,
season_number: episode.metadata.season_number,
+
+ episode_id: episode.id,
+ episode_number: episode.metadata.episode.parse().unwrap_or(episode.metadata.sequence_number),
}
}
pub fn new_from_movie(movie: Media, stream: VariantData) -> Self {
Self {
- id: movie.id,
title: movie.title,
description: movie.description,
- number: 1,
+
audio: Locale::ja_JP,
duration: movie.metadata.duration.to_std().unwrap(),
@@ -60,6 +63,9 @@ impl Format {
season_id: movie.metadata.movie_listing_id,
season_title: movie.metadata.movie_listing_title,
season_number: 1,
+
+ episode_id: movie.id,
+ episode_number: 1.0,
}
}
}
@@ -79,31 +85,28 @@ pub fn format_path(path: PathBuf, format: &Format, sanitize: bool) -> PathBuf {
PathBuf::from(
as_string
.replace("{title}", &sanitize_func(&format.title))
- .replace("{series_name}", &sanitize_func(&format.series_name))
- .replace("{season_name}", &sanitize_func(&format.season_title))
.replace("{audio}", &sanitize_func(&format.audio.to_string()))
.replace(
"{resolution}",
&sanitize_func(&format.stream.resolution.to_string()),
)
- .replace(
- "{padded_season_number}",
- &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
- )
+ .replace("{series_id}", &sanitize_func(&format.series_id))
+ .replace("{series_name}", &sanitize_func(&format.series_name))
+ .replace("{season_id}", &sanitize_func(&format.season_id))
+ .replace("{season_name}", &sanitize_func(&format.season_title))
.replace(
"{season_number}",
&sanitize_func(&format.season_number.to_string()),
)
.replace(
- "{padded_episode_number}",
- &sanitize_func(&format!("{:0>2}", format.number.to_string())),
+ "{padded_season_number}",
+ &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
)
+ .replace("{episode_id}", &sanitize_func(&format.episode_id))
+ .replace("{episode_number}", &sanitize_func(&format.episode_number.to_string()))
.replace(
- "{episode_number}",
- &sanitize_func(&format.number.to_string()),
- )
- .replace("{series_id}", &sanitize_func(&format.series_id))
- .replace("{season_id}", &sanitize_func(&format.season_id))
- .replace("{episode_id}", &sanitize_func(&format.id)),
+ "{padded_episode_number}",
+ &sanitize_func(&format!("{:0>2}", format.episode_number.to_string())),
+ ),
)
}
diff --git a/crunchy-cli-core/src/utils/sort.rs b/crunchy-cli-core/src/utils/sort.rs
index 9f8d81c..1af0194 100644
--- a/crunchy-cli-core/src/utils/sort.rs
+++ b/crunchy-cli-core/src/utils/sort.rs
@@ -42,7 +42,7 @@ pub fn sort_formats_after_seasons(formats: Vec) -> Vec> {
let mut sorted = as_map
.into_iter()
.map(|(_, mut values)| {
- values.sort_by(|a, b| a.number.cmp(&b.number));
+ values.sort_by(|a, b| a.episode_number.total_cmp(&b.episode_number));
values
})
.collect::>>();
From 7d3a90e8112a4ce27158b217a564ded45c08c576 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 19:12:00 +0100
Subject: [PATCH 066/395] Add relative episode number to format
---
crunchy-cli-core/src/cli/archive.rs | 29 +++---
crunchy-cli-core/src/cli/download.rs | 54 +++++++---
crunchy-cli-core/src/utils/format.rs | 150 ++++++++++++++++-----------
3 files changed, 145 insertions(+), 88 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 1de0997..96d0737 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -4,7 +4,7 @@ use crate::cli::utils::{
interactive_season_choosing, FFmpegPreset,
};
use crate::utils::context::Context;
-use crate::utils::format::{format_path, Format};
+use crate::utils::format::Format;
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -243,16 +243,17 @@ impl Execute for Archive {
for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
- let path = free_file(format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- &primary,
- true,
- ));
+ let path = free_file(
+ primary.format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ true,
+ ),
+ );
info!(
"Downloading {} to '{}'",
@@ -395,7 +396,9 @@ async fn formats_from_series(
let mut result: BTreeMap, Vec)>> = BTreeMap::new();
let mut primary_season = true;
for season in seasons {
- for episode in season.episodes().await? {
+ let episodes = season.episodes().await?;
+
+ for episode in episodes.iter() {
if !url_filter.is_episode_valid(
episode.metadata.episode_number,
episode.metadata.season_number,
@@ -434,7 +437,7 @@ async fn formats_from_series(
};
Some(subtitle)
}));
- formats.push(Format::new_from_episode(episode, stream));
+ formats.push(Format::new_from_episode(episode, &episodes, stream));
}
primary_season = false;
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 14f9503..d027df7 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -4,7 +4,7 @@ use crate::cli::utils::{
interactive_season_choosing, FFmpegPreset,
};
use crate::utils::context::Context;
-use crate::utils::format::{format_path, Format};
+use crate::utils::format::Format;
use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file};
use crate::utils::parse::{parse_url, UrlFilter};
@@ -16,6 +16,7 @@ use crunchyroll_rs::{
Episode, Locale, Media, MediaCollection, Movie, MovieListing, Season, Series,
};
use log::{debug, error, info, warn};
+use std::borrow::Cow;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
@@ -148,7 +149,7 @@ impl Execute for Download {
episode.metadata.season_title,
episode.metadata.series_title
);
- format_from_episode(&self, episode, &url_filter, false)
+ format_from_episode(&self, &episode, &url_filter, None, false)
.await?
.map(|fmt| vec![fmt])
}
@@ -209,16 +210,17 @@ impl Execute for Download {
}
for format in formats {
- let path = free_file(format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- &format,
- true,
- ));
+ let path = free_file(
+ format.format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ true,
+ ),
+ );
info!(
"Downloading {} to '{}'",
@@ -392,8 +394,11 @@ async fn formats_from_season(
let mut formats = vec![];
- for episode in season.episodes().await? {
- if let Some(fmt) = format_from_episode(download, episode, url_filter, true).await? {
+ let episodes = season.episodes().await?;
+ for episode in episodes.iter() {
+ if let Some(fmt) =
+ format_from_episode(download, &episode, url_filter, Some(&episodes), true).await?
+ {
formats.push(fmt)
}
}
@@ -403,8 +408,9 @@ async fn formats_from_season(
async fn format_from_episode(
download: &Download,
- episode: Media,
+ episode: &Media,
url_filter: &UrlFilter,
+ season_episodes: Option<&Vec>>,
filter_audio: bool,
) -> Result> {
if filter_audio && episode.metadata.audio_locale != download.audio {
@@ -457,7 +463,21 @@ async fn format_from_episode(
)
};
- Ok(Some(Format::new_from_episode(episode, stream)))
+ let season_eps = if Format::has_relative_episodes_fmt(&download.output) {
+ if let Some(eps) = season_episodes {
+ Cow::from(eps)
+ } else {
+ Cow::from(episode.season().await?.episodes().await?)
+ }
+ } else {
+ Cow::from(vec![])
+ };
+
+ Ok(Some(Format::new_from_episode(
+ episode,
+ &season_eps.to_vec(),
+ stream,
+ )))
}
async fn format_from_movie_listing(
@@ -515,7 +535,7 @@ async fn format_from_movie(
}
};
- Ok(Some(Format::new_from_movie(movie, stream)))
+ Ok(Some(Format::new_from_movie(&movie, stream)))
}
fn some_vec_or_none(v: Vec) -> Option> {
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index 5570960..3db28c3 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -1,5 +1,6 @@
use crunchyroll_rs::media::VariantData;
use crunchyroll_rs::{Episode, Locale, Media, Movie};
+use log::warn;
use std::path::PathBuf;
use std::time::Duration;
@@ -22,35 +23,56 @@ pub struct Format {
pub episode_id: String,
pub episode_number: f32,
+ pub relative_episode_number: f32,
}
impl Format {
- pub fn new_from_episode(episode: Media, stream: VariantData) -> Self {
+ pub fn new_from_episode(
+ episode: &Media,
+ season_episodes: &Vec>,
+ stream: VariantData,
+ ) -> Self {
Self {
- title: episode.title,
- description: episode.description,
+ title: episode.title.clone(),
+ description: episode.description.clone(),
- audio: episode.metadata.audio_locale,
+ audio: episode.metadata.audio_locale.clone(),
duration: episode.metadata.duration.to_std().unwrap(),
stream,
- series_id: episode.metadata.series_id,
- series_name: episode.metadata.series_title,
+ series_id: episode.metadata.series_id.clone(),
+ series_name: episode.metadata.series_title.clone(),
- season_id: episode.metadata.season_id,
- season_title: episode.metadata.season_title,
- season_number: episode.metadata.season_number,
+ season_id: episode.metadata.season_id.clone(),
+ season_title: episode.metadata.season_title.clone(),
+ season_number: episode.metadata.season_number.clone(),
- episode_id: episode.id,
- episode_number: episode.metadata.episode.parse().unwrap_or(episode.metadata.sequence_number),
+ episode_id: episode.id.clone(),
+ episode_number: episode
+ .metadata
+ .episode
+ .parse()
+ .unwrap_or(episode.metadata.sequence_number),
+ relative_episode_number: season_episodes
+ .iter()
+ .enumerate()
+ .find_map(|(i, e)| if e == episode { Some((i + 1) as f32) } else { None })
+ .unwrap_or_else(|| {
+ warn!("Cannot find relative episode number for episode {} ({}) of season {} ({}) of {}, using normal episode number", episode.metadata.episode_number, episode.title, episode.metadata.season_number, episode.metadata.season_title, episode.metadata.series_title);
+ episode
+ .metadata
+ .episode
+ .parse()
+ .unwrap_or(episode.metadata.sequence_number)
+ }),
}
}
- pub fn new_from_movie(movie: Media, stream: VariantData) -> Self {
+ pub fn new_from_movie(movie: &Media, stream: VariantData) -> Self {
Self {
- title: movie.title,
- description: movie.description,
+ title: movie.title.clone(),
+ description: movie.description.clone(),
audio: Locale::ja_JP,
@@ -60,53 +82,65 @@ impl Format {
series_id: movie.metadata.movie_listing_id.clone(),
series_name: movie.metadata.movie_listing_title.clone(),
- season_id: movie.metadata.movie_listing_id,
- season_title: movie.metadata.movie_listing_title,
+ season_id: movie.metadata.movie_listing_id.clone(),
+ season_title: movie.metadata.movie_listing_title.clone(),
season_number: 1,
- episode_id: movie.id,
+ episode_id: movie.id.clone(),
episode_number: 1.0,
+ relative_episode_number: 1.0,
}
}
-}
-
-/// Formats the given string if it has specific pattern in it. It's possible to sanitize it which
-/// removes characters which can cause failures if the output string is used as a file name.
-pub fn format_path(path: PathBuf, format: &Format, sanitize: bool) -> PathBuf {
- let sanitize_func = if sanitize {
- |s: &str| sanitize_filename::sanitize(s)
- } else {
- // converting this to a string is actually unnecessary
- |s: &str| s.to_string()
- };
-
- let as_string = path.to_string_lossy().to_string();
-
- PathBuf::from(
- as_string
- .replace("{title}", &sanitize_func(&format.title))
- .replace("{audio}", &sanitize_func(&format.audio.to_string()))
- .replace(
- "{resolution}",
- &sanitize_func(&format.stream.resolution.to_string()),
- )
- .replace("{series_id}", &sanitize_func(&format.series_id))
- .replace("{series_name}", &sanitize_func(&format.series_name))
- .replace("{season_id}", &sanitize_func(&format.season_id))
- .replace("{season_name}", &sanitize_func(&format.season_title))
- .replace(
- "{season_number}",
- &sanitize_func(&format.season_number.to_string()),
- )
- .replace(
- "{padded_season_number}",
- &sanitize_func(&format!("{:0>2}", format.season_number.to_string())),
- )
- .replace("{episode_id}", &sanitize_func(&format.episode_id))
- .replace("{episode_number}", &sanitize_func(&format.episode_number.to_string()))
- .replace(
- "{padded_episode_number}",
- &sanitize_func(&format!("{:0>2}", format.episode_number.to_string())),
- ),
- )
+
+ /// Formats the given string if it has specific pattern in it. It's possible to sanitize it which
+ /// removes characters which can cause failures if the output string is used as a file name.
+ pub fn format_path(&self, path: PathBuf, sanitize: bool) -> PathBuf {
+ let sanitize_func = if sanitize {
+ |s: &str| sanitize_filename::sanitize(s)
+ } else {
+ // converting this to a string is actually unnecessary
+ |s: &str| s.to_string()
+ };
+
+ let as_string = path.to_string_lossy().to_string();
+
+ PathBuf::from(
+ as_string
+ .replace("{title}", &sanitize_func(&self.title))
+ .replace("{audio}", &sanitize_func(&self.audio.to_string()))
+ .replace(
+ "{resolution}",
+ &sanitize_func(&self.stream.resolution.to_string()),
+ )
+ .replace("{series_id}", &sanitize_func(&self.series_id))
+ .replace("{series_name}", &sanitize_func(&self.series_name))
+ .replace("{season_id}", &sanitize_func(&self.season_id))
+ .replace("{season_name}", &sanitize_func(&self.season_title))
+ .replace(
+ "{season_number}",
+ &sanitize_func(&self.season_number.to_string()),
+ )
+ .replace(
+ "{padded_season_number}",
+ &sanitize_func(&format!("{:0>2}", self.season_number.to_string())),
+ )
+ .replace("{episode_id}", &sanitize_func(&self.episode_id))
+ .replace(
+ "{episode_number}",
+ &sanitize_func(&self.episode_number.to_string()),
+ )
+ .replace(
+ "{padded_episode_number}",
+ &sanitize_func(&format!("{:0>2}", self.episode_number.to_string())),
+ )
+ .replace(
+ "{relative_episode_number}",
+ &sanitize_func(&format!("{:0>2}", self.relative_episode_number.to_string())),
+ ),
+ )
+ }
+
+ pub fn has_relative_episodes_fmt>(s: S) -> bool {
+ return s.as_ref().contains("{relative_episode_number}");
+ }
}
From 2ea036d4c6b7faa5bdc33da1eb9a630126ef1e05 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 19:12:31 +0100
Subject: [PATCH 067/395] Remove padded_*_number and make it default for
*_number for output format
---
crunchy-cli-core/src/utils/format.rs | 8 --------
1 file changed, 8 deletions(-)
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index 3db28c3..60596ad 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -118,19 +118,11 @@ impl Format {
.replace("{season_name}", &sanitize_func(&self.season_title))
.replace(
"{season_number}",
- &sanitize_func(&self.season_number.to_string()),
- )
- .replace(
- "{padded_season_number}",
&sanitize_func(&format!("{:0>2}", self.season_number.to_string())),
)
.replace("{episode_id}", &sanitize_func(&self.episode_id))
.replace(
"{episode_number}",
- &sanitize_func(&self.episode_number.to_string()),
- )
- .replace(
- "{padded_episode_number}",
&sanitize_func(&format!("{:0>2}", self.episode_number.to_string())),
)
.replace(
From a0aab3bfb964195128abb25ed5c0cfa0f4841707 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 23:25:16 +0100
Subject: [PATCH 068/395] Add arabic locale in duplicated seasons check
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index bc19b07..da56f5e 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -332,7 +332,7 @@ impl FFmpegPreset {
}
lazy_static! {
- static ref DUPLICATED_SEASONS_MULTILANG_REGEX: Regex = Regex::new(r"(-castilian|-english|-english-in|-french|-german|-hindi|-italian|-portuguese|-russian|-spanish)$").unwrap();
+ static ref DUPLICATED_SEASONS_MULTILANG_REGEX: Regex = Regex::new(r"(-arabic|-castilian|-english|-english-in|-french|-german|-hindi|-italian|-portuguese|-russian|-spanish)$").unwrap();
}
pub(crate) fn find_multiple_seasons_with_same_number(seasons: &Vec>) -> Vec {
From 3029325776de09ef159081df847ae67cea3be93d Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Mon, 9 Jan 2023 23:40:53 +0100
Subject: [PATCH 069/395] Add check if request locale is valid (#102)
---
crunchy-cli-core/src/lib.rs | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 52a4da1..6cef42e 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -6,7 +6,7 @@ use anyhow::bail;
use anyhow::Result;
use clap::{Parser, Subcommand};
use crunchyroll_rs::{Crunchyroll, Locale};
-use log::{debug, error, LevelFilter};
+use log::{debug, error, warn, LevelFilter};
use std::{env, fs};
mod cli;
@@ -189,8 +189,41 @@ async fn create_ctx(cli: &Cli) -> Result {
}
async fn crunchyroll_session(cli: &Cli) -> Result {
+ let supported_langs = vec![
+ Locale::ar_ME,
+ Locale::de_DE,
+ Locale::en_US,
+ Locale::es_ES,
+ Locale::es_419,
+ Locale::fr_FR,
+ Locale::it_IT,
+ Locale::pt_BR,
+ Locale::pt_PT,
+ Locale::ru_RU,
+ ];
+ let locale = if let Some(lang) = &cli.lang {
+ if !supported_langs.contains(lang) {
+ bail!(
+ "Via `--lang` specified language is not supported. Supported languages: {}",
+ supported_langs
+ .iter()
+ .map(|l| format!("`{}` ({})", l.to_string(), l.to_human_readable()))
+ .collect::>()
+ .join(", ")
+ )
+ }
+ lang.clone()
+ } else {
+ let mut lang = system_locale();
+ if !supported_langs.contains(&lang) {
+ warn!("Recognized system locale is not supported. Using en-US as default. Use `--lang` to overwrite the used language");
+ lang = Locale::en_US
+ }
+ lang
+ };
+
let builder = Crunchyroll::builder()
- .locale(cli.lang.clone().unwrap_or_else(system_locale))
+ .locale(locale)
.stabilization_locales(true);
let login_methods_count = cli.login_method.credentials.is_some() as u8
From 5ce5b249c91fbfa752e4779bb0a9776c740ec88b Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 10 Jan 2023 19:20:08 +0100
Subject: [PATCH 070/395] Add relative episode number to cli help
---
crunchy-cli-core/src/cli/archive.rs | 3 +--
crunchy-cli-core/src/cli/download.rs | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 96d0737..768c629 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -67,10 +67,9 @@ pub struct Archive {
{season_name} → Name of the season\n \
{audio} → Audio language of the video\n \
{resolution} → Resolution of the video\n \
- {padded_season_number} → Number of the season padded to double digits\n \
{season_number} → Number of the season\n \
- {padded_episode_number} → Number of the episode padded to double digits\n \
{episode_number} → Number of the episode\n \
+ {relative_episode_number} → Number of the episode relative to its season\
{series_id} → ID of the series\n \
{season_id} → ID of the season\n \
{episode_id} → ID of the episode")]
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index d027df7..7a49a4c 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -45,10 +45,9 @@ pub struct Download {
{season_name} → Name of the season\n \
{audio} → Audio language of the video\n \
{resolution} → Resolution of the video\n \
- {padded_season_number} → Number of the season padded to double digits\n \
{season_number} → Number of the season\n \
- {padded_episode_number} → Number of the episode padded to double digits\n \
{episode_number} → Number of the episode\n \
+ {relative_episode_number} → Number of the episode relative to its season\
{series_id} → ID of the series\n \
{season_id} → ID of the season\n \
{episode_id} → ID of the episode")]
From 17233f2fd2721dc4f9e1b86957cb404d09f73249 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 10 Jan 2023 22:15:36 +0100
Subject: [PATCH 071/395] Update dependencies and version
---
Cargo.lock | 26 ++++++++++++++++----------
Cargo.toml | 2 +-
crunchy-cli-core/Cargo.lock | 24 +++++++++++++++---------
crunchy-cli-core/Cargo.toml | 2 +-
4 files changed, 33 insertions(+), 21 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 77e1342..42fe778 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -60,6 +60,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+[[package]]
+name = "base64"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -279,7 +285,7 @@ dependencies = [
[[package]]
name = "crunchy-cli"
-version = "3.0.0-dev.7"
+version = "3.0.0-dev.8"
dependencies = [
"chrono",
"clap",
@@ -291,7 +297,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.7"
+version = "3.0.0-dev.8"
dependencies = [
"anyhow",
"async-trait",
@@ -318,9 +324,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "184d0c725a09aec815316cbf41a2f362008ecb0e8c8e3b6b9930d01a89b5df21"
+checksum = "f3770cda4c67e68c689c8e361af46bb9d017caf82263905358fd0751d10657a0"
dependencies = [
"aes",
"async-trait",
@@ -343,9 +349,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f3c82e1766339727fc2c10d66d0c4f001b1cf42e2993f9d93997b610f408776"
+checksum = "4a260a73e733bb0ce30343caaed5e968d3c1cc2ea0ab27c601481e9ef22a2fd7"
dependencies = [
"darling",
"quote",
@@ -1268,7 +1274,7 @@ version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [
- "base64",
+ "base64 0.13.1",
"bytes",
"cookie",
"cookie_store",
@@ -1356,11 +1362,11 @@ dependencies = [
[[package]]
name = "rustls-pemfile"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
+checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
- "base64",
+ "base64 0.21.0",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index ec8e4ef..db1f129 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.7"
+version = "3.0.0-dev.8"
edition = "2021"
[dependencies]
diff --git a/crunchy-cli-core/Cargo.lock b/crunchy-cli-core/Cargo.lock
index 5bdabf0..b12b3a3 100644
--- a/crunchy-cli-core/Cargo.lock
+++ b/crunchy-cli-core/Cargo.lock
@@ -60,6 +60,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+[[package]]
+name = "base64"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -260,7 +266,7 @@ dependencies = [
[[package]]
name = "crunchy-cli-core"
-version = "3.0.0-dev.7"
+version = "3.0.0-dev.8"
dependencies = [
"anyhow",
"async-trait",
@@ -287,9 +293,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "184d0c725a09aec815316cbf41a2f362008ecb0e8c8e3b6b9930d01a89b5df21"
+checksum = "f3770cda4c67e68c689c8e361af46bb9d017caf82263905358fd0751d10657a0"
dependencies = [
"aes",
"async-trait",
@@ -312,9 +318,9 @@ dependencies = [
[[package]]
name = "crunchyroll-rs-internal"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f3c82e1766339727fc2c10d66d0c4f001b1cf42e2993f9d93997b610f408776"
+checksum = "4a260a73e733bb0ce30343caaed5e968d3c1cc2ea0ab27c601481e9ef22a2fd7"
dependencies = [
"darling",
"quote",
@@ -1237,7 +1243,7 @@ version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [
- "base64",
+ "base64 0.13.1",
"bytes",
"cookie",
"cookie_store",
@@ -1319,11 +1325,11 @@ dependencies = [
[[package]]
name = "rustls-pemfile"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
+checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
- "base64",
+ "base64 0.21.0",
]
[[package]]
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 5bda1db..8eea6a8 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "crunchy-cli-core"
authors = ["Crunchy Labs Maintainers"]
-version = "3.0.0-dev.7"
+version = "3.0.0-dev.8"
edition = "2021"
[dependencies]
From 6d1f8d49f67aabbc9b1cf577fce38c3209993371 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 13 Jan 2023 15:21:23 +0100
Subject: [PATCH 072/395] Add hardsubs manually to download videos (#81)
---
crunchy-cli-core/src/cli/archive.rs | 151 +------------------------
crunchy-cli-core/src/cli/download.rs | 134 +++++++++++++---------
crunchy-cli-core/src/cli/utils.rs | 20 ++--
crunchy-cli-core/src/utils/format.rs | 6 +-
crunchy-cli-core/src/utils/mod.rs | 1 +
crunchy-cli-core/src/utils/subtitle.rs | 108 ++++++++++++++++++
crunchy-cli-core/src/utils/video.rs | 25 ++++
7 files changed, 233 insertions(+), 212 deletions(-)
create mode 100644 crunchy-cli-core/src/utils/video.rs
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 768c629..c7030b4 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -9,16 +9,14 @@ use crate::utils::log::progress;
use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
-use crate::utils::subtitle::Subtitle;
+use crate::utils::subtitle::{download_subtitle, Subtitle};
+use crate::utils::video::get_video_length;
use crate::Execute;
use anyhow::{bail, Result};
-use chrono::NaiveTime;
-use crunchyroll_rs::media::{Resolution, StreamSubtitle};
+use crunchyroll_rs::media::Resolution;
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
use log::{debug, error, info, warn};
-use regex::Regex;
use std::collections::BTreeMap;
-use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use tempfile::TempPath;
@@ -113,14 +111,6 @@ pub struct Archive {
)]
#[arg(long)]
default_subtitle: Option,
- #[arg(help = "Disable subtitle optimizations")]
- #[arg(
- long_help = "By default, Crunchyroll delivers subtitles in a format which may cause issues in some video players. \
- These issues are fixed internally by setting a flag which is not part of the official specification of the subtitle format. \
- If you do not want this fixes or they cause more trouble than they solve (for you), it can be disabled with this flag"
- )]
- #[arg(long)]
- no_subtitle_optimizations: bool,
#[arg(help = "Ignore interactive input")]
#[arg(short, long, default_value_t = false)]
@@ -326,12 +316,8 @@ impl Execute for Archive {
let primary_video_length = get_video_length(primary_video.to_path_buf()).unwrap();
for subtitle in subtitles {
subtitle_paths.push((
- download_subtitle(
- &self,
- subtitle.stream_subtitle.clone(),
- primary_video_length,
- )
- .await?,
+ download_subtitle(subtitle.stream_subtitle.clone(), primary_video_length)
+ .await?,
subtitle,
))
}
@@ -436,7 +422,7 @@ async fn formats_from_series(
};
Some(subtitle)
}));
- formats.push(Format::new_from_episode(episode, &episodes, stream));
+ formats.push(Format::new_from_episode(episode, &episodes, stream, vec![]));
}
primary_season = false;
@@ -476,111 +462,6 @@ async fn download_video(ctx: &Context, format: &Format, only_audio: bool) -> Res
Ok(path)
}
-async fn download_subtitle(
- archive: &Archive,
- subtitle: StreamSubtitle,
- max_length: NaiveTime,
-) -> Result {
- let tempfile = tempfile(".ass")?;
- let (mut file, path) = tempfile.into_parts();
-
- let mut buf = vec![];
- subtitle.write_to(&mut buf).await?;
- if !archive.no_subtitle_optimizations {
- buf = fix_subtitle_look_and_feel(buf)
- }
- buf = fix_subtitle_length(buf, max_length);
-
- file.write_all(buf.as_slice())?;
-
- Ok(path)
-}
-
-/// Add `ScaledBorderAndShadows: yes` to subtitles; without it they look very messy on some video
-/// players. See [crunchy-labs/crunchy-cli#66](https://github.com/crunchy-labs/crunchy-cli/issues/66)
-/// for more information.
-fn fix_subtitle_look_and_feel(raw: Vec) -> Vec {
- let mut script_info = false;
- let mut new = String::new();
-
- for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
- if line.trim().starts_with('[') && script_info {
- new.push_str("ScaledBorderAndShadow: yes\n");
- script_info = false
- } else if line.trim() == "[Script Info]" {
- script_info = true
- }
- new.push_str(line);
- new.push('\n')
- }
-
- new.into_bytes()
-}
-
-/// Fix the length of subtitles to a specified maximum amount. This is required because sometimes
-/// subtitles have an unnecessary entry long after the actual video ends with artificially extends
-/// the video length on some video players. To prevent this, the video length must be hard set. See
-/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
-/// information.
-fn fix_subtitle_length(raw: Vec, max_length: NaiveTime) -> Vec {
- let re =
- Regex::new(r#"^Dialogue:\s\d+,(?P\d+:\d+:\d+\.\d+),(?P\d+:\d+:\d+\.\d+),"#)
- .unwrap();
-
- // chrono panics if we try to format NaiveTime with `%2f` and the nano seconds has more than 2
- // digits so them have to be reduced manually to avoid the panic
- fn format_naive_time(native_time: NaiveTime) -> String {
- let formatted_time = native_time.format("%f").to_string();
- format!(
- "{}.{}",
- native_time.format("%T"),
- if formatted_time.len() <= 2 {
- native_time.format("%2f").to_string()
- } else {
- formatted_time.split_at(2).0.parse().unwrap()
- }
- )
- }
-
- let length_as_string = format_naive_time(max_length);
- let mut new = String::new();
-
- for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
- if let Some(capture) = re.captures(line) {
- let start = capture.name("start").map_or(NaiveTime::default(), |s| {
- NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
- });
- let end = capture.name("end").map_or(NaiveTime::default(), |s| {
- NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
- });
-
- if start > max_length {
- continue;
- } else if end > max_length {
- new.push_str(
- re.replace(
- line,
- format!(
- "Dialogue: {},{},",
- format_naive_time(start),
- &length_as_string
- ),
- )
- .to_string()
- .as_str(),
- )
- } else {
- new.push_str(line)
- }
- } else {
- new.push_str(line)
- }
- new.push('\n')
- }
-
- new.into_bytes()
-}
-
fn generate_mkv(
archive: &Archive,
target: PathBuf,
@@ -721,23 +602,3 @@ fn generate_mkv(
Ok(())
}
-
-/// Get the length of a video. This is required because sometimes subtitles have an unnecessary entry
-/// long after the actual video ends with artificially extends the video length on some video players.
-/// To prevent this, the video length must be hard set. See
-/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
-/// information.
-fn get_video_length(path: PathBuf) -> Result {
- let video_length = Regex::new(r"Duration:\s(?P\d+:\d+:\d+\.\d+),")?;
-
- let ffmpeg = Command::new("ffmpeg")
- .stdout(Stdio::null())
- .stderr(Stdio::piped())
- .arg("-y")
- .args(["-i", path.to_str().unwrap()])
- .output()?;
- let ffmpeg_output = String::from_utf8(ffmpeg.stderr)?;
- let caps = video_length.captures(ffmpeg_output.as_str()).unwrap();
-
- Ok(NaiveTime::parse_from_str(caps.name("time").unwrap().as_str(), "%H:%M:%S%.f").unwrap())
-}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 7a49a4c..223162f 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -6,19 +6,21 @@ use crate::cli::utils::{
use crate::utils::context::Context;
use crate::utils::format::Format;
use crate::utils::log::progress;
-use crate::utils::os::{free_file, has_ffmpeg, is_special_file};
+use crate::utils::os::{free_file, has_ffmpeg, is_special_file, tempfile};
use crate::utils::parse::{parse_url, UrlFilter};
use crate::utils::sort::{sort_formats_after_seasons, sort_seasons_after_number};
+use crate::utils::subtitle::download_subtitle;
+use crate::utils::video::get_video_length;
use crate::Execute;
use anyhow::{bail, Result};
-use crunchyroll_rs::media::{Resolution, VariantData};
+use crunchyroll_rs::media::{Resolution, StreamSubtitle, VariantData};
use crunchyroll_rs::{
Episode, Locale, Media, MediaCollection, Movie, MovieListing, Season, Series,
};
use log::{debug, error, info, warn};
use std::borrow::Cow;
-use std::fs::File;
-use std::path::{Path, PathBuf};
+use std::io::Read;
+use std::path::Path;
use std::process::{Command, Stdio};
#[derive(Debug, clap::Parser)]
@@ -51,7 +53,7 @@ pub struct Download {
{series_id} → ID of the series\n \
{season_id} → ID of the season\n \
{episode_id} → ID of the episode")]
- #[arg(short, long, default_value = "{title}.ts")]
+ #[arg(short, long, default_value = "{title}.mp4")]
output: String,
#[arg(help = "Video resolution")]
@@ -85,17 +87,14 @@ pub struct Download {
#[async_trait::async_trait(?Send)]
impl Execute for Download {
fn pre_check(&self) -> Result<()> {
- if has_ffmpeg() {
- debug!("FFmpeg detected")
- } else if PathBuf::from(&self.output)
+ if !has_ffmpeg() {
+ bail!("FFmpeg is needed to run this command")
+ } else if Path::new(&self.output)
.extension()
.unwrap_or_default()
- .to_string_lossy()
- != "ts"
+ .is_empty()
{
- bail!("File extension is not '.ts'. If you want to use a custom file format, please install ffmpeg")
- } else if !self.ffmpeg_preset.is_empty() {
- bail!("FFmpeg is required to use (ffmpeg) presets")
+ bail!("No file extension found. Please specify a file extension (via `-o`) for the output file")
}
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
@@ -245,23 +244,14 @@ impl Execute for Download {
tab_info!("Resolution: {}", format.stream.resolution);
tab_info!("FPS: {:.2}", format.stream.fps);
- let extension = path.extension().unwrap_or_default().to_string_lossy();
-
- if (!extension.is_empty() && extension != "ts") || !self.ffmpeg_preset.is_empty() {
- download_ffmpeg(&ctx, &self, format.stream, path.as_path()).await?;
- } else if path.to_str().unwrap() == "-" {
- let mut stdout = std::io::stdout().lock();
- download_segments(&ctx, &mut stdout, None, format.stream).await?;
- } else {
- // create parent directory if it does not exist
- if let Some(parent) = path.parent() {
- if !parent.exists() {
- std::fs::create_dir_all(parent)?
- }
- }
- let mut file = File::options().create(true).write(true).open(&path)?;
- download_segments(&ctx, &mut file, None, format.stream).await?
- }
+ download_ffmpeg(
+ &ctx,
+ &self,
+ format.stream,
+ format.subtitles.get(0).cloned(),
+ path.as_path(),
+ )
+ .await?;
}
}
@@ -273,9 +263,10 @@ async fn download_ffmpeg(
ctx: &Context,
download: &Download,
variant_data: VariantData,
+ subtitle: Option,
target: &Path,
) -> Result<()> {
- let (input_presets, output_presets) =
+ let (input_presets, mut output_presets) =
FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
// create parent directory if it does not exist
@@ -285,32 +276,66 @@ async fn download_ffmpeg(
}
}
+ if let Some(ext) = target.extension() {
+ if ext.to_string_lossy() != "mp4" && subtitle.is_some() {
+ warn!("Detected a non mp4 output container. Adding subtitles may take a while")
+ }
+ }
+
+ let mut video_file = tempfile(".ts")?;
+ download_segments(ctx, &mut video_file, None, variant_data).await?;
+ let subtitle_file = if let Some(ref sub) = subtitle {
+ let video_len = get_video_length(video_file.path().to_path_buf())?;
+ Some(download_subtitle(sub.clone(), video_len).await?)
+ } else {
+ None
+ };
+
+ let subtitle_preset = if let Some(sub_file) = &subtitle_file {
+ if target.extension().unwrap_or_default().to_string_lossy() == "mp4" {
+ vec![
+ "-i".to_string(),
+ sub_file.to_string_lossy().to_string(),
+ "-c:s".to_string(),
+ "mov_text".to_string(),
+ "-disposition:s:s:0".to_string(),
+ "forced".to_string(),
+ ]
+ } else {
+ // remove '-c:v copy' and '-c:a copy' from output presets as its causes issues with
+ // burning subs into the video
+ let mut last = String::new();
+ let mut remove_count = 0;
+ for (i, s) in output_presets.clone().iter().enumerate() {
+ if (last == "-c:v" || last == "-c:a") && s == "copy" {
+ // remove last
+ output_presets.remove(i - remove_count - 1);
+ remove_count += 1;
+ output_presets.remove(i - remove_count);
+ remove_count += 1;
+ }
+ last = s.clone();
+ }
+
+ vec![
+ "-vf".to_string(),
+ format!("subtitles={}", sub_file.to_string_lossy()),
+ ]
+ }
+ } else {
+ vec![]
+ };
+
let mut ffmpeg = Command::new("ffmpeg")
- .stdin(Stdio::piped())
- .stdout(Stdio::null())
.stderr(Stdio::piped())
.arg("-y")
.args(input_presets)
- .args(["-f", "mpegts", "-i", "pipe:"])
- .args(
- if target
- .extension()
- .unwrap_or_default()
- .to_string_lossy()
- .is_empty()
- {
- vec!["-f", "mpegts"]
- } else {
- vec![]
- }
- .as_slice(),
- )
+ .args(["-i", video_file.path().to_string_lossy().as_ref()])
+ .args(subtitle_preset)
.args(output_presets)
.arg(target.to_str().unwrap())
.spawn()?;
- download_segments(ctx, &mut ffmpeg.stdin.take().unwrap(), None, variant_data).await?;
-
let _progress_handler = progress!("Generating output file");
ffmpeg.wait()?;
info!("Output file generated");
@@ -431,8 +456,11 @@ async fn format_from_episode(
}
let streams = episode.streams().await?;
- let streaming_data = if let Some(subtitle) = &download.subtitle {
- if !streams.subtitles.keys().cloned().any(|x| &x == subtitle) {
+ let streaming_data = streams.hls_streaming_data(None).await?;
+ let subtitle = if let Some(subtitle) = &download.subtitle {
+ if let Some(sub) = streams.subtitles.get(subtitle) {
+ Some(sub.clone())
+ } else {
error!(
"Episode {} ({}) of season {} ({}) of {} has no {} subtitles",
episode.metadata.episode_number,
@@ -444,9 +472,8 @@ async fn format_from_episode(
);
return Ok(None);
}
- streams.hls_streaming_data(Some(subtitle.clone())).await?
} else {
- streams.hls_streaming_data(None).await?
+ None
};
let Some(stream) = find_resolution(streaming_data, &download.resolution) else {
@@ -476,6 +503,7 @@ async fn format_from_episode(
episode,
&season_eps.to_vec(),
stream,
+ subtitle.map_or_else(|| vec![], |s| vec![s]),
)))
}
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index da56f5e..8a7a79a 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -290,38 +290,32 @@ impl FFmpegPreset {
FFmpegPreset::Av1 => bail!("'nvidia' hardware acceleration preset is not available in combination with the 'av1' codec preset"),
FFmpegPreset::H265 => {
input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "hevc_nvenc"]);
+ output.extend(["-c:v", "hevc_nvenc", "-c:a", "copy"]);
}
FFmpegPreset::H264 => {
input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "h264_nvenc"]);
+ output.extend(["-c:v", "h264_nvenc", "-c:a", "copy"]);
}
_ => ()
}
} else {
match preset {
FFmpegPreset::Av1 => {
- output.extend(["-c:v", "libaom-av1"]);
+ output.extend(["-c:v", "libaom-av1", "-c:a", "copy"]);
}
FFmpegPreset::H265 => {
- output.extend(["-c:v", "libx265"]);
+ output.extend(["-c:v", "libx265", "-c:a", "copy"]);
}
FFmpegPreset::H264 => {
- output.extend(["-c:v", "libx264"]);
+ output.extend(["-c:v", "libx264", "-c:a", "copy"]);
}
_ => (),
}
}
}
- if input.is_empty() && output.is_empty() {
- output.extend(["-c", "copy"])
- } else {
- if output.is_empty() {
- output.extend(["-c", "copy"])
- } else {
- output.extend(["-c:a", "copy", "-c:s", "copy"])
- }
+ if output.is_empty() {
+ output.extend(["-c:v", "copy", "-c:a", "copy"])
}
Ok((
diff --git a/crunchy-cli-core/src/utils/format.rs b/crunchy-cli-core/src/utils/format.rs
index 60596ad..93ee773 100644
--- a/crunchy-cli-core/src/utils/format.rs
+++ b/crunchy-cli-core/src/utils/format.rs
@@ -1,4 +1,4 @@
-use crunchyroll_rs::media::VariantData;
+use crunchyroll_rs::media::{StreamSubtitle, VariantData};
use crunchyroll_rs::{Episode, Locale, Media, Movie};
use log::warn;
use std::path::PathBuf;
@@ -10,6 +10,7 @@ pub struct Format {
pub description: String,
pub audio: Locale,
+ pub subtitles: Vec,
pub duration: Duration,
pub stream: VariantData,
@@ -31,12 +32,14 @@ impl Format {
episode: &Media,
season_episodes: &Vec>,
stream: VariantData,
+ subtitles: Vec,
) -> Self {
Self {
title: episode.title.clone(),
description: episode.description.clone(),
audio: episode.metadata.audio_locale.clone(),
+ subtitles,
duration: episode.metadata.duration.to_std().unwrap(),
stream,
@@ -78,6 +81,7 @@ impl Format {
duration: movie.metadata.duration.to_std().unwrap(),
stream,
+ subtitles: vec![],
series_id: movie.metadata.movie_listing_id.clone(),
series_name: movie.metadata.movie_listing_title.clone(),
diff --git a/crunchy-cli-core/src/utils/mod.rs b/crunchy-cli-core/src/utils/mod.rs
index 3b15a89..552c198 100644
--- a/crunchy-cli-core/src/utils/mod.rs
+++ b/crunchy-cli-core/src/utils/mod.rs
@@ -7,3 +7,4 @@ pub mod os;
pub mod parse;
pub mod sort;
pub mod subtitle;
+pub mod video;
diff --git a/crunchy-cli-core/src/utils/subtitle.rs b/crunchy-cli-core/src/utils/subtitle.rs
index 86b9359..f638b1b 100644
--- a/crunchy-cli-core/src/utils/subtitle.rs
+++ b/crunchy-cli-core/src/utils/subtitle.rs
@@ -1,5 +1,11 @@
+use crate::utils::os::tempfile;
+use anyhow::Result;
+use chrono::NaiveTime;
use crunchyroll_rs::media::StreamSubtitle;
use crunchyroll_rs::Locale;
+use regex::Regex;
+use std::io::Write;
+use tempfile::TempPath;
#[derive(Clone)]
pub struct Subtitle {
@@ -9,3 +15,105 @@ pub struct Subtitle {
pub forced: bool,
pub primary: bool,
}
+
+pub async fn download_subtitle(
+ subtitle: StreamSubtitle,
+ max_length: NaiveTime,
+) -> Result {
+ let tempfile = tempfile(".ass")?;
+ let (mut file, path) = tempfile.into_parts();
+
+ let mut buf = vec![];
+ subtitle.write_to(&mut buf).await?;
+ buf = fix_subtitle_look_and_feel(buf);
+ buf = fix_subtitle_length(buf, max_length);
+
+ file.write_all(buf.as_slice())?;
+
+ Ok(path)
+}
+
+/// Add `ScaledBorderAndShadows: yes` to subtitles; without it they look very messy on some video
+/// players. See [crunchy-labs/crunchy-cli#66](https://github.com/crunchy-labs/crunchy-cli/issues/66)
+/// for more information.
+fn fix_subtitle_look_and_feel(raw: Vec) -> Vec {
+ let mut script_info = false;
+ let mut new = String::new();
+
+ for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
+ if line.trim().starts_with('[') && script_info {
+ new.push_str("ScaledBorderAndShadow: yes\n");
+ script_info = false
+ } else if line.trim() == "[Script Info]" {
+ script_info = true
+ }
+ new.push_str(line);
+ new.push('\n')
+ }
+
+ new.into_bytes()
+}
+
+/// Fix the length of subtitles to a specified maximum amount. This is required because sometimes
+/// subtitles have an unnecessary entry long after the actual video ends with artificially extends
+/// the video length on some video players. To prevent this, the video length must be hard set. See
+/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
+/// information.
+fn fix_subtitle_length(raw: Vec, max_length: NaiveTime) -> Vec {
+ let re =
+ Regex::new(r#"^Dialogue:\s\d+,(?P\d+:\d+:\d+\.\d+),(?P\d+:\d+:\d+\.\d+),"#)
+ .unwrap();
+
+ // chrono panics if we try to format NaiveTime with `%2f` and the nano seconds has more than 2
+ // digits so them have to be reduced manually to avoid the panic
+ fn format_naive_time(native_time: NaiveTime) -> String {
+ let formatted_time = native_time.format("%f").to_string();
+ format!(
+ "{}.{}",
+ native_time.format("%T"),
+ if formatted_time.len() <= 2 {
+ native_time.format("%2f").to_string()
+ } else {
+ formatted_time.split_at(2).0.parse().unwrap()
+ }
+ )
+ }
+
+ let length_as_string = format_naive_time(max_length);
+ let mut new = String::new();
+
+ for line in String::from_utf8_lossy(raw.as_slice()).split('\n') {
+ if let Some(capture) = re.captures(line) {
+ let start = capture.name("start").map_or(NaiveTime::default(), |s| {
+ NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
+ });
+ let end = capture.name("end").map_or(NaiveTime::default(), |s| {
+ NaiveTime::parse_from_str(s.as_str(), "%H:%M:%S.%f").unwrap()
+ });
+
+ if start > max_length {
+ continue;
+ } else if end > max_length {
+ new.push_str(
+ re.replace(
+ line,
+ format!(
+ "Dialogue: {},{},",
+ format_naive_time(start),
+ &length_as_string
+ ),
+ )
+ .to_string()
+ .as_str(),
+ )
+ } else {
+ new.push_str(line)
+ }
+ } else {
+ new.push_str(line)
+ }
+ new.push('\n')
+ }
+
+ new.into_bytes()
+}
diff --git a/crunchy-cli-core/src/utils/video.rs b/crunchy-cli-core/src/utils/video.rs
new file mode 100644
index 0000000..2d12bfc
--- /dev/null
+++ b/crunchy-cli-core/src/utils/video.rs
@@ -0,0 +1,25 @@
+use anyhow::Result;
+use chrono::NaiveTime;
+use regex::Regex;
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+
+/// Get the length of a video. This is required because sometimes subtitles have an unnecessary entry
+/// long after the actual video ends with artificially extends the video length on some video players.
+/// To prevent this, the video length must be hard set. See
+/// [crunchy-labs/crunchy-cli#32](https://github.com/crunchy-labs/crunchy-cli/issues/32) for more
+/// information.
+pub fn get_video_length(path: PathBuf) -> Result {
+ let video_length = Regex::new(r"Duration:\s(?P\d+:\d+:\d+\.\d+),")?;
+
+ let ffmpeg = Command::new("ffmpeg")
+ .stdout(Stdio::null())
+ .stderr(Stdio::piped())
+ .arg("-y")
+ .args(["-i", path.to_str().unwrap()])
+ .output()?;
+ let ffmpeg_output = String::from_utf8(ffmpeg.stderr)?;
+ let caps = video_length.captures(ffmpeg_output.as_str()).unwrap();
+
+ Ok(NaiveTime::parse_from_str(caps.name("time").unwrap().as_str(), "%H:%M:%S%.f").unwrap())
+}
From 08c4e30a06d13703d948ccc431a4f459e8c53fa5 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 13 Jan 2023 16:03:19 +0100
Subject: [PATCH 073/395] (Re-)add download pipe to stdout
---
crunchy-cli-core/src/cli/download.rs | 43 ++++++++++++++++++++--------
1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 223162f..9885b3c 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -19,8 +19,7 @@ use crunchyroll_rs::{
};
use log::{debug, error, info, warn};
use std::borrow::Cow;
-use std::io::Read;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
#[derive(Debug, clap::Parser)]
@@ -93,10 +92,19 @@ impl Execute for Download {
.extension()
.unwrap_or_default()
.is_empty()
+ && self.output != "-"
{
bail!("No file extension found. Please specify a file extension (via `-o`) for the output file")
}
+ if self.subtitle.is_some() {
+ if let Some(ext) = Path::new(&self.output).extension() {
+ if ext.to_string_lossy() != "mp4" {
+ warn!("Detected a non mp4 output container. Adding subtitles may take a while")
+ }
+ }
+ }
+
let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
if self.ffmpeg_preset.len() == 1
&& self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia
@@ -249,7 +257,7 @@ impl Execute for Download {
&self,
format.stream,
format.subtitles.get(0).cloned(),
- path.as_path(),
+ path.to_path_buf(),
)
.await?;
}
@@ -264,7 +272,7 @@ async fn download_ffmpeg(
download: &Download,
variant_data: VariantData,
subtitle: Option,
- target: &Path,
+ mut target: PathBuf,
) -> Result<()> {
let (input_presets, mut output_presets) =
FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
@@ -276,12 +284,6 @@ async fn download_ffmpeg(
}
}
- if let Some(ext) = target.extension() {
- if ext.to_string_lossy() != "mp4" && subtitle.is_some() {
- warn!("Detected a non mp4 output container. Adding subtitles may take a while")
- }
- }
-
let mut video_file = tempfile(".ts")?;
download_segments(ctx, &mut video_file, None, variant_data).await?;
let subtitle_file = if let Some(ref sub) = subtitle {
@@ -291,11 +293,22 @@ async fn download_ffmpeg(
None
};
- let subtitle_preset = if let Some(sub_file) = &subtitle_file {
+ let stdout_tempfile = if target.to_string_lossy() == "-" {
+ let file = tempfile(".mp4")?;
+ target = file.path().to_path_buf();
+
+ Some(file)
+ } else {
+ None
+ };
+
+ let subtitle_presets = if let Some(sub_file) = &subtitle_file {
if target.extension().unwrap_or_default().to_string_lossy() == "mp4" {
vec![
"-i".to_string(),
sub_file.to_string_lossy().to_string(),
+ "-movflags".to_string(),
+ "faststart".to_string(),
"-c:s".to_string(),
"mov_text".to_string(),
"-disposition:s:s:0".to_string(),
@@ -331,7 +344,7 @@ async fn download_ffmpeg(
.arg("-y")
.args(input_presets)
.args(["-i", video_file.path().to_string_lossy().as_ref()])
- .args(subtitle_preset)
+ .args(subtitle_presets)
.args(output_presets)
.arg(target.to_str().unwrap())
.spawn()?;
@@ -340,6 +353,12 @@ async fn download_ffmpeg(
ffmpeg.wait()?;
info!("Output file generated");
+ if let Some(mut stdout_file) = stdout_tempfile {
+ let mut stdout = std::io::stdout();
+
+ std::io::copy(&mut stdout_file, &mut stdout)?;
+ }
+
Ok(())
}
From 3d145b021baa207016b9ca419c33cfbd4bf8aa46 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 13 Jan 2023 16:04:53 +0100
Subject: [PATCH 074/395] Add download ffmpeg error output
---
crunchy-cli-core/src/cli/download.rs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 9885b3c..66027a2 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -340,6 +340,7 @@ async fn download_ffmpeg(
};
let mut ffmpeg = Command::new("ffmpeg")
+ .stdout(Stdio::null())
.stderr(Stdio::piped())
.arg("-y")
.args(input_presets)
@@ -350,7 +351,9 @@ async fn download_ffmpeg(
.spawn()?;
let _progress_handler = progress!("Generating output file");
- ffmpeg.wait()?;
+ if !ffmpeg.wait()?.success() {
+ bail!("{}", std::io::read_to_string(ffmpeg.stderr.unwrap())?)
+ }
info!("Output file generated");
if let Some(mut stdout_file) = stdout_tempfile {
From 497f22ee49e0476203e75abef56413e891a584cb Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Fri, 13 Jan 2023 22:38:29 +0100
Subject: [PATCH 075/395] Fix double download progress output message
---
crunchy-cli-core/src/cli/download.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 66027a2..05372a4 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -350,11 +350,11 @@ async fn download_ffmpeg(
.arg(target.to_str().unwrap())
.spawn()?;
- let _progress_handler = progress!("Generating output file");
+ let progress_handler = progress!("Generating output file");
if !ffmpeg.wait()?.success() {
bail!("{}", std::io::read_to_string(ffmpeg.stderr.unwrap())?)
}
- info!("Output file generated");
+ progress_handler.stop("Output file generated");
if let Some(mut stdout_file) = stdout_tempfile {
let mut stdout = std::io::stdout();
From 685ac85857c37b7d6abd53c3171faeda4b1a8fd5 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 15 Jan 2023 21:38:35 +0100
Subject: [PATCH 076/395] Add flag to skip existing files (#67, #109)
---
crunchy-cli-core/src/cli/archive.rs | 31 +++++++++++++++++++---------
crunchy-cli-core/src/cli/download.rs | 31 +++++++++++++++++++---------
crunchy-cli-core/src/utils/os.rs | 6 +++---
3 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 768c629..a8b79b6 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -122,6 +122,10 @@ pub struct Archive {
#[arg(long)]
no_subtitle_optimizations: bool,
+ #[arg(help = "Skip files which are already existing")]
+ #[arg(long, default_value_t = false)]
+ skip_existing: bool,
+
#[arg(help = "Ignore interactive input")]
#[arg(short, long, default_value_t = false)]
yes: bool,
@@ -242,17 +246,24 @@ impl Execute for Archive {
for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
- let path = free_file(
- primary.format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- true,
- ),
+ let formatted_path = primary.format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ true,
);
+ let (path, changed) = free_file(formatted_path.clone());
+
+ if changed && self.skip_existing {
+ debug!(
+ "Skipping already existing file '{}'",
+ formatted_path.to_string_lossy()
+ );
+ continue;
+ }
info!(
"Downloading {} to '{}'",
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 7a49a4c..fddbfd3 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -74,6 +74,10 @@ pub struct Download {
#[arg(value_parser = FFmpegPreset::parse)]
ffmpeg_preset: Vec,
+ #[arg(help = "Skip files which are already existing")]
+ #[arg(long, default_value_t = false)]
+ skip_existing: bool,
+
#[arg(help = "Ignore interactive input")]
#[arg(short, long, default_value_t = false)]
yes: bool,
@@ -209,17 +213,24 @@ impl Execute for Download {
}
for format in formats {
- let path = free_file(
- format.format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- true,
- ),
+ let formatted_path = format.format_path(
+ if self.output.is_empty() {
+ "{title}.mkv"
+ } else {
+ &self.output
+ }
+ .into(),
+ true,
);
+ let (path, changed) = free_file(formatted_path.clone());
+
+ if changed && self.skip_existing {
+ debug!(
+ "Skipping already existing file '{}'",
+ formatted_path.to_string_lossy()
+ );
+ continue;
+ }
info!(
"Downloading {} to '{}'",
diff --git a/crunchy-cli-core/src/utils/os.rs b/crunchy-cli-core/src/utils/os.rs
index a7b3fbf..94e9d02 100644
--- a/crunchy-cli-core/src/utils/os.rs
+++ b/crunchy-cli-core/src/utils/os.rs
@@ -36,10 +36,10 @@ pub fn tempfile>(suffix: S) -> io::Result {
}
/// Check if the given path exists and rename it until the new (renamed) file does not exist.
-pub fn free_file(mut path: PathBuf) -> PathBuf {
+pub fn free_file(mut path: PathBuf) -> (PathBuf, bool) {
// if it's a special file does not rename it
if is_special_file(&path) {
- return path;
+ return (path, false);
}
let mut i = 0;
@@ -55,7 +55,7 @@ pub fn free_file(mut path: PathBuf) -> PathBuf {
path.set_file_name(format!("{} ({}).{}", filename, i, ext))
}
- path
+ (path, i != 0)
}
/// Check if the given path is a special file. On Linux this is probably a pipe and on Windows
From 577c0679adee027dc52801a8745968a830d35120 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 15 Jan 2023 21:43:31 +0100
Subject: [PATCH 077/395] Remove automatically set filename if output is empty
---
crunchy-cli-core/src/cli/archive.rs | 10 +---------
crunchy-cli-core/src/cli/download.rs | 10 +---------
2 files changed, 2 insertions(+), 18 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index a8b79b6..31d39c6 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -246,15 +246,7 @@ impl Execute for Archive {
for (formats, mut subtitles) in archive_formats {
let (primary, additionally) = formats.split_first().unwrap();
- let formatted_path = primary.format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- true,
- );
+ let formatted_path = primary.format_path((&self.output).into(), true);
let (path, changed) = free_file(formatted_path.clone());
if changed && self.skip_existing {
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index fddbfd3..d8fb003 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -213,15 +213,7 @@ impl Execute for Download {
}
for format in formats {
- let formatted_path = format.format_path(
- if self.output.is_empty() {
- "{title}.mkv"
- } else {
- &self.output
- }
- .into(),
- true,
- );
+ let formatted_path = format.format_path((&self.output).into(), true);
let (path, changed) = free_file(formatted_path.clone());
if changed && self.skip_existing {
From 3dd8385aac345c3a7f3b9f817810c0e74f82a35e Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 15 Jan 2023 22:09:23 +0100
Subject: [PATCH 078/395] (Re-)enable -l all for archive (#110)
---
crunchy-cli-core/src/cli/archive.rs | 9 ++++++---
crunchy-cli-core/src/cli/download.rs | 6 +++---
crunchy-cli-core/src/cli/utils.rs | 16 +++++++++++++++-
crunchy-cli-core/src/lib.rs | 6 +++---
4 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 768c629..d7e6bf9 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -1,7 +1,7 @@
use crate::cli::log::tab_info;
use crate::cli::utils::{
- download_segments, find_multiple_seasons_with_same_number, find_resolution,
- interactive_season_choosing, FFmpegPreset,
+ all_locale_in_locales, download_segments, find_multiple_seasons_with_same_number,
+ find_resolution, interactive_season_choosing, FFmpegPreset,
};
use crate::utils::context::Context;
use crate::utils::format::Format;
@@ -132,7 +132,7 @@ pub struct Archive {
#[async_trait::async_trait(?Send)]
impl Execute for Archive {
- fn pre_check(&self) -> Result<()> {
+ fn pre_check(&mut self) -> Result<()> {
if !has_ffmpeg() {
bail!("FFmpeg is needed to run this command")
} else if PathBuf::from(&self.output)
@@ -151,6 +151,9 @@ impl Execute for Archive {
warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
}
+ self.locale = all_locale_in_locales(self.locale.clone());
+ self.subtitle = all_locale_in_locales(self.subtitle.clone());
+
Ok(())
}
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index 7a49a4c..2f83ffd 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,7 +1,7 @@
use crate::cli::log::tab_info;
use crate::cli::utils::{
- download_segments, find_multiple_seasons_with_same_number, find_resolution,
- interactive_season_choosing, FFmpegPreset,
+ download_segments, find_multiple_seasons_with_same_number,
+ find_resolution, interactive_season_choosing, FFmpegPreset,
};
use crate::utils::context::Context;
use crate::utils::format::Format;
@@ -84,7 +84,7 @@ pub struct Download {
#[async_trait::async_trait(?Send)]
impl Execute for Download {
- fn pre_check(&self) -> Result<()> {
+ fn pre_check(&mut self) -> Result<()> {
if has_ffmpeg() {
debug!("FFmpeg detected")
} else if PathBuf::from(&self.output)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index da56f5e..84850f8 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -1,7 +1,7 @@
use crate::utils::context::Context;
use anyhow::{bail, Result};
use crunchyroll_rs::media::{Resolution, VariantData, VariantSegment};
-use crunchyroll_rs::{Media, Season};
+use crunchyroll_rs::{Locale, Media, Season};
use indicatif::{ProgressBar, ProgressFinish, ProgressStyle};
use lazy_static::lazy_static;
use log::{debug, LevelFilter};
@@ -369,6 +369,20 @@ pub(crate) fn find_multiple_seasons_with_same_number(seasons: &Vec
.collect()
}
+/// Check if [`Locale::Custom("all")`] is in the provided locale list and return [`Locale::all`] if
+/// so. If not, just return the provided locale list.
+pub(crate) fn all_locale_in_locales(locales: Vec) -> Vec {
+ if locales
+ .iter()
+ .find(|l| l.to_string().to_lowercase().trim() == "all")
+ .is_some()
+ {
+ Locale::all()
+ } else {
+ locales
+ }
+}
+
pub(crate) fn interactive_season_choosing(seasons: Vec>) -> Vec> {
let input_regex =
Regex::new(r"((?P\d+)|(?P\d+)-(?P\d+)?)(\s|$)").unwrap();
diff --git a/crunchy-cli-core/src/lib.rs b/crunchy-cli-core/src/lib.rs
index 6cef42e..ab3f33c 100644
--- a/crunchy-cli-core/src/lib.rs
+++ b/crunchy-cli-core/src/lib.rs
@@ -16,10 +16,10 @@ pub use cli::{archive::Archive, download::Download, login::Login};
#[async_trait::async_trait(?Send)]
trait Execute {
- fn pre_check(&self) -> Result<()> {
+ fn pre_check(&mut self) -> Result<()> {
Ok(())
}
- async fn execute(self, ctx: Context) -> Result<()>;
+ async fn execute(mut self, ctx: Context) -> Result<()>;
}
#[derive(Debug, Parser)]
@@ -171,7 +171,7 @@ pub async fn cli_entrypoint() {
/// Cannot be done in the main function. I wanted to return `dyn` [`Execute`] from the match but had to
/// box it which then conflicts with [`Execute::execute`] which consumes `self`
-async fn execute_executor(executor: impl Execute, ctx: Context) {
+async fn execute_executor(mut executor: impl Execute, ctx: Context) {
if let Err(err) = executor.pre_check() {
error!("Misconfigurations detected: {}", err);
std::process::exit(1)
From 6bd75c93cb554eba55a63ccd08bb3bd05dfdc49d Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 15 Jan 2023 22:18:10 +0100
Subject: [PATCH 079/395] Simplify archive no audio present output
---
crunchy-cli-core/src/cli/archive.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index d7e6bf9..7c26d33 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -366,12 +366,12 @@ async fn formats_from_series(
.into_iter()
.filter(|l| !season.iter().any(|s| s.metadata.audio_locales.contains(l)))
.collect::>();
- for not_present in not_present_audio {
+ if !not_present_audio.is_empty() {
error!(
"Season {} of series {} is not available with {} audio",
season.first().unwrap().metadata.season_number,
series.title,
- not_present
+ not_present_audio.into_iter().map(|l| l.to_string()).collect::>().join(", ")
)
}
From b3226cdde54ae1381e1a38d720b3f3880ea642df Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Tue, 17 Jan 2023 17:25:09 +0100
Subject: [PATCH 080/395] Change av1 encoder to libsvtav1 (#108)
---
crunchy-cli-core/src/cli/utils.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 0e9e02f..7352d95 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -301,7 +301,7 @@ impl FFmpegPreset {
} else {
match preset {
FFmpegPreset::Av1 => {
- output.extend(["-c:v", "libaom-av1", "-c:a", "copy"]);
+ output.extend(["-c:v", "libsvtav1", "-c:a", "copy"]);
}
FFmpegPreset::H265 => {
output.extend(["-c:v", "libx265", "-c:a", "copy"]);
From 21a5782825e41449a0d9fe62a72775907a22cbb5 Mon Sep 17 00:00:00 2001
From: Hannes Braun
Date: Tue, 17 Jan 2023 21:06:57 +0100
Subject: [PATCH 081/395] Don't remove the subtitles if the video is detected
to be identical
---
crunchy-cli-core/src/cli/archive.rs | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index e0fc9b0..2c06ca0 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -298,10 +298,11 @@ impl Execute for Archive {
video_paths.push((download_video(&ctx, primary, false).await?, primary));
for additional in additionally {
+ let identical_video = additionally
+ .iter()
+ .all(|a| a.stream.bandwidth == primary.stream.bandwidth);
let only_audio = match self.merge {
- MergeBehavior::Auto => additionally
- .iter()
- .all(|a| a.stream.bandwidth == primary.stream.bandwidth),
+ MergeBehavior::Auto => identical_video,
MergeBehavior::Audio => true,
MergeBehavior::Video => false,
};
@@ -312,8 +313,8 @@ impl Execute for Archive {
video_paths.push((path, additional))
}
- // Remove subtitles of deleted video
- if only_audio {
+ // Remove subtitles of forcibly deleted video
+ if matches!(self.merge, MergeBehavior::Audio) && !identical_video {
subtitles.retain(|s| s.episode_id != additional.episode_id);
}
}
From e115dcd87f9a31925b771b365065604f95d23772 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Wed, 25 Jan 2023 00:48:35 +0100
Subject: [PATCH 082/395] Rework ffmpeg preset, add 3 quality levels and custom
flags (#108)
---
Cargo.lock | 7 +
crunchy-cli-core/Cargo.toml | 1 +
crunchy-cli-core/src/cli/archive.rs | 35 ++-
crunchy-cli-core/src/cli/download.rs | 32 ++-
crunchy-cli-core/src/cli/utils.rs | 397 +++++++++++++++++++++------
5 files changed, 356 insertions(+), 116 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 42fe778..ae46f99 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -315,6 +315,7 @@ dependencies = [
"sanitize-filename",
"serde",
"serde_json",
+ "shlex",
"signal-hook",
"sys-locale",
"tempfile",
@@ -1476,6 +1477,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "shlex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
[[package]]
name = "signal-hook"
version = "0.3.14"
diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml
index 8eea6a8..e56cf71 100644
--- a/crunchy-cli-core/Cargo.toml
+++ b/crunchy-cli-core/Cargo.toml
@@ -21,6 +21,7 @@ regex = "1.7"
sanitize-filename = "0.4"
serde = "1.0"
serde_json = "1.0"
+shlex = "1.1"
signal-hook = "0.3"
tempfile = "3.3"
terminal_size = "0.2"
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index e0fc9b0..69f999a 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -15,7 +15,7 @@ use crate::Execute;
use anyhow::{bail, Result};
use crunchyroll_rs::media::Resolution;
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
-use log::{debug, error, info, warn};
+use log::{debug, error, info};
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::{Command, Stdio};
@@ -97,14 +97,14 @@ pub struct Archive {
merge: MergeBehavior,
#[arg(help = format!("Presets for video converting. Can be used multiple times. \
- Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ Available presets: \n {}", FFmpegPreset::available_matches_human_readable().join("\n ")))]
#[arg(long_help = format!("Presets for video converting. Can be used multiple times. \
Generally used to minify the file size with keeping (nearly) the same quality. \
It is recommended to only use this if you archive videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
- Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ Available presets: \n {}", FFmpegPreset::available_matches_human_readable().join("\n ")))]
#[arg(long)]
#[arg(value_parser = FFmpegPreset::parse)]
- ffmpeg_preset: Vec,
+ ffmpeg_preset: Option,
#[arg(
help = "Set which subtitle language should be set as default / auto shown when starting a video"
@@ -138,12 +138,6 @@ impl Execute for Archive {
{
bail!("File extension is not '.mkv'. Currently only matroska / '.mkv' files are supported")
}
- let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
- if self.ffmpeg_preset.len() == 1
- && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia
- {
- warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
- }
self.locale = all_locale_in_locales(self.locale.clone());
self.subtitle = all_locale_in_locales(self.subtitle.clone());
@@ -360,7 +354,11 @@ async fn formats_from_series(
"Season {} of series {} is not available with {} audio",
season.first().unwrap().metadata.season_number,
series.title,
- not_present_audio.into_iter().map(|l| l.to_string()).collect::>().join(", ")
+ not_present_audio
+ .into_iter()
+ .map(|l| l.to_string())
+ .collect::>()
+ .join(", ")
)
}
@@ -545,8 +543,19 @@ fn generate_mkv(
}
}
- let (input_presets, output_presets) =
- FFmpegPreset::ffmpeg_presets(archive.ffmpeg_preset.clone())?;
+ let (input_presets, output_presets) = if let Some(preset) = archive.ffmpeg_preset.clone() {
+ preset.to_input_output_args()
+ } else {
+ (
+ vec![],
+ vec![
+ "-c:v".to_string(),
+ "copy".to_string(),
+ "-c:a".to_string(),
+ "copy".to_string(),
+ ],
+ )
+ };
let mut command_args = vec!["-y".to_string()];
command_args.extend(input_presets);
diff --git a/crunchy-cli-core/src/cli/download.rs b/crunchy-cli-core/src/cli/download.rs
index c8e244c..b4c037c 100644
--- a/crunchy-cli-core/src/cli/download.rs
+++ b/crunchy-cli-core/src/cli/download.rs
@@ -1,7 +1,7 @@
use crate::cli::log::tab_info;
use crate::cli::utils::{
- download_segments, find_multiple_seasons_with_same_number,
- find_resolution, interactive_season_choosing, FFmpegPreset,
+ download_segments, find_multiple_seasons_with_same_number, find_resolution,
+ interactive_season_choosing, FFmpegPreset,
};
use crate::utils::context::Context;
use crate::utils::format::Format;
@@ -66,14 +66,14 @@ pub struct Download {
resolution: Resolution,
#[arg(help = format!("Presets for video converting. Can be used multiple times. \
- Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ Available presets: \n {}", FFmpegPreset::available_matches_human_readable().join("\n ")))]
#[arg(long_help = format!("Presets for video converting. Can be used multiple times. \
Generally used to minify the file size with keeping (nearly) the same quality. \
It is recommended to only use this if you download videos with high resolutions since low resolution videos tend to result in a larger file with any of the provided presets. \
- Available presets: \n {}", FFmpegPreset::all().into_iter().map(|p| format!("{}: {}", p.to_string(), p.description())).collect::>().join("\n ")))]
+ Available presets: \n {}", FFmpegPreset::available_matches_human_readable().join("\n ")))]
#[arg(long)]
#[arg(value_parser = FFmpegPreset::parse)]
- ffmpeg_preset: Vec,
+ ffmpeg_preset: Option,
#[arg(help = "Skip files which are already existing")]
#[arg(long, default_value_t = false)]
@@ -109,13 +109,6 @@ impl Execute for Download {
}
}
- let _ = FFmpegPreset::ffmpeg_presets(self.ffmpeg_preset.clone())?;
- if self.ffmpeg_preset.len() == 1
- && self.ffmpeg_preset.get(0).unwrap() == &FFmpegPreset::Nvidia
- {
- warn!("Skipping 'nvidia' hardware acceleration preset since no other codec preset was specified")
- }
-
Ok(())
}
@@ -277,8 +270,19 @@ async fn download_ffmpeg(
subtitle: Option,
mut target: PathBuf,
) -> Result<()> {
- let (input_presets, mut output_presets) =
- FFmpegPreset::ffmpeg_presets(download.ffmpeg_preset.clone())?;
+ let (input_presets, mut output_presets) = if let Some(preset) = download.ffmpeg_preset.clone() {
+ preset.to_input_output_args()
+ } else {
+ (
+ vec![],
+ vec![
+ "-c:v".to_string(),
+ "copy".to_string(),
+ "-c:a".to_string(),
+ "copy".to_string(),
+ ],
+ )
+ };
// create parent directory if it does not exist
if let Some(parent) = target.parent() {
diff --git a/crunchy-cli-core/src/cli/utils.rs b/crunchy-cli-core/src/cli/utils.rs
index 7352d95..44cd63c 100644
--- a/crunchy-cli-core/src/cli/utils.rs
+++ b/crunchy-cli-core/src/cli/utils.rs
@@ -8,7 +8,9 @@ use log::{debug, LevelFilter};
use regex::Regex;
use std::borrow::{Borrow, BorrowMut};
use std::collections::BTreeMap;
+use std::env;
use std::io::{BufRead, Write};
+use std::str::FromStr;
use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
use tokio::task::JoinSet;
@@ -210,118 +212,335 @@ pub async fn download_segments(
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FFmpegPreset {
- Nvidia,
-
- Av1,
- H265,
- H264,
+ Predefined(FFmpegCodec, Option, FFmpegQuality),
+ Custom(Option, Option),
}
-impl ToString for FFmpegPreset {
- fn to_string(&self) -> String {
- match self {
- &FFmpegPreset::Nvidia => "nvidia",
- &FFmpegPreset::Av1 => "av1",
- &FFmpegPreset::H265 => "h265",
- &FFmpegPreset::H264 => "h264",
+lazy_static! {
+ static ref PREDEFINED_PRESET: Regex = Regex::new(r"^\w+(-\w+)*?$").unwrap();
+}
+
+macro_rules! FFmpegEnum {
+ (enum $name:ident { $($field:ident),* }) => {
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+ pub enum $name {
+ $(
+ $field
+ ),*,
}
- .to_string()
+
+ impl $name {
+ fn all() -> Vec<$name> {
+ vec![
+ $(
+ $name::$field
+ ),*,
+ ]
+ }
+ }
+
+ impl ToString for $name {
+ fn to_string(&self) -> String {
+ match self {
+ $(
+ &$name::$field => stringify!($field).to_string().to_lowercase()
+ ),*
+ }
+ }
+ }
+
+ impl FromStr for $name {
+ type Err = anyhow::Error;
+
+ fn from_str(s: &str) -> std::result::Result {
+ match s {
+ $(
+ stringify!($field) => Ok($name::$field)
+ ),*,
+ _ => bail!("{} is not a valid {}", s, stringify!($name).to_lowercase())
+ }
+ }
+ }
+ }
+}
+
+FFmpegEnum! {
+ enum FFmpegCodec {
+ H264,
+ H265,
+ Av1
+ }
+}
+
+FFmpegEnum! {
+ enum FFmpegHwAccel {
+ Nvidia
+ }
+}
+
+FFmpegEnum! {
+ enum FFmpegQuality {
+ Lossless,
+ Normal,
+ Low
}
}
impl FFmpegPreset {
- pub(crate) fn all() -> Vec {
- vec![
- FFmpegPreset::Nvidia,
- FFmpegPreset::Av1,
- FFmpegPreset::H265,
- FFmpegPreset::H264,
- ]
+ pub(crate) fn available_matches(
+ ) -> Vec<(FFmpegCodec, Option, Option)> {
+ let codecs = vec![
+ (
+ FFmpegCodec::H264,
+ FFmpegHwAccel::all(),
+ FFmpegQuality::all(),
+ ),
+ (
+ FFmpegCodec::H265,
+ FFmpegHwAccel::all(),
+ FFmpegQuality::all(),
+ ),
+ (FFmpegCodec::Av1, vec![], FFmpegQuality::all()),
+ ];
+
+ let mut return_values = vec![];
+
+ for (codec, hwaccels, qualities) in codecs {
+ return_values.push((codec.clone(), None, None));
+ for hwaccel in hwaccels.clone() {
+ return_values.push((codec.clone(), Some(hwaccel), None));
+ }
+ for quality in qualities.clone() {
+ return_values.push((codec.clone(), None, Some(quality)))
+ }
+ for hwaccel in hwaccels {
+ for quality in qualities.clone() {
+ return_values.push((codec.clone(), Some(hwaccel.clone()), Some(quality)))
+ }
+ }
+ }
+
+ return_values
}
- pub(crate) fn description(self) -> String {
- match self {
- FFmpegPreset::Nvidia => "If you're have a nvidia card, use hardware / gpu accelerated video processing if available",
- FFmpegPreset::Av1 => "Encode the video(s) with the av1 codec. Hardware acceleration is currently not possible with this",
- FFmpegPreset::H265 => "Encode the video(s) with the h265 codec",
- FFmpegPreset::H264 => "Encode the video(s) with the h264 codec"
- }.to_string()
+ pub(crate) fn available_matches_human_readable() -> Vec {
+ let mut return_values = vec![];
+
+ for (codec, hwaccel, quality) in FFmpegPreset::available_matches() {
+ let mut description_details = vec![];
+ if let Some(h) = &hwaccel {
+ description_details.push(format!("{} hardware acceleration", h.to_string()))
+ }
+ if let Some(q) = &quality {
+ description_details.push(format!("{} video quality/compression", q.to_string()))
+ }
+
+ let description = if description_details.len() == 0 {
+ format!(
+ "{} encoded with default video quality/compression",
+ codec.to_string()
+ )
+ } else if description_details.len() == 1 {
+ format!(
+ "{} encoded with {}",
+ codec.to_string(),
+ description_details[0]
+ )
+ } else {
+ let first = description_details.remove(0);
+ let last = description_details.remove(description_details.len() - 1);
+ let mid = if !description_details.is_empty() {
+ format!(", {} ", description_details.join(", "))
+ } else {
+ "".to_string()
+ };
+
+ format!(
+ "{} encoded with {}{} and {}",
+ codec.to_string(),
+ first,
+ mid,
+ last
+ )
+ };
+
+ return_values.push(format!(
+ "{} ({})",
+ vec![
+ Some(codec.to_string()),
+ hwaccel.map(|h| h.to_string()),
+ quality.map(|q| q.to_string())
+ ]
+ .into_iter()
+ .flatten()
+ .collect::>()
+ .join("-"),
+ description
+ ))
+ }
+ return_values
}
pub(crate) fn parse(s: &str) -> Result {
- Ok(match s.to_lowercase().as_str() {
- "nvidia" => FFmpegPreset::Nvidia,
- "av1" => FFmpegPreset::Av1,
- "h265" | "h.265" | "hevc" => FFmpegPreset::H265,
- "h264" | "h.264" => FFmpegPreset::H264,
- _ => return Err(format!("'{}' is not a valid ffmpeg preset", s)),
- })
+ let env_ffmpeg_input_args = env::var("FFMPEG_INPUT_ARGS").ok();
+ let env_ffmpeg_output_args = env::var("FFMPEG_OUTPUT_ARGS").ok();
+
+ if env_ffmpeg_input_args.is_some() || env_ffmpeg_output_args.is_some() {
+ if let Some(input) = &env_ffmpeg_input_args {
+ if shlex::split(input).is_none() {
+ return Err(format!("Failed to parse custom ffmpeg input '{}' (`FFMPEG_INPUT_ARGS` env variable)", input));
+ }
+ }
+ if let Some(output) = &env_ffmpeg_output_args {
+ if shlex::split(output).is_none() {
+ return Err(format!("Failed to parse custom ffmpeg output '{}' (`FFMPEG_INPUT_ARGS` env variable)", output));
+ }
+ }
+
+ return Ok(FFmpegPreset::Custom(
+ env_ffmpeg_input_args,
+ env_ffmpeg_output_args,
+ ));
+ } else if !PREDEFINED_PRESET.is_match(s) {
+ return Ok(FFmpegPreset::Custom(None, Some(s.to_string())));
+ }
+
+ let mut codec: Option = None;
+ let mut hwaccel: Option = None;
+ let mut quality: Option = None;
+ for token in s.split('-') {
+ if let Some(c) = FFmpegCodec::all()
+ .into_iter()
+ .find(|p| p.to_string() == token.to_lowercase())
+ {
+ if let Some(cc) = codec {
+ return Err(format!(
+ "cannot use multiple codecs (found {} and {})",
+ cc.to_string(),
+ c.to_string()
+ ));
+ }
+ codec = Some(c)
+ } else if let Some(h) = FFmpegHwAccel::all()
+ .into_iter()
+ .find(|p| p.to_string() == token.to_lowercase())
+ {
+ if let Some(hh) = hwaccel {
+ return Err(format!(
+ "cannot use multiple hardware accelerations (found {} and {})",
+ hh.to_string(),
+ h.to_string()
+ ));
+ }
+ hwaccel = Some(h)
+ } else if let Some(q) = FFmpegQuality::all()
+ .into_iter()
+ .find(|p| p.to_string() == token.to_lowercase())
+ {
+ if let Some(qq) = quality {
+ return Err(format!(
+ "cannot use multiple ffmpeg preset qualities (found {} and {})",
+ qq.to_string(),
+ q.to_string()
+ ));
+ }
+ quality = Some(q)
+ } else {
+ return Err(format!(
+ "'{}' is not a valid ffmpeg preset (unknown token '{}'",
+ s, token
+ ));
+ }
+ }
+
+ if let Some(c) = codec {
+ if !FFmpegPreset::available_matches().contains(&(
+ c.clone(),
+ hwaccel.clone(),
+ quality.clone(),
+ )) {
+ return Err(format!("ffmpeg preset is not supported"));
+ }
+ Ok(FFmpegPreset::Predefined(
+ c,
+ hwaccel,
+ quality.unwrap_or(FFmpegQuality::Normal),
+ ))
+ } else {
+ Err(format!("cannot use ffmpeg preset with without a codec"))
+ }
}
- pub(crate) fn ffmpeg_presets(
- mut presets: Vec,
- ) -> Result<(Vec, Vec)> {
- fn preset_check_remove(presets: &mut Vec, preset: FFmpegPreset) -> bool {
- if let Some(i) = presets.iter().position(|p| p == &preset) {
- presets.remove(i);
- true
- } else {
- false
- }
- }
+ pub(crate) fn to_input_output_args(self) -> (Vec, Vec) {
+ match self {
+ FFmpegPreset::Custom(input, output) => (
+ input.map_or(vec![], |i| shlex::split(&i).unwrap_or_default()),
+ output.map_or(vec![], |o| shlex::split(&o).unwrap_or_default()),
+ ),
+ FFmpegPreset::Predefined(codec, hwaccel_opt, quality) => {
+ let mut input = vec![];
+ let mut output = vec![];
- let nvidia = preset_check_remove(&mut presets, FFmpegPreset::Nvidia);
- if presets.len() > 1 {
- bail!(
- "Can only use one video codec, {} found: {}",
- presets.len(),
- presets
- .iter()
- .map(|p| p.to_string())
- .collect::>()
- .join(", ")
- )
- }
+ match codec {
+ FFmpegCodec::H264 => {
+ if let Some(hwaccel) = hwaccel_opt {
+ match hwaccel {
+ FFmpegHwAccel::Nvidia => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "h264_nvenc", "-c:a", "copy"])
+ }
+ }
+ } else {
+ output.extend(["-c:v", "libx264", "-c:a", "copy"])
+ }
- let (mut input, mut output) = (vec![], vec![]);
- for preset in presets {
- if nvidia {
- match preset {
- FFmpegPreset::Av1 => bail!("'nvidia' hardware acceleration preset is not available in combination with the 'av1' codec preset"),
- FFmpegPreset::H265 => {
- input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "hevc_nvenc", "-c:a", "copy"]);
+ match quality {
+ FFmpegQuality::Lossless => output.extend(["-crf", "18"]),
+ FFmpegQuality::Normal => (),
+ FFmpegQuality::Low => output.extend(["-crf", "35"]),
+ }
}
- FFmpegPreset::H264 => {
- input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
- output.extend(["-c:v", "h264_nvenc", "-c:a", "copy"]);
+ FFmpegCodec::H265 => {
+ if let Some(hwaccel) = hwaccel_opt {
+ match hwaccel {
+ FFmpegHwAccel::Nvidia => {
+ input.extend(["-hwaccel", "cuvid", "-c:v", "h264_cuvid"]);
+ output.extend(["-c:v", "hevc_nvenc", "-c:a", "copy"])
+ }
+ }
+ } else {
+ output.extend(["-c:v", "libx265", "-c:a", "copy"])
+ }
+
+ match quality {
+ FFmpegQuality::Lossless => output.extend(["-crf", "20"]),
+ FFmpegQuality::Normal => (),
+ FFmpegQuality::Low => output.extend(["-crf", "35"]),
+ }
}
- _ => ()
- }
- } else {
- match preset {
- FFmpegPreset::Av1 => {
+ FFmpegCodec::Av1 => {
output.extend(["-c:v", "libsvtav1", "-c:a", "copy"]);
+
+ match quality {
+ FFmpegQuality::Lossless => output.extend(["-crf", "22"]),
+ FFmpegQuality::Normal => (),
+ FFmpegQuality::Low => output.extend(["-crf", "35"]),
+ }
}
- FFmpegPreset::H265 => {
- output.extend(["-c:v", "libx265", "-c:a", "copy"]);
- }
- FFmpegPreset::H264 => {
- output.extend(["-c:v", "libx264", "-c:a", "copy"]);
- }
- _ => (),
}
+
+ (
+ input
+ .into_iter()
+ .map(|s| s.to_string())
+ .collect::>(),
+ output
+ .into_iter()
+ .map(|s| s.to_string())
+ .collect::>(),
+ )
}
}
-
- if output.is_empty() {
- output.extend(["-c:v", "copy", "-c:a", "copy"])
- }
-
- Ok((
- input.into_iter().map(|i| i.to_string()).collect(),
- output.into_iter().map(|o| o.to_string()).collect(),
- ))
}
}
From e83de60efa34bb637dbf01b8049fda91fc5e7ea8 Mon Sep 17 00:00:00 2001
From: Alexandru Dracea
Date: Tue, 31 Jan 2023 13:37:29 +0200
Subject: [PATCH 083/395] Update README.md
Adds a bit of guidance for how to properly `install` .
---
README.md | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/README.md b/README.md
index bf57145..eb40d1c 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,25 @@ $ cargo build --release
```
After the binary has built successfully it is available in `target/release`.
+### Final steps
+
+In order to make the binary globally accessible you will need to add it to `PATH` so it's recommended you move it to a general folder.
+
+
+Examples:
+
+- Linux/MacOS
+ - ```shell
+ mkdir ~/crunchy-cli
+ mv /path/to/repo/target/release/crunchy-cli ~/crunchy-cli/crunchy # OR
+ mv /path/to/downloaded/file/crunchy-cli(rest of filename here) ~/crunchy-cli/crunchy
+ export PATH=$PATH:~/crunchy-cli
+ ```
+
+ For persistent usage you should add the above export to your `.shellrc`(.bashrc, .zshrc ,etc. file)
+- Windows
+ - Download the `.exe` file or build it yourself. Rename it to the way you will be calling it (ex: `crunchy.exe`) and move it into a folder where it's easily accessible. Afterwards follow a [guide](https://www.wikihow.com/Change-the-PATH-Environment-Variable-on-Windows) for adding that folder to the `PATH` variable. A restart of `CMD` or `powershell` might be required for the changes to take effect.
+
## 🖥️ Usage
> All shown command are just examples
From 96b259ce9a0fbc7678195dbca6742ade5986f7e0 Mon Sep 17 00:00:00 2001
From: ByteDream
Date: Sun, 5 Feb 2023 15:00:50 +0100
Subject: [PATCH 084/395] Add url filtering section to README (#133)
---
README.md | 59 +++++++++++++++++++++++++++----------------------------
1 file changed, 29 insertions(+), 30 deletions(-)
diff --git a/README.md b/README.md
index eb40d1c..5e859c4 100644
--- a/README.md
+++ b/README.md
@@ -61,25 +61,6 @@ $ cargo build --release
```
After the binary has built successfully it is available in `target/release`.
-### Final steps
-
-In order to make the binary globally accessible you will need to add it to `PATH` so it's recommended you move it to a general folder.
-
-
-Examples:
-
-- Linux/MacOS
- - ```shell
- mkdir ~/crunchy-cli
- mv /path/to/repo/target/release/crunchy-cli ~/crunchy-cli/crunchy # OR
- mv /path/to/downloaded/file/crunchy-cli(rest of filename here) ~/crunchy-cli/crunchy
- export PATH=$PATH:~/crunchy-cli
- ```
-
- For persistent usage you should add the above export to your `.shellrc`(.bashrc, .zshrc ,etc. file)
-- Windows
- - Download the `.exe` file or build it yourself. Rename it to the way you will be calling it (ex: `crunchy.exe`) and move it into a folder where it's easily accessible. Afterwards follow a [guide](https://www.wikihow.com/Change-the-PATH-Environment-Variable-on-Windows) for adding that folder to the `PATH` variable. A restart of `CMD` or `powershell` might be required for the changes to take effect.
-
## 🖥️ Usage
> All shown command are just examples
@@ -89,7 +70,7 @@ It doesn't matter if this account is premium or not, both works (but as free use
You can pass your account via credentials (username & password) or refresh token.
- Refresh Token
- - To get the token you have to log in at [crunchyroll.com](https://www.crunchyroll.com/) and extract the `etp_rt` cookie.
+ - To get the token you have to log in at [crunchyroll.com](https://www.crunchyroll.com/) and extract the `etp_rt` cookie.
The easiest way to get it is via a browser extension with lets you view your cookies, like [Cookie-Editor](https://cookie-editor.cgagnier.ca/) ([Firefox Store](https://addons.mozilla.org/en-US/firefox/addon/cookie-editor/); [Chrome Store](https://chrome.google.com/webstore/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm)).
If installed, search the `etp_rt` entry and extract the value.
- ```shell
@@ -126,18 +107,11 @@ This does not work if you've using this with `--anonymous`.
```shell
$ crunchy download https://www.crunchyroll.com/watch/GRDQPM1ZY/alone-and-lonesome
```
-- Episode range
-
- If you want only specific episodes / seasons of an anime you can easily provide the series url along with a _filter_.
- The filter has to be attached to the url. See the [wiki](https://github.com/crunchy-labs/crunchy-cli/wiki/Cli#filter) for more information
- ```shell
- $ crunchy download https://www.crunchyroll.com/series/GY8VEQ95Y/darling-in-the-franxx[E1]
- ```
- Series
```shell
$ crunchy download https://www.crunchyroll.com/series/GY8VEQ95Y/darling-in-the-franxx
```
-
+
**Options**
- Audio language
@@ -183,7 +157,7 @@ This does not work if you've using this with `--anonymous`.
```shell
$ crunchy archive https://www.crunchyroll.com/series/GY8VEQ95Y/darling-in-the-franxx
```
-
+
**Options**
- Audio languages
@@ -242,7 +216,7 @@ This does not work if you've using this with `--anonymous`.
- No subtitle optimizations
- Subtitles, as Crunchyroll delivers them, look weird in some video players (#66).
+ Subtitles, as Crunchyroll delivers them, look weird in some video players (#66).
This can be fixed by adding a specific entry to the subtitles.
But since this entry is only a de-factor standard and not represented in the official specification of the subtitle format ([`.ass`](https://en.wikipedia.org/wiki/SubStation_Alpha)) it could cause issues with some video players (but no issue got reported so far, so it's relatively safe to use).
`--no_subtitle_optimizations` can disable these optimizations.
@@ -250,6 +224,31 @@ This does not work if you've using this with `--anonymous`.
$ crunchy archive --no_subtitle_optimizations https://www.crunchyroll.com/series/GY8VEQ95Y/darling-in-the-franxx
```
+### Url Filtering
+
+If you want to download only specific episode of a series, you could either pass every single episode url to the downloader (which is fine for 1 - 3 episodes) or use _filtering_.
+
+It works pretty simple, just put a specific pattern surrounded by square brackets at the end of the url from the anime you want to download.
+A season and / or episode as well as a range from where to where episodes should be downloaded can be specified.
+Use the list below to get a better overview what is possible
+- `...[E5]` - Download the fifth episode.
+- `...[S1]` - Download the full first season.
+- `...[-S2]` - Download all seasons up to and including season 2.
+- `...[S3E4-]` - Download all episodes from and including season 3, episode 4.
+- `...[S1E4-S3]` - Download all episodes from and including season 1, episode 4, until and including season 3.
+- `...[S3,S5]` - Download episode 3 and 5.
+- `...[S1-S3,S4E2-S4E6]` - Download season 1 to 3 and episode 2 to episode 6 of season 4.
+
+In practice, it would look like this: `https://www.crunchyroll.com/series/GY8VEQ95Y/darling-in-the-franxx[E1-E5]`.
+
+The `S`, followed by the number indicates the _season_ number, `E`, followed by the number indicates an _episode_ number.
+It doesn't matter if `S`, `E` or both are missing.
+Note that `S` must always stay before `E` when used.
+
+There is also a regex available at [regex101.com](https://regex101.com/r/SDZyZM) where you can test if your pattern is correct.
+Just put in your pattern without square brackets into the big empty field and if the full pattern is highlighted this means it is valid.
+If none or only some parts are highlighted, it's not valid not.
+
# ☝️ Disclaimer
This tool is **ONLY** meant to be used for private purposes. To use this tool you need crunchyroll premium anyway, so there is no reason why rip and share the episodes.
From ba57d3c25d261249d921b5f146fd7c706e38fc1e Mon Sep 17 00:00:00 2001
From: bocchi <121779542+hitorilabs@users.noreply.github.com>
Date: Mon, 6 Feb 2023 03:11:52 -0500
Subject: [PATCH 085/395] bugfix: btreemap skips duplicate ep nums
---
crunchy-cli-core/src/cli/archive.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index ff13128..b189406 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -383,7 +383,7 @@ async fn formats_from_series(
}
#[allow(clippy::type_complexity)]
- let mut result: BTreeMap, Vec)>> = BTreeMap::new();
+ let mut result: BTreeMap, Vec)>> = BTreeMap::new();
let mut primary_season = true;
for season in seasons {
let episodes = season.episodes().await?;
@@ -414,7 +414,7 @@ async fn formats_from_series(
let (ref mut formats, subtitles) = result
.entry(season.metadata.season_number)
.or_insert_with(BTreeMap::new)
- .entry(episode.metadata.episode_number)
+ .entry(episode.metadata.episode.clone())
.or_insert_with(|| (vec![], vec![]));
subtitles.extend(archive.subtitle.iter().filter_map(|l| {
let stream_subtitle = streams.subtitles.get(l).cloned()?;
From 264d943a2c0eeb8f8b7e7116989dc018ef539b55 Mon Sep 17 00:00:00 2001
From: bocchi <121779542+hitorilabs@users.noreply.github.com>
Date: Mon, 6 Feb 2023 03:22:04 -0500
Subject: [PATCH 086/395] use episode id instead
---
crunchy-cli-core/src/cli/archive.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index b189406..82e70f7 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -414,7 +414,7 @@ async fn formats_from_series(
let (ref mut formats, subtitles) = result
.entry(season.metadata.season_number)
.or_insert_with(BTreeMap::new)
- .entry(episode.metadata.episode.clone())
+ .entry(episode.id.clone())
.or_insert_with(|| (vec![], vec![]));
subtitles.extend(archive.subtitle.iter().filter_map(|l| {
let stream_subtitle = streams.subtitles.get(l).cloned()?;
From cba921f1a8352704874fe30fb3cc067885150037 Mon Sep 17 00:00:00 2001
From: bocchi <121779542+hitorilabs@users.noreply.github.com>
Date: Mon, 6 Feb 2023 04:04:26 -0500
Subject: [PATCH 087/395] use sequence_number instead of episode_number
---
crunchy-cli-core/src/cli/archive.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 82e70f7..9b6ac4b 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -383,7 +383,7 @@ async fn formats_from_series(
}
#[allow(clippy::type_complexity)]
- let mut result: BTreeMap, Vec)>> = BTreeMap::new();
+ let mut result: BTreeMap, Vec)>> = BTreeMap::new();
let mut primary_season = true;
for season in seasons {
let episodes = season.episodes().await?;
@@ -414,7 +414,7 @@ async fn formats_from_series(
let (ref mut formats, subtitles) = result
.entry(season.metadata.season_number)
.or_insert_with(BTreeMap::new)
- .entry(episode.id.clone())
+ .entry((episode.metadata.sequence_number * 100.0) as u32)
.or_insert_with(|| (vec![], vec![]));
subtitles.extend(archive.subtitle.iter().filter_map(|l| {
let stream_subtitle = streams.subtitles.get(l).cloned()?;
From 03dd1c5264c0e304ec7ab6843b8faf9944032f61 Mon Sep 17 00:00:00 2001
From: bocchi <121779542+hitorilabs@users.noreply.github.com>
Date: Tue, 7 Feb 2023 11:04:41 -0500
Subject: [PATCH 088/395] get rid of btreemap in archive
---
crunchy-cli-core/src/cli/archive.rs | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/crunchy-cli-core/src/cli/archive.rs b/crunchy-cli-core/src/cli/archive.rs
index 9b6ac4b..e500f21 100644
--- a/crunchy-cli-core/src/cli/archive.rs
+++ b/crunchy-cli-core/src/cli/archive.rs
@@ -16,7 +16,6 @@ use anyhow::{bail, Result};
use crunchyroll_rs::media::Resolution;
use crunchyroll_rs::{Locale, Media, MediaCollection, Series};
use log::{debug, error, info};
-use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use tempfile::TempPath;
@@ -383,7 +382,7 @@ async fn formats_from_series(
}
#[allow(clippy::type_complexity)]
- let mut result: BTreeMap