mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 14:55:43 +00:00
fix(albums): order each artist's albums by title when sorting by artist (#1115)
* fix(albums): order each artist's albums by title when sorting by artist Browsing albums by artist left the albums within each artist in an undefined order. The local-index sort only emitted the artist key; it now appends album title as a secondary key (and artist as the tiebreak for the by-name sort), matching the network path's per-page ordering. * docs(changelog): note album sort-within-artist fix (#1115)
This commit is contained in:
@@ -35,6 +35,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
* The Previous / Play-Pause / Next buttons in the Windows taskbar thumbnail preview (the popup shown when hovering the taskbar icon) had stopped appearing. They are back, and the middle button's icon again reflects the current playback state.
|
||||
|
||||
### Album order within each artist when sorting by artist
|
||||
|
||||
**By [@Psychotoxical](https://github.com/Psychotoxical), PR [#1115](https://github.com/Psychotoxical/psysonic/pull/1115)**, suggested by [@kingley82](https://github.com/kingley82)
|
||||
|
||||
* When browsing albums sorted by artist, each artist's albums appeared in an arbitrary order. They are now ordered A–Z by album title within each artist.
|
||||
|
||||
|
||||
## [1.48.1] - 2026-06-15
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { SubsonicAlbum } from '../../api/subsonicTypes';
|
||||
import { albumSortClauses, sortSubsonicAlbums } from './albumBrowseSort';
|
||||
|
||||
const album = (artist: string, name: string): SubsonicAlbum =>
|
||||
({ id: `${artist}-${name}`, artist, name }) as SubsonicAlbum;
|
||||
|
||||
describe('albumSortClauses', () => {
|
||||
it('sorts by artist then album name', () => {
|
||||
expect(albumSortClauses('alphabeticalByArtist')).toEqual([
|
||||
{ field: 'artist', dir: 'asc' },
|
||||
{ field: 'name', dir: 'asc' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('sorts by album name then artist', () => {
|
||||
expect(albumSortClauses('alphabeticalByName')).toEqual([
|
||||
{ field: 'name', dir: 'asc' },
|
||||
{ field: 'artist', dir: 'asc' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortSubsonicAlbums', () => {
|
||||
it('orders each artist group by album name when sorting by artist', () => {
|
||||
const input = [
|
||||
album('Rammstein', 'Sehnsucht'),
|
||||
album('Duran Duran', 'Rio'),
|
||||
album('Rammstein', 'Mutter'),
|
||||
album('Duran Duran', 'DD'),
|
||||
album('Duran Duran', 'The Wedding Album'),
|
||||
];
|
||||
const ordered = sortSubsonicAlbums(input, 'alphabeticalByArtist').map(a => `${a.artist} - ${a.name}`);
|
||||
expect(ordered).toEqual([
|
||||
'Duran Duran - DD',
|
||||
'Duran Duran - Rio',
|
||||
'Duran Duran - The Wedding Album',
|
||||
'Rammstein - Mutter',
|
||||
'Rammstein - Sehnsucht',
|
||||
]);
|
||||
});
|
||||
|
||||
it('breaks album-name ties by artist when sorting by name', () => {
|
||||
const input = [
|
||||
album('Zebra', 'Greatest Hits'),
|
||||
album('Alpha', 'Greatest Hits'),
|
||||
];
|
||||
const ordered = sortSubsonicAlbums(input, 'alphabeticalByName').map(a => a.artist);
|
||||
expect(ordered).toEqual(['Alpha', 'Zebra']);
|
||||
});
|
||||
});
|
||||
@@ -4,10 +4,19 @@ import type { LibrarySortClause } from '../../api/library';
|
||||
export type AlbumBrowseSort = 'alphabeticalByName' | 'alphabeticalByArtist';
|
||||
|
||||
export function albumSortClauses(sort: AlbumBrowseSort): LibrarySortClause[] {
|
||||
// Always append a secondary key so albums sharing the primary key keep a
|
||||
// stable order — by artist groups each artist's albums by title (rather than
|
||||
// an undefined order within the artist), mirroring `sortSubsonicAlbums`.
|
||||
if (sort === 'alphabeticalByArtist') {
|
||||
return [{ field: 'artist', dir: 'asc' }];
|
||||
return [
|
||||
{ field: 'artist', dir: 'asc' },
|
||||
{ field: 'name', dir: 'asc' },
|
||||
];
|
||||
}
|
||||
return [{ field: 'name', dir: 'asc' }];
|
||||
return [
|
||||
{ field: 'name', dir: 'asc' },
|
||||
{ field: 'artist', dir: 'asc' },
|
||||
];
|
||||
}
|
||||
|
||||
export function sortSubsonicAlbums(albums: SubsonicAlbum[], sort: AlbumBrowseSort): SubsonicAlbum[] {
|
||||
|
||||
Reference in New Issue
Block a user