edar 1.0.0

A tool to extract metadata from an audio file
Documentation
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)
    }
}