mirror of
https://github.com/tubearchivist/tubearchivist
synced 2024-11-02 09:41:07 +00:00
add keyboard shortcuts to video player (#342)
* add keyboard shortcuts to video player * fix modal on the inline player
This commit is contained in:
parent
51f7210195
commit
ff82690d3c
@ -2,7 +2,9 @@
|
||||
{% block content %}
|
||||
{% load static %}
|
||||
{% load humanize %}
|
||||
<div class="video-main"></div>
|
||||
<div class="video-main">
|
||||
<div class="video-modal"><span class="video-modal-text"></span></div>
|
||||
</div>
|
||||
<div class="notifications" id="notifications"></div>
|
||||
<div class="sponsorblock" id="sponsorblock">
|
||||
{% if video.sponsorblock.is_enabled %}
|
||||
|
@ -388,6 +388,7 @@ button:hover {
|
||||
display: grid;
|
||||
align-content: space-evenly;
|
||||
height: 100vh;
|
||||
position: relative; /* needed for modal */
|
||||
}
|
||||
|
||||
.notifications {
|
||||
@ -744,6 +745,22 @@ video:-webkit-full-screen {
|
||||
/* video page */
|
||||
.video-main {
|
||||
margin: 1rem 0;
|
||||
position: relative; /* needed for modal */
|
||||
}
|
||||
|
||||
.video-modal {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 20%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.video-modal-text {
|
||||
background: rgba(0,0,0,.5);
|
||||
color: #eeeeee;
|
||||
font-size: 1.3em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.video-main video {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
function sortChange(sortValue) {
|
||||
var payload = JSON.stringify({'sort_order': sortValue});
|
||||
sendPost(payload);
|
||||
@ -426,6 +425,7 @@ function createPlayer(button) {
|
||||
|
||||
const markup = `
|
||||
<div class="video-player" data-id="${videoId}">
|
||||
<div class="video-modal"><span class="video-modal-text"></span></div>
|
||||
${videoTag}
|
||||
<div class="notifications" id="notifications"></div>
|
||||
${sponsorBlockElements}
|
||||
@ -444,13 +444,14 @@ function createPlayer(button) {
|
||||
`;
|
||||
const divPlayer = document.getElementById("player");
|
||||
divPlayer.innerHTML = markup;
|
||||
recordTextTrackChanges();
|
||||
}
|
||||
|
||||
// Add video tag to video page when passed a video id, function loaded on page load `video.html (115-117)`
|
||||
function insertVideoTag(videoData, videoProgress) {
|
||||
var videoTag = createVideoTag(videoData, videoProgress);
|
||||
var videoMain = document.getElementsByClassName("video-main");
|
||||
videoMain[0].innerHTML = videoTag;
|
||||
var videoMain = document.querySelector(".video-main");
|
||||
videoMain.innerHTML += videoTag;
|
||||
}
|
||||
|
||||
// Generates a video tag with subtitles when passed videoData and videoProgress.
|
||||
@ -1173,3 +1174,133 @@ function animate(elementId, animationClass) {
|
||||
toAnimate.classList.remove(animationClass);
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of changes to the subtitles list made with the native UI
|
||||
// needed so that when toggling subtitles with the shortcut we go to the last selected one, not the first one
|
||||
addEventListener('DOMContentLoaded', recordTextTrackChanges);
|
||||
|
||||
let lastSeenTextTrack = 0;
|
||||
function recordTextTrackChanges() {
|
||||
let player = getVideoPlayer();
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
player.textTracks.addEventListener('change', () => {
|
||||
let active = [...player.textTracks].findIndex(x => x.mode === 'showing');
|
||||
if (active !== -1) {
|
||||
lastSeenTextTrack = active;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// keyboard shortcuts for the video player
|
||||
document.addEventListener('keydown', doShortcut);
|
||||
|
||||
let modalHideTimeout = -1;
|
||||
function showModal(html, duration) {
|
||||
let player = getVideoPlayer();
|
||||
let modal = document.querySelector('.video-modal-text');
|
||||
modal.innerHTML = html;
|
||||
modal.style.display = 'initial';
|
||||
clearTimeout(modalHideTimeout);
|
||||
modalHideTimeout = setTimeout(() => { modal.style.display = 'none'; }, duration);
|
||||
}
|
||||
|
||||
let videoSpeeds = [.25, .5, .75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3];
|
||||
function doShortcut(e) {
|
||||
if (!(e.target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
let target = e.target;
|
||||
let targetName = target.nodeName.toLowerCase();
|
||||
if (targetName === 'textarea' || targetName === 'input' || targetName === 'select' || target.isContentEditable) {
|
||||
return;
|
||||
}
|
||||
if (e.altKey || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
let player = getVideoPlayer();
|
||||
if (player == null) {
|
||||
// not on the video page
|
||||
return;
|
||||
}
|
||||
switch (e.key) {
|
||||
case 'c': {
|
||||
// toggle captions
|
||||
let tracks = [...player.textTracks];
|
||||
if (tracks.length === 0) {
|
||||
break;
|
||||
}
|
||||
let active = tracks.find(x => x.mode === 'showing');
|
||||
if (active != null) {
|
||||
active.mode = 'disabled';
|
||||
} else {
|
||||
tracks[lastSeenTextTrack].mode = 'showing';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
player.muted = !player.muted;
|
||||
break;
|
||||
}
|
||||
case 'ArrowLeft': {
|
||||
if (targetName === 'video') {
|
||||
// hitting arrows while the video is focused will use the built-in skip
|
||||
break;
|
||||
}
|
||||
showModal('- 5 seconds', 500);
|
||||
player.currentTime -= 5;
|
||||
break;
|
||||
}
|
||||
case 'ArrowRight': {
|
||||
if (targetName === 'video') {
|
||||
// hitting space while the video is focused will use the built-in skip
|
||||
break;
|
||||
}
|
||||
showModal('+ 5 seconds', 500);
|
||||
player.currentTime += 5;
|
||||
break;
|
||||
}
|
||||
case '<':
|
||||
case '>': {
|
||||
// change speed
|
||||
let currentSpeedIdx = videoSpeeds.findIndex(s => s >= player.playbackRate);
|
||||
if (currentSpeedIdx === -1) {
|
||||
// handle the case where the user manually set the speed above our max speed
|
||||
currentSpeedIdx = videoSpeeds.length - 1;
|
||||
}
|
||||
let newSpeedIdx = e.key === '<' ? Math.max(0, currentSpeedIdx - 1) : Math.min(videoSpeeds.length - 1, currentSpeedIdx + 1);
|
||||
let newSpeed = videoSpeeds[newSpeedIdx];
|
||||
player.playbackRate = newSpeed;
|
||||
showModal(newSpeed + 'x', 500);
|
||||
break;
|
||||
}
|
||||
case ' ': {
|
||||
if (targetName === 'video') {
|
||||
// hitting space while the video is focused will toggle it anyway
|
||||
break;
|
||||
}
|
||||
e.preventDefault();
|
||||
if (player.paused) {
|
||||
player.play();
|
||||
} else {
|
||||
player.pause();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '?': {
|
||||
showModal(`
|
||||
<table style="margin: auto; background: rgba(0,0,0,.5)"><tbody>
|
||||
<tr><td>Show help</td><td>?</td>
|
||||
<tr><td>Toggle mute</td><td>m</td>
|
||||
<tr><td>Toggle subtitles (if available)</td><td>c</td>
|
||||
<tr><td>Increase speed</td><td>></td>
|
||||
<tr><td>Decrease speed</td><td><</td>
|
||||
<tr><td>Back 5 seconds</td><td>←</td>
|
||||
<tr><td>Forward 5 seconds</td><td>→</td>
|
||||
`, 3000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user