[bugfix]: fix scrobble race conditions

This commit is contained in:
Kendall Garner 2024-04-01 22:13:06 -07:00
parent 2854a91700
commit ab17ba8add
No known key found for this signature in database
GPG key ID: 18D2767419676C87

View file

@ -1,7 +1,7 @@
import { useEffect, useCallback, useState, useRef } from 'react'; import { useEffect, useCallback, useState, useRef } from 'react';
import { QueueSong, ServerType } from '/@/renderer/api/types'; import { QueueSong, ServerType } from '/@/renderer/api/types';
import { useSendScrobble } from '/@/renderer/features/player/mutations/scrobble-mutation'; import { useSendScrobble } from '/@/renderer/features/player/mutations/scrobble-mutation';
import { useCurrentStatus, usePlayerStore } from '/@/renderer/store'; import { usePlayerStore } from '/@/renderer/store';
import { usePlaybackSettings } from '/@/renderer/store/settings.store'; import { usePlaybackSettings } from '/@/renderer/store/settings.store';
import { PlayerStatus } from '/@/renderer/types'; import { PlayerStatus } from '/@/renderer/types';
@ -52,7 +52,6 @@ const checkScrobbleConditions = (args: {
}; };
export const useScrobble = () => { export const useScrobble = () => {
const status = useCurrentStatus();
const scrobbleSettings = usePlaybackSettings().scrobble; const scrobbleSettings = usePlaybackSettings().scrobble;
const isScrobbleEnabled = scrobbleSettings?.enabled; const isScrobbleEnabled = scrobbleSettings?.enabled;
const sendScrobble = useSendScrobble(); const sendScrobble = useSendScrobble();
@ -94,6 +93,7 @@ export const useScrobble = () => {
if (progressIntervalId.current) { if (progressIntervalId.current) {
clearInterval(progressIntervalId.current); clearInterval(progressIntervalId.current);
progressIntervalId.current = null;
} }
// const currentSong = current[0] as QueueSong | undefined; // const currentSong = current[0] as QueueSong | undefined;
@ -135,9 +135,13 @@ export const useScrobble = () => {
clearTimeout(songChangeTimeoutId.current as ReturnType<typeof setTimeout>); clearTimeout(songChangeTimeoutId.current as ReturnType<typeof setTimeout>);
songChangeTimeoutId.current = setTimeout(() => { songChangeTimeoutId.current = setTimeout(() => {
const currentSong = current[0] as QueueSong | undefined; const currentSong = current[0] as QueueSong | undefined;
// Get the current status from the state, not variable. This is because
// of a timing issue where, when playing the first track, the first
// event is song, and then the event is play
const currentStatus = usePlayerStore.getState().current.status;
// Send start scrobble when song changes and the new song is playing // Send start scrobble when song changes and the new song is playing
if (status === PlayerStatus.PLAYING && currentSong?.id) { if (currentStatus === PlayerStatus.PLAYING && currentSong?.id) {
sendScrobble.mutate({ sendScrobble.mutate({
query: { query: {
event: 'start', event: 'start',
@ -149,6 +153,12 @@ export const useScrobble = () => {
}); });
if (currentSong?.serverType === ServerType.JELLYFIN) { if (currentSong?.serverType === ServerType.JELLYFIN) {
// It is possible that another function sets an interval.
// We only want one running, so clear the existing interval
if (progressIntervalId.current) {
clearInterval(progressIntervalId.current);
}
progressIntervalId.current = setInterval(() => { progressIntervalId.current = setInterval(() => {
const currentTime = usePlayerStore.getState().current.time; const currentTime = usePlayerStore.getState().current.time;
handleScrobbleFromSeek(currentTime); handleScrobbleFromSeek(currentTime);
@ -163,7 +173,6 @@ export const useScrobble = () => {
scrobbleSettings?.scrobbleAtPercentage, scrobbleSettings?.scrobbleAtPercentage,
isCurrentSongScrobbled, isCurrentSongScrobbled,
sendScrobble, sendScrobble,
status,
handleScrobbleFromSeek, handleScrobbleFromSeek,
], ],
); );
@ -200,8 +209,14 @@ export const useScrobble = () => {
}); });
if (currentSong?.serverType === ServerType.JELLYFIN) { if (currentSong?.serverType === ServerType.JELLYFIN) {
// It is possible that another function sets an interval.
// We only want one running, so clear the existing interval
if (progressIntervalId.current) {
clearInterval(progressIntervalId.current);
}
progressIntervalId.current = setInterval(() => { progressIntervalId.current = setInterval(() => {
const currentTime = currentTimeSec; const currentTime = usePlayerStore.getState().current.time;
handleScrobbleFromSeek(currentTime); handleScrobbleFromSeek(currentTime);
}, 10000); }, 10000);
} }
@ -220,6 +235,7 @@ export const useScrobble = () => {
if (progressIntervalId.current) { if (progressIntervalId.current) {
clearInterval(progressIntervalId.current as ReturnType<typeof setInterval>); clearInterval(progressIntervalId.current as ReturnType<typeof setInterval>);
progressIntervalId.current = null;
} }
} else { } else {
const isLastTrackInQueue = usePlayerStore.getState().actions.checkIsLastTrack(); const isLastTrackInQueue = usePlayerStore.getState().actions.checkIsLastTrack();