From 2f5f493f9b6102a632c07730d0c64cdb38de61f7 Mon Sep 17 00:00:00 2001 From: chaos Date: Thu, 19 Oct 2023 17:22:01 +0100 Subject: [PATCH] change default formatting to use tabs instead of spaces --- .rustfmt.toml | 2 + modules/taglib/build.rs | 46 +-- modules/taglib/src/errors.rs | 12 +- modules/taglib/src/impls/file.rs | 114 +++---- modules/taglib/src/impls/oggtag.rs | 38 +-- modules/taglib/src/impls/tag.rs | 34 +-- modules/taglib/src/lib.rs | 14 +- modules/taglib/src/traits.rs | 10 +- modules/taglib/src/utils.rs | 20 +- src/args.rs | 110 +++---- src/commands/copy.rs | 368 +++++++++++------------ src/commands/genhtml.rs | 238 +++++++-------- src/commands/get_tags.rs | 90 +++--- src/commands/process.rs | 278 ++++++++--------- src/commands/set_tags.rs | 34 +-- src/commands/transcode.rs | 114 +++---- src/main.rs | 44 +-- src/types.rs | 148 ++++----- src/utils/ascii_reduce/mod.rs | 68 ++--- src/utils/ffprobe/errors.rs | 42 +-- src/utils/ffprobe/ffprobe_output.rs | 38 +-- src/utils/ffprobe/mod.rs | 62 ++-- src/utils/ffprobe/types.rs | 28 +- src/utils/format_detection.rs | 182 +++++------ src/utils/formats/handlers/ffprobe.rs | 260 ++++++++-------- src/utils/formats/handlers/flac.rs | 167 +++++----- src/utils/formats/handlers/id3.rs | 198 ++++++------ src/utils/formats/handlers/mod.rs | 216 +++++++------ src/utils/formats/handlers/taglib.rs | 252 ++++++++-------- src/utils/formats/mod.rs | 87 +++--- src/utils/mod.rs | 4 +- src/utils/music_scanner.rs | 70 ++--- src/utils/replaygain/mod.rs | 162 +++++----- src/utils/transcoder/mod.rs | 2 +- src/utils/transcoder/presets.rs | 332 ++++++++++---------- src/utils/transcoder/progress_monitor.rs | 188 ++++++------ src/utils/transcoder/transcoder.rs | 118 ++++---- src/utils/transcoder/types.rs | 54 ++-- 38 files changed, 2118 insertions(+), 2126 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..b204247 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,2 @@ +hard_tabs = true +use_field_init_shorthand = true \ No newline at end of file diff --git a/modules/taglib/build.rs b/modules/taglib/build.rs index 076d254..3637b30 100644 --- a/modules/taglib/build.rs +++ b/modules/taglib/build.rs @@ -2,35 +2,35 @@ use std::env; use std::path::PathBuf; fn main() { - println!("cargo:rerun-if-changed=src/wrapper.h"); - println!("cargo:rerun-if-changed=src/wrapper.cxx"); + println!("cargo:rerun-if-changed=src/wrapper.h"); + println!("cargo:rerun-if-changed=src/wrapper.cxx"); - let taglib = pkg_config::Config::new().probe("taglib").unwrap(); + let taglib = pkg_config::Config::new().probe("taglib").unwrap(); - let mut cc_builder = cc::Build::new(); + let mut cc_builder = cc::Build::new(); - cc_builder - .file("src/wrapper.cxx") - .flag("-std=c++2b") - .flag("-Og") - .include("src") - .cpp(true); + cc_builder + .file("src/wrapper.cxx") + .flag("-std=c++2b") + .flag("-Og") + .include("src") + .cpp(true); - for include in taglib.include_paths { - cc_builder.include(include); - } + for include in taglib.include_paths { + cc_builder.include(include); + } - cc_builder.compile("wrapper"); + cc_builder.compile("wrapper"); - let bindings = bindgen::Builder::default() - .header("src/wrapper.h") - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - .generate() - .expect("Unable to generate bindings"); + let bindings = bindgen::Builder::default() + .header("src/wrapper.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .generate() + .expect("Unable to generate bindings"); - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); } diff --git a/modules/taglib/src/errors.rs b/modules/taglib/src/errors.rs index 2146814..138c9ae 100644 --- a/modules/taglib/src/errors.rs +++ b/modules/taglib/src/errors.rs @@ -2,10 +2,10 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum TagLibError { - #[error("could not save file")] - SaveError, - #[error("invalid file")] - InvalidFile, - #[error("metadata unavailable")] - MetadataUnavailable, + #[error("could not save file")] + SaveError, + #[error("invalid file")] + InvalidFile, + #[error("metadata unavailable")] + MetadataUnavailable, } diff --git a/modules/taglib/src/impls/file.rs b/modules/taglib/src/impls/file.rs index 330b489..81c542b 100644 --- a/modules/taglib/src/impls/file.rs +++ b/modules/taglib/src/impls/file.rs @@ -5,83 +5,83 @@ use crate::{bindings, errors::TagLibError, traits::File, TagLibFileType}; use super::{oggtag::TagLibOggTag, tag::TagLibTag}; pub struct TagLibFile { - ctx: *mut bindings::TagLib_File, - taglib_type: Option, + ctx: *mut bindings::TagLib_File, + taglib_type: Option, } pub fn new_taglib_file( - filepath: String, - taglib_type: Option, + filepath: String, + taglib_type: Option, ) -> Result { - let filename_c = CString::new(filepath).unwrap(); - let filename_c_ptr = filename_c.as_ptr(); + let filename_c = CString::new(filepath).unwrap(); + let filename_c_ptr = filename_c.as_ptr(); - let file = unsafe { - if let Some(taglib_type) = taglib_type { - bindings::wrap_taglib_file_new_with_type(filename_c_ptr, (taglib_type as u8).into()) - } else { - bindings::wrap_taglib_file_new(filename_c_ptr) - } - }; + let file = unsafe { + if let Some(taglib_type) = taglib_type { + bindings::wrap_taglib_file_new_with_type(filename_c_ptr, (taglib_type as u8).into()) + } else { + bindings::wrap_taglib_file_new(filename_c_ptr) + } + }; - if file.is_null() { - return Err(TagLibError::InvalidFile); - } + if file.is_null() { + return Err(TagLibError::InvalidFile); + } - Ok(TagLibFile { - ctx: file, - taglib_type, - }) + Ok(TagLibFile { + ctx: file, + taglib_type, + }) } impl TagLibFile { - pub fn tag(&self) -> Result { - let tag = unsafe { bindings::wrap_taglib_file_tag(self.ctx) }; - if tag.is_null() { - return Err(TagLibError::MetadataUnavailable); - } + pub fn tag(&self) -> Result { + let tag = unsafe { bindings::wrap_taglib_file_tag(self.ctx) }; + if tag.is_null() { + return Err(TagLibError::MetadataUnavailable); + } - Ok(TagLibTag { ctx: tag }) - } + Ok(TagLibTag { ctx: tag }) + } - pub fn oggtag(&self) -> Result { - if let Some(taglib_type) = &self.taglib_type { - let supported = match taglib_type { - TagLibFileType::OggFLAC - | TagLibFileType::OggOpus - | TagLibFileType::OggSpeex - | TagLibFileType::OggVorbis => true, - }; + pub fn oggtag(&self) -> Result { + if let Some(taglib_type) = &self.taglib_type { + let supported = match taglib_type { + TagLibFileType::OggFLAC + | TagLibFileType::OggOpus + | TagLibFileType::OggSpeex + | TagLibFileType::OggVorbis => true, + }; - if !supported { - panic!("ogg tag not supported") - } - } + if !supported { + panic!("ogg tag not supported") + } + } - let tag = unsafe { bindings::wrap_taglib_file_tag(self.ctx) }; - if tag.is_null() { - return Err(TagLibError::MetadataUnavailable); - } + let tag = unsafe { bindings::wrap_taglib_file_tag(self.ctx) }; + if tag.is_null() { + return Err(TagLibError::MetadataUnavailable); + } - Ok(TagLibOggTag { ctx: tag }) - } + Ok(TagLibOggTag { ctx: tag }) + } } impl File for TagLibFile { - fn save(&mut self) -> Result<(), TagLibError> { - let result = unsafe { bindings::wrap_taglib_file_save(self.ctx) }; + fn save(&mut self) -> Result<(), TagLibError> { + let result = unsafe { bindings::wrap_taglib_file_save(self.ctx) }; - match result { - true => Ok(()), - false => Err(TagLibError::SaveError), - } - } + match result { + true => Ok(()), + false => Err(TagLibError::SaveError), + } + } } impl Drop for TagLibFile { - fn drop(&mut self) { - unsafe { - bindings::wrap_taglib_file_free(self.ctx); - } - } + fn drop(&mut self) { + unsafe { + bindings::wrap_taglib_file_free(self.ctx); + } + } } diff --git a/modules/taglib/src/impls/oggtag.rs b/modules/taglib/src/impls/oggtag.rs index 69fe539..63adc82 100644 --- a/modules/taglib/src/impls/oggtag.rs +++ b/modules/taglib/src/impls/oggtag.rs @@ -3,31 +3,31 @@ use std::ffi::CString; use crate::{bindings, utils::c_str_to_str}; pub struct TagLibOggTag { - pub ctx: *mut bindings::TagLib_Tag, + pub ctx: *mut bindings::TagLib_Tag, } impl TagLibOggTag { - pub fn get_field(&self, key: String) -> Option { - let key = CString::new(key).unwrap(); - let value = unsafe { bindings::wrap_taglib_opustag_get_field(self.ctx, key.as_ptr()) }; + pub fn get_field(&self, key: String) -> Option { + let key = CString::new(key).unwrap(); + let value = unsafe { bindings::wrap_taglib_opustag_get_field(self.ctx, key.as_ptr()) }; - if value.is_null() { - None - } else { - c_str_to_str(value) - } - } + if value.is_null() { + None + } else { + c_str_to_str(value) + } + } - pub fn add_field(&self, key: String, value: String) { - let key = CString::new(key).unwrap(); - let value = CString::new(value).unwrap(); + pub fn add_field(&self, key: String, value: String) { + let key = CString::new(key).unwrap(); + let value = CString::new(value).unwrap(); - unsafe { bindings::wrap_taglib_opustag_add_field(self.ctx, key.as_ptr(), value.as_ptr()) }; - } + unsafe { bindings::wrap_taglib_opustag_add_field(self.ctx, key.as_ptr(), value.as_ptr()) }; + } - pub fn remove_fields(&self, key: String) { - let key = CString::new(key).unwrap(); + pub fn remove_fields(&self, key: String) { + let key = CString::new(key).unwrap(); - unsafe { bindings::wrap_taglib_opustag_remove_fields(self.ctx, key.as_ptr()) }; - } + unsafe { bindings::wrap_taglib_opustag_remove_fields(self.ctx, key.as_ptr()) }; + } } diff --git a/modules/taglib/src/impls/tag.rs b/modules/taglib/src/impls/tag.rs index a588a4b..9aaf44a 100644 --- a/modules/taglib/src/impls/tag.rs +++ b/modules/taglib/src/impls/tag.rs @@ -3,28 +3,28 @@ use std::ffi::CString; use crate::{bindings, traits::Tag, utils::c_str_to_str}; pub struct TagLibTag { - pub ctx: *mut bindings::TagLib_Tag, + pub ctx: *mut bindings::TagLib_Tag, } impl Tag for TagLibTag { - fn title(&self) -> Option { - let title_ref = unsafe { bindings::wrap_taglib_tag_title(self.ctx) }; + fn title(&self) -> Option { + let title_ref = unsafe { bindings::wrap_taglib_tag_title(self.ctx) }; - c_str_to_str(title_ref) - } - fn set_title(&mut self, title: String) { - let title = CString::new(title).unwrap(); + c_str_to_str(title_ref) + } + fn set_title(&mut self, title: String) { + let title = CString::new(title).unwrap(); - unsafe { bindings::wrap_taglib_tag_set_title(self.ctx, title.as_ptr()) }; - } - fn artist(&self) -> Option { - let artist_ref = unsafe { bindings::wrap_taglib_tag_artist(self.ctx) }; + unsafe { bindings::wrap_taglib_tag_set_title(self.ctx, title.as_ptr()) }; + } + fn artist(&self) -> Option { + let artist_ref = unsafe { bindings::wrap_taglib_tag_artist(self.ctx) }; - c_str_to_str(artist_ref) - } - fn set_artist(&mut self, artist: String) { - let artist = CString::new(artist).unwrap(); + c_str_to_str(artist_ref) + } + fn set_artist(&mut self, artist: String) { + let artist = CString::new(artist).unwrap(); - unsafe { bindings::wrap_taglib_tag_set_artist(self.ctx, artist.as_ptr()) }; - } + unsafe { bindings::wrap_taglib_tag_set_artist(self.ctx, artist.as_ptr()) }; + } } diff --git a/modules/taglib/src/lib.rs b/modules/taglib/src/lib.rs index b71dc31..23870cc 100644 --- a/modules/taglib/src/lib.rs +++ b/modules/taglib/src/lib.rs @@ -6,17 +6,17 @@ pub mod traits; pub(crate) mod utils; pub(crate) mod bindings { - #![allow(non_snake_case)] - #![allow(dead_code)] - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + #![allow(non_snake_case)] + #![allow(dead_code)] + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } #[derive(Debug, Clone, Copy)] pub enum TagLibFileType { - OggFLAC = 1, - OggOpus = 2, - OggSpeex = 3, - OggVorbis = 4, + OggFLAC = 1, + OggOpus = 2, + OggSpeex = 3, + OggVorbis = 4, } pub use impls::file::*; diff --git a/modules/taglib/src/traits.rs b/modules/taglib/src/traits.rs index 88115ce..c18ee23 100644 --- a/modules/taglib/src/traits.rs +++ b/modules/taglib/src/traits.rs @@ -1,12 +1,12 @@ use crate::errors::TagLibError; pub trait File { - fn save(&mut self) -> Result<(), TagLibError>; + fn save(&mut self) -> Result<(), TagLibError>; } pub trait Tag { - fn title(&self) -> Option; - fn artist(&self) -> Option; - fn set_title(&mut self, title: String); - fn set_artist(&mut self, artist: String); + fn title(&self) -> Option; + fn artist(&self) -> Option; + fn set_title(&mut self, title: String); + fn set_artist(&mut self, artist: String); } diff --git a/modules/taglib/src/utils.rs b/modules/taglib/src/utils.rs index 1ee24e5..726708d 100644 --- a/modules/taglib/src/utils.rs +++ b/modules/taglib/src/utils.rs @@ -1,15 +1,15 @@ use std::{ffi::CStr, os::raw::c_char}; pub fn c_str_to_str(c_str: *const c_char) -> Option { - if c_str.is_null() { - None - } else { - let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; + if c_str.is_null() { + None + } else { + let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; - if bytes.is_empty() { - None - } else { - Some(String::from_utf8_lossy(bytes).to_string()) - } - } + if bytes.is_empty() { + None + } else { + Some(String::from_utf8_lossy(bytes).to_string()) + } + } } diff --git a/src/args.rs b/src/args.rs index 8b331d5..2f5eb90 100644 --- a/src/args.rs +++ b/src/args.rs @@ -3,87 +3,87 @@ use clap::{Args, Parser, Subcommand}; #[derive(Debug, Parser)] #[clap()] pub struct CLIArgs { - #[clap(subcommand)] - pub command: Commands, + #[clap(subcommand)] + pub command: Commands, } #[derive(Debug, Clone, Subcommand)] pub enum Commands { - Process(ProcessCommandArgs), - Genhtml(GenHTMLCommandArgs), - Transcode(TranscodeCommandArgs), - Copy(CopyCommandArgs), - SetTags(SetTagsCommandArgs), - GetTags(GetTagsCommandArgs), + Process(ProcessCommandArgs), + Genhtml(GenHTMLCommandArgs), + Transcode(TranscodeCommandArgs), + Copy(CopyCommandArgs), + SetTags(SetTagsCommandArgs), + GetTags(GetTagsCommandArgs), } #[derive(Debug, Clone, Args)] pub struct ProcessCommandArgs { - pub source: String, - #[clap(long)] - pub dry_run: bool, - #[clap(long)] - pub skip_replaygain: bool, - #[clap(long)] - pub force_replaygain: bool, - #[clap(long)] - pub replaygain_threads: Option, + pub source: String, + #[clap(long)] + pub dry_run: bool, + #[clap(long)] + pub skip_replaygain: bool, + #[clap(long)] + pub force_replaygain: bool, + #[clap(long)] + pub replaygain_threads: Option, } #[derive(Debug, Clone, Args)] pub struct GenHTMLCommandArgs { - pub source: String, - pub dest: String, - #[clap(long, default_value = "musicutil")] - pub title: String, - #[clap(long, default_value = "generated by musicutil")] - pub description: String, - #[clap(long)] - pub link_base: Option, + pub source: String, + pub dest: String, + #[clap(long, default_value = "musicutil")] + pub title: String, + #[clap(long, default_value = "generated by musicutil")] + pub description: String, + #[clap(long)] + pub link_base: Option, } #[derive(Debug, Clone, Args)] pub struct TranscodeCommandArgs { - pub source: String, - pub dest: String, - #[clap(long)] - pub transcode_preset: Option, - #[clap(long)] - pub transcode_config: Option, - #[clap(long)] - pub ignore_extension: bool, - #[clap(long)] - pub hide_progress: bool, + pub source: String, + pub dest: String, + #[clap(long)] + pub transcode_preset: Option, + #[clap(long)] + pub transcode_config: Option, + #[clap(long)] + pub ignore_extension: bool, + #[clap(long)] + pub hide_progress: bool, } #[derive(Debug, Clone, Args)] pub struct CopyCommandArgs { - pub source: String, - pub dest: String, - #[clap(long)] - pub transcode_preset: Option, - #[clap(long)] - pub transcode_config: Option, - #[clap(long)] - pub threads: Option, - #[clap(long)] - pub no_skip_existing: bool, - #[clap(long)] - pub single_directory: bool, + pub source: String, + pub dest: String, + #[clap(long)] + pub transcode_preset: Option, + #[clap(long)] + pub transcode_config: Option, + #[clap(long)] + pub threads: Option, + #[clap(long)] + pub no_skip_existing: bool, + #[clap(long)] + pub single_directory: bool, } #[derive(Debug, Clone, Args)] pub struct SetTagsCommandArgs { - pub files: Vec, - #[clap(long)] - pub title: Option, - #[clap(long)] - pub artist: Option, + pub files: Vec, + #[clap(long)] + pub title: Option, + #[clap(long)] + pub artist: Option, } #[derive(Debug, Clone, Args)] pub struct GetTagsCommandArgs { - pub files: Vec, - #[clap(long)] - pub json: bool, + pub files: Vec, + #[clap(long)] + pub json: bool, } diff --git a/src/commands/copy.rs b/src/commands/copy.rs index ebedf8a..8cba9e4 100644 --- a/src/commands/copy.rs +++ b/src/commands/copy.rs @@ -1,243 +1,243 @@ use std::{ - collections::{hash_map::Entry, HashMap}, - fs, - path::PathBuf, - process::exit, - str::FromStr, - sync::{Arc, Mutex}, - thread::scope, + collections::{hash_map::Entry, HashMap}, + fs, + path::PathBuf, + process::exit, + str::FromStr, + sync::{Arc, Mutex}, + thread::scope, }; use crate::{ - args::{CLIArgs, CopyCommandArgs}, - types::File, - utils::{ - formats::get_format_handler, - scan_for_music, - transcoder::{ - presets::{print_presets, transcode_preset_or_config}, - transcode, - types::TranscodeConfig, - }, - }, + args::{CLIArgs, CopyCommandArgs}, + types::File, + utils::{ + formats::get_format_handler, + scan_for_music, + transcoder::{ + presets::{print_presets, transcode_preset_or_config}, + transcode, + types::TranscodeConfig, + }, + }, }; pub fn copy_command( - _args: CLIArgs, - copy_args: &CopyCommandArgs, + _args: CLIArgs, + copy_args: &CopyCommandArgs, ) -> Result<(), Box> { - if copy_args.transcode_config.is_none() && copy_args.transcode_preset.is_none() { - panic!("Please provide Transcode Preset/Config"); - } + if copy_args.transcode_config.is_none() && copy_args.transcode_preset.is_none() { + panic!("Please provide Transcode Preset/Config"); + } - if let Some(preset) = ©_args.transcode_preset { - if preset == "list" { - print_presets(); - exit(0); - } - } + if let Some(preset) = ©_args.transcode_preset { + if preset == "list" { + print_presets(); + exit(0); + } + } - println!("Scanning For Music"); - let mut files = scan_for_music(©_args.source)?; + println!("Scanning For Music"); + let mut files = scan_for_music(©_args.source)?; - println!("Analysing Files"); - for file in files.iter_mut() { - println!("Analysing: {:?}", file.join_path_from_source()); + println!("Analysing Files"); + for file in files.iter_mut() { + println!("Analysing: {:?}", file.join_path_from_source()); - let mut handler = get_format_handler(file)?; + let mut handler = get_format_handler(file)?; - file.info = handler.get_audio_file_info(true)?; - } + file.info = handler.get_audio_file_info(true)?; + } - if copy_args.single_directory { - println!("Checking for Duplicates"); - let mut seen: HashMap = HashMap::new(); - let mut dupes: Vec = Vec::new(); + if copy_args.single_directory { + println!("Checking for Duplicates"); + let mut seen: HashMap = HashMap::new(); + let mut dupes: Vec = Vec::new(); - for file in files.iter() { - let filename = file.join_filename(); + for file in files.iter() { + let filename = file.join_filename(); - if let Entry::Vacant(entry) = seen.entry(filename.clone()) { - entry.insert(true); - } else { - dupes.push(filename); - } - } + if let Entry::Vacant(entry) = seen.entry(filename.clone()) { + entry.insert(true); + } else { + dupes.push(filename); + } + } - if !dupes.is_empty() { - panic!("Duplicates Found: {}", dupes.join(",")) - } - } + if !dupes.is_empty() { + panic!("Duplicates Found: {}", dupes.join(",")) + } + } - if !copy_args.single_directory { - println!("Creating Directories"); + if !copy_args.single_directory { + println!("Creating Directories"); - let mut directories: Vec = Vec::new(); - for file in files.iter() { - let file_directory = file.path_from_source.to_string_lossy().to_string(); + let mut directories: Vec = Vec::new(); + for file in files.iter() { + let file_directory = file.path_from_source.to_string_lossy().to_string(); - if !directories.contains(&file_directory) { - directories.push(file_directory.clone()); - } - } - for directory in directories.iter() { - fs::create_dir_all( - PathBuf::from_str(copy_args.dest.as_str()) - .expect("invalid destination") - .join(directory), - )?; - } - } + if !directories.contains(&file_directory) { + directories.push(file_directory.clone()); + } + } + for directory in directories.iter() { + fs::create_dir_all( + PathBuf::from_str(copy_args.dest.as_str()) + .expect("invalid destination") + .join(directory), + )?; + } + } - if copy_args - .transcode_preset - .as_ref() - .unwrap_or(&"".to_string()) - == "copy" - { - println!("Copying Files Into Dest"); - copy_files(&files, copy_args)?; - } else { - println!("Transcoding Files"); - transcode_files(&files, copy_args)?; - } + if copy_args + .transcode_preset + .as_ref() + .unwrap_or(&"".to_string()) + == "copy" + { + println!("Copying Files Into Dest"); + copy_files(&files, copy_args)?; + } else { + println!("Transcoding Files"); + transcode_files(&files, copy_args)?; + } - Ok(()) + Ok(()) } fn copy_file(file: &File, copy_args: &CopyCommandArgs) -> Result<(), Box> { - let from_path = file.join_path_to(); + let from_path = file.join_path_to(); - let to_path_dest = PathBuf::from_str(copy_args.dest.as_str()).expect("invalid destination"); - let to_path = match copy_args.single_directory { - true => to_path_dest.join(file.join_filename()), - false => to_path_dest - .join(file.path_from_source.clone()) - .join(file.join_filename()), - }; + let to_path_dest = PathBuf::from_str(copy_args.dest.as_str()).expect("invalid destination"); + let to_path = match copy_args.single_directory { + true => to_path_dest.join(file.join_filename()), + false => to_path_dest + .join(file.path_from_source.clone()) + .join(file.join_filename()), + }; - let to_path_string = to_path.to_string_lossy(); + let to_path_string = to_path.to_string_lossy(); - if !copy_args.no_skip_existing && to_path.exists() { - println!( - "Skipping {} as already exists in destination", - to_path_string - ); - } else { - println!("Copying {:?} to {}", from_path, to_path_string); - fs::copy(from_path, to_path)?; - } - Ok(()) + if !copy_args.no_skip_existing && to_path.exists() { + println!( + "Skipping {} as already exists in destination", + to_path_string + ); + } else { + println!("Copying {:?} to {}", from_path, to_path_string); + fs::copy(from_path, to_path)?; + } + Ok(()) } fn copy_files( - files: &[File], - copy_args: &CopyCommandArgs, + files: &[File], + copy_args: &CopyCommandArgs, ) -> Result<(), Box> { - for file in files.iter() { - copy_file(file, copy_args)?; + for file in files.iter() { + copy_file(file, copy_args)?; - if !file.extra_files.is_empty() { - for extra_file in file.extra_files.iter() { - copy_file(extra_file, copy_args)?; - } - } - } + if !file.extra_files.is_empty() { + for extra_file in file.extra_files.iter() { + copy_file(extra_file, copy_args)?; + } + } + } - Ok(()) + Ok(()) } fn transcode_file( - file: &File, - copy_args: &CopyCommandArgs, - config: &TranscodeConfig, - is_threaded: bool, + file: &File, + copy_args: &CopyCommandArgs, + config: &TranscodeConfig, + is_threaded: bool, ) -> Result<(), Box> { - let new_filename_full: String = match config.file_extension.clone() { - Some(ext) => format!("{}.{}", file.filename, ext), - None => { - panic!("file_extension is required in custom transcode configs"); - } - }; + let new_filename_full: String = match config.file_extension.clone() { + Some(ext) => format!("{}.{}", file.filename, ext), + None => { + panic!("file_extension is required in custom transcode configs"); + } + }; - let to_path_dest = PathBuf::from_str(copy_args.dest.as_str()).expect("invalid destination"); - let to_path = match copy_args.single_directory { - true => to_path_dest.join(new_filename_full), - false => to_path_dest - .join(file.path_from_source.clone()) - .join(new_filename_full), - }; + let to_path_dest = PathBuf::from_str(copy_args.dest.as_str()).expect("invalid destination"); + let to_path = match copy_args.single_directory { + true => to_path_dest.join(new_filename_full), + false => to_path_dest + .join(file.path_from_source.clone()) + .join(new_filename_full), + }; - let to_path_string = to_path.to_string_lossy(); + let to_path_string = to_path.to_string_lossy(); - if !file.extra_files.is_empty() { - for extra_file in file.extra_files.iter() { - copy_file(extra_file, copy_args)?; - } - } + if !file.extra_files.is_empty() { + for extra_file in file.extra_files.iter() { + copy_file(extra_file, copy_args)?; + } + } - if !copy_args.no_skip_existing && to_path.exists() { - println!( - "Skipping transcode for {} as file already exists", - to_path_string - ); + if !copy_args.no_skip_existing && to_path.exists() { + println!( + "Skipping transcode for {} as file already exists", + to_path_string + ); - return Ok(()); - } + return Ok(()); + } - println!("Transcoding {}", to_path_string); + println!("Transcoding {}", to_path_string); - transcode(file.to_owned(), to_path_string.to_string(), config, None)?; + transcode(file.to_owned(), to_path_string.to_string(), config, None)?; - if is_threaded { - println!("Finished Transcoding {}", to_path_string); - } + if is_threaded { + println!("Finished Transcoding {}", to_path_string); + } - Ok(()) + Ok(()) } fn transcode_files( - files: &[File], - copy_args: &CopyCommandArgs, + files: &[File], + copy_args: &CopyCommandArgs, ) -> Result<(), Box> { - let transcode_config = transcode_preset_or_config( - copy_args.transcode_preset.as_ref(), - copy_args.transcode_config.as_ref(), - ) - .expect("transcode config error"); + let transcode_config = transcode_preset_or_config( + copy_args.transcode_preset.as_ref(), + copy_args.transcode_config.as_ref(), + ) + .expect("transcode config error"); - let threads = copy_args.threads.unwrap_or(1); + let threads = copy_args.threads.unwrap_or(1); - if threads > 1 { - let files_copy = files.to_vec(); + if threads > 1 { + let files_copy = files.to_vec(); - let jobs: Arc>> = Arc::new(Mutex::new(files_copy)); + let jobs: Arc>> = Arc::new(Mutex::new(files_copy)); - let copy_args = Arc::new(copy_args); - let transcode_config = Arc::new(transcode_config); + let copy_args = Arc::new(copy_args); + let transcode_config = Arc::new(transcode_config); - scope(|s| { - for _ in 0..threads { - s.spawn(|| loop { - let mut jobs = jobs.lock().unwrap(); + scope(|s| { + for _ in 0..threads { + s.spawn(|| loop { + let mut jobs = jobs.lock().unwrap(); - let job = jobs.pop(); - if let Some(job) = job { - let result = transcode_file(&job, ©_args, &transcode_config, true); - if let Err(err) = result { - panic!("Error Transcoding: {}", err) - } - } else { - break; - } - }); - } - }); - } else { - for file in files.iter() { - transcode_file(file, copy_args, &transcode_config, false)?; - } - } + let job = jobs.pop(); + if let Some(job) = job { + let result = transcode_file(&job, ©_args, &transcode_config, true); + if let Err(err) = result { + panic!("Error Transcoding: {}", err) + } + } else { + break; + } + }); + } + }); + } else { + for file in files.iter() { + transcode_file(file, copy_args, &transcode_config, false)?; + } + } - Ok(()) + Ok(()) } diff --git a/src/commands/genhtml.rs b/src/commands/genhtml.rs index 8de1de3..341aa0b 100644 --- a/src/commands/genhtml.rs +++ b/src/commands/genhtml.rs @@ -11,21 +11,21 @@ use html_escape::encode_text; use urlencoding::encode as url_encode; fn table_for_files(files: Vec, includes_path: bool, link_base: &Option) -> String { - let mut html_content = String::new(); + let mut html_content = String::new(); - let mut path_head = String::new(); - if includes_path { - path_head.push_str("Path") - } + let mut path_head = String::new(); + if includes_path { + path_head.push_str("Path") + } - let mut link_head = String::new(); - if link_base.is_some() { - link_head.push_str("Link") - } + let mut link_head = String::new(); + if link_base.is_some() { + link_head.push_str("Link") + } - html_content.push_str( - format!( - " + html_content.push_str( + format!( + " @@ -38,69 +38,69 @@ fn table_for_files(files: Vec, includes_path: bool, link_base: &Option ", - link_head, path_head - ) - .as_str(), - ); + link_head, path_head + ) + .as_str(), + ); - let mut is_odd = true; - for file in files.iter() { - let td_class = match is_odd { - true => "pure-table-odd", - false => "pure-table-even", - }; + let mut is_odd = true; + for file in files.iter() { + let td_class = match is_odd { + true => "pure-table-odd", + false => "pure-table-even", + }; - let data_title = encode_text(&file.info.tags.title); - let data_artist = encode_text(&file.info.tags.artist); + let data_title = encode_text(&file.info.tags.title); + let data_artist = encode_text(&file.info.tags.artist); - let format = if let Some(format) = &file.info.format { - format.to_string() - } else { - "unknown".to_string() - }; + let format = if let Some(format) = &file.info.format { + format.to_string() + } else { + "unknown".to_string() + }; - let data_format = encode_text(&format); + let data_format = encode_text(&format); - let mut path_data = String::new(); - if includes_path { - let file_directory = file.path_from_source.to_string_lossy().to_string(); + let mut path_data = String::new(); + if includes_path { + let file_directory = file.path_from_source.to_string_lossy().to_string(); - path_data.push_str(format!("", encode_text(&file_directory)).as_str()); - } + path_data.push_str(format!("", encode_text(&file_directory)).as_str()); + } - let mut url_data = String::new(); - if let Some(link_base) = &link_base { - let mut url = String::new(); + let mut url_data = String::new(); + if let Some(link_base) = &link_base { + let mut url = String::new(); - url.push_str(link_base.as_str()); - url.push('/'); + url.push_str(link_base.as_str()); + url.push('/'); - let file_path = file.join_path_from_source(); - let file_path: Vec<&OsStr> = file_path.iter().collect(); + let file_path = file.join_path_from_source(); + let file_path: Vec<&OsStr> = file_path.iter().collect(); - for i in 0..(file_path.len()) { - let file_path_element = file_path.get(i).unwrap(); + for i in 0..(file_path.len()) { + let file_path_element = file_path.get(i).unwrap(); - url.push_str( - url_encode( - file_path_element - .to_str() - .expect("invalid character in filename"), - ) - .to_string() - .as_str(), - ); - if i != file_path.len() - 1 { - url.push('/'); - } - } + url.push_str( + url_encode( + file_path_element + .to_str() + .expect("invalid character in filename"), + ) + .to_string() + .as_str(), + ); + if i != file_path.len() - 1 { + url.push('/'); + } + } - url_data.push_str(format!("", url).as_str()); - } + url_data.push_str(format!("", url).as_str()); + } - html_content.push_str( - format!( - " + html_content.push_str( + format!( + " {} {} @@ -109,58 +109,58 @@ fn table_for_files(files: Vec, includes_path: bool, link_base: &Option{} ", - td_class, url_data, path_data, data_title, data_artist, data_format - ) - .as_str(), - ); - is_odd = !is_odd; - } + td_class, url_data, path_data, data_title, data_artist, data_format + ) + .as_str(), + ); + is_odd = !is_odd; + } - html_content.push_str( - " + html_content.push_str( + "
{}{}🔗🔗
", - ); + ); - html_content + html_content } pub fn genhtml_command( - _args: CLIArgs, - genhtml_args: &GenHTMLCommandArgs, + _args: CLIArgs, + genhtml_args: &GenHTMLCommandArgs, ) -> Result<(), Box> { - println!("Scanning For Music"); - let mut files = scan_for_music(&genhtml_args.source)?; + println!("Scanning For Music"); + let mut files = scan_for_music(&genhtml_args.source)?; - println!("Analysing Files"); - for file in files.iter_mut() { - println!("Analysing: {:?}", file.join_path_from_source()); + println!("Analysing Files"); + for file in files.iter_mut() { + println!("Analysing: {:?}", file.join_path_from_source()); - let mut handler = get_format_handler(file)?; + let mut handler = get_format_handler(file)?; - file.info = handler.get_audio_file_info(false)?; - } + file.info = handler.get_audio_file_info(false)?; + } - files.sort_by(|a, b| -> Ordering { - if a.path_from_source != b.path_from_source { - return a.path_from_source.cmp(&b.path_from_source); - } + files.sort_by(|a, b| -> Ordering { + if a.path_from_source != b.path_from_source { + return a.path_from_source.cmp(&b.path_from_source); + } - let a_tags = &a.info.tags; - let b_tags = &b.info.tags; + let a_tags = &a.info.tags; + let b_tags = &b.info.tags; - if a_tags.title != b_tags.title { - return a_tags.title.cmp(&b_tags.title); - } + if a_tags.title != b_tags.title { + return a_tags.title.cmp(&b_tags.title); + } - a_tags.artist.cmp(&b_tags.artist) - }); + a_tags.artist.cmp(&b_tags.artist) + }); - let mut html_content = String::new(); - html_content.push_str( - format!( - " + let mut html_content = String::new(); + html_content.push_str( + format!( + " @@ -173,30 +173,30 @@ pub fn genhtml_command( ", - encode_text(&genhtml_args.title), - encode_text(&genhtml_args.title), - encode_text(&genhtml_args.description) - ) - .as_str(), - ); + encode_text(&genhtml_args.title), + encode_text(&genhtml_args.title), + encode_text(&genhtml_args.description) + ) + .as_str(), + ); - html_content.push_str(&table_for_files(files, true, &genhtml_args.link_base)); - html_content.push_str(""); + html_content.push_str(&table_for_files(files, true, &genhtml_args.link_base)); + html_content.push_str(""); - let file_path = std::path::PathBuf::from(genhtml_args.dest.as_str()).join("index.html"); - let html_index_file = std::fs::File::create(file_path); + let file_path = std::path::PathBuf::from(genhtml_args.dest.as_str()).join("index.html"); + let html_index_file = std::fs::File::create(file_path); - match html_index_file { - Ok(mut file) => match file.write_all(html_content.as_bytes()) { - Ok(_) => {} - Err(e) => { - panic!("Could not write HTML file: {}", e); - } - }, - Err(e) => { - panic!("Could not create HTML file: {}", e); - } - } + match html_index_file { + Ok(mut file) => match file.write_all(html_content.as_bytes()) { + Ok(_) => {} + Err(e) => { + panic!("Could not write HTML file: {}", e); + } + }, + Err(e) => { + panic!("Could not create HTML file: {}", e); + } + } - Ok(()) + Ok(()) } diff --git a/src/commands/get_tags.rs b/src/commands/get_tags.rs index 9dc1ff5..39f540a 100644 --- a/src/commands/get_tags.rs +++ b/src/commands/get_tags.rs @@ -10,62 +10,62 @@ use crate::utils::formats::get_format_handler; #[derive(Debug, Clone, Serialize)] struct Tags { - title: String, - artist: String, + title: String, + artist: String, } fn from_main_tags(tags: &crate::types::Tags) -> Tags { - Tags { - title: tags.title.clone(), - artist: tags.artist.clone(), - } + Tags { + title: tags.title.clone(), + artist: tags.artist.clone(), + } } pub fn get_tags_command( - _args: CLIArgs, - get_tags_args: &GetTagsCommandArgs, + _args: CLIArgs, + get_tags_args: &GetTagsCommandArgs, ) -> Result<(), Box> { - let mut files: Vec = Vec::new(); + let mut files: Vec = Vec::new(); - for file in get_tags_args.files.iter() { - files.push(File::from_path("".to_string(), PathBuf::from(file))); - } + for file in get_tags_args.files.iter() { + files.push(File::from_path("".to_string(), PathBuf::from(file))); + } - for file in files.iter_mut() { - let handler = get_format_handler(file)?; + for file in files.iter_mut() { + let handler = get_format_handler(file)?; - file.info.tags = handler.get_tags(true)?; - } + file.info.tags = handler.get_tags(true)?; + } - if files.len() == 1 { - let file = files.first().unwrap(); + if files.len() == 1 { + let file = files.first().unwrap(); - if get_tags_args.json { - println!( - "{}", - serde_json::to_string_pretty(&from_main_tags(&file.info.tags)).unwrap() - ); - } else { - println!("{:#?}", from_main_tags(&file.info.tags)); - } - } else if get_tags_args.json { - let mut result: HashMap = HashMap::new(); - for file in files.iter() { - result.insert( - file.join_path_to().to_string_lossy().to_string(), - from_main_tags(&file.info.tags), - ); - } - println!("{}", serde_json::to_string_pretty(&result)?); - } else { - for file in files.iter() { - println!( - "{}: {:#?}", - file.join_path_to().to_string_lossy(), - from_main_tags(&file.info.tags) - ); - } - } + if get_tags_args.json { + println!( + "{}", + serde_json::to_string_pretty(&from_main_tags(&file.info.tags)).unwrap() + ); + } else { + println!("{:#?}", from_main_tags(&file.info.tags)); + } + } else if get_tags_args.json { + let mut result: HashMap = HashMap::new(); + for file in files.iter() { + result.insert( + file.join_path_to().to_string_lossy().to_string(), + from_main_tags(&file.info.tags), + ); + } + println!("{}", serde_json::to_string_pretty(&result)?); + } else { + for file in files.iter() { + println!( + "{}: {:#?}", + file.join_path_to().to_string_lossy(), + from_main_tags(&file.info.tags) + ); + } + } - Ok(()) + Ok(()) } diff --git a/src/commands/process.rs b/src/commands/process.rs index af1a607..dc33c91 100644 --- a/src/commands/process.rs +++ b/src/commands/process.rs @@ -11,184 +11,184 @@ use crate::utils::replaygain::analyze_replaygain; use crate::utils::scan_for_music; fn rename_file(process_args: &ProcessCommandArgs, file: &mut File) { - let title = &file.info.tags.title; - let artist = &file.info.tags.artist; + let title = &file.info.tags.title; + let artist = &file.info.tags.artist; - let replace_char = "_".to_string(); + let replace_char = "_".to_string(); - // Step 1: Remove Newlines - let title = title.replace('\n', ""); - let artist = artist.replace('\n', ""); + // Step 1: Remove Newlines + let title = title.replace('\n', ""); + let artist = artist.replace('\n', ""); - // Step 2: Strip ASCII - let title = reduce_to_ascii(title); - let artist = reduce_to_ascii(artist); + // Step 2: Strip ASCII + let title = reduce_to_ascii(title); + let artist = reduce_to_ascii(artist); - // Step 3: Remove File Seperators - let title = title.replace('\\', &replace_char); - let title = title.replace('/', &replace_char); - let artist = artist.replace('\\', &replace_char); - let artist = artist.replace('/', &replace_char); + // Step 3: Remove File Seperators + let title = title.replace('\\', &replace_char); + let title = title.replace('/', &replace_char); + let artist = artist.replace('\\', &replace_char); + let artist = artist.replace('/', &replace_char); - // Step 4: Join Filename - let filename = format!("{} - {}", artist, title); + // Step 4: Join Filename + let filename = format!("{} - {}", artist, title); - if filename == file.filename { - return; - } + if filename == file.filename { + return; + } - // Step 5: Make new File with filename set - let mut new_file = file.clone(); - new_file.filename = filename.clone(); + // Step 5: Make new File with filename set + let mut new_file = file.clone(); + new_file.filename = filename.clone(); - let extension = &file.extension; + let extension = &file.extension; - // Step 6: Rename File - println!( - "Renaming File from {}.{extension} to {}.{extension}", - file.filename, filename - ); - if !process_args.dry_run { - if std::path::Path::new(&new_file.join_path_to()).exists() { - panic!( - "Refusing to rename {} to {}, please retag to be distinct", - &file.join_filename(), - &new_file.join_filename() - ); - } else { - let err = std::fs::rename(&file.join_path_to(), &new_file.join_path_to()); - if err.is_err() { - panic!("Could not rename {:?}", err) - } - } - } + // Step 6: Rename File + println!( + "Renaming File from {}.{extension} to {}.{extension}", + file.filename, filename + ); + if !process_args.dry_run { + if std::path::Path::new(&new_file.join_path_to()).exists() { + panic!( + "Refusing to rename {} to {}, please retag to be distinct", + &file.join_filename(), + &new_file.join_filename() + ); + } else { + let err = std::fs::rename(&file.join_path_to(), &new_file.join_path_to()); + if err.is_err() { + panic!("Could not rename {:?}", err) + } + } + } - if !file.extra_files.is_empty() { - let mut new_extra_files: Vec = Vec::new(); + if !file.extra_files.is_empty() { + let mut new_extra_files: Vec = Vec::new(); - for extra_file in file.extra_files.iter() { - let mut new_extra_file = extra_file.clone(); - new_extra_file.filename = filename.clone(); + for extra_file in file.extra_files.iter() { + let mut new_extra_file = extra_file.clone(); + new_extra_file.filename = filename.clone(); - let extra_extension = &extra_file.extension; + let extra_extension = &extra_file.extension; - println!( - "Renaming Extra File from {}.{extra_extension} to {}.{extra_extension}", - file.filename, filename - ); + println!( + "Renaming Extra File from {}.{extra_extension} to {}.{extra_extension}", + file.filename, filename + ); - if !process_args.dry_run { - let err = - std::fs::rename(&extra_file.join_path_to(), &new_extra_file.join_path_to()); - if err.is_err() { - panic!("Could not rename {:?}", err) - } - new_extra_files.push(new_extra_file); - } - } - if !process_args.dry_run { - file.extra_files.clear(); - file.extra_files.extend(new_extra_files); - } - } + if !process_args.dry_run { + let err = + std::fs::rename(&extra_file.join_path_to(), &new_extra_file.join_path_to()); + if err.is_err() { + panic!("Could not rename {:?}", err) + } + new_extra_files.push(new_extra_file); + } + } + if !process_args.dry_run { + file.extra_files.clear(); + file.extra_files.extend(new_extra_files); + } + } - if !process_args.dry_run { - file.filename = filename; - } + if !process_args.dry_run { + file.filename = filename; + } } pub fn add_replaygain_tags(file: &File, force: bool) -> Result<(), Box> { - if !file.info.supports_replaygain { - println!( - "Skipping replaygain for {:?}, not supported", - file.join_path_from_source() - ); + if !file.info.supports_replaygain { + println!( + "Skipping replaygain for {:?}, not supported", + file.join_path_from_source() + ); - return Ok(()); - } + return Ok(()); + } - if file.info.contains_replaygain && !force { - println!( - "Skipping replaygain for {:?}, contains already", - file.join_path_from_source() - ); - return Ok(()); - } + if file.info.contains_replaygain && !force { + println!( + "Skipping replaygain for {:?}, contains already", + file.join_path_from_source() + ); + return Ok(()); + } - println!( - "Analyzing replaygain for {:?}", - file.join_path_from_source() - ); + println!( + "Analyzing replaygain for {:?}", + file.join_path_from_source() + ); - let replaygain_data = analyze_replaygain(file.join_path_to())?; + let replaygain_data = analyze_replaygain(file.join_path_to())?; - let mut handler = get_format_handler(file)?; + let mut handler = get_format_handler(file)?; - handler.set_replaygain_data(replaygain_data)?; - handler.save_changes()?; + handler.set_replaygain_data(replaygain_data)?; + handler.save_changes()?; - println!( - "Applied replaygain tags for {:?}", - file.join_path_from_source() - ); + println!( + "Applied replaygain tags for {:?}", + file.join_path_from_source() + ); - Ok(()) + Ok(()) } pub fn process_command( - _args: CLIArgs, - process_args: &ProcessCommandArgs, + _args: CLIArgs, + process_args: &ProcessCommandArgs, ) -> Result<(), Box> { - println!("Scanning For Music"); - let mut files = scan_for_music(&process_args.source)?; + println!("Scanning For Music"); + let mut files = scan_for_music(&process_args.source)?; - println!("Analysing Files"); - for file in files.iter_mut() { - println!("Analysing: {:?}", file.join_path_from_source()); + println!("Analysing Files"); + for file in files.iter_mut() { + println!("Analysing: {:?}", file.join_path_from_source()); - let mut handler = get_format_handler(file)?; + let mut handler = get_format_handler(file)?; - file.info = handler.get_audio_file_info(false)?; - } + file.info = handler.get_audio_file_info(false)?; + } - println!("Renaming Files"); - for file in files.iter_mut() { - rename_file(process_args, file); - } + println!("Renaming Files"); + for file in files.iter_mut() { + rename_file(process_args, file); + } - if !process_args.skip_replaygain && !process_args.dry_run { - println!("Adding ReplayGain Tags to Files"); + if !process_args.skip_replaygain && !process_args.dry_run { + println!("Adding ReplayGain Tags to Files"); - let threads = process_args.replaygain_threads.unwrap_or(0); + let threads = process_args.replaygain_threads.unwrap_or(0); - if threads <= 1 { - for file in files.iter_mut() { - add_replaygain_tags(file, process_args.force_replaygain)?; - } + if threads <= 1 { + for file in files.iter_mut() { + add_replaygain_tags(file, process_args.force_replaygain)?; + } - return Ok(()); - } else { - let jobs: Arc>> = Arc::new(Mutex::new(files)); + return Ok(()); + } else { + let jobs: Arc>> = Arc::new(Mutex::new(files)); - scope(|s| { - for _ in 0..threads { - s.spawn(|| loop { - let mut jobs = jobs.lock().unwrap(); + scope(|s| { + for _ in 0..threads { + s.spawn(|| loop { + let mut jobs = jobs.lock().unwrap(); - let job = jobs.pop(); - if let Some(job) = job { - let result = add_replaygain_tags(&job, process_args.force_replaygain); - if let Err(err) = result { - panic!("Error doing replaygain: {}", err) - } - } else { - break; - } - }); - } - }); - } - } + let job = jobs.pop(); + if let Some(job) = job { + let result = add_replaygain_tags(&job, process_args.force_replaygain); + if let Err(err) = result { + panic!("Error doing replaygain: {}", err) + } + } else { + break; + } + }); + } + }); + } + } - Ok(()) + Ok(()) } diff --git a/src/commands/set_tags.rs b/src/commands/set_tags.rs index 4c2e365..dd25095 100644 --- a/src/commands/set_tags.rs +++ b/src/commands/set_tags.rs @@ -6,28 +6,28 @@ use crate::types::File; use crate::utils::formats::get_format_handler; pub fn set_tags_command( - _args: CLIArgs, - add_tags_args: &SetTagsCommandArgs, + _args: CLIArgs, + add_tags_args: &SetTagsCommandArgs, ) -> Result<(), Box> { - let mut files: Vec = Vec::new(); + let mut files: Vec = Vec::new(); - for file in add_tags_args.files.iter() { - files.push(File::from_path("".to_string(), PathBuf::from(file))); - } + for file in add_tags_args.files.iter() { + files.push(File::from_path("".to_string(), PathBuf::from(file))); + } - for file in files.iter() { - let mut handler = get_format_handler(file)?; + for file in files.iter() { + let mut handler = get_format_handler(file)?; - if let Some(title) = &add_tags_args.title { - handler.set_title(title.clone())?; - } + if let Some(title) = &add_tags_args.title { + handler.set_title(title.clone())?; + } - if let Some(artist) = &add_tags_args.artist { - handler.set_artist(artist.clone())?; - } + if let Some(artist) = &add_tags_args.artist { + handler.set_artist(artist.clone())?; + } - handler.save_changes()?; - } + handler.save_changes()?; + } - Ok(()) + Ok(()) } diff --git a/src/commands/transcode.rs b/src/commands/transcode.rs index aba335b..19c5ccb 100644 --- a/src/commands/transcode.rs +++ b/src/commands/transcode.rs @@ -12,73 +12,73 @@ use crate::utils::transcoder::presets::transcode_preset_or_config; use crate::utils::transcoder::transcode; pub fn transcode_command( - _args: CLIArgs, - transcode_args: &TranscodeCommandArgs, + _args: CLIArgs, + transcode_args: &TranscodeCommandArgs, ) -> Result<(), Box> { - if let Some(preset) = &transcode_args.transcode_preset { - if preset == "list" { - print_presets(); - exit(0); - } - } + if let Some(preset) = &transcode_args.transcode_preset { + if preset == "list" { + print_presets(); + exit(0); + } + } - let transcode_config = transcode_preset_or_config( - transcode_args.transcode_preset.as_ref(), - transcode_args.transcode_config.as_ref(), - ) - .expect("transcode config error"); + let transcode_config = transcode_preset_or_config( + transcode_args.transcode_preset.as_ref(), + transcode_args.transcode_config.as_ref(), + ) + .expect("transcode config error"); - println!("Transcoding"); + println!("Transcoding"); - let input_file = File::from_path("".to_string(), PathBuf::from(&transcode_args.source)); - let output_file = File::from_path("".to_string(), PathBuf::from(&transcode_args.dest)); + let input_file = File::from_path("".to_string(), PathBuf::from(&transcode_args.source)); + let output_file = File::from_path("".to_string(), PathBuf::from(&transcode_args.dest)); - if !transcode_args.ignore_extension { - if let Some(ref file_extension) = transcode_config.file_extension { - if file_extension != &output_file.extension { - panic!( - concat!( - "{} is not the recommended ", - "extension for specified transcode config ", - "please change it to {} ", - "or run with --ignore-extension" - ), - output_file.extension, file_extension - ); - } - } - } + if !transcode_args.ignore_extension { + if let Some(ref file_extension) = transcode_config.file_extension { + if file_extension != &output_file.extension { + panic!( + concat!( + "{} is not the recommended ", + "extension for specified transcode config ", + "please change it to {} ", + "or run with --ignore-extension" + ), + output_file.extension, file_extension + ); + } + } + } - let (tx, rx) = mpsc::channel::(); - let mut child: Option> = None; + let (tx, rx) = mpsc::channel::(); + let mut child: Option> = None; - if !transcode_args.hide_progress { - child = Some(thread::spawn(move || loop { - let progress = rx.recv(); + if !transcode_args.hide_progress { + child = Some(thread::spawn(move || loop { + let progress = rx.recv(); - if let Ok(progress_str) = progress { - println!("Transcode Progress: {}", progress_str); - } else { - break; - } - })); - } + if let Ok(progress_str) = progress { + println!("Transcode Progress: {}", progress_str); + } else { + break; + } + })); + } - transcode( - input_file, - transcode_args.dest.clone(), - &transcode_config, - match transcode_args.hide_progress { - true => None, - false => Some(tx), - }, - )?; + transcode( + input_file, + transcode_args.dest.clone(), + &transcode_config, + match transcode_args.hide_progress { + true => None, + false => Some(tx), + }, + )?; - if let Some(child) = child { - child.join().expect("oops! the child thread panicked"); - } + if let Some(child) = child { + child.join().expect("oops! the child thread panicked"); + } - println!("Transcode Finished"); + println!("Transcode Finished"); - Ok(()) + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 3181006..89762da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,28 +15,28 @@ use commands::set_tags::set_tags_command; use commands::transcode::transcode_command; fn main() -> Result<(), Box> { - let cli = CLIArgs::parse(); + let cli = CLIArgs::parse(); - let command = cli.command.to_owned(); + let command = cli.command.to_owned(); - match command { - Commands::Process(process_args) => { - return process_command(cli, &process_args); - } - Commands::Genhtml(genhtml_args) => { - return genhtml_command(cli, &genhtml_args); - } - Commands::Transcode(transcode_args) => { - return transcode_command(cli, &transcode_args); - } - Commands::Copy(copy_args) => { - return copy_command(cli, ©_args); - } - Commands::SetTags(set_tags_args) => { - return set_tags_command(cli, &set_tags_args); - } - Commands::GetTags(get_tags_args) => { - return get_tags_command(cli, &get_tags_args); - } - } + match command { + Commands::Process(process_args) => { + return process_command(cli, &process_args); + } + Commands::Genhtml(genhtml_args) => { + return genhtml_command(cli, &genhtml_args); + } + Commands::Transcode(transcode_args) => { + return transcode_command(cli, &transcode_args); + } + Commands::Copy(copy_args) => { + return copy_command(cli, ©_args); + } + Commands::SetTags(set_tags_args) => { + return set_tags_command(cli, &set_tags_args); + } + Commands::GetTags(get_tags_args) => { + return get_tags_command(cli, &get_tags_args); + } + } } diff --git a/src/types.rs b/src/types.rs index 9135a45..4659c8f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -4,115 +4,115 @@ use crate::utils::format_detection::FileFormat; #[derive(Debug, Clone)] pub struct Tags { - pub title: String, - pub artist: String, + pub title: String, + pub artist: String, } impl Default for Tags { - fn default() -> Self { - Tags { - title: "".to_string(), - artist: "".to_string(), - } - } + fn default() -> Self { + Tags { + title: "".to_string(), + artist: "".to_string(), + } + } } #[derive(Debug, Clone)] pub struct ReplayGainData { - pub track_gain: String, - pub track_peak: String, + pub track_gain: String, + pub track_peak: String, } #[derive(Debug, Clone)] pub struct ReplayGainRawData { - pub track_gain: f64, - pub track_peak: f64, + pub track_gain: f64, + pub track_peak: f64, } impl ReplayGainRawData { - pub fn to_normal(&self, is_ogg_opus: bool) -> ReplayGainData { - if is_ogg_opus { - ReplayGainData { - track_gain: format!("{:.6}", (self.track_gain * 256.0).ceil()), - track_peak: "".to_string(), // Not Required - } - } else { - ReplayGainData { - track_gain: format!("{:.2} dB", self.track_gain), - track_peak: format!("{:.6}", self.track_peak), - } - } - } + pub fn to_normal(&self, is_ogg_opus: bool) -> ReplayGainData { + if is_ogg_opus { + ReplayGainData { + track_gain: format!("{:.6}", (self.track_gain * 256.0).ceil()), + track_peak: "".to_string(), // Not Required + } + } else { + ReplayGainData { + track_gain: format!("{:.2} dB", self.track_gain), + track_peak: format!("{:.6}", self.track_peak), + } + } + } } #[derive(Default, Debug, Clone)] pub struct AudioFileInfo { - pub tags: Tags, - pub contains_replaygain: bool, - pub supports_replaygain: bool, - pub format: Option, + pub tags: Tags, + pub contains_replaygain: bool, + pub supports_replaygain: bool, + pub format: Option, } #[derive(Debug, Clone)] pub struct File { - pub filename: String, - pub extension: String, + pub filename: String, + pub extension: String, - // relative path to file's folder - pub path_to: PathBuf, - // path to folder from source - pub path_from_source: PathBuf, + // relative path to file's folder + pub path_to: PathBuf, + // path to folder from source + pub path_from_source: PathBuf, - pub extra_files: Vec, + pub extra_files: Vec, - pub info: AudioFileInfo, + pub info: AudioFileInfo, } impl File { - pub fn from_path(source_dir: String, full_path: PathBuf) -> File { - let full_file_path = PathBuf::from(&source_dir).join(full_path); + pub fn from_path(source_dir: String, full_path: PathBuf) -> File { + let full_file_path = PathBuf::from(&source_dir).join(full_path); - let filename_without_extension = full_file_path - .file_stem() - .expect("filename invalid") - .to_string_lossy() - .to_string(); + let filename_without_extension = full_file_path + .file_stem() + .expect("filename invalid") + .to_string_lossy() + .to_string(); - let extension = full_file_path.extension(); + let extension = full_file_path.extension(); - let extension = if let Some(extension) = extension { - extension.to_string_lossy().to_string() - } else { - "".to_string() - }; + let extension = if let Some(extension) = extension { + extension.to_string_lossy().to_string() + } else { + "".to_string() + }; - let path_from_src = full_file_path - .strip_prefix(&source_dir) - .expect("couldn't get path relative to source"); + let path_from_src = full_file_path + .strip_prefix(&source_dir) + .expect("couldn't get path relative to source"); - let mut folder_path_from_src = path_from_src.to_path_buf(); - folder_path_from_src.pop(); + let mut folder_path_from_src = path_from_src.to_path_buf(); + folder_path_from_src.pop(); - let path_to = PathBuf::from(&source_dir).join(&folder_path_from_src); + let path_to = PathBuf::from(&source_dir).join(&folder_path_from_src); - File { - filename: filename_without_extension, - extension, - path_from_source: folder_path_from_src, - path_to, - extra_files: Vec::new(), - info: AudioFileInfo::default(), - } - } + File { + filename: filename_without_extension, + extension, + path_from_source: folder_path_from_src, + path_to, + extra_files: Vec::new(), + info: AudioFileInfo::default(), + } + } - pub fn join_filename(&self) -> String { - format!("{}.{}", self.filename, self.extension) - } - pub fn join_path_to(&self) -> PathBuf { - PathBuf::from(&self.path_to).join(self.join_filename()) - } - pub fn join_path_from_source(&self) -> PathBuf { - PathBuf::from(&self.path_from_source).join(self.join_filename()) - } + pub fn join_filename(&self) -> String { + format!("{}.{}", self.filename, self.extension) + } + pub fn join_path_to(&self) -> PathBuf { + PathBuf::from(&self.path_to).join(self.join_filename()) + } + pub fn join_path_from_source(&self) -> PathBuf { + PathBuf::from(&self.path_from_source).join(self.join_filename()) + } } diff --git a/src/utils/ascii_reduce/mod.rs b/src/utils/ascii_reduce/mod.rs index 24ddc6d..451c4d9 100644 --- a/src/utils/ascii_reduce/mod.rs +++ b/src/utils/ascii_reduce/mod.rs @@ -4,47 +4,47 @@ use std::collections::HashMap; const MAPPINGS_DATA: &str = include_str!("mappings.json"); lazy_static! { - static ref MAPPINGS: HashMap = { - let data: HashMap = - serde_json::from_str(MAPPINGS_DATA).expect("mapping data invalid"); + static ref MAPPINGS: HashMap = { + let data: HashMap = + serde_json::from_str(MAPPINGS_DATA).expect("mapping data invalid"); - let mut replacement_map: HashMap = HashMap::new(); - for (chr, repl) in &data { - match chr.parse::() { - Ok(n) => { - let b = char::from_u32(n).expect("invalid char in string"); + let mut replacement_map: HashMap = HashMap::new(); + for (chr, repl) in &data { + match chr.parse::() { + Ok(n) => { + let b = char::from_u32(n).expect("invalid char in string"); - replacement_map.insert(b, repl.to_string()); - } - Err(e) => { - panic!( - "mapping data broken, could not parse char {} with error {}", - chr, e - ); - } - } - } + replacement_map.insert(b, repl.to_string()); + } + Err(e) => { + panic!( + "mapping data broken, could not parse char {} with error {}", + chr, e + ); + } + } + } - replacement_map - }; + replacement_map + }; } pub fn reduce_to_ascii(input: String) -> String { - if input.is_ascii() { - return input; - } + if input.is_ascii() { + return input; + } - let mut output = String::with_capacity(input.len()); - for c in input.chars() { - if c.is_ascii() { - output.push(c); - continue; - } + let mut output = String::with_capacity(input.len()); + for c in input.chars() { + if c.is_ascii() { + output.push(c); + continue; + } - if let Some(replacement) = MAPPINGS.get(&c) { - output.push_str(replacement); - } - } + if let Some(replacement) = MAPPINGS.get(&c) { + output.push_str(replacement); + } + } - output + output } diff --git a/src/utils/ffprobe/errors.rs b/src/utils/ffprobe/errors.rs index 372a079..c4f08b6 100644 --- a/src/utils/ffprobe/errors.rs +++ b/src/utils/ffprobe/errors.rs @@ -2,34 +2,34 @@ use std::{fmt, io, process}; #[derive(Debug)] pub enum AnalyzeError { - FFProbeError(FFProbeError), - IOError(io::Error), - ParseError(serde_json::Error), + FFProbeError(FFProbeError), + IOError(io::Error), + ParseError(serde_json::Error), } impl fmt::Display for AnalyzeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - AnalyzeError::FFProbeError(err) => write!(f, "{}", err), - AnalyzeError::IOError(err) => write!(f, "{}", err), - AnalyzeError::ParseError(err) => write!(f, "{}", err), - } - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AnalyzeError::FFProbeError(err) => write!(f, "{}", err), + AnalyzeError::IOError(err) => write!(f, "{}", err), + AnalyzeError::ParseError(err) => write!(f, "{}", err), + } + } } #[derive(Debug, Clone)] pub struct FFProbeError { - pub exit_status: process::ExitStatus, - pub stderr: String, + pub exit_status: process::ExitStatus, + pub stderr: String, } impl fmt::Display for FFProbeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "ffprobe exited with error code {}, stderr: {}", - self.exit_status.code().unwrap(), - self.stderr - ) - } -} \ No newline at end of file + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "ffprobe exited with error code {}, stderr: {}", + self.exit_status.code().unwrap(), + self.stderr + ) + } +} diff --git a/src/utils/ffprobe/ffprobe_output.rs b/src/utils/ffprobe/ffprobe_output.rs index 19541c7..9f5c6de 100644 --- a/src/utils/ffprobe/ffprobe_output.rs +++ b/src/utils/ffprobe/ffprobe_output.rs @@ -2,34 +2,34 @@ use serde::Deserialize; #[derive(Debug, Clone, Deserialize)] pub struct FFProbeOutput { - pub format: FFProbeOutputFormat, + pub format: FFProbeOutputFormat, } #[derive(Debug, Clone, Deserialize)] pub struct FFProbeOutputFormat { - pub tags: FFProbeOutputTags, + pub tags: FFProbeOutputTags, } #[derive(Debug, Clone, Deserialize)] pub struct FFProbeOutputTags { - #[serde(alias = "TITLE")] - pub title: String, - #[serde(default, alias = "ARTIST")] - pub artist: String, + #[serde(alias = "TITLE")] + pub title: String, + #[serde(default, alias = "ARTIST")] + pub artist: String, - #[serde(default, alias = "REPLAYGAIN_TRACK_PEAK")] - pub replaygain_track_peak: Option, - #[serde(default, alias = "REPLAYGAIN_TRACK_GAIN")] - pub replaygain_track_gain: Option, + #[serde(default, alias = "REPLAYGAIN_TRACK_PEAK")] + pub replaygain_track_peak: Option, + #[serde(default, alias = "REPLAYGAIN_TRACK_GAIN")] + pub replaygain_track_gain: Option, } impl Default for FFProbeOutputTags { - fn default() -> Self { - FFProbeOutputTags { - title: "".to_string(), - artist: "".to_string(), - replaygain_track_peak: None, - replaygain_track_gain: None, - } - } -} \ No newline at end of file + fn default() -> Self { + FFProbeOutputTags { + title: "".to_string(), + artist: "".to_string(), + replaygain_track_peak: None, + replaygain_track_gain: None, + } + } +} diff --git a/src/utils/ffprobe/mod.rs b/src/utils/ffprobe/mod.rs index 27a47fd..52cea90 100644 --- a/src/utils/ffprobe/mod.rs +++ b/src/utils/ffprobe/mod.rs @@ -1,47 +1,43 @@ -mod ffprobe_output; pub mod errors; +mod ffprobe_output; pub mod types; -use std::{ - convert::Into, - path::Path, - process::Command, -}; +use std::{convert::Into, path::Path, process::Command}; use self::errors::{AnalyzeError, FFProbeError}; pub fn analyze(path: &Path) -> Result { - let output = Command::new(crate::meta::FFPROBE) - .args([ - "-v", - "quiet", - "-print_format", - "json", - "-show_format", - path.to_str().unwrap(), - ]) - .output(); + let output = Command::new(crate::meta::FFPROBE) + .args([ + "-v", + "quiet", + "-print_format", + "json", + "-show_format", + path.to_str().unwrap(), + ]) + .output(); - if let Err(err) = output { - return Err(AnalyzeError::IOError(err)); - } + if let Err(err) = output { + return Err(AnalyzeError::IOError(err)); + } - let output = output.unwrap(); + let output = output.unwrap(); - if !output.status.success() { - return Err(AnalyzeError::FFProbeError(FFProbeError { - exit_status: output.status, - stderr: String::from_utf8(output.stderr).unwrap(), - })); - } + if !output.status.success() { + return Err(AnalyzeError::FFProbeError(FFProbeError { + exit_status: output.status, + stderr: String::from_utf8(output.stderr).unwrap(), + })); + } - let output = String::from_utf8(output.stdout).unwrap(); - let ffprobe_out: serde_json::Result = - serde_json::from_str(output.as_str()); + let output = String::from_utf8(output.stdout).unwrap(); + let ffprobe_out: serde_json::Result = + serde_json::from_str(output.as_str()); - let ffprobe_out = ffprobe_out.unwrap(); + let ffprobe_out = ffprobe_out.unwrap(); - Ok(types::FFProbeData { - tags: ffprobe_out.format.tags.into(), - }) + Ok(types::FFProbeData { + tags: ffprobe_out.format.tags.into(), + }) } diff --git a/src/utils/ffprobe/types.rs b/src/utils/ffprobe/types.rs index 7597551..2b81c3d 100644 --- a/src/utils/ffprobe/types.rs +++ b/src/utils/ffprobe/types.rs @@ -4,24 +4,24 @@ use super::ffprobe_output; #[derive(Debug, Clone, Serialize)] pub struct FFProbeTags { - pub title: String, - pub artist: String, - pub replaygain_track_peak: Option, - pub replaygain_track_gain: Option, + pub title: String, + pub artist: String, + pub replaygain_track_peak: Option, + pub replaygain_track_gain: Option, } impl From for FFProbeTags { - fn from(val: ffprobe_output::FFProbeOutputTags) -> Self { - FFProbeTags { - title: val.title, - artist: val.artist, - replaygain_track_peak: val.replaygain_track_peak, - replaygain_track_gain: val.replaygain_track_gain, - } - } + fn from(val: ffprobe_output::FFProbeOutputTags) -> Self { + FFProbeTags { + title: val.title, + artist: val.artist, + replaygain_track_peak: val.replaygain_track_peak, + replaygain_track_gain: val.replaygain_track_gain, + } + } } #[derive(Debug, Clone, Serialize)] pub struct FFProbeData { - pub tags: FFProbeTags, -} \ No newline at end of file + pub tags: FFProbeTags, +} diff --git a/src/utils/format_detection.rs b/src/utils/format_detection.rs index e474aed..5c8b10e 100644 --- a/src/utils/format_detection.rs +++ b/src/utils/format_detection.rs @@ -4,126 +4,126 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum FormatDetectionError { - #[error("could not read file")] - FileReadError, - #[error("file format unrecognised")] - UnrecognisedFormat, + #[error("could not read file")] + FileReadError, + #[error("file format unrecognised")] + UnrecognisedFormat, } #[derive(Clone, Copy, Debug, PartialEq)] pub enum FileFormat { - FLAC, - MP3, - OggVorbis, - OggOpus, - OggFLAC, - OggSpeex, - OggTheora, - AIFF, - Wav, - WavPack, + FLAC, + MP3, + OggVorbis, + OggOpus, + OggFLAC, + OggSpeex, + OggTheora, + AIFF, + Wav, + WavPack, } impl ToString for FileFormat { - fn to_string(&self) -> String { - match self { - FileFormat::FLAC => "FLAC".to_string(), - FileFormat::MP3 => "MP3".to_string(), - FileFormat::OggVorbis => "Ogg (Vorbis)".to_string(), - FileFormat::OggOpus => "Ogg (Opus)".to_string(), - FileFormat::OggFLAC => "Ogg (FLAC)".to_string(), - FileFormat::OggSpeex => "Ogg (Speex)".to_string(), - FileFormat::OggTheora => "Ogg (Theora)".to_string(), - FileFormat::AIFF => "AIFF".to_string(), - FileFormat::Wav => "Wav".to_string(), - FileFormat::WavPack => "WavPack".to_string(), - } - } + fn to_string(&self) -> String { + match self { + FileFormat::FLAC => "FLAC".to_string(), + FileFormat::MP3 => "MP3".to_string(), + FileFormat::OggVorbis => "Ogg (Vorbis)".to_string(), + FileFormat::OggOpus => "Ogg (Opus)".to_string(), + FileFormat::OggFLAC => "Ogg (FLAC)".to_string(), + FileFormat::OggSpeex => "Ogg (Speex)".to_string(), + FileFormat::OggTheora => "Ogg (Theora)".to_string(), + FileFormat::AIFF => "AIFF".to_string(), + FileFormat::Wav => "Wav".to_string(), + FileFormat::WavPack => "WavPack".to_string(), + } + } } pub fn detect_ogg_subformat(path: &Path) -> Result { - let file = File::open(path); + let file = File::open(path); - if let Err(_error) = file { - return Err(FormatDetectionError::FileReadError); - } + if let Err(_error) = file { + return Err(FormatDetectionError::FileReadError); + } - let file = file.unwrap(); + let file = file.unwrap(); - let limit = file - .metadata() - .map(|m| std::cmp::min(m.len(), 128) as usize + 1) - .unwrap_or(0); + let limit = file + .metadata() + .map(|m| std::cmp::min(m.len(), 128) as usize + 1) + .unwrap_or(0); - let mut bytes = Vec::with_capacity(limit); - if let Err(_err) = file.take(128).read_to_end(&mut bytes) { - return Err(FormatDetectionError::FileReadError); - } + let mut bytes = Vec::with_capacity(limit); + if let Err(_err) = file.take(128).read_to_end(&mut bytes) { + return Err(FormatDetectionError::FileReadError); + } - let mut mem = Bytes::from(bytes); - mem.advance(28); + let mut mem = Bytes::from(bytes); + mem.advance(28); - let vorbis_type = mem.get_u8(); + let vorbis_type = mem.get_u8(); - match vorbis_type { - 0x01 => return Ok(FileFormat::OggVorbis), - 0x7f => return Ok(FileFormat::OggFLAC), - 0x80 => return Ok(FileFormat::OggTheora), - // S for speex - 0x53 => return Ok(FileFormat::OggSpeex), - _ => {} - } + match vorbis_type { + 0x01 => return Ok(FileFormat::OggVorbis), + 0x7f => return Ok(FileFormat::OggFLAC), + 0x80 => return Ok(FileFormat::OggTheora), + // S for speex + 0x53 => return Ok(FileFormat::OggSpeex), + _ => {} + } - Err(FormatDetectionError::UnrecognisedFormat) + Err(FormatDetectionError::UnrecognisedFormat) } fn wavpack_matcher(buf: &[u8]) -> bool { - // 77 76 70 6b - buf.len() >= 4 && buf[0] == 0x77 && buf[1] == 0x76 && buf[2] == 0x70 && buf[3] == 0x6b + // 77 76 70 6b + buf.len() >= 4 && buf[0] == 0x77 && buf[1] == 0x76 && buf[2] == 0x70 && buf[3] == 0x6b } pub fn detect_format(path: &Path) -> Result { - let mut info = infer::Infer::new(); - info.add("custom/wavpack", "wv", wavpack_matcher); + let mut info = infer::Infer::new(); + info.add("custom/wavpack", "wv", wavpack_matcher); - let kind = info.get_from_path(path); + let kind = info.get_from_path(path); - if let Err(_error) = kind { - return Err(FormatDetectionError::FileReadError); - } + if let Err(_error) = kind { + return Err(FormatDetectionError::FileReadError); + } - let kind = kind.unwrap(); + let kind = kind.unwrap(); - if kind.is_none() { - return Err(FormatDetectionError::UnrecognisedFormat); - } + if kind.is_none() { + return Err(FormatDetectionError::UnrecognisedFormat); + } - let kind = kind.unwrap(); + let kind = kind.unwrap(); - match kind.mime_type() { - "audio/mpeg" => { - return Ok(FileFormat::MP3); - } - "audio/x-wav" => { - return Ok(FileFormat::Wav); - } - "custom/wavpack" => { - return Ok(FileFormat::WavPack); - } - "audio/ogg" => { - return detect_ogg_subformat(path); - } - "audio/x-flac" => { - return Ok(FileFormat::FLAC); - } - "audio/x-aiff" => { - return Ok(FileFormat::AIFF); - } - "audio/opus" => { - return Ok(FileFormat::OggOpus); - } - _ => {} - } + match kind.mime_type() { + "audio/mpeg" => { + return Ok(FileFormat::MP3); + } + "audio/x-wav" => { + return Ok(FileFormat::Wav); + } + "custom/wavpack" => { + return Ok(FileFormat::WavPack); + } + "audio/ogg" => { + return detect_ogg_subformat(path); + } + "audio/x-flac" => { + return Ok(FileFormat::FLAC); + } + "audio/x-aiff" => { + return Ok(FileFormat::AIFF); + } + "audio/opus" => { + return Ok(FileFormat::OggOpus); + } + _ => {} + } - Err(FormatDetectionError::UnrecognisedFormat) + Err(FormatDetectionError::UnrecognisedFormat) } diff --git a/src/utils/formats/handlers/ffprobe.rs b/src/utils/formats/handlers/ffprobe.rs index 0eea72e..0f70ab1 100644 --- a/src/utils/formats/handlers/ffprobe.rs +++ b/src/utils/formats/handlers/ffprobe.rs @@ -1,189 +1,189 @@ use std::{ - path::{Path, PathBuf}, - process::Command, + path::{Path, PathBuf}, + process::Command, }; use string_error::into_err; use crate::{ - types::{AudioFileInfo, ReplayGainData, ReplayGainRawData, Tags}, - utils::formats::{AudioFormatError, BoxedError, FormatHandler}, - utils::{ - ffprobe, - format_detection::{detect_format, FileFormat}, - }, + types::{AudioFileInfo, ReplayGainData, ReplayGainRawData, Tags}, + utils::formats::{AudioFormatError, BoxedError, FormatHandler}, + utils::{ + ffprobe, + format_detection::{detect_format, FileFormat}, + }, }; #[derive(Default)] struct Changes { - title: Option, - artist: Option, + title: Option, + artist: Option, } #[derive(Default)] struct ExtractedData { - tags: Tags, - replaygain_data: Option, + tags: Tags, + replaygain_data: Option, } pub struct GenericFFMpegAudioFormat { - file_format: FileFormat, - path: Box, + file_format: FileFormat, + path: Box, - extracted_data: ExtractedData, - changes: Changes, + extracted_data: ExtractedData, + changes: Changes, } impl GenericFFMpegAudioFormat { - fn analyze(&mut self) -> Result<(), BoxedError> { - let output = ffprobe::analyze(&self.path); + fn analyze(&mut self) -> Result<(), BoxedError> { + let output = ffprobe::analyze(&self.path); - if let Err(err) = output { - return Err(into_err(format!("{}", err))); - } + if let Err(err) = output { + return Err(into_err(format!("{}", err))); + } - let output = output.unwrap(); + let output = output.unwrap(); - self.extracted_data.tags = Tags { - title: output.tags.title, - artist: output.tags.artist, - }; + self.extracted_data.tags = Tags { + title: output.tags.title, + artist: output.tags.artist, + }; - if output.tags.replaygain_track_gain.is_some() - && output.tags.replaygain_track_peak.is_some() - { - self.extracted_data.replaygain_data = Some(ReplayGainData { - track_gain: output.tags.replaygain_track_gain.unwrap(), - track_peak: output.tags.replaygain_track_peak.unwrap(), - }); - } else { - self.extracted_data.replaygain_data = None; - } + if output.tags.replaygain_track_gain.is_some() + && output.tags.replaygain_track_peak.is_some() + { + self.extracted_data.replaygain_data = Some(ReplayGainData { + track_gain: output.tags.replaygain_track_gain.unwrap(), + track_peak: output.tags.replaygain_track_peak.unwrap(), + }); + } else { + self.extracted_data.replaygain_data = None; + } - Ok(()) - } + Ok(()) + } } impl FormatHandler for GenericFFMpegAudioFormat { - fn get_tags(&self, allow_missing: bool) -> Result { - let mut tags = self.extracted_data.tags.clone(); + fn get_tags(&self, allow_missing: bool) -> Result { + let mut tags = self.extracted_data.tags.clone(); - if let Some(title) = &self.changes.title { - tags.title = title.clone(); - } + if let Some(title) = &self.changes.title { + tags.title = title.clone(); + } - if let Some(artist) = &self.changes.title { - tags.artist = artist.clone(); - } + if let Some(artist) = &self.changes.title { + tags.artist = artist.clone(); + } - if !allow_missing { - if tags.title.is_empty() { - return Err(Box::new(AudioFormatError::MissingTitle)); - } - if tags.artist.is_empty() { - return Err(Box::new(AudioFormatError::MissingArtist)); - } - } + if !allow_missing { + if tags.title.is_empty() { + return Err(Box::new(AudioFormatError::MissingTitle)); + } + if tags.artist.is_empty() { + return Err(Box::new(AudioFormatError::MissingArtist)); + } + } - Ok(tags) - } + Ok(tags) + } - fn contains_replaygain_tags(&self) -> bool { - false - } + fn contains_replaygain_tags(&self) -> bool { + false + } - fn supports_replaygain(&self) -> bool { - false - } + fn supports_replaygain(&self) -> bool { + false + } - fn set_title(&mut self, title: String) -> Result<(), BoxedError> { - self.changes.title = Some(title); - Ok(()) - } + fn set_title(&mut self, title: String) -> Result<(), BoxedError> { + self.changes.title = Some(title); + Ok(()) + } - fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { - self.changes.artist = Some(artist); - Ok(()) - } + fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { + self.changes.artist = Some(artist); + Ok(()) + } - fn set_replaygain_data(&mut self, _data: ReplayGainRawData) -> Result<(), BoxedError> { - panic!("ffprobe doesn't support setting replaygain data, check supports_replaygain() f") - } + fn set_replaygain_data(&mut self, _data: ReplayGainRawData) -> Result<(), BoxedError> { + panic!("ffprobe doesn't support setting replaygain data, check supports_replaygain() f") + } - fn save_changes(&mut self) -> Result<(), BoxedError> { - if self.changes.title.is_none() && self.changes.artist.is_none() { - return Ok(()); - } + fn save_changes(&mut self) -> Result<(), BoxedError> { + if self.changes.title.is_none() && self.changes.artist.is_none() { + return Ok(()); + } - let mut args: Vec = Vec::new(); + let mut args: Vec = Vec::new(); - let tempdir = tempfile::tempdir()?; - let temp_file = tempdir - .path() - .join(PathBuf::from(self.path.file_name().unwrap())); + let tempdir = tempfile::tempdir()?; + let temp_file = tempdir + .path() + .join(PathBuf::from(self.path.file_name().unwrap())); - args.extend(vec![ - "-i".to_string(), - self.path.to_string_lossy().to_string(), - ]); + args.extend(vec![ + "-i".to_string(), + self.path.to_string_lossy().to_string(), + ]); - args.extend(vec!["-c".to_string(), "copy".to_string()]); + args.extend(vec!["-c".to_string(), "copy".to_string()]); - if let Some(title) = &self.changes.title { - args.extend(vec![ - "-metadata".to_string(), - format!("title=\"{}\"", title.as_str()), - ]) - } + if let Some(title) = &self.changes.title { + args.extend(vec![ + "-metadata".to_string(), + format!("title=\"{}\"", title.as_str()), + ]) + } - if let Some(artist) = &self.changes.artist { - args.extend(vec![ - "-metadata".to_string(), - format!("artist={}", artist.as_str()), - ]) - } + if let Some(artist) = &self.changes.artist { + args.extend(vec![ + "-metadata".to_string(), + format!("artist={}", artist.as_str()), + ]) + } - args.push(temp_file.to_string_lossy().to_string()); + args.push(temp_file.to_string_lossy().to_string()); - let output = Command::new(crate::meta::FFMPEG).args(args).output()?; + let output = Command::new(crate::meta::FFMPEG).args(args).output()?; - println!("{:?}", String::from_utf8(output.stderr)); + println!("{:?}", String::from_utf8(output.stderr)); - std::fs::copy(temp_file, self.path.to_path_buf())?; + std::fs::copy(temp_file, self.path.to_path_buf())?; - Ok(()) - } + Ok(()) + } - fn get_audio_file_info( - &mut self, - allow_missing_tags: bool, - ) -> Result { - Ok(AudioFileInfo { - tags: self.get_tags(allow_missing_tags)?, - contains_replaygain: self.contains_replaygain_tags(), - supports_replaygain: self.supports_replaygain(), - format: Some(self.file_format), - }) - } + fn get_audio_file_info( + &mut self, + allow_missing_tags: bool, + ) -> Result { + Ok(AudioFileInfo { + tags: self.get_tags(allow_missing_tags)?, + contains_replaygain: self.contains_replaygain_tags(), + supports_replaygain: self.supports_replaygain(), + format: Some(self.file_format), + }) + } } pub fn new_handler( - path: &Path, - file_format: Option, + path: &Path, + file_format: Option, ) -> Result { - let mut file_format = file_format; - if file_format.is_none() { - file_format = Some(detect_format(path)?); - } + let mut file_format = file_format; + if file_format.is_none() { + file_format = Some(detect_format(path)?); + } - let mut handler = GenericFFMpegAudioFormat { - file_format: file_format.unwrap(), - path: Box::new(path.to_path_buf()), - extracted_data: ExtractedData::default(), - changes: Changes::default(), - }; + let mut handler = GenericFFMpegAudioFormat { + file_format: file_format.unwrap(), + path: Box::new(path.to_path_buf()), + extracted_data: ExtractedData::default(), + changes: Changes::default(), + }; - handler.analyze()?; + handler.analyze()?; - Ok(handler) + Ok(handler) } diff --git a/src/utils/formats/handlers/flac.rs b/src/utils/formats/handlers/flac.rs index 6079300..64f49b2 100644 --- a/src/utils/formats/handlers/flac.rs +++ b/src/utils/formats/handlers/flac.rs @@ -1,115 +1,114 @@ use std::path::PathBuf; use crate::{ - types::{AudioFileInfo, ReplayGainRawData, Tags}, - utils::format_detection::FileFormat, - utils::formats::{FormatHandler, AudioFormatError, BoxedError} + types::{AudioFileInfo, ReplayGainRawData, Tags}, + utils::format_detection::FileFormat, + utils::formats::{AudioFormatError, BoxedError, FormatHandler}, }; - pub struct FLACAudioFormat { - flac_tags: metaflac::Tag, - path: Box, + flac_tags: metaflac::Tag, + path: Box, } fn flac_get_first(tag: &metaflac::Tag, key: &str) -> Option { - if let Some(Some(v)) = tag.vorbis_comments().map(|c| c.get(key)) { - if !v.is_empty() { - Some(v[0].to_string()) - } else { - None - } - } else { - None - } + if let Some(Some(v)) = tag.vorbis_comments().map(|c| c.get(key)) { + if !v.is_empty() { + Some(v[0].to_string()) + } else { + None + } + } else { + None + } } impl FormatHandler for FLACAudioFormat { - fn get_tags(&self, allow_missing: bool) -> Result { - let title = flac_get_first(&self.flac_tags, "TITLE"); - let artist = flac_get_first(&self.flac_tags, "ARTIST"); + fn get_tags(&self, allow_missing: bool) -> Result { + let title = flac_get_first(&self.flac_tags, "TITLE"); + let artist = flac_get_first(&self.flac_tags, "ARTIST"); - if !allow_missing { - if title.is_none() { - return Err(Box::new(AudioFormatError::MissingTitle)); - } - if artist.is_none() { - return Err(Box::new(AudioFormatError::MissingArtist)); - } - } + if !allow_missing { + if title.is_none() { + return Err(Box::new(AudioFormatError::MissingTitle)); + } + if artist.is_none() { + return Err(Box::new(AudioFormatError::MissingArtist)); + } + } - Ok(Tags { - title: title.unwrap(), - artist: artist.unwrap(), - }) - } + Ok(Tags { + title: title.unwrap(), + artist: artist.unwrap(), + }) + } - fn contains_replaygain_tags(&self) -> bool { - let track_gain = flac_get_first(&self.flac_tags, "REPLAYGAIN_TRACK_GAIN"); - let track_peak = flac_get_first(&self.flac_tags, "REPLAYGAIN_TRACK_PEAK"); + fn contains_replaygain_tags(&self) -> bool { + let track_gain = flac_get_first(&self.flac_tags, "REPLAYGAIN_TRACK_GAIN"); + let track_peak = flac_get_first(&self.flac_tags, "REPLAYGAIN_TRACK_PEAK"); - if track_gain.is_none() || track_peak.is_none() { - return false; - } + if track_gain.is_none() || track_peak.is_none() { + return false; + } - true - } + true + } - fn supports_replaygain(&self) -> bool { - true - } + fn supports_replaygain(&self) -> bool { + true + } - fn set_title(&mut self, title: String) -> Result<(), BoxedError> { - self.flac_tags.remove_vorbis("TITLE"); - self.flac_tags.set_vorbis("TITLE", vec![title]); + fn set_title(&mut self, title: String) -> Result<(), BoxedError> { + self.flac_tags.remove_vorbis("TITLE"); + self.flac_tags.set_vorbis("TITLE", vec![title]); - Ok(()) - } + Ok(()) + } - fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { - self.flac_tags.remove_vorbis("ARTIST"); - self.flac_tags.set_vorbis("ARTIST", vec![artist]); + fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { + self.flac_tags.remove_vorbis("ARTIST"); + self.flac_tags.set_vorbis("ARTIST", vec![artist]); - Ok(()) - } + Ok(()) + } - fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { - self.flac_tags.remove_vorbis("REPLAYGAIN_TRACK_GAIN"); - self.flac_tags.remove_vorbis("REPLAYGAIN_TRACK_PEAK"); + fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { + self.flac_tags.remove_vorbis("REPLAYGAIN_TRACK_GAIN"); + self.flac_tags.remove_vorbis("REPLAYGAIN_TRACK_PEAK"); - self.flac_tags.set_vorbis( - "REPLAYGAIN_TRACK_GAIN", - vec![format!("{:.2} dB", data.track_gain)], - ); - self.flac_tags.set_vorbis( - "REPLAYGAIN_TRACK_PEAK", - vec![format!("{:.6}", data.track_peak)], - ); + self.flac_tags.set_vorbis( + "REPLAYGAIN_TRACK_GAIN", + vec![format!("{:.2} dB", data.track_gain)], + ); + self.flac_tags.set_vorbis( + "REPLAYGAIN_TRACK_PEAK", + vec![format!("{:.6}", data.track_peak)], + ); - Ok(()) - } + Ok(()) + } - fn save_changes(&mut self) -> Result<(), BoxedError> { - self.flac_tags.write_to_path(self.path.as_path())?; - Ok(()) - } + fn save_changes(&mut self) -> Result<(), BoxedError> { + self.flac_tags.write_to_path(self.path.as_path())?; + Ok(()) + } - fn get_audio_file_info( - &mut self, - allow_missing_tags: bool, - ) -> Result { - Ok(AudioFileInfo { - tags: self.get_tags(allow_missing_tags)?, - contains_replaygain: self.contains_replaygain_tags(), - supports_replaygain: self.supports_replaygain(), - format: Some(FileFormat::FLAC), - }) - } + fn get_audio_file_info( + &mut self, + allow_missing_tags: bool, + ) -> Result { + Ok(AudioFileInfo { + tags: self.get_tags(allow_missing_tags)?, + contains_replaygain: self.contains_replaygain_tags(), + supports_replaygain: self.supports_replaygain(), + format: Some(FileFormat::FLAC), + }) + } } pub fn new_handler(path: &PathBuf) -> Result { - Ok(FLACAudioFormat { - flac_tags: metaflac::Tag::read_from_path(path)?, - path: Box::new(path.clone()), - }) + Ok(FLACAudioFormat { + flac_tags: metaflac::Tag::read_from_path(path)?, + path: Box::new(path.clone()), + }) } diff --git a/src/utils/formats/handlers/id3.rs b/src/utils/formats/handlers/id3.rs index 69a97c0..70a9a46 100644 --- a/src/utils/formats/handlers/id3.rs +++ b/src/utils/formats/handlers/id3.rs @@ -3,131 +3,131 @@ use std::path::PathBuf; use id3::TagLike; use crate::{ - types::{AudioFileInfo, ReplayGainRawData, Tags}, - utils::format_detection::FileFormat, - utils::formats::{FormatHandler, AudioFormatError, BoxedError}, + types::{AudioFileInfo, ReplayGainRawData, Tags}, + utils::format_detection::FileFormat, + utils::formats::{AudioFormatError, BoxedError, FormatHandler}, }; pub struct ID3AudioFormat { - id3_tags: id3::Tag, - path: Box, + id3_tags: id3::Tag, + path: Box, } impl FormatHandler for ID3AudioFormat { - fn get_tags(&self, allow_missing: bool) -> Result { - let title = self.id3_tags.title(); - let artist = self.id3_tags.artist(); + fn get_tags(&self, allow_missing: bool) -> Result { + let title = self.id3_tags.title(); + let artist = self.id3_tags.artist(); - if !allow_missing { - if title.is_none() { - return Err(Box::new(AudioFormatError::MissingTitle)); - } - if artist.is_none() { - return Err(Box::new(AudioFormatError::MissingArtist)); - } - } + if !allow_missing { + if title.is_none() { + return Err(Box::new(AudioFormatError::MissingTitle)); + } + if artist.is_none() { + return Err(Box::new(AudioFormatError::MissingArtist)); + } + } - Ok(Tags { - title: String::from(title.unwrap()), - artist: String::from(artist.unwrap()), - }) - } + Ok(Tags { + title: String::from(title.unwrap()), + artist: String::from(artist.unwrap()), + }) + } - fn contains_replaygain_tags(&self) -> bool { - let frames = self.id3_tags.frames(); + fn contains_replaygain_tags(&self) -> bool { + let frames = self.id3_tags.frames(); - let mut contains_replaygain_tags = false; + let mut contains_replaygain_tags = false; - for frame in frames { - if frame.id() == "TXXX" { - if let Some(extended_text) = frame.content().extended_text() { - match extended_text.description.as_str() { - "REPLAYGAIN_TRACK_GAIN" => { - contains_replaygain_tags = true; - } - "REPLAYGAIN_TRACK_PEAK" => { - contains_replaygain_tags = true; - } - _ => {} - } - } - } - } + for frame in frames { + if frame.id() == "TXXX" { + if let Some(extended_text) = frame.content().extended_text() { + match extended_text.description.as_str() { + "REPLAYGAIN_TRACK_GAIN" => { + contains_replaygain_tags = true; + } + "REPLAYGAIN_TRACK_PEAK" => { + contains_replaygain_tags = true; + } + _ => {} + } + } + } + } - contains_replaygain_tags - } + contains_replaygain_tags + } - fn supports_replaygain(&self) -> bool { - true - } + fn supports_replaygain(&self) -> bool { + true + } - fn set_title(&mut self, title: String) -> Result<(), BoxedError> { - self.id3_tags.set_title(title); + fn set_title(&mut self, title: String) -> Result<(), BoxedError> { + self.id3_tags.set_title(title); - Ok(()) - } + Ok(()) + } - fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { - self.id3_tags.set_artist(artist); + fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { + self.id3_tags.set_artist(artist); - Ok(()) - } + Ok(()) + } - fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { - let frames = self.id3_tags.remove("TXXX"); + fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { + let frames = self.id3_tags.remove("TXXX"); - for frame in frames { - if let Some(extended_text) = frame.content().extended_text() { - if extended_text.description.starts_with("REPLAYGAIN") { - continue; - } - } - self.id3_tags.add_frame(frame); - } + for frame in frames { + if let Some(extended_text) = frame.content().extended_text() { + if extended_text.description.starts_with("REPLAYGAIN") { + continue; + } + } + self.id3_tags.add_frame(frame); + } - self.id3_tags.add_frame(id3::Frame::with_content( - "TXXX", - id3::Content::ExtendedText(id3::frame::ExtendedText { - description: "REPLAYGAIN_TRACK_GAIN".to_string(), - value: format!("{:.2} dB", data.track_gain), - }), - )); + self.id3_tags.add_frame(id3::Frame::with_content( + "TXXX", + id3::Content::ExtendedText(id3::frame::ExtendedText { + description: "REPLAYGAIN_TRACK_GAIN".to_string(), + value: format!("{:.2} dB", data.track_gain), + }), + )); - self.id3_tags.add_frame(id3::Frame::with_content( - "TXXX", - id3::Content::ExtendedText(id3::frame::ExtendedText { - description: "REPLAYGAIN_TRACK_PEAK".to_string(), - value: format!("{:.6}", data.track_peak), - }), - )); + self.id3_tags.add_frame(id3::Frame::with_content( + "TXXX", + id3::Content::ExtendedText(id3::frame::ExtendedText { + description: "REPLAYGAIN_TRACK_PEAK".to_string(), + value: format!("{:.6}", data.track_peak), + }), + )); - Ok(()) - } + Ok(()) + } - fn save_changes(&mut self) -> Result<(), BoxedError> { - self.id3_tags - .write_to_path(self.path.as_path(), id3::Version::Id3v24)?; - Ok(()) - } + fn save_changes(&mut self) -> Result<(), BoxedError> { + self.id3_tags + .write_to_path(self.path.as_path(), id3::Version::Id3v24)?; + Ok(()) + } - fn get_audio_file_info( - &mut self, - allow_missing_tags: bool, - ) -> Result { - Ok(AudioFileInfo { - tags: self.get_tags(allow_missing_tags)?, - supports_replaygain: self.supports_replaygain(), - format: Some(FileFormat::MP3), - contains_replaygain: self.contains_replaygain_tags(), - }) - } + fn get_audio_file_info( + &mut self, + allow_missing_tags: bool, + ) -> Result { + Ok(AudioFileInfo { + tags: self.get_tags(allow_missing_tags)?, + supports_replaygain: self.supports_replaygain(), + format: Some(FileFormat::MP3), + contains_replaygain: self.contains_replaygain_tags(), + }) + } } pub fn new_handler(path: &PathBuf) -> Result { - let id3_tags = id3::Tag::read_from_path(path)?; + let id3_tags = id3::Tag::read_from_path(path)?; - Ok(ID3AudioFormat { - id3_tags, - path: Box::new(path.clone()), - }) + Ok(ID3AudioFormat { + id3_tags, + path: Box::new(path.clone()), + }) } diff --git a/src/utils/formats/handlers/mod.rs b/src/utils/formats/handlers/mod.rs index 6e00e44..de13f94 100644 --- a/src/utils/formats/handlers/mod.rs +++ b/src/utils/formats/handlers/mod.rs @@ -6,136 +6,134 @@ use lazy_static::lazy_static; use super::{BoxedError, FormatHandler}; -#[cfg(feature = "flac_extractor")] -mod flac; #[cfg(feature = "ffprobe_extractor")] mod ffprobe; -#[cfg(feature = "taglib_extractor")] -mod taglib; +#[cfg(feature = "flac_extractor")] +mod flac; #[cfg(feature = "mp3_extractor")] mod id3; +#[cfg(feature = "taglib_extractor")] +mod taglib; type NewHandlerFuncReturn = Result, BoxedError>; type NewHandlerFunc = fn(path: &PathBuf, file_format: Option) -> NewHandlerFuncReturn; pub struct Handler { - pub supported_extensions: Vec, - pub supported_formats: Vec, - pub new: NewHandlerFunc + pub supported_extensions: Vec, + pub supported_formats: Vec, + pub new: NewHandlerFunc, } lazy_static! { - pub static ref SUPPORTED_EXTENSIONS: Vec = { - let mut extensions: Vec = Vec::new(); - for handler in HANDLERS.iter() { - for extension in handler.supported_extensions.iter() { - if !extensions.contains(extension) { - extensions.push(extension.clone()); - } - } - } + pub static ref SUPPORTED_EXTENSIONS: Vec = { + let mut extensions: Vec = Vec::new(); + for handler in HANDLERS.iter() { + for extension in handler.supported_extensions.iter() { + if !extensions.contains(extension) { + extensions.push(extension.clone()); + } + } + } - extensions - }; + extensions + }; + pub static ref SUPPORTED_FORMATS: Vec = { + let mut formats: Vec = Vec::new(); + for handler in HANDLERS.iter() { + for format in handler.supported_formats.iter() { + if !formats.contains(format) { + formats.push(*format); + } + } + } - pub static ref SUPPORTED_FORMATS: Vec = { - let mut formats: Vec = Vec::new(); - for handler in HANDLERS.iter() { - for format in handler.supported_formats.iter() { - if !formats.contains(format) { - formats.push(*format); - } - } - } + formats + }; + pub static ref HANDLERS: Vec = { + let mut handlers: Vec = Vec::new(); - formats - }; + #[cfg(feature = "mp3_extractor")] + handlers.push(Handler { + supported_extensions: vec!["mp3".to_string()], + supported_formats: vec![FileFormat::MP3], + new: |path, _file_format| -> NewHandlerFuncReturn { + let handler = id3::new_handler(path)?; - pub static ref HANDLERS: Vec = { - let mut handlers: Vec = Vec::new(); + Ok(Box::from(handler)) + }, + }); - #[cfg(feature = "mp3_extractor")] - handlers.push(Handler { - supported_extensions: vec!["mp3".to_string()], - supported_formats: vec![FileFormat::MP3], - new: |path, _file_format| -> NewHandlerFuncReturn { - let handler = id3::new_handler(path)?; + #[cfg(feature = "flac_extractor")] + handlers.push(Handler { + supported_extensions: vec!["flac".to_string()], + supported_formats: vec![FileFormat::FLAC], + new: |path, _file_format| -> NewHandlerFuncReturn { + let handler = flac::new_handler(path)?; - Ok(Box::from(handler)) - }, - }); + Ok(Box::from(handler)) + }, + }); - #[cfg(feature = "flac_extractor")] - handlers.push(Handler { - supported_extensions: vec!["flac".to_string()], - supported_formats: vec![FileFormat::FLAC], - new: |path, _file_format| -> NewHandlerFuncReturn { - let handler = flac::new_handler(path)?; + #[cfg(feature = "taglib_extractor")] + handlers.push(Handler { + supported_extensions: vec![ + "mp3".to_string(), + "flac".to_string(), + "ogg".to_string(), + "opus".to_string(), + "wav".to_string(), + "wv".to_string(), + "aiff".to_string(), + ], + supported_formats: vec![ + FileFormat::MP3, + FileFormat::FLAC, + FileFormat::OggVorbis, + FileFormat::OggOpus, + FileFormat::OggFLAC, + FileFormat::OggSpeex, + FileFormat::OggTheora, + FileFormat::Wav, + FileFormat::WavPack, + FileFormat::AIFF, + ], + new: |path, file_format| -> NewHandlerFuncReturn { + let handler = taglib::new_handler(path, file_format)?; - Ok(Box::from(handler)) - }, - }); + Ok(Box::from(handler)) + }, + }); - #[cfg(feature = "taglib_extractor")] - handlers.push(Handler { - supported_extensions: vec![ - "mp3".to_string(), - "flac".to_string(), - "ogg".to_string(), - "opus".to_string(), - "wav".to_string(), - "wv".to_string(), - "aiff".to_string(), - ], - supported_formats: vec![ - FileFormat::MP3, - FileFormat::FLAC, - FileFormat::OggVorbis, - FileFormat::OggOpus, - FileFormat::OggFLAC, - FileFormat::OggSpeex, - FileFormat::OggTheora, - FileFormat::Wav, - FileFormat::WavPack, - FileFormat::AIFF, - ], - new: |path, file_format| -> NewHandlerFuncReturn { - let handler = taglib::new_handler(path, file_format)?; + #[cfg(feature = "ffprobe_extractor")] + handlers.push(Handler { + supported_extensions: vec![ + "mp3".to_string(), + "flac".to_string(), + "ogg".to_string(), + "opus".to_string(), + "wav".to_string(), + "wv".to_string(), + "aiff".to_string(), + ], + supported_formats: vec![ + FileFormat::MP3, + FileFormat::FLAC, + FileFormat::OggVorbis, + FileFormat::OggOpus, + FileFormat::OggFLAC, + FileFormat::OggSpeex, + FileFormat::OggTheora, + FileFormat::Wav, + FileFormat::WavPack, + FileFormat::AIFF, + ], + new: |path, file_format| -> NewHandlerFuncReturn { + let handler = ffprobe::new_handler(path, file_format)?; - Ok(Box::from(handler)) - }, - }); + Ok(Box::from(handler)) + }, + }); - #[cfg(feature = "ffprobe_extractor")] - handlers.push(Handler { - supported_extensions: vec![ - "mp3".to_string(), - "flac".to_string(), - "ogg".to_string(), - "opus".to_string(), - "wav".to_string(), - "wv".to_string(), - "aiff".to_string(), - ], - supported_formats: vec![ - FileFormat::MP3, - FileFormat::FLAC, - FileFormat::OggVorbis, - FileFormat::OggOpus, - FileFormat::OggFLAC, - FileFormat::OggSpeex, - FileFormat::OggTheora, - FileFormat::Wav, - FileFormat::WavPack, - FileFormat::AIFF, - ], - new: |path, file_format| -> NewHandlerFuncReturn { - let handler = ffprobe::new_handler(path, file_format)?; - - Ok(Box::from(handler)) - }, - }); - - handlers - }; + handlers + }; } diff --git a/src/utils/formats/handlers/taglib.rs b/src/utils/formats/handlers/taglib.rs index c794a02..14cb715 100644 --- a/src/utils/formats/handlers/taglib.rs +++ b/src/utils/formats/handlers/taglib.rs @@ -1,165 +1,163 @@ use std::path::Path; use taglib::{ - new_taglib_file, - traits::{File, Tag}, - TagLibFileType, + new_taglib_file, + traits::{File, Tag}, + TagLibFileType, }; use crate::{ - types::{AudioFileInfo, ReplayGainRawData, Tags}, - utils::format_detection::FileFormat, - utils::formats::{FormatHandler, AudioFormatError, BoxedError} + types::{AudioFileInfo, ReplayGainRawData, Tags}, + utils::format_detection::FileFormat, + utils::formats::{AudioFormatError, BoxedError, FormatHandler}, }; - pub struct TaglibAudioFormat { - file: taglib::TagLibFile, - file_format: Option, + file: taglib::TagLibFile, + file_format: Option, } impl FormatHandler for TaglibAudioFormat { - fn get_tags(&self, allow_missing: bool) -> Result { - let tags = self.file.tag()?; + fn get_tags(&self, allow_missing: bool) -> Result { + let tags = self.file.tag()?; - let mut title = tags.title(); - if title.is_none() { - if !allow_missing { - return Err(Box::new(AudioFormatError::MissingTitle)); - } else { - title = Some("".to_string()) - } - } + let mut title = tags.title(); + if title.is_none() { + if !allow_missing { + return Err(Box::new(AudioFormatError::MissingTitle)); + } else { + title = Some("".to_string()) + } + } - let mut artist = tags.artist(); - if artist.is_none() { - if !allow_missing { - return Err(Box::new(AudioFormatError::MissingArtist)); - } else { - artist = Some("".to_string()) - } - } + let mut artist = tags.artist(); + if artist.is_none() { + if !allow_missing { + return Err(Box::new(AudioFormatError::MissingArtist)); + } else { + artist = Some("".to_string()) + } + } - Ok(Tags { - title: title.unwrap(), - artist: artist.unwrap(), - }) - } + Ok(Tags { + title: title.unwrap(), + artist: artist.unwrap(), + }) + } - fn contains_replaygain_tags(&self) -> bool { - if let Some(format) = self.file_format { - if format == FileFormat::OggOpus { - let oggtag = self.file.oggtag().expect("oggtag not available?"); + fn contains_replaygain_tags(&self) -> bool { + if let Some(format) = self.file_format { + if format == FileFormat::OggOpus { + let oggtag = self.file.oggtag().expect("oggtag not available?"); - return oggtag.get_field("R128_TRACK_GAIN".to_string()).is_some(); - } - match format { - FileFormat::OggVorbis | FileFormat::OggFLAC | FileFormat::OggSpeex => { - let oggtag = self.file.oggtag().expect("oggtag not available?"); - let gain = oggtag.get_field("REPLAYGAIN_TRACK_GAIN".to_string()); - let peak = oggtag.get_field("REPLAYGAIN_TRACK_PEAK".to_string()); - return gain.is_some() && peak.is_some(); - } - _ => {} - } - } + return oggtag.get_field("R128_TRACK_GAIN".to_string()).is_some(); + } + match format { + FileFormat::OggVorbis | FileFormat::OggFLAC | FileFormat::OggSpeex => { + let oggtag = self.file.oggtag().expect("oggtag not available?"); + let gain = oggtag.get_field("REPLAYGAIN_TRACK_GAIN".to_string()); + let peak = oggtag.get_field("REPLAYGAIN_TRACK_PEAK".to_string()); + return gain.is_some() && peak.is_some(); + } + _ => {} + } + } - false - } + false + } - fn supports_replaygain(&self) -> bool { - if let Some(format) = self.file_format { - return matches!( - format, - // All Ogg formats support ReplayGain - FileFormat::OggVorbis - | FileFormat::OggOpus - | FileFormat::OggFLAC - | FileFormat::OggSpeex - // Both "support" ReplayGain but not implemented yet - // FileFormat::Wav | - // FileFormat::WavPack - ); - } + fn supports_replaygain(&self) -> bool { + if let Some(format) = self.file_format { + return matches!( + format, + // All Ogg formats support ReplayGain + FileFormat::OggVorbis + | FileFormat::OggOpus + | FileFormat::OggFLAC + | FileFormat::OggSpeex // Both "support" ReplayGain but not implemented yet + // FileFormat::Wav | + // FileFormat::WavPack + ); + } - false - } + false + } - fn set_title(&mut self, title: String) -> Result<(), BoxedError> { - let mut tags = self.file.tag()?; - tags.set_title(title); + fn set_title(&mut self, title: String) -> Result<(), BoxedError> { + let mut tags = self.file.tag()?; + tags.set_title(title); - Ok(()) - } + Ok(()) + } - fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { - let mut tags = self.file.tag()?; - tags.set_artist(artist); + fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> { + let mut tags = self.file.tag()?; + tags.set_artist(artist); - Ok(()) - } + Ok(()) + } - fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { - if let Some(format) = self.file_format { - let oggtag = self.file.oggtag().expect("oggtag not available?"); + fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> { + if let Some(format) = self.file_format { + let oggtag = self.file.oggtag().expect("oggtag not available?"); - if format == FileFormat::OggOpus { - let data = data.to_normal(true); + if format == FileFormat::OggOpus { + let data = data.to_normal(true); - oggtag.add_field("R128_TRACK_GAIN".to_string(), data.track_gain); - } else if matches!( - format, - FileFormat::OggVorbis | FileFormat::OggFLAC | FileFormat::OggSpeex - ) { - let data = data.to_normal(false); + oggtag.add_field("R128_TRACK_GAIN".to_string(), data.track_gain); + } else if matches!( + format, + FileFormat::OggVorbis | FileFormat::OggFLAC | FileFormat::OggSpeex + ) { + let data = data.to_normal(false); - oggtag.add_field("REPLAYGAIN_TRACK_GAIN".to_string(), data.track_gain); - oggtag.add_field("REPLAYGAIN_TRACK_PEAK".to_string(), data.track_peak); - } - } + oggtag.add_field("REPLAYGAIN_TRACK_GAIN".to_string(), data.track_gain); + oggtag.add_field("REPLAYGAIN_TRACK_PEAK".to_string(), data.track_peak); + } + } - Ok(()) - } + Ok(()) + } - fn save_changes(&mut self) -> Result<(), BoxedError> { - let res = self.file.save(); + fn save_changes(&mut self) -> Result<(), BoxedError> { + let res = self.file.save(); - match res { - Ok(()) => Ok(()), - Err(e) => Err(Box::new(e)), - } - } + match res { + Ok(()) => Ok(()), + Err(e) => Err(Box::new(e)), + } + } - fn get_audio_file_info( - &mut self, - allow_missing_tags: bool, - ) -> Result { - Ok(AudioFileInfo { - tags: self.get_tags(allow_missing_tags)?, - contains_replaygain: self.contains_replaygain_tags(), - supports_replaygain: self.supports_replaygain(), - format: self.file_format, - }) - } + fn get_audio_file_info( + &mut self, + allow_missing_tags: bool, + ) -> Result { + Ok(AudioFileInfo { + tags: self.get_tags(allow_missing_tags)?, + contains_replaygain: self.contains_replaygain_tags(), + supports_replaygain: self.supports_replaygain(), + format: self.file_format, + }) + } } pub fn new_handler( - path: &Path, - file_format: Option, + path: &Path, + file_format: Option, ) -> Result { - let mut taglib_format: Option = None; - if let Some(format) = file_format { - taglib_format = match format { - FileFormat::OggVorbis => Some(TagLibFileType::OggVorbis), - FileFormat::OggOpus => Some(TagLibFileType::OggOpus), - FileFormat::OggFLAC => Some(TagLibFileType::OggFLAC), - FileFormat::OggSpeex => Some(TagLibFileType::OggSpeex), - _ => None, - } - } + let mut taglib_format: Option = None; + if let Some(format) = file_format { + taglib_format = match format { + FileFormat::OggVorbis => Some(TagLibFileType::OggVorbis), + FileFormat::OggOpus => Some(TagLibFileType::OggOpus), + FileFormat::OggFLAC => Some(TagLibFileType::OggFLAC), + FileFormat::OggSpeex => Some(TagLibFileType::OggSpeex), + _ => None, + } + } - Ok(TaglibAudioFormat { - file_format, - file: new_taglib_file(path.to_string_lossy().to_string(), taglib_format)?, - }) + Ok(TaglibAudioFormat { + file_format, + file: new_taglib_file(path.to_string_lossy().to_string(), taglib_format)?, + }) } diff --git a/src/utils/formats/mod.rs b/src/utils/formats/mod.rs index ca582a6..1e7114f 100644 --- a/src/utils/formats/mod.rs +++ b/src/utils/formats/mod.rs @@ -7,80 +7,79 @@ use thiserror::Error; use crate::types::{AudioFileInfo, File, ReplayGainRawData, Tags}; - use super::format_detection::detect_format; type BoxedError = Box; pub trait FormatHandler { - fn get_tags(&self, allow_missing: bool) -> Result; - fn contains_replaygain_tags(&self) -> bool; - fn supports_replaygain(&self) -> bool; + fn get_tags(&self, allow_missing: bool) -> Result; + fn contains_replaygain_tags(&self) -> bool; + fn supports_replaygain(&self) -> bool; - fn set_title(&mut self, title: String) -> Result<(), BoxedError>; - fn set_artist(&mut self, artist: String) -> Result<(), BoxedError>; - fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError>; + fn set_title(&mut self, title: String) -> Result<(), BoxedError>; + fn set_artist(&mut self, artist: String) -> Result<(), BoxedError>; + fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError>; - fn save_changes(&mut self) -> Result<(), BoxedError>; + fn save_changes(&mut self) -> Result<(), BoxedError>; - fn get_audio_file_info( - &mut self, - allow_missing_tags: bool, - ) -> Result; + fn get_audio_file_info( + &mut self, + allow_missing_tags: bool, + ) -> Result; } #[derive(Error, Debug)] pub enum AudioFormatError { - #[error("title missing from tags")] - MissingTitle, - #[error("artist missing from tags")] - MissingArtist, + #[error("title missing from tags")] + MissingTitle, + #[error("artist missing from tags")] + MissingArtist, } pub fn get_format_handler(file: &File) -> Result, BoxedError> { - let format = detect_format(&file.join_path_to())?; - let path = file.join_path_to(); + let format = detect_format(&file.join_path_to())?; + let path = file.join_path_to(); - for handler in handlers::HANDLERS.iter() { - if !handler.supported_extensions.contains(&file.extension) { - continue - } + for handler in handlers::HANDLERS.iter() { + if !handler.supported_extensions.contains(&file.extension) { + continue; + } - if !handler.supported_formats.contains(&format) { - continue - } + if !handler.supported_formats.contains(&format) { + continue; + } - let new = handler.new; + let new = handler.new; - return new(&path, Some(format)); - } + return new(&path, Some(format)); + } - panic!("no supported handler found"); + panic!("no supported handler found"); } fn is_supported_extension(ext: &str) -> bool { - handlers::SUPPORTED_EXTENSIONS.contains(&ext.to_string()) + handlers::SUPPORTED_EXTENSIONS.contains(&ext.to_string()) } pub fn is_supported_file(file_path: &Path) -> bool { - let ext = file_path.extension(); + let ext = file_path.extension(); - if ext.is_none() { - return false; - } + if ext.is_none() { + return false; + } - let ext = ext.unwrap().to_str().unwrap(); + let ext = ext.unwrap().to_str().unwrap(); - if !is_supported_extension(ext) { - return false; - } + if !is_supported_extension(ext) { + return false; + } - let format = detect_format(file_path); - if format.is_err() { - return false; - } + let format = detect_format(file_path); + if format.is_err() { + return false; + } - let format = format.unwrap(); + let format = format.unwrap(); - handlers::SUPPORTED_FORMATS.contains(&format) + handlers::SUPPORTED_FORMATS.contains(&format) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 2461fd5..3ba47d2 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,11 +1,11 @@ pub mod ascii_reduce; +pub mod ffprobe; pub mod format_detection; pub mod replaygain; pub mod transcoder; -pub mod ffprobe; pub mod formats; - mod music_scanner; +mod music_scanner; pub use formats::is_supported_file; pub use music_scanner::scan_for_music; diff --git a/src/utils/music_scanner.rs b/src/utils/music_scanner.rs index 4480a5c..72ecce2 100644 --- a/src/utils/music_scanner.rs +++ b/src/utils/music_scanner.rs @@ -6,52 +6,52 @@ use walkdir::WalkDir; use super::is_supported_file; pub fn find_extra_files( - src_dir: String, - file: &File, + src_dir: String, + file: &File, ) -> Result, Box> { - let mut extra_files: Vec = Vec::new(); + let mut extra_files: Vec = Vec::new(); - for entry in fs::read_dir(&file.path_to)? { - let entry = entry?; - if !entry.metadata()?.is_file() { - continue; - } - let entry_path = entry.path(); + for entry in fs::read_dir(&file.path_to)? { + let entry = entry?; + if !entry.metadata()?.is_file() { + continue; + } + let entry_path = entry.path(); - let extension = entry_path.extension(); - if extension.is_none() { - continue; - } + let extension = entry_path.extension(); + if extension.is_none() { + continue; + } - if entry_path.file_stem().unwrap().to_string_lossy() == file.filename - && extension.unwrap().to_string_lossy() != file.extension - { - extra_files.push(File::from_path(src_dir.clone(), entry_path.clone())); - } - } + if entry_path.file_stem().unwrap().to_string_lossy() == file.filename + && extension.unwrap().to_string_lossy() != file.extension + { + extra_files.push(File::from_path(src_dir.clone(), entry_path.clone())); + } + } - Ok(extra_files) + Ok(extra_files) } pub fn scan_for_music(src_dir: &String) -> Result, Box> { - let mut files: Vec = Vec::new(); + let mut files: Vec = Vec::new(); - for entry in WalkDir::new(src_dir) { - let entry = entry.unwrap(); - let entry_path = entry.into_path(); - if entry_path.is_dir() { - continue; - } + for entry in WalkDir::new(src_dir) { + let entry = entry.unwrap(); + let entry_path = entry.into_path(); + if entry_path.is_dir() { + continue; + } - if is_supported_file(&entry_path) { - let mut file = File::from_path(src_dir.clone(), entry_path.clone()); + if is_supported_file(&entry_path) { + let mut file = File::from_path(src_dir.clone(), entry_path.clone()); - file.extra_files - .extend(find_extra_files(src_dir.clone(), &file)?); + file.extra_files + .extend(find_extra_files(src_dir.clone(), &file)?); - files.push(file); - } - } + files.push(file); + } + } - Ok(files) + Ok(files) } diff --git a/src/utils/replaygain/mod.rs b/src/utils/replaygain/mod.rs index 3da1f84..463b8ba 100644 --- a/src/utils/replaygain/mod.rs +++ b/src/utils/replaygain/mod.rs @@ -1,7 +1,7 @@ use std::{ - io::{BufRead, BufReader}, - path::PathBuf, - process::Command, + io::{BufRead, BufReader}, + path::PathBuf, + process::Command, }; use string_error::static_err; @@ -9,94 +9,94 @@ use string_error::static_err; use crate::types::ReplayGainRawData; pub fn analyze_replaygain(path: PathBuf) -> Result> { - let output = Command::new(crate::meta::FFMPEG) - .args([ - "-hide_banner", - "-nostats", - "-v", - "info", - "-i", - &path.to_string_lossy(), - "-filter_complex", - "[0:a]ebur128=framelog=verbose:peak=sample:dualmono=true[s6]", - "-map", - "[s6]", - "-f", - "null", - "/dev/null", - ]) - .output()?; + let output = Command::new(crate::meta::FFMPEG) + .args([ + "-hide_banner", + "-nostats", + "-v", + "info", + "-i", + &path.to_string_lossy(), + "-filter_complex", + "[0:a]ebur128=framelog=verbose:peak=sample:dualmono=true[s6]", + "-map", + "[s6]", + "-f", + "null", + "/dev/null", + ]) + .output()?; - if !output.status.success() { - print!("{:?}", String::from_utf8(output.stderr).unwrap()); - return Err(static_err("FFmpeg Crashed")); - } + if !output.status.success() { + print!("{:?}", String::from_utf8(output.stderr).unwrap()); + return Err(static_err("FFmpeg Crashed")); + } - // info we need is in stdout - let output_str = String::from_utf8(output.stderr).unwrap(); + // info we need is in stdout + let output_str = String::from_utf8(output.stderr).unwrap(); - let mut ebur128_summary = String::new(); + let mut ebur128_summary = String::new(); - // for some reason ffmpeg outputs the summary twice, - // the first time is garbage data - let mut has_seen_first_summary = false; - let mut should_start_reading_lines = false; + // for some reason ffmpeg outputs the summary twice, + // the first time is garbage data + let mut has_seen_first_summary = false; + let mut should_start_reading_lines = false; - let output_reader = BufReader::new(output_str.as_bytes()); - for line in output_reader.lines() { - if let Ok(line) = line { - if line.starts_with("[Parsed_ebur128_0") { - if has_seen_first_summary { - should_start_reading_lines = true; - ebur128_summary.push_str("Summary:\n") - } else { - has_seen_first_summary = true; - } - } else if should_start_reading_lines { - ebur128_summary.push_str(line.trim()); - ebur128_summary.push('\n') - } - } else { - break; - } - } + let output_reader = BufReader::new(output_str.as_bytes()); + for line in output_reader.lines() { + if let Ok(line) = line { + if line.starts_with("[Parsed_ebur128_0") { + if has_seen_first_summary { + should_start_reading_lines = true; + ebur128_summary.push_str("Summary:\n") + } else { + has_seen_first_summary = true; + } + } else if should_start_reading_lines { + ebur128_summary.push_str(line.trim()); + ebur128_summary.push('\n') + } + } else { + break; + } + } - let mut track_gain: f64 = 0.0; - let mut track_peak: f64 = 0.0; + let mut track_gain: f64 = 0.0; + let mut track_peak: f64 = 0.0; - let summary_reader = BufReader::new(ebur128_summary.as_bytes()); - for line in summary_reader.lines() { - if let Ok(line) = line { - if line.starts_with("I:") { - let mut l = line.split(':'); - l.next(); + let summary_reader = BufReader::new(ebur128_summary.as_bytes()); + for line in summary_reader.lines() { + if let Ok(line) = line { + if line.starts_with("I:") { + let mut l = line.split(':'); + l.next(); - let gain = l.next().unwrap().trim().trim_end_matches(" LUFS"); - let gain = gain.parse::()?; + let gain = l.next().unwrap().trim().trim_end_matches(" LUFS"); + let gain = gain.parse::()?; - // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Gain_calculation - // "In order to maintain backwards compatibility with RG1, RG2 uses a -18 LUFS reference, which based on lots of music, can give similar loudness compared to RG1." - let gain = -18_f64 - gain; + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Gain_calculation + // "In order to maintain backwards compatibility with RG1, RG2 uses a -18 LUFS reference, which based on lots of music, can give similar loudness compared to RG1." + let gain = -18_f64 - gain; - track_gain = gain; - } + track_gain = gain; + } - if line.starts_with("Peak:") { - let mut l = line.split(':'); - l.next(); + if line.starts_with("Peak:") { + let mut l = line.split(':'); + l.next(); - // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Loudness_normalization - let peak = l.next().unwrap().trim().trim_end_matches(" dBFS"); - let peak = peak.parse::()?; - let peak = f64::powf(10_f64, peak / 20.0_f64); - track_peak = peak; - } - } else { - break; - } - } - Ok(ReplayGainRawData { - track_gain, - track_peak, - }) + // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Loudness_normalization + let peak = l.next().unwrap().trim().trim_end_matches(" dBFS"); + let peak = peak.parse::()?; + let peak = f64::powf(10_f64, peak / 20.0_f64); + track_peak = peak; + } + } else { + break; + } + } + Ok(ReplayGainRawData { + track_gain, + track_peak, + }) } diff --git a/src/utils/transcoder/mod.rs b/src/utils/transcoder/mod.rs index ae1cc4a..4f91c67 100644 --- a/src/utils/transcoder/mod.rs +++ b/src/utils/transcoder/mod.rs @@ -3,5 +3,5 @@ pub mod progress_monitor; #[allow(clippy::all)] mod transcoder; pub mod types; - use self::progress_monitor::progress_monitor; +use self::progress_monitor::progress_monitor; pub use self::transcoder::transcode; diff --git a/src/utils/transcoder/presets.rs b/src/utils/transcoder/presets.rs index eb491e4..bf8849a 100644 --- a/src/utils/transcoder/presets.rs +++ b/src/utils/transcoder/presets.rs @@ -6,212 +6,212 @@ use crate::utils::transcoder::types::PresetCategory; use crate::utils::transcoder::types::TranscodeConfig; lazy_static! { - #[derive(Debug)] - pub static ref TRANSCODE_CONFIGS: Vec = { - let mut preset_categories: Vec = Vec::new(); + #[derive(Debug)] + pub static ref TRANSCODE_CONFIGS: Vec = { + let mut preset_categories: Vec = Vec::new(); - add_mp3_presets(&mut preset_categories); - add_opus_presets(&mut preset_categories); - add_vorbis_presets(&mut preset_categories); - add_g726_presets(&mut preset_categories); - add_speex_presets(&mut preset_categories); - add_flac_preset(&mut preset_categories); - add_wav_preset(&mut preset_categories); + add_mp3_presets(&mut preset_categories); + add_opus_presets(&mut preset_categories); + add_vorbis_presets(&mut preset_categories); + add_g726_presets(&mut preset_categories); + add_speex_presets(&mut preset_categories); + add_flac_preset(&mut preset_categories); + add_wav_preset(&mut preset_categories); - preset_categories - }; + preset_categories + }; } fn add_mp3_presets(preset_categories: &mut Vec) { - let mut presets: Vec = Vec::new(); - for bitrate in [ - 8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, - ] { - presets.push(Preset { - name: format!("mp3-{}k", bitrate).to_string(), - config: TranscodeConfig { - file_extension: Some("mp3".to_string()), - encoder: Some("libmp3lame".to_string()), - container: Some("mp3".to_string()), - bitrate: Some(format!("{}k", bitrate).to_string()), - ..TranscodeConfig::default() - }, - }) - } + let mut presets: Vec = Vec::new(); + for bitrate in [ + 8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, + ] { + presets.push(Preset { + name: format!("mp3-{}k", bitrate).to_string(), + config: TranscodeConfig { + file_extension: Some("mp3".to_string()), + encoder: Some("libmp3lame".to_string()), + container: Some("mp3".to_string()), + bitrate: Some(format!("{}k", bitrate).to_string()), + ..TranscodeConfig::default() + }, + }) + } - for quality in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] { - presets.push(Preset { - name: format!("mp3-v{}", quality).to_string(), - config: TranscodeConfig { - file_extension: Some("mp3".to_string()), - encoder: Some("libmp3lame".to_string()), - container: Some("mp3".to_string()), - quality: Some(format!("{}", quality).to_string()), - ..TranscodeConfig::default() - }, - }) - } + for quality in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] { + presets.push(Preset { + name: format!("mp3-v{}", quality).to_string(), + config: TranscodeConfig { + file_extension: Some("mp3".to_string()), + encoder: Some("libmp3lame".to_string()), + container: Some("mp3".to_string()), + quality: Some(format!("{}", quality).to_string()), + ..TranscodeConfig::default() + }, + }) + } - preset_categories.push(PresetCategory { - name: "mp3".to_string(), - presets, - }); + preset_categories.push(PresetCategory { + name: "mp3".to_string(), + presets, + }); } fn add_opus_presets(preset_categories: &mut Vec) { - let mut presets: Vec = Vec::new(); - for bitrate in [16, 24, 32, 64, 96, 128, 256] { - presets.push(Preset { - name: format!("opus-{}k", bitrate).to_string(), - config: TranscodeConfig { - file_extension: Some("opus".to_string()), - encoder: Some("libopus".to_string()), - container: Some("ogg".to_string()), - bitrate: Some(format!("{}k", bitrate).to_string()), - ..TranscodeConfig::default() - }, - }) - } + let mut presets: Vec = Vec::new(); + for bitrate in [16, 24, 32, 64, 96, 128, 256] { + presets.push(Preset { + name: format!("opus-{}k", bitrate).to_string(), + config: TranscodeConfig { + file_extension: Some("opus".to_string()), + encoder: Some("libopus".to_string()), + container: Some("ogg".to_string()), + bitrate: Some(format!("{}k", bitrate).to_string()), + ..TranscodeConfig::default() + }, + }) + } - preset_categories.push(PresetCategory { - name: "opus".to_string(), - presets, - }); + preset_categories.push(PresetCategory { + name: "opus".to_string(), + presets, + }); } fn add_vorbis_presets(preset_categories: &mut Vec) { - let mut presets: Vec = Vec::new(); - for quality in [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] { - presets.push(Preset { - name: format!("vorbis-v{}", quality).to_string(), - config: TranscodeConfig { - file_extension: Some("ogg".to_string()), - encoder: Some("libvorbis".to_string()), - container: Some("ogg".to_string()), - quality: Some(format!("{}", quality).to_string()), - ..TranscodeConfig::default() - }, - }) - } + let mut presets: Vec = Vec::new(); + for quality in [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] { + presets.push(Preset { + name: format!("vorbis-v{}", quality).to_string(), + config: TranscodeConfig { + file_extension: Some("ogg".to_string()), + encoder: Some("libvorbis".to_string()), + container: Some("ogg".to_string()), + quality: Some(format!("{}", quality).to_string()), + ..TranscodeConfig::default() + }, + }) + } - preset_categories.push(PresetCategory { - name: "vorbis".to_string(), - presets, - }); + preset_categories.push(PresetCategory { + name: "vorbis".to_string(), + presets, + }); } fn add_g726_presets(preset_categories: &mut Vec) { - let mut presets: Vec = Vec::new(); - for bitrate in [16, 24, 32, 64, 96, 128, 256] { - presets.push(Preset { - name: format!("g726-{}k", bitrate).to_string(), - config: TranscodeConfig { - file_extension: Some("mka".to_string()), - encoder: Some("g726".to_string()), - container: Some("matroska".to_string()), - sample_rate: Some("8000".to_string()), - channels: Some("1".to_string()), - bitrate: Some(format!("{}k", bitrate).to_string()), - ..TranscodeConfig::default() - }, - }) - } + let mut presets: Vec = Vec::new(); + for bitrate in [16, 24, 32, 64, 96, 128, 256] { + presets.push(Preset { + name: format!("g726-{}k", bitrate).to_string(), + config: TranscodeConfig { + file_extension: Some("mka".to_string()), + encoder: Some("g726".to_string()), + container: Some("matroska".to_string()), + sample_rate: Some("8000".to_string()), + channels: Some("1".to_string()), + bitrate: Some(format!("{}k", bitrate).to_string()), + ..TranscodeConfig::default() + }, + }) + } - preset_categories.push(PresetCategory { - name: "g726".to_string(), - presets, - }); + preset_categories.push(PresetCategory { + name: "g726".to_string(), + presets, + }); } fn add_speex_presets(preset_categories: &mut Vec) { - let mut presets: Vec = Vec::new(); - for quality in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] { - presets.push(Preset { - name: format!("speex-q{}", quality).to_string(), - config: TranscodeConfig { - file_extension: Some("ogg".to_string()), - encoder: Some("libspeex".to_string()), - container: Some("ogg".to_string()), - quality: Some(format!("{}", quality).to_string()), - ..TranscodeConfig::default() - }, - }) - } + let mut presets: Vec = Vec::new(); + for quality in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] { + presets.push(Preset { + name: format!("speex-q{}", quality).to_string(), + config: TranscodeConfig { + file_extension: Some("ogg".to_string()), + encoder: Some("libspeex".to_string()), + container: Some("ogg".to_string()), + quality: Some(format!("{}", quality).to_string()), + ..TranscodeConfig::default() + }, + }) + } - preset_categories.push(PresetCategory { - name: "speex".to_string(), - presets, - }); + preset_categories.push(PresetCategory { + name: "speex".to_string(), + presets, + }); } fn add_flac_preset(preset_categories: &mut Vec) { - preset_categories.push(PresetCategory { - name: "flac".to_string(), - presets: Vec::from([Preset { - name: "flac".to_string(), - config: TranscodeConfig { - encoder: Some("flac".to_string()), - container: Some("flac".to_string()), - file_extension: Some("flac".to_string()), - ..TranscodeConfig::default() - }, - }]), - }) + preset_categories.push(PresetCategory { + name: "flac".to_string(), + presets: Vec::from([Preset { + name: "flac".to_string(), + config: TranscodeConfig { + encoder: Some("flac".to_string()), + container: Some("flac".to_string()), + file_extension: Some("flac".to_string()), + ..TranscodeConfig::default() + }, + }]), + }) } fn add_wav_preset(preset_categories: &mut Vec) { - preset_categories.push(PresetCategory { - name: "wav".to_string(), - presets: Vec::from([Preset { - name: "wav".to_string(), - config: TranscodeConfig { - container: Some("wav".to_string()), - file_extension: Some("wav".to_string()), - ..TranscodeConfig::default() - }, - }]), - }) + preset_categories.push(PresetCategory { + name: "wav".to_string(), + presets: Vec::from([Preset { + name: "wav".to_string(), + config: TranscodeConfig { + container: Some("wav".to_string()), + file_extension: Some("wav".to_string()), + ..TranscodeConfig::default() + }, + }]), + }) } pub fn print_presets() { - for category in TRANSCODE_CONFIGS.iter() { - println!("Category {}:", category.name); - for preset in category.presets.iter() { - println!("- {}", preset.name) - } - } + for category in TRANSCODE_CONFIGS.iter() { + println!("Category {}:", category.name); + for preset in category.presets.iter() { + println!("- {}", preset.name) + } + } } pub fn get_preset(name: String) -> Option { - for category in TRANSCODE_CONFIGS.iter() { - for preset in category.presets.iter() { - if preset.name == name { - return Some(preset.config.clone()); - } - } - } + for category in TRANSCODE_CONFIGS.iter() { + for preset in category.presets.iter() { + if preset.name == name { + return Some(preset.config.clone()); + } + } + } - None + None } pub fn transcode_preset_or_config( - preset_name: Option<&String>, - config_path: Option<&String>, + preset_name: Option<&String>, + config_path: Option<&String>, ) -> Result> { - if let Some(preset_name) = preset_name { - let preset_config = get_preset(preset_name.to_string()); + if let Some(preset_name) = preset_name { + let preset_config = get_preset(preset_name.to_string()); - match preset_config { - Some(config) => Ok(config), - None => Err(into_err("invalid preset name".to_string())), - } - } else if let Some(config_path) = config_path { - let config = TranscodeConfig::load(config_path.to_string())?; + match preset_config { + Some(config) => Ok(config), + None => Err(into_err("invalid preset name".to_string())), + } + } else if let Some(config_path) = config_path { + let config = TranscodeConfig::load(config_path.to_string())?; - Ok(config) - } else { - Err(into_err( - "please provide a transcode config or preset".to_string(), - )) - } + Ok(config) + } else { + Err(into_err( + "please provide a transcode config or preset".to_string(), + )) + } } diff --git a/src/utils/transcoder/progress_monitor.rs b/src/utils/transcoder/progress_monitor.rs index c737a4d..6dc721e 100644 --- a/src/utils/transcoder/progress_monitor.rs +++ b/src/utils/transcoder/progress_monitor.rs @@ -1,11 +1,11 @@ use std::{ - fs, - io::{BufRead, BufReader, Seek, SeekFrom}, - path::PathBuf, - process::Command, - sync::mpsc::{self, Sender}, - thread::{self, JoinHandle}, - time::Duration, + fs, + io::{BufRead, BufReader, Seek, SeekFrom}, + path::PathBuf, + process::Command, + sync::mpsc::{self, Sender}, + thread::{self, JoinHandle}, + time::Duration, }; use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher}; @@ -14,127 +14,127 @@ use string_error::static_err; #[derive(Debug, Clone, Deserialize)] struct FFProbeOutput { - pub format: FFProbeFormat, + pub format: FFProbeFormat, } #[derive(Debug, Clone, Deserialize)] struct FFProbeFormat { - pub duration: String, + pub duration: String, } fn get_file_length_milliseconds( - source_filepath: PathBuf, + source_filepath: PathBuf, ) -> Result> { - let output = Command::new(crate::meta::FFPROBE) - .args([ - "-v", - "quiet", - "-print_format", - "json", - "-show_format", - &source_filepath.to_string_lossy(), - ]) - .output()?; + let output = Command::new(crate::meta::FFPROBE) + .args([ + "-v", + "quiet", + "-print_format", + "json", + "-show_format", + &source_filepath.to_string_lossy(), + ]) + .output()?; - if !output.status.success() { - print!("{:?}", String::from_utf8(output.stderr).unwrap()); - return Err(static_err("FFprobe Crashed")); - } + if !output.status.success() { + print!("{:?}", String::from_utf8(output.stderr).unwrap()); + return Err(static_err("FFprobe Crashed")); + } - let output_str = String::from_utf8(output.stdout).unwrap(); - let ffprobe_out: FFProbeOutput = serde_json::from_str(output_str.as_str())?; + let output_str = String::from_utf8(output.stdout).unwrap(); + let ffprobe_out: FFProbeOutput = serde_json::from_str(output_str.as_str())?; - let duration_seconds = ffprobe_out.format.duration.parse::()?; + let duration_seconds = ffprobe_out.format.duration.parse::()?; - Ok((duration_seconds * 1000.0).round() as u64) + Ok((duration_seconds * 1000.0).round() as u64) } fn ffprobe_duration_to_ms(duration: String) -> Result> { - let fields: Vec<&str> = duration.split(':').collect(); - let mut duration = Duration::from_nanos(0); + let fields: Vec<&str> = duration.split(':').collect(); + let mut duration = Duration::from_nanos(0); - let hours = fields[0].parse::()?; - duration += Duration::from_secs(hours * 60 * 60); + let hours = fields[0].parse::()?; + duration += Duration::from_secs(hours * 60 * 60); - let minutes = fields[1].parse::()?; - duration += Duration::from_secs(minutes * 60); + let minutes = fields[1].parse::()?; + duration += Duration::from_secs(minutes * 60); - let seconds = fields[1].parse::()?; - duration += Duration::from_millis((seconds * 1000.0) as u64); + let seconds = fields[1].parse::()?; + duration += Duration::from_millis((seconds * 1000.0) as u64); - Ok(duration.as_millis() as u64) + Ok(duration.as_millis() as u64) } pub fn progress_monitor( - source_filepath: PathBuf, - sender_base: &Sender, + source_filepath: PathBuf, + sender_base: &Sender, ) -> Result<(String, JoinHandle<()>), Box> { - let total_length_millis = get_file_length_milliseconds(source_filepath)?; + let total_length_millis = get_file_length_milliseconds(source_filepath)?; - let tempdir = tempfile::tempdir()?; - let file_path = tempdir.path().join("progress.log"); - let file_path_string = file_path.to_str().unwrap().to_string(); - fs::File::create(&file_path)?; + let tempdir = tempfile::tempdir()?; + let file_path = tempdir.path().join("progress.log"); + let file_path_string = file_path.to_str().unwrap().to_string(); + fs::File::create(&file_path)?; - let sender = sender_base.clone(); - let child = thread::spawn(move || { - let _ = &tempdir; + let sender = sender_base.clone(); + let child = thread::spawn(move || { + let _ = &tempdir; - let (tx, rx) = mpsc::channel(); - let mut watcher = RecommendedWatcher::new( - tx, - notify::Config::default().with_poll_interval(Duration::from_millis(100)), - ) - .expect("could not watch for ffmpeg log progress status"); + let (tx, rx) = mpsc::channel(); + let mut watcher = RecommendedWatcher::new( + tx, + notify::Config::default().with_poll_interval(Duration::from_millis(100)), + ) + .expect("could not watch for ffmpeg log progress status"); - watcher - .watch(&file_path, RecursiveMode::NonRecursive) - .unwrap(); + watcher + .watch(&file_path, RecursiveMode::NonRecursive) + .unwrap(); - let mut pos = 0; + let mut pos = 0; - 'outer: for res in rx { - if res.is_err() { - break 'outer; - } + 'outer: for res in rx { + if res.is_err() { + break 'outer; + } - let res = res.unwrap(); + let res = res.unwrap(); - match res.kind { - EventKind::Modify(_) => { - let mut file = fs::File::open(&file_path).unwrap(); - file.seek(SeekFrom::Start(pos)).unwrap(); + match res.kind { + EventKind::Modify(_) => { + let mut file = fs::File::open(&file_path).unwrap(); + file.seek(SeekFrom::Start(pos)).unwrap(); - pos = file.metadata().unwrap().len(); + pos = file.metadata().unwrap().len(); - let reader = BufReader::new(file); - for line in reader.lines() { - let ln = line.unwrap(); + let reader = BufReader::new(file); + for line in reader.lines() { + let ln = line.unwrap(); - if ln == "progress=end" { - break 'outer; - } + if ln == "progress=end" { + break 'outer; + } - if ln.starts_with("out_time=") { - let out_time = ln.strip_prefix("out_time=").unwrap().to_string(); - let out_time_ms = ffprobe_duration_to_ms(out_time).unwrap(); - if sender - .send(format!( - "{:.2}%", - ((out_time_ms as f64 / total_length_millis as f64) * 100.0) - )) - .is_err() - { - break 'outer; - }; - } - } - } - EventKind::Remove(_) => break 'outer, - _ => {} - } - } - }); + if ln.starts_with("out_time=") { + let out_time = ln.strip_prefix("out_time=").unwrap().to_string(); + let out_time_ms = ffprobe_duration_to_ms(out_time).unwrap(); + if sender + .send(format!( + "{:.2}%", + ((out_time_ms as f64 / total_length_millis as f64) * 100.0) + )) + .is_err() + { + break 'outer; + }; + } + } + } + EventKind::Remove(_) => break 'outer, + _ => {} + } + } + }); - Ok((file_path_string, child)) + Ok((file_path_string, child)) } diff --git a/src/utils/transcoder/transcoder.rs b/src/utils/transcoder/transcoder.rs index 3846a57..45b38fd 100644 --- a/src/utils/transcoder/transcoder.rs +++ b/src/utils/transcoder/transcoder.rs @@ -6,80 +6,80 @@ use string_error::static_err; use super::{progress_monitor, types::TranscodeConfig}; pub fn transcode( - file: File, - dest: String, - config: &TranscodeConfig, - progress_sender: Option>, + file: File, + dest: String, + config: &TranscodeConfig, + progress_sender: Option>, ) -> Result<(), Box> { - let mut command_args: Vec = Vec::new(); - command_args.extend(vec!["-y".to_string(), "-hide_banner".to_string()]); + let mut command_args: Vec = Vec::new(); + command_args.extend(vec!["-y".to_string(), "-hide_banner".to_string()]); - command_args.extend(vec![ - "-i".to_string(), - file.join_path_to().to_string_lossy().to_string(), - ]); + command_args.extend(vec![ + "-i".to_string(), + file.join_path_to().to_string_lossy().to_string(), + ]); - if let Some(encoder) = &config.encoder { - command_args.extend(vec!["-c:a".to_string(), encoder.to_string()]); - } + if let Some(encoder) = &config.encoder { + command_args.extend(vec!["-c:a".to_string(), encoder.to_string()]); + } - if let Some(container) = &config.container { - command_args.extend(vec!["-f".to_string(), container.to_string()]); - } + if let Some(container) = &config.container { + command_args.extend(vec!["-f".to_string(), container.to_string()]); + } - if let Some(sample_rate) = &config.sample_rate { - command_args.extend(vec!["-ar".to_string(), sample_rate.to_string()]); - } + if let Some(sample_rate) = &config.sample_rate { + command_args.extend(vec!["-ar".to_string(), sample_rate.to_string()]); + } - if let Some(channels) = &config.channels { - command_args.extend(vec!["-ac".to_string(), channels.to_string()]); - } + if let Some(channels) = &config.channels { + command_args.extend(vec!["-ac".to_string(), channels.to_string()]); + } - if let Some(quality) = &config.quality { - command_args.extend(vec!["-q:a".to_string(), quality.to_string()]); - } + if let Some(quality) = &config.quality { + command_args.extend(vec!["-q:a".to_string(), quality.to_string()]); + } - if let Some(bitrate) = &config.bitrate { - command_args.extend(vec!["-b:a".to_string(), bitrate.to_string()]); - } + if let Some(bitrate) = &config.bitrate { + command_args.extend(vec!["-b:a".to_string(), bitrate.to_string()]); + } - command_args.push(dest); + command_args.push(dest); - let mut progress_thread: Option> = None; - let mut progress_file: Option = None; + let mut progress_thread: Option> = None; + let mut progress_file: Option = None; - if let Some(sender) = &progress_sender { - let result = progress_monitor(file.join_path_to(), sender); + if let Some(sender) = &progress_sender { + let result = progress_monitor(file.join_path_to(), sender); - if let Ok(result) = result { - progress_thread = Some(result.1); - progress_file = Some(result.0.clone()); - command_args.extend(vec![ - "-progress".to_string(), - result.0, - "-nostats".to_string(), - ]); - } - } + if let Ok(result) = result { + progress_thread = Some(result.1); + progress_file = Some(result.0.clone()); + command_args.extend(vec![ + "-progress".to_string(), + result.0, + "-nostats".to_string(), + ]); + } + } - let output = Command::new(crate::meta::FFMPEG) - .args(command_args) - .output() - .expect("failed to execute process"); + let output = Command::new(crate::meta::FFMPEG) + .args(command_args) + .output() + .expect("failed to execute process"); - if let Some(sender) = progress_sender { - drop(sender); - } + if let Some(sender) = progress_sender { + drop(sender); + } - if let Some(thread) = progress_thread { - fs::remove_file(progress_file.unwrap())?; - thread.join().expect("thread couldn't join"); - } + if let Some(thread) = progress_thread { + fs::remove_file(progress_file.unwrap())?; + thread.join().expect("thread couldn't join"); + } - if !output.status.success() { - print!("{}", String::from_utf8(output.stderr).unwrap()); - return Err(static_err("FFmpeg Crashed")); - } + if !output.status.success() { + print!("{}", String::from_utf8(output.stderr).unwrap()); + return Err(static_err("FFmpeg Crashed")); + } - Ok(()) + Ok(()) } diff --git a/src/utils/transcoder/types.rs b/src/utils/transcoder/types.rs index 34035df..e09b964 100644 --- a/src/utils/transcoder/types.rs +++ b/src/utils/transcoder/types.rs @@ -5,43 +5,43 @@ use string_error::static_err; #[derive(Debug, Serialize, Deserialize)] pub struct Preset { - pub name: String, - pub config: TranscodeConfig, + pub name: String, + pub config: TranscodeConfig, } #[derive(Debug, Serialize, Deserialize)] pub struct PresetCategory { - pub name: String, - pub presets: Vec, + pub name: String, + pub presets: Vec, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct TranscodeConfig { - pub encoder: Option, - pub file_extension: Option, - pub container: Option, - pub bitrate: Option, - pub quality: Option, - pub sample_rate: Option, - pub channels: Option, + pub encoder: Option, + pub file_extension: Option, + pub container: Option, + pub bitrate: Option, + pub quality: Option, + pub sample_rate: Option, + pub channels: Option, } impl TranscodeConfig { - pub fn load(path: String) -> Result> { - let path_buf = PathBuf::from(&path); - let extension = path_buf.extension().unwrap(); - let file = File::open(path)?; - let reader = BufReader::new(file); + pub fn load(path: String) -> Result> { + let path_buf = PathBuf::from(&path); + let extension = path_buf.extension().unwrap(); + let file = File::open(path)?; + let reader = BufReader::new(file); - if extension == "yml" || extension == "yaml" { - let u: TranscodeConfig = - serde_yaml::from_reader(reader).expect("error while reading yaml"); - return Ok(u); - } else if extension == "json" { - let u: TranscodeConfig = - serde_json::from_reader(reader).expect("error while reading json"); - return Ok(u); - } - Err(static_err("Invalid File Extension")) - } + if extension == "yml" || extension == "yaml" { + let u: TranscodeConfig = + serde_yaml::from_reader(reader).expect("error while reading yaml"); + return Ok(u); + } else if extension == "json" { + let u: TranscodeConfig = + serde_json::from_reader(reader).expect("error while reading json"); + return Ok(u); + } + Err(static_err("Invalid File Extension")) + } }