use std::time::Duration;
use lofty::{
file::{AudioFile, TaggedFile, TaggedFileExt},
tag::{Accessor, Tag, items::Timestamp},
};
use crate::{Metadata, MetadataError};
pub fn extract_metadata(file_path: &str) -> Result<Metadata, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
let metadata = match extract_tag(file_path) {
Ok(t) => Metadata {
title: extract_title(&t),
artist: extract_artist(&t),
album: extract_album(&t),
time_stamp: extract_time_stamp(&t),
genre: extract_genre(&t),
cover: extract_cover(&t),
duration: extract_duration(&file),
sample_rate: extract_sample_rate(&file),
channels: extract_channels(&file),
has_tag: true,
},
Err(_) => Metadata {
title: None,
artist: None,
album: None,
time_stamp: None,
genre: None,
cover: None,
duration: extract_duration(&file),
sample_rate: extract_sample_rate(&file),
channels: extract_channels(&file),
has_tag: false,
},
};
Ok(metadata)
}
pub fn extract_tag(file_path: &str) -> Result<Tag, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
if let Some(tag) = file.primary_tag().or_else(|| file.first_tag()) {
Ok(tag.clone())
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_title(tag: &Tag) -> Option<String> {
tag.title().map(|t| t.to_string())
}
pub fn extract_artist(tag: &Tag) -> Option<String> {
tag.artist().map(|a| a.to_string())
}
pub fn extract_album(tag: &Tag) -> Option<String> {
tag.album().map(|a| a.to_string())
}
pub fn extract_time_stamp(tag: &Tag) -> Option<Timestamp> {
tag.date()
}
pub fn extract_genre(tag: &Tag) -> Option<String> {
tag.genre().map(|g| g.to_string())
}
pub fn extract_cover(tag: &Tag) -> Option<Vec<u8>> {
if let Some(cover) = tag.pictures().first() {
Some(cover.data().to_vec())
} else {
None
}
}
pub fn extract_sample_rate(file: &TaggedFile) -> Option<u32> {
file.properties().sample_rate()
}
pub fn extract_duration(file: &TaggedFile) -> Duration {
file.properties().duration()
}
pub fn extract_channels(file: &TaggedFile) -> Option<u8> {
file.properties().channels()
}
pub fn extract_bitrate(file: &TaggedFile) -> Option<u32> {
file.properties().audio_bitrate()
}