1
0
Fork 0
musicutil/src/utils/formats/handlers/flac.rs

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()),
})
}