resend mediasession on player repeat (#1472)

This commit is contained in:
jeffvli
2026-01-01 20:17:49 -08:00
parent af8470e254
commit aaf840d358
4 changed files with 58 additions and 16 deletions
+5
View File
@@ -11,6 +11,7 @@ export type EventMap = {
MEDIA_NEXT: MediaNextEventPayload; MEDIA_NEXT: MediaNextEventPayload;
MEDIA_PREV: MediaPrevEventPayload; MEDIA_PREV: MediaPrevEventPayload;
PLAYER_PLAY: PlayerPlayEventPayload; PLAYER_PLAY: PlayerPlayEventPayload;
PLAYER_REPEATED: PlayerRepeatedEventPayload;
PLAYLIST_MOVE_DOWN: PlaylistMoveEventPayload; PLAYLIST_MOVE_DOWN: PlaylistMoveEventPayload;
PLAYLIST_MOVE_TO_BOTTOM: PlaylistMoveEventPayload; PLAYLIST_MOVE_TO_BOTTOM: PlaylistMoveEventPayload;
PLAYLIST_MOVE_TO_TOP: PlaylistMoveEventPayload; PLAYLIST_MOVE_TO_TOP: PlaylistMoveEventPayload;
@@ -46,6 +47,10 @@ export type PlayerPlayEventPayload = {
index: number; index: number;
}; };
export type PlayerRepeatedEventPayload = {
index: number;
};
export type PlaylistMoveEventPayload = { export type PlaylistMoveEventPayload = {
playlistId: string; playlistId: string;
sourceIds: string[]; sourceIds: string[];
@@ -35,6 +35,7 @@ interface PlayerEventsCallbacks {
onPlayerProgress?: (properties: { timestamp: number }, prev: { timestamp: number }) => void; onPlayerProgress?: (properties: { timestamp: number }, prev: { timestamp: number }) => void;
onPlayerQueueChange?: (queue: QueueData, prev: QueueData) => void; onPlayerQueueChange?: (queue: QueueData, prev: QueueData) => void;
onPlayerRepeat?: (properties: { repeat: PlayerRepeat }, prev: { repeat: PlayerRepeat }) => void; onPlayerRepeat?: (properties: { repeat: PlayerRepeat }, prev: { repeat: PlayerRepeat }) => void;
onPlayerRepeated?: (properties: { index: number }) => void;
onPlayerSeek?: (properties: { seconds: number }, prev: { seconds: number }) => void; onPlayerSeek?: (properties: { seconds: number }, prev: { seconds: number }) => void;
onPlayerSeekToTimestamp?: ( onPlayerSeekToTimestamp?: (
properties: { timestamp: number }, properties: { timestamp: number },
@@ -161,6 +162,10 @@ function createPlayerEvents(callbacks: PlayerEventsCallbacks): PlayerEvents {
eventEmitter.on('PLAYER_PLAY', callbacks.onPlayerPlay); eventEmitter.on('PLAYER_PLAY', callbacks.onPlayerPlay);
} }
if (callbacks.onPlayerRepeated) {
eventEmitter.on('PLAYER_REPEATED', callbacks.onPlayerRepeated);
}
if (callbacks.onQueueRestored) { if (callbacks.onQueueRestored) {
eventEmitter.on('QUEUE_RESTORED', callbacks.onQueueRestored); eventEmitter.on('QUEUE_RESTORED', callbacks.onQueueRestored);
} }
@@ -185,6 +190,9 @@ function createPlayerEvents(callbacks: PlayerEventsCallbacks): PlayerEvents {
if (callbacks.onPlayerPlay) { if (callbacks.onPlayerPlay) {
eventEmitter.off('PLAYER_PLAY', callbacks.onPlayerPlay); eventEmitter.off('PLAYER_PLAY', callbacks.onPlayerPlay);
} }
if (callbacks.onPlayerRepeated) {
eventEmitter.off('PLAYER_REPEATED', callbacks.onPlayerRepeated);
}
if (callbacks.onQueueRestored) { if (callbacks.onQueueRestored) {
eventEmitter.off('QUEUE_RESTORED', callbacks.onQueueRestored); eventEmitter.off('QUEUE_RESTORED', callbacks.onQueueRestored);
} }
@@ -1,11 +1,16 @@
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { useEffect, useMemo } from 'react'; import { useCallback, useEffect, useMemo } from 'react';
import { getItemImageUrl } from '/@/renderer/components/item-image/item-image'; import { getItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events'; import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { usePlayer } from '/@/renderer/features/player/context/player-context';
import { usePlaybackSettings, useSettingsStore, useTimestampStoreBase } from '/@/renderer/store'; import {
import { LibraryItem } from '/@/shared/types/domain-types'; usePlaybackSettings,
usePlayerStore,
useSettingsStore,
useTimestampStoreBase,
} from '/@/renderer/store';
import { LibraryItem, QueueSong } from '/@/shared/types/domain-types';
import { PlayerStatus, PlayerType } from '/@/shared/types/types'; import { PlayerStatus, PlayerType } from '/@/shared/types/types';
const mediaSession = navigator.mediaSession; const mediaSession = navigator.mediaSession;
@@ -85,6 +90,29 @@ export const useMediaSession = () => {
}; };
}, [player, skip?.skipBackwardSeconds, skip?.skipForwardSeconds, isMediaSessionEnabled]); }, [player, skip?.skipBackwardSeconds, skip?.skipForwardSeconds, isMediaSessionEnabled]);
const updateMediaSessionMetadata = useCallback(
(song: QueueSong | undefined) => {
if (!isMediaSessionEnabled || !song) {
return;
}
const imageUrl = getItemImageUrl({
id: song?.imageId || undefined,
imageUrl: song?.imageUrl,
itemType: LibraryItem.SONG,
type: 'itemCard',
});
mediaSession.metadata = new MediaMetadata({
album: song?.album ?? '',
artist: song?.artistName ?? '',
artwork: imageUrl ? [{ src: imageUrl, type: 'image/png' }] : [],
title: song?.name ?? '',
});
},
[isMediaSessionEnabled],
);
usePlayerEvents( usePlayerEvents(
{ {
onCurrentSongChange: (properties) => { onCurrentSongChange: (properties) => {
@@ -92,20 +120,15 @@ export const useMediaSession = () => {
return; return;
} }
const song = properties.song; updateMediaSessionMetadata(properties.song);
const imageUrl = getItemImageUrl({ },
id: song?.imageId || undefined, onPlayerRepeated: () => {
imageUrl: song?.imageUrl, if (!isMediaSessionEnabled) {
itemType: LibraryItem.SONG, return;
type: 'itemCard', }
});
mediaSession.metadata = new MediaMetadata({ const currentSong = usePlayerStore.getState().getCurrentSong();
album: song?.album ?? '', updateMediaSessionMetadata(currentSong);
artist: song?.artistName ?? '',
artwork: imageUrl ? [{ src: imageUrl, type: 'image/png' }] : [],
title: song?.name ?? '',
});
}, },
onPlayerStatus: (properties) => { onPlayerStatus: (properties) => {
if (!isMediaSessionEnabled) { if (!isMediaSessionEnabled) {
+6
View File
@@ -1367,6 +1367,12 @@ export const usePlayerStoreBase = createWithEqualityFn<PlayerState>()(
state.player.status = newStatus; state.player.status = newStatus;
}); });
if (repeat === PlayerRepeat.ONE && nextIndex === currentIndex) {
eventEmitter.emit('PLAYER_REPEATED', {
index: nextIndex,
});
}
const nextSong = calculateNextSong(nextIndex, queue.items, repeat); const nextSong = calculateNextSong(nextIndex, queue.items, repeat);
return { return {