diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-06 08:46:31 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-06 08:46:31 +0300 |
| commit | 728ef661402c57e44e1035c311341cf8c5f11922 (patch) | |
| tree | a651e2284de9cfc78ad305acbda87294990c2642 /web | |
| parent | 30ad6a0416c2a1fec58ddc6f4af727af9518f73c (diff) | |
Add PgUp/PgDn 10% seek in fullscreen mode
Diffstat (limited to 'web')
| -rw-r--r-- | web/index.html | 1 | ||||
| -rw-r--r-- | web/js/app.js | 7 | ||||
| -rw-r--r-- | web/js/detach.js | 13 | ||||
| -rw-r--r-- | web/js/keyboard.js | 10 | ||||
| -rw-r--r-- | web/js/player.js | 16 |
5 files changed, 46 insertions, 1 deletions
diff --git a/web/index.html b/web/index.html index d35a390..6e85ec6 100644 --- a/web/index.html +++ b/web/index.html @@ -135,6 +135,7 @@ <div class="help-row"><span><kbd>i</kbd></span><span>Show / hide media info</span></div> <div class="help-row"><span><kbd>n</kbd></span><span>Open notes</span></div> <div class="help-row"><span><kbd>f</kbd></span><span>Toggle fullscreen</span></div> + <div class="help-row"><span><kbd>PgUp</kbd> <kbd>PgDn</kbd></span><span>Seek +10% / −10% (fullscreen)</span></div> <div class="help-row"><span><kbd>C</kbd></span><span>Minimize player</span></div> <div class="help-row"><span><kbd>d</kbd></span><span>Detach / attach player</span></div> <div class="help-row"><span><kbd>D</kbd></span><span>Download selected media</span></div> diff --git a/web/js/app.js b/web/js/app.js index 78dd16d..99ae0f3 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -1,7 +1,7 @@ import { API } from './api.js'; import { initKeyboard } from './keyboard.js'; import { initSelection, clearSelection, select, selectByElement, next, prev, currentIndex, currentElement, navUp, navDown, navLeft, navRight } from './selection.js'; -import { initPlayer, togglePlay, toggleFullscreen, toggleMinimize, toggleDetach, exitFullscreenIfNeeded, toggleCrop, currentMediaId, currentMediaInfo, hasLoadedMedia, isPlaybackActive, seekRelative, selectAndPlay, zoomIn as playerZoomIn, zoomOut as playerZoomOut, toggleSlideshow as playerToggleSlideshow, isImageMode as playerIsImageMode } from './player.js'; +import { initPlayer, togglePlay, toggleFullscreen, toggleMinimize, toggleDetach, exitFullscreenIfNeeded, toggleCrop, currentMediaId, currentMediaInfo, hasLoadedMedia, isPlaybackActive, seekRelative, seekPercent, selectAndPlay, zoomIn as playerZoomIn, zoomOut as playerZoomOut, toggleSlideshow as playerToggleSlideshow, isImageMode as playerIsImageMode } from './player.js'; import { initSearch, focusSearch, trigger as triggerSearch, parseQuery, showSearchHelp } from './search.js'; import { initShuffle, toggle as toggleShuffle, isOn as isShuffle } from './shuffle.js'; import { initThemes } from './themes.js'; @@ -104,6 +104,11 @@ async function initApp() { navRight: () => navRight(), seekBackward: (e) => seekByKeyboard(-1, e.repeat), seekForward: (e) => seekByKeyboard(1, e.repeat), + seekPercent: (e, percent) => { + if (!hasLoadedMedia()) return false; + if (!document.fullscreenElement) return false; + return seekPercent(percent); + }, nextSet: () => setSetByDelta(1), prevSet: () => setSetByDelta(-1), isSidebarOpen: () => document.getElementById('sidebar')?.classList.contains('open'), diff --git a/web/js/detach.js b/web/js/detach.js index 3b48122..b1dfd87 100644 --- a/web/js/detach.js +++ b/web/js/detach.js @@ -145,6 +145,8 @@ function handleCommand(payload) { el.play().catch(() => {}); } else if (action === 'seek-relative') { seekRelative(Number(payload.seconds || 0)); + } else if (action === 'seek-percent') { + seekPercent(Number(payload.percent || 0)); } } @@ -164,6 +166,17 @@ function seekRelative(seconds) { sendState(); } +function seekPercent(percent) { + const el = mediaElement(); + if (!currentMedia || !el || !isFinite(percent)) return; + const dur = (el.duration && isFinite(el.duration) && el.duration > 0) ? el.duration : (currentMedia?.duration || 0); + if (!dur) return; + const upper = el.duration && isFinite(el.duration) ? el.duration : Infinity; + el.currentTime = Math.max(0, Math.min(upper, (el.currentTime || 0) + dur * percent)); + lastKnownPosition = el.currentTime || 0; + sendState(); +} + function toggleFullscreen() { const player = document.getElementById('player'); if (!player) return; diff --git a/web/js/keyboard.js b/web/js/keyboard.js index b7769b7..76c3a9d 100644 --- a/web/js/keyboard.js +++ b/web/js/keyboard.js @@ -206,6 +206,16 @@ export function initKeyboard(handlers) { } handlers.navRight?.(e); break; + case 'PageUp': + if (handlers.seekPercent?.(e, -0.10)) { + e.preventDefault(); + } + break; + case 'PageDown': + if (handlers.seekPercent?.(e, 0.10)) { + e.preventDefault(); + } + break; case 'Enter': handlers.enter?.(e); break; case 'n': handlers.notes?.(e); diff --git a/web/js/player.js b/web/js/player.js index e179856..f9a96da 100644 --- a/web/js/player.js +++ b/web/js/player.js @@ -275,6 +275,22 @@ export function hasLoadedMedia() { return !!currentMedia; } +export function seekPercent(deltaPercent) { + const dp = Number(deltaPercent); + if (!currentMedia || !isFinite(dp)) return false; + if (isDetached()) { + postToDetach({ type: 'detach-command', action: 'seek-percent', percent: dp }); + return true; + } + const m = currentMediaElement(); + if (!m) return false; + const dur = effectiveDuration(); + if (!dur) return false; + const upper = m.duration && isFinite(m.duration) ? m.duration : dur; + m.currentTime = Math.max(0, Math.min(upper, (m.currentTime || 0) + dur * dp)); + return true; +} + export function seekRelative(seconds) { const amount = Number(seconds); if (!currentMedia || !isFinite(amount)) return false; |
