mirror of
https://github.com/antebudimir/feishin.git
synced 2025-12-31 18:13:31 +00:00
More typechecks on scrobble, use timeout on notification (#1004)
This commit is contained in:
parent
56130d8503
commit
69341f4492
1 changed files with 35 additions and 23 deletions
|
|
@ -34,6 +34,8 @@ Progress Events (Jellyfin only):
|
|||
- Sends the 'progress' scrobble event on an interval
|
||||
*/
|
||||
|
||||
type PlayerEvent = [PlayerStatus, number];
|
||||
|
||||
type SongEvent = [QueueSong | undefined, number, 1 | 2];
|
||||
|
||||
const checkScrobbleConditions = (args: {
|
||||
|
|
@ -86,21 +88,35 @@ export const useScrobble = () => {
|
|||
);
|
||||
|
||||
const progressIntervalId = useRef<null | ReturnType<typeof setInterval>>(null);
|
||||
const songChangeTimeoutId = useRef<null | ReturnType<typeof setTimeout>>(null);
|
||||
const songChangeTimeoutId = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const notifyTimeoutId = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
|
||||
const handleScrobbleFromSongChange = useCallback(
|
||||
(current: SongEvent, previous: SongEvent) => {
|
||||
if (scrobbleSettings?.notify && current[0]) {
|
||||
if (scrobbleSettings?.notify && current[0]?.id) {
|
||||
clearTimeout(notifyTimeoutId.current);
|
||||
const currentSong = current[0];
|
||||
|
||||
const artists =
|
||||
currentSong.artists?.length > 0
|
||||
? currentSong.artists.map((artist) => artist.name).join(', ')
|
||||
: currentSong.artistName;
|
||||
// Set a delay so that quickly (within a second) switching songs doesn't trigger multiple
|
||||
// notifications
|
||||
notifyTimeoutId.current = setTimeout(() => {
|
||||
// Only trigger if the song changed, or the player changed. This should be the case
|
||||
// anyways, but who knows
|
||||
if (
|
||||
currentSong.uniqueId !== previous[0]?.uniqueId ||
|
||||
current[2] !== previous[2]
|
||||
) {
|
||||
const artists =
|
||||
currentSong.artists?.length > 0
|
||||
? currentSong.artists.map((artist) => artist.name).join(', ')
|
||||
: currentSong.artistName;
|
||||
|
||||
new Notification(`Now playing ${currentSong.name}`, {
|
||||
body: `by ${artists} on ${currentSong.album}`,
|
||||
icon: currentSong.imageUrl || undefined,
|
||||
});
|
||||
new Notification(`Now playing ${currentSong.name}`, {
|
||||
body: `by ${artists} on ${currentSong.album}`,
|
||||
icon: currentSong.imageUrl || undefined,
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if (!isScrobbleEnabled) return;
|
||||
|
|
@ -110,7 +126,6 @@ export const useScrobble = () => {
|
|||
progressIntervalId.current = null;
|
||||
}
|
||||
|
||||
// const currentSong = current[0] as QueueSong | undefined;
|
||||
const previousSong = previous[0];
|
||||
const previousSongTimeSec = previous[1];
|
||||
|
||||
|
|
@ -146,7 +161,7 @@ export const useScrobble = () => {
|
|||
setIsCurrentSongScrobbled(false);
|
||||
|
||||
// Use a timeout to prevent spamming the server with scrobble events when switching through songs quickly
|
||||
clearTimeout(songChangeTimeoutId.current as ReturnType<typeof setTimeout>);
|
||||
clearTimeout(songChangeTimeoutId.current);
|
||||
songChangeTimeoutId.current = setTimeout(() => {
|
||||
const currentSong = current[0];
|
||||
// Get the current status from the state, not variable. This is because
|
||||
|
|
@ -193,10 +208,7 @@ export const useScrobble = () => {
|
|||
);
|
||||
|
||||
const handleScrobbleFromStatusChange = useCallback(
|
||||
(
|
||||
current: (number | PlayerStatus | undefined)[],
|
||||
previous: (number | PlayerStatus | undefined)[],
|
||||
) => {
|
||||
(current: PlayerEvent, previous: PlayerEvent) => {
|
||||
if (!isScrobbleEnabled) return;
|
||||
|
||||
const currentSong = usePlayerStore.getState().current.song;
|
||||
|
|
@ -208,8 +220,8 @@ export const useScrobble = () => {
|
|||
? usePlayerStore.getState().current.time * 1e7
|
||||
: undefined;
|
||||
|
||||
const currentStatus = current[0] as PlayerStatus;
|
||||
const currentTimeSec = current[1] as number;
|
||||
const currentStatus = current[0];
|
||||
const currentTimeSec = current[1];
|
||||
|
||||
// Whenever the player is restarted, send a 'start' scrobble
|
||||
if (currentStatus === PlayerStatus.PLAYING) {
|
||||
|
|
@ -249,12 +261,12 @@ export const useScrobble = () => {
|
|||
});
|
||||
|
||||
if (progressIntervalId.current) {
|
||||
clearInterval(progressIntervalId.current as ReturnType<typeof setInterval>);
|
||||
clearInterval(progressIntervalId.current);
|
||||
progressIntervalId.current = null;
|
||||
}
|
||||
} else {
|
||||
const isLastTrackInQueue = usePlayerStore.getState().actions.checkIsLastTrack();
|
||||
const previousTimeSec = previous[1] as number;
|
||||
const previousTimeSec = previous[1];
|
||||
|
||||
// If not already scrobbled, send a 'submission' scrobble if conditions are met
|
||||
const shouldSubmitScrobble = checkScrobbleConditions({
|
||||
|
|
@ -358,17 +370,17 @@ export const useScrobble = () => {
|
|||
// multiple times in a row and playback goes normally (no next/previous)
|
||||
equalityFn: (a, b) =>
|
||||
// compute whether the song changed
|
||||
(a[0] as QueueSong)?.uniqueId === (b[0] as QueueSong)?.uniqueId &&
|
||||
a[0]?.uniqueId === b[0]?.uniqueId &&
|
||||
// compute whether the same player: relevant for repeat one and repeat all (one track)
|
||||
a[2] === b[2],
|
||||
},
|
||||
);
|
||||
|
||||
const unsubStatusChange = usePlayerStore.subscribe(
|
||||
(state) => [state.current.status, state.current.time],
|
||||
(state): PlayerEvent => [state.current.status, state.current.time],
|
||||
handleScrobbleFromStatusChange,
|
||||
{
|
||||
equalityFn: (a, b) => (a[0] as PlayerStatus) === (b[0] as PlayerStatus),
|
||||
equalityFn: (a, b) => a[0] === b[0],
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue