upend/src/extractors/audio.rs

92 lines
3.0 KiB
Rust

use std::sync::Arc;
use super::Extractor;
use crate::{
addressing::Address,
database::{
constants,
entry::{Entry, EntryValue},
stores::{fs::FILE_MIME_KEY, UpStore},
UpEndConnection,
},
util::jobs::{JobContainer, JobState},
};
use anyhow::{anyhow, Result};
pub struct ID3Extractor;
impl Extractor for ID3Extractor {
fn get(
&self,
address: &Address,
connection: &UpEndConnection,
store: Arc<Box<dyn UpStore + Send + Sync>>,
mut job_container: JobContainer,
) -> Result<Vec<Entry>> {
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 = store.retrieve(hash)?;
if let Some(file) = files.get(0) {
let file_path = file.get_file_path();
let mut job_handle = job_container.add_job(
None,
&format!(
r#"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<Entry> = 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![])
}
}
}