Faster song sorting using dictionary ordering
This commit is contained in:
parent
f371d5e331
commit
b9bcdd46b1
2 changed files with 58 additions and 57 deletions
|
@ -5,7 +5,6 @@ use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use icu_collator::Collator;
|
|
||||||
use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng};
|
use rand::{rngs::StdRng, seq::SliceRandom, SeedableRng};
|
||||||
use rayon::slice::ParallelSliceMut;
|
use rayon::slice::ParallelSliceMut;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -237,15 +236,12 @@ impl Collection {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
artists.sort_by(|a, b| collator.compare(&a.name, &b.name));
|
artists.sort_by(|a, b| collator.compare(&a.name, &b.name));
|
||||||
|
|
||||||
let mut songs = genre
|
let mut songs = genre.songs.iter().copied().collect::<Vec<_>>();
|
||||||
.songs
|
self.sort_songs(&mut songs, dictionary);
|
||||||
.iter()
|
let songs = songs
|
||||||
.filter_map(|k| self.get_song(dictionary, *k))
|
.into_iter()
|
||||||
|
.filter_map(|k| self.get_song(dictionary, k))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
songs.par_sort_unstable_by(|a, b| {
|
|
||||||
let collator = dictionary::make_collator();
|
|
||||||
compare_songs(a, b, &collator)
|
|
||||||
});
|
|
||||||
|
|
||||||
let related_genres = genre
|
let related_genres = genre
|
||||||
.related_genres
|
.related_genres
|
||||||
|
@ -272,49 +268,61 @@ impl Collection {
|
||||||
pub fn get_song(&self, dictionary: &Dictionary, song_key: SongKey) -> Option<Song> {
|
pub fn get_song(&self, dictionary: &Dictionary, song_key: SongKey) -> Option<Song> {
|
||||||
self.songs.get(&song_key).map(|s| fetch_song(dictionary, s))
|
self.songs.get(&song_key).map(|s| fetch_song(dictionary, s))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compare_songs(a: &Song, b: &Song, collator: &Collator) -> Ordering {
|
pub fn sort_songs(&self, songs: &mut Vec<SongKey>, dictionary: &Dictionary) {
|
||||||
let a_artists = if a.album_artists.is_empty() {
|
songs.par_sort_unstable_by(|a, b| self.compare_songs(*a, *b, dictionary));
|
||||||
&a.artists
|
}
|
||||||
} else {
|
|
||||||
&a.album_artists
|
|
||||||
};
|
|
||||||
|
|
||||||
let b_artists = if b.album_artists.is_empty() {
|
fn compare_songs(&self, a: SongKey, b: SongKey, dictionary: &Dictionary) -> Ordering {
|
||||||
&b.artists
|
let (a, b) = match (self.songs.get(&a), self.songs.get(&b)) {
|
||||||
} else {
|
(None, None) => return Ordering::Equal,
|
||||||
&b.album_artists
|
(None, Some(_)) => return Ordering::Less,
|
||||||
};
|
(Some(_), None) => return Ordering::Greater,
|
||||||
|
(Some(a), Some(b)) => (a, b),
|
||||||
|
};
|
||||||
|
|
||||||
for (a_artist, b_artist) in a_artists.iter().zip(b_artists) {
|
let a_artists = if a.album_artists.is_empty() {
|
||||||
match collator.compare(a_artist, b_artist) {
|
&a.artists
|
||||||
|
} else {
|
||||||
|
&a.album_artists
|
||||||
|
};
|
||||||
|
|
||||||
|
let b_artists = if b.album_artists.is_empty() {
|
||||||
|
&b.artists
|
||||||
|
} else {
|
||||||
|
&b.album_artists
|
||||||
|
};
|
||||||
|
|
||||||
|
for (a_artist, b_artist) in a_artists.iter().zip(b_artists) {
|
||||||
|
match dictionary.cmp(&a_artist.0, &b_artist.0) {
|
||||||
|
Ordering::Equal => (),
|
||||||
|
o => return o,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match a_artists.len().cmp(&b_artists.len()) {
|
||||||
Ordering::Equal => (),
|
Ordering::Equal => (),
|
||||||
o => return o,
|
o => return o,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match a.year.cmp(&b.year) {
|
||||||
|
Ordering::Equal => (),
|
||||||
|
o => return o,
|
||||||
|
}
|
||||||
|
|
||||||
|
match (a.album, b.album) {
|
||||||
|
(None, None) => (),
|
||||||
|
(None, Some(_)) => return Ordering::Less,
|
||||||
|
(Some(_), None) => return Ordering::Greater,
|
||||||
|
(Some(a_album), Some(b_album)) if a_album == b_album => (),
|
||||||
|
(Some(a_album), Some(b_album)) => return dictionary.cmp(&a_album, &b_album),
|
||||||
|
}
|
||||||
|
|
||||||
|
let a_key = (a.disc_number, a.track_number);
|
||||||
|
let b_key = (b.disc_number, b.track_number);
|
||||||
|
|
||||||
|
a_key.cmp(&b_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
match a_artists.len().cmp(&b_artists.len()) {
|
|
||||||
Ordering::Equal => (),
|
|
||||||
o => return o,
|
|
||||||
}
|
|
||||||
|
|
||||||
match a.year.cmp(&b.year) {
|
|
||||||
Ordering::Equal => (),
|
|
||||||
o => return o,
|
|
||||||
}
|
|
||||||
|
|
||||||
let a_album = a.album.as_ref().map(|s| s.as_str()).unwrap_or(&"");
|
|
||||||
let b_album = b.album.as_ref().map(|s| s.as_str()).unwrap_or(&"");
|
|
||||||
match collator.compare(a_album, b_album) {
|
|
||||||
Ordering::Equal => (),
|
|
||||||
o => return o,
|
|
||||||
}
|
|
||||||
|
|
||||||
let a_key = (a.disc_number, a.track_number);
|
|
||||||
let b_key = (b.disc_number, b.track_number);
|
|
||||||
|
|
||||||
a_key.cmp(&b_key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_album_header(album: &storage::Album, dictionary: &Dictionary) -> AlbumHeader {
|
fn make_album_header(album: &storage::Album, dictionary: &Dictionary) -> AlbumHeader {
|
||||||
|
|
|
@ -2,7 +2,6 @@ use chumsky::Parser;
|
||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use lasso2::Spur;
|
use lasso2::Spur;
|
||||||
use nohash_hasher::IntSet;
|
use nohash_hasher::IntSet;
|
||||||
use rayon::slice::ParallelSliceMut;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use tinyvec::TinyVec;
|
use tinyvec::TinyVec;
|
||||||
|
@ -16,12 +15,7 @@ use crate::app::{
|
||||||
scanner, Error,
|
scanner, Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{collection, dictionary::sanitize, query::make_parser, storage};
|
||||||
collection,
|
|
||||||
dictionary::{self, sanitize},
|
|
||||||
query::make_parser,
|
|
||||||
storage,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Search {
|
pub struct Search {
|
||||||
|
@ -52,15 +46,14 @@ impl Search {
|
||||||
|
|
||||||
let mut songs = self
|
let mut songs = self
|
||||||
.eval(dictionary, &parsed_query)
|
.eval(dictionary, &parsed_query)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
collection.sort_songs(&mut songs, dictionary);
|
||||||
|
let songs = songs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|song_key| collection.get_song(dictionary, song_key))
|
.filter_map(|song_key| collection.get_song(dictionary, song_key))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
songs.par_sort_unstable_by(|a, b| {
|
|
||||||
let collator = dictionary::make_collator();
|
|
||||||
collection::compare_songs(a, b, &collator)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(songs)
|
Ok(songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue