feat(genre): support sorting by track/album count

This commit is contained in:
Kendall Garner
2026-06-28 19:39:32 -07:00
parent c875146779
commit da445b815d
5 changed files with 49 additions and 23 deletions
@@ -19,7 +19,6 @@ import {
DeleteInternetRadioStationImageResponse, DeleteInternetRadioStationImageResponse,
DeletePlaylistImageArgs, DeletePlaylistImageArgs,
DeletePlaylistImageResponse, DeletePlaylistImageResponse,
genreListSortMap,
InternalControllerEndpoint, InternalControllerEndpoint,
playlistListSortMap, playlistListSortMap,
PlaylistSongListArgs, PlaylistSongListArgs,
@@ -596,26 +595,7 @@ export const NavidromeController: InternalControllerEndpoint = {
}; };
} }
const res = await ndApiClient(apiClientProps).getGenreList({ return SubsonicController.getGenreList(args);
query: {
_end: query.startIndex + (query.limit || 0),
_order: sortOrderMap.navidrome[query.sortOrder],
_sort: genreListSortMap.navidrome[query.sortBy],
_start: query.startIndex,
library_id: getLibraryId(query.musicFolderId),
name: query.searchTerm,
},
});
if (res.status !== 200) {
throw new Error('Failed to get genre list');
}
return {
items: res.body.data.map((genre) => ndNormalize.genre(genre, apiClientProps.server)),
startIndex: query.startIndex || 0,
totalRecordCount: Number(res.body.headers.get('x-total-count') || 0),
};
}, },
getImageRequest: SubsonicController.getImageRequest, getImageRequest: SubsonicController.getImageRequest,
getImageUrl: SubsonicController.getImageUrl, getImageUrl: SubsonicController.getImageUrl,
@@ -1090,9 +1090,15 @@ export const SubsonicController: InternalControllerEndpoint = {
} }
switch (query.sortBy) { switch (query.sortBy) {
case GenreListSort.ALBUM_COUNT:
results = orderBy(results, [(v) => v.albumCount], [sortOrder]);
break;
case GenreListSort.NAME: case GenreListSort.NAME:
results = orderBy(results, [(v) => v.value.toLowerCase()], [sortOrder]); results = orderBy(results, [(v) => v.value.toLowerCase()], [sortOrder]);
break; break;
case GenreListSort.SONG_COUNT:
results = orderBy(results, [(v) => v.songCount], [sortOrder]);
break;
default: default:
break; break;
} }
@@ -823,18 +823,38 @@ const GENRE_LIST_FILTERS: Partial<
}, },
], ],
[ServerType.NAVIDROME]: [ [ServerType.NAVIDROME]: [
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.albumCount'),
value: GenreListSort.ALBUM_COUNT,
},
{ {
defaultOrder: SortOrder.ASC, defaultOrder: SortOrder.ASC,
name: i18n.t('filter.name'), name: i18n.t('filter.name'),
value: GenreListSort.NAME, value: GenreListSort.NAME,
}, },
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.songCount'),
value: GenreListSort.SONG_COUNT,
},
], ],
[ServerType.SUBSONIC]: [ [ServerType.SUBSONIC]: [
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.albumCount'),
value: GenreListSort.ALBUM_COUNT,
},
{ {
defaultOrder: SortOrder.ASC, defaultOrder: SortOrder.ASC,
name: i18n.t('filter.name'), name: i18n.t('filter.name'),
value: GenreListSort.NAME, value: GenreListSort.NAME,
}, },
{
defaultOrder: SortOrder.ASC,
name: i18n.t('filter.albumCount'),
value: GenreListSort.SONG_COUNT,
},
], ],
}; };
@@ -27,7 +27,9 @@ export enum NDAlbumListSort {
} }
export enum NDGenreListSort { export enum NDGenreListSort {
ALBUM_COUNT = 'albumCount',
NAME = 'name', NAME = 'name',
SONG_COUNT = 'songCount',
} }
export enum NDPlaylistListSort { export enum NDPlaylistListSort {
@@ -754,6 +756,8 @@ const tag = z.object({
const tagList = z.array(tag); const tagList = z.array(tag);
export enum NDTagListSort { export enum NDTagListSort {
ALBUM_COUNT = 'albumCount',
SONG_COUNT = 'songCount',
TAG_VALUE = 'tagValue', TAG_VALUE = 'tagValue',
} }
+18 -2
View File
@@ -155,7 +155,9 @@ export enum ExternalType {
} }
export enum GenreListSort { export enum GenreListSort {
ALBUM_COUNT = 'albumCount',
NAME = 'name', NAME = 'name',
SONG_COUNT = 'songCount',
} }
export enum ImageType { export enum ImageType {
@@ -166,7 +168,9 @@ export enum ImageType {
} }
export enum TagListSort { export enum TagListSort {
ALBUM_COUNT = 'albumCount',
NAME = 'name', NAME = 'name',
SONG_COUNT = 'songCount',
} }
export type Album = { export type Album = {
@@ -430,19 +434,25 @@ type BaseEndpointArgs = {
type GenreListSortMap = { type GenreListSortMap = {
jellyfin: Record<GenreListSort, JFGenreListSort | undefined>; jellyfin: Record<GenreListSort, JFGenreListSort | undefined>;
navidrome: Record<GenreListSort, NDGenreListSort | undefined>; navidrome: Record<GenreListSort, NDGenreListSort>;
subsonic: Record<UserListSort, undefined>; subsonic: Record<GenreListSort, undefined>;
}; };
export const genreListSortMap: GenreListSortMap = { export const genreListSortMap: GenreListSortMap = {
jellyfin: { jellyfin: {
albumCount: undefined,
name: JFGenreListSort.NAME, name: JFGenreListSort.NAME,
songCount: undefined,
}, },
navidrome: { navidrome: {
albumCount: NDGenreListSort.NAME,
name: NDGenreListSort.NAME, name: NDGenreListSort.NAME,
songCount: NDGenreListSort.NAME,
}, },
subsonic: { subsonic: {
albumCount: undefined,
name: undefined, name: undefined,
songCount: undefined,
}, },
}; };
@@ -454,13 +464,19 @@ type TagListSortMap = {
export const tagListSortMap: TagListSortMap = { export const tagListSortMap: TagListSortMap = {
jellyfin: { jellyfin: {
albumCount: undefined,
name: undefined, name: undefined,
songCount: undefined,
}, },
navidrome: { navidrome: {
albumCount: NDTagListSort.ALBUM_COUNT,
name: NDTagListSort.TAG_VALUE, name: NDTagListSort.TAG_VALUE,
songCount: NDTagListSort.SONG_COUNT,
}, },
subsonic: { subsonic: {
albumCount: undefined,
name: undefined, name: undefined,
songCount: undefined,
}, },
}; };