mirror of
https://github.com/Dangoware/dmp-core.git
synced 2025-04-19 13:22:54 -05:00
added function to show album art anf other small changes
This commit is contained in:
parent
7dcca94174
commit
c4c842e637
3 changed files with 95 additions and 11 deletions
|
@ -36,3 +36,6 @@ font = "0.27.0"
|
||||||
uuid = { version = "1.6.1", features = ["v4", "serde"]}
|
uuid = { version = "1.6.1", features = ["v4", "serde"]}
|
||||||
serde_json = "1.0.111"
|
serde_json = "1.0.111"
|
||||||
deunicode = "1.4.2"
|
deunicode = "1.4.2"
|
||||||
|
opener = { version = "0.7.0", features = ["reveal"]}
|
||||||
|
image = "0.25.0"
|
||||||
|
tempfile = "3.10.1"
|
||||||
|
|
|
@ -5,16 +5,19 @@ use crate::config::config::Config;
|
||||||
// Various std things
|
// Various std things
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::io::BufWriter;
|
||||||
use std::ops::ControlFlow::{Break, Continue};
|
use std::ops::ControlFlow::{Break, Continue};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
use file_format::{FileFormat, Kind};
|
use file_format::{FileFormat, Kind};
|
||||||
use glib::filename_to_uri;
|
use glib::filename_to_uri;
|
||||||
|
use image::guess_format;
|
||||||
use lofty::{AudioFile, ItemKey, ItemValue, ParseOptions, Probe, TagType, TaggedFileExt};
|
use lofty::{AudioFile, ItemKey, ItemValue, ParseOptions, Probe, TagType, TaggedFileExt};
|
||||||
use rcue::parser::parse_from_file;
|
use rcue::parser::parse_from_file;
|
||||||
|
use tempfile::tempfile;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::fs;
|
use std::fs::{self, OpenOptions};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
@ -158,6 +161,15 @@ pub struct Song {
|
||||||
pub tags: BTreeMap<Tag, String>,
|
pub tags: BTreeMap<Tag, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 {
|
impl Song {
|
||||||
/// Get a tag's value
|
/// Get a tag's value
|
||||||
///
|
///
|
||||||
|
@ -298,7 +310,7 @@ impl Song {
|
||||||
|
|
||||||
/// creates a `Vec<Song>` from a cue file
|
/// creates a `Vec<Song>` from a cue file
|
||||||
|
|
||||||
pub fn from_cue(cuesheet: &Path) -> Result<(Vec<(Self, PathBuf)>), Box<dyn Error>> {
|
pub fn from_cue(cuesheet: &Path) -> Result<Vec<(Self, PathBuf)>, Box<dyn Error>> {
|
||||||
let mut tracks = Vec::new();
|
let mut tracks = Vec::new();
|
||||||
|
|
||||||
let cue_data = parse_from_file(&cuesheet.to_string_lossy(), false).unwrap();
|
let cue_data = parse_from_file(&cuesheet.to_string_lossy(), false).unwrap();
|
||||||
|
@ -422,6 +434,71 @@ impl Song {
|
||||||
}
|
}
|
||||||
Ok(tracks)
|
Ok(tracks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_album_art(&self, index: usize) -> Result<(), Box<dyn Error>> {
|
||||||
|
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)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
@ -526,7 +603,7 @@ pub struct Album<'a> {
|
||||||
#[allow(clippy::len_without_is_empty)]
|
#[allow(clippy::len_without_is_empty)]
|
||||||
impl Album<'_> {
|
impl Album<'_> {
|
||||||
//returns the Album title
|
//returns the Album title
|
||||||
fn title(&self) -> &String {
|
pub fn title(&self) -> &String {
|
||||||
self.title
|
self.title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::any::Any;
|
||||||
use std::fs::{File, self};
|
use std::fs::{File, self};
|
||||||
use std::io::{BufReader, BufWriter};
|
use std::io::{BufReader, BufWriter};
|
||||||
|
use std::os::windows::fs::MetadataExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
@ -74,20 +76,22 @@ pub fn find_images(song_path: &Path) -> Result<Vec<AlbumArt>, Box<dyn Error>> {
|
||||||
.follow_links(true)
|
.follow_links(true)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
|
.filter(|e| e.depth() < 3) // Don't recurse very deep
|
||||||
{
|
{
|
||||||
if target_file.depth() >= 3 {
|
// println!("{:?}", target_file);
|
||||||
// Don't recurse very deep
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = target_file.path();
|
let path = target_file.path();
|
||||||
if !path.is_file() {
|
if !path.is_file() || !path.exists() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let format = FileFormat::from_file(path)?.kind();
|
let format = FileFormat::from_file(path)?.kind();
|
||||||
if format != Kind::Image {
|
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()?);
|
let image_uri = URI::Local(path.to_path_buf().canonicalize()?);
|
||||||
|
|
Loading…
Reference in a new issue