mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-31 08:18:35 +00:00
152 lines
4.6 KiB
TypeScript
152 lines
4.6 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
|
|
|
import { useCaptions } from "@/components/player/hooks/useCaptions";
|
|
import { useVolume } from "@/components/player/hooks/useVolume";
|
|
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
|
|
import { usePlayerStore } from "@/stores/player/store";
|
|
import { useEmpheralVolumeStore } from "@/stores/volume";
|
|
|
|
export function KeyboardEvents() {
|
|
const router = useOverlayRouter("");
|
|
const display = usePlayerStore((s) => s.display);
|
|
const mediaProgress = usePlayerStore((s) => s.progress);
|
|
const { isSeeking } = usePlayerStore((s) => s.interface);
|
|
const mediaPlaying = usePlayerStore((s) => s.mediaPlaying);
|
|
const time = usePlayerStore((s) => s.progress.time);
|
|
const { setVolume, toggleMute } = useVolume();
|
|
|
|
const { toggleLastUsed } = useCaptions();
|
|
const setShowVolume = useEmpheralVolumeStore((s) => s.setShowVolume);
|
|
|
|
const [isRolling, setIsRolling] = useState(false);
|
|
const volumeDebounce = useRef<ReturnType<typeof setTimeout> | undefined>();
|
|
|
|
const dataRef = useRef({
|
|
setShowVolume,
|
|
setVolume,
|
|
toggleMute,
|
|
setIsRolling,
|
|
toggleLastUsed,
|
|
display,
|
|
mediaPlaying,
|
|
mediaProgress,
|
|
isSeeking,
|
|
isRolling,
|
|
time,
|
|
router,
|
|
});
|
|
useEffect(() => {
|
|
dataRef.current = {
|
|
setShowVolume,
|
|
setVolume,
|
|
toggleMute,
|
|
setIsRolling,
|
|
toggleLastUsed,
|
|
display,
|
|
mediaPlaying,
|
|
mediaProgress,
|
|
isSeeking,
|
|
isRolling,
|
|
time,
|
|
router,
|
|
};
|
|
}, [
|
|
setShowVolume,
|
|
setVolume,
|
|
toggleMute,
|
|
setIsRolling,
|
|
toggleLastUsed,
|
|
display,
|
|
mediaPlaying,
|
|
mediaProgress,
|
|
isSeeking,
|
|
isRolling,
|
|
time,
|
|
router,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const keyEventHandler = (evt: KeyboardEvent) => {
|
|
if (evt.target && (evt.target as HTMLInputElement).nodeName === "INPUT")
|
|
return;
|
|
|
|
const k = evt.key;
|
|
|
|
// Volume
|
|
if (["ArrowUp", "ArrowDown", "m"].includes(k)) {
|
|
dataRef.current.setShowVolume(true);
|
|
|
|
if (volumeDebounce.current) clearTimeout(volumeDebounce.current);
|
|
volumeDebounce.current = setTimeout(() => {
|
|
dataRef.current.setShowVolume(false);
|
|
}, 3e3);
|
|
}
|
|
if (k === "ArrowUp")
|
|
dataRef.current.setVolume(
|
|
(dataRef.current.mediaPlaying?.volume || 0) + 0.15,
|
|
);
|
|
if (k === "ArrowDown")
|
|
dataRef.current.setVolume(
|
|
(dataRef.current.mediaPlaying?.volume || 0) - 0.15,
|
|
);
|
|
if (k === "m") dataRef.current.toggleMute();
|
|
|
|
// Video playback speed
|
|
if (k === ">" || k === "<") {
|
|
const options = [0.25, 0.5, 1, 1.5, 2];
|
|
let idx = options.indexOf(dataRef.current.mediaPlaying?.playbackRate);
|
|
if (idx === -1) idx = options.indexOf(1);
|
|
const nextIdx = idx + (k === ">" ? 1 : -1);
|
|
const next = options[nextIdx];
|
|
if (next) dataRef.current.display?.setPlaybackRate(next);
|
|
}
|
|
|
|
// Video progress
|
|
if (k === "ArrowRight")
|
|
dataRef.current.display?.setTime(dataRef.current.time + 5);
|
|
if (k === "ArrowLeft")
|
|
dataRef.current.display?.setTime(dataRef.current.time - 5);
|
|
if (k === "j")
|
|
dataRef.current.display?.setTime(dataRef.current.time - 10);
|
|
if (k === "l")
|
|
dataRef.current.display?.setTime(dataRef.current.time + 10);
|
|
if (k === "." && dataRef.current.mediaPlaying?.isPaused)
|
|
dataRef.current.display?.setTime(dataRef.current.time + 1);
|
|
if (k === "," && dataRef.current.mediaPlaying?.isPaused)
|
|
dataRef.current.display?.setTime(dataRef.current.time - 1);
|
|
|
|
// Utils
|
|
if (k === "f") dataRef.current.display?.toggleFullscreen();
|
|
if (k === " ")
|
|
dataRef.current.display?.[
|
|
dataRef.current.mediaPlaying.isPaused ? "play" : "pause"
|
|
]();
|
|
if (k === "Escape") dataRef.current.router.close();
|
|
|
|
// captions
|
|
if (k === "c") dataRef.current.toggleLastUsed().catch(() => {}); // ignore errors
|
|
|
|
// Do a barrell roll!
|
|
if (k === "r") {
|
|
if (dataRef.current.isRolling || evt.ctrlKey || evt.metaKey) return;
|
|
|
|
dataRef.current.setIsRolling(true);
|
|
document.querySelector(".popout-location")?.classList.add("roll");
|
|
document.body.setAttribute("data-no-scroll", "true");
|
|
|
|
setTimeout(() => {
|
|
document.querySelector(".popout-location")?.classList.remove("roll");
|
|
document.body.removeAttribute("data-no-scroll");
|
|
dataRef.current.setIsRolling(false);
|
|
}, 1e3);
|
|
}
|
|
};
|
|
window.addEventListener("keydown", keyEventHandler);
|
|
|
|
return () => {
|
|
window.removeEventListener("keydown", keyEventHandler);
|
|
};
|
|
}, []);
|
|
|
|
return null;
|
|
}
|