Add unminimized sources and license information
parent
e8c9641548
commit
7f868ecdf9
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,373 @@
|
|||||||
|
/*! @name videojs-contrib-quality-levels @version 2.0.7 @license Apache-2.0 */
|
||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js'), require('global/document')) :
|
||||||
|
typeof define === 'function' && define.amd ? define(['video.js', 'global/document'], factory) :
|
||||||
|
(global.videojsContribQualityLevels = factory(global.videojs,global.document));
|
||||||
|
}(this, (function (videojs,document) { 'use strict';
|
||||||
|
|
||||||
|
videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
|
||||||
|
document = document && document.hasOwnProperty('default') ? document['default'] : document;
|
||||||
|
|
||||||
|
var classCallCheck = function (instance, Constructor) {
|
||||||
|
if (!(instance instanceof Constructor)) {
|
||||||
|
throw new TypeError("Cannot call a class as a function");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var inherits = function (subClass, superClass) {
|
||||||
|
if (typeof superClass !== "function" && superClass !== null) {
|
||||||
|
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: subClass,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
||||||
|
};
|
||||||
|
|
||||||
|
var possibleConstructorReturn = function (self, call) {
|
||||||
|
if (!self) {
|
||||||
|
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||||||
|
}
|
||||||
|
|
||||||
|
return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single QualityLevel.
|
||||||
|
*
|
||||||
|
* interface QualityLevel {
|
||||||
|
* readonly attribute DOMString id;
|
||||||
|
* attribute DOMString label;
|
||||||
|
* readonly attribute long width;
|
||||||
|
* readonly attribute long height;
|
||||||
|
* readonly attribute long bitrate;
|
||||||
|
* attribute boolean enabled;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @class QualityLevel
|
||||||
|
*/
|
||||||
|
|
||||||
|
var QualityLevel =
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a QualityLevel
|
||||||
|
*
|
||||||
|
* @param {Representation|Object} representation The representation of the quality level
|
||||||
|
* @param {string} representation.id Unique id of the QualityLevel
|
||||||
|
* @param {number=} representation.width Resolution width of the QualityLevel
|
||||||
|
* @param {number=} representation.height Resolution height of the QualityLevel
|
||||||
|
* @param {number} representation.bandwidth Bitrate of the QualityLevel
|
||||||
|
* @param {Function} representation.enabled Callback to enable/disable QualityLevel
|
||||||
|
*/
|
||||||
|
function QualityLevel(representation) {
|
||||||
|
classCallCheck(this, QualityLevel);
|
||||||
|
|
||||||
|
|
||||||
|
var level = this; // eslint-disable-line
|
||||||
|
|
||||||
|
if (videojs.browser.IS_IE8) {
|
||||||
|
level = document.createElement('custom');
|
||||||
|
for (var prop in QualityLevel.prototype) {
|
||||||
|
if (prop !== 'constructor') {
|
||||||
|
level[prop] = QualityLevel.prototype[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
level.id = representation.id;
|
||||||
|
level.label = level.id;
|
||||||
|
level.width = representation.width;
|
||||||
|
level.height = representation.height;
|
||||||
|
level.bitrate = representation.bandwidth;
|
||||||
|
level.enabled_ = representation.enabled;
|
||||||
|
|
||||||
|
Object.defineProperty(level, 'enabled', {
|
||||||
|
/**
|
||||||
|
* Get whether the QualityLevel is enabled.
|
||||||
|
*
|
||||||
|
* @return {boolean} True if the QualityLevel is enabled.
|
||||||
|
*/
|
||||||
|
get: function get$$1() {
|
||||||
|
return level.enabled_();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable the QualityLevel.
|
||||||
|
*
|
||||||
|
* @param {boolean} enable true to enable QualityLevel, false to disable.
|
||||||
|
*/
|
||||||
|
set: function set$$1(enable) {
|
||||||
|
level.enabled_(enable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return level;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of QualityLevels.
|
||||||
|
*
|
||||||
|
* interface QualityLevelList : EventTarget {
|
||||||
|
* getter QualityLevel (unsigned long index);
|
||||||
|
* readonly attribute unsigned long length;
|
||||||
|
* readonly attribute long selectedIndex;
|
||||||
|
*
|
||||||
|
* void addQualityLevel(QualityLevel qualityLevel)
|
||||||
|
* void removeQualityLevel(QualityLevel remove)
|
||||||
|
* QualityLevel? getQualityLevelById(DOMString id);
|
||||||
|
*
|
||||||
|
* attribute EventHandler onchange;
|
||||||
|
* attribute EventHandler onaddqualitylevel;
|
||||||
|
* attribute EventHandler onremovequalitylevel;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @extends videojs.EventTarget
|
||||||
|
* @class QualityLevelList
|
||||||
|
*/
|
||||||
|
|
||||||
|
var QualityLevelList = function (_videojs$EventTarget) {
|
||||||
|
inherits(QualityLevelList, _videojs$EventTarget);
|
||||||
|
|
||||||
|
function QualityLevelList() {
|
||||||
|
var _ret;
|
||||||
|
|
||||||
|
classCallCheck(this, QualityLevelList);
|
||||||
|
|
||||||
|
var _this = possibleConstructorReturn(this, _videojs$EventTarget.call(this));
|
||||||
|
|
||||||
|
var list = _this; // eslint-disable-line
|
||||||
|
|
||||||
|
if (videojs.browser.IS_IE8) {
|
||||||
|
list = document.createElement('custom');
|
||||||
|
for (var prop in QualityLevelList.prototype) {
|
||||||
|
if (prop !== 'constructor') {
|
||||||
|
list[prop] = QualityLevelList.prototype[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.levels_ = [];
|
||||||
|
list.selectedIndex_ = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the currently selected QualityLevel.
|
||||||
|
*
|
||||||
|
* @returns {number} The index of the selected QualityLevel. -1 if none selected.
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
Object.defineProperty(list, 'selectedIndex', {
|
||||||
|
get: function get$$1() {
|
||||||
|
return list.selectedIndex_;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the length of the list of QualityLevels.
|
||||||
|
*
|
||||||
|
* @returns {number} The length of the list.
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
Object.defineProperty(list, 'length', {
|
||||||
|
get: function get$$1() {
|
||||||
|
return list.levels_.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return _ret = list, possibleConstructorReturn(_this, _ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a quality level to the list.
|
||||||
|
*
|
||||||
|
* @param {Representation|Object} representation The representation of the quality level
|
||||||
|
* @param {string} representation.id Unique id of the QualityLevel
|
||||||
|
* @param {number=} representation.width Resolution width of the QualityLevel
|
||||||
|
* @param {number=} representation.height Resolution height of the QualityLevel
|
||||||
|
* @param {number} representation.bandwidth Bitrate of the QualityLevel
|
||||||
|
* @param {Function} representation.enabled Callback to enable/disable QualityLevel
|
||||||
|
* @return {QualityLevel} the QualityLevel added to the list
|
||||||
|
* @method addQualityLevel
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
QualityLevelList.prototype.addQualityLevel = function addQualityLevel(representation) {
|
||||||
|
var qualityLevel = this.getQualityLevelById(representation.id);
|
||||||
|
|
||||||
|
// Do not add duplicate quality levels
|
||||||
|
if (qualityLevel) {
|
||||||
|
return qualityLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = this.levels_.length;
|
||||||
|
|
||||||
|
qualityLevel = new QualityLevel(representation);
|
||||||
|
|
||||||
|
if (!('' + index in this)) {
|
||||||
|
Object.defineProperty(this, index, {
|
||||||
|
get: function get$$1() {
|
||||||
|
return this.levels_[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.levels_.push(qualityLevel);
|
||||||
|
|
||||||
|
this.trigger({
|
||||||
|
qualityLevel: qualityLevel,
|
||||||
|
type: 'addqualitylevel'
|
||||||
|
});
|
||||||
|
|
||||||
|
return qualityLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a quality level from the list.
|
||||||
|
*
|
||||||
|
* @param {QualityLevel} remove QualityLevel to remove to the list.
|
||||||
|
* @return {QualityLevel|null} the QualityLevel removed or null if nothing removed
|
||||||
|
* @method removeQualityLevel
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
QualityLevelList.prototype.removeQualityLevel = function removeQualityLevel(qualityLevel) {
|
||||||
|
var removed = null;
|
||||||
|
|
||||||
|
for (var i = 0, l = this.length; i < l; i++) {
|
||||||
|
if (this[i] === qualityLevel) {
|
||||||
|
removed = this.levels_.splice(i, 1)[0];
|
||||||
|
|
||||||
|
if (this.selectedIndex_ === i) {
|
||||||
|
this.selectedIndex_ = -1;
|
||||||
|
} else if (this.selectedIndex_ > i) {
|
||||||
|
this.selectedIndex_--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed) {
|
||||||
|
this.trigger({
|
||||||
|
qualityLevel: qualityLevel,
|
||||||
|
type: 'removequalitylevel'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for a QualityLevel with the given id.
|
||||||
|
*
|
||||||
|
* @param {string} id The id of the QualityLevel to find.
|
||||||
|
* @return {QualityLevel|null} The QualityLevel with id, or null if not found.
|
||||||
|
* @method getQualityLevelById
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
QualityLevelList.prototype.getQualityLevelById = function getQualityLevelById(id) {
|
||||||
|
for (var i = 0, l = this.length; i < l; i++) {
|
||||||
|
var level = this[i];
|
||||||
|
|
||||||
|
if (level.id === id) {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the list of QualityLevels to empty
|
||||||
|
*
|
||||||
|
* @method dispose
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
QualityLevelList.prototype.dispose = function dispose() {
|
||||||
|
this.selectedIndex_ = -1;
|
||||||
|
this.levels_.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return QualityLevelList;
|
||||||
|
}(videojs.EventTarget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change - The selected QualityLevel has changed.
|
||||||
|
* addqualitylevel - A QualityLevel has been added to the QualityLevelList.
|
||||||
|
* removequalitylevel - A QualityLevel has been removed from the QualityLevelList.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
QualityLevelList.prototype.allowedEvents_ = {
|
||||||
|
change: 'change',
|
||||||
|
addqualitylevel: 'addqualitylevel',
|
||||||
|
removequalitylevel: 'removequalitylevel'
|
||||||
|
};
|
||||||
|
|
||||||
|
// emulate attribute EventHandler support to allow for feature detection
|
||||||
|
for (var event in QualityLevelList.prototype.allowedEvents_) {
|
||||||
|
QualityLevelList.prototype['on' + event] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vjs 5/6 support
|
||||||
|
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization function for the qualityLevels plugin. Sets up the QualityLevelList and
|
||||||
|
* event handlers.
|
||||||
|
*
|
||||||
|
* @param {Player} player Player object.
|
||||||
|
* @param {Object} options Plugin options object.
|
||||||
|
* @function initPlugin
|
||||||
|
*/
|
||||||
|
var initPlugin = function initPlugin(player, options) {
|
||||||
|
var originalPluginFn = player.qualityLevels;
|
||||||
|
|
||||||
|
var qualityLevelList = new QualityLevelList();
|
||||||
|
|
||||||
|
var disposeHandler = function disposeHandler() {
|
||||||
|
qualityLevelList.dispose();
|
||||||
|
player.qualityLevels = originalPluginFn;
|
||||||
|
player.off('dispose', disposeHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
player.on('dispose', disposeHandler);
|
||||||
|
|
||||||
|
player.qualityLevels = function () {
|
||||||
|
return qualityLevelList;
|
||||||
|
};
|
||||||
|
player.qualityLevels.VERSION = '__VERSION__';
|
||||||
|
|
||||||
|
return qualityLevelList;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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"!
|
||||||
|
*
|
||||||
|
* @param {Object} options Plugin options object
|
||||||
|
* @function qualityLevels
|
||||||
|
*/
|
||||||
|
var qualityLevels = function qualityLevels(options) {
|
||||||
|
return initPlugin(this, videojs.mergeOptions({}, options));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register the plugin with video.js.
|
||||||
|
registerPlugin('qualityLevels', qualityLevels);
|
||||||
|
|
||||||
|
// Include the version number.
|
||||||
|
qualityLevels.VERSION = '__VERSION__';
|
||||||
|
|
||||||
|
return qualityLevels;
|
||||||
|
|
||||||
|
})));
|
@ -0,0 +1,455 @@
|
|||||||
|
/*! videojs-contrib-dash - v2.8.2 - 2017-04-26
|
||||||
|
* Copyright (c) 2017 Brightcove */
|
||||||
|
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
|
(function (global){
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = setupAudioTracks;
|
||||||
|
|
||||||
|
var _dashjs = (typeof window !== "undefined" ? window['dashjs'] : typeof global !== "undefined" ? global['dashjs'] : null);
|
||||||
|
|
||||||
|
var _dashjs2 = _interopRequireDefault(_dashjs);
|
||||||
|
|
||||||
|
var _video = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
|
||||||
|
|
||||||
|
var _video2 = _interopRequireDefault(_video);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup audio tracks. Take the tracks from dash and add the tracks to videojs. Listen for when
|
||||||
|
* videojs changes tracks and apply that to the dash player because videojs doesn't do this
|
||||||
|
* natively.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {videojs} player the videojs player instance
|
||||||
|
* @param {videojs.tech} tech the videojs tech being used
|
||||||
|
*/
|
||||||
|
function handlePlaybackMetadataLoaded(player, tech) {
|
||||||
|
var mediaPlayer = player.dash.mediaPlayer;
|
||||||
|
|
||||||
|
var dashAudioTracks = mediaPlayer.getTracksFor('audio');
|
||||||
|
var videojsAudioTracks = player.audioTracks();
|
||||||
|
|
||||||
|
function generateIdFromTrackIndex(index) {
|
||||||
|
return 'dash-audio-' + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDashAudioTrack(dashAudioTracks, videojsAudioTrack) {
|
||||||
|
return dashAudioTracks.find(function (_ref) {
|
||||||
|
var index = _ref.index;
|
||||||
|
return generateIdFromTrackIndex(index) === videojsAudioTrack.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safari creates a single native `AudioTrack` (not `videojs.AudioTrack`) when loading. Clear all
|
||||||
|
// automatically generated audio tracks so we can create them all ourself.
|
||||||
|
if (videojsAudioTracks.length) {
|
||||||
|
tech.clearTracks(['audio']);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentAudioTrack = mediaPlayer.getCurrentTrackFor('audio');
|
||||||
|
|
||||||
|
dashAudioTracks.forEach(function (dashTrack) {
|
||||||
|
var label = dashTrack.lang;
|
||||||
|
|
||||||
|
if (dashTrack.roles && dashTrack.roles.length) {
|
||||||
|
label += ' (' + dashTrack.roles.join(', ') + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the track to the player's audio track list.
|
||||||
|
videojsAudioTracks.addTrack(new _video2.default.AudioTrack({
|
||||||
|
enabled: dashTrack === currentAudioTrack,
|
||||||
|
id: generateIdFromTrackIndex(dashTrack.index),
|
||||||
|
kind: dashTrack.kind || 'main',
|
||||||
|
label: label,
|
||||||
|
language: dashTrack.lang
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
videojsAudioTracks.addEventListener('change', function () {
|
||||||
|
for (var i = 0; i < videojsAudioTracks.length; i++) {
|
||||||
|
var track = videojsAudioTracks[i];
|
||||||
|
|
||||||
|
if (track.enabled) {
|
||||||
|
// Find the audio track we just selected by the id
|
||||||
|
var dashAudioTrack = findDashAudioTrack(dashAudioTracks, track);
|
||||||
|
|
||||||
|
// Set is as the current track
|
||||||
|
mediaPlayer.setCurrentTrack(dashAudioTrack);
|
||||||
|
|
||||||
|
// Stop looping
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call `handlePlaybackMetadataLoaded` when `mediaPlayer` emits
|
||||||
|
* `dashjs.MediaPlayer.events.PLAYBACK_METADATA_LOADED`.
|
||||||
|
*/
|
||||||
|
function setupAudioTracks(player, tech) {
|
||||||
|
// When `dashjs` finishes loading metadata, create audio tracks for `video.js`.
|
||||||
|
player.dash.mediaPlayer.on(_dashjs2.default.MediaPlayer.events.PLAYBACK_METADATA_LOADED, handlePlaybackMetadataLoaded.bind(null, player, tech));
|
||||||
|
}
|
||||||
|
|
||||||
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
|
},{}],2:[function(require,module,exports){
|
||||||
|
(function (global){
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||||
|
|
||||||
|
var _window = require('global/window');
|
||||||
|
|
||||||
|
var _window2 = _interopRequireDefault(_window);
|
||||||
|
|
||||||
|
var _video = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
|
||||||
|
|
||||||
|
var _video2 = _interopRequireDefault(_video);
|
||||||
|
|
||||||
|
var _dashjs = (typeof window !== "undefined" ? window['dashjs'] : typeof global !== "undefined" ? global['dashjs'] : null);
|
||||||
|
|
||||||
|
var _dashjs2 = _interopRequireDefault(_dashjs);
|
||||||
|
|
||||||
|
var _setupAudioTracks = require('./setup-audio-tracks');
|
||||||
|
|
||||||
|
var _setupAudioTracks2 = _interopRequireDefault(_setupAudioTracks);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||||
|
|
||||||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||||
|
|
||||||
|
var isArray = function isArray(a) {
|
||||||
|
return Object.prototype.toString.call(a) === '[object Array]';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* videojs-contrib-dash
|
||||||
|
*
|
||||||
|
* Use Dash.js to playback DASH content inside of Video.js via a SourceHandler
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Html5DashJS = function () {
|
||||||
|
function Html5DashJS(source, tech, options) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
_classCallCheck(this, Html5DashJS);
|
||||||
|
|
||||||
|
// Get options from tech if not provided for backwards compatibility
|
||||||
|
options = options || tech.options_;
|
||||||
|
|
||||||
|
this.player = (0, _video2.default)(options.playerId);
|
||||||
|
this.player.dash = this.player.dash || {};
|
||||||
|
|
||||||
|
this.tech_ = tech;
|
||||||
|
this.el_ = tech.el();
|
||||||
|
this.elParent_ = this.el_.parentNode;
|
||||||
|
|
||||||
|
// Do nothing if the src is falsey
|
||||||
|
if (!source.src) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While the manifest is loading and Dash.js has not finished initializing
|
||||||
|
// we must defer events and functions calls with isReady_ and then `triggerReady`
|
||||||
|
// again later once everything is setup
|
||||||
|
tech.isReady_ = false;
|
||||||
|
|
||||||
|
if (Html5DashJS.updateSourceData) {
|
||||||
|
_video2.default.log.warn('updateSourceData has been deprecated.' + ' Please switch to using hook("updatesource", callback).');
|
||||||
|
source = Html5DashJS.updateSourceData(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call updatesource hooks
|
||||||
|
Html5DashJS.hooks('updatesource').forEach(function (hook) {
|
||||||
|
source = hook(source);
|
||||||
|
});
|
||||||
|
|
||||||
|
var manifestSource = source.src;
|
||||||
|
this.keySystemOptions_ = Html5DashJS.buildDashJSProtData(source.keySystemOptions);
|
||||||
|
|
||||||
|
this.player.dash.mediaPlayer = _dashjs2.default.MediaPlayer().create();
|
||||||
|
|
||||||
|
this.mediaPlayer_ = this.player.dash.mediaPlayer;
|
||||||
|
|
||||||
|
// Log MedaPlayer messages through video.js
|
||||||
|
if (Html5DashJS.useVideoJSDebug) {
|
||||||
|
_video2.default.log.warn('useVideoJSDebug has been deprecated.' + ' Please switch to using hook("beforeinitialize", callback).');
|
||||||
|
Html5DashJS.useVideoJSDebug(this.mediaPlayer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Html5DashJS.beforeInitialize) {
|
||||||
|
_video2.default.log.warn('beforeInitialize has been deprecated.' + ' Please switch to using hook("beforeinitialize", callback).');
|
||||||
|
Html5DashJS.beforeInitialize(this.player, this.mediaPlayer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Html5DashJS.hooks('beforeinitialize').forEach(function (hook) {
|
||||||
|
hook(_this.player, _this.mediaPlayer_);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Must run controller before these two lines or else there is no
|
||||||
|
// element to bind to.
|
||||||
|
this.mediaPlayer_.initialize();
|
||||||
|
|
||||||
|
// Apply all dash options that are set
|
||||||
|
if (options.dash) {
|
||||||
|
Object.keys(options.dash).forEach(function (key) {
|
||||||
|
var _mediaPlayer_;
|
||||||
|
|
||||||
|
var dashOptionsKey = 'set' + key.charAt(0).toUpperCase() + key.slice(1);
|
||||||
|
var value = options.dash[key];
|
||||||
|
|
||||||
|
if (_this.mediaPlayer_.hasOwnProperty(dashOptionsKey)) {
|
||||||
|
// Providing a key without `set` prefix is now deprecated.
|
||||||
|
_video2.default.log.warn('Using dash options in videojs-contrib-dash without the set prefix ' + ('has been deprecated. Change \'' + key + '\' to \'' + dashOptionsKey + '\''));
|
||||||
|
|
||||||
|
// Set key so it will still work
|
||||||
|
key = dashOptionsKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_this.mediaPlayer_.hasOwnProperty(key)) {
|
||||||
|
_video2.default.log.warn('Warning: dash configuration option unrecognized: ' + key);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guarantee `value` is an array
|
||||||
|
if (!isArray(value)) {
|
||||||
|
value = [value];
|
||||||
|
}
|
||||||
|
|
||||||
|
(_mediaPlayer_ = _this.mediaPlayer_)[key].apply(_mediaPlayer_, _toConsumableArray(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mediaPlayer_.attachView(this.el_);
|
||||||
|
|
||||||
|
// Dash.js autoplays by default, video.js will handle autoplay
|
||||||
|
this.mediaPlayer_.setAutoPlay(false);
|
||||||
|
|
||||||
|
// Setup audio tracks
|
||||||
|
_setupAudioTracks2.default.call(null, this.player, tech);
|
||||||
|
|
||||||
|
// Attach the source with any protection data
|
||||||
|
this.mediaPlayer_.setProtectionData(this.keySystemOptions_);
|
||||||
|
this.mediaPlayer_.attachSource(manifestSource);
|
||||||
|
|
||||||
|
this.tech_.triggerReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate over the `keySystemOptions` array and convert each object into
|
||||||
|
* the type of object Dash.js expects in the `protData` argument.
|
||||||
|
*
|
||||||
|
* Also rename 'licenseUrl' property in the options to an 'serverURL' property
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
_createClass(Html5DashJS, [{
|
||||||
|
key: 'dispose',
|
||||||
|
value: function dispose() {
|
||||||
|
if (this.mediaPlayer_) {
|
||||||
|
this.mediaPlayer_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.player.dash) {
|
||||||
|
delete this.player.dash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'duration',
|
||||||
|
value: function duration() {
|
||||||
|
var duration = this.el_.duration;
|
||||||
|
if (duration === Number.MAX_VALUE) {
|
||||||
|
return Infinity;
|
||||||
|
}
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of hooks for a specific lifecycle
|
||||||
|
*
|
||||||
|
* @param {string} type the lifecycle to get hooks from
|
||||||
|
* @param {Function=|Function[]=} hook Optionally add a hook tothe lifecycle
|
||||||
|
* @return {Array} an array of hooks or epty if none
|
||||||
|
* @method hooks
|
||||||
|
*/
|
||||||
|
|
||||||
|
}], [{
|
||||||
|
key: 'buildDashJSProtData',
|
||||||
|
value: function buildDashJSProtData(keySystemOptions) {
|
||||||
|
var output = {};
|
||||||
|
|
||||||
|
if (!keySystemOptions || !isArray(keySystemOptions)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < keySystemOptions.length; i++) {
|
||||||
|
var keySystem = keySystemOptions[i];
|
||||||
|
var options = _video2.default.mergeOptions({}, keySystem.options);
|
||||||
|
|
||||||
|
if (options.licenseUrl) {
|
||||||
|
options.serverURL = options.licenseUrl;
|
||||||
|
delete options.licenseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
output[keySystem.name] = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'hooks',
|
||||||
|
value: function hooks(type, hook) {
|
||||||
|
Html5DashJS.hooks_[type] = Html5DashJS.hooks_[type] || [];
|
||||||
|
|
||||||
|
if (hook) {
|
||||||
|
Html5DashJS.hooks_[type] = Html5DashJS.hooks_[type].concat(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Html5DashJS.hooks_[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a function hook to a specific dash lifecycle
|
||||||
|
*
|
||||||
|
* @param {string} type the lifecycle to hook the function to
|
||||||
|
* @param {Function|Function[]} hook the function or array of functions to attach
|
||||||
|
* @method hook
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'hook',
|
||||||
|
value: function hook(type, _hook) {
|
||||||
|
Html5DashJS.hooks(type, _hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a hook from a specific dash lifecycle.
|
||||||
|
*
|
||||||
|
* @param {string} type the lifecycle that the function hooked to
|
||||||
|
* @param {Function} hook The hooked function to remove
|
||||||
|
* @return {boolean} True if the function was removed, false if not found
|
||||||
|
* @method removeHook
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'removeHook',
|
||||||
|
value: function removeHook(type, hook) {
|
||||||
|
var index = Html5DashJS.hooks(type).indexOf(hook);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Html5DashJS.hooks_[type] = Html5DashJS.hooks_[type].slice();
|
||||||
|
Html5DashJS.hooks_[type].splice(index, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return Html5DashJS;
|
||||||
|
}();
|
||||||
|
|
||||||
|
Html5DashJS.hooks_ = {};
|
||||||
|
|
||||||
|
var canHandleKeySystems = function canHandleKeySystems(source) {
|
||||||
|
// copy the source
|
||||||
|
source = JSON.parse(JSON.stringify(source));
|
||||||
|
|
||||||
|
if (Html5DashJS.updateSourceData) {
|
||||||
|
_video2.default.log.warn('updateSourceData has been deprecated.' + ' Please switch to using hook("updatesource", callback).');
|
||||||
|
source = Html5DashJS.updateSourceData(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call updatesource hooks
|
||||||
|
Html5DashJS.hooks('updatesource').forEach(function (hook) {
|
||||||
|
source = hook(source);
|
||||||
|
});
|
||||||
|
|
||||||
|
var videoEl = document.createElement('video');
|
||||||
|
if (source.keySystemOptions && !(navigator.requestMediaKeySystemAccess ||
|
||||||
|
// IE11 Win 8.1
|
||||||
|
videoEl.msSetMediaKeys)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
_video2.default.DashSourceHandler = function () {
|
||||||
|
return {
|
||||||
|
canHandleSource: function canHandleSource(source) {
|
||||||
|
var dashExtRE = /\.mpd/i;
|
||||||
|
|
||||||
|
if (!canHandleKeySystems(source)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_video2.default.DashSourceHandler.canPlayType(source.type)) {
|
||||||
|
return 'probably';
|
||||||
|
} else if (dashExtRE.test(source.src)) {
|
||||||
|
return 'maybe';
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSource: function handleSource(source, tech, options) {
|
||||||
|
return new Html5DashJS(source, tech, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
canPlayType: function canPlayType(type) {
|
||||||
|
return _video2.default.DashSourceHandler.canPlayType(type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
_video2.default.DashSourceHandler.canPlayType = function (type) {
|
||||||
|
var dashTypeRE = /^application\/dash\+xml/i;
|
||||||
|
if (dashTypeRE.test(type)) {
|
||||||
|
return 'probably';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only add the SourceHandler if the browser supports MediaSourceExtensions
|
||||||
|
if (!!_window2.default.MediaSource) {
|
||||||
|
_video2.default.getTech('Html5').registerSourceHandler(_video2.default.DashSourceHandler(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_video2.default.Html5DashJS = Html5DashJS;
|
||||||
|
exports.default = Html5DashJS;
|
||||||
|
|
||||||
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
|
},{"./setup-audio-tracks":1,"global/window":3}],3:[function(require,module,exports){
|
||||||
|
(function (global){
|
||||||
|
var win;
|
||||||
|
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
win = window;
|
||||||
|
} else if (typeof global !== "undefined") {
|
||||||
|
win = global;
|
||||||
|
} else if (typeof self !== "undefined"){
|
||||||
|
win = self;
|
||||||
|
} else {
|
||||||
|
win = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = win;
|
||||||
|
|
||||||
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||||||
|
},{}]},{},[2]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,517 @@
|
|||||||
|
(function (global, factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
define(['video.js'], factory);
|
||||||
|
} else if (typeof exports !== "undefined") {
|
||||||
|
factory(require('video.js'));
|
||||||
|
} else {
|
||||||
|
var mod = {
|
||||||
|
exports: {}
|
||||||
|
};
|
||||||
|
factory(global.videojs);
|
||||||
|
global.videojsMarkers = mod.exports;
|
||||||
|
}
|
||||||
|
})(this, function (_video) {
|
||||||
|
/*! videojs-markers - v1.0.1 - 2018-02-03
|
||||||
|
* Copyright (c) 2018 ; Licensed */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _video2 = _interopRequireDefault(_video);
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) {
|
||||||
|
return obj && obj.__esModule ? obj : {
|
||||||
|
default: obj
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
||||||
|
return typeof obj;
|
||||||
|
} : function (obj) {
|
||||||
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
// default setting
|
||||||
|
var defaultSetting = {
|
||||||
|
markerStyle: {
|
||||||
|
'width': '7px',
|
||||||
|
'border-radius': '30%',
|
||||||
|
'background-color': 'red'
|
||||||
|
},
|
||||||
|
markerTip: {
|
||||||
|
display: true,
|
||||||
|
text: function text(marker) {
|
||||||
|
return "Break: " + marker.text;
|
||||||
|
},
|
||||||
|
time: function time(marker) {
|
||||||
|
return marker.time;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
breakOverlay: {
|
||||||
|
display: false,
|
||||||
|
displayTime: 3,
|
||||||
|
text: function text(marker) {
|
||||||
|
return "Break overlay: " + marker.overlayText;
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
'width': '100%',
|
||||||
|
'height': '20%',
|
||||||
|
'background-color': 'rgba(0,0,0,0.7)',
|
||||||
|
'color': 'white',
|
||||||
|
'font-size': '17px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMarkerClick: function onMarkerClick(marker) {},
|
||||||
|
onMarkerReached: function onMarkerReached(marker, index) {},
|
||||||
|
markers: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// create a non-colliding random number
|
||||||
|
function generateUUID() {
|
||||||
|
var d = new Date().getTime();
|
||||||
|
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
|
var r = (d + Math.random() * 16) % 16 | 0;
|
||||||
|
d = Math.floor(d / 16);
|
||||||
|
return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);
|
||||||
|
});
|
||||||
|
return uuid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of an element and its position
|
||||||
|
* a default Object with 0 on each of its properties
|
||||||
|
* its return in case there's an error
|
||||||
|
* @param {Element} element el to get the size and position
|
||||||
|
* @return {DOMRect|Object} size and position of an element
|
||||||
|
*/
|
||||||
|
function getElementBounding(element) {
|
||||||
|
var elementBounding;
|
||||||
|
var defaultBoundingRect = {
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
right: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
elementBounding = element.getBoundingClientRect();
|
||||||
|
} catch (e) {
|
||||||
|
elementBounding = defaultBoundingRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elementBounding;
|
||||||
|
}
|
||||||
|
|
||||||
|
var NULL_INDEX = -1;
|
||||||
|
|
||||||
|
function registerVideoJsMarkersPlugin(options) {
|
||||||
|
// copied from video.js/src/js/utils/merge-options.js since
|
||||||
|
// videojs 4 doens't support it by defualt.
|
||||||
|
if (!_video2.default.mergeOptions) {
|
||||||
|
var isPlain = function isPlain(value) {
|
||||||
|
return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && toString.call(value) === '[object Object]' && value.constructor === Object;
|
||||||
|
};
|
||||||
|
|
||||||
|
var mergeOptions = function mergeOptions(source1, source2) {
|
||||||
|
|
||||||
|
var result = {};
|
||||||
|
var sources = [source1, source2];
|
||||||
|
sources.forEach(function (source) {
|
||||||
|
if (!source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object.keys(source).forEach(function (key) {
|
||||||
|
var value = source[key];
|
||||||
|
if (!isPlain(value)) {
|
||||||
|
result[key] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isPlain(result[key])) {
|
||||||
|
result[key] = {};
|
||||||
|
}
|
||||||
|
result[key] = mergeOptions(result[key], value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
_video2.default.mergeOptions = mergeOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_video2.default.createEl) {
|
||||||
|
_video2.default.createEl = function (tagName, props, attrs) {
|
||||||
|
var el = _video2.default.Player.prototype.createEl(tagName, props);
|
||||||
|
if (!!attrs) {
|
||||||
|
Object.keys(attrs).forEach(function (key) {
|
||||||
|
el.setAttribute(key, attrs[key]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register the markers plugin (dependent on jquery)
|
||||||
|
*/
|
||||||
|
var setting = _video2.default.mergeOptions(defaultSetting, options),
|
||||||
|
markersMap = {},
|
||||||
|
markersList = [],
|
||||||
|
// list of markers sorted by time
|
||||||
|
currentMarkerIndex = NULL_INDEX,
|
||||||
|
player = this,
|
||||||
|
markerTip = null,
|
||||||
|
breakOverlay = null,
|
||||||
|
overlayIndex = NULL_INDEX;
|
||||||
|
|
||||||
|
function sortMarkersList() {
|
||||||
|
// sort the list by time in asc order
|
||||||
|
markersList.sort(function (a, b) {
|
||||||
|
return setting.markerTip.time(a) - setting.markerTip.time(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMarkers(newMarkers) {
|
||||||
|
newMarkers.forEach(function (marker) {
|
||||||
|
marker.key = generateUUID();
|
||||||
|
|
||||||
|
player.el().querySelector('.vjs-progress-holder').appendChild(createMarkerDiv(marker));
|
||||||
|
|
||||||
|
// store marker in an internal hash map
|
||||||
|
markersMap[marker.key] = marker;
|
||||||
|
markersList.push(marker);
|
||||||
|
});
|
||||||
|
|
||||||
|
sortMarkersList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPosition(marker) {
|
||||||
|
return setting.markerTip.time(marker) / player.duration() * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMarkderDivStyle(marker, markerDiv) {
|
||||||
|
markerDiv.className = 'vjs-marker ' + (marker.class || "");
|
||||||
|
|
||||||
|
Object.keys(setting.markerStyle).forEach(function (key) {
|
||||||
|
markerDiv.style[key] = setting.markerStyle[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
// hide out-of-bound markers
|
||||||
|
var ratio = marker.time / player.duration();
|
||||||
|
if (ratio < 0 || ratio > 1) {
|
||||||
|
markerDiv.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// set position
|
||||||
|
markerDiv.style.left = getPosition(marker) + '%';
|
||||||
|
if (marker.duration) {
|
||||||
|
markerDiv.style.width = marker.duration / player.duration() * 100 + '%';
|
||||||
|
markerDiv.style.marginLeft = '0px';
|
||||||
|
} else {
|
||||||
|
var markerDivBounding = getElementBounding(markerDiv);
|
||||||
|
markerDiv.style.marginLeft = markerDivBounding.width / 2 + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMarkerDiv(marker) {
|
||||||
|
|
||||||
|
var markerDiv = _video2.default.createEl('div', {}, {
|
||||||
|
'data-marker-key': marker.key,
|
||||||
|
'data-marker-time': setting.markerTip.time(marker)
|
||||||
|
});
|
||||||
|
|
||||||
|
setMarkderDivStyle(marker, markerDiv);
|
||||||
|
|
||||||
|
// bind click event to seek to marker time
|
||||||
|
markerDiv.addEventListener('click', function (e) {
|
||||||
|
var preventDefault = false;
|
||||||
|
if (typeof setting.onMarkerClick === "function") {
|
||||||
|
// if return false, prevent default behavior
|
||||||
|
preventDefault = setting.onMarkerClick(marker) === false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preventDefault) {
|
||||||
|
var key = this.getAttribute('data-marker-key');
|
||||||
|
player.currentTime(setting.markerTip.time(markersMap[key]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (setting.markerTip.display) {
|
||||||
|
registerMarkerTipHandler(markerDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return markerDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMarkers(force) {
|
||||||
|
// update UI for markers whose time changed
|
||||||
|
markersList.forEach(function (marker) {
|
||||||
|
var markerDiv = player.el().querySelector(".vjs-marker[data-marker-key='" + marker.key + "']");
|
||||||
|
var markerTime = setting.markerTip.time(marker);
|
||||||
|
|
||||||
|
if (force || markerDiv.getAttribute('data-marker-time') !== markerTime) {
|
||||||
|
setMarkderDivStyle(marker, markerDiv);
|
||||||
|
markerDiv.setAttribute('data-marker-time', markerTime);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sortMarkersList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMarkers(indexArray) {
|
||||||
|
// reset overlay
|
||||||
|
if (!!breakOverlay) {
|
||||||
|
overlayIndex = NULL_INDEX;
|
||||||
|
breakOverlay.style.visibility = "hidden";
|
||||||
|
}
|
||||||
|
currentMarkerIndex = NULL_INDEX;
|
||||||
|
|
||||||
|
var deleteIndexList = [];
|
||||||
|
indexArray.forEach(function (index) {
|
||||||
|
var marker = markersList[index];
|
||||||
|
if (marker) {
|
||||||
|
// delete from memory
|
||||||
|
delete markersMap[marker.key];
|
||||||
|
deleteIndexList.push(index);
|
||||||
|
|
||||||
|
// delete from dom
|
||||||
|
var el = player.el().querySelector(".vjs-marker[data-marker-key='" + marker.key + "']");
|
||||||
|
el && el.parentNode.removeChild(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clean up markers array
|
||||||
|
deleteIndexList.reverse();
|
||||||
|
deleteIndexList.forEach(function (deleteIndex) {
|
||||||
|
markersList.splice(deleteIndex, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sort again
|
||||||
|
sortMarkersList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach hover event handler
|
||||||
|
function registerMarkerTipHandler(markerDiv) {
|
||||||
|
markerDiv.addEventListener('mouseover', function () {
|
||||||
|
var marker = markersMap[markerDiv.getAttribute('data-marker-key')];
|
||||||
|
if (!!markerTip) {
|
||||||
|
markerTip.querySelector('.vjs-tip-inner').innerText = setting.markerTip.text(marker);
|
||||||
|
// margin-left needs to minus the padding length to align correctly with the marker
|
||||||
|
markerTip.style.left = getPosition(marker) + '%';
|
||||||
|
var markerTipBounding = getElementBounding(markerTip);
|
||||||
|
var markerDivBounding = getElementBounding(markerDiv);
|
||||||
|
markerTip.style.marginLeft = -parseFloat(markerTipBounding.width / 2) + parseFloat(markerDivBounding.width / 4) + 'px';
|
||||||
|
markerTip.style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
markerDiv.addEventListener('mouseout', function () {
|
||||||
|
if (!!markerTip) {
|
||||||
|
markerTip.style.visibility = "hidden";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeMarkerTip() {
|
||||||
|
markerTip = _video2.default.createEl('div', {
|
||||||
|
className: 'vjs-tip',
|
||||||
|
innerHTML: "<div class='vjs-tip-arrow'></div><div class='vjs-tip-inner'></div>"
|
||||||
|
});
|
||||||
|
player.el().querySelector('.vjs-progress-holder').appendChild(markerTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// show or hide break overlays
|
||||||
|
function updateBreakOverlay() {
|
||||||
|
if (!setting.breakOverlay.display || currentMarkerIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTime = player.currentTime();
|
||||||
|
var marker = markersList[currentMarkerIndex];
|
||||||
|
var markerTime = setting.markerTip.time(marker);
|
||||||
|
|
||||||
|
if (currentTime >= markerTime && currentTime <= markerTime + setting.breakOverlay.displayTime) {
|
||||||
|
if (overlayIndex !== currentMarkerIndex) {
|
||||||
|
overlayIndex = currentMarkerIndex;
|
||||||
|
if (breakOverlay) {
|
||||||
|
breakOverlay.querySelector('.vjs-break-overlay-text').innerHTML = setting.breakOverlay.text(marker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakOverlay) {
|
||||||
|
breakOverlay.style.visibility = "visible";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
overlayIndex = NULL_INDEX;
|
||||||
|
if (breakOverlay) {
|
||||||
|
breakOverlay.style.visibility = "hidden";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// problem when the next marker is within the overlay display time from the previous marker
|
||||||
|
function initializeOverlay() {
|
||||||
|
breakOverlay = _video2.default.createEl('div', {
|
||||||
|
className: 'vjs-break-overlay',
|
||||||
|
innerHTML: "<div class='vjs-break-overlay-text'></div>"
|
||||||
|
});
|
||||||
|
Object.keys(setting.breakOverlay.style).forEach(function (key) {
|
||||||
|
if (breakOverlay) {
|
||||||
|
breakOverlay.style[key] = setting.breakOverlay.style[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.el().appendChild(breakOverlay);
|
||||||
|
overlayIndex = NULL_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeUpdate() {
|
||||||
|
onUpdateMarker();
|
||||||
|
updateBreakOverlay();
|
||||||
|
options.onTimeUpdateAfterMarkerUpdate && options.onTimeUpdateAfterMarkerUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUpdateMarker() {
|
||||||
|
/*
|
||||||
|
check marker reached in between markers
|
||||||
|
the logic here is that it triggers a new marker reached event only if the player
|
||||||
|
enters a new marker range (e.g. from marker 1 to marker 2). Thus, if player is on marker 1 and user clicked on marker 1 again, no new reached event is triggered)
|
||||||
|
*/
|
||||||
|
if (!markersList.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var getNextMarkerTime = function getNextMarkerTime(index) {
|
||||||
|
if (index < markersList.length - 1) {
|
||||||
|
return setting.markerTip.time(markersList[index + 1]);
|
||||||
|
}
|
||||||
|
// next marker time of last marker would be end of video time
|
||||||
|
return player.duration();
|
||||||
|
};
|
||||||
|
var currentTime = player.currentTime();
|
||||||
|
var newMarkerIndex = NULL_INDEX;
|
||||||
|
|
||||||
|
if (currentMarkerIndex !== NULL_INDEX) {
|
||||||
|
// check if staying at same marker
|
||||||
|
var nextMarkerTime = getNextMarkerTime(currentMarkerIndex);
|
||||||
|
if (currentTime >= setting.markerTip.time(markersList[currentMarkerIndex]) && currentTime < nextMarkerTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for ending (at the end current time equals player duration)
|
||||||
|
if (currentMarkerIndex === markersList.length - 1 && currentTime === player.duration()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check first marker, no marker is selected
|
||||||
|
if (currentTime < setting.markerTip.time(markersList[0])) {
|
||||||
|
newMarkerIndex = NULL_INDEX;
|
||||||
|
} else {
|
||||||
|
// look for new index
|
||||||
|
for (var i = 0; i < markersList.length; i++) {
|
||||||
|
nextMarkerTime = getNextMarkerTime(i);
|
||||||
|
if (currentTime >= setting.markerTip.time(markersList[i]) && currentTime < nextMarkerTime) {
|
||||||
|
newMarkerIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new marker index
|
||||||
|
if (newMarkerIndex !== currentMarkerIndex) {
|
||||||
|
// trigger event if index is not null
|
||||||
|
if (newMarkerIndex !== NULL_INDEX && options.onMarkerReached) {
|
||||||
|
options.onMarkerReached(markersList[newMarkerIndex], newMarkerIndex);
|
||||||
|
}
|
||||||
|
currentMarkerIndex = newMarkerIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the whole thing
|
||||||
|
function initialize() {
|
||||||
|
if (setting.markerTip.display) {
|
||||||
|
initializeMarkerTip();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove existing markers if already initialized
|
||||||
|
player.markers.removeAll();
|
||||||
|
addMarkers(setting.markers);
|
||||||
|
|
||||||
|
if (setting.breakOverlay.display) {
|
||||||
|
initializeOverlay();
|
||||||
|
}
|
||||||
|
onTimeUpdate();
|
||||||
|
player.on("timeupdate", onTimeUpdate);
|
||||||
|
player.off("loadedmetadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the plugin after we loaded video's meta data
|
||||||
|
player.on("loadedmetadata", function () {
|
||||||
|
initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// exposed plugin API
|
||||||
|
player.markers = {
|
||||||
|
getMarkers: function getMarkers() {
|
||||||
|
return markersList;
|
||||||
|
},
|
||||||
|
next: function next() {
|
||||||
|
// go to the next marker from current timestamp
|
||||||
|
var currentTime = player.currentTime();
|
||||||
|
for (var i = 0; i < markersList.length; i++) {
|
||||||
|
var markerTime = setting.markerTip.time(markersList[i]);
|
||||||
|
if (markerTime > currentTime) {
|
||||||
|
player.currentTime(markerTime);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prev: function prev() {
|
||||||
|
// go to previous marker
|
||||||
|
var currentTime = player.currentTime();
|
||||||
|
for (var i = markersList.length - 1; i >= 0; i--) {
|
||||||
|
var markerTime = setting.markerTip.time(markersList[i]);
|
||||||
|
// add a threshold
|
||||||
|
if (markerTime + 0.5 < currentTime) {
|
||||||
|
player.currentTime(markerTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
add: function add(newMarkers) {
|
||||||
|
// add new markers given an array of index
|
||||||
|
addMarkers(newMarkers);
|
||||||
|
},
|
||||||
|
remove: function remove(indexArray) {
|
||||||
|
// remove markers given an array of index
|
||||||
|
removeMarkers(indexArray);
|
||||||
|
},
|
||||||
|
removeAll: function removeAll() {
|
||||||
|
var indexArray = [];
|
||||||
|
for (var i = 0; i < markersList.length; i++) {
|
||||||
|
indexArray.push(i);
|
||||||
|
}
|
||||||
|
removeMarkers(indexArray);
|
||||||
|
},
|
||||||
|
// force - force all markers to be updated, regardless of if they have changed or not.
|
||||||
|
updateTime: function updateTime(force) {
|
||||||
|
// notify the plugin to update the UI for changes in marker times
|
||||||
|
updateMarkers(force);
|
||||||
|
},
|
||||||
|
reset: function reset(newMarkers) {
|
||||||
|
// remove all the existing markers and add new ones
|
||||||
|
player.markers.removeAll();
|
||||||
|
addMarkers(newMarkers);
|
||||||
|
},
|
||||||
|
destroy: function destroy() {
|
||||||
|
// unregister the plugins and clean up even handlers
|
||||||
|
player.markers.removeAll();
|
||||||
|
breakOverlay && breakOverlay.remove();
|
||||||
|
markerTip && markerTip.remove();
|
||||||
|
player.off("timeupdate", updateBreakOverlay);
|
||||||
|
delete player.markers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_video2.default.plugin('markers', registerVideoJsMarkersPlugin);
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=videojs-markers.js.map
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* Video.js Hotkeys
|
||||||
|
* https://github.com/ctd1500/videojs-hotkeys
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Chris Dougherty
|
||||||
|
* Licensed under the Apache-2.0 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
;(function(root, factory) {
|
||||||
|
if (typeof window !== 'undefined' && window.videojs) {
|
||||||
|
factory(window.videojs);
|
||||||
|
} else if (typeof define === 'function' && define.amd) {
|
||||||
|
define('videojs-hotkeys', ['video.js'], function (module) {
|
||||||
|
return factory(module.default || module);
|
||||||
|
});
|
||||||
|
} else if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
module.exports = factory(require('video.js'));
|
||||||
|
}
|
||||||
|
}(this, function (videojs) {
|
||||||
|
"use strict";
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window['videojs_hotkeys'] = { version: "0.2.22" };
|
||||||
|
}
|
||||||
|
|
||||||
|
var hotkeys = function(options) {
|
||||||
|
var player = this;
|
||||||
|
var pEl = player.el();
|
||||||
|
var doc = document;
|
||||||
|
var def_options = {
|
||||||
|
volumeStep: 0.1,
|
||||||
|
seekStep: 5,
|
||||||
|
enableMute: true,
|
||||||
|
enableVolumeScroll: true,
|
||||||
|
enableHoverScroll: true,
|
||||||
|
enableFullscreen: true,
|
||||||
|
enableNumbers: true,
|
||||||
|
enableJogStyle: false,
|
||||||
|
alwaysCaptureHotkeys: false,
|
||||||
|
enableModifiersForNumbers: true,
|
||||||
|
enableInactiveFocus: true,
|
||||||
|
skipInitialFocus: false,
|
||||||
|
playPauseKey: playPauseKey,
|
||||||
|
rewindKey: rewindKey,
|
||||||
|
forwardKey: forwardKey,
|
||||||
|
volumeUpKey: volumeUpKey,
|
||||||
|
volumeDownKey: volumeDownKey,
|
||||||
|
muteKey: muteKey,
|
||||||
|
fullscreenKey: fullscreenKey,
|
||||||
|
customKeys: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var cPlay = 1,
|
||||||
|
cRewind = 2,
|
||||||
|
cForward = 3,
|
||||||
|
cVolumeUp = 4,
|
||||||
|
cVolumeDown = 5,
|
||||||
|
cMute = 6,
|
||||||
|
cFullscreen = 7;
|
||||||
|
|
||||||
|
// Use built-in merge function from Video.js v5.0+ or v4.4.0+
|
||||||
|
var mergeOptions = videojs.mergeOptions || videojs.util.mergeOptions;
|
||||||
|
options = mergeOptions(def_options, options || {});
|
||||||
|
|
||||||
|
var volumeStep = options.volumeStep,
|
||||||
|
seekStep = options.seekStep,
|
||||||
|
enableMute = options.enableMute,
|
||||||
|
enableVolumeScroll = options.enableVolumeScroll,
|
||||||
|
enableHoverScroll = options.enableHoverScroll,
|
||||||
|
enableFull = options.enableFullscreen,
|
||||||
|
enableNumbers = options.enableNumbers,
|
||||||
|
enableJogStyle = options.enableJogStyle,
|
||||||
|
alwaysCaptureHotkeys = options.alwaysCaptureHotkeys,
|
||||||
|
enableModifiersForNumbers = options.enableModifiersForNumbers,
|
||||||
|
enableInactiveFocus = options.enableInactiveFocus,
|
||||||
|
skipInitialFocus = options.skipInitialFocus;
|
||||||
|
|
||||||
|
// Set default player tabindex to handle keydown and doubleclick events
|
||||||
|
if (!pEl.hasAttribute('tabIndex')) {
|
||||||
|
pEl.setAttribute('tabIndex', '-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove player outline to fix video performance issue
|
||||||
|
pEl.style.outline = "none";
|
||||||
|
|
||||||
|
if (alwaysCaptureHotkeys || !player.autoplay()) {
|
||||||
|
if (!skipInitialFocus) {
|
||||||
|
player.one('play', function() {
|
||||||
|
pEl.focus(); // Fixes the .vjs-big-play-button handing focus back to body instead of the player
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableInactiveFocus) {
|
||||||
|
player.on('userinactive', function() {
|
||||||
|
// When the control bar fades, re-apply focus to the player if last focus was a control button
|
||||||
|
var cancelFocusingPlayer = function() {
|
||||||
|
clearTimeout(focusingPlayerTimeout);
|
||||||
|
};
|
||||||
|
var focusingPlayerTimeout = setTimeout(function() {
|
||||||
|
player.off('useractive', cancelFocusingPlayer);
|
||||||
|
var activeElement = doc.activeElement;
|
||||||
|
var controlBar = pEl.querySelector('.vjs-control-bar');
|
||||||
|
if (activeElement && activeElement.parentElement == controlBar) {
|
||||||
|
pEl.focus();
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
player.one('useractive', cancelFocusingPlayer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
player.on('play', function() {
|
||||||
|
// Fix allowing the YouTube plugin to have hotkey support.
|
||||||
|
var ifblocker = pEl.querySelector('.iframeblocker');
|
||||||
|
if (ifblocker && ifblocker.style.display === '') {
|
||||||
|
ifblocker.style.display = "block";
|
||||||
|
ifblocker.style.bottom = "39px";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var keyDown = function keyDown(event) {
|
||||||
|
var ewhich = event.which, wasPlaying, seekTime;
|
||||||
|
var ePreventDefault = event.preventDefault;
|
||||||
|
var duration = player.duration();
|
||||||
|
// When controls are disabled, hotkeys will be disabled as well
|
||||||
|
if (player.controls()) {
|
||||||
|
|
||||||
|
// Don't catch keys if any control buttons are focused, unless alwaysCaptureHotkeys is true
|
||||||
|
var activeEl = doc.activeElement;
|
||||||
|
if (alwaysCaptureHotkeys ||
|
||||||
|
activeEl == pEl ||
|
||||||
|
activeEl == pEl.querySelector('.vjs-tech') ||
|
||||||
|
activeEl == pEl.querySelector('.vjs-control-bar') ||
|
||||||
|
activeEl == pEl.querySelector('.iframeblocker')) {
|
||||||
|
|
||||||
|
switch (checkKeys(event, player)) {
|
||||||
|
// Spacebar toggles play/pause
|
||||||
|
case cPlay:
|
||||||
|
ePreventDefault();
|
||||||
|
if (alwaysCaptureHotkeys) {
|
||||||
|
// Prevent control activation with space
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.paused()) {
|
||||||
|
player.play();
|
||||||
|
} else {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Seeking with the left/right arrow keys
|
||||||
|
case cRewind: // Seek Backward
|
||||||
|
wasPlaying = !player.paused();
|
||||||
|
ePreventDefault();
|
||||||
|
if (wasPlaying) {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
|
seekTime = player.currentTime() - seekStepD(event);
|
||||||
|
// The flash player tech will allow you to seek into negative
|
||||||
|
// numbers and break the seekbar, so try to prevent that.
|
||||||
|
if (seekTime <= 0) {
|
||||||
|
seekTime = 0;
|
||||||
|
}
|
||||||
|
player.currentTime(seekTime);
|
||||||
|
if (wasPlaying) {
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case cForward: // Seek Forward
|
||||||
|
wasPlaying = !player.paused();
|
||||||
|
ePreventDefault();
|
||||||
|
if (wasPlaying) {
|
||||||
|
player.pause();
|
||||||
|
}
|
||||||
|
seekTime = player.currentTime() + seekStepD(event);
|
||||||
|
// Fixes the player not sending the end event if you
|
||||||
|
// try to seek past the duration on the seekbar.
|
||||||
|
if (seekTime >= duration) {
|
||||||
|
seekTime = wasPlaying ? duration - .001 : duration;
|
||||||
|
}
|
||||||
|
player.currentTime(seekTime);
|
||||||
|
if (wasPlaying) {
|
||||||
|
player.play();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Volume control with the up/down arrow keys
|
||||||
|
case cVolumeDown:
|
||||||
|
ePreventDefault();
|
||||||
|
if (!enableJogStyle) {
|
||||||
|
player.volume(player.volume() - volumeStep);
|
||||||
|
} else {
|
||||||
|
seekTime = player.currentTime() - 1;
|
||||||
|
if (player.currentTime() <= 1) {
|
||||||
|
seekTime = 0;
|
||||||
|
}
|
||||||
|
player.currentTime(seekTime);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case cVolumeUp:
|
||||||
|
ePreventDefault();
|
||||||
|
if (!enableJogStyle) {
|
||||||
|
player.volume(player.volume() + volumeStep);
|
||||||
|
} else {
|
||||||
|
seekTime = player.currentTime() + 1;
|
||||||
|
if (seekTime >= duration) {
|
||||||
|
seekTime = duration;
|
||||||
|
}
|
||||||
|
player.currentTime(seekTime);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Mute with the M key
|
||||||
|
case cMute:
|
||||||
|
if (enableMute) {
|
||||||
|
player.muted(!player.muted());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Fullscreen with the F key
|
||||||
|
case cFullscreen:
|
||||||
|
if (enableFull) {
|
||||||
|
if (player.isFullscreen()) {
|
||||||
|
player.exitFullscreen();
|
||||||
|
} else {
|
||||||
|
player.requestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Number keys from 0-9 skip to a percentage of the video. 0 is 0% and 9 is 90%
|
||||||
|
if ((ewhich > 47 && ewhich < 59) || (ewhich > 95 && ewhich < 106)) {
|
||||||
|
// Do not handle if enableModifiersForNumbers set to false and keys are Ctrl, Cmd or Alt
|
||||||
|
if (enableModifiersForNumbers || !(event.metaKey || event.ctrlKey || event.altKey)) {
|
||||||
|
if (enableNumbers) {
|
||||||
|
var sub = 48;
|
||||||
|
if (ewhich > 95) {
|
||||||
|
sub = 96;
|
||||||
|
}
|
||||||
|
var number = ewhich - sub;
|
||||||
|
ePreventDefault();
|
||||||
|
player.currentTime(player.duration() * number * 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any custom hotkeys
|
||||||
|
for (var customKey in options.customKeys) {
|
||||||
|
var customHotkey = options.customKeys[customKey];
|
||||||
|
// Check for well formed custom keys
|
||||||
|
if (customHotkey && customHotkey.key && customHotkey.handler) {
|
||||||
|
// Check if the custom key's condition matches
|
||||||
|
if (customHotkey.key(event)) {
|
||||||
|
ePreventDefault();
|
||||||
|
customHotkey.handler(player, options, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var doubleClick = function doubleClick(event) {
|
||||||
|
// When controls are disabled, hotkeys will be disabled as well
|
||||||
|
if (player.controls()) {
|
||||||
|
|
||||||
|
// Don't catch clicks if any control buttons are focused
|
||||||
|
var activeEl = event.relatedTarget || event.toElement || doc.activeElement;
|
||||||
|
if (activeEl == pEl ||
|
||||||
|
activeEl == pEl.querySelector('.vjs-tech') ||
|
||||||
|
activeEl == pEl.querySelector('.iframeblocker')) {
|
||||||
|
|
||||||
|
if (enableFull) {
|
||||||
|
if (player.isFullscreen()) {
|
||||||
|
player.exitFullscreen();
|
||||||
|
} else {
|
||||||
|
player.requestFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var volumeHover = false;
|
||||||
|
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
|
||||||
|
volumeSelector.onmouseover = function() { volumeHover = true; }
|
||||||
|
volumeSelector.onmouseout = function() { volumeHover = false; }
|
||||||
|
|
||||||
|
var mouseScroll = function mouseScroll(event) {
|
||||||
|
if (enableHoverScroll) {
|
||||||
|
// If we leave this undefined then it can match non-existent elements below
|
||||||
|
var activeEl = 0;
|
||||||
|
} else {
|
||||||
|
var activeEl = doc.activeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When controls are disabled, hotkeys will be disabled as well
|
||||||
|
if (player.controls()) {
|
||||||
|
if (alwaysCaptureHotkeys ||
|
||||||
|
activeEl == pEl ||
|
||||||
|
activeEl == pEl.querySelector('.vjs-tech') ||
|
||||||
|
activeEl == pEl.querySelector('.iframeblocker') ||
|
||||||
|
activeEl == pEl.querySelector('.vjs-control-bar') ||
|
||||||
|
volumeHover) {
|
||||||
|
|
||||||
|
if (enableVolumeScroll) {
|
||||||
|
event = window.event || event;
|
||||||
|
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (delta == 1) {
|
||||||
|
player.volume(player.volume() + volumeStep);
|
||||||
|
} else if (delta == -1) {
|
||||||
|
player.volume(player.volume() - volumeStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkKeys = function checkKeys(e, player) {
|
||||||
|
// Allow some modularity in defining custom hotkeys
|
||||||
|
|
||||||
|
// Play/Pause check
|
||||||
|
if (options.playPauseKey(e, player)) {
|
||||||
|
return cPlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek Backward check
|
||||||
|
if (options.rewindKey(e, player)) {
|
||||||
|
return cRewind;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek Forward check
|
||||||
|
if (options.forwardKey(e, player)) {
|
||||||
|
return cForward;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume Up check
|
||||||
|
if (options.volumeUpKey(e, player)) {
|
||||||
|
return cVolumeUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume Down check
|
||||||
|
if (options.volumeDownKey(e, player)) {
|
||||||
|
return cVolumeDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mute check
|
||||||
|
if (options.muteKey(e, player)) {
|
||||||
|
return cMute;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fullscreen check
|
||||||
|
if (options.fullscreenKey(e, player)) {
|
||||||
|
return cFullscreen;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function playPauseKey(e) {
|
||||||
|
// Space bar or MediaPlayPause
|
||||||
|
return (e.which === 32 || e.which === 179);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewindKey(e) {
|
||||||
|
// Left Arrow or MediaRewind
|
||||||
|
return (e.which === 37 || e.which === 177);
|
||||||
|
}
|
||||||
|
|
||||||
|
function forwardKey(e) {
|
||||||
|
// Right Arrow or MediaForward
|
||||||
|
return (e.which === 39 || e.which === 176);
|
||||||
|
}
|
||||||
|
|
||||||
|
function volumeUpKey(e) {
|
||||||
|
// Up Arrow
|
||||||
|
return (e.which === 38);
|
||||||
|
}
|
||||||
|
|
||||||
|
function volumeDownKey(e) {
|
||||||
|
// Down Arrow
|
||||||
|
return (e.which === 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
function muteKey(e) {
|
||||||
|
// M key
|
||||||
|
return (e.which === 77);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fullscreenKey(e) {
|
||||||
|
// F key
|
||||||
|
return (e.which === 70);
|
||||||
|
}
|
||||||
|
|
||||||
|
function seekStepD(e) {
|
||||||
|
// SeekStep caller, returns an int, or a function returning an int
|
||||||
|
return (typeof seekStep === "function" ? seekStep(e) : seekStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.on('keydown', keyDown);
|
||||||
|
player.on('dblclick', doubleClick);
|
||||||
|
player.on('mousewheel', mouseScroll);
|
||||||
|
player.on("DOMMouseScroll", mouseScroll);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
||||||
|
registerPlugin('hotkeys', hotkeys);
|
||||||
|
}));
|
@ -0,0 +1,153 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>JavaScript license information</h1>
|
||||||
|
<table id="jslicense-labels1">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/dash.mediaplayer.min.js">dash.mediaplayer.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://directory.fsf.org/wiki/License:BSD_3Clause">Modified-BSD</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/dash.mediaplayer.debug.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/silvermine-videojs-quality-selector.min.js">silvermine-videojs-quality-selector.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.jclark.com/xml/copying.txt">Expat</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/silvermine-videojs-quality-selector.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/video.min.js">video.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache-2.0-only</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/video.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-contrib-quality-levels.min.js">videojs-contrib-quality-levels.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache-2.0-only</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-contrib-quality-levels.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-dash.min.js">videojs-dash.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache-2.0-only</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-dash.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-http-streaming.min.js">videojs-http-streaming.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache-2.0-only</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-http-streaming.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-markers.min.js">videojs-markers.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.jclark.com/xml/copying.txt">Expat</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-markers.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-share.min.js">videojs-share.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.jclark.com/xml/copying.txt">Expat</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs-share.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs.hotkeys.min.js">videojs.hotkeys.min.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache-2.0-only</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/videojs.hotkeys.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/js/watch.js">watch.js</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="https://www.gnu.org/licenses/agpl-3.0.html">GNU-AGPL-3.0-or-later</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<a href="/js/watch.js">source</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue