A small web app for watching movies and shows easily
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

152 lines
4.6 KiB

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;
}