From 8b130cb097f1cbacb46db959b1a7fd85bac33047 Mon Sep 17 00:00:00 2001 From: Tiberiu Ichim Date: Sun, 22 Feb 2026 09:57:10 +0200 Subject: [PATCH] Added player keyboard shortcuts --- AGENTS.md | 1 + artifacts/docs/ux_power_user_shortcuts.md | 7 +++++++ client/components/player/PlayerUi.vue | 14 ++++++++++++-- client/layouts/default.vue | 7 ++++--- client/pages/share/_slug.vue | 7 ++++--- client/plugins/constants.js | 14 +++++++++++--- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 614f1a773..0bece6e3a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -219,6 +219,7 @@ Each new feature or major change should be documented in an artifact specificati ### Organization - **Location**: All artifact specifications are stored in the `artifacts/` directory. +- **Index**: You can look up previous artifact specification files in `artifacts/index.md`. - **Dated Folders**: Specifications **MUST** be placed in a subfolder named by the current date (e.g., `artifacts/YYYY-MM-DD/`). - **CRITICAL**: Do **NOT** create specification files directly in the `artifacts/` root. Always use the dated folder. - **Filename**: Use descriptive names for the specification files (e.g., `move-to-library-specification.md`). diff --git a/artifacts/docs/ux_power_user_shortcuts.md b/artifacts/docs/ux_power_user_shortcuts.md index 1595e9164..c8d7b57eb 100644 --- a/artifacts/docs/ux_power_user_shortcuts.md +++ b/artifacts/docs/ux_power_user_shortcuts.md @@ -28,6 +28,13 @@ To improve the efficiency of batch operations, global keyboard listeners have be - **Collections**: `Alt + C`. - **Authors**: `Alt + A`. +- **Audio Player Shortcuts**: + - **Jump Forward**: `Shift + Right Arrow` (Standard), `Ctrl + Shift + Right Arrow` (Major, 60s). + - **Jump Backward**: `Shift + Left Arrow` (Standard), `Ctrl + Shift + Left Arrow` (Major, 60s). + - **Next Chapter**: `Shift + Up Arrow`. + - **Previous Chapter**: `Shift + Down Arrow`. + - **Playback Rate**: `]` (Increase), `[` (Decrease). + - **Modal & Prompt Controls**: - **Confirm / Submit**: `Enter` (Works on confirmation prompts and many action modals like "Move", "Quick Match", and "Split"). - **Cancel / Close**: `Escape` (Closes modals, cancels prompts, and clears batch selections). diff --git a/client/components/player/PlayerUi.vue b/client/components/player/PlayerUi.vue index f929943c4..6087d89b8 100644 --- a/client/components/player/PlayerUi.vue +++ b/client/components/player/PlayerUi.vue @@ -203,6 +203,12 @@ export default { jumpForward() { this.$emit('jumpForward') }, + jumpBackwardMajor() { + this.seek(Math.max(this.currentTime - 60, 0)) + }, + jumpForwardMajor() { + this.seek(Math.min(this.currentTime + 60, this.duration)) + }, increaseVolume() { if (this.volume >= 1) return this.volume = Math.min(1, this.volume + 0.1) @@ -343,8 +349,12 @@ export default { }, hotkey(action) { if (action === this.$hotkeys.AudioPlayer.PLAY_PAUSE) this.playPause() - else if (action === this.$hotkeys.AudioPlayer.JUMP_FORWARD) this.jumpForward() - else if (action === this.$hotkeys.AudioPlayer.JUMP_BACKWARD) this.jumpBackward() + else if (action === this.$hotkeys.AudioPlayer.JUMP_FORWARD || action === this.$hotkeys.AudioPlayer.JUMP_FORWARD_ALT) this.jumpForward() + else if (action === this.$hotkeys.AudioPlayer.JUMP_BACKWARD || action === this.$hotkeys.AudioPlayer.JUMP_BACKWARD_ALT) this.jumpBackward() + else if (action === this.$hotkeys.AudioPlayer.JUMP_FORWARD_MAJOR) this.jumpForwardMajor() + else if (action === this.$hotkeys.AudioPlayer.JUMP_BACKWARD_MAJOR) this.jumpBackwardMajor() + else if (action === this.$hotkeys.AudioPlayer.NEXT_CHAPTER) this.goToNext() + else if (action === this.$hotkeys.AudioPlayer.PREV_CHAPTER) this.prevChapter() else if (action === this.$hotkeys.AudioPlayer.VOLUME_UP) this.increaseVolume() else if (action === this.$hotkeys.AudioPlayer.VOLUME_DOWN) this.decreaseVolume() else if (action === this.$hotkeys.AudioPlayer.MUTE_UNMUTE) this.toggleMute() diff --git a/client/layouts/default.vue b/client/layouts/default.vue index 4d12aeb02..21fe0538f 100644 --- a/client/layouts/default.vue +++ b/client/layouts/default.vue @@ -531,9 +531,10 @@ export default { return null } - var keyName = this.$keynames[keyCode] - var name = keyName - if (e.shiftKey) name = 'Shift-' + keyName + var name = this.$keynames[keyCode] + if (e.ctrlKey || e.metaKey) name = 'Ctrl-' + name + if (e.altKey) name = 'Alt-' + name + if (e.shiftKey) name = 'Shift-' + name if (process.env.NODE_ENV !== 'production') { console.log('Hotkey command', name) } diff --git a/client/pages/share/_slug.vue b/client/pages/share/_slug.vue index 64c099632..ff49f4746 100644 --- a/client/pages/share/_slug.vue +++ b/client/pages/share/_slug.vue @@ -314,9 +314,10 @@ export default { return null } - var keyName = this.$keynames[keyCode] - var name = keyName - if (e.shiftKey) name = 'Shift-' + keyName + var name = this.$keynames[keyCode] + if (e.ctrlKey || e.metaKey) name = 'Ctrl-' + name + if (e.altKey) name = 'Alt-' + name + if (e.shiftKey) name = 'Shift-' + name if (process.env.NODE_ENV !== 'production') { console.log('Hotkey command', name) } diff --git a/client/plugins/constants.js b/client/plugins/constants.js index 3b893d3c1..45e9f0b7a 100644 --- a/client/plugins/constants.js +++ b/client/plugins/constants.js @@ -64,19 +64,27 @@ const KeyNames = { 81: 'KeyQ', 82: 'KeyR', 83: 'KeyS', - 191: 'Slash' + 191: 'Slash', + 219: 'BracketLeft', + 221: 'BracketRight' } const Hotkeys = { AudioPlayer: { PLAY_PAUSE: 'Space', JUMP_FORWARD: 'ArrowRight', JUMP_BACKWARD: 'ArrowLeft', + JUMP_FORWARD_ALT: 'Shift-ArrowRight', + JUMP_BACKWARD_ALT: 'Shift-ArrowLeft', + JUMP_FORWARD_MAJOR: 'Shift-Ctrl-ArrowRight', + JUMP_BACKWARD_MAJOR: 'Shift-Ctrl-ArrowLeft', VOLUME_UP: 'ArrowUp', VOLUME_DOWN: 'ArrowDown', MUTE_UNMUTE: 'KeyM', SHOW_CHAPTERS: 'KeyL', - INCREASE_PLAYBACK_RATE: 'Shift-ArrowUp', - DECREASE_PLAYBACK_RATE: 'Shift-ArrowDown', + NEXT_CHAPTER: 'Shift-ArrowUp', + PREV_CHAPTER: 'Shift-ArrowDown', + INCREASE_PLAYBACK_RATE: 'BracketRight', + DECREASE_PLAYBACK_RATE: 'BracketLeft', CLOSE: 'Escape' }, EReader: {