mirror of
https://codeberg.org/unspeaker/perch.git
synced 2025-12-07 10:06:44 +01:00
refactor; EntryInfo -> Metadata
This commit is contained in:
parent
95aa9f8b02
commit
cf18e32e13
5 changed files with 384 additions and 351 deletions
185
src/model/metadata.rs
Normal file
185
src/model/metadata.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
use crate::*;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use lofty::{file::TaggedFileExt, probe::Probe, tag::Accessor};
|
||||
use byte_unit::{Byte, Unit::MB};
|
||||
|
||||
#[derive(Ord, Eq, PartialEq, PartialOrd, Debug)]
|
||||
pub enum Metadata {
|
||||
Directory {
|
||||
hash_file: Option<()>,
|
||||
catalog_file: Option<()>,
|
||||
artist_file: Option<()>,
|
||||
release_file: Option<()>,
|
||||
},
|
||||
Music {
|
||||
hash: Arc<str>,
|
||||
size: Arc<str>,
|
||||
artist: Option<Arc<str>>,
|
||||
album: Option<Arc<str>>,
|
||||
track: Option<u32>,
|
||||
title: Option<Arc<str>>,
|
||||
date: Option<Arc<str>>,
|
||||
year: Option<u32>,
|
||||
people: Option<Vec<Arc<str>>>,
|
||||
publisher: Option<Arc<str>>,
|
||||
key: Option<Arc<str>>,
|
||||
bpm: Option<Arc<str>>,
|
||||
invalid: bool,
|
||||
},
|
||||
Image {
|
||||
hash: Arc<str>,
|
||||
size: Arc<str>,
|
||||
title: Option<String>,
|
||||
author: Option<String>,
|
||||
invalid: bool,
|
||||
},
|
||||
Unknown {
|
||||
hash: Arc<str>,
|
||||
size: Arc<str>,
|
||||
}
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn new (path: &Path) -> Usually<Self> {
|
||||
let reader = BufReader::new(File::open(path)?);
|
||||
let probe = Probe::new(reader)
|
||||
//.options(ParseOptions::new().parsing_mode(ParsingMode::Strict))
|
||||
.guess_file_type()?;
|
||||
if probe.file_type().is_some() {
|
||||
let file = lofty::read_from_path(path)?;
|
||||
let tag = file.primary_tag();
|
||||
let data = std::fs::read(path)?;
|
||||
let hash = hex::encode(xxh3_64(data.as_slice()).to_be_bytes()).into();
|
||||
let size = Byte::from_u64(data.len() as u64).get_adjusted_unit(MB);
|
||||
Ok(Self::Music {
|
||||
hash,
|
||||
size: format!("{:#>8.2}", size).into(),
|
||||
artist: tag.map(|t|t.artist().map(|t|t.into())).flatten(),
|
||||
album: tag.map(|t|t.album().map(|t|t.into())).flatten(),
|
||||
track: tag.map(|t|t.track().map(|t|t.into())).flatten(),
|
||||
title: tag.map(|t|t.title().map(|t|t.into())).flatten(),
|
||||
year: tag.map(|t|t.year().map(|t|t.into())).flatten(),
|
||||
date: None,
|
||||
people: None,
|
||||
publisher: None,
|
||||
key: None,
|
||||
bpm: None,
|
||||
invalid: false,
|
||||
})
|
||||
} else {
|
||||
Self::new_fallback(path)
|
||||
}
|
||||
}
|
||||
pub fn new_fallback (path: &Path) -> Usually<Self> {
|
||||
let file = File::open(path)?;
|
||||
let size = Byte::from_u64(file.metadata()?.len() as u64).get_adjusted_unit(MB);
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut bytes = vec![0;16];
|
||||
reader.read(&mut bytes)?;
|
||||
// PNG
|
||||
if bytes.starts_with(&[0x89, b'P', b'N', b'G', 0x0D, 0x0A, 0x1A, 0x0A]) {
|
||||
let mut bytes = vec![];
|
||||
BufReader::new(File::open(path)?).read(&mut bytes)?;
|
||||
return Ok(Self::Image {
|
||||
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),
|
||||
size: format!("{:#>8.2}", size).into(),
|
||||
title: None,
|
||||
author: None,
|
||||
invalid: false,
|
||||
})
|
||||
}
|
||||
// JPG
|
||||
if bytes.starts_with(&[0xFF, 0xD8, 0xFF, 0xDB])
|
||||
|| bytes.starts_with(&[0xFF, 0xD8, 0xFF, 0xE0,
|
||||
0x00, 0x10, 0x4A, 0x46,
|
||||
0x49, 0x46, 0x00, 0x01])
|
||||
|| bytes.starts_with(&[0xFF, 0xD8, 0xFF, 0xEE])
|
||||
|| (bytes.starts_with(&[0xFF, 0xD8, 0xFF, 0xE1]) &&
|
||||
bytes.get(6) == Some(&0x45) && bytes.get(7) == Some(&0x78) &&
|
||||
bytes.get(8) == Some(&0x69) && bytes.get(9) == Some(&0x66) &&
|
||||
bytes.get(10) == Some(&0x00) && bytes.get(11) == Some(&0x00))
|
||||
{
|
||||
return Ok(Self::Image {
|
||||
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),
|
||||
size: format!("{:#>8.2}", size).into(),
|
||||
title: None,
|
||||
author: None,
|
||||
invalid: false,
|
||||
})
|
||||
}
|
||||
Ok(Self::Unknown {
|
||||
size: format!("{:#>8.2}", size).into(),
|
||||
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),
|
||||
})
|
||||
}
|
||||
pub fn hash (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Image { hash, .. } => Some(hash.clone()),
|
||||
Metadata::Music { hash, .. } => Some(hash.clone()),
|
||||
Metadata::Unknown { hash, .. } => Some(hash.clone()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn size (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Image { size, .. } => Some(size.clone()),
|
||||
Metadata::Music { size, .. } => Some(size.clone()),
|
||||
Metadata::Unknown { size, .. } => Some(size.clone()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn artist (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Music { artist, .. } => artist.clone(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn album (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Music { album, .. } => album.clone(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn title (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Music { title, .. } => title.clone(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn track (&self) -> Option<Arc<str>> {
|
||||
match self {
|
||||
Metadata::Music { track, .. } => track.map(|t|format!("{t}").into()).clone(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
pub fn set_artist (&mut self, value: &impl AsRef<str> ) {
|
||||
match self {
|
||||
Metadata::Music { artist, .. } => *artist = Some(value.as_ref().into()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn set_album (&mut self, value: &impl AsRef<str> ) {
|
||||
match self {
|
||||
Metadata::Music { album, .. } => *album = Some(value.as_ref().into()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn set_title (&mut self, value: &impl AsRef<str> ) {
|
||||
match self {
|
||||
Metadata::Music { title, .. } => *title = Some(value.as_ref().into()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn set_track (&mut self, value: &impl AsRef<str> ) {
|
||||
match self {
|
||||
Metadata::Directory { .. } => todo!("set track for whole directory"),
|
||||
Metadata::Music { track, .. } => {
|
||||
if let Ok(value) = value.as_ref().trim().parse::<u32>() {
|
||||
*track = Some(value)
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue