diff --git a/Cargo.toml b/Cargo.toml index 0267611..a3c737b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,6 @@ font = "0.27.0" uuid = { version = "1.6.1", features = ["v4", "serde"]} serde_json = "1.0.111" deunicode = "1.4.2" +opener = { version = "0.7.0", features = ["reveal"]} +image = "0.25.0" +tempfile = "3.10.1" diff --git a/src/music_storage/library.rs b/src/music_storage/library.rs index 9915682..f91b590 100644 --- a/src/music_storage/library.rs +++ b/src/music_storage/library.rs @@ -5,16 +5,19 @@ use crate::config::config::Config; // Various std things use std::collections::BTreeMap; use std::error::Error; +use std::io::BufWriter; use std::ops::ControlFlow::{Break, Continue}; use std::ops::Deref; // Files use file_format::{FileFormat, Kind}; use glib::filename_to_uri; +use image::guess_format; use lofty::{AudioFile, ItemKey, ItemValue, ParseOptions, Probe, TagType, TaggedFileExt}; use rcue::parser::parse_from_file; +use tempfile::tempfile; use uuid::Uuid; -use std::fs; +use std::fs::{self, OpenOptions}; use std::path::{Path, PathBuf}; use walkdir::WalkDir; @@ -158,6 +161,15 @@ pub struct Song { pub tags: BTreeMap, } +#[test] +fn get_art_test() { + use urlencoding::decode; + + let s = Song::from_file(Path::new("F:\\Music\\Mp3\\ななひら\\Colory Starry\\05 - Fly Away!.mp3")).unwrap(); + s.open_album_art(0).inspect_err(|e| println!("{e:?}")); + +} + impl Song { /// Get a tag's value /// @@ -298,7 +310,7 @@ impl Song { /// creates a `Vec` from a cue file - pub fn from_cue(cuesheet: &Path) -> Result<(Vec<(Self, PathBuf)>), Box> { + pub fn from_cue(cuesheet: &Path) -> Result, Box> { let mut tracks = Vec::new(); let cue_data = parse_from_file(&cuesheet.to_string_lossy(), false).unwrap(); @@ -422,6 +434,71 @@ impl Song { } Ok(tracks) } + + pub fn open_album_art(&self, index: usize) -> Result<(), Box> { + use opener::open; + use urlencoding::decode; + + if index >= self.album_art.len() { + return Err("index out of bounds?".into()); + } + + let uri: String = match &self.album_art[index] { + AlbumArt::External(uri) => { + decode(match uri.as_uri().strip_prefix("file:///") { Some(e) => e, None => return Err("Invalid path?".into()) })?.into_owned() + }, + AlbumArt::Embedded(_) => { + + let normal_options = ParseOptions::new().parsing_mode(lofty::ParsingMode::Relaxed); + let blank_tag = &lofty::Tag::new(TagType::Id3v2); + let tagged_file: lofty::TaggedFile; + + let uri = dbg!(urlencoding::decode(self.location.as_uri().strip_prefix("file:///").unwrap())?.into_owned()); + + let tag = match Probe::open(uri)?.options(normal_options).read() { + Ok(file) => { + tagged_file = file; + + match tagged_file.primary_tag() { + Some(primary_tag) => primary_tag, + + None => match tagged_file.first_tag() { + Some(first_tag) => first_tag, + None => blank_tag, + }, + } + } + + Err(_) => blank_tag, + }; + + let data = tag.pictures()[index].data(); + let format = dbg!(guess_format(data)?); + let img = image::load_from_memory(data)?; + + let mut location = String::new(); + let i: u32 = 0; + loop { + use image::ImageFormat::*; + //TODO: create a place for temporary images + let fmt = match format { + Jpeg => "jpeg", + Png => "png", + _ => todo!(), + }; + + location = format!("./test-config/images/tempcover{i}.{fmt}.tmp"); + break; + }; + img.save_with_format(&location, format)?; + + location.to_string() + }, + }; + open(uri)?; + + Ok(()) + } } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -526,7 +603,7 @@ pub struct Album<'a> { #[allow(clippy::len_without_is_empty)] impl Album<'_> { //returns the Album title - fn title(&self) -> &String { + pub fn title(&self) -> &String { self.title } @@ -1060,4 +1137,4 @@ impl MusicLibrary { Ok(albums) } -} +} \ No newline at end of file diff --git a/src/music_storage/utils.rs b/src/music_storage/utils.rs index 0d6fb47..9d832e1 100644 --- a/src/music_storage/utils.rs +++ b/src/music_storage/utils.rs @@ -1,5 +1,7 @@ +use std::any::Any; use std::fs::{File, self}; use std::io::{BufReader, BufWriter}; +use std::os::windows::fs::MetadataExt; use std::path::{Path, PathBuf}; use std::error::Error; @@ -74,20 +76,22 @@ pub fn find_images(song_path: &Path) -> Result, Box> { .follow_links(true) .into_iter() .filter_map(|e| e.ok()) + .filter(|e| e.depth() < 3) // Don't recurse very deep { - if target_file.depth() >= 3 { - // Don't recurse very deep - break; - } - + // println!("{:?}", target_file); let path = target_file.path(); - if !path.is_file() { + if !path.is_file() || !path.exists() { continue; } let format = FileFormat::from_file(path)?.kind(); if format != Kind::Image { - break; + continue; + } + + #[cfg(target_family = "windows")] + if (4 & path.metadata().unwrap().file_attributes()) == 4 { + continue; } let image_uri = URI::Local(path.to_path_buf().canonicalize()?);