diff --git a/Cargo.toml b/Cargo.toml index 76b0ba9..1673cfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,4 +30,5 @@ glib = "0.18.3" crossbeam-channel = "0.5.8" crossbeam = "0.8.2" quick-xml = "0.31.0" -leb128 = "0.2.5" \ No newline at end of file +leb128 = "0.2.5" +urlencoding = "2.1.3" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 32a8453..9981527 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,15 @@ pub mod music_storage { pub mod library; + pub mod music_collection; pub mod playlist; mod utils; - pub mod music_collection; pub mod db_reader { pub mod foobar { pub mod reader; } pub mod musicbee { - pub mod utils; pub mod reader; + pub mod utils; } pub mod xml { pub mod reader; diff --git a/src/music_player.rs b/src/music_player.rs index ecafff6..4c0ee19 100644 --- a/src/music_player.rs +++ b/src/music_player.rs @@ -191,7 +191,7 @@ impl Player { .unwrap() .set_state(gst::State::Playing) .unwrap(); - }, + } gst::MessageView::Buffering(buffering) => { let percent = buffering.percent(); if percent < 100 { diff --git a/src/music_storage/db_reader/common.rs b/src/music_storage/db_reader/common.rs index 80e0910..0849081 100644 --- a/src/music_storage/db_reader/common.rs +++ b/src/music_storage/db_reader/common.rs @@ -48,4 +48,4 @@ pub fn get_datetime(iterator: &mut std::vec::IntoIter, topbyte: bool) -> Dat Utc.timestamp_opt(unix_time_seconds, unix_time_nanos as u32) .unwrap() -} \ No newline at end of file +} diff --git a/src/music_storage/db_reader/extern_library.rs b/src/music_storage/db_reader/extern_library.rs index 5a0add5..dc5c306 100644 --- a/src/music_storage/db_reader/extern_library.rs +++ b/src/music_storage/db_reader/extern_library.rs @@ -2,7 +2,6 @@ use std::path::PathBuf; use crate::music_storage::library::Song; - pub trait ExternalLibrary { fn from_file(file: &PathBuf) -> Self; fn write(&self) { diff --git a/src/music_storage/db_reader/xml/reader.rs b/src/music_storage/db_reader/xml/reader.rs index de2a057..0b1689c 100644 --- a/src/music_storage/db_reader/xml/reader.rs +++ b/src/music_storage/db_reader/xml/reader.rs @@ -1,19 +1,26 @@ +use file_format::FileFormat; +use lofty::{AudioFile, LoftyError, ParseOptions, Probe, TagType, TaggedFileExt}; use quick_xml::events::Event; use quick_xml::reader::Reader; - use std::collections::{BTreeMap, HashMap}; +use std::fs::File; use std::io::Error; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::time::Duration as StdDur; use std::vec::Vec; use chrono::prelude::*; use crate::music_storage::db_reader::extern_library::ExternalLibrary; +use crate::music_storage::library::{AlbumArt, Service, Song, Tag, URI}; +use crate::music_storage::utils; + +use urlencoding::decode; #[derive(Debug, Default, Clone)] pub struct XmlLibrary { - tracks: Vec + tracks: Vec, } impl XmlLibrary { fn new() -> Self { @@ -21,7 +28,7 @@ impl XmlLibrary { } } impl ExternalLibrary for XmlLibrary { - fn from_file(&mut self, file: &PathBuf) -> Self { + fn from_file(file: &PathBuf) -> Self { let mut reader = Reader::from_file(file).unwrap(); reader.trim_text(true); //count every event, for fun ig? @@ -38,7 +45,6 @@ impl ExternalLibrary for XmlLibrary { let mut converted_songs: Vec = Vec::new(); - let mut song_tags: HashMap = HashMap::new(); let mut key: String = String::new(); let mut tagvalue: String = String::new(); @@ -78,7 +84,7 @@ impl ExternalLibrary for XmlLibrary { Ok(Event::Text(e)) => { if count < 17 && count != 10 { continue; - }else if skip { + } else if skip { skip = false; continue; } @@ -113,10 +119,140 @@ impl ExternalLibrary for XmlLibrary { let elasped = now.elapsed(); println!("\n\nXMLReader\n=========================================\n\nDone!\n{} songs grabbed in {:#?}\nIDs Skipped: {}", count3, elasped, count4); // dbg!(folder); - self.tracks.append(converted_songs.as_mut()); - self.clone() + let mut lib = XmlLibrary::new(); + lib.tracks.append(converted_songs.as_mut()); + lib + } + fn to_songs(&self) -> Vec { + let mut count = 0; + let mut bun: Vec = Vec::new(); + for track in &self.tracks { + //grab "other" tags + let mut tags_: BTreeMap = BTreeMap::new(); + for (key, val) in &track.tags { + tags_.insert(to_tag(key.clone()), val.clone()); + } + //make the path readable + let loc_ = if track.location.contains("file://localhost/") { + decode(track.location.strip_prefix("file://localhost/").unwrap()) + .unwrap() + .into_owned() + } else { + decode(track.location.as_str()).unwrap().into_owned() + }; + let loc = loc_.as_str(); + if File::open(loc).is_err() && !loc.contains("http") { + count += 1; + dbg!(loc); + continue; + } + + let sug: URI = if track.location.contains("file://localhost/") { + URI::Local(PathBuf::from( + decode(track.location.strip_prefix("file://localhost/").unwrap()) + .unwrap() + .into_owned() + .as_str(), + )) + } else { + URI::Remote(Service::None, decode(&track.location).unwrap().into_owned()) + }; + let dur = match get_duration(Path::new(&loc)) { + Ok(e) => e, + Err(e) => { + dbg!(e); + StdDur::from_secs(0) + } + }; + let play_time_ = StdDur::from_secs(track.plays as u64 * dur.as_secs()); + + let ny: Song = Song { + location: sug, + plays: track.plays, + skips: 0, + favorited: track.favorited, + rating: track.rating, + format: match FileFormat::from_file(PathBuf::from(&loc)) { + Ok(e) => Some(e), + Err(_) => None, + }, + duration: dur, + play_time: play_time_, + last_played: track.last_played, + date_added: track.date_added, + date_modified: track.date_modified, + album_art: match get_art(Path::new(&loc)) { + Ok(e) => e, + Err(_) => Vec::new(), + }, + tags: tags_, + }; + // dbg!(&ny.tags); + bun.push(ny); + } + println!("skipped: {}", count); + bun } } +fn to_tag(string: String) -> Tag { + match string.to_lowercase().as_str() { + "name" => Tag::Title, + "album" => Tag::Album, + "artist" => Tag::Artist, + "album artist" => Tag::AlbumArtist, + "genre" => Tag::Genre, + "comment" => Tag::Comment, + "track" => Tag::Track, + "disc" => Tag::Disk, + _ => Tag::Key(string), + } +} +fn get_duration(file: &Path) -> Result { + let dur = match Probe::open(file)?.read() { + Ok(tagged_file) => tagged_file.properties().duration(), + + Err(_) => StdDur::from_secs(0), + }; + Ok(dur) +} +fn get_art(file: &Path) -> Result, LoftyError> { + let mut album_art: Vec = Vec::new(); + + let blank_tag = &lofty::Tag::new(TagType::Id3v2); + let normal_options = ParseOptions::new().parsing_mode(lofty::ParsingMode::Relaxed); + let tagged_file: lofty::TaggedFile; + + let tag = match Probe::open(file)?.options(normal_options).read() { + Ok(e) => { + tagged_file = e; + 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 mut img = match utils::find_images(file) { + Ok(e) => e, + Err(_) => Vec::new(), + }; + if !img.is_empty() { + album_art.append(img.as_mut()); + } + + for (i, _art) in tag.pictures().iter().enumerate() { + let new_art = AlbumArt::Embedded(i); + + album_art.push(new_art) + } + + Ok(album_art) +} + #[derive(Debug, Clone, Default)] pub struct XMLSong { pub id: i32, @@ -138,8 +274,7 @@ impl XMLSong { Default::default() } - - fn from_hashmap(map: &mut HashMap) -> Result { + fn from_hashmap(map: &mut HashMap) -> Result { let mut song = XMLSong::new(); //get the path with the first bit chopped off let path_: String = map.get_key_value("Location").unwrap().1.clone(); @@ -188,8 +323,7 @@ impl XMLSong { } } - -pub fn get_folder(file: &PathBuf) -> String { +fn get_folder(file: &PathBuf) -> String { let mut reader = Reader::from_file(file).unwrap(); reader.trim_text(true); //count every event, for fun ig? diff --git a/src/music_storage/library.rs b/src/music_storage/library.rs index d264bdf..99b8bb5 100644 --- a/src/music_storage/library.rs +++ b/src/music_storage/library.rs @@ -275,7 +275,6 @@ impl Album<'_> { self.artist } - pub fn discs(&self) -> &BTreeMap> { &self.discs } diff --git a/src/music_storage/music_collection.rs b/src/music_storage/music_collection.rs index 8abcd71..9b1c7ca 100644 --- a/src/music_storage/music_collection.rs +++ b/src/music_storage/music_collection.rs @@ -1,8 +1,7 @@ -use crate::music_storage::library::{ AlbumArt, Song }; +use crate::music_storage::library::{AlbumArt, Song}; pub trait MusicCollection { fn title(&self) -> &String; fn cover(&self) -> Option<&AlbumArt>; fn tracks(&self) -> Vec<&Song>; } - diff --git a/src/music_storage/playlist.rs b/src/music_storage/playlist.rs index 710e6fd..ce4366d 100644 --- a/src/music_storage/playlist.rs +++ b/src/music_storage/playlist.rs @@ -2,9 +2,12 @@ use chrono::Duration; use walkdir::Error; use crate::music_controller::config::Config; -use std::{path::Path, default, thread::AccessError}; +use std::{default, path::Path, thread::AccessError}; -use super::{library::{AlbumArt, Song, self, Tag}, music_collection::MusicCollection}; +use super::{ + library::{self, AlbumArt, Song, Tag}, + music_collection::MusicCollection, +}; #[derive(Debug, Clone)] pub struct Playlist<'a> { @@ -48,7 +51,7 @@ impl<'a> Playlist<'a> { for track in &self.tracks { index += 1; if song_name == track.tags.get_key_value(&Tag::Title).unwrap().1 { - dbg!("Index gotted! ",index); + dbg!("Index gotted! ", index); return Some(index); } } @@ -75,17 +78,17 @@ impl MusicCollection for Playlist<'_> { } } fn tracks(&self) -> Vec<&Song> { - self.tracks.clone() + self.tracks.clone() } } impl Default for Playlist<'_> { fn default() -> Self { - Playlist { - title: String::default(), - cover: None, - tracks: Vec::default(), - play_count: -1, - play_time: Duration::zero(), + Playlist { + title: String::default(), + cover: None, + tracks: Vec::default(), + play_count: -1, + play_time: Duration::zero(), } } -} \ No newline at end of file +}