From e59228886076eed79f8711e75dffcc2d83c54159 Mon Sep 17 00:00:00 2001 From: greenyouse Date: Wed, 18 Nov 2020 19:09:25 -0600 Subject: [PATCH 1/6] feat: Add video hotkeys --- package.json | 1 + src/components/VideoPlayer/VideoPlayer.ts | 30 +++++++++++++++++++++++ yarn.lock | 5 ++++ 3 files changed, 36 insertions(+) diff --git a/package.json b/package.json index caeacac..d3ab3f8 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "haptic-movie-file-reader": "^0.0.10", "matomo-tracker": "^2.2.1", "mousetrap": "^1.6.3", + "videojs-hotkeys": "^0.2.27", "videojs-youtube": "^2.6.0", "viewport-units-buggyfill": "^0.6.2", "vue": "^2.6.10", diff --git a/src/components/VideoPlayer/VideoPlayer.ts b/src/components/VideoPlayer/VideoPlayer.ts index 0573b6e..c110da8 100644 --- a/src/components/VideoPlayer/VideoPlayer.ts +++ b/src/components/VideoPlayer/VideoPlayer.ts @@ -1,6 +1,7 @@ import Vue from "vue"; import { Component, Model, Prop, Watch } from "vue-property-decorator"; import videojs from "video.js"; +import "videojs-hotkeys"; const vjsyoutube = require("./videojs-youtube"); const videoPlayer = require("vue-video-player").videoPlayer; @@ -35,6 +36,35 @@ export default class VideoPlayer extends Vue { sources: [{}], start: 0, loop: this.loopVideo, + plugins: { + hotkeys: { + enableVolumeScroll: false, + skipInitialFocus: true, + enableInactiveFocus: false, + captureDocumentHotkeys: true, + documentHotkeysFocusElementFilter: (e: HTMLElement) => { + const tagName = e.tagName.toLowerCase(); + return e.id === "content" || tagName === "body" || tagName === "video"; + }, + + forwardKey: ({ key }: KeyboardEvent) => { + return key === "ArrowRight" || key === "ArrowUp"; + }, + rewindKey: ({ key }: KeyboardEvent) => { + return key === "ArrowLeft" || key === "ArrowDown"; + }, + + seekStep: ({ key }: KeyboardEvent) => { + console.log("key - - - - - ", key); + // mimic mpv seek behavior, 5s for left/right, 60s for up/down + if (key === "ArrowUp" || key === "ArrowDown") { + return 60; + } else { + return 5; + } + }, + }, + }, }; public mounted() { diff --git a/yarn.lock b/yarn.lock index fee540d..05eb733 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7345,6 +7345,11 @@ videojs-hotkeys@^0.2.20: resolved "https://registry.yarnpkg.com/videojs-hotkeys/-/videojs-hotkeys-0.2.25.tgz#b34b5816db1af747e41a90a3be268d51449b4cb0" integrity sha512-XgMjWiqGlmAjuHtpP529A2voVh++z46FSD0XeSy+65yeuTZOd+w2CJmfrL4jPpGm+MME5l9lOLfVpoEeDaBa1Q== +videojs-hotkeys@^0.2.27: + version "0.2.27" + resolved "https://registry.yarnpkg.com/videojs-hotkeys/-/videojs-hotkeys-0.2.27.tgz#0df97952b9dff0e6cc1cf8a439fed7eac9c73f01" + integrity sha512-pwtm1QocRmzJy1PWQsmFVHyeldYHHpLdeATK3FsFHVMmNpz6CROkAn8TFy2UILr8Ghgq134K8jEKNue8HWpudQ== + videojs-ie8@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/videojs-ie8/-/videojs-ie8-1.1.2.tgz#a23d3d8608ad7192b69c6077fc4eb848998d35d9" From c406ad1cf8993d6afcb6dd4fc55090db30f6acf0 Mon Sep 17 00:00:00 2001 From: greenyouse Date: Wed, 18 Nov 2020 21:33:48 -0600 Subject: [PATCH 2/6] feat: Add playback speed hotkeys --- src/components/VideoPlayer/VideoPlayer.ts | 38 ++++++++++++++++++++++ src/components/VideoPlayer/VideoPlayer.vue | 9 +++++ 2 files changed, 47 insertions(+) diff --git a/src/components/VideoPlayer/VideoPlayer.ts b/src/components/VideoPlayer/VideoPlayer.ts index c110da8..861aec9 100644 --- a/src/components/VideoPlayer/VideoPlayer.ts +++ b/src/components/VideoPlayer/VideoPlayer.ts @@ -25,6 +25,9 @@ export default class VideoPlayer extends Vue { private vrControlButton: videojs.Component | null = null; private currentPlayer: videojs.Player | null = null; + private showPlaybackSpeed: boolean = false; + private playbackSpeed: number = 1; + // This is a combination of videojs's Playback options plus some extra stuff // from vue-video-player, so it has to be an any instead of a // videojs.PlaybackOptions until we derive something that supports both. @@ -63,6 +66,18 @@ export default class VideoPlayer extends Vue { return 5; } }, + + customKeys: { + // mimic mpv the playback behavior, change playback rate by 10% + incPlayback: { + key: ({ key }: KeyboardEvent) => key === "]", + handler: () => this.setPlaybackSpeed(0.1), + }, + decPlayback: { + key: ({ key }: KeyboardEvent) => key === "[", + handler: () => this.setPlaybackSpeed(-0.1), + }, + }, }, }, }; @@ -173,6 +188,29 @@ export default class VideoPlayer extends Vue { this.$emit("videoPaused"); } + private setPlaybackSpeed(playbackSpeedChange: number) { + const player = this.currentPlayer; + if (!player) { + return; + } + // not a great way to handle the playback type here + const currentSpeed = player.playbackRate() as any; + if (currentSpeed > 0.1 || playbackSpeedChange > 0) { + // set the playback speed, then show a speed notification over the video + const newSpeed = +(currentSpeed + playbackSpeedChange).toPrecision(2); + player.playbackRate(newSpeed); + this.playbackSpeed = newSpeed; + this.showPlaybackSpeed = true; + + // hide the speed notification after 3 seconds + const id = setInterval(() => this.showPlaybackSpeed = true, 10); + setTimeout(() => { + clearInterval(id); + this.showPlaybackSpeed = false; + }, 3000); + } + } + private runTimeUpdateLoop() { window.requestAnimationFrame(() => { if (this.currentPlayer!.paused()) { diff --git a/src/components/VideoPlayer/VideoPlayer.vue b/src/components/VideoPlayer/VideoPlayer.vue index 483df8e..b3fccae 100644 --- a/src/components/VideoPlayer/VideoPlayer.vue +++ b/src/components/VideoPlayer/VideoPlayer.vue @@ -19,6 +19,7 @@ + Speed: {{ playbackSpeed }} @@ -27,6 +28,14 @@ display: flex; max-width: 100vw; } + + .speed-notification { + color: white; + font-size: 24px; + position: absolute; + top: 15px; + left: 15px; + }