diff --git a/src/renderer/features/albums/components/album-detail-header.tsx b/src/renderer/features/albums/components/album-detail-header.tsx index cc672b8d..c25dd1e9 100644 --- a/src/renderer/features/albums/components/album-detail-header.tsx +++ b/src/renderer/features/albums/components/album-detail-header.tsx @@ -1,9 +1,9 @@ -import { forwardRef, Fragment, Ref } from 'react'; +import { forwardRef, Fragment, Ref, useCallback, useMemo } from 'react'; import { Group, Stack } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { generatePath, useParams } from 'react-router'; import { Link } from 'react-router-dom'; -import { LibraryItem, ServerType } from '/@/renderer/api/types'; +import { AlbumDetailResponse, LibraryItem, ServerType } from '/@/renderer/api/types'; import { Rating, Text } from '/@/renderer/components'; import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query'; import { LibraryHeader, useSetRating } from '/@/renderer/features/shared'; @@ -11,6 +11,9 @@ import { useContainerQuery } from '/@/renderer/hooks'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; import { formatDateAbsoluteUTC, formatDurationString } from '/@/renderer/utils'; +import { useSongChange } from '/@/renderer/hooks/use-song-change'; +import { queryKeys } from '/@/renderer/api/query-keys'; +import { queryClient } from '/@/renderer/lib/react-query'; interface AlbumDetailHeaderProps { background: { @@ -37,6 +40,36 @@ export const AlbumDetailHeader = forwardRef( ? t('page.albumDetail.released', { postProcess: 'sentenceCase' }) : '♫'; + const songIds = useMemo(() => { + return new Set(detailQuery.data?.songs?.map((song) => song.id)); + }, [detailQuery.data?.songs]); + + const handleSongChange = useCallback( + (id: string) => { + if (songIds.has(id)) { + const queryKey = queryKeys.albums.detail(server?.id, { id: albumId }); + queryClient.setQueryData( + queryKey, + (previous) => { + if (!previous) return undefined; + + return { + ...previous, + playCount: previous.playCount ? previous.playCount + 1 : 1, + }; + }, + ); + } + }, + [albumId, server?.id, songIds], + ); + + useSongChange((ids, event) => { + if (event.event === 'play') { + handleSongChange(ids[0]); + } + }, detailQuery.data !== undefined); + const metadataItems = [ { id: 'releaseDate', diff --git a/src/renderer/features/player/mutations/scrobble-mutation.ts b/src/renderer/features/player/mutations/scrobble-mutation.ts index 714c937b..8b1688d1 100644 --- a/src/renderer/features/player/mutations/scrobble-mutation.ts +++ b/src/renderer/features/player/mutations/scrobble-mutation.ts @@ -25,7 +25,7 @@ export const useSendScrobble = (options?: MutationOptions) => { // Manually increment the play count for the song in the queue if scrobble was submitted if (variables.query.submission) { incrementPlayCount([variables.query.id]); - sendPlayEvent([variables.query.id]); + sendPlayEvent(variables.query.id); } }, ...options, diff --git a/src/renderer/store/event.store.ts b/src/renderer/store/event.store.ts index 8d69bd3e..668b8e07 100644 --- a/src/renderer/store/event.store.ts +++ b/src/renderer/store/event.store.ts @@ -27,7 +27,7 @@ export interface EventState { export interface EventSlice extends EventState { actions: { favorite: (ids: string[], favorite: boolean) => void; - play: (ids: string[]) => void; + play: (id: string) => void; rate: (ids: string[], rating: number | null) => void; }; } @@ -43,10 +43,10 @@ export const useEventStore = create()( state.ids = ids; }); }, - play(ids) { + play(id) { set((state) => { state.event = { event: 'play', timestamp: new Date().toISOString() }; - state.ids = ids; + state.ids = [id]; }); }, rate(ids, rating) {