diff --git a/src/renderer/features/player/hooks/use-scrobble.ts b/src/renderer/features/player/hooks/use-scrobble.ts index bc88a0840..26b991533 100644 --- a/src/renderer/features/player/hooks/use-scrobble.ts +++ b/src/renderer/features/player/hooks/use-scrobble.ts @@ -36,17 +36,18 @@ Progress Events (Jellyfin only): const checkScrobbleConditions = (args: { scrobbleAtDuration: number; scrobbleAtPercentage: number; - songCompletedDuration: number; - songDuration: number; + songCompletedDurationMs: number; + songDurationMs: number; }) => { - const { scrobbleAtDuration, scrobbleAtPercentage, songCompletedDuration, songDuration } = args; - const percentageOfSongCompleted = songDuration - ? (songCompletedDuration / songDuration) * 100 + const { scrobbleAtDuration, scrobbleAtPercentage, songCompletedDurationMs, songDurationMs } = + args; + const percentageOfSongCompleted = songDurationMs + ? (songCompletedDurationMs / songDurationMs) * 100 : 0; return ( percentageOfSongCompleted >= scrobbleAtPercentage || - songCompletedDuration >= scrobbleAtDuration + songCompletedDurationMs >= scrobbleAtDuration ); }; @@ -97,15 +98,15 @@ export const useScrobble = () => { // const currentSong = current[0] as QueueSong | undefined; const previousSong = previous[0] as QueueSong; - const previousSongTime = previous[1] as number; + const previousSongTimeSec = previous[1] as number; // Send completion scrobble when song changes and a previous song exists if (previousSong?.id) { const shouldSubmitScrobble = checkScrobbleConditions({ scrobbleAtDuration: scrobbleSettings?.scrobbleAtDuration, scrobbleAtPercentage: scrobbleSettings?.scrobbleAtPercentage, - songCompletedDuration: previousSongTime, - songDuration: previousSong.duration, + songCompletedDurationMs: previousSongTimeSec * 1000, + songDurationMs: previousSong.duration, }); if ( @@ -114,7 +115,7 @@ export const useScrobble = () => { ) { const position = previousSong?.serverType === ServerType.JELLYFIN - ? previousSongTime * 1e7 + ? previousSongTimeSec * 1e7 : undefined; sendScrobble.mutate({ @@ -168,7 +169,10 @@ export const useScrobble = () => { ); const handleScrobbleFromStatusChange = useCallback( - (status: PlayerStatus | undefined) => { + ( + current: (PlayerStatus | number | undefined)[], + previous: (PlayerStatus | number | undefined)[], + ) => { if (!isScrobbleEnabled) return; const currentSong = usePlayerStore.getState().current.song; @@ -180,8 +184,11 @@ export const useScrobble = () => { ? usePlayerStore.getState().current.time * 1e7 : undefined; + const currentStatus = current[0] as PlayerStatus; + const currentTimeSec = current[1] as number; + // Whenever the player is restarted, send a 'start' scrobble - if (status === PlayerStatus.PLAYING) { + if (currentStatus === PlayerStatus.PLAYING) { sendScrobble.mutate({ query: { event: 'unpause', @@ -194,7 +201,7 @@ export const useScrobble = () => { if (currentSong?.serverType === ServerType.JELLYFIN) { progressIntervalId.current = setInterval(() => { - const currentTime = usePlayerStore.getState().current.time; + const currentTime = currentTimeSec; handleScrobbleFromSeek(currentTime); }, 10000); } @@ -215,12 +222,17 @@ export const useScrobble = () => { clearInterval(progressIntervalId.current as ReturnType); } } else { + const isLastTrackInQueue = usePlayerStore.getState().actions.checkIsLastTrack(); + const previousTimeSec = previous[1] as number; + // If not already scrobbled, send a 'submission' scrobble if conditions are met const shouldSubmitScrobble = checkScrobbleConditions({ scrobbleAtDuration: scrobbleSettings?.scrobbleAtDuration, scrobbleAtPercentage: scrobbleSettings?.scrobbleAtPercentage, - songCompletedDuration: usePlayerStore.getState().current.time, - songDuration: currentSong.duration, + // If scrobbling the last song in the queue, use the previous time instead of the current time since otherwise time value will be 0 + songCompletedDurationMs: + (isLastTrackInQueue ? previousTimeSec : currentTimeSec) * 1000, + songDurationMs: currentSong.duration, }); if (!isCurrentSongScrobbled && shouldSubmitScrobble) { @@ -263,8 +275,8 @@ export const useScrobble = () => { const shouldSubmitScrobble = checkScrobbleConditions({ scrobbleAtDuration: scrobbleSettings?.scrobbleAtDuration, scrobbleAtPercentage: scrobbleSettings?.scrobbleAtPercentage, - songCompletedDuration: currentTime, - songDuration: currentSong.duration, + songCompletedDurationMs: currentTime, + songDurationMs: currentSong.duration, }); if (!isCurrentSongScrobbled && shouldSubmitScrobble) { @@ -313,8 +325,11 @@ export const useScrobble = () => { ); const unsubStatusChange = usePlayerStore.subscribe( - (state) => state.current.status, + (state) => [state.current.status, state.current.time], handleScrobbleFromStatusChange, + { + equalityFn: (a, b) => (a[0] as PlayerStatus) === (b[0] as PlayerStatus), + }, ); return () => {