re-implement mpv with new player

This commit is contained in:
jeffvli
2025-11-05 19:01:15 -08:00
parent a452495c22
commit 9fd4abec25
17 changed files with 642 additions and 233 deletions
@@ -0,0 +1,147 @@
import { t } from 'i18next';
import isElectron from 'is-electron';
import { useCallback, useEffect } from 'react';
import { usePlayerActions } from '/@/renderer/store';
import { toast } from '/@/shared/components/toast/toast';
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
const mpvPlayerListener = isElectron() ? window.api.mpvPlayerListener : null;
const ipc = isElectron() ? window.api.ipc : null;
export const useMainPlayerListener = () => {
const {
decreaseVolume,
increaseVolume,
mediaAutoNext,
mediaNext,
mediaPause,
mediaPlay,
mediaPrevious,
mediaSkipBackward,
mediaSkipForward,
mediaStop,
mediaToggleMute,
mediaTogglePlayPause,
toggleRepeat,
toggleShuffle,
} = usePlayerActions();
const handleMpvError = useCallback(
(message: string) => {
toast.error({
id: 'mpv-error',
message,
title: t('error.playbackError', { postProcess: 'sentenceCase' }) as string,
});
mediaPause();
mpvPlayer!.pause();
},
[mediaPause],
);
useEffect(() => {
if (!mpvPlayerListener) {
return;
}
mpvPlayerListener.rendererPlayPause(() => {
mediaTogglePlayPause();
});
mpvPlayerListener.rendererNext(() => {
mediaNext();
});
mpvPlayerListener.rendererPrevious(() => {
mediaPrevious();
});
mpvPlayerListener.rendererPlayPause(() => {
mediaTogglePlayPause();
});
mpvPlayerListener.rendererPlay(() => {
mediaPlay();
});
mpvPlayerListener.rendererPause(() => {
mediaPause();
});
mpvPlayerListener.rendererStop(() => {
mediaStop();
});
mpvPlayerListener.rendererSkipForward(() => {
mediaSkipForward();
});
mpvPlayerListener.rendererSkipBackward(() => {
mediaSkipBackward();
});
mpvPlayerListener.rendererAutoNext(() => {
mediaAutoNext();
});
mpvPlayerListener.rendererToggleShuffle(() => {
toggleShuffle();
});
mpvPlayerListener.rendererToggleRepeat(() => {
toggleRepeat();
});
mpvPlayerListener.rendererVolumeMute(() => {
mediaToggleMute();
});
mpvPlayerListener.rendererVolumeUp(() => {
increaseVolume(1);
});
mpvPlayerListener.rendererVolumeDown(() => {
decreaseVolume(1);
});
mpvPlayerListener.rendererError((_event: any, message: string) => {
handleMpvError(message);
});
return () => {
ipc?.removeAllListeners('renderer-player-play-pause');
ipc?.removeAllListeners('renderer-player-next');
ipc?.removeAllListeners('renderer-player-previous');
ipc?.removeAllListeners('renderer-player-play-pause');
ipc?.removeAllListeners('renderer-player-play');
ipc?.removeAllListeners('renderer-player-pause');
ipc?.removeAllListeners('renderer-player-stop');
ipc?.removeAllListeners('renderer-player-skip-forward');
ipc?.removeAllListeners('renderer-player-skip-backward');
ipc?.removeAllListeners('renderer-player-auto-next');
ipc?.removeAllListeners('renderer-player-toggle-shuffle');
ipc?.removeAllListeners('renderer-player-toggle-repeat');
ipc?.removeAllListeners('renderer-player-volume-mute');
ipc?.removeAllListeners('renderer-player-volume-up');
ipc?.removeAllListeners('renderer-player-volume-down');
ipc?.removeAllListeners('renderer-player-error');
};
}, [
decreaseVolume,
handleMpvError,
increaseVolume,
mediaAutoNext,
mediaNext,
mediaPause,
mediaPlay,
mediaPrevious,
mediaSkipForward,
mediaSkipBackward,
mediaStop,
mediaToggleMute,
mediaTogglePlayPause,
toggleRepeat,
toggleShuffle,
]);
};
@@ -0,0 +1,105 @@
import { useEffect } from 'react';
import {
subscribeCurrentTrack,
subscribePlayerMute,
subscribePlayerProgress,
subscribePlayerQueue,
subscribePlayerSeekToTimestamp,
subscribePlayerSpeed,
subscribePlayerStatus,
subscribePlayerVolume,
} from '/@/renderer/store';
import { QueueData, QueueSong } from '/@/shared/types/domain-types';
import { PlayerStatus } from '/@/shared/types/types';
interface PlayerEvents {
cleanup: () => void;
}
interface PlayerEventsCallbacks {
onCurrentSongChange?: (
properties: { index: number; song: QueueSong | undefined },
prev: { index: number; song: QueueSong | undefined },
) => void;
onPlayerMute?: (properties: { muted: boolean }, prev: { muted: boolean }) => void;
onPlayerProgress?: (properties: { timestamp: number }, prev: { timestamp: number }) => void;
onPlayerQueueChange?: (queue: QueueData, prev: QueueData) => void;
onPlayerSeek?: (properties: { seconds: number }, prev: { seconds: number }) => void;
onPlayerSeekToTimestamp?: (
properties: { timestamp: number },
prev: { timestamp: number },
) => void;
onPlayerSpeed?: (properties: { speed: number }, prev: { speed: number }) => void;
onPlayerStatus?: (properties: { status: PlayerStatus }, prev: { status: PlayerStatus }) => void;
onPlayerVolume?: (properties: { volume: number }, prev: { volume: number }) => void;
}
export function usePlayerEvents(callbacks: PlayerEventsCallbacks, deps: React.DependencyList) {
useEffect(() => {
const engine = createPlayerEvents(callbacks);
return () => {
engine.cleanup();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...deps]);
}
function createPlayerEvents(callbacks: PlayerEventsCallbacks): PlayerEvents {
const unsubscribers: (() => void)[] = [];
// Subscribe to current track changes
if (callbacks.onCurrentSongChange) {
const unsubscribe = subscribeCurrentTrack(callbacks.onCurrentSongChange);
unsubscribers.push(unsubscribe);
}
// Subscribe to player progress
if (callbacks.onPlayerProgress) {
const unsubscribe = subscribePlayerProgress(callbacks.onPlayerProgress);
unsubscribers.push(unsubscribe);
}
// Subscribe to queue changes
if (callbacks.onPlayerQueueChange) {
const unsubscribe = subscribePlayerQueue(callbacks.onPlayerQueueChange);
unsubscribers.push(unsubscribe);
}
// Subscribe to seek events
if (callbacks.onPlayerSeekToTimestamp) {
const unsubscribe = subscribePlayerSeekToTimestamp(callbacks.onPlayerSeekToTimestamp);
unsubscribers.push(unsubscribe);
}
// Subscribe to player status changes
if (callbacks.onPlayerStatus) {
const unsubscribe = subscribePlayerStatus(callbacks.onPlayerStatus);
unsubscribers.push(unsubscribe);
}
// Subscribe to volume changes
if (callbacks.onPlayerVolume) {
const unsubscribe = subscribePlayerVolume(callbacks.onPlayerVolume);
unsubscribers.push(unsubscribe);
}
// Subscribe to mute changes
if (callbacks.onPlayerMute) {
const unsubscribe = subscribePlayerMute(callbacks.onPlayerMute);
unsubscribers.push(unsubscribe);
}
// Subscribe to speed changes
if (callbacks.onPlayerSpeed) {
const unsubscribe = subscribePlayerSpeed(callbacks.onPlayerSpeed);
unsubscribers.push(unsubscribe);
}
return {
cleanup: () => {
unsubscribers.forEach((unsubscribe) => unsubscribe());
},
};
}