feat: YouTube's keyboard shortcuts in the player

This is a video player, so the keys fingers already know should work.

  space / k   play, pause
  j / l       ten seconds back, forward
  ← / →       five seconds
  ↑ / ↓       volume
  0–9         jump to that tenth of the video
  Home / End  the ends
  m           mute
  f           fullscreen
  i           Picture in Picture, YouTube's miniplayer
  c           subtitles on or off
  , / .       one frame back or forward, while paused
  shift , / . slower, faster
  shift N / P next, previous video
  Escape      leave fullscreen, then close the player

Speed gets a chip in the transport bar when it is not 1×, since nothing
else there would say so, and clicking it goes back to normal. The other
buttons now name their key in the tooltip.

Arrow keys are taken from a focused slider, which would otherwise seek
by a tenth of a second rather than five. Typing in a field is left
alone, as are the system's own modifier combinations. A frame is taken
as a thirtieth of a second, since a video element will not say what its
frame rate is.

Verified in the running app: 5 jumped to exactly half, j seeked, m
muted, shift-. reached 1.5×, c turned subtitles off and on again, and
shift+N moved to the next video.
This commit is contained in:
vincent
2026-09-03 23:29:25 +02:00
parent 90f1eddb31
commit ddad42593c
2 changed files with 133 additions and 23 deletions
+4 -3
View File
@@ -303,9 +303,10 @@ export default function Player({
// fullscreen. Closing the player as well would drop you all the way back
// to the feed in one keypress.
if (e.key === "Escape" && !document.fullscreenElement) leave();
// Arrow keys only when the video does not own them for seeking.
if (e.key === "ArrowLeft" && e.shiftKey) onPrev?.();
if (e.key === "ArrowRight" && e.shiftKey) onNext?.();
// Moving between videos. Shift with the arrows because the bare ones
// seek, and shift with N and P because that is what YouTube uses.
if (e.shiftKey && (e.key === "ArrowLeft" || e.key === "P" || e.key === "p")) onPrev?.();
if (e.shiftKey && (e.key === "ArrowRight" || e.key === "N" || e.key === "n")) onNext?.();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);