summaryrefslogtreecommitdiff
path: root/web/js/detach.js
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-02 22:50:26 +0300
committerPaul Buetow <paul@buetow.org>2026-05-02 22:50:26 +0300
commit0482a98c538cbe9ca32b4775bd897b9c728cf686 (patch)
tree226bcd3b3d9c6b8330cff531de40f5c137291879 /web/js/detach.js
parentdaccc2fd2c43545fe2a904cccb1f866e38817a10 (diff)
add playback navigation shortcuts
Diffstat (limited to 'web/js/detach.js')
-rw-r--r--web/js/detach.js22
1 files changed, 20 insertions, 2 deletions
diff --git a/web/js/detach.js b/web/js/detach.js
index f884231..d255b2e 100644
--- a/web/js/detach.js
+++ b/web/js/detach.js
@@ -35,6 +35,7 @@ window.__playerDetachCurrentState = currentState;
lastStateSent = now;
}
});
+ el?.addEventListener('ended', () => post({ type: 'detach-next' }));
});
document.addEventListener('keydown', (ev) => {
@@ -48,6 +49,12 @@ document.addEventListener('keydown', (ev) => {
} else if (ev.key === 'f') {
ev.preventDefault();
toggleFullscreen();
+ } else if (ev.key === 'ArrowLeft' || ev.key === 'h') {
+ ev.preventDefault();
+ seekRelative(ev.repeat ? -15 : -5);
+ } else if (ev.key === 'ArrowRight' || ev.key === 'l') {
+ ev.preventDefault();
+ seekRelative(ev.repeat ? 15 : 5);
}
});
@@ -63,7 +70,7 @@ window.addEventListener('message', (ev) => {
loadDetachedMedia(ev.data);
break;
case 'detach-command':
- handleCommand(ev.data.action);
+ handleCommand(ev.data);
break;
case 'detach-request-state':
sendState();
@@ -97,7 +104,8 @@ function loadDetachedMedia(payload) {
sendState();
}
-function handleCommand(action) {
+function handleCommand(payload) {
+ const action = payload?.action;
if (action === 'toggle-play') {
togglePlayback();
} else if (action === 'pause') {
@@ -108,6 +116,8 @@ function handleCommand(action) {
const el = mediaElement();
if (!el) return;
el.play().catch(() => {});
+ } else if (action === 'seek-relative') {
+ seekRelative(Number(payload.seconds || 0));
}
}
@@ -118,6 +128,14 @@ function togglePlayback() {
else el.pause();
}
+function seekRelative(seconds) {
+ const el = mediaElement();
+ if (!currentMedia || !el || !isFinite(seconds)) return;
+ const upper = el.duration && isFinite(el.duration) ? el.duration : Infinity;
+ el.currentTime = Math.max(0, Math.min(upper, (el.currentTime || 0) + seconds));
+ sendState();
+}
+
function toggleFullscreen() {
const player = document.getElementById('player');
if (!player) return;