load metadata using lofty (shout out @Frieder_Hannenheim - you are #1)

This commit is contained in:
🪞👃🪞 2025-03-16 08:50:29 +02:00
parent 28f9220e6c
commit bc067e2739
4 changed files with 92 additions and 53 deletions

View file

@ -1,6 +1,11 @@
use crate::*;
use walkdir::DirEntry;
use id3::{Tag, TagLike};
use std::fs::File;
use std::io::{BufReader, Read};
use lofty::{
file::TaggedFileExt,
probe::Probe,
tag::Accessor,
};
pub struct Taggart {
pub _root: PathBuf,
@ -36,7 +41,7 @@ pub enum EntryInfo {
track: Option<u32>,
title: Option<Arc<str>>,
date: Option<Arc<str>>,
year: Option<i32>,
year: Option<u32>,
people: Option<Vec<Arc<str>>>,
publisher: Option<Arc<str>>,
key: Option<Arc<str>>,
@ -104,7 +109,7 @@ impl Entry {
Ok(None)
}
}
fn new_dir (root: &impl AsRef<Path>, path: &Path, depth: usize) -> Perhaps<Self> {
fn new_dir (_: &impl AsRef<Path>, path: &Path, depth: usize) -> Perhaps<Self> {
Ok(Some(Self {
depth,
path: path.into(),
@ -116,11 +121,11 @@ impl Entry {
},
}))
}
fn new_file (root: &impl AsRef<Path>, path: &Path, depth: usize) -> Perhaps<Self> {
fn new_file (_: &impl AsRef<Path>, path: &Path, depth: usize) -> Perhaps<Self> {
Ok(Some(Self {
depth,
info: EntryInfo::new(path)?,
path: path.into(),
info: EntryInfo::new(&read(path)?)?
}))
}
pub fn is_dir (&self) -> bool {
@ -165,19 +170,23 @@ impl Entry {
}
}
impl EntryInfo {
pub fn new (bytes: &[u8]) -> Usually<Self> {
// MP3 with ID3v2
if bytes.starts_with(&[b'I', b'D', b'3']) {
#[allow(deprecated)]
let id3 = Tag::read_from(bytes)?;
return Ok(Self::Music {
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),
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 hash = hex::encode(xxh3_64(std::fs::read(path)?.as_slice()).to_be_bytes()).into();
Ok(Self::Music {
hash,
file_type: None,
artist: id3.artist().map(|x|x.into()),
album: id3.album().map(|x|x.into()),
track: id3.track().map(|x|x.into()),
title: id3.title().map(|x|x.into()),
year: id3.year().map(|x|x.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,
@ -185,29 +194,18 @@ impl EntryInfo {
bpm: None,
invalid: false,
})
} else {
Self::new_fallback(path)
}
// Ogg (Opus)
if bytes.starts_with(&[b'O', b'g', b'g', b'S']) {
let headers = opus_headers::parse_from_read(bytes)?;
println!("{headers:?}");
return Ok(Self::Music {
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),
file_type: None,
artist: None,
album: None,
track: None,
title: None,
date: None,
year: None,
people: None,
publisher: None,
key: None,
bpm: None,
invalid: false,
})
}
}
pub fn new_fallback (path: &Path) -> Usually<Self> {
let mut reader = BufReader::new(File::open(path)?);
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 {
file_type: None,
hash: hex::encode(xxh3_64(&bytes).to_be_bytes()).into(),