Can query by URI now

This commit is contained in:
G2-Games 2023-10-03 20:00:13 -05:00
parent bde2d194dc
commit 140bae703a
2 changed files with 51 additions and 25 deletions

View file

@ -79,8 +79,9 @@ impl MusicController {
&self, &self,
query_string: &String, query_string: &String,
target_tags: Vec<Tag>, target_tags: Vec<Tag>,
search_location: bool,
sort_by: Vec<Tag> sort_by: Vec<Tag>
) -> Option<Vec<&Song>> { ) -> Option<Vec<&Song>> {
self.library.query(query_string, &target_tags, &sort_by) self.library.query(query_string, &target_tags, search_location, &sort_by)
} }
} }

View file

@ -1,5 +1,6 @@
use file_format::{FileFormat, Kind}; use file_format::{FileFormat, Kind};
use lofty::{AudioFile, ItemKey, ItemValue, Probe, TagType, TaggedFileExt}; use lofty::{AudioFile, ItemKey, ItemValue, Probe, TagType, TaggedFileExt};
use std::any::Any;
use std::{error::Error, io::BufReader}; use std::{error::Error, io::BufReader};
use chrono::{serde::ts_seconds_option, DateTime, Utc}; use chrono::{serde::ts_seconds_option, DateTime, Utc};
@ -15,7 +16,6 @@ use unidecode::unidecode;
// Fun parallel stuff // Fun parallel stuff
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use rayon::iter;
use rayon::prelude::*; use rayon::prelude::*;
use crate::music_controller::config::Config; use crate::music_controller::config::Config;
@ -35,20 +35,22 @@ pub enum Tag {
Comment, Comment,
Track, Track,
Disk, Disk,
Key(String) Key(String),
Field(String)
} }
impl ToString for Tag { impl ToString for Tag {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
Self::Title => "TrackTitle".into(), Self::Title => "TrackTitle".into(),
Self::Album => "AlbumTitle".into(), Self::Album => "AlbumTitle".into(),
Self::Artist => "TrackArtist".into(), Self::Artist => "TrackArtist".into(),
Self::Genre => "Genre".into(), Self::Genre => "Genre".into(),
Self::Comment => "Comment".into(), Self::Comment => "Comment".into(),
Self::Track => "TrackNumber".into(), Self::Track => "TrackNumber".into(),
Self::Disk => "DiscNumber".into(), Self::Disk => "DiscNumber".into(),
Self::Key(key) => key.into() Self::Key(key) => key.into(),
Self::Field(f) => f.into()
} }
} }
} }
@ -95,17 +97,12 @@ impl Song {
} }
} }
pub fn get_tags(&self, target_keys: &Vec<String>) -> Vec<Option<String>> { pub fn get_field(&self, target_field: &str) -> Box<dyn Any> {
let mut results = Vec::new(); match target_field {
for tag in &self.tags { "location" => Box::new(self.location.clone()),
for key in target_keys { "plays" => Box::new(self.plays.clone()),
if &tag.0.to_string() == key { _ => todo!()
results.push(Some(tag.1.to_owned()))
}
}
results.push(None);
} }
results
} }
} }
@ -116,6 +113,15 @@ pub enum URI {
Remote(Service, String), Remote(Service, String),
} }
impl ToString for URI {
fn to_string(&self) -> String {
match self {
URI::Local(location) => location.to_string(),
URI::Remote(_, location) => location.to_string()
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum Service { pub enum Service {
InternetRadio, InternetRadio,
@ -142,7 +148,7 @@ pub struct MusicLibrary {
} }
pub fn normalize(input_string: &String) -> String { pub fn normalize(input_string: &String) -> String {
unidecode(input_string).to_ascii_lowercase().replace(|c: char| !c.is_alphanumeric() && !c.is_ascii_punctuation(), "") unidecode(input_string).to_ascii_lowercase().replace(|c: char| !c.is_alphanumeric(), "")
} }
impl MusicLibrary { impl MusicLibrary {
@ -207,7 +213,9 @@ impl MusicLibrary {
Ok(()) Ok(())
} }
fn find_by_uri(&self, path: &URI) -> Option<Song> { /// Queries for a [Song] by its [URI], returning a single Song
/// with the URI that matches
fn query_by_uri(&self, path: &URI) -> Option<Song> {
for track in &self.library { for track in &self.library {
if path == &track.location { if path == &track.location {
return Some(track.clone()); return Some(track.clone());
@ -348,14 +356,14 @@ impl MusicLibrary {
match self.add_song_to_db(new_song) { match self.add_song_to_db(new_song) {
Ok(_) => (), Ok(_) => (),
Err(error) => () Err(_error) => ()
}; };
Ok(()) Ok(())
} }
pub fn add_song_to_db(&mut self, new_song: Song) -> Result<(), Box<dyn std::error::Error>> { pub fn add_song_to_db(&mut self, new_song: Song) -> Result<(), Box<dyn std::error::Error>> {
match self.find_by_uri(&new_song.location) { match self.query_by_uri(&new_song.location) {
Some(_) => return Err(format!("URI already in database: {:?}", new_song.location).into()), Some(_) => return Err(format!("URI already in database: {:?}", new_song.location).into()),
None => () None => ()
} }
@ -366,7 +374,7 @@ impl MusicLibrary {
} }
pub fn update_song_tags(&mut self, new_tags: Song) -> Result<(), Box<dyn std::error::Error>> { pub fn update_song_tags(&mut self, new_tags: Song) -> Result<(), Box<dyn std::error::Error>> {
match self.find_by_uri(&new_tags.location) { match self.query_by_uri(&new_tags.location) {
Some(_) => (), Some(_) => (),
None => return Err(format!("URI not in database!").into()) None => return Err(format!("URI not in database!").into())
} }
@ -379,6 +387,7 @@ impl MusicLibrary {
&self, &self,
query_string: &String, // The query itself query_string: &String, // The query itself
target_tags: &Vec<Tag>, // The tags to search target_tags: &Vec<Tag>, // The tags to search
search_location: bool, // Whether to search the location field or not
sort_by: &Vec<Tag>, // Tags to sort the resulting data by sort_by: &Vec<Tag>, // Tags to sort the resulting data by
) -> Option<Vec<&Song>> { ) -> Option<Vec<&Song>> {
let songs = Arc::new(Mutex::new(Vec::new())); let songs = Arc::new(Mutex::new(Vec::new()));
@ -391,9 +400,25 @@ impl MusicLibrary {
if normalize(&tag.1).contains(&normalize(&query_string)) { if normalize(&tag.1).contains(&normalize(&query_string)) {
songs.lock().unwrap().push(track); songs.lock().unwrap().push(track);
break return
} }
} }
if !search_location {
return
}
// Find a URL in the song
match &track.location {
URI::Local(path) if normalize(&path).contains(&normalize(&query_string)) => {
songs.lock().unwrap().push(track);
return
},
URI::Remote(_, path) if normalize(&path).contains(&normalize(&query_string)) => {
songs.lock().unwrap().push(track);
return
}, _ => ()
};
}); });
let lock = Arc::try_unwrap(songs).expect("Lock still has multiple owners!"); let lock = Arc::try_unwrap(songs).expect("Lock still has multiple owners!");