diff --git a/package.json b/package.json
index caeacac..cfc8b46 100644
--- a/package.json
+++ b/package.json
@@ -21,13 +21,14 @@
},
"dependencies": {
"@tweenjs/tween.js": "^17.3.5",
- "aframe": "^0.9.2",
+ "aframe": "^1.0.4",
"aframe-stereo-component": "^0.6.0",
"buttplug": "^0.12.2",
"d3": "^5.9.2",
"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",
@@ -35,7 +36,8 @@
"vue-buttplug-material-component": "^0.3.1",
"vue-touch": "next",
"vue-video-player": "^5.0.2",
- "vuetify": "^1.5.14"
+ "vuetify": "^1.5.14",
+ "yarn.lock": "^0.0.1-security"
},
"devDependencies": {
"@types/aframe": "^0.8.3",
diff --git a/src/App.vue b/src/App.vue
index 5635d53..0288eba 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -348,5 +348,9 @@
justify-content: center;
}
+ /* disable the duplicate vr button */
+ .a-enter-vr {
+ display: none;
+ }
diff --git a/src/components/VideoPlayer/VideoPlayer.ts b/src/components/VideoPlayer/VideoPlayer.ts
index 0573b6e..19dd60e 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;
@@ -24,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.
@@ -35,6 +39,50 @@ export default class VideoPlayer extends Vue {
sources: [{}],
start: 0,
loop: this.loopVideo,
+ plugins: {
+ hotkeys: {
+ enableNumbers: false,
+ 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, shiftKey }: KeyboardEvent) => {
+ // mimic mpv seek behavior, 5s for left/right, 60s for up/down
+ if (key === "ArrowUp" || key === "ArrowDown") {
+ return 60;
+ } else if (shiftKey && (key === "ArrowLeft" || key === "ArrowRight")) {
+ // might be helpful to use while scripting
+ return 1;
+ } else {
+ 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),
+ },
+ },
+ },
+ },
};
public mounted() {
@@ -143,6 +191,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, 1);
+ 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;
+ }