Support for accented characters when sorting songs

This commit is contained in:
Antoine Gersant 2025-01-01 23:25:13 -08:00
parent 41187199ba
commit f371d5e331
2 changed files with 55 additions and 20 deletions

View file

@ -5,7 +5,9 @@ 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 serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tinyvec::TinyVec; use tinyvec::TinyVec;
use unicase::UniCase; use unicase::UniCase;
@ -116,6 +118,7 @@ impl Collection {
} }
pub fn get_artist(&self, dictionary: &Dictionary, artist_key: ArtistKey) -> Option<Artist> { pub fn get_artist(&self, dictionary: &Dictionary, artist_key: ArtistKey) -> Option<Artist> {
let collator = dictionary::make_collator();
self.artists.get(&artist_key).map(|artist| { self.artists.get(&artist_key).map(|artist| {
let header = make_artist_header(artist, dictionary); let header = make_artist_header(artist, dictionary);
let albums = { let albums = {
@ -125,7 +128,7 @@ impl Collection {
.filter_map(|key| self.get_album(dictionary, key.clone())) .filter_map(|key| self.get_album(dictionary, key.clone()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
albums.sort_by(|a, b| match a.header.year.cmp(&b.header.year) { albums.sort_by(|a, b| match a.header.year.cmp(&b.header.year) {
Ordering::Equal => a.header.name.cmp(&b.header.name), Ordering::Equal => collator.compare(&a.header.name, &b.header.name),
o => o, o => o,
}); });
albums albums
@ -239,7 +242,10 @@ impl Collection {
.iter() .iter()
.filter_map(|k| self.get_song(dictionary, *k)) .filter_map(|k| self.get_song(dictionary, *k))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
songs.sort_by(compare_songs); 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
@ -268,26 +274,46 @@ impl Collection {
} }
} }
pub fn compare_songs(a: &Song, b: &Song) -> Ordering { pub fn compare_songs(a: &Song, b: &Song, collator: &Collator) -> Ordering {
let a_key = { let a_artists = if a.album_artists.is_empty() {
let artists = if a.album_artists.is_empty() { &a.artists
&a.artists } else {
} else { &a.album_artists
&a.album_artists
};
(artists, a.year, &a.album, a.disc_number, a.track_number)
}; };
let b_key = { let b_artists = if b.album_artists.is_empty() {
let artists = if b.album_artists.is_empty() { &b.artists
&b.artists } else {
} else { &b.album_artists
&b.album_artists
};
(artists, b.year, &b.album, b.disc_number, b.track_number)
}; };
// TODO collator for (a_artist, b_artist) in a_artists.iter().zip(b_artists) {
match collator.compare(a_artist, b_artist) {
Ordering::Equal => (),
o => return o,
}
}
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) a_key.cmp(&b_key)
} }

View file

@ -2,6 +2,7 @@ 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;
@ -15,7 +16,12 @@ use crate::app::{
scanner, Error, scanner, Error,
}; };
use super::{collection, dictionary::sanitize, query::make_parser, storage}; use super::{
collection,
dictionary::{self, sanitize},
query::make_parser,
storage,
};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Search { pub struct Search {
@ -50,7 +56,10 @@ impl Search {
.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.sort_by(collection::compare_songs); songs.par_sort_unstable_by(|a, b| {
let collator = dictionary::make_collator();
collection::compare_songs(a, b, &collator)
});
Ok(songs) Ok(songs)
} }