add ID3 metadata extractor
parent
920e67a283
commit
506727356c
|
@ -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",
|
||||
|
|
10
Cargo.toml
10
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"]
|
||||
|
|
|
@ -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<Mutex<UpEndConnection>>,
|
||||
address: &Address,
|
||||
connection: &UpEndConnection,
|
||||
job_container: Arc<RwLock<JobContainer>>,
|
||||
) -> Result<Vec<Entry>> {
|
||||
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<Entry> = 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![])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RwLock<JobContainer>>,
|
||||
) -> Result<Vec<Entry>>;
|
||||
|
||||
|
@ -25,18 +29,19 @@ pub trait Extractor {
|
|||
address: &Address,
|
||||
connection: &UpEndConnection,
|
||||
job_container: Arc<RwLock<JobContainer>>,
|
||||
) -> Result<()> {
|
||||
) -> Result<usize> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<RwLock<JobContainer>>,
|
||||
) -> anyhow::Result<Vec<Entry>> {
|
||||
if let Address::Url(url) = address {
|
||||
|
|
Loading…
Reference in New Issue