diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 5fa7ba3e..19d3cda8 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -457,6 +457,8 @@
"albumBackgroundBlur_description": "adjusts the amount of blur applied to the album background image",
"applicationHotkeys": "application hotkeys",
"applicationHotkeys_description": "configure application hotkeys. toggle the checkbox to set as a global hotkey (desktop only)",
+ "artistConfiguration": "album artist page configuration",
+ "artistConfiguration_description": "configure what items are shown, and in what order, on the album artist page",
"audioDevice": "audio device",
"audioDevice_description": "select the audio device to use for playback (web player only)",
"audioExclusiveMode": "audio exclusive mode",
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 7224ce13..025d877d 100644
--- a/src/renderer/features/artists/components/album-artist-detail-content.tsx
+++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { ColDef, RowDoubleClickedEvent } from '@ag-grid-community/core';
-import { Box, Group, Stack } from '@mantine/core';
+import { Box, Grid, Group, Stack } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { FaLastfmSquare } from 'react-icons/fa';
import { RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri';
@@ -36,7 +36,7 @@ import { PlayButton, useCreateFavorite, useDeleteFavorite } from '/@/renderer/fe
import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay';
import { useContainerQuery } from '/@/renderer/hooks';
import { AppRoute } from '/@/renderer/router/routes';
-import { useCurrentServer } from '/@/renderer/store';
+import { ArtistItem, useCurrentServer } from '/@/renderer/store';
import { useGeneralSettings, usePlayButtonBehavior } from '/@/renderer/store/settings.store';
import { CardRow, Play, TableColumn } from '/@/renderer/types';
import { sanitize } from '/@/renderer/utils/sanitize';
@@ -65,13 +65,25 @@ interface AlbumArtistDetailContentProps {
export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailContentProps) => {
const { t } = useTranslation();
- const { externalLinks } = useGeneralSettings();
+ const { artistItems, externalLinks } = useGeneralSettings();
const { albumArtistId } = useParams() as { albumArtistId: string };
const cq = useContainerQuery();
const handlePlayQueueAdd = usePlayQueueAdd();
const server = useCurrentServer();
const genrePath = useGenreRoute();
+ const [enabledItem, itemOrder] = useMemo(() => {
+ const enabled: { [key in ArtistItem]?: boolean } = {};
+ const order: { [key in ArtistItem]?: number } = {};
+
+ for (const [idx, item] of artistItems.entries()) {
+ enabled[item.id] = !item.disabled;
+ order[item.id] = idx + 1;
+ }
+
+ return [enabled, order];
+ }, [artistItems]);
+
const detailQuery = useAlbumArtistDetail({
query: { id: albumArtistId },
serverId: server?.id,
@@ -95,6 +107,9 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
})}`;
const recentAlbumsQuery = useAlbumList({
+ options: {
+ enabled: enabledItem.recentAlbums,
+ },
query: {
_custom: {
jellyfin: {
@@ -117,6 +132,9 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
});
const compilationAlbumsQuery = useAlbumList({
+ options: {
+ enabled: enabledItem.compilations,
+ },
query: {
_custom: {
jellyfin: {
@@ -140,7 +158,7 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
const topSongsQuery = useTopSongsList({
options: {
- enabled: !!detailQuery?.data?.name,
+ enabled: !!detailQuery?.data?.name && enabledItem.topSongs,
},
query: {
artist: detailQuery?.data?.name || '',
@@ -207,9 +225,10 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
return [
{
data: recentAlbumsQuery?.data?.items,
- isHidden: !recentAlbumsQuery?.data?.items?.length,
+ isHidden: !recentAlbumsQuery?.data?.items?.length || !enabledItem.recentAlbums,
itemType: LibraryItem.ALBUM,
loading: recentAlbumsQuery?.isLoading || recentAlbumsQuery.isFetching,
+ order: itemOrder.recentAlbums,
title: (
{
const bio = detailQuery?.data?.biography;
- if (!bio) return null;
+ if (!bio || !enabledItem.biography) return null;
return sanitize(bio);
- }, [detailQuery?.data?.biography]);
+ }, [detailQuery?.data?.biography, enabledItem.biography]);
- const showTopSongs = topSongsQuery?.data?.items?.length;
+ const showTopSongs = topSongsQuery?.data?.items?.length && enabledItem.topSongs;
const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false;
const mbzId = detailQuery?.data?.mbz;
@@ -467,103 +494,127 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten
) : null}
- {biography ? (
-
-
+ {biography ? (
+
- {t('page.albumArtistDetail.about', {
- artist: detailQuery?.data?.name,
- })}
-
-
-
- ) : null}
- {showTopSongs ? (
-
-
-
- {t('page.albumArtistDetail.topSongs', {
- postProcess: 'sentenceCase',
+ {t('page.albumArtistDetail.about', {
+ artist: detailQuery?.data?.name,
})}
-
+
+
+ ) : null}
+ {showTopSongs ? (
+
+
+
- {t('page.albumArtistDetail.viewAll', {
- postProcess: 'sentenceCase',
- })}
-
-
-
- data.data.uniqueId}
- rowData={topSongs}
- rowHeight={60}
- rowSelection="multiple"
- onCellContextMenu={handleContextMenu}
- onRowDoubleClicked={handleRowDoubleClick}
- />
-
- ) : null}
-
-
- {carousels
- .filter((c) => !c.isHidden)
- .map((carousel) => (
-
+
+ {t('page.albumArtistDetail.topSongs', {
+ postProcess: 'sentenceCase',
+ })}
+
+
+
+
+ data.data.uniqueId}
+ rowData={topSongs}
+ rowHeight={60}
+ rowSelection="multiple"
+ onCellContextMenu={handleContextMenu}
+ onRowDoubleClicked={handleRowDoubleClick}
/>
- ))}
-
-
+
+
+ ) : null}
+
+ {carousels
+ .filter((c) => !c.isHidden)
+ .map((carousel) => (
+
+
+
+
+
+
+
+ ))}
+
);
diff --git a/src/renderer/features/settings/components/general/artist-settings.tsx b/src/renderer/features/settings/components/general/artist-settings.tsx
new file mode 100644
index 00000000..9a22ca7d
--- /dev/null
+++ b/src/renderer/features/settings/components/general/artist-settings.tsx
@@ -0,0 +1,25 @@
+import { DraggableItems } from '/@/renderer/features/settings/components/general/draggable-items';
+import { ArtistItem, useGeneralSettings, useSettingsStoreActions } from '/@/renderer/store';
+
+const ARTIST_ITEMS: Array<[ArtistItem, string]> = [
+ [ArtistItem.BIOGRAPHY, 'table.column.biography'],
+ [ArtistItem.TOP_SONGS, 'page.albumArtistDetail.topSongs'],
+ [ArtistItem.RECENT_ALBUMS, 'page.albumArtistDetail.recentReleases'],
+ [ArtistItem.COMPILATIONS, 'page.albumArtistDetail.appearsOn'],
+ [ArtistItem.SIMILAR_ARTISTS, 'page.albumArtistDetail.relatedArtists'],
+];
+
+export const ArtistSettings = () => {
+ const { artistItems } = useGeneralSettings();
+ const { setArtistItems } = useSettingsStoreActions();
+
+ return (
+
+ );
+};
diff --git a/src/renderer/features/settings/components/general/general-tab.tsx b/src/renderer/features/settings/components/general/general-tab.tsx
index adceee4b..f8f4c983 100644
--- a/src/renderer/features/settings/components/general/general-tab.tsx
+++ b/src/renderer/features/settings/components/general/general-tab.tsx
@@ -9,6 +9,7 @@ import isElectron from 'is-electron';
import { HomeSettings } from '/@/renderer/features/settings/components/general/home-settings';
import { SidebarReorder } from '/@/renderer/features/settings/components/general/sidebar-reorder';
import { ContextMenuSettings } from '/@/renderer/features/settings/components/general/context-menu-settings';
+import { ArtistSettings } from '/@/renderer/features/settings/components/general/artist-settings';
export const GeneralTab = () => {
return (
@@ -17,6 +18,7 @@ export const GeneralTab = () => {
+
diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts
index 85330efd..99a3ac21 100644
--- a/src/renderer/store/settings.store.ts
+++ b/src/renderer/store/settings.store.ts
@@ -105,7 +105,22 @@ export enum HomeItem {
RECENTLY_PLAYED = 'recentlyPlayed',
}
-export const homeItems = Object.values(HomeItem).map((item) => ({
+const homeItems = Object.values(HomeItem).map((item) => ({
+ disabled: false,
+ id: item,
+}));
+
+/* eslint-disable typescript-sort-keys/string-enum */
+export enum ArtistItem {
+ BIOGRAPHY = 'biography',
+ TOP_SONGS = 'topSongs',
+ RECENT_ALBUMS = 'recentAlbums',
+ COMPILATIONS = 'compilations',
+ SIMILAR_ARTISTS = 'similarArtists',
+}
+/* eslint-enable typescript-sort-keys/string-enum */
+
+const artistItems = Object.values(ArtistItem).map((item) => ({
disabled: false,
id: item,
}));
@@ -207,6 +222,7 @@ export interface SettingsState {
albumArtRes?: number | null;
albumBackground: boolean;
albumBackgroundBlur: number;
+ artistItems: SortableItem[];
buttonSize: number;
defaultFullPlaylist: boolean;
disabledContextMenu: { [k in ContextMenuItemType]?: boolean };
@@ -305,6 +321,7 @@ export interface SettingsSlice extends SettingsState {
actions: {
reset: () => void;
resetSampleRate: () => void;
+ setArtistItems: (item: SortableItem[]) => void;
setGenreBehavior: (target: GenreTarget) => void;
setHomeItems: (item: SortableItem[]) => void;
setSettings: (data: Partial) => void;
@@ -347,6 +364,7 @@ const initialState: SettingsState = {
albumArtRes: undefined,
albumBackground: false,
albumBackgroundBlur: 6,
+ artistItems,
buttonSize: 20,
defaultFullPlaylist: true,
disabledContextMenu: {},
@@ -656,6 +674,11 @@ export const useSettingsStore = create()(
state.playback.mpvProperties.audioSampleRateHz = 0;
});
},
+ setArtistItems: (items) => {
+ set((state) => {
+ state.general.artistItems = items;
+ });
+ },
setGenreBehavior: (target: GenreTarget) => {
set((state) => {
state.general.genreTarget = target;