diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-06 08:56:12 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-06 08:56:12 +0300 |
| commit | 1d68090f09b791c060dee7222dd2963a74c8e19b (patch) | |
| tree | 7730bb20d9d03aa798c8817aac54914f8e1d5ba3 | |
| parent | e2958122bfb7304a43b7815d80e0f42c761aa68c (diff) | |
Add q hotkey to stop playback and close player
| -rw-r--r-- | web/index.html | 1 | ||||
| -rw-r--r-- | web/js/app.js | 3 | ||||
| -rw-r--r-- | web/js/keyboard.js | 4 | ||||
| -rw-r--r-- | web/js/player.js | 35 |
4 files changed, 42 insertions, 1 deletions
diff --git a/web/index.html b/web/index.html index 55cefc9..f44da8e 100644 --- a/web/index.html +++ b/web/index.html @@ -141,6 +141,7 @@ <div class="help-row"><span><kbd>D</kbd></span><span>Download selected media</span></div> <div class="help-row"><span><kbd>T</kbd></span><span>Regenerate thumbnail</span></div> <div class="help-row"><span><kbd>Esc</kbd></span><span>Exit fullscreen / close</span></div> + <div class="help-row"><span><kbd>q</kbd></span><span>Stop playback and close player</span></div> <div class="help-row"><span><kbd>Backspace</kbd></span><span>Go up one folder</span></div> <div class="help-row"><span><kbd>r</kbd></span><span>Toggle shuffle</span></div> <div class="help-row"><span><kbd>s</kbd></span><span>Toggle sets sidebar</span></div> diff --git a/web/js/app.js b/web/js/app.js index 2e3caa7..102072b 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, shiftCropPosition, cycleCropPosition, currentMediaId, currentMediaInfo, hasLoadedMedia, isPlaybackActive, seekRelative, seekPercent, selectAndPlay, zoomIn as playerZoomIn, zoomOut as playerZoomOut, toggleSlideshow as playerToggleSlideshow, isImageMode as playerIsImageMode } from './player.js'; +import { initPlayer, togglePlay, toggleFullscreen, toggleMinimize, toggleDetach, exitFullscreenIfNeeded, toggleCrop, shiftCropPosition, cycleCropPosition, currentMediaId, currentMediaInfo, hasLoadedMedia, isPlaybackActive, seekRelative, seekPercent, selectAndPlay, stopAndClose, 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'; @@ -150,6 +150,7 @@ async function initApp() { notes: openNotesForSelected, tags: openTagsForSelected, toggleDetach: () => toggleDetach(), + stopAndClose: () => stopAndClose(), download: downloadSelected, help: toggleHelp, backspace: () => { navigateBack(); }, diff --git a/web/js/keyboard.js b/web/js/keyboard.js index 1a933c6..53ee3d0 100644 --- a/web/js/keyboard.js +++ b/web/js/keyboard.js @@ -275,6 +275,10 @@ export function initKeyboard(handlers) { case 'u': handlers.upload?.(e); break; case 'L': handlers.sharesToggle?.(e); break; case 'T': handlers.regenThumbnail?.(e); break; + case 'q': + e.preventDefault(); + handlers.stopAndClose?.(e); + break; case '?': e.preventDefault(); handlers.help?.(e); diff --git a/web/js/player.js b/web/js/player.js index 343bc1b..ad44e14 100644 --- a/web/js/player.js +++ b/web/js/player.js @@ -315,6 +315,41 @@ export function seekRelative(seconds) { return true; } +export function stopAndClose() { + const m = currentMediaElement(); + if (m) m.pause(); + if (currentMedia?.type === 'image') { + stopSlideshow(); + resetImageZoom(); + } + exitFullscreenIfNeeded(); + const e = els(); + e.player?.classList.remove('open', 'has-image', 'minimized'); + e.video?.classList.add('hidden'); + e.audio?.classList.add('hidden'); + e.image?.classList.add('hidden'); + e.coverArt?.classList.add('hidden'); + e.bigPlay?.classList.add('hidden'); + e.track?.classList.add('hidden'); + e.timeElapsed?.classList.add('hidden'); + e.timeTotal?.classList.add('hidden'); + e.btnPlay?.classList.add('hidden'); + e.btnZoomIn?.classList.add('hidden'); + e.btnZoomOut?.classList.add('hidden'); + e.btnSlideshow?.classList.add('hidden'); + currentMedia = null; + currentMediaIndex = -1; + isPlaying = false; + stopProgressTimer(); + updateUI(false); + highlightPlayingCard(); + if (e.fill) e.fill.style.width = '0%'; + if (e.thumb) e.thumb.style.left = '0%'; + if (e.timeElapsed) e.timeElapsed.textContent = '0:00'; + if (e.timeTotal) e.timeTotal.textContent = '0:00'; + if (e.buffered) e.buffered.style.background = 'transparent'; +} + export function selectAndPlay(media, index, resumeFrom = 0) { currentMedia = media; currentMediaIndex = index ?? -1; |
