From 395c1e84d705dfdd99b6cce3aaf21b0b15ce0f41 Mon Sep 17 00:00:00 2001 From: endrl <119058008+endrl@users.noreply.github.com> Date: Sun, 21 May 2023 00:01:09 +0200 Subject: [PATCH] feat(player): add keyboard media control --- frontend/src/composables/use-playerkeys.ts | 44 +++++++++++++++++++++ frontend/src/pages/playback/music/index.vue | 3 ++ frontend/src/pages/playback/video/index.vue | 10 ++--- 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 frontend/src/composables/use-playerkeys.ts diff --git a/frontend/src/composables/use-playerkeys.ts b/frontend/src/composables/use-playerkeys.ts new file mode 100644 index 00000000000..445c60392b4 --- /dev/null +++ b/frontend/src/composables/use-playerkeys.ts @@ -0,0 +1,44 @@ +import { + onKeyStroke, + whenever, + useMagicKeys, + useThrottleFn +} from '@vueuse/core'; +import playbackManager from '@/store/playbackManager'; + +/** + * Register keyboard player control. + * @param osdHandler - show the player osd for a short period whenever a suitable action is called + */ +export function usePlayerKeys(osdHandler?: () => void): void { + const keys = useMagicKeys(); + + whenever(keys.mediapause, playbackManager.playPause); + whenever(keys.mediaplaypause, playbackManager.playPause); + whenever(keys.mediastop, playbackManager.stop); + whenever(keys.mediatracknext, playbackManager.setNextTrack); + whenever(keys.mediatrackprevious, playbackManager.setPreviousTrack); + whenever(keys.audiovolumemute, playbackManager.toggleMute); + whenever(keys.space, playbackManager.playPause); + whenever(keys.k, playbackManager.playPause); + whenever(keys.m, playbackManager.toggleMute); + + const callHandler = (): void => { + if (osdHandler) { + osdHandler(); + } + }; + + const throttledForwardFn = useThrottleFn(() => { + playbackManager.skipForward(); + callHandler(); + }, 500); + + const throttledBackwardFn = useThrottleFn(() => { + playbackManager.skipBackward(); + callHandler(); + }, 500); + + onKeyStroke(['j', 'ArrowLeft'], throttledBackwardFn); + onKeyStroke(['l', 'ArrowRight'], throttledForwardFn); +} diff --git a/frontend/src/pages/playback/music/index.vue b/frontend/src/pages/playback/music/index.vue index 10248c47a98..dbb1dedebe9 100644 --- a/frontend/src/pages/playback/music/index.vue +++ b/frontend/src/pages/playback/music/index.vue @@ -87,6 +87,7 @@ import { isNil } from 'lodash-es'; import { useRoute } from 'vue-router'; import { getBlurhash } from '@/utils/images'; import { playbackManagerStore } from '@/store'; +import { usePlayerKeys } from '@/composables/use-playerkeys'; const modules = [A11y, Keyboard, Virtual, EffectCoverflow]; const route = useRoute(); @@ -99,6 +100,8 @@ const coverflowEffect = { stretch: -400 }; +usePlayerKeys(); + const backdropHash = computed(() => { return playbackManager.currentItem ? getBlurhash(playbackManager.currentItem, ImageType.Primary) diff --git a/frontend/src/pages/playback/video/index.vue b/frontend/src/pages/playback/video/index.vue index 75265b4344e..6ef08b6ad98 100644 --- a/frontend/src/pages/playback/video/index.vue +++ b/frontend/src/pages/playback/video/index.vue @@ -129,6 +129,7 @@ import { useMagicKeys, whenever } from '@vueuse/core'; +import { usePlayerKeys } from '@/composables/use-playerkeys'; import { playbackManagerStore, playerElementStore, @@ -173,6 +174,8 @@ function handleMouseMove(): void { timeout.start(); } +usePlayerKeys(handleMouseMove); + onBeforeUnmount(() => { if (playerElement.isFullscreenVideoPlayer) { playbackManager.stop(); @@ -189,14 +192,7 @@ onMounted(() => { playerElement.isFullscreenMounted = true; }); -whenever(keys.space, playbackManager.playPause); -whenever(keys.k, playbackManager.playPause); -whenever(keys.right, playbackManager.skipForward); -whenever(keys.l, playbackManager.skipForward); -whenever(keys.left, playbackManager.skipBackward); -whenever(keys.j, playbackManager.skipBackward); whenever(keys.f, fullscreen.toggle); -whenever(keys.m, playbackManager.toggleMute); watch(staticOverlay, (val) => { if (val) {