Merge pull request #1252 from erik-kroon/erik-kroon/mac-media-keys
Some checks are pending
Build / build (push) Waiting to run

Handle macOS media controls in player
This commit is contained in:
Timothy Z. 2026-05-02 22:40:08 +03:00 committed by GitHub
commit d2a116cd04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 10 deletions

View file

@ -255,6 +255,12 @@ const Player = ({ urlParams, queryParams }) => {
} }
}, [player.nextVideo, handleNextVideoNavigation, profile.settings]); }, [player.nextVideo, handleNextVideoNavigation, profile.settings]);
const onPreviousTrackRequested = React.useCallback(() => {
if (video.state.time !== null && video.state.time > 5000) {
onSeekRequested(0);
}
}, [video.state.time, onSeekRequested]);
const onVideoClick = React.useCallback(() => { const onVideoClick = React.useCallback(() => {
if (video.state.paused !== null && !longPress.current) { if (video.state.paused !== null && !longPress.current) {
if (video.state.paused) { if (video.state.paused) {
@ -534,13 +540,21 @@ const Player = ({ urlParams, queryParams }) => {
} }
}, [settings.pauseOnMinimize, shell.windowClosed, shell.windowHidden]); }, [settings.pauseOnMinimize, shell.windowClosed, shell.windowHidden]);
useMediaSession(video.state, player, onPlayRequested, onPauseRequested, onNextVideoRequested); useMediaSession(video.state, player, onPlayRequested, onPauseRequested, onNextVideoRequested, onPreviousTrackRequested);
React.useEffect(() => { React.useEffect(() => {
const onMediaKey = (action) => { const onMediaKey = (action) => {
switch (action) { switch (action) {
case 'play-pause': case 'play-pause':
video.state.paused ? onPlayRequested() : onPauseRequested(); if (video.state.paused !== null) {
video.state.paused ? onPlayRequested() : onPauseRequested();
}
break;
case 'play':
onPlayRequested();
break;
case 'pause':
onPauseRequested();
break; break;
case 'next-track': case 'next-track':
if (player.nextVideo !== null) { if (player.nextVideo !== null) {
@ -549,15 +563,13 @@ const Player = ({ urlParams, queryParams }) => {
} }
break; break;
case 'previous-track': case 'previous-track':
if (video.state.time !== null && video.state.time > 5000) { onPreviousTrackRequested();
onSeekRequested(0);
}
break; break;
} }
}; };
shell.on('media-key', onMediaKey); shell.on('media-key', onMediaKey);
return () => shell.off('media-key', onMediaKey); return () => shell.off('media-key', onMediaKey);
}, [video.state.paused, video.state.time, player.nextVideo, onPlayRequested, onPauseRequested, onNextVideoRequested, onSeekRequested]); }, [video.state.paused, player.nextVideo, onPlayRequested, onPauseRequested, onNextVideoRequested, onPreviousTrackRequested]);
onShortcut('seekForward', (combo) => { onShortcut('seekForward', (combo) => {
if (video.state.time !== null) { if (video.state.time !== null) {

View file

@ -6,11 +6,12 @@ const useMediaSession = (
onPlayRequested: () => void, onPlayRequested: () => void,
onPauseRequested: () => void, onPauseRequested: () => void,
onNextVideoRequested: () => void, onNextVideoRequested: () => void,
onPreviousTrackRequested: () => void,
) => { ) => {
useEffect(() => { useEffect(() => {
if (!navigator.mediaSession) return; if (!navigator.mediaSession) return;
const playbackState = !videoState.paused ? 'playing' : 'paused'; const playbackState = videoState.paused === null ? 'none' : videoState.paused ? 'paused' : 'playing';
navigator.mediaSession.playbackState = playbackState; navigator.mediaSession.playbackState = playbackState;
return () => { return () => {
@ -49,9 +50,17 @@ const useMediaSession = (
navigator.mediaSession.setActionHandler('play', onPlayRequested); navigator.mediaSession.setActionHandler('play', onPlayRequested);
navigator.mediaSession.setActionHandler('pause', onPauseRequested); navigator.mediaSession.setActionHandler('pause', onPauseRequested);
const nexVideoCallback = player.nextVideo ? onNextVideoRequested : null; const nextVideoCallback = player.nextVideo ? onNextVideoRequested : null;
navigator.mediaSession.setActionHandler('nexttrack', nexVideoCallback); navigator.mediaSession.setActionHandler('nexttrack', nextVideoCallback);
}, [player.nextVideo, onPlayRequested, onPauseRequested, onNextVideoRequested]); navigator.mediaSession.setActionHandler('previoustrack', onPreviousTrackRequested);
return () => {
navigator.mediaSession.setActionHandler('play', null);
navigator.mediaSession.setActionHandler('pause', null);
navigator.mediaSession.setActionHandler('nexttrack', null);
navigator.mediaSession.setActionHandler('previoustrack', null);
};
}, [player.nextVideo, onPlayRequested, onPauseRequested, onNextVideoRequested, onPreviousTrackRequested]);
}; };
export default useMediaSession; export default useMediaSession;