From 73a9c43ebbc5a36a3ed384407918ad3db71bb34b Mon Sep 17 00:00:00 2001
From: Valera Rozuvan <valera@edx.org>
Date: Fri, 6 Sep 2013 11:55:55 +0300
Subject: [PATCH] Addressing Anton's comments on PR 869.

Removed extra check for console.log() existance. Modified error
messages. Formatted entire file to fit in 80 lines or less.

Formatting files so that they fit under 80 lines. Adding debug info for
what type of YouTube video player is being used. Also comment on whether
playbackRates is available for HTML5 mode.

Changed back Anton's original function _checkPlaybackRates(). Now logging for
this function's result is done only on error (in the function that is invoking)
it).
---
 .../xmodule/js/src/video/01_initialize.js     | 222 +++++++++++-------
 .../xmodule/js/src/video/03_video_player.js   | 210 +++++++++++------
 .../js/src/video/08_video_speed_control.js    |  45 ++--
 3 files changed, 298 insertions(+), 179 deletions(-)

diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
index 30b5ac5778f..7f8057c0252 100644
--- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
+++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js
@@ -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,18 +17,8 @@ define(
 ['video/03_video_player.js'],
 function (VideoPlayer) {
 
-    // In case if console.log() is unavailable for some reason.
-    //
-    // console.log() will be used to put case critical messages to the browser
-    // JavaScript console to allow for better and quicker debugging.
-    //
-    // This is placed here because '01_initialize.js' gets loaded first.
-    if (typeof window.console === 'undefined') {
-        window.console = {};
-    }
-    if ($.isFunction(window.console.log) === false) {
-        window.console.log = function () {};
-    }
+    // 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
@@ -69,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);
         }
     }
@@ -121,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');
@@ -138,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', {
@@ -154,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;
     }
 
@@ -203,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;
         }
 
@@ -231,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)
@@ -240,17 +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_/, '');
 
-        console.log('[Video info]: Initializing video with id "' + this.id + '".');
+        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.
+        // 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,
 
@@ -259,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'),
@@ -282,62 +314,70 @@ function (VideoPlayer) {
         }
         this.config.ytTestTimeout = tempYtTestTimeout;
 
-        console.log('[Video info]: Try parsing YouTube IDs.');
         if (!(_parseYouTubeIDs(this))) {
-            console.log('[Video info]: Could not parse YouTube IDs. Try parsing non-YouTube video sources.');
 
             // If we do not have YouTube ID's, try parsing HTML5 video sources.
             if (!_prepareHTML5Video(this, true)) {
-                console.log('[Video info]: No video sources available at all.');
 
                 // Non-YouTube sources were not found either.
                 return;
             }
 
+            console.log('[Video info]: Start player in HTML5 mode.');
+
             _setConfigurations(this);
             _renderElements(this);
         } else {
-            console.log('[Video info]: Valid YouTube IDs found.');
             if (!this.youtubeXhr) {
-                console.log('[Video info]: Making request to see if YouTube responds.');
                 this.youtubeXhr = this.getVideoMetadata();
             }
 
-            console.log('[Video info]: Waiting for YouTube to respond.');
-
             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]: An error happened while waiting for YouTube to respond.');
-                        console.log('[Video info]: Checking if alternate non-YouTube video sources are available.');
+                        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]: No alternative non-YouTube video sources available.');
-                            console.log('[Video info]: Will try to continue loading YouTube video. Maybe the response timeout is longer than was specified.');
+                            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]: Alternative non-YouTube video sources were found and will be loaded.');
+                            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]: YouTube responded with OK. Loading YouTube video.');
+                        console.log(
+                            '[Video info]: Start player in YouTube mode.'
+                        );
 
                         _this.fetchMetadata();
                         _this.parseSpeed();
@@ -353,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(/:/);
@@ -383,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'),
@@ -416,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;
                 }
@@ -437,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();
 
@@ -479,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;
@@ -497,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});
      *
@@ -514,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();
 
diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
index 25617283f59..649dd9cf668 100644
--- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
+++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js
@@ -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.videos[key] = baseSpeedSubs;
 
-                    _this.speeds.push(value.toFixed(2).replace(/\.00$/, '.0'));
+                    _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;
             });
         }
diff --git a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
index 6a6587186da..9db56ffc0d9 100644
--- a/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
+++ b/common/lib/xmodule/xmodule/js/src/video/08_video_speed_control.js
@@ -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>';
-- 
GitLab