diff --git a/Cargo.toml b/Cargo.toml index 2b0ed87..243c8d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,8 @@ infer = "0.15" bytes = "1" # tag reading -id3 = "1" -metaflac = "0.2" +id3 = { version = "1", optional = true } +metaflac = { version = "0.2", optional = true } taglib = { path = "./modules/taglib", optional = true } # for genhtml command @@ -51,5 +51,10 @@ tempfile = "3" notify = "6" [features] -default = ["taglib"] +default = ["taglib", "flac", "mp3", "ffmpeg_fallback"] + +# Formats taglib = ["dep:taglib"] +flac = ["dep:metaflac"] +mp3 = ["dep:id3"] +ffmpeg_fallback = [] # If to allow using ffmpeg as a fallback tag extractor \ No newline at end of file diff --git a/src/utils/ffprobe/mod.rs b/src/utils/ffprobe/mod.rs index 8b2a5ea..27a47fd 100644 --- a/src/utils/ffprobe/mod.rs +++ b/src/utils/ffprobe/mod.rs @@ -4,13 +4,13 @@ pub mod types; use std::{ convert::Into, - path::PathBuf, + path::Path, process::Command, }; use self::errors::{AnalyzeError, FFProbeError}; -pub fn analyze(path: &PathBuf) -> Result { +pub fn analyze(path: &Path) -> Result { let output = Command::new(crate::meta::FFPROBE) .args([ "-v", @@ -41,7 +41,7 @@ pub fn analyze(path: &PathBuf) -> Result { let ffprobe_out = ffprobe_out.unwrap(); - return Ok(types::FFProbeData { + Ok(types::FFProbeData { tags: ffprobe_out.format.tags.into(), - }); + }) } diff --git a/src/utils/ffprobe/types.rs b/src/utils/ffprobe/types.rs index 5274d35..7597551 100644 --- a/src/utils/ffprobe/types.rs +++ b/src/utils/ffprobe/types.rs @@ -10,13 +10,13 @@ pub struct FFProbeTags { pub replaygain_track_gain: Option, } -impl Into for ffprobe_output::FFProbeOutputTags { - fn into(self) -> FFProbeTags { +impl From for FFProbeTags { + fn from(val: ffprobe_output::FFProbeOutputTags) -> Self { FFProbeTags { - title: self.title, - artist: self.artist, - replaygain_track_peak: self.replaygain_track_peak, - replaygain_track_gain: self.replaygain_track_gain, + title: val.title, + artist: val.artist, + replaygain_track_peak: val.replaygain_track_peak, + replaygain_track_gain: val.replaygain_track_gain, } } } diff --git a/src/utils/formats/flac.rs b/src/utils/formats/handlers/flac.rs similarity index 97% rename from src/utils/formats/flac.rs rename to src/utils/formats/handlers/flac.rs index 83f7cd2..ea9523e 100644 --- a/src/utils/formats/flac.rs +++ b/src/utils/formats/handlers/flac.rs @@ -3,9 +3,9 @@ use std::path::PathBuf; use crate::{ types::{AudioFileInfo, ReplayGainRawData, Tags}, utils::format_detection::FileFormat, + utils::formats::{AudioContainerFormat, AudioFormatError, BoxedError} }; -use super::{AudioContainerFormat, AudioFormatError, BoxedError}; pub struct FLACAudioFormat { flac_tags: metaflac::Tag, diff --git a/src/utils/formats/generic_ffmpeg.rs b/src/utils/formats/handlers/generic_ffmpeg.rs similarity index 98% rename from src/utils/formats/generic_ffmpeg.rs rename to src/utils/formats/handlers/generic_ffmpeg.rs index 93b82df..3377c73 100644 --- a/src/utils/formats/generic_ffmpeg.rs +++ b/src/utils/formats/handlers/generic_ffmpeg.rs @@ -8,10 +8,9 @@ use string_error::into_err; use crate::{ types::{AudioFileInfo, ReplayGainData, ReplayGainRawData, Tags}, utils::{format_detection::FileFormat, ffprobe}, + utils::formats::{AudioContainerFormat, AudioFormatError, BoxedError}, }; -use super::{AudioContainerFormat, AudioFormatError, BoxedError}; - #[derive(Default)] struct Changes { title: Option, diff --git a/src/utils/formats/generic_taglib.rs b/src/utils/formats/handlers/generic_taglib.rs similarity index 98% rename from src/utils/formats/generic_taglib.rs rename to src/utils/formats/handlers/generic_taglib.rs index 878a7bc..c3cc77b 100644 --- a/src/utils/formats/generic_taglib.rs +++ b/src/utils/formats/handlers/generic_taglib.rs @@ -9,9 +9,9 @@ use taglib::{ use crate::{ types::{AudioFileInfo, ReplayGainRawData, Tags}, utils::format_detection::FileFormat, + utils::formats::{AudioContainerFormat, AudioFormatError, BoxedError} }; -use super::{AudioContainerFormat, AudioFormatError, BoxedError}; pub struct TaglibAudioFormat { file: taglib::TagLibFile, diff --git a/src/utils/formats/id3.rs b/src/utils/formats/handlers/id3.rs similarity index 98% rename from src/utils/formats/id3.rs rename to src/utils/formats/handlers/id3.rs index 692025a..1fb4c29 100644 --- a/src/utils/formats/id3.rs +++ b/src/utils/formats/handlers/id3.rs @@ -5,10 +5,9 @@ use id3::TagLike; use crate::{ types::{AudioFileInfo, ReplayGainRawData, Tags}, utils::format_detection::FileFormat, + utils::formats::{AudioContainerFormat, AudioFormatError, BoxedError}, }; -use super::{AudioContainerFormat, AudioFormatError, BoxedError}; - pub struct ID3AudioFormat { id3_tags: id3::Tag, path: Box, diff --git a/src/utils/formats/handlers/mod.rs b/src/utils/formats/handlers/mod.rs new file mode 100644 index 0000000..b8afeea --- /dev/null +++ b/src/utils/formats/handlers/mod.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "ffmpeg_fallback")] +pub mod generic_ffmpeg; +#[cfg(feature = "flac")] +pub mod flac; +#[cfg(feature = "taglib")] +pub mod generic_taglib; +#[cfg(feature = "mp3")] +pub mod id3; \ No newline at end of file diff --git a/src/utils/formats/mod.rs b/src/utils/formats/mod.rs index b235ea9..b476c5a 100644 --- a/src/utils/formats/mod.rs +++ b/src/utils/formats/mod.rs @@ -1,9 +1,4 @@ -pub mod flac; -pub mod generic_ffmpeg; -pub mod id3; - -#[cfg(feature = "taglib")] -pub mod generic_taglib; +mod handlers; use std::error::Error; use std::path::Path; @@ -12,11 +7,14 @@ use thiserror::Error; use crate::types::{AudioFileInfo, File, ReplayGainRawData, Tags}; -use self::flac::new_flac_format_handler; -use self::id3::new_id3_format_handler; - +#[cfg(feature = "flac")] +use self::handlers::flac::new_flac_format_handler; #[cfg(feature = "taglib")] -use self::generic_taglib::new_taglib_format_handler; +use self::handlers::generic_taglib::new_taglib_format_handler; +#[cfg(feature = "mp3")] +use self::handlers::id3::new_id3_format_handler; +#[cfg(feature = "ffmpeg_fallback")] +use self::handlers::generic_ffmpeg::new_generic_ffmpeg_format_handler; use super::format_detection::{detect_format, FileFormat}; @@ -67,22 +65,65 @@ pub fn get_format_handler(file: &File) -> Result, } } - match format { - FileFormat::FLAC => { - // Native FLAC support - return Ok(Box::new(new_flac_format_handler(&path)?)); - } - FileFormat::MP3 => { - // Native MP3 support - return Ok(Box::new(new_id3_format_handler(&path)?)); - } - _ => {} + #[cfg(feature = "mp3")] + if format == FileFormat::MP3 { + // Native MP3 support + return Ok(Box::new(new_id3_format_handler(&path)?)); } + #[cfg(feature = "flac")] + if format == FileFormat::FLAC { + // Native FLAC support + return Ok(Box::new(new_flac_format_handler(&path)?)); + } + + #[cfg(feature = "ffmpeg_fallback")] + match format { + FileFormat::MP3 + | FileFormat::FLAC + | FileFormat::OggVorbis + | FileFormat::OggOpus + | FileFormat::OggFLAC + | FileFormat::OggSpeex + | FileFormat::OggTheora + | FileFormat::Wav + | FileFormat::WavPack + | FileFormat::AIFF => { + return Ok(Box::new(new_generic_ffmpeg_format_handler(&path, format)?)); + } + #[allow(unreachable_patterns)] + _ => {}, + } + panic!("no supported handler found"); } -fn is_supported_extension(file_path: &Path) -> bool { +fn is_supported_extension(ext: &str) -> bool { + #[cfg(feature = "taglib")] + if matches!(ext, "ogg" | "opus" | "wav" | "wv" | "aiff") { + return true; + } + + #[cfg(feature = "mp3")] + if ext == "mp3" { + return true; + } + + #[cfg(feature = "flac")] + if ext == "flac" { + return true; + } + + // FFMpeg Fallback + #[cfg(feature = "ffmpeg_fallback")] + if matches!(ext, "mp3" | "flac" | "ogg" | "opus" | "wav" | "wv" | "aiff") { + return true; + } + + false +} + +pub fn is_supported_file(file_path: &Path) -> bool { let ext = file_path.extension(); if ext.is_none() { @@ -91,18 +132,7 @@ fn is_supported_extension(file_path: &Path) -> bool { let ext = ext.unwrap().to_str().unwrap(); - #[cfg(feature = "taglib")] - { - if matches!(ext, "ogg" | "opus" | "wav" | "wv" | "aiff") { - return true; - } - } - - matches!(ext, "mp3" | "flac") -} - -pub fn is_supported_file(file_path: &Path) -> bool { - if !is_supported_extension(file_path) { + if !is_supported_extension(ext) { return false; } @@ -114,26 +144,46 @@ pub fn is_supported_file(file_path: &Path) -> bool { let format = format.unwrap(); #[cfg(feature = "taglib")] - { - match format { - FileFormat::OggVorbis - | FileFormat::OggOpus - | FileFormat::OggFLAC - | FileFormat::OggSpeex - | FileFormat::Wav - | FileFormat::WavPack - | FileFormat::AIFF => { - return true; - } - _ => {} + match format { + FileFormat::OggVorbis + | FileFormat::OggOpus + | FileFormat::OggFLAC + | FileFormat::OggSpeex + | FileFormat::Wav + | FileFormat::WavPack + | FileFormat::AIFF => { + return true; } + _ => {} } - match format { - // Not supported yet - FileFormat::OggTheora => false, - FileFormat::FLAC | FileFormat::MP3 => true, - // Rest not supported - _ => false, + #[cfg(feature = "mp3")] + if format == FileFormat::MP3 { + return true; } + + #[cfg(feature = "flac")] + if format == FileFormat::FLAC { + return true; + } + + #[cfg(feature = "ffmpeg_fallback")] + match format { + FileFormat::MP3 + | FileFormat::FLAC + | FileFormat::OggVorbis + | FileFormat::OggOpus + | FileFormat::OggFLAC + | FileFormat::OggSpeex + | FileFormat::OggTheora + | FileFormat::Wav + | FileFormat::WavPack + | FileFormat::AIFF => { + return true; + } + #[allow(unreachable_patterns)] + _ => {} + } + + false } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index ea2eb2b..2461fd5 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,7 +5,7 @@ pub mod transcoder; pub mod ffprobe; pub mod formats; -pub(self) mod music_scanner; + mod music_scanner; pub use formats::is_supported_file; pub use music_scanner::scan_for_music; diff --git a/src/utils/transcoder/mod.rs b/src/utils/transcoder/mod.rs index 33d4ac6..ae1cc4a 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; -pub(self) use self::progress_monitor::progress_monitor; + use self::progress_monitor::progress_monitor; pub use self::transcoder::transcode;