move timestamp update to separate effect

This commit is contained in:
jeffvli
2025-11-16 21:37:07 -08:00
parent 6842da1d68
commit a78d917fd2
4 changed files with 74 additions and 29 deletions
@@ -17,7 +17,7 @@ interface MpvPlayerEngineProps {
nextSrc: string | undefined;
onEnded: () => void;
onProgress: (e: PlayerOnProgressProps) => void;
playerRef: RefObject<MpvPlayerEngineHandle>;
playerRef: RefObject<MpvPlayerEngineHandle | null>;
playerStatus: PlayerStatus;
speed?: number;
volume: number;
@@ -109,7 +109,9 @@ export const MpvPlayerEngine = (props: MpvPlayerEngineProps) => {
}
const vol = volume / 100 || 0;
setInternalVolume(vol);
queueMicrotask(() => {
setInternalVolume(vol);
});
mpvPlayer.volume(volume);
}, [volume]);
@@ -147,11 +149,15 @@ export const MpvPlayerEngine = (props: MpvPlayerEngineProps) => {
if (currentSrc) {
// Set current song at position 0 and next song at position 1
mpvPlayer.setQueue(currentSrc, nextSrc, playerStatus !== PlayerStatus.PLAYING);
setPreviousCurrentSrc(currentSrc);
setTimeout(() => {
setPreviousCurrentSrc(currentSrc);
}, 0);
} else {
// Clear queue if no current song
mpvPlayer.setQueue(undefined, undefined, true);
setPreviousCurrentSrc(undefined);
setTimeout(() => {
setPreviousCurrentSrc(undefined);
}, 0);
}
} else {
// If currentSrc hasn't changed but nextSrc has, update position 1
@@ -26,7 +26,7 @@ interface WebPlayerEngineProps {
onProgressPlayer1: (e: PlayerOnProgressProps) => void;
onProgressPlayer2: (e: PlayerOnProgressProps) => void;
playerNum: number;
playerRef: RefObject<WebPlayerEngineHandle>;
playerRef: RefObject<null | WebPlayerEngineHandle>;
playerStatus: PlayerStatus;
speed?: number;
src1: string | undefined;
@@ -1,10 +1,10 @@
import { useCallback, useRef, useState } from 'react';
import isElectron from 'is-electron';
import { useCallback, useEffect, useRef, useState } from 'react';
import { MpvPlayerEngine, MpvPlayerEngineHandle } from './engine/mpv-player-engine';
import { useMainPlayerListener } from '/@/renderer/features/player/audio-player/hooks/use-main-player-listener';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
import {
usePlayerActions,
usePlayerData,
@@ -17,6 +17,8 @@ import { PlayerStatus } from '/@/shared/types/types';
const PLAY_PAUSE_FADE_DURATION = 300;
const PLAY_PAUSE_FADE_INTERVAL = 10;
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
export function MpvPlayer() {
const playerRef = useRef<MpvPlayerEngineHandle>(null);
const { currentSong, nextSong, status } = usePlayerData();
@@ -64,12 +66,10 @@ export function MpvPlayer() {
[isTransitioning],
);
const onProgress = useCallback(
(e: PlayerOnProgressProps) => {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
},
[setTimestamp],
);
const onProgress = useCallback(() => {
// Progress callback is now only used for transition logic
// Timestamp updates are handled separately in useEffect
}, []);
const handleOnEnded = useCallback(() => {
// When mpv auto-advances to the next song (position 1 becomes position 0),
@@ -107,6 +107,29 @@ export function MpvPlayer() {
[volume, isTransitioning, fadeAndSetStatus],
);
useEffect(() => {
if (localPlayerStatus !== PlayerStatus.PLAYING) {
return;
}
const interval = setInterval(async () => {
if (!mpvPlayer) {
return;
}
try {
const time = await mpvPlayer.getCurrentTime();
if (time !== undefined) {
setTimestamp(Number(time.toFixed(0)));
}
} catch {
// Do nothing
}
}, 500);
return () => clearInterval(interval);
}, [localPlayerStatus, setTimestamp]);
useMainPlayerListener();
return (
@@ -1,7 +1,7 @@
import type { Dispatch } from 'react';
import type ReactPlayer from 'react-player';
import { useCallback, useRef, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import {
WebPlayerEngine,
@@ -23,7 +23,7 @@ const PLAY_PAUSE_FADE_DURATION = 300;
const PLAY_PAUSE_FADE_INTERVAL = 10;
export function WebPlayer() {
const playerRef = useRef<WebPlayerEngineHandle>(null);
const playerRef = useRef<null | WebPlayerEngineHandle>(null);
const { num, player1, player2, status } = usePlayerData();
const { mediaAutoNext, setTimestamp } = usePlayerActions();
const { crossfadeDuration, speed, transitionType } = usePlayerProperties();
@@ -71,12 +71,6 @@ export function WebPlayer() {
const onProgressPlayer1 = useCallback(
(e: PlayerOnProgressProps) => {
if (transitionType === 'crossfade' && num === 1) {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
} else if (transitionType === 'gapless') {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
}
if (!playerRef.current?.player1()) {
return;
}
@@ -108,17 +102,11 @@ export function WebPlayer() {
break;
}
},
[crossfadeDuration, isTransitioning, num, setTimestamp, transitionType, volume],
[crossfadeDuration, isTransitioning, num, transitionType, volume],
);
const onProgressPlayer2 = useCallback(
(e: PlayerOnProgressProps) => {
if (transitionType === PlayerStyle.CROSSFADE && num === 2) {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
} else if (transitionType === PlayerStyle.GAPLESS) {
setTimestamp(Number(e.playedSeconds.toFixed(0)));
}
if (!playerRef.current?.player2()) {
return;
}
@@ -150,7 +138,7 @@ export function WebPlayer() {
break;
}
},
[crossfadeDuration, isTransitioning, num, setTimestamp, transitionType, volume],
[crossfadeDuration, isTransitioning, num, transitionType, volume],
);
const handleOnEndedPlayer1 = useCallback(() => {
@@ -205,6 +193,34 @@ export function WebPlayer() {
[volume, num, isTransitioning],
);
useEffect(() => {
if (localPlayerStatus !== PlayerStatus.PLAYING) {
return;
}
const interval = setInterval(() => {
const activePlayer =
num === 1 ? playerRef.current?.player1() : playerRef.current?.player2();
const internalPlayer =
activePlayer?.ref?.getInternalPlayer() as HTMLAudioElement | null;
if (!internalPlayer) {
return;
}
const currentTime = internalPlayer.currentTime;
if (
transitionType === PlayerStyle.CROSSFADE ||
transitionType === PlayerStyle.GAPLESS
) {
setTimestamp(Number(currentTime.toFixed(0)));
}
}, 500);
return () => clearInterval(interval);
}, [localPlayerStatus, num, setTimestamp, transitionType]);
useMainPlayerListener();
return (