use super::Extractor; use crate::{ addressing::Address, database::{ constants, entry::{Entry, EntryValue}, UpEndConnection, }, filesystem::FILE_MIME_KEY, util::jobs::{JobContainer, JobState}, }; use anyhow::{anyhow, Result}; pub struct ID3Extractor; impl Extractor for ID3Extractor { fn get( &self, address: &Address, connection: &UpEndConnection, mut job_container: JobContainer, ) -> Result> { if let Address::Hash(hash) = address { let is_audio = connection.retrieve_object(address)?.iter().any(|e| { if e.attribute == FILE_MIME_KEY { if let EntryValue::String(mime) = &e.value { return mime.starts_with("audio") || mime == "application/x-riff"; } } false }); if !is_audio { return Ok(vec![]); } let files = connection.retrieve_file(hash)?; if let Some(file) = files.get(0) { let mut job_handle = job_container.add_job( None, &format!( "Getting ID3 info from \"{:}\"", file.path .components() .last() .unwrap() .as_os_str() .to_string_lossy() ), )?; let tags = id3::Tag::read_from_path(&file.path)?; let result: Vec = tags .frames() .flat_map(|frame| match frame.content() { id3::Content::Text(text) => vec![ Entry { entity: address.clone(), attribute: format!("ID3_{}", frame.id()), value: match frame.id() { "TYER" | "TBPM" => EntryValue::guess_from(text), _ => text.clone().into(), }, }, Entry { entity: Address::Attribute(format!("ID3_{}", frame.id())), attribute: constants::LABEL_ATTR.into(), value: format!("ID3: {}", frame.name()).into(), }, ], _ => vec![], }) .collect(); let _ = job_handle.update_state(JobState::Done); Ok(result) } else { Err(anyhow!("Couldn't find file for {hash:?}!")) } } else { Ok(vec![]) } } }