148 lines
3.5 KiB
Rust
148 lines
3.5 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use crate::{
|
|
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>,
|
|
}
|
|
|
|
fn flac_get_first(tag: &metaflac::Tag, key: &str) -> Option<String> {
|
|
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<Tags, BoxedError> {
|
|
let title = flac_get_first(&self.flac_tags, "TITLE");
|
|
let artist = flac_get_first(&self.flac_tags, "ARTIST");
|
|
let album = flac_get_first(&self.flac_tags, "ALBUM");
|
|
|
|
let mut track_number = flac_get_first(&self.flac_tags, "TRACKNUMBER");
|
|
|
|
if !allow_missing {
|
|
if title.is_none() {
|
|
return Err(Box::new(AudioFormatError::MissingTitle));
|
|
}
|
|
if artist.is_none() {
|
|
return Err(Box::new(AudioFormatError::MissingArtist));
|
|
}
|
|
}
|
|
|
|
if let Some(number) = &track_number {
|
|
if number.contains('/') {
|
|
let mut split = number.split('/');
|
|
track_number = Some(split.next().unwrap().to_string())
|
|
}
|
|
}
|
|
|
|
Ok(Tags {
|
|
title: title.unwrap(),
|
|
artist: artist.unwrap(),
|
|
album,
|
|
track_number: match track_number {
|
|
Some(num) => match num.parse::<u64>() {
|
|
Ok(n) => Some(n),
|
|
Err(_e) => None,
|
|
},
|
|
None => None,
|
|
},
|
|
})
|
|
}
|
|
|
|
#[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");
|
|
|
|
if track_gain.is_none() || track_peak.is_none() {
|
|
return false;
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
#[cfg(feature = "replaygain")]
|
|
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]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn set_artist(&mut self, artist: String) -> Result<(), BoxedError> {
|
|
self.flac_tags.remove_vorbis("ARTIST");
|
|
self.flac_tags.set_vorbis("ARTIST", vec![artist]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn set_album(&mut self, album: String) -> Result<(), BoxedError> {
|
|
self.flac_tags.remove_vorbis("ALBUM");
|
|
self.flac_tags.set_vorbis("ALBUM", vec![album]);
|
|
|
|
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");
|
|
|
|
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(())
|
|
}
|
|
|
|
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<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),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn new_handler(path: &PathBuf) -> Result<FLACAudioFormat, BoxedError> {
|
|
Ok(FLACAudioFormat {
|
|
flac_tags: metaflac::Tag::read_from_path(path)?,
|
|
path: Box::new(path.clone()),
|
|
})
|
|
}
|