diff --git a/Cargo.lock b/Cargo.lock index 64a539f..8f8971e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1232,6 +1232,17 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "id3" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3598f9ed06d8a7ff358dc1a52f07f98d6625b996ad60588805b3d8cfd4d0cd" +dependencies = [ + "bitflags", + "byteorder", + "flate2", +] + [[package]] name = "idna" version = "0.2.3" @@ -2894,6 +2905,7 @@ dependencies = [ "env_logger", "filebuffer", "futures-util", + "id3", "image", "is_executable", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 07bf4af..fb4d98d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,13 +69,21 @@ image = { version = "0.23.14", optional = true } webp = { version = "0.2.0", optional = true } webpage = { version = "1.4.0", optional = true } +id3 = { version = "1.0.2", optional = true } [build-dependencies] built = "0.5.1" [features] -default = ["desktop", "previews", "previews-image", 'extractors-web'] +default = [ + "desktop", + "previews", + "previews-image", + "extractors-web", + "extractors-audio", +] desktop = ["webbrowser", "opener", "is_executable"] previews = [] previews-image = ["image", "webp"] extractors-web = ["webpage"] +extractors-audio = ["id3"] diff --git a/src/extractors/audio.rs b/src/extractors/audio.rs index b6d7945..fe2d639 100644 --- a/src/extractors/audio.rs +++ b/src/extractors/audio.rs @@ -4,22 +4,59 @@ use crate::{ database::{entry::Entry, UpEndConnection}, util::jobs::{Job, JobContainer, State}, }; -use actix_web::web; use anyhow::{anyhow, Result}; -use async_trait::async_trait; -use std::sync::{Arc, Mutex, RwLock}; -use webpage::{Webpage, WebpageOptions}; +use std::sync::{Arc, RwLock}; pub struct ID3Extractor; -#[async_trait] impl Extractor for ID3Extractor { - async fn get( + fn get( &self, - address: Address, - connection: Arc>, + address: &Address, + connection: &UpEndConnection, job_container: Arc>, ) -> Result> { - todo!(); + if let Address::Hash(hash) = address { + let files = connection.retrieve_file(hash)?; + + if let Some(file) = files.get(0) { + let job_id = job_container + .write() + .unwrap() + .add_job(Job::new( + None, + &format!( + "Getting ID3 info from {:?}", + file.path.components().last().unwrap() + ), + )) + .unwrap(); + + let tags = id3::Tag::read_from_path(&file.path)?; + + let result: Vec = tags + .frames() + .filter_map(|frame| match frame.content() { + id3::Content::Text(text) => Some(Entry { + entity: address.clone(), + attribute: format!("ID3_{}", frame.id()), + value: text.clone().into(), + }), + _ => None, + }) + .collect(); + + let _ = job_container + .write() + .unwrap() + .update_state(&job_id, State::Done); + + Ok(result) + } else { + Err(anyhow!("Couldn't find file for {hash:?}!")) + } + } else { + Ok(vec![]) + } } } diff --git a/src/extractors/mod.rs b/src/extractors/mod.rs index dca9540..053b02d 100644 --- a/src/extractors/mod.rs +++ b/src/extractors/mod.rs @@ -9,10 +9,14 @@ use std::sync::{Arc, RwLock}; #[cfg(feature = "extractors-web")] pub mod web; +#[cfg(feature = "extractors-audio")] +pub mod audio; + pub trait Extractor { fn get( &self, address: &Address, + connection: &UpEndConnection, job_container: Arc>, ) -> Result>; @@ -25,18 +29,19 @@ pub trait Extractor { address: &Address, connection: &UpEndConnection, job_container: Arc>, - ) -> Result<()> { + ) -> Result { if self.is_needed(address, connection)? { - let entries = self.get(address, job_container)?; + let entries = self.get(address, connection, job_container)?; connection.transaction(|| { + let len = entries.len(); for entry in entries { connection.insert_entry(entry)?; } - Ok(()) + Ok(len) }) } else { - Ok(()) + Ok(0) } } -} +} \ No newline at end of file diff --git a/src/extractors/web.rs b/src/extractors/web.rs index af70a18..a1422fa 100644 --- a/src/extractors/web.rs +++ b/src/extractors/web.rs @@ -1,7 +1,7 @@ use super::Extractor; use crate::{ addressing::Address, - database::entry::Entry, + database::{entry::Entry, UpEndConnection}, util::jobs::{Job, JobContainer, State}, }; use anyhow::anyhow; @@ -15,6 +15,7 @@ impl Extractor for WebExtractor { fn get( &self, address: &Address, + _: &UpEndConnection, job_container: Arc>, ) -> anyhow::Result> { if let Address::Url(url) = address {