move replaygain stuff into its own crate, run clippy
This commit is contained in:
parent
feee847463
commit
d5ab74d17a
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -683,6 +683,7 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"metaflac",
|
||||
"notify",
|
||||
"replaygain",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
|
@ -876,6 +877,14 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "replaygain"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
|
|
|
@ -41,6 +41,9 @@ metaflac = { version = "0.2", optional = true }
|
|||
taglib = { path = "./modules/taglib", optional = true }
|
||||
ffprobe = { path = "./modules/ffprobe" }
|
||||
|
||||
# replaygain_analysis
|
||||
replaygain = { path = "./modules/replaygain", optional = true }
|
||||
|
||||
# for genhtml command
|
||||
html-escape = { version = "0.2", optional = true }
|
||||
urlencoding = { version = "2", optional = true }
|
||||
|
@ -73,4 +76,4 @@ ffprobe_extractor = [] # If to allow using ffmpeg/ffprobe as a fallback tag extr
|
|||
|
||||
command_genhtml = ["dep:html-escape", "dep:urlencoding"]
|
||||
|
||||
replaygain = []
|
||||
replaygain = ["dep:replaygain"]
|
|
@ -37,12 +37,12 @@ fn main() {
|
|||
}
|
||||
|
||||
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
|
||||
let mut file = BufWriter::new(File::create(&path).unwrap());
|
||||
let mut file = BufWriter::new(File::create(path).unwrap());
|
||||
write!(
|
||||
&mut file,
|
||||
"static MAPPINGS: phf::Map<char, &'static str> = {}",
|
||||
map.build()
|
||||
)
|
||||
.unwrap();
|
||||
write!(&mut file, ";\n").unwrap();
|
||||
writeln!(&mut file, ";").unwrap();
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test() {
|
||||
assert_eq!(crate::reduce("öwo owö 😊".to_string()), "owo owo ");
|
||||
}
|
||||
#[test]
|
||||
fn test() {
|
||||
assert_eq!(crate::reduce("öwo owö 😊".to_string()), "owo owo ");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reduce(input: String) -> String {
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
pub mod errors;
|
||||
pub mod types;
|
||||
mod ffprobe_output;
|
||||
pub mod types;
|
||||
|
||||
use std::{convert::Into, path::Path, process::Command};
|
||||
|
||||
use self::errors::{AnalyzeError, FFProbeError};
|
||||
|
||||
fn extract(path: &Path, ffprobe_command: Option<&str>) -> Result<ffprobe_output::FFProbeOutput, AnalyzeError> {
|
||||
fn extract(
|
||||
path: &Path,
|
||||
ffprobe_command: Option<&str>,
|
||||
) -> Result<ffprobe_output::FFProbeOutput, AnalyzeError> {
|
||||
let output = Command::new(ffprobe_command.unwrap_or("ffprobe"))
|
||||
.args([
|
||||
"-v",
|
||||
|
@ -39,7 +42,10 @@ fn extract(path: &Path, ffprobe_command: Option<&str>) -> Result<ffprobe_output:
|
|||
Ok(ffprobe_out.unwrap())
|
||||
}
|
||||
|
||||
pub fn analyze(path: &Path, ffprobe_command: Option<&str>) -> Result<types::FFProbeData, AnalyzeError> {
|
||||
pub fn analyze(
|
||||
path: &Path,
|
||||
ffprobe_command: Option<&str>,
|
||||
) -> Result<types::FFProbeData, AnalyzeError> {
|
||||
let raw_data = extract(path, ffprobe_command)?;
|
||||
|
||||
let mut data = types::FFProbeData {
|
||||
|
|
8
modules/replaygain/Cargo.toml
Normal file
8
modules/replaygain/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "replaygain"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
|
@ -1,15 +1,75 @@
|
|||
use std::{
|
||||
fmt,
|
||||
io::{BufRead, BufReader},
|
||||
path::PathBuf,
|
||||
process::Command,
|
||||
process::{self, Command},
|
||||
};
|
||||
|
||||
use string_error::static_err;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReplayGainRawData {
|
||||
pub track_gain: f64,
|
||||
pub track_peak: f64,
|
||||
}
|
||||
|
||||
use crate::types::ReplayGainRawData;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReplayGainData {
|
||||
pub track_gain: String,
|
||||
pub track_peak: String,
|
||||
}
|
||||
|
||||
pub fn analyze_replaygain_track(path: PathBuf) -> Result<ReplayGainRawData, Box<dyn std::error::Error>> {
|
||||
let output = Command::new(crate::meta::FFMPEG)
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FFMpegError {
|
||||
pub exit_status: process::ExitStatus,
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for FFMpegError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ffmpeg exited with error code {}, stderr: {}",
|
||||
self.exit_status.code().unwrap(),
|
||||
self.stderr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
FFMpegError(FFMpegError),
|
||||
ParseError(std::num::ParseFloatError),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::FFMpegError(err) => write!(f, "{}", err),
|
||||
Error::ParseError(err) => write!(f, "{}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze_replaygain_track(
|
||||
path: PathBuf,
|
||||
ffmpeg_command: Option<&str>,
|
||||
) -> Result<ReplayGainRawData, Error> {
|
||||
let output = Command::new(ffmpeg_command.unwrap_or("ffmpeg"))
|
||||
.args([
|
||||
"-hide_banner",
|
||||
"-nostats",
|
||||
|
@ -25,13 +85,16 @@ pub fn analyze_replaygain_track(path: PathBuf) -> Result<ReplayGainRawData, Box<
|
|||
"null",
|
||||
"/dev/null",
|
||||
])
|
||||
.output()?;
|
||||
.output();
|
||||
|
||||
let output = output.unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
print!("{:?}", String::from_utf8(output.stderr).unwrap());
|
||||
return Err(static_err("FFmpeg Crashed"));
|
||||
return Err(Error::FFMpegError(FFMpegError {
|
||||
exit_status: output.status,
|
||||
stderr: String::from_utf8(output.stderr).unwrap(),
|
||||
}));
|
||||
}
|
||||
|
||||
// info we need is in stdout
|
||||
let output_str = String::from_utf8(output.stderr).unwrap();
|
||||
|
||||
|
@ -72,7 +135,10 @@ pub fn analyze_replaygain_track(path: PathBuf) -> Result<ReplayGainRawData, Box<
|
|||
l.next();
|
||||
|
||||
let gain = l.next().unwrap().trim().trim_end_matches(" LUFS");
|
||||
let gain = gain.parse::<f64>()?;
|
||||
let gain = match gain.parse::<f64>() {
|
||||
Ok(parsed) => Ok(parsed),
|
||||
Err(err) => Err(Error::ParseError(err)),
|
||||
}?;
|
||||
|
||||
// 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."
|
||||
|
@ -87,7 +153,10 @@ pub fn analyze_replaygain_track(path: PathBuf) -> Result<ReplayGainRawData, Box<
|
|||
|
||||
// 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::<f64>()?;
|
||||
let peak = match peak.parse::<f64>() {
|
||||
Ok(parsed) => Ok(parsed),
|
||||
Err(err) => Err(Error::ParseError(err)),
|
||||
}?;
|
||||
let peak = f64::powf(10_f64, peak / 20.0_f64);
|
||||
track_peak = peak;
|
||||
}
|
|
@ -6,11 +6,11 @@ use crate::args::CLIArgs;
|
|||
use crate::types::AudioFileInfo;
|
||||
use crate::types::File;
|
||||
use crate::utils::formats::get_format_handler;
|
||||
#[cfg(feature = "replaygain")]
|
||||
use crate::utils::replaygain::analyze_replaygain_track;
|
||||
use crate::utils::scan_for_music;
|
||||
|
||||
use ascii_reduce::reduce;
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::analyze_replaygain_track;
|
||||
|
||||
#[derive(Debug, Clone, clap::Args)]
|
||||
pub struct ProcessCommandArgs {
|
||||
|
@ -153,7 +153,8 @@ pub fn add_replaygain_tags(file: &File, force: bool) -> Result<(), Box<dyn std::
|
|||
file.join_path_from_source()
|
||||
);
|
||||
|
||||
let replaygain_data = analyze_replaygain_track(file.join_path_to())?;
|
||||
let replaygain_data = analyze_replaygain_track(file.join_path_to(), Some(crate::meta::FFMPEG))
|
||||
.expect("could not analyze replaygain");
|
||||
|
||||
let mut handler = get_format_handler(file)?;
|
||||
|
||||
|
|
31
src/types.rs
31
src/types.rs
|
@ -21,39 +21,12 @@ impl Default for Tags {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
pub struct ReplayGainData {
|
||||
pub track_gain: String,
|
||||
pub track_peak: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReplayGainRawData {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct AudioFileInfo {
|
||||
pub tags: Tags,
|
||||
#[cfg(feature = "replaygain")]
|
||||
pub contains_replaygain: bool,
|
||||
#[cfg(feature = "replaygain")]
|
||||
pub supports_replaygain: bool,
|
||||
pub format: Option<FileFormat>,
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@ use std::{
|
|||
use string_error::into_err;
|
||||
|
||||
use crate::{
|
||||
types::{AudioFileInfo, ReplayGainData, ReplayGainRawData, Tags},
|
||||
meta,
|
||||
types::{AudioFileInfo, Tags},
|
||||
utils::format_detection::{detect_format, FileFormat},
|
||||
utils::formats::{AudioFormatError, BoxedError, FormatHandler}, meta,
|
||||
utils::formats::{AudioFormatError, BoxedError, FormatHandler},
|
||||
};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::{ReplayGainData, ReplayGainRawData};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Changes {
|
||||
title: Option<String>,
|
||||
|
@ -20,6 +24,7 @@ struct Changes {
|
|||
#[derive(Default)]
|
||||
struct ExtractedData {
|
||||
tags: Tags,
|
||||
#[cfg(feature = "replaygain")]
|
||||
replaygain_data: Option<ReplayGainData>,
|
||||
}
|
||||
|
||||
|
@ -47,6 +52,7 @@ impl GenericFFMpegAudioFormat {
|
|||
track_number: output.tags.track_number,
|
||||
};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
if output.tags.replaygain_track_gain.is_some()
|
||||
&& output.tags.replaygain_track_peak.is_some()
|
||||
{
|
||||
|
@ -86,10 +92,12 @@ impl FormatHandler for GenericFFMpegAudioFormat {
|
|||
Ok(tags)
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn contains_replaygain_tags(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn supports_replaygain(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -104,6 +112,7 @@ impl FormatHandler for GenericFFMpegAudioFormat {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn set_replaygain_data(&mut self, _data: ReplayGainRawData) -> Result<(), BoxedError> {
|
||||
panic!("ffprobe doesn't support setting replaygain data, check supports_replaygain()")
|
||||
}
|
||||
|
@ -158,7 +167,9 @@ impl FormatHandler for GenericFFMpegAudioFormat {
|
|||
) -> Result<AudioFileInfo, BoxedError> {
|
||||
Ok(AudioFileInfo {
|
||||
tags: self.get_tags(allow_missing_tags)?,
|
||||
#[cfg(feature = "replaygain")]
|
||||
contains_replaygain: self.contains_replaygain_tags(),
|
||||
#[cfg(feature = "replaygain")]
|
||||
supports_replaygain: self.supports_replaygain(),
|
||||
format: Some(self.file_format),
|
||||
})
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
types::{AudioFileInfo, ReplayGainRawData, Tags},
|
||||
types::{AudioFileInfo, Tags},
|
||||
utils::format_detection::FileFormat,
|
||||
utils::formats::{AudioFormatError, BoxedError, FormatHandler},
|
||||
};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::ReplayGainRawData;
|
||||
|
||||
pub struct FLACAudioFormat {
|
||||
flac_tags: metaflac::Tag,
|
||||
path: Box<PathBuf>,
|
||||
|
@ -58,6 +61,7 @@ impl FormatHandler for FLACAudioFormat {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
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");
|
||||
|
@ -69,6 +73,7 @@ impl FormatHandler for FLACAudioFormat {
|
|||
true
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn supports_replaygain(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -87,6 +92,7 @@ impl FormatHandler for FLACAudioFormat {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
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");
|
||||
|
@ -114,7 +120,9 @@ impl FormatHandler for FLACAudioFormat {
|
|||
) -> Result<AudioFileInfo, BoxedError> {
|
||||
Ok(AudioFileInfo {
|
||||
tags: self.get_tags(allow_missing_tags)?,
|
||||
#[cfg(feature = "replaygain")]
|
||||
contains_replaygain: self.contains_replaygain_tags(),
|
||||
#[cfg(feature = "replaygain")]
|
||||
supports_replaygain: self.supports_replaygain(),
|
||||
format: Some(FileFormat::FLAC),
|
||||
})
|
||||
|
|
|
@ -3,11 +3,14 @@ use std::path::PathBuf;
|
|||
use id3::TagLike;
|
||||
|
||||
use crate::{
|
||||
types::{AudioFileInfo, ReplayGainRawData, Tags},
|
||||
types::{AudioFileInfo, Tags},
|
||||
utils::format_detection::FileFormat,
|
||||
utils::formats::{AudioFormatError, BoxedError, FormatHandler},
|
||||
};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::ReplayGainRawData;
|
||||
|
||||
pub struct ID3AudioFormat {
|
||||
id3_tags: id3::Tag,
|
||||
path: Box<PathBuf>,
|
||||
|
@ -37,6 +40,7 @@ impl FormatHandler for ID3AudioFormat {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn contains_replaygain_tags(&self) -> bool {
|
||||
let frames = self.id3_tags.frames();
|
||||
|
||||
|
@ -61,6 +65,7 @@ impl FormatHandler for ID3AudioFormat {
|
|||
contains_replaygain_tags
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn supports_replaygain(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -77,6 +82,7 @@ impl FormatHandler for ID3AudioFormat {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> {
|
||||
let frames = self.id3_tags.remove("TXXX");
|
||||
|
||||
|
@ -121,7 +127,9 @@ impl FormatHandler for ID3AudioFormat {
|
|||
Ok(AudioFileInfo {
|
||||
tags: self.get_tags(allow_missing_tags)?,
|
||||
format: Some(FileFormat::MP3),
|
||||
#[cfg(feature = "replaygain")]
|
||||
supports_replaygain: self.supports_replaygain(),
|
||||
#[cfg(feature = "replaygain")]
|
||||
contains_replaygain: self.contains_replaygain_tags(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,11 +7,14 @@ use taglib::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
types::{AudioFileInfo, ReplayGainRawData, Tags},
|
||||
types::{AudioFileInfo, Tags},
|
||||
utils::format_detection::FileFormat,
|
||||
utils::formats::{AudioFormatError, BoxedError, FormatHandler},
|
||||
};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::ReplayGainRawData;
|
||||
|
||||
pub struct TaglibAudioFormat {
|
||||
file: taglib::TagLibFile,
|
||||
file_format: Option<FileFormat>,
|
||||
|
@ -46,6 +49,7 @@ impl FormatHandler for TaglibAudioFormat {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn contains_replaygain_tags(&self) -> bool {
|
||||
if let Some(format) = self.file_format {
|
||||
if format == FileFormat::OggOpus {
|
||||
|
@ -67,6 +71,7 @@ impl FormatHandler for TaglibAudioFormat {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn supports_replaygain(&self) -> bool {
|
||||
if let Some(format) = self.file_format {
|
||||
return matches!(
|
||||
|
@ -99,6 +104,7 @@ impl FormatHandler for TaglibAudioFormat {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError> {
|
||||
if let Some(format) = self.file_format {
|
||||
match format {
|
||||
|
@ -143,7 +149,9 @@ impl FormatHandler for TaglibAudioFormat {
|
|||
) -> Result<AudioFileInfo, BoxedError> {
|
||||
Ok(AudioFileInfo {
|
||||
tags: self.get_tags(allow_missing_tags)?,
|
||||
#[cfg(feature = "replaygain")]
|
||||
contains_replaygain: self.contains_replaygain_tags(),
|
||||
#[cfg(feature = "replaygain")]
|
||||
supports_replaygain: self.supports_replaygain(),
|
||||
format: self.file_format,
|
||||
})
|
||||
|
|
|
@ -5,19 +5,24 @@ use std::path::Path;
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::types::{AudioFileInfo, File, ReplayGainRawData, Tags};
|
||||
|
||||
use super::format_detection::detect_format;
|
||||
use crate::types::{AudioFileInfo, File, Tags};
|
||||
|
||||
#[cfg(feature = "replaygain")]
|
||||
use replaygain::ReplayGainRawData;
|
||||
|
||||
type BoxedError = Box<dyn Error>;
|
||||
|
||||
pub trait FormatHandler {
|
||||
fn get_tags(&self, allow_missing: bool) -> Result<Tags, BoxedError>;
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn contains_replaygain_tags(&self) -> bool;
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn supports_replaygain(&self) -> bool;
|
||||
|
||||
fn set_title(&mut self, title: String) -> Result<(), BoxedError>;
|
||||
fn set_artist(&mut self, artist: String) -> Result<(), BoxedError>;
|
||||
#[cfg(feature = "replaygain")]
|
||||
fn set_replaygain_data(&mut self, data: ReplayGainRawData) -> Result<(), BoxedError>;
|
||||
|
||||
fn save_changes(&mut self) -> Result<(), BoxedError>;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
pub mod format_detection;
|
||||
#[cfg(feature = "replaygain")]
|
||||
pub mod replaygain;
|
||||
pub mod transcoder;
|
||||
|
||||
pub mod formats;
|
||||
|
|
Loading…
Reference in a new issue