use std::time::Duration;
use lofty::{
file::{AudioFile, TaggedFileExt},
tag::Accessor,
};
use crate::{Metadata, 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 properties = file.properties();
let tag = file.primary_tag().or_else(|| file.first_tag());
let metadata = if let Some(tag) = tag {
let picture = tag.pictures().first().map(|p| p.data().to_vec());
Metadata {
title: tag.title().map(|t| t.to_string()),
artist: tag.artist().map(|a| a.to_string()),
album: tag.album().map(|a| a.to_string()),
year: tag.year().map(|y| y.to_string()),
genre: tag.genre().map(|g| g.to_string()),
cover: picture,
duration: Some(properties.duration()),
sample_rate: properties.sample_rate(),
channels: properties.channels(),
has_tag: true,
}
} else {
Metadata {
title: None,
artist: None,
album: None,
year: None,
genre: None,
cover: None,
duration: Some(properties.duration()),
sample_rate: properties.sample_rate(),
channels: properties.channels(),
has_tag: false,
}
};
Ok(metadata)
}
pub fn extract_title(file_path: &str) -> Result<String, 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()) {
if let Some(title) = tag.title().map(|t| t.to_string()) {
Ok(title)
} else {
Err(MetadataError::NoTitle)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_artist(file_path: &str) -> Result<String, 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()) {
if let Some(artist) = tag.artist().map(|a| a.to_string()) {
Ok(artist)
} else {
Err(MetadataError::NoArtist)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_album(file_path: &str) -> Result<String, 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()) {
if let Some(album) = tag.album().map(|a| a.to_string()) {
Ok(album)
} else {
Err(MetadataError::NoAlbum)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_year(file_path: &str) -> Result<String, 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()) {
if let Some(year) = tag.year().map(|y| y.to_string()) {
Ok(year)
} else {
Err(MetadataError::NoYear)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_genre(file_path: &str) -> Result<String, 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()) {
if let Some(genre) = tag.genre().map(|g| g.to_string()) {
Ok(genre)
} else {
Err(MetadataError::NoGenre)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_cover(file_path: &str) -> Result<Vec<u8>, 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()) {
if let Some(cover) = tag.pictures().first() {
Ok(cover.data().to_vec())
} else {
Err(MetadataError::NoCover)
}
} else {
Err(MetadataError::NoTag)
}
}
pub fn extract_duration(file_path: &str) -> Result<Duration, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
let properties = file.properties();
Ok(properties.duration())
}
pub fn extract_sample_rate(file_path: &str) -> Result<u32, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
let properties = file.properties();
if let Some(sample_rate) = properties.sample_rate() {
Ok(sample_rate)
} else {
Err(MetadataError::NoSampleRate)
}
}
pub fn extract_channels(file_path: &str) -> Result<u8, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
let properties = file.properties();
if let Some(channels) = properties.channels() {
Ok(channels)
} else {
Err(MetadataError::NoChannels)
}
}
pub fn extract_bitrate(file_path: &str) -> Result<u32, MetadataError> {
let file = lofty::read_from_path(file_path).map_err(|_| MetadataError::ReadError)?;
let properties = file.properties();
if let Some(bitrate) = properties.audio_bitrate() {
Ok(bitrate)
} else {
Err(MetadataError::NoBitrate)
}
}