diff --git a/src/renderer/api/jellyfin/jellyfin-controller.ts b/src/renderer/api/jellyfin/jellyfin-controller.ts index b05224997..68732acff 100644 --- a/src/renderer/api/jellyfin/jellyfin-controller.ts +++ b/src/renderer/api/jellyfin/jellyfin-controller.ts @@ -38,6 +38,10 @@ const formatCommaDelimitedString = (value: string[]) => { // not the POST body const MAX_ITEMS_PER_PLAYLIST_ADD = 50; +// Defining a re-usable Collator instance for performance reasons. +const numericSortCollator = new Intl.Collator(undefined, { numeric: true }); +const collator = new Intl.Collator(); + const VERSION_INFO: VersionInfo = [ [ '10.9.0', @@ -1250,11 +1254,12 @@ export const JellyfinController: InternalControllerEndpoint = { if (res.body.Tags?.length) { tags.push({ name: 'Tags', - options: res.body.Tags.sort((a, b) => - a - .toLocaleLowerCase() - .localeCompare(b.toLocaleLowerCase(), undefined, { numeric: true }), - ).map((tag) => ({ id: tag, name: tag })), + options: res.body.Tags.sort((a, b) => { + return numericSortCollator.compare( + a.toLocaleLowerCase(), + b.toLocaleLowerCase(), + ); + }).map((tag) => ({ id: tag, name: tag })), }); } @@ -1262,7 +1267,7 @@ export const JellyfinController: InternalControllerEndpoint = { tags.push({ name: 'Studios', options: studioRes.body.Items.sort((a, b) => - a.Name.toLocaleLowerCase().localeCompare(b.Name.toLocaleLowerCase()), + collator.compare(a.Name.toLocaleLowerCase(), b.Name.toLocaleLowerCase()), ).map((option) => ({ id: option.Name, name: option.Name })), }); } diff --git a/src/renderer/api/navidrome/navidrome-controller.ts b/src/renderer/api/navidrome/navidrome-controller.ts index 9a136ec24..b41c28c6f 100644 --- a/src/renderer/api/navidrome/navidrome-controller.ts +++ b/src/renderer/api/navidrome/navidrome-controller.ts @@ -71,6 +71,10 @@ const EXCLUDED_ALBUM_TAGS = new Set([ const EXCLUDED_SONG_TAGS = new Set(['disctotal', 'tracktotal']); +// Defining a re-usable Collator instance for performance reasons. +const numericSortCollator = new Intl.Collator(undefined, { numeric: true }); +const collator = new Intl.Collator(); + // Tags that use IDs as values as opposed to the tag value const ID_TAGS = new Set(['albumversion', 'mood']); @@ -780,16 +784,17 @@ export const NavidromeController: InternalControllerEndpoint = { .map((data) => ({ name: data[0], options: data[1] - .sort((a, b) => - a.name - .toLocaleLowerCase() - .localeCompare(b.name.toLocaleLowerCase(), undefined, { - numeric: true, - }), - ) + .sort((a, b) => { + return numericSortCollator.compare( + a.name.toLocaleLowerCase(), + b.name.toLocaleLowerCase(), + ); + }) .map((option) => ({ id: option.id, name: option.name })), })) - .sort((a, b) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())); + .sort((a, b) => + collator.compare(a.name.toLocaleLowerCase(), b.name.toLocaleLowerCase()), + ); const excludedAlbumTags = Array.from(EXCLUDED_ALBUM_TAGS.values()); const excludedSongTags = Array.from(EXCLUDED_SONG_TAGS.values()); diff --git a/src/renderer/features/artists/components/album-artist-detail-content.tsx b/src/renderer/features/artists/components/album-artist-detail-content.tsx index 68359de0b..dd62508b4 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -88,6 +88,8 @@ import { } from '/@/shared/types/domain-types'; import { ItemListKey, ListDisplayType, Play } from '/@/shared/types/types'; +const collator = new Intl.Collator(); + interface AlbumArtistActionButtonsProps { artistDiscographyLink: string; artistSongsLink: string; @@ -1251,12 +1253,12 @@ const ArtistAlbums = ({ albumsQuery }: ArtistAlbumsProps) => { const secondaryKeyB = getSecondaryTypePriorityKey(b.releaseType); if (secondaryKeyA && secondaryKeyB) { - return secondaryKeyA.localeCompare(secondaryKeyB); + return collator.compare(secondaryKeyA, secondaryKeyB); } } // Fallback to alphabetical for non-combined types or if weighted comparison isn't applicable - return a.releaseType.localeCompare(b.releaseType); + return collator.compare(a.releaseType, b.releaseType); }); }, [albumsByReleaseType, artistReleaseTypeItems, t]);