mirror of
https://github.com/goodtube4u/goodtube.git
synced 2025-11-22 10:16:11 +00:00
Updates
This commit is contained in:
6
js/sweetalert2@11.js
Normal file
6
js/sweetalert2@11.js
Normal file
File diff suppressed because one or more lines are too long
40
js/video.min.js
vendored
Normal file
40
js/video.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
30
js/videojs-core.js
Normal file
30
js/videojs-core.js
Normal file
File diff suppressed because one or more lines are too long
312
js/videojs-hls-quality-selector.js
Normal file
312
js/videojs-hls-quality-selector.js
Normal file
@@ -0,0 +1,312 @@
|
||||
/*! @name videojs-hls-quality-selector @version 2.0.0 @license MIT */
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['video.js'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.videojsHlsQualitySelector = factory(global.videojs));
|
||||
}(this, (function (videojs) { 'use strict';
|
||||
|
||||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
||||
|
||||
var videojs__default = /*#__PURE__*/_interopDefaultLegacy(videojs);
|
||||
|
||||
var version = "2.0.0";
|
||||
|
||||
const MenuButton = videojs__default['default'].getComponent('MenuButton');
|
||||
const Menu = videojs__default['default'].getComponent('Menu');
|
||||
const Component = videojs__default['default'].getComponent('Component');
|
||||
const Dom = videojs__default['default'].dom;
|
||||
|
||||
/**
|
||||
* Convert string to title case.
|
||||
*
|
||||
* @param {string} string - the string to convert
|
||||
* @return {string} the returned titlecase string
|
||||
*/
|
||||
function toTitleCase(string) {
|
||||
if (typeof string !== 'string') {
|
||||
return string;
|
||||
}
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend vjs button class for quality button.
|
||||
*/
|
||||
class ConcreteButton extends MenuButton {
|
||||
/**
|
||||
* Button constructor.
|
||||
*
|
||||
* @param {Player} player - videojs player instance
|
||||
*/
|
||||
constructor(player) {
|
||||
super(player, {
|
||||
title: player.localize('Quality'),
|
||||
name: 'QualityButton'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates button items.
|
||||
*
|
||||
* @return {Array} - Button items
|
||||
*/
|
||||
createItems() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the menu and add all items to it.
|
||||
*
|
||||
* @return {Menu}
|
||||
* The constructed menu
|
||||
*/
|
||||
createMenu() {
|
||||
const menu = new Menu(this.player_, {
|
||||
menuButton: this
|
||||
});
|
||||
this.hideThreshold_ = 0;
|
||||
|
||||
this.items = this.createItems();
|
||||
if (this.items) {
|
||||
// Add menu items to the menu
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
menu.addItem(this.items[i]);
|
||||
}
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
|
||||
// Concrete classes
|
||||
const VideoJsMenuItemClass = videojs__default['default'].getComponent('MenuItem');
|
||||
|
||||
/**
|
||||
* Extend vjs menu item class.
|
||||
*/
|
||||
class ConcreteMenuItem extends VideoJsMenuItemClass {
|
||||
/**
|
||||
* Menu item constructor.
|
||||
*
|
||||
* @param {Player} player - vjs player
|
||||
* @param {Object} item - Item object
|
||||
* @param {ConcreteButton} qualityButton - The containing button.
|
||||
* @param {HlsQualitySelector} plugin - This plugin instance.
|
||||
*/
|
||||
constructor(player, item, qualityButton, plugin) {
|
||||
super(player, {
|
||||
label: item.label,
|
||||
selectable: true,
|
||||
selected: item.selected || false
|
||||
});
|
||||
this.item = item;
|
||||
this.qualityButton = qualityButton;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click event for menu item.
|
||||
*/
|
||||
handleClick() {
|
||||
// Reset other menu items selected status.
|
||||
for (let i = 0; i < this.qualityButton.items.length; ++i) {
|
||||
this.qualityButton.items[i].selected(false);
|
||||
}
|
||||
|
||||
// Set this menu item to selected, and set quality.
|
||||
this.plugin.setQuality(this.item.value);
|
||||
this.selected(true);
|
||||
}
|
||||
}
|
||||
|
||||
const Plugin = videojs__default['default'].getPlugin('plugin');
|
||||
|
||||
// Default options for the plugin.
|
||||
const defaults = {};
|
||||
|
||||
/**
|
||||
* An advanced Video.js plugin. For more information on the API
|
||||
*
|
||||
* See: https://blog.videojs.com/feature-spotlight-advanced-plugins/
|
||||
*/
|
||||
class HlsQualitySelector extends Plugin {
|
||||
/**
|
||||
* Create a HlsQualitySelector plugin instance.
|
||||
*
|
||||
* @param {Player} player
|
||||
* A Video.js Player instance.
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* An optional options object.
|
||||
*
|
||||
* While not a core part of the Video.js plugin architecture, a
|
||||
* second argument of options is a convenient way to accept inputs
|
||||
* from your plugin's caller.
|
||||
*/
|
||||
constructor(player, options) {
|
||||
// the parent class will add player under this.player
|
||||
super(player);
|
||||
this.options = videojs__default['default'].obj.merge(defaults, options);
|
||||
this.player.ready(() => {
|
||||
// If there is quality levels plugin and the HLS tech exists then continue.
|
||||
if (this.player.qualityLevels) {
|
||||
this.player.addClass('vjs-hls-quality-selector');
|
||||
// Create the quality button.
|
||||
this.createQualityButton();
|
||||
this.bindPlayerEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds listener for quality level changes.
|
||||
*/
|
||||
bindPlayerEvents() {
|
||||
this.player.qualityLevels().on('addqualitylevel', this.onAddQualityLevel.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the quality menu button to the player control bar.
|
||||
*/
|
||||
createQualityButton() {
|
||||
const player = this.player;
|
||||
this._qualityButton = new ConcreteButton(player);
|
||||
const placementIndex = player.controlBar.children().length - 2;
|
||||
const concreteButtonInstance = player.controlBar.addChild(this._qualityButton, {
|
||||
componentClass: 'qualitySelector'
|
||||
}, this.options.placementIndex || placementIndex);
|
||||
concreteButtonInstance.addClass('vjs-quality-selector');
|
||||
if (!this.options.displayCurrentQuality) {
|
||||
const icon = ` ${this.options.vjsIconClass || 'vjs-icon-hd'}`;
|
||||
concreteButtonInstance.menuButton_.$('.vjs-icon-placeholder').className += icon;
|
||||
} else {
|
||||
this.setButtonInnerText(player.localize('Auto'));
|
||||
}
|
||||
concreteButtonInstance.removeClass('vjs-hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
*Set inner button text.
|
||||
*
|
||||
* @param {string} text - the text to display in the button.
|
||||
*/
|
||||
setButtonInnerText(text) {
|
||||
this._qualityButton.menuButton_.$('.vjs-icon-placeholder').innerHTML = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds individual quality menu items.
|
||||
*
|
||||
* @param {Object} item - Individual quality menu item.
|
||||
* @return {ConcreteMenuItem} - Menu item
|
||||
*/
|
||||
getQualityMenuItem(item) {
|
||||
const player = this.player;
|
||||
return new ConcreteMenuItem(player, item, this._qualityButton, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when a quality level is added from HLS playlist.
|
||||
*/
|
||||
onAddQualityLevel() {
|
||||
const player = this.player;
|
||||
const qualityList = player.qualityLevels();
|
||||
const levels = qualityList.levels_ || [];
|
||||
const levelItems = [];
|
||||
for (let i = 0; i < levels.length; ++i) {
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = levels[i];
|
||||
const pixels = width > height ? height : width;
|
||||
if (!pixels) {
|
||||
continue;
|
||||
}
|
||||
if (!levelItems.filter(_existingItem => {
|
||||
return _existingItem.item && _existingItem.item.value === pixels;
|
||||
}).length) {
|
||||
const levelItem = this.getQualityMenuItem.call(this, {
|
||||
label: pixels + 'p',
|
||||
value: pixels
|
||||
});
|
||||
levelItems.push(levelItem);
|
||||
}
|
||||
}
|
||||
levelItems.sort((current, next) => {
|
||||
if (typeof current !== 'object' || typeof next !== 'object') {
|
||||
return -1;
|
||||
}
|
||||
if (current.item.value < next.item.value) {
|
||||
return 1;
|
||||
}
|
||||
if (current.item.value > next.item.value) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
levelItems.push(this.getQualityMenuItem.call(this, {
|
||||
label: this.player.localize('Auto'),
|
||||
value: 'auto',
|
||||
selected: true
|
||||
}));
|
||||
if (this._qualityButton) {
|
||||
this._qualityButton.createItems = () => {
|
||||
return levelItems;
|
||||
};
|
||||
this._qualityButton.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets quality (based on media short side)
|
||||
*
|
||||
* @param {number} quality - A number representing HLS playlist.
|
||||
*/
|
||||
setQuality(quality) {
|
||||
const qualityList = this.player.qualityLevels();
|
||||
|
||||
// Set quality on plugin
|
||||
this._currentQuality = quality;
|
||||
if (this.options.displayCurrentQuality) {
|
||||
this.setButtonInnerText(quality === 'auto' ? this.player.localize('Auto') : `${quality}p`);
|
||||
}
|
||||
for (let i = 0; i < qualityList.length; ++i) {
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = qualityList[i];
|
||||
const pixels = width > height ? height : width;
|
||||
qualityList[i].enabled = pixels === quality || quality === 'auto';
|
||||
}
|
||||
|
||||
this._qualityButton.unpressButton();
|
||||
|
||||
// Select the correct quality menu item on screen
|
||||
for (let i = 0; i < this._qualityButton.items.length; ++i) {
|
||||
if (this._qualityButton.items[i]['item']['value'] == this._currentQuality) {
|
||||
this._qualityButton.items[i].selected(true);
|
||||
}
|
||||
else {
|
||||
this._qualityButton.items[i].selected(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current set quality or 'auto'
|
||||
*
|
||||
* @return {string} the currently set quality
|
||||
*/
|
||||
getCurrentQuality() {
|
||||
return this._currentQuality || 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
// Include the version number.
|
||||
HlsQualitySelector.VERSION = version;
|
||||
|
||||
// Register the plugin with video.js.
|
||||
videojs__default['default'].registerPlugin('hlsQualitySelector', HlsQualitySelector);
|
||||
|
||||
return HlsQualitySelector;
|
||||
|
||||
})));
|
||||
4
js/videojs-quality-selector.js
Normal file
4
js/videojs-quality-selector.js
Normal file
File diff suppressed because one or more lines are too long
603
js/videojs-vtt-thumbnails.js
Normal file
603
js/videojs-vtt-thumbnails.js
Normal file
@@ -0,0 +1,603 @@
|
||||
/**
|
||||
* pthumbnails
|
||||
* @version 1.2.0
|
||||
* @copyright 2020 Rigel Kent <sendmemail@rigelk.eu>
|
||||
* @license MIT
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :
|
||||
typeof define === 'function' && define.amd ? define(['video.js'], factory) :
|
||||
(global.videojsVttThumbnails = factory(global.videojs));
|
||||
}(this, (function (videojs) { 'use strict';
|
||||
|
||||
videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
|
||||
|
||||
var version = "1.2.0";
|
||||
|
||||
var asyncGenerator = function () {
|
||||
function AwaitValue(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
function AsyncGenerator(gen) {
|
||||
var front, back;
|
||||
|
||||
function send(key, arg) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var request = {
|
||||
key: key,
|
||||
arg: arg,
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
next: null
|
||||
};
|
||||
|
||||
if (back) {
|
||||
back = back.next = request;
|
||||
} else {
|
||||
front = back = request;
|
||||
resume(key, arg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resume(key, arg) {
|
||||
try {
|
||||
var result = gen[key](arg);
|
||||
var value = result.value;
|
||||
|
||||
if (value instanceof AwaitValue) {
|
||||
Promise.resolve(value.value).then(function (arg) {
|
||||
resume("next", arg);
|
||||
}, function (arg) {
|
||||
resume("throw", arg);
|
||||
});
|
||||
} else {
|
||||
settle(result.done ? "return" : "normal", result.value);
|
||||
}
|
||||
} catch (err) {
|
||||
settle("throw", err);
|
||||
}
|
||||
}
|
||||
|
||||
function settle(type, value) {
|
||||
switch (type) {
|
||||
case "return":
|
||||
front.resolve({
|
||||
value: value,
|
||||
done: true
|
||||
});
|
||||
break;
|
||||
|
||||
case "throw":
|
||||
front.reject(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
front.resolve({
|
||||
value: value,
|
||||
done: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
front = front.next;
|
||||
|
||||
if (front) {
|
||||
resume(front.key, front.arg);
|
||||
} else {
|
||||
back = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._invoke = send;
|
||||
|
||||
if (typeof gen.return !== "function") {
|
||||
this.return = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof Symbol === "function" && Symbol.asyncIterator) {
|
||||
AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
AsyncGenerator.prototype.next = function (arg) {
|
||||
return this._invoke("next", arg);
|
||||
};
|
||||
|
||||
AsyncGenerator.prototype.throw = function (arg) {
|
||||
return this._invoke("throw", arg);
|
||||
};
|
||||
|
||||
AsyncGenerator.prototype.return = function (arg) {
|
||||
return this._invoke("return", arg);
|
||||
};
|
||||
|
||||
return {
|
||||
wrap: function (fn) {
|
||||
return function () {
|
||||
return new AsyncGenerator(fn.apply(this, arguments));
|
||||
};
|
||||
},
|
||||
await: function (value) {
|
||||
return new AwaitValue(value);
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var classCallCheck = function (instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
};
|
||||
|
||||
// import request from 'request';
|
||||
|
||||
// Default options for the plugin.
|
||||
var defaults = {};
|
||||
|
||||
// Cache for image elements
|
||||
var cache = {};
|
||||
|
||||
// Cross-compatibility for Video.js 5 and 6.
|
||||
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
||||
// const dom = videojs.dom || videojs;
|
||||
|
||||
/**
|
||||
* Function to invoke when the player is ready.
|
||||
*
|
||||
* This is a great place for your plugin to initialize itself. When this
|
||||
* function is called, the player will have its DOM and child components
|
||||
* in place.
|
||||
*
|
||||
* @function onPlayerReady
|
||||
* @param {Player} player
|
||||
* A Video.js player object.
|
||||
*
|
||||
* @param {Object} [options={}]
|
||||
* A plain object containing options for the plugin.
|
||||
*/
|
||||
var onPlayerReady = function onPlayerReady(player, options) {
|
||||
player.addClass('vjs-vtt-thumbnails');
|
||||
player.vttThumbnails = new vttThumbnailsPlugin(player, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* A video.js plugin.
|
||||
*
|
||||
* In the plugin function, the value of `this` is a video.js `Player`
|
||||
* instance. You cannot rely on the player being in a "ready" state here,
|
||||
* depending on how the plugin is invoked. This may or may not be important
|
||||
* to you; if not, remove the wait for "ready"!
|
||||
*
|
||||
* @function vttThumbnails
|
||||
* @param {Object} [options={}]
|
||||
* An object of options left to the plugin author to define.
|
||||
*/
|
||||
var vttThumbnails = function vttThumbnails(options) {
|
||||
var _this = this;
|
||||
|
||||
this.ready(function () {
|
||||
onPlayerReady(_this, videojs.mergeOptions(defaults, options));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* VTT Thumbnails class.
|
||||
*
|
||||
* This class performs all functions related to displaying the vtt
|
||||
* thumbnails.
|
||||
*/
|
||||
|
||||
var vttThumbnailsPlugin = function () {
|
||||
|
||||
/**
|
||||
* Plugin class constructor, called by videojs on
|
||||
* ready event.
|
||||
*
|
||||
* @function constructor
|
||||
* @param {Player} player
|
||||
* A Video.js player object.
|
||||
*
|
||||
* @param {Object} [options={}]
|
||||
* A plain object containing options for the plugin.
|
||||
* - src: path to the .vtt file
|
||||
* - baseUrl (optional): host prepended to the image definitions
|
||||
* - preloadStrategy (optional): preload images in the cache, for smooth scrubbing (default: none, available: 'all')
|
||||
*/
|
||||
function vttThumbnailsPlugin(player, options) {
|
||||
classCallCheck(this, vttThumbnailsPlugin);
|
||||
|
||||
this.player = player;
|
||||
this.options = options;
|
||||
this.listenForDurationChange();
|
||||
this.initializeThumbnails();
|
||||
this.registeredEvents = {};
|
||||
return this;
|
||||
}
|
||||
|
||||
vttThumbnailsPlugin.prototype.src = function src(source) {
|
||||
this.resetPlugin();
|
||||
this.options.src = source;
|
||||
this.initializeThumbnails();
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.detach = function detach() {
|
||||
this.resetPlugin();
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.resetPlugin = function resetPlugin() {
|
||||
this.thumbnailHolder && this.thumbnailHolder.parentNode.removeChild(this.thumbnailHolder);
|
||||
this.progressBar && this.progressBar.removeEventListener('mouseenter', this.registeredEvents.progressBarMouseEnter);
|
||||
this.progressBar && this.progressBar.removeEventListener('mouseleave', this.registeredEvents.progressBarMouseLeave);
|
||||
this.progressBar && this.progressBar.removeEventListener('mousemove', this.registeredEvents.progressBarMouseMove);
|
||||
delete this.registeredEvents.progressBarMouseEnter;
|
||||
delete this.registeredEvents.progressBarMouseLeave;
|
||||
delete this.registeredEvents.progressBarMouseMove;
|
||||
delete this.progressBar;
|
||||
delete this.vttData;
|
||||
delete this.thumbnailHolder;
|
||||
delete this.timeHolder;
|
||||
delete this.lastStyle;
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.listenForDurationChange = function listenForDurationChange() {
|
||||
this.player.on('durationchange', function () {});
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstrap the plugin.
|
||||
*/
|
||||
|
||||
|
||||
vttThumbnailsPlugin.prototype.initializeThumbnails = function initializeThumbnails() {
|
||||
var _this2 = this;
|
||||
|
||||
if (!this.options.src) {
|
||||
return;
|
||||
}
|
||||
var baseUrl = this.getBaseUrl();
|
||||
var url = this.getFullyQualifiedUrl(this.options.src, baseUrl);
|
||||
this.getVttFile(url).then(function (data) {
|
||||
_this2.vttData = _this2.processVtt(data);
|
||||
_this2.setupThumbnailElement();
|
||||
|
||||
if (_this2.options.hasOwnProperty('preloadStrategy')) {
|
||||
_this2.preload(_this2.vttData);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a base URL should we require one.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
|
||||
vttThumbnailsPlugin.prototype.getBaseUrl = function getBaseUrl() {
|
||||
return [window.location.protocol, '//', window.location.hostname, window.location.port ? ':' + window.location.port : '', window.location.pathname].join('').split(/([^\/]*)$/gi).shift();
|
||||
};
|
||||
|
||||
/**
|
||||
* Grabs the contents of the VTT file.
|
||||
*
|
||||
* @param url
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
|
||||
vttThumbnailsPlugin.prototype.getVttFile = function getVttFile(url) {
|
||||
var _this3 = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.data = {
|
||||
resolve: resolve
|
||||
};
|
||||
req.addEventListener('load', _this3.vttFileLoaded);
|
||||
req.open('GET', url);
|
||||
req.send();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for loaded VTT file.
|
||||
*/
|
||||
|
||||
|
||||
vttThumbnailsPlugin.prototype.vttFileLoaded = function vttFileLoaded() {
|
||||
this.data.resolve(this.responseText);
|
||||
};
|
||||
|
||||
/**
|
||||
* This will fill the cache and thus preload images
|
||||
*/
|
||||
|
||||
|
||||
vttThumbnailsPlugin.prototype.preload = function preload(data) {
|
||||
var _this4 = this;
|
||||
|
||||
data.forEach(function (item) {
|
||||
return _this4.setImageInCacheForItem(item);
|
||||
});
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.setupThumbnailElement = function setupThumbnailElement(data) {
|
||||
var _this5 = this;
|
||||
|
||||
var mouseDisplay = this.player.$('.vjs-mouse-display');
|
||||
this.progressBar = this.player.$('.vjs-progress-control');
|
||||
// thumbnail element
|
||||
var thumbHolder = document.createElement('div');
|
||||
thumbHolder.setAttribute('class', 'vjs-vtt-thumbnail-display');
|
||||
this.progressBar.appendChild(thumbHolder);
|
||||
this.thumbnailHolder = thumbHolder;
|
||||
// time element
|
||||
var timeHolder = document.createElement('time');
|
||||
timeHolder.setAttribute('class', 'vjs-vtt-thumbnail-time');
|
||||
this.thumbnailHolder.appendChild(timeHolder);
|
||||
this.timeHolder = timeHolder;
|
||||
if (mouseDisplay) {
|
||||
mouseDisplay.classList.add('vjs-hidden');
|
||||
}
|
||||
this.registeredEvents.progressBarMouseEnter = function () {
|
||||
return _this5.onBarMouseenter();
|
||||
};
|
||||
this.registeredEvents.progressBarMouseLeave = function () {
|
||||
return _this5.onBarMouseleave();
|
||||
};
|
||||
this.progressBar.addEventListener('mouseenter', this.registeredEvents.progressBarMouseEnter);
|
||||
this.progressBar.addEventListener('mouseleave', this.registeredEvents.progressBarMouseLeave);
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.onBarMouseenter = function onBarMouseenter() {
|
||||
var _this6 = this;
|
||||
|
||||
this.mouseMoveCallback = function (e) {
|
||||
_this6.onBarMousemove(e);
|
||||
};
|
||||
this.registeredEvents.progressBarMouseMove = this.mouseMoveCallback;
|
||||
this.progressBar.addEventListener('mousemove', this.registeredEvents.progressBarMouseMove);
|
||||
this.showThumbnailHolder();
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.onBarMouseleave = function onBarMouseleave() {
|
||||
if (this.registeredEvents.progressBarMouseMove) {
|
||||
this.progressBar.removeEventListener('mousemove', this.registeredEvents.progressBarMouseMove);
|
||||
}
|
||||
this.hideThumbnailHolder();
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getXCoord = function getXCoord(bar, mouseX) {
|
||||
var rect = bar.getBoundingClientRect();
|
||||
var docEl = document.documentElement;
|
||||
return mouseX - (rect.left + (window.pageXOffset || docEl.scrollLeft || 0));
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.onBarMousemove = function onBarMousemove(event) {
|
||||
this.updateThumbnailStyle(videojs.dom.getPointerPosition(this.progressBar, event).x, this.progressBar.offsetWidth);
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.setImageInCacheForItem = function setImageInCacheForItem(item) {
|
||||
// Cache miss
|
||||
if (item.css.url && !cache[item.css.url]) {
|
||||
var image = new Image();
|
||||
image.src = item.css.url;
|
||||
cache[item.css.url] = image;
|
||||
}
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getStyleForTime = function getStyleForTime(time) {
|
||||
for (var i = 0; i < this.vttData.length; ++i) {
|
||||
var item = this.vttData[i];
|
||||
if (time >= item.start && time < item.end) {
|
||||
this.setImageInCacheForItem(item);
|
||||
|
||||
return item.css;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.showThumbnailHolder = function showThumbnailHolder() {
|
||||
this.thumbnailHolder.style.opacity = '1';
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.hideThumbnailHolder = function hideThumbnailHolder() {
|
||||
this.thumbnailHolder.style.opacity = '0';
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.updateThumbnailStyle = function updateThumbnailStyle(percent, width) {
|
||||
var duration = this.player.duration();
|
||||
var time = percent * duration;
|
||||
var currentStyle = this.getStyleForTime(time);
|
||||
|
||||
var timestamp = new Date(Math.round(time) * 1000).toISOString().substr(11, 8);
|
||||
timestamp = duration > 3599 ? timestamp : timestamp.substring(3);
|
||||
this.timeHolder.innerText = timestamp;
|
||||
|
||||
if (!currentStyle) {
|
||||
return this.hideThumbnailHolder();
|
||||
}
|
||||
|
||||
var xPos = percent * width;
|
||||
var thumbnailWidth = parseInt(this.thumbnailHolder.offsetWidth);
|
||||
var halfthumbnailWidth = thumbnailWidth / 2;
|
||||
var marginRight = width - (xPos + halfthumbnailWidth);
|
||||
var marginLeft = xPos - halfthumbnailWidth;
|
||||
|
||||
if (marginLeft > 0 && marginRight > 0) {
|
||||
this.thumbnailHolder.style.transform = 'translateX(' + (xPos - halfthumbnailWidth) + 'px)';
|
||||
} else if (marginLeft <= 0) {
|
||||
this.thumbnailHolder.style.transform = 'translateX(' + 0 + 'px)';
|
||||
} else if (marginRight <= 0) {
|
||||
this.thumbnailHolder.style.transform = 'translateX(' + (xPos + marginRight - halfthumbnailWidth) + 'px)';
|
||||
}
|
||||
|
||||
if (this.lastStyle && this.lastStyle === currentStyle) {
|
||||
return;
|
||||
}
|
||||
this.lastStyle = currentStyle;
|
||||
|
||||
for (var style in currentStyle) {
|
||||
if (currentStyle.hasOwnProperty(style)) {
|
||||
this.thumbnailHolder.style[style] = currentStyle[style];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.processVtt = function processVtt(data) {
|
||||
var _this7 = this;
|
||||
|
||||
var processedVtts = [];
|
||||
var vttDefinitions = data.split(/[\r\n][\r\n]/i);
|
||||
vttDefinitions.forEach(function (vttDef) {
|
||||
if (vttDef.match(/([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?( ?--> ?)([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?[\r\n]{1}.*/gi)) {
|
||||
var vttDefSplit = vttDef.split(/[\r\n]/i);
|
||||
var vttTiming = vttDefSplit[0];
|
||||
var vttTimingSplit = vttTiming.split(/ ?--> ?/i);
|
||||
var vttTimeStart = vttTimingSplit[0];
|
||||
var vttTimeEnd = vttTimingSplit[1];
|
||||
var vttImageDef = vttDefSplit[1];
|
||||
var vttCssDef = _this7.getVttCss(vttImageDef);
|
||||
|
||||
processedVtts.push({
|
||||
start: _this7.getSecondsFromTimestamp(vttTimeStart),
|
||||
end: _this7.getSecondsFromTimestamp(vttTimeEnd),
|
||||
css: vttCssDef
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return processedVtts;
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getFullyQualifiedUrl = function getFullyQualifiedUrl(path, base) {
|
||||
if (path.indexOf('//') >= 0) {
|
||||
// We have a fully qualified path.
|
||||
return path;
|
||||
}
|
||||
if (base.indexOf('//') === 0) {
|
||||
// We don't have a fully qualified path, but need to
|
||||
// be careful with trimming.
|
||||
return [base.replace(/\/$/gi, ''), this.trim(path, '/')].join('/');
|
||||
}
|
||||
if (base.indexOf('//') > 0) {
|
||||
// We don't have a fully qualified path, and should
|
||||
// trim both sides of base and path.
|
||||
return [this.trim(base, '/'), this.trim(path, '/')].join('/');
|
||||
}
|
||||
|
||||
// If all else fails.
|
||||
return path;
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getPropsFromDef = function getPropsFromDef(def) {
|
||||
var imageDefSplit = def.split(/#xywh=/i);
|
||||
var imageUrl = imageDefSplit[0];
|
||||
var imageCoords = imageDefSplit[1];
|
||||
var splitCoords = imageCoords.match(/[0-9]+/gi);
|
||||
return {
|
||||
x: splitCoords[0],
|
||||
y: splitCoords[1],
|
||||
w: splitCoords[2],
|
||||
h: splitCoords[3],
|
||||
image: imageUrl
|
||||
};
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getVttCss = function getVttCss(vttImageDef) {
|
||||
|
||||
var cssObj = {};
|
||||
|
||||
// If there isn't a protocol, use the VTT source URL.
|
||||
var baseSplit = void 0;
|
||||
if (this.options.baseUrl) {
|
||||
baseSplit = this.options.baseUrl;
|
||||
} else if (this.options.src.indexOf('//') >= 0) {
|
||||
baseSplit = this.options.src.split(/([^\/]*)$/gi).shift();
|
||||
} else {
|
||||
baseSplit = this.getBaseUrl() + this.options.src.split(/([^\/]*)$/gi).shift();
|
||||
}
|
||||
|
||||
vttImageDef = this.getFullyQualifiedUrl(vttImageDef, baseSplit);
|
||||
|
||||
// deal with regular thumbnails
|
||||
if (!vttImageDef.match(/#xywh=/i)) {
|
||||
cssObj.background = 'url("' + vttImageDef + '")';
|
||||
cssObj.url = vttImageDef;
|
||||
return cssObj;
|
||||
}
|
||||
|
||||
// deal with sprited thumbnails
|
||||
var imageProps = this.getPropsFromDef(vttImageDef);
|
||||
cssObj.background = 'url("' + imageProps.image + '") no-repeat -' + imageProps.x + 'px -' + imageProps.y + 'px';
|
||||
cssObj.width = imageProps.w + 'px';
|
||||
cssObj.height = imageProps.h + 'px';
|
||||
cssObj.url = imageProps.image;
|
||||
|
||||
return cssObj;
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.doconstructTimestamp = function doconstructTimestamp(timestamp) {
|
||||
var splitStampMilliseconds = timestamp.split('.');
|
||||
var timeParts = splitStampMilliseconds[0];
|
||||
var timePartsSplit = timeParts.split(':');
|
||||
return {
|
||||
milliseconds: parseInt(splitStampMilliseconds[1]) || 0,
|
||||
seconds: parseInt(timePartsSplit.pop()) || 0,
|
||||
minutes: parseInt(timePartsSplit.pop()) || 0,
|
||||
hours: parseInt(timePartsSplit.pop()) || 0
|
||||
};
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.getSecondsFromTimestamp = function getSecondsFromTimestamp(timestamp) {
|
||||
var timestampParts = this.doconstructTimestamp(timestamp);
|
||||
return parseInt(timestampParts.hours * (60 * 60) + timestampParts.minutes * 60 + timestampParts.seconds + timestampParts.milliseconds / 1000);
|
||||
};
|
||||
|
||||
vttThumbnailsPlugin.prototype.trim = function trim(str, charlist) {
|
||||
var whitespace = [' ', '\n', '\r', '\t', '\f', '\x0b', '\xa0', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200A', '\u200B', '\u2028', '\u2029', '\u3000'].join('');
|
||||
var l = 0;
|
||||
var i = 0;
|
||||
str += '';
|
||||
if (charlist) {
|
||||
whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1');
|
||||
}
|
||||
l = str.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
if (whitespace.indexOf(str.charAt(i)) === -1) {
|
||||
str = str.substring(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
l = str.length;
|
||||
for (i = l - 1; i >= 0; i--) {
|
||||
if (whitespace.indexOf(str.charAt(i)) === -1) {
|
||||
str = str.substring(0, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
|
||||
};
|
||||
|
||||
return vttThumbnailsPlugin;
|
||||
}();
|
||||
|
||||
// Register the plugin with video.js.
|
||||
|
||||
|
||||
registerPlugin('vttThumbnails', vttThumbnails);
|
||||
|
||||
// Include the version number.
|
||||
vttThumbnails.VERSION = version;
|
||||
|
||||
return vttThumbnails;
|
||||
|
||||
})));
|
||||
Reference in New Issue
Block a user