feishin/src/renderer/features/player/hooks/use-center-controls.ts
2022-12-21 01:29:00 -08:00

523 lines
12 KiB
TypeScript

import { useCallback, useEffect } from 'react';
import isElectron from 'is-electron';
import { PlaybackType, PlayerRepeat, PlayerShuffle, PlayerStatus } from '/@/renderer/types';
import {
useCurrentPlayer,
useCurrentStatus,
useDefaultQueue,
usePlayerControls,
usePlayerStore,
useRepeatStatus,
useSetCurrentTime,
useShuffleStatus,
} from '/@/renderer/store';
import { useSettingsStore } from '/@/renderer/store/settings.store';
const mpvPlayer = window.electron.mpvPlayer;
const mpvPlayerListener = window.electron.mpvPlayerListener;
const ipc = window.electron.ipc;
export const useCenterControls = (args: { playersRef: any }) => {
const { playersRef } = args;
const settings = useSettingsStore((state) => state.player);
const currentPlayer = useCurrentPlayer();
const { setShuffle, setRepeat, play, pause, previous, next, setCurrentIndex, autoNext } =
usePlayerControls();
const setCurrentTime = useSetCurrentTime();
const queue = useDefaultQueue();
const playerStatus = useCurrentStatus();
const repeatStatus = useRepeatStatus();
const shuffleStatus = useShuffleStatus();
const playerType = useSettingsStore((state) => state.player.type);
const player1Ref = playersRef?.current?.player1;
const player2Ref = playersRef?.current?.player2;
const currentPlayerRef = currentPlayer === 1 ? player1Ref : player2Ref;
const nextPlayerRef = currentPlayer === 1 ? player2Ref : player1Ref;
const resetPlayers = useCallback(() => {
if (player1Ref.getInternalPlayer()) {
player1Ref.getInternalPlayer().currentTime = 0;
player1Ref.getInternalPlayer().pause();
}
if (player2Ref.getInternalPlayer()) {
player2Ref.getInternalPlayer().currentTime = 0;
player2Ref.getInternalPlayer().pause();
}
}, [player1Ref, player2Ref]);
const resetNextPlayer = useCallback(() => {
currentPlayerRef.getInternalPlayer().volume = 0.1;
nextPlayerRef.getInternalPlayer().currentTime = 0;
nextPlayerRef.getInternalPlayer().pause();
}, [currentPlayerRef, nextPlayerRef]);
const stopPlayback = useCallback(() => {
player1Ref.getInternalPlayer().pause();
player2Ref.getInternalPlayer().pause();
resetPlayers();
}, [player1Ref, player2Ref, resetPlayers]);
const isMpvPlayer = isElectron() && settings.type === PlaybackType.LOCAL;
const handlePlay = useCallback(() => {
if (isMpvPlayer) {
mpvPlayer.play();
} else {
currentPlayerRef.getInternalPlayer().play();
}
play();
}, [currentPlayerRef, isMpvPlayer, play]);
const handlePause = useCallback(() => {
if (isMpvPlayer) {
mpvPlayer.pause();
}
pause();
}, [isMpvPlayer, pause]);
const handleStop = useCallback(() => {
if (isMpvPlayer) {
mpvPlayer.stop();
} else {
stopPlayback();
}
setCurrentTime(0);
pause();
}, [isMpvPlayer, pause, setCurrentTime, stopPlayback]);
const handleToggleShuffle = useCallback(() => {
if (shuffleStatus === PlayerShuffle.NONE) {
const playerData = setShuffle(PlayerShuffle.TRACK);
return mpvPlayer.setQueueNext(playerData);
}
const playerData = setShuffle(PlayerShuffle.NONE);
return mpvPlayer.setQueueNext(playerData);
}, [setShuffle, shuffleStatus]);
const handleToggleRepeat = useCallback(() => {
if (repeatStatus === PlayerRepeat.NONE) {
const playerData = setRepeat(PlayerRepeat.ALL);
return mpvPlayer.setQueueNext(playerData);
}
if (repeatStatus === PlayerRepeat.ALL) {
const playerData = setRepeat(PlayerRepeat.ONE);
return mpvPlayer.setQueueNext(playerData);
}
return setRepeat(PlayerRepeat.NONE);
}, [repeatStatus, setRepeat]);
const checkIsLastTrack = useCallback(() => {
return usePlayerStore.getState().actions.checkIsLastTrack();
}, []);
const checkIsFirstTrack = useCallback(() => {
return usePlayerStore.getState().actions.checkIsFirstTrack();
}, []);
const handleAutoNext = useCallback(() => {
const isLastTrack = checkIsLastTrack();
const handleRepeatAll = {
local: () => {
const playerData = autoNext();
mpvPlayer.autoNext(playerData);
play();
},
web: () => {
autoNext();
},
};
const handleRepeatNone = {
local: () => {
if (isLastTrack) {
const playerData = setCurrentIndex(0);
mpvPlayer.setQueue(playerData);
mpvPlayer.pause();
pause();
} else {
const playerData = autoNext();
mpvPlayer.autoNext(playerData);
play();
}
},
web: () => {
if (isLastTrack) {
resetPlayers();
pause();
} else {
autoNext();
resetPlayers();
}
},
};
const handleRepeatOne = {
local: () => {
const playerData = autoNext();
mpvPlayer.autoNext(playerData);
play();
},
web: () => {
if (isLastTrack) {
resetPlayers();
} else {
autoNext();
resetPlayers();
}
},
};
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
case PlayerRepeat.ALL:
handleRepeatAll[playerType]();
break;
case PlayerRepeat.ONE:
handleRepeatOne[playerType]();
break;
default:
break;
}
}, [
autoNext,
checkIsLastTrack,
pause,
play,
playerType,
repeatStatus,
resetPlayers,
setCurrentIndex,
]);
const handleNextTrack = useCallback(() => {
const isLastTrack = checkIsLastTrack();
setCurrentTime(0);
const handleRepeatAll = {
local: () => {
const playerData = next();
mpvPlayer.setQueue(playerData);
mpvPlayer.next();
},
web: () => {
next();
},
};
const handleRepeatNone = {
local: () => {
if (isLastTrack) {
const playerData = setCurrentIndex(0);
mpvPlayer.setQueue(playerData);
mpvPlayer.pause();
pause();
} else {
const playerData = next();
mpvPlayer.setQueue(playerData);
mpvPlayer.next();
}
},
web: () => {
if (isLastTrack) {
setCurrentIndex(0);
resetPlayers();
pause();
} else {
next();
resetPlayers();
}
},
};
const handleRepeatOne = {
local: () => {
const playerData = next();
mpvPlayer.setQueue(playerData);
mpvPlayer.next();
},
web: () => {
if (!isLastTrack) {
next();
}
},
};
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
case PlayerRepeat.ALL:
handleRepeatAll[playerType]();
break;
case PlayerRepeat.ONE:
handleRepeatOne[playerType]();
break;
default:
break;
}
setCurrentTime(0);
}, [
checkIsLastTrack,
next,
pause,
playerType,
repeatStatus,
resetPlayers,
setCurrentIndex,
setCurrentTime,
]);
const handlePrevTrack = useCallback(() => {
const currentTime = isMpvPlayer
? usePlayerStore.getState().current.time
: currentPlayerRef.getCurrentTime();
// Reset the current track more than 10 seconds have elapsed
if (currentTime >= 10) {
setCurrentTime(0);
if (isMpvPlayer) {
return mpvPlayer.seekTo(0);
}
return currentPlayerRef.seekTo(0);
}
const isFirstTrack = checkIsFirstTrack();
const handleRepeatAll = {
local: () => {
if (!isFirstTrack) {
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
} else {
const playerData = setCurrentIndex(queue.length - 1);
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
}
},
web: () => {
if (isFirstTrack) {
setCurrentIndex(queue.length - 1);
resetPlayers();
} else {
previous();
resetPlayers();
}
},
};
const handleRepeatNone = {
local: () => {
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
},
web: () => {
if (isFirstTrack) {
resetPlayers();
pause();
} else {
previous();
resetPlayers();
}
},
};
const handleRepeatOne = {
local: () => {
if (!isFirstTrack) {
const playerData = previous();
mpvPlayer.setQueue(playerData);
mpvPlayer.previous();
} else {
mpvPlayer.stop();
}
},
web: () => {
previous();
resetPlayers();
},
};
switch (repeatStatus) {
case PlayerRepeat.NONE:
handleRepeatNone[playerType]();
break;
case PlayerRepeat.ALL:
handleRepeatAll[playerType]();
break;
case PlayerRepeat.ONE:
handleRepeatOne[playerType]();
break;
default:
break;
}
return setCurrentTime(0);
}, [
checkIsFirstTrack,
currentPlayerRef,
isMpvPlayer,
pause,
playerType,
previous,
queue.length,
repeatStatus,
resetPlayers,
setCurrentIndex,
setCurrentTime,
]);
const handlePlayPause = useCallback(() => {
if (queue) {
if (playerStatus === PlayerStatus.PAUSED) {
return handlePlay();
}
return handlePause();
}
return null;
}, [handlePause, handlePlay, playerStatus, queue]);
const handleSkipBackward = (seconds: number) => {
const currentTime = isMpvPlayer
? usePlayerStore.getState().current.time
: currentPlayerRef.getCurrentTime();
if (isMpvPlayer) {
const newTime = currentTime - seconds;
mpvPlayer.seek(-seconds);
setCurrentTime(newTime < 0 ? 0 : newTime);
} else {
const newTime = currentTime - seconds;
resetNextPlayer();
setCurrentTime(newTime);
currentPlayerRef.seekTo(newTime);
}
};
const handleSkipForward = (seconds: number) => {
const currentTime = isMpvPlayer
? usePlayerStore.getState().current.time
: currentPlayerRef.getCurrentTime();
if (isMpvPlayer) {
const newTime = currentTime + seconds;
mpvPlayer.seek(seconds);
setCurrentTime(newTime);
} else {
const checkNewTime = currentTime + seconds;
const songDuration = currentPlayerRef.player.player.duration;
const newTime = checkNewTime >= songDuration ? songDuration - 1 : checkNewTime;
resetNextPlayer();
setCurrentTime(newTime);
currentPlayerRef.seekTo(newTime);
}
};
const handleSeekSlider = useCallback(
(e: number | any) => {
setCurrentTime(e);
if (isMpvPlayer) {
mpvPlayer.seekTo(e);
} else {
currentPlayerRef.seekTo(e);
}
},
[currentPlayerRef, isMpvPlayer, setCurrentTime],
);
useEffect(() => {
if (isElectron()) {
mpvPlayerListener.rendererPlayPause(() => {
handlePlayPause();
});
mpvPlayerListener.rendererNext(() => {
handleNextTrack();
});
mpvPlayerListener.rendererPrevious(() => {
handlePrevTrack();
});
mpvPlayerListener.rendererPlay(() => {
handlePlay();
});
mpvPlayerListener.rendererPause(() => {
handlePause();
});
mpvPlayerListener.rendererStop(() => {
handleStop();
});
mpvPlayerListener.rendererCurrentTime((_event: any, time: number) => {
setCurrentTime(time);
});
mpvPlayerListener.rendererAutoNext(() => {
handleAutoNext();
});
}
return () => {
ipc?.removeAllListeners('renderer-player-play-pause');
ipc?.removeAllListeners('renderer-player-next');
ipc?.removeAllListeners('renderer-player-previous');
ipc?.removeAllListeners('renderer-player-play');
ipc?.removeAllListeners('renderer-player-pause');
ipc?.removeAllListeners('renderer-player-stop');
ipc?.removeAllListeners('renderer-player-current-time');
ipc?.removeAllListeners('renderer-player-auto-next');
};
}, [
autoNext,
handleAutoNext,
handleNextTrack,
handlePause,
handlePlay,
handlePlayPause,
handlePrevTrack,
handleStop,
isMpvPlayer,
next,
pause,
play,
previous,
setCurrentTime,
]);
return {
handleNextTrack,
handlePlayPause,
handlePrevTrack,
handleSeekSlider,
handleSkipBackward,
handleSkipForward,
handleStop,
handleToggleRepeat,
handleToggleShuffle,
};
};