Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I9e0ff5ea33a5cf697473423e88f167ce6a6a6964
91 lines
2.5 KiB
Rust
91 lines
2.5 KiB
Rust
use std::path::Path;
|
|
|
|
use lofty::{
|
|
file::{AudioFile, TaggedFileExt},
|
|
tag::Accessor,
|
|
};
|
|
|
|
use super::{ExtractedMetadata, MetadataExtractor};
|
|
use crate::{
|
|
error::{PinakesError, Result},
|
|
media_type::{BuiltinMediaType, MediaType},
|
|
};
|
|
|
|
pub struct AudioExtractor;
|
|
|
|
impl MetadataExtractor for AudioExtractor {
|
|
fn extract(&self, path: &Path) -> Result<ExtractedMetadata> {
|
|
let tagged_file = lofty::read_from_path(path).map_err(|e| {
|
|
PinakesError::MetadataExtraction(format!("audio metadata: {e}"))
|
|
})?;
|
|
|
|
let mut meta = ExtractedMetadata::default();
|
|
|
|
if let Some(tag) = tagged_file
|
|
.primary_tag()
|
|
.or_else(|| tagged_file.first_tag())
|
|
{
|
|
meta.title = tag.title().map(|s| s.to_string());
|
|
meta.artist = tag.artist().map(|s| s.to_string());
|
|
meta.album = tag.album().map(|s| s.to_string());
|
|
meta.genre = tag.genre().map(|s| s.to_string());
|
|
meta.year = tag.date().map(|ts| i32::from(ts.year));
|
|
}
|
|
|
|
if let Some(tag) = tagged_file
|
|
.primary_tag()
|
|
.or_else(|| tagged_file.first_tag())
|
|
{
|
|
if let Some(track) = tag.track() {
|
|
meta
|
|
.extra
|
|
.insert("track_number".to_string(), track.to_string());
|
|
}
|
|
if let Some(disc) = tag.disk() {
|
|
meta
|
|
.extra
|
|
.insert("disc_number".to_string(), disc.to_string());
|
|
}
|
|
if let Some(comment) = tag.comment() {
|
|
meta
|
|
.extra
|
|
.insert("comment".to_string(), comment.to_string());
|
|
}
|
|
}
|
|
|
|
let properties = tagged_file.properties();
|
|
let duration = properties.duration();
|
|
if !duration.is_zero() {
|
|
meta.duration_secs = Some(duration.as_secs_f64());
|
|
}
|
|
|
|
if let Some(bitrate) = properties.audio_bitrate() {
|
|
meta
|
|
.extra
|
|
.insert("bitrate".to_string(), format!("{bitrate} kbps"));
|
|
}
|
|
if let Some(sample_rate) = properties.sample_rate() {
|
|
meta
|
|
.extra
|
|
.insert("sample_rate".to_string(), format!("{sample_rate} Hz"));
|
|
}
|
|
if let Some(channels) = properties.channels() {
|
|
meta
|
|
.extra
|
|
.insert("channels".to_string(), channels.to_string());
|
|
}
|
|
|
|
Ok(meta)
|
|
}
|
|
|
|
fn supported_types(&self) -> Vec<MediaType> {
|
|
vec![
|
|
MediaType::Builtin(BuiltinMediaType::Mp3),
|
|
MediaType::Builtin(BuiltinMediaType::Flac),
|
|
MediaType::Builtin(BuiltinMediaType::Ogg),
|
|
MediaType::Builtin(BuiltinMediaType::Wav),
|
|
MediaType::Builtin(BuiltinMediaType::Aac),
|
|
MediaType::Builtin(BuiltinMediaType::Opus),
|
|
]
|
|
}
|
|
}
|