|
|
@ -151,45 +151,47 @@ player.vttThumbnails({
|
|
|
|
|
|
|
|
|
|
|
|
// Enable annotations
|
|
|
|
// Enable annotations
|
|
|
|
if (!video_data.params.listen && video_data.params.annotations) {
|
|
|
|
if (!video_data.params.listen && video_data.params.annotations) {
|
|
|
|
var video_container = document.getElementById('player');
|
|
|
|
window.addEventListener('load', function (e) {
|
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
var video_container = document.getElementById('player');
|
|
|
|
xhr.responseType = 'text';
|
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
xhr.timeout = 60000;
|
|
|
|
xhr.responseType = 'text';
|
|
|
|
xhr.open('GET', '/api/v1/annotations/' + video_data.id, true);
|
|
|
|
xhr.timeout = 60000;
|
|
|
|
|
|
|
|
xhr.open('GET', '/api/v1/annotations/' + video_data.id, true);
|
|
|
|
xhr.onreadystatechange = function () {
|
|
|
|
|
|
|
|
if (xhr.readyState === 4) {
|
|
|
|
xhr.onreadystatechange = function () {
|
|
|
|
if (xhr.status === 200) {
|
|
|
|
if (xhr.readyState === 4) {
|
|
|
|
videojs.registerPlugin('youtubeAnnotationsPlugin', youtubeAnnotationsPlugin);
|
|
|
|
if (xhr.status === 200) {
|
|
|
|
if (!player.paused()) {
|
|
|
|
videojs.registerPlugin('youtubeAnnotationsPlugin', youtubeAnnotationsPlugin);
|
|
|
|
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
|
|
|
|
if (!player.paused()) {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
player.one('play', function (event) {
|
|
|
|
|
|
|
|
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
|
|
|
|
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
|
|
|
|
player.one('play', function (event) {
|
|
|
|
|
|
|
|
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener('__ar_annotation_click', e => {
|
|
|
|
window.addEventListener('__ar_annotation_click', e => {
|
|
|
|
const { url, target, seconds } = e.detail;
|
|
|
|
const { url, target, seconds } = e.detail;
|
|
|
|
var path = new URL(url);
|
|
|
|
var path = new URL(url);
|
|
|
|
|
|
|
|
|
|
|
|
if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) {
|
|
|
|
if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) {
|
|
|
|
path.search += '&t=' + seconds;
|
|
|
|
path.search += '&t=' + seconds;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
path = path.pathname + path.search;
|
|
|
|
path = path.pathname + path.search;
|
|
|
|
|
|
|
|
|
|
|
|
if (target === 'current') {
|
|
|
|
if (target === 'current') {
|
|
|
|
window.location.href = path;
|
|
|
|
window.location.href = path;
|
|
|
|
} else if (target === 'new') {
|
|
|
|
} else if (target === 'new') {
|
|
|
|
window.open(path, '_blank');
|
|
|
|
window.open(path, '_blank');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
xhr.send();
|
|
|
|
xhr.send();
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function increase_volume(delta) {
|
|
|
|
function increase_volume(delta) {
|
|
|
@ -234,25 +236,25 @@ function toggle_play() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const toggle_captions = (function() {
|
|
|
|
const toggle_captions = (function () {
|
|
|
|
let toggledTrack = null;
|
|
|
|
let toggledTrack = null;
|
|
|
|
const onChange = function(e) {
|
|
|
|
const onChange = function (e) {
|
|
|
|
toggledTrack = null;
|
|
|
|
toggledTrack = null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
const bindChange = function(onOrOff) {
|
|
|
|
const bindChange = function (onOrOff) {
|
|
|
|
player.textTracks()[onOrOff]('change', onChange);
|
|
|
|
player.textTracks()[onOrOff]('change', onChange);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
// Wrapper function to ignore our own emitted events and only listen
|
|
|
|
// Wrapper function to ignore our own emitted events and only listen
|
|
|
|
// to events emitted by Video.js on click on the captions menu items.
|
|
|
|
// to events emitted by Video.js on click on the captions menu items.
|
|
|
|
const setMode = function(track, mode) {
|
|
|
|
const setMode = function (track, mode) {
|
|
|
|
bindChange('off');
|
|
|
|
bindChange('off');
|
|
|
|
track.mode = mode;
|
|
|
|
track.mode = mode;
|
|
|
|
window.setTimeout(function() {
|
|
|
|
window.setTimeout(function () {
|
|
|
|
bindChange('on');
|
|
|
|
bindChange('on');
|
|
|
|
}, 0);
|
|
|
|
}, 0);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
bindChange('on');
|
|
|
|
bindChange('on');
|
|
|
|
return function() {
|
|
|
|
return function () {
|
|
|
|
if (toggledTrack !== null) {
|
|
|
|
if (toggledTrack !== null) {
|
|
|
|
if (toggledTrack.mode !== 'showing') {
|
|
|
|
if (toggledTrack.mode !== 'showing') {
|
|
|
|
setMode(toggledTrack, 'showing');
|
|
|
|
setMode(toggledTrack, 'showing');
|
|
|
@ -323,95 +325,95 @@ window.addEventListener('keydown', e => {
|
|
|
|
|| e.target === document.querySelector('.vjs-tech')
|
|
|
|
|| e.target === document.querySelector('.vjs-tech')
|
|
|
|
|| e.target === document.querySelector('.iframeblocker')
|
|
|
|
|| e.target === document.querySelector('.iframeblocker')
|
|
|
|
|| e.target === document.querySelector('.vjs-control-bar')
|
|
|
|
|| e.target === document.querySelector('.vjs-control-bar')
|
|
|
|
;
|
|
|
|
;
|
|
|
|
let action = null;
|
|
|
|
let action = null;
|
|
|
|
|
|
|
|
|
|
|
|
const code = e.keyCode;
|
|
|
|
const code = e.keyCode;
|
|
|
|
const decoratedKey =
|
|
|
|
const decoratedKey =
|
|
|
|
e.key
|
|
|
|
e.key
|
|
|
|
+ (e.altKey ? '+alt' : '')
|
|
|
|
+ (e.altKey ? '+alt' : '')
|
|
|
|
+ (e.ctrlKey ? '+ctrl' : '')
|
|
|
|
+ (e.ctrlKey ? '+ctrl' : '')
|
|
|
|
+ (e.metaKey ? '+meta' : '')
|
|
|
|
+ (e.metaKey ? '+meta' : '')
|
|
|
|
;
|
|
|
|
;
|
|
|
|
switch (decoratedKey) {
|
|
|
|
switch (decoratedKey) {
|
|
|
|
case ' ':
|
|
|
|
case ' ':
|
|
|
|
case 'k':
|
|
|
|
case 'k':
|
|
|
|
action = toggle_play;
|
|
|
|
action = toggle_play;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'ArrowUp':
|
|
|
|
case 'ArrowUp':
|
|
|
|
if (isPlayerFocused) {
|
|
|
|
if (isPlayerFocused) {
|
|
|
|
action = increase_volume.bind(this, 0.1);
|
|
|
|
action = increase_volume.bind(this, 0.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'ArrowDown':
|
|
|
|
case 'ArrowDown':
|
|
|
|
if (isPlayerFocused) {
|
|
|
|
if (isPlayerFocused) {
|
|
|
|
action = increase_volume.bind(this, -0.1);
|
|
|
|
action = increase_volume.bind(this, -0.1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'm':
|
|
|
|
case 'm':
|
|
|
|
action = toggle_muted;
|
|
|
|
action = toggle_muted;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'ArrowRight':
|
|
|
|
case 'ArrowRight':
|
|
|
|
action = skip_seconds.bind(this, 5);
|
|
|
|
action = skip_seconds.bind(this, 5);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'ArrowLeft':
|
|
|
|
case 'ArrowLeft':
|
|
|
|
action = skip_seconds.bind(this, -5);
|
|
|
|
action = skip_seconds.bind(this, -5);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
case 'l':
|
|
|
|
action = skip_seconds.bind(this, 10);
|
|
|
|
action = skip_seconds.bind(this, 10);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'j':
|
|
|
|
case 'j':
|
|
|
|
action = skip_seconds.bind(this, -10);
|
|
|
|
action = skip_seconds.bind(this, -10);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
case '9':
|
|
|
|
const percent = (code - 48) * 10;
|
|
|
|
const percent = (code - 48) * 10;
|
|
|
|
action = set_time_percent.bind(this, percent);
|
|
|
|
action = set_time_percent.bind(this, percent);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
case 'c':
|
|
|
|
action = toggle_captions;
|
|
|
|
action = toggle_captions;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
case 'f':
|
|
|
|
action = toggle_fullscreen;
|
|
|
|
action = toggle_fullscreen;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 'N':
|
|
|
|
case 'N':
|
|
|
|
action = next_video;
|
|
|
|
action = next_video;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
case 'P':
|
|
|
|
// TODO: Add support to play back previous video.
|
|
|
|
// TODO: Add support to play back previous video.
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '.':
|
|
|
|
case '.':
|
|
|
|
// TODO: Add support for next-frame-stepping.
|
|
|
|
// TODO: Add support for next-frame-stepping.
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
case ',':
|
|
|
|
// TODO: Add support for previous-frame-stepping.
|
|
|
|
// TODO: Add support for previous-frame-stepping.
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
case '>':
|
|
|
|
action = increase_playback_rate.bind(this, 1);
|
|
|
|
action = increase_playback_rate.bind(this, 1);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
case '<':
|
|
|
|
action = increase_playback_rate.bind(this, -1);
|
|
|
|
action = increase_playback_rate.bind(this, -1);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
console.info('Unhandled key down event: %s:', decoratedKey, e);
|
|
|
|
console.info('Unhandled key down event: %s:', decoratedKey, e);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (action) {
|
|
|
|
if (action) {
|
|
|
@ -422,7 +424,7 @@ window.addEventListener('keydown', e => {
|
|
|
|
|
|
|
|
|
|
|
|
// Add support for controlling the player volume by scrolling over it. Adapted from
|
|
|
|
// Add support for controlling the player volume by scrolling over it. Adapted from
|
|
|
|
// https://github.com/ctd1500/videojs-hotkeys/blob/bb4a158b2e214ccab87c2e7b95f42bc45c6bfd87/videojs.hotkeys.js#L292-L328
|
|
|
|
// https://github.com/ctd1500/videojs-hotkeys/blob/bb4a158b2e214ccab87c2e7b95f42bc45c6bfd87/videojs.hotkeys.js#L292-L328
|
|
|
|
(function() {
|
|
|
|
(function () {
|
|
|
|
const volumeStep = 0.05;
|
|
|
|
const volumeStep = 0.05;
|
|
|
|
const enableVolumeScroll = true;
|
|
|
|
const enableVolumeScroll = true;
|
|
|
|
const enableHoverScroll = true;
|
|
|
|
const enableHoverScroll = true;
|
|
|
@ -432,33 +434,33 @@ window.addEventListener('keydown', e => {
|
|
|
|
var volumeHover = false;
|
|
|
|
var volumeHover = false;
|
|
|
|
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
|
|
|
|
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
|
|
|
|
if (volumeSelector != null) {
|
|
|
|
if (volumeSelector != null) {
|
|
|
|
volumeSelector.onmouseover = function() { volumeHover = true; };
|
|
|
|
volumeSelector.onmouseover = function () { volumeHover = true; };
|
|
|
|
volumeSelector.onmouseout = function() { volumeHover = false; };
|
|
|
|
volumeSelector.onmouseout = function () { volumeHover = false; };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var mouseScroll = function mouseScroll(event) {
|
|
|
|
var mouseScroll = function mouseScroll(event) {
|
|
|
|
var activeEl = doc.activeElement;
|
|
|
|
var activeEl = doc.activeElement;
|
|
|
|
if (enableHoverScroll) {
|
|
|
|
if (enableHoverScroll) {
|
|
|
|
// If we leave this undefined then it can match non-existent elements below
|
|
|
|
// If we leave this undefined then it can match non-existent elements below
|
|
|
|
activeEl = 0;
|
|
|
|
activeEl = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// When controls are disabled, hotkeys will be disabled as well
|
|
|
|
// When controls are disabled, hotkeys will be disabled as well
|
|
|
|
if (player.controls()) {
|
|
|
|
if (player.controls()) {
|
|
|
|
if (volumeHover) {
|
|
|
|
if (volumeHover) {
|
|
|
|
if (enableVolumeScroll) {
|
|
|
|
if (enableVolumeScroll) {
|
|
|
|
event = window.event || event;
|
|
|
|
event = window.event || event;
|
|
|
|
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
|
|
|
|
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
|
|
|
|
event.preventDefault();
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
if (delta == 1) {
|
|
|
|
if (delta == 1) {
|
|
|
|
increase_volume(volumeStep);
|
|
|
|
increase_volume(volumeStep);
|
|
|
|
} else if (delta == -1) {
|
|
|
|
} else if (delta == -1) {
|
|
|
|
increase_volume(-volumeStep);
|
|
|
|
increase_volume(-volumeStep);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
player.on('mousewheel', mouseScroll);
|
|
|
|
player.on('mousewheel', mouseScroll);
|
|
|
|