Merge pull request #869 from edx/valera/video_js_console_log_useful_debug_info
Adding debugging messages for Video player.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* @file Initialize module works with the JSON config, and sets up various settings, parameters,
|
||||
* variables. After all setup actions are performed, it invokes the video player to play the
|
||||
* specified video. This module must be invoked first. It provides several functions which do not
|
||||
* fit in with other modules.
|
||||
* @file Initialize module works with the JSON config, and sets up various
|
||||
* settings, parameters, variables. After all setup actions are performed, it
|
||||
* invokes the video player to play the specified video. This module must be
|
||||
* invoked first. It provides several functions which do not fit in with other
|
||||
* modules.
|
||||
*
|
||||
* @external VideoPlayer
|
||||
*
|
||||
@@ -16,8 +17,17 @@ define(
|
||||
['video/03_video_player.js'],
|
||||
function (VideoPlayer) {
|
||||
|
||||
if (typeof(window.gettext) == "undefined") {
|
||||
window.gettext = function(s){return s;};
|
||||
// window.console.log() is expected to be available. We do not support
|
||||
// browsers which lack this functionality.
|
||||
|
||||
// The function gettext() is defined by a vendor library. If, however, it
|
||||
// is undefined, it is a simple wrapper. It is used to return a different
|
||||
// version of the string passed (translated string, etc.). In the basic
|
||||
// case, the original string is returned.
|
||||
if (typeof(window.gettext) == 'undefined') {
|
||||
window.gettext = function (s) {
|
||||
return s;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,43 +60,54 @@ function (VideoPlayer) {
|
||||
* methods, modules) of the Video player.
|
||||
*/
|
||||
function _makeFunctionsPublic(state) {
|
||||
state.setSpeed = _.bind(setSpeed, state);
|
||||
state.youtubeId = _.bind(youtubeId, state);
|
||||
state.getDuration = _.bind(getDuration, state);
|
||||
state.trigger = _.bind(trigger, state);
|
||||
state.setSpeed = _.bind(setSpeed, state);
|
||||
state.youtubeId = _.bind(youtubeId, state);
|
||||
state.getDuration = _.bind(getDuration, state);
|
||||
state.trigger = _.bind(trigger, state);
|
||||
state.stopBuffering = _.bind(stopBuffering, state);
|
||||
|
||||
// Old private functions. Now also public so that can be
|
||||
// tested by Jasmine.
|
||||
|
||||
state.initialize = _.bind(initialize, state);
|
||||
state.parseSpeed = _.bind(parseSpeed, state);
|
||||
state.fetchMetadata = _.bind(fetchMetadata, state);
|
||||
state.initialize = _.bind(initialize, state);
|
||||
state.parseSpeed = _.bind(parseSpeed, state);
|
||||
state.fetchMetadata = _.bind(fetchMetadata, state);
|
||||
state.parseYoutubeStreams = _.bind(parseYoutubeStreams, state);
|
||||
state.parseVideoSources = _.bind(parseVideoSources, state);
|
||||
state.getVideoMetadata = _.bind(getVideoMetadata, state);
|
||||
state.parseVideoSources = _.bind(parseVideoSources, state);
|
||||
state.getVideoMetadata = _.bind(getVideoMetadata, state);
|
||||
}
|
||||
|
||||
// function _renderElements(state)
|
||||
//
|
||||
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
|
||||
// make the created DOM elements available via the 'state' object. Much easier to work this
|
||||
// way - you don't have to do repeated jQuery element selects.
|
||||
// Create any necessary DOM elements, attach them, and set their
|
||||
// initial configuration. Also make the created DOM elements available
|
||||
// via the 'state' object. Much easier to work this way - you don't
|
||||
// have to do repeated jQuery element selects.
|
||||
function _renderElements(state) {
|
||||
// Launch embedding of actual video content, or set it up so that it will be done as soon as the
|
||||
// appropriate video player (YouTube or stand alone HTML5) is loaded, and can handle embedding.
|
||||
// Launch embedding of actual video content, or set it up so that it
|
||||
// will be done as soon as the appropriate video player (YouTube or
|
||||
// stand-alone HTML5) is loaded, and can handle embedding.
|
||||
//
|
||||
// Note that the loading of stand alone HTML5 player API is handled by Require JS. At the time
|
||||
// when we reach this code, the stand alone HTML5 player is already loaded, so no further testing
|
||||
// in that case is required.
|
||||
// Note that the loading of stand alone HTML5 player API is handled by
|
||||
// Require JS. At the time when we reach this code, the stand alone
|
||||
// HTML5 player is already loaded, so no further testing in that case
|
||||
// is required.
|
||||
var onPlayerReadyFunc;
|
||||
if (
|
||||
((state.videoType === 'youtube') && (window.YT) && (window.YT.Player)) ||
|
||||
(
|
||||
(state.videoType === 'youtube') &&
|
||||
(window.YT) &&
|
||||
(window.YT.Player)
|
||||
) ||
|
||||
(state.videoType === 'html5')
|
||||
) {
|
||||
VideoPlayer(state);
|
||||
} else {
|
||||
onPlayerReadyFunc = (state.videoType === 'youtube') ? 'onYouTubePlayerAPIReady' : 'onHTML5PlayerAPIReady';
|
||||
if (state.videoType === 'youtube') {
|
||||
onPlayerReadyFunc = 'onYouTubePlayerAPIReady';
|
||||
} else {
|
||||
onPlayerReadyFunc = 'onHTML5PlayerAPIReady';
|
||||
}
|
||||
window[onPlayerReadyFunc] = _.bind(VideoPlayer, window, state);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +123,8 @@ function (VideoPlayer) {
|
||||
// Option
|
||||
// this.hide_captions = true | false
|
||||
//
|
||||
// represents the user's choice of having the subtitles shown or hidden. This choice is stored in cookies.
|
||||
// represents the user's choice of having the subtitles shown or
|
||||
// hidden. This choice is stored in cookies.
|
||||
function _configureCaptions(state) {
|
||||
if (state.config.show_captions) {
|
||||
state.hide_captions = ($.cookie('hide_captions') === 'true');
|
||||
@@ -119,14 +141,19 @@ function (VideoPlayer) {
|
||||
}
|
||||
|
||||
// function _setPlayerMode(state)
|
||||
// By default we will be forcing HTML5 player mode. Only in the case when, after initializtion, we will
|
||||
// get one available playback rate, we will change to Flash player mode. There is a need to store this
|
||||
// setting in cookies because otherwise we will have to change from HTML5 to Flash on every page load
|
||||
// in a browser that doesn't fully support HTML5. When we have this setting in cookies, we can select
|
||||
// By default we will be forcing HTML5 player mode. Only in the case
|
||||
// when, after initializtion, we will get one available playback rate,
|
||||
// we will change to Flash player mode. There is a need to store this
|
||||
// setting in cookies because otherwise we will have to change from
|
||||
// HTML5 to Flash on every page load in a browser that doesn't fully
|
||||
// support HTML5. When we have this setting in cookies, we can select
|
||||
// the proper mode from the start (not having to change mode later on).
|
||||
function _setPlayerMode(state) {
|
||||
(function (currentPlayerMode) {
|
||||
if ((currentPlayerMode === 'html5') || (currentPlayerMode === 'flash')) {
|
||||
if (
|
||||
(currentPlayerMode === 'html5') ||
|
||||
(currentPlayerMode === 'flash')
|
||||
) {
|
||||
state.currentPlayerMode = currentPlayerMode;
|
||||
} else {
|
||||
$.cookie('current_player_mode', 'html5', {
|
||||
@@ -135,20 +162,32 @@ function (VideoPlayer) {
|
||||
});
|
||||
state.currentPlayerMode = 'html5';
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[Video info]: YouTube player mode is "' +
|
||||
state.currentPlayerMode + '".'
|
||||
);
|
||||
}($.cookie('current_player_mode')));
|
||||
}
|
||||
|
||||
// function _parseYouTubeIDs(state)
|
||||
// The function parse YouTube stream ID's.
|
||||
// @return
|
||||
// false: We don't have YouTube video IDs to work with; most likely we have HTML5 video sources.
|
||||
// true: Parsing of YouTube video IDs went OK, and we can proceed onwards to play YouTube videos.
|
||||
// false: We don't have YouTube video IDs to work with; most likely
|
||||
// we have HTML5 video sources.
|
||||
// true: Parsing of YouTube video IDs went OK, and we can proceed
|
||||
// onwards to play YouTube videos.
|
||||
function _parseYouTubeIDs(state) {
|
||||
if (state.parseYoutubeStreams(state.config.youtubeStreams)) {
|
||||
state.videoType = 'youtube';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[Video info]: Youtube Video IDs are incorrect or absent.'
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,6 +223,10 @@ function (VideoPlayer) {
|
||||
state.el.find('.video-player div').addClass('hidden');
|
||||
state.el.find('.video-player h3').removeClass('hidden');
|
||||
|
||||
console.log(
|
||||
'[Video info]: Non-youtube video sources aren\'t available.'
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -212,8 +255,9 @@ function (VideoPlayer) {
|
||||
|
||||
// ***************************************************************
|
||||
// Public functions start here.
|
||||
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
|
||||
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
|
||||
// These are available via the 'state' object. Their context ('this'
|
||||
// keyword) is the 'state' object. The magic private function that makes
|
||||
// them available and sets up their context is makeFunctionsPublic().
|
||||
// ***************************************************************
|
||||
|
||||
// function initialize(element)
|
||||
@@ -221,15 +265,21 @@ function (VideoPlayer) {
|
||||
|
||||
function initialize(element) {
|
||||
var _this = this, tempYtTestTimeout;
|
||||
// This is used in places where we instead would have to check if an element has a CSS class 'fullscreen'.
|
||||
// This is used in places where we instead would have to check if an
|
||||
// element has a CSS class 'fullscreen'.
|
||||
this.isFullScreen = false;
|
||||
|
||||
// The parent element of the video, and the ID.
|
||||
this.el = $(element).find('.video');
|
||||
this.id = this.el.attr('id').replace(/video_/, '');
|
||||
|
||||
// We store all settings passed to us by the server in one place. These are "read only", so don't
|
||||
// modify them. All variable content lives in 'state' object.
|
||||
console.log(
|
||||
'[Video info]: Initializing video with id "' + this.id + '".'
|
||||
);
|
||||
|
||||
// We store all settings passed to us by the server in one place. These
|
||||
// are "read only", so don't modify them. All variable content lives in
|
||||
// 'state' object.
|
||||
this.config = {
|
||||
element: element,
|
||||
|
||||
@@ -238,7 +288,10 @@ function (VideoPlayer) {
|
||||
|
||||
caption_data_dir: this.el.data('caption-data-dir'),
|
||||
caption_asset_path: this.el.data('caption-asset-path'),
|
||||
show_captions: (this.el.data('show-captions').toString().toLowerCase() === 'true'),
|
||||
show_captions: (
|
||||
this.el.data('show-captions')
|
||||
.toString().toLowerCase() === 'true'
|
||||
),
|
||||
youtubeStreams: this.el.data('streams'),
|
||||
|
||||
sub: this.el.data('sub'),
|
||||
@@ -262,12 +315,16 @@ function (VideoPlayer) {
|
||||
this.config.ytTestTimeout = tempYtTestTimeout;
|
||||
|
||||
if (!(_parseYouTubeIDs(this))) {
|
||||
|
||||
// If we do not have YouTube ID's, try parsing HTML5 video sources.
|
||||
if (!_prepareHTML5Video(this, true)) {
|
||||
|
||||
// Non-YouTube sources were not found either.
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Video info]: Start player in HTML5 mode.');
|
||||
|
||||
_setConfigurations(this);
|
||||
_renderElements(this);
|
||||
} else {
|
||||
@@ -276,29 +333,52 @@ function (VideoPlayer) {
|
||||
}
|
||||
|
||||
this.youtubeXhr
|
||||
.always(function(json, status) {
|
||||
.always(function (json, status) {
|
||||
var err = $.isPlainObject(json.error) ||
|
||||
(status !== 'success' && status !== 'notmodified');
|
||||
(
|
||||
status !== 'success' &&
|
||||
status !== 'notmodified'
|
||||
);
|
||||
if (err) {
|
||||
console.log(
|
||||
'[Video info]: YouTube returned an error for ' +
|
||||
'video with id "' + _this.id + '".'
|
||||
);
|
||||
|
||||
// When the youtube link doesn't work for any reason
|
||||
// (for example, the great firewall in china) any
|
||||
// alternate sources should automatically play.
|
||||
if (!_prepareHTML5Video(_this)) {
|
||||
console.log(
|
||||
'[Video info]: Continue loading ' +
|
||||
'YouTube video.'
|
||||
);
|
||||
|
||||
// Non-YouTube sources were not found either.
|
||||
|
||||
_this.el.find('.video-player div').removeClass('hidden');
|
||||
_this.el.find('.video-player h3').addClass('hidden');
|
||||
_this.el.find('.video-player div')
|
||||
.removeClass('hidden');
|
||||
_this.el.find('.video-player h3')
|
||||
.addClass('hidden');
|
||||
|
||||
// If in reality the timeout was to short, try to
|
||||
// continue loading the YouTube video anyways.
|
||||
_this.fetchMetadata();
|
||||
_this.parseSpeed();
|
||||
} else {
|
||||
console.log(
|
||||
'[Video info]: Change player mode to HTML5.'
|
||||
);
|
||||
|
||||
// In-browser HTML5 player does not support quality
|
||||
// control.
|
||||
_this.el.find('a.quality_control').hide();
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'[Video info]: Start player in YouTube mode.'
|
||||
);
|
||||
|
||||
_this.fetchMetadata();
|
||||
_this.parseSpeed();
|
||||
}
|
||||
@@ -313,23 +393,28 @@ function (VideoPlayer) {
|
||||
//
|
||||
// Take a string in the form:
|
||||
// "iCawTYPtehk:0.75,KgpclqP-LBA:1.0,9-2670d5nvU:1.5"
|
||||
// parse it, and make it available via the 'state' object. If we are not given a string, or
|
||||
// it's length is zero, then we return false.
|
||||
// parse it, and make it available via the 'state' object. If we are
|
||||
// not given a string, or it's length is zero, then we return false.
|
||||
//
|
||||
// @return
|
||||
// false: We don't have YouTube video IDs to work with; most likely we have HTML5 video sources.
|
||||
// true: Parsing of YouTube video IDs went OK, and we can proceed onwards to play YouTube videos.
|
||||
// false: We don't have YouTube video IDs to work with; most likely
|
||||
// we have HTML5 video sources.
|
||||
// true: Parsing of YouTube video IDs went OK, and we can proceed
|
||||
// onwards to play YouTube videos.
|
||||
function parseYoutubeStreams(youtubeStreams) {
|
||||
var _this;
|
||||
|
||||
if (typeof youtubeStreams === 'undefined' || youtubeStreams.length === 0) {
|
||||
if (
|
||||
typeof youtubeStreams === 'undefined' ||
|
||||
youtubeStreams.length === 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_this = this;
|
||||
this.videos = {};
|
||||
|
||||
$.each(youtubeStreams.split(/,/), function(index, video) {
|
||||
$.each(youtubeStreams.split(/,/), function (index, video) {
|
||||
var speed;
|
||||
|
||||
video = video.split(/:/);
|
||||
@@ -343,8 +428,8 @@ function (VideoPlayer) {
|
||||
|
||||
// function parseVideoSources(, mp4Source, webmSource, oggSource)
|
||||
//
|
||||
// Take the HTML5 sources (URLs of videos), and make them available explictly for each type
|
||||
// of video format (mp4, webm, ogg).
|
||||
// Take the HTML5 sources (URLs of videos), and make them available
|
||||
// explictly for each type of video format (mp4, webm, ogg).
|
||||
function parseVideoSources(sources) {
|
||||
var _this = this,
|
||||
v = document.createElement('video'),
|
||||
@@ -376,16 +461,17 @@ function (VideoPlayer) {
|
||||
|
||||
// function fetchMetadata()
|
||||
//
|
||||
// When dealing with YouTube videos, we must fetch meta data that has certain key facts
|
||||
// not available while the video is loading. For example the length of the video can be
|
||||
// determined from the meta data.
|
||||
// When dealing with YouTube videos, we must fetch meta data that has
|
||||
// certain key facts not available while the video is loading. For
|
||||
// example the length of the video can be determined from the meta
|
||||
// data.
|
||||
function fetchMetadata() {
|
||||
var _this = this;
|
||||
|
||||
this.metadata = {};
|
||||
|
||||
$.each(this.videos, function (speed, url) {
|
||||
_this.getVideoMetadata(url, function(data) {
|
||||
_this.getVideoMetadata(url, function (data) {
|
||||
if (data.data) {
|
||||
_this.metadata[data.data.id] = data.data;
|
||||
}
|
||||
@@ -397,7 +483,7 @@ function (VideoPlayer) {
|
||||
//
|
||||
// Create a separate array of available speeds.
|
||||
function parseSpeed() {
|
||||
this.speeds = ($.map(this.videos, function(url, speed) {
|
||||
this.speeds = ($.map(this.videos, function (url, speed) {
|
||||
return speed;
|
||||
})).sort();
|
||||
|
||||
@@ -439,7 +525,7 @@ function (VideoPlayer) {
|
||||
function stopBuffering() {
|
||||
var video;
|
||||
|
||||
if (this.videoType === 'html5'){
|
||||
if (this.videoType === 'html5') {
|
||||
// HTML5 player haven't default way to abort bufferization.
|
||||
// In this case we simply resetting source and call load().
|
||||
video = this.videoPlayer.player.video;
|
||||
@@ -457,9 +543,9 @@ function (VideoPlayer) {
|
||||
}
|
||||
|
||||
/*
|
||||
* The trigger() function will assume that the @objChain is a complete chain with a method
|
||||
* (function) at the end. It will call this function. So for example, when trigger() is
|
||||
* called like so:
|
||||
* The trigger() function will assume that the @objChain is a complete
|
||||
* chain with a method (function) at the end. It will call this function.
|
||||
* So for example, when trigger() is called like so:
|
||||
*
|
||||
* state.trigger('videoPlayer.pause', {'param1': 10});
|
||||
*
|
||||
@@ -474,10 +560,10 @@ function (VideoPlayer) {
|
||||
tmpObj = this;
|
||||
chain = objChain.split('.');
|
||||
|
||||
// At the end of the loop the variable 'tmpObj' will either be the correct
|
||||
// object/function to trigger/invoke. If the 'chain' chain of object is
|
||||
// incorrect (one of the link is non-existent), then the loop will immediately
|
||||
// exit.
|
||||
// At the end of the loop the variable 'tmpObj' will either be the
|
||||
// correct object/function to trigger/invoke. If the 'chain' chain of
|
||||
// object is incorrect (one of the link is non-existent), then the loop
|
||||
// will immediately exit.
|
||||
while (chain.length) {
|
||||
i = chain.shift();
|
||||
|
||||
|
||||
@@ -21,35 +21,46 @@ function (HTML5Video) {
|
||||
|
||||
// function _makeFunctionsPublic(state)
|
||||
//
|
||||
// Functions which will be accessible via 'state' object. When called, these functions will
|
||||
// get the 'state' object as a context.
|
||||
// Functions which will be accessible via 'state' object. When called,
|
||||
// these functions will get the 'state' object as a context.
|
||||
function _makeFunctionsPublic(state) {
|
||||
state.videoPlayer.pause = _.bind(pause, state);
|
||||
state.videoPlayer.play = _.bind(play, state);
|
||||
state.videoPlayer.update = _.bind(update, state);
|
||||
state.videoPlayer.onSpeedChange = _.bind(onSpeedChange, state);
|
||||
state.videoPlayer.onCaptionSeek = _.bind(onSeek, state);
|
||||
state.videoPlayer.onSlideSeek = _.bind(onSeek, state);
|
||||
state.videoPlayer.onEnded = _.bind(onEnded, state);
|
||||
state.videoPlayer.onPause = _.bind(onPause, state);
|
||||
state.videoPlayer.onPlay = _.bind(onPlay, state);
|
||||
state.videoPlayer.onUnstarted = _.bind(onUnstarted, state);
|
||||
state.videoPlayer.handlePlaybackQualityChange = _.bind(handlePlaybackQualityChange, state);
|
||||
state.videoPlayer.onPlaybackQualityChange = _.bind(onPlaybackQualityChange, state);
|
||||
state.videoPlayer.onStateChange = _.bind(onStateChange, state);
|
||||
state.videoPlayer.onReady = _.bind(onReady, state);
|
||||
state.videoPlayer.updatePlayTime = _.bind(updatePlayTime, state);
|
||||
state.videoPlayer.isPlaying = _.bind(isPlaying, state);
|
||||
state.videoPlayer.log = _.bind(log, state);
|
||||
state.videoPlayer.duration = _.bind(duration, state);
|
||||
state.videoPlayer.onVolumeChange = _.bind(onVolumeChange, state);
|
||||
state.videoPlayer.pause = _.bind(pause, state);
|
||||
state.videoPlayer.play = _.bind(play, state);
|
||||
state.videoPlayer.update = _.bind(update, state);
|
||||
state.videoPlayer.onSpeedChange = _.bind(onSpeedChange, state);
|
||||
state.videoPlayer.onCaptionSeek = _.bind(onSeek, state);
|
||||
state.videoPlayer.onSlideSeek = _.bind(onSeek, state);
|
||||
state.videoPlayer.onEnded = _.bind(onEnded, state);
|
||||
state.videoPlayer.onPause = _.bind(onPause, state);
|
||||
state.videoPlayer.onPlay = _.bind(onPlay, state);
|
||||
|
||||
state.videoPlayer.onUnstarted = _.bind(
|
||||
onUnstarted, state
|
||||
);
|
||||
|
||||
state.videoPlayer.handlePlaybackQualityChange = _.bind(
|
||||
handlePlaybackQualityChange, state
|
||||
);
|
||||
|
||||
state.videoPlayer.onPlaybackQualityChange = _.bind(
|
||||
onPlaybackQualityChange, state
|
||||
);
|
||||
|
||||
state.videoPlayer.onStateChange = _.bind(onStateChange, state);
|
||||
state.videoPlayer.onReady = _.bind(onReady, state);
|
||||
state.videoPlayer.updatePlayTime = _.bind(updatePlayTime, state);
|
||||
state.videoPlayer.isPlaying = _.bind(isPlaying, state);
|
||||
state.videoPlayer.log = _.bind(log, state);
|
||||
state.videoPlayer.duration = _.bind(duration, state);
|
||||
state.videoPlayer.onVolumeChange = _.bind(onVolumeChange, state);
|
||||
}
|
||||
|
||||
// function _initialize(state)
|
||||
//
|
||||
// Create any necessary DOM elements, attach them, and set their initial configuration. Also
|
||||
// make the created DOM elements available via the 'state' object. Much easier to work this
|
||||
// way - you don't have to do repeated jQuery element selects.
|
||||
// Create any necessary DOM elements, attach them, and set their
|
||||
// initial configuration. Also make the created DOM elements available
|
||||
// via the 'state' object. Much easier to work this way - you don't
|
||||
// have to do repeated jQuery element selects.
|
||||
function _initialize(state) {
|
||||
var youTubeId;
|
||||
|
||||
@@ -92,9 +103,10 @@ function (HTML5Video) {
|
||||
//
|
||||
// TODO: Check the status of
|
||||
// http://code.google.com/p/gdata-issues/issues/detail?id=4654
|
||||
// When the YouTube team fixes the API bug, we can remove this temporary
|
||||
// bug fix.
|
||||
state.browserIsFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
// When the YouTube team fixes the API bug, we can remove this
|
||||
// temporary bug fix.
|
||||
state.browserIsFirefox = navigator.userAgent
|
||||
.toLowerCase().indexOf('firefox') > -1;
|
||||
|
||||
if (state.videoType === 'html5') {
|
||||
state.videoPlayer.player = new HTML5Video.Player(state.el, {
|
||||
@@ -117,7 +129,8 @@ function (HTML5Video) {
|
||||
events: {
|
||||
onReady: state.videoPlayer.onReady,
|
||||
onStateChange: state.videoPlayer.onStateChange,
|
||||
onPlaybackQualityChange: state.videoPlayer.onPlaybackQualityChange
|
||||
onPlaybackQualityChange: state.videoPlayer
|
||||
.onPlaybackQualityChange
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -125,9 +138,10 @@ function (HTML5Video) {
|
||||
|
||||
// function _restartUsingFlash(state)
|
||||
//
|
||||
// When we are about to play a YouTube video in HTML5 mode and discover that we only
|
||||
// have one available playback rate, we will switch to Flash mode. In Flash speed
|
||||
// switching is done by reloading videos recorded at different frame rates.
|
||||
// When we are about to play a YouTube video in HTML5 mode and discover
|
||||
// that we only have one available playback rate, we will switch to
|
||||
// Flash mode. In Flash speed switching is done by reloading videos
|
||||
// recorded at different frame rates.
|
||||
function _restartUsingFlash(state) {
|
||||
// Remove from the page current iFrame with HTML5 video.
|
||||
state.videoPlayer.player.destroy();
|
||||
@@ -139,25 +153,29 @@ function (HTML5Video) {
|
||||
});
|
||||
state.currentPlayerMode = 'flash';
|
||||
|
||||
console.log('[Video info]: Changing YouTube player mode to "flash".');
|
||||
|
||||
// Removed configuration option that requests the HTML5 mode.
|
||||
delete state.videoPlayer.playerVars.html5;
|
||||
|
||||
// Request for the creation of a new Flash player
|
||||
state.videoPlayer.player = new YT.Player(state.id, {
|
||||
'playerVars': state.videoPlayer.playerVars,
|
||||
'videoId': state.youtubeId(),
|
||||
'events': {
|
||||
'onReady': state.videoPlayer.onReady,
|
||||
'onStateChange': state.videoPlayer.onStateChange,
|
||||
'onPlaybackQualityChange': state.videoPlayer.onPlaybackQualityChange
|
||||
playerVars: state.videoPlayer.playerVars,
|
||||
videoId: state.youtubeId(),
|
||||
events: {
|
||||
onReady: state.videoPlayer.onReady,
|
||||
onStateChange: state.videoPlayer.onStateChange,
|
||||
onPlaybackQualityChange: state.videoPlayer
|
||||
.onPlaybackQualityChange
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ***************************************************************
|
||||
// Public functions start here.
|
||||
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
|
||||
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
|
||||
// These are available via the 'state' object. Their context ('this'
|
||||
// keyword) is the 'state' object. The magic private function that makes
|
||||
// them available and sets up their context is makeFunctionsPublic().
|
||||
// ***************************************************************
|
||||
|
||||
function pause() {
|
||||
@@ -174,9 +192,11 @@ function (HTML5Video) {
|
||||
|
||||
// This function gets the video's current play position in time
|
||||
// (currentTime) and its duration.
|
||||
// It is called at a regular interval when the video is playing (see below).
|
||||
// It is called at a regular interval when the video is playing (see
|
||||
// below).
|
||||
function update() {
|
||||
this.videoPlayer.currentTime = this.videoPlayer.player.getCurrentTime();
|
||||
this.videoPlayer.currentTime = this.videoPlayer.player
|
||||
.getCurrentTime();
|
||||
|
||||
if (isFinite(this.videoPlayer.currentTime)) {
|
||||
this.videoPlayer.updatePlayTime(this.videoPlayer.currentTime);
|
||||
@@ -206,19 +226,27 @@ function (HTML5Video) {
|
||||
|
||||
if (
|
||||
this.currentPlayerMode === 'html5' &&
|
||||
!(this.browserIsFirefox && newSpeed === '1.0' && this.videoType === 'youtube')
|
||||
!(
|
||||
this.browserIsFirefox &&
|
||||
newSpeed === '1.0' &&
|
||||
this.videoType === 'youtube'
|
||||
)
|
||||
) {
|
||||
this.videoPlayer.player.setPlaybackRate(newSpeed);
|
||||
} else {
|
||||
// We request the reloading of the video in the case when YouTube is in
|
||||
// Flash player mode, or when we are in Firefox, and the new speed is 1.0.
|
||||
// The second case is necessary to avoid the bug where in Firefox speed
|
||||
// switching to 1.0 in HTML5 player mode is handled incorrectly by YouTube
|
||||
// API.
|
||||
// We request the reloading of the video in the case when YouTube
|
||||
// is in Flash player mode, or when we are in Firefox, and the new
|
||||
// speed is 1.0. The second case is necessary to avoid the bug
|
||||
// where in Firefox speed switching to 1.0 in HTML5 player mode is
|
||||
// handled incorrectly by YouTube API.
|
||||
if (this.videoPlayer.isPlaying()) {
|
||||
this.videoPlayer.player.loadVideoById(this.youtubeId(), this.videoPlayer.currentTime);
|
||||
this.videoPlayer.player.loadVideoById(
|
||||
this.youtubeId(), this.videoPlayer.currentTime
|
||||
);
|
||||
} else {
|
||||
this.videoPlayer.player.cueVideoById(this.youtubeId(), this.videoPlayer.currentTime);
|
||||
this.videoPlayer.player.cueVideoById(
|
||||
this.youtubeId(), this.videoPlayer.currentTime
|
||||
);
|
||||
}
|
||||
|
||||
this.videoPlayer.updatePlayTime(this.videoPlayer.currentTime);
|
||||
@@ -243,7 +271,9 @@ function (HTML5Video) {
|
||||
|
||||
if (this.videoPlayer.isPlaying()) {
|
||||
clearInterval(this.videoPlayer.updateInterval);
|
||||
this.videoPlayer.updateInterval = setInterval(this.videoPlayer.update, 200);
|
||||
this.videoPlayer.updateInterval = setInterval(
|
||||
this.videoPlayer.update, 200
|
||||
);
|
||||
} else {
|
||||
this.videoPlayer.currentTime = params.time;
|
||||
}
|
||||
@@ -286,7 +316,9 @@ function (HTML5Video) {
|
||||
);
|
||||
|
||||
if (!this.videoPlayer.updateInterval) {
|
||||
this.videoPlayer.updateInterval = setInterval(this.videoPlayer.update, 200);
|
||||
this.videoPlayer.updateInterval = setInterval(
|
||||
this.videoPlayer.update, 200
|
||||
);
|
||||
}
|
||||
|
||||
this.trigger('videoControl.play', null);
|
||||
@@ -325,19 +357,26 @@ function (HTML5Video) {
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=840745
|
||||
// https://developer.mozilla.org/en-US/docs/DOM/HTMLMediaElement
|
||||
|
||||
availablePlaybackRates = _.filter(availablePlaybackRates, function(item){
|
||||
var speed = Number(item);
|
||||
return speed > 0.25 && speed <= 5;
|
||||
});
|
||||
availablePlaybackRates = _.filter(
|
||||
availablePlaybackRates,
|
||||
function (item) {
|
||||
var speed = Number(item);
|
||||
return speed > 0.25 && speed <= 5;
|
||||
}
|
||||
);
|
||||
|
||||
if ((this.currentPlayerMode === 'html5') && (this.videoType === 'youtube')) {
|
||||
if (
|
||||
this.currentPlayerMode === 'html5' &&
|
||||
this.videoType === 'youtube'
|
||||
) {
|
||||
if (availablePlaybackRates.length === 1) {
|
||||
// This condition is needed in cases when Firefox version is less than 20. In those versions
|
||||
// HTML5 playback could only happen at 1 speed (no speed changing). Therefore, in this case,
|
||||
// we need to switch back to Flash.
|
||||
// This condition is needed in cases when Firefox version is
|
||||
// less than 20. In those versions HTML5 playback could only
|
||||
// happen at 1 speed (no speed changing). Therefore, in this
|
||||
// case, we need to switch back to Flash.
|
||||
//
|
||||
// This might also happen in other browsers, therefore when we have 1 speed available, we fall
|
||||
// back to Flash.
|
||||
// This might also happen in other browsers, therefore when we
|
||||
// have 1 speed available, we fall back to Flash.
|
||||
|
||||
_restartUsingFlash(this);
|
||||
|
||||
@@ -352,18 +391,26 @@ function (HTML5Video) {
|
||||
// and their associated subs.
|
||||
|
||||
// First clear the dictionary.
|
||||
$.each(this.videos, function(index, value) {
|
||||
$.each(this.videos, function (index, value) {
|
||||
delete _this.videos[index];
|
||||
});
|
||||
this.speeds = [];
|
||||
// Recreate it with the supplied frame rates.
|
||||
$.each(availablePlaybackRates, function(index, value) {
|
||||
_this.videos[value.toFixed(2).replace(/\.00$/, '.0')] = baseSpeedSubs;
|
||||
$.each(availablePlaybackRates, function (index, value) {
|
||||
var key = value.toFixed(2).replace(/\.00$/, '.0');
|
||||
|
||||
_this.speeds.push(value.toFixed(2).replace(/\.00$/, '.0'));
|
||||
_this.videos[key] = baseSpeedSubs;
|
||||
|
||||
_this.speeds.push(key);
|
||||
});
|
||||
|
||||
this.trigger('videoSpeedControl.reRender', {'newSpeeds': this.speeds, 'currentSpeed': this.speed});
|
||||
this.trigger(
|
||||
'videoSpeedControl.reRender',
|
||||
{
|
||||
newSpeeds: this.speeds,
|
||||
currentSpeed: this.speed
|
||||
}
|
||||
);
|
||||
|
||||
this.setSpeed($.cookie('video_speed'));
|
||||
}
|
||||
@@ -373,7 +420,10 @@ function (HTML5Video) {
|
||||
this.videoPlayer.player.setPlaybackRate(this.speed);
|
||||
}
|
||||
|
||||
if (!onTouchBasedDevice() && $('.video:first').data('autoplay') === 'True') {
|
||||
if (
|
||||
!onTouchBasedDevice() &&
|
||||
$('.video:first').data('autoplay') === 'True'
|
||||
) {
|
||||
this.videoPlayer.play();
|
||||
}
|
||||
}
|
||||
@@ -400,19 +450,37 @@ function (HTML5Video) {
|
||||
|
||||
duration = this.videoPlayer.duration();
|
||||
|
||||
this.trigger('videoProgressSlider.updatePlayTime', {'time': time, 'duration': duration});
|
||||
this.trigger('videoControl.updateVcrVidTime', {'time': time, 'duration': duration});
|
||||
this.trigger(
|
||||
'videoProgressSlider.updatePlayTime',
|
||||
{
|
||||
time: time,
|
||||
duration: duration
|
||||
}
|
||||
);
|
||||
|
||||
this.trigger(
|
||||
'videoControl.updateVcrVidTime',
|
||||
{
|
||||
time: time,
|
||||
duration: duration
|
||||
}
|
||||
);
|
||||
|
||||
this.trigger('videoCaption.updatePlayTime', time);
|
||||
}
|
||||
|
||||
function isPlaying() {
|
||||
return this.videoPlayer.player.getPlayerState() === this.videoPlayer.PlayerState.PLAYING;
|
||||
var playerState = this.videoPlayer.player.getPlayerState(),
|
||||
PLAYING = this.videoPlayer.PlayerState.PLAYING;
|
||||
|
||||
return playerState === PLAYING;
|
||||
}
|
||||
|
||||
function duration() {
|
||||
var dur;
|
||||
|
||||
dur = this.videoPlayer.player.getDuration();
|
||||
|
||||
if (!isFinite(dur)) {
|
||||
dur = this.getDuration();
|
||||
}
|
||||
@@ -431,7 +499,7 @@ function (HTML5Video) {
|
||||
|
||||
// If extra parameters were passed to the log.
|
||||
if (data) {
|
||||
$.each(data, function(paramName, value) {
|
||||
$.each(data, function (paramName, value) {
|
||||
logInfo[paramName] = value;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ function () {
|
||||
}
|
||||
|
||||
if (state.videoType === 'html5' && !(_checkPlaybackRates())) {
|
||||
console.log(
|
||||
'[Video info]: HTML5 mode - playbackRate is not supported.'
|
||||
);
|
||||
|
||||
_hideSpeedControl(state);
|
||||
|
||||
return;
|
||||
@@ -65,7 +69,7 @@ function () {
|
||||
state.videoSpeedControl.el
|
||||
);
|
||||
|
||||
$.each(state.videoSpeedControl.speeds, function(index, speed) {
|
||||
$.each(state.videoSpeedControl.speeds, function (index, speed) {
|
||||
var link = '<a class="speed_link" href="#">' + speed + 'x</a>';
|
||||
|
||||
state.videoSpeedControl.videoSpeedsEl
|
||||
@@ -78,26 +82,27 @@ function () {
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc Check if playbackRate supports by browser.
|
||||
*
|
||||
* @type {function}
|
||||
* @access private
|
||||
*
|
||||
* @param {object} state The object containg the state of the video player.
|
||||
* All other modules, their parameters, public variables, etc. are
|
||||
* available via this object.
|
||||
*
|
||||
* @this {object} The global window object.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true: Browser support playbackRate functionality.
|
||||
* false: Browser doesn't support playbackRate functionality.
|
||||
*/
|
||||
* @desc Check if playbackRate supports by browser.
|
||||
*
|
||||
* @type {function}
|
||||
* @access private
|
||||
*
|
||||
* @param {object} state The object containg the state of the video player.
|
||||
* All other modules, their parameters, public variables, etc. are
|
||||
* available via this object.
|
||||
*
|
||||
* @this {object} The global window object.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true: Browser support playbackRate functionality.
|
||||
* false: Browser doesn't support playbackRate functionality.
|
||||
*/
|
||||
function _checkPlaybackRates() {
|
||||
var video = document.createElement('video');
|
||||
|
||||
// If browser supports, 1.0 should be returned by playbackRate property.
|
||||
// In this case, function return True. Otherwise, False will be returned.
|
||||
// If browser supports, 1.0 should be returned by playbackRate
|
||||
// property. In this case, function return True. Otherwise, False will
|
||||
// be returned.
|
||||
return Boolean(video.playbackRate);
|
||||
}
|
||||
|
||||
@@ -128,7 +133,7 @@ function () {
|
||||
.on('click', state.videoSpeedControl.changeVideoSpeed);
|
||||
|
||||
if (onTouchBasedDevice()) {
|
||||
state.videoSpeedControl.el.on('click', function(event) {
|
||||
state.videoSpeedControl.el.on('click', function (event) {
|
||||
// So that you can't highlight this control via a drag
|
||||
// operation, we disable the default browser actions on a
|
||||
// click event.
|
||||
@@ -287,7 +292,7 @@ function () {
|
||||
this.videoSpeedControl.videoSpeedsEl.find('li').removeClass('active');
|
||||
this.videoSpeedControl.speeds = params.newSpeeds;
|
||||
|
||||
$.each(this.videoSpeedControl.speeds, function(index, speed) {
|
||||
$.each(this.videoSpeedControl.speeds, function (index, speed) {
|
||||
var link, listItem;
|
||||
|
||||
link = '<a class="speed_link" href="#">' + speed + 'x</a>';
|
||||
|
||||
Reference in New Issue
Block a user