From c360b4effb82935dc8386e27ef0ca8b51b19710d Mon Sep 17 00:00:00 2001
From: muhammad-ammar <mammar@gmail.com>
Date: Thu, 3 May 2018 17:34:02 +0500
Subject: [PATCH] fix poster display issue with hls

EDUCATOR-2606

another approach
---
 .../js/src/video/02_html5_hls_video.js        | 31 +++++++++++++-
 .../xmodule/js/src/video/02_html5_video.js    | 42 +++++++++++++++++--
 .../xmodule/js/src/video/03_video_player.js   |  6 +++
 .../tests/video/test_video_module.py          |  9 +++-
 4 files changed, 83 insertions(+), 5 deletions(-)

diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js
index 4df4794043e..f2124c06431 100644
--- a/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js
+++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js
@@ -20,23 +20,40 @@
             function Player(el, config) {
                 var self = this;
 
+                this.config = config;
+
                 // do common initialization independent of player type
                 this.init(el, config);
 
+                _.bindAll(this, 'playVideo', 'onReady');
+
                 // If we have only HLS sources and browser doesn't support HLS then show error message.
                 if (config.HLSOnlySources && !config.canPlayHLS) {
                     this.showErrorMessage(null, '.video-hls-error');
                     return;
                 }
 
+                this.config.state.el.on('initialize', _.once(function() {
+                    console.log('[HLS Video]: HLS Player initialized');
+                    self.showPlayButton();
+                }));
+
                 // Safari has native support to play HLS videos
                 if (config.browserIsSafari) {
                     this.videoEl.attr('src', config.videoSources[0]);
                 } else {
-                    this.hls = new HLS();
+                    this.hls = new HLS({autoStartLoad: false});
                     this.hls.loadSource(config.videoSources[0]);
                     this.hls.attachMedia(this.video);
 
+                    this.showLoadingOnce = _.once(function() {
+                        HTML5Video.Player.prototype.updatePlayerLoadingState.apply(self, ['show']);
+                    });
+
+                    this.hideLoadingOnce = _.once(function() {
+                        HTML5Video.Player.prototype.updatePlayerLoadingState.apply(self, ['hide']);
+                    });
+
                     this.hls.on(HLS.Events.ERROR, this.onError.bind(this));
 
                     this.hls.on(HLS.Events.MANIFEST_PARSED, function(event, data) {
@@ -49,6 +66,7 @@
                                 };
                             })
                         );
+                        self.config.onReadyHLS();
                     });
                     this.hls.on(HLS.Events.LEVEL_SWITCHED, function(event, data) {
                         var level = self.hls.levels[data.level];
@@ -59,6 +77,7 @@
                                 resolution: level.width + 'x' + level.height
                             }
                         );
+                        self.hideLoadingOnce();
                     });
                 }
             }
@@ -66,6 +85,16 @@
             Player.prototype = Object.create(HTML5Video.Player.prototype);
             Player.prototype.constructor = Player;
 
+            Player.prototype.playVideo = function() {
+                this.hls.startLoad();
+                this.video.play();
+                this.showLoadingOnce();
+            };
+
+            Player.prototype.onReady = function() {
+                this.config.events.onReady(null);
+            };
+
             /**
              * Handler for HLS video errors. This only takes care of fatal erros, non-fatal errors
              * are automatically handled by hls.js
diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
index 367939e21a7..f24a08b5fba 100644
--- a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
+++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
@@ -95,6 +95,38 @@ function(_) {
             this.videoEl.on('error', this.onError.bind(this));
         }
 
+        Player.prototype.showPlayButton = function() {
+            this.videoOverlayEl.removeClass('is-hidden');
+        };
+
+        Player.prototype.hidePlayButton = function() {
+            this.videoOverlayEl.addClass('is-hidden');
+        };
+
+        Player.prototype.showLoading = function() {
+            this.el
+                .removeClass('is-initialized')
+                .find('.spinner')
+                .removeAttr('tabindex')
+                .attr({'aria-hidden': 'false'});
+        };
+
+        Player.prototype.hideLoading = function() {
+            this.el
+                .addClass('is-initialized')
+                .find('.spinner')
+                .attr({'aria-hidden': 'false', 'tabindex': -1});
+        };
+
+        Player.prototype.updatePlayerLoadingState = function(state) {
+            if (state === 'show') {
+                this.hidePlayButton();
+                this.showLoading();
+            } else if (state === 'hide') {
+                this.hideLoading();
+            }
+        };
+
         Player.prototype.callStateChangeCallback = function() {
             if ($.isFunction(this.config.events.onStateChange)) {
                 this.config.events.onStateChange({
@@ -211,11 +243,15 @@ function(_) {
             this.videoEl.remove();
         };
 
+        Player.prototype.onReady = function() {
+            this.config.events.onReady(null);
+            this.showPlayButton();
+        };
+
         Player.prototype.onLoadedMetadata = function() {
             this.playerState = HTML5Video.PlayerState.PAUSED;
             if ($.isFunction(this.config.events.onReady)) {
-                this.config.events.onReady(null);
-                this.videoOverlayEl.removeClass('is-hidden');
+                this.onReady();
             }
         };
 
@@ -234,7 +270,7 @@ function(_) {
         Player.prototype.onPause = function() {
             this.playerState = HTML5Video.PlayerState.PAUSED;
             this.callStateChangeCallback();
-            this.videoOverlayEl.removeClass('is-hidden');
+            this.showPlayButton();
         };
 
         Player.prototype.onEnded = function() {
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 fee8806aa93..44b54d82f81 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
@@ -179,6 +179,8 @@ function(HTML5Video, HTML5HLSVideo, Resizer, HLS, _, Time) {
                 state.videoPlayer.player = new HTML5HLSVideo.Player(
                     state.el,
                     _.extend({}, commonPlayerConfig, {
+                        state: state,
+                        onReadyHLS: onReadyHLS,
                         videoSources: state.HLSVideoSources,
                         canPlayHLS: state.canPlayHLS,
                         HLSOnlySources: state.HLSOnlySources
@@ -559,6 +561,10 @@ function(HTML5Video, HTML5HLSVideo, Resizer, HLS, _, Time) {
         this.el.trigger('qualitychange', arguments);
     }
 
+    function onReadyHLS() {
+        dfd.resolve();
+    }
+
     function onReady() {
         var _this = this,
             availablePlaybackRates, baseSpeedSubs,
diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py
index a9350804f8c..bd1a9f5a5b1 100644
--- a/common/test/acceptance/tests/video/test_video_module.py
+++ b/common/test/acceptance/tests/video/test_video_module.py
@@ -1142,7 +1142,7 @@ class HLSVideoTest(VideoBaseTest):
         self.navigate_to_video()
 
         self.video.click_player_button('play')
-        self.assertEqual(self.video.state, 'playing')
+        self.assertIn(self.video.state, ['buffering', 'playing'])
         self.video.click_player_button('pause')
         self.assertEqual(self.video.state, 'pause')
 
@@ -1231,6 +1231,7 @@ class HLSVideoTest(VideoBaseTest):
         Given the course has a Video component with "HLS" video only
         And I have defined a transcript for the video
         Then I see the correct text in the captions for transcript
+        Then I play, pause and seek to 0:00
         Then I click on a caption line
         And video position should be updated accordingly
         Then I change video position
@@ -1243,6 +1244,12 @@ class HLSVideoTest(VideoBaseTest):
 
         self.assertIn("Hi, edX welcomes you0.", self.video.captions_text)
 
+        # This is required to load the video
+        self.video.click_player_button('play')
+        # Below 2 steps are required to test the caption line click scenario
+        self.video.click_player_button('pause')
+        self.video.seek('0:00')
+
         for line_no in range(5):
             self.video.click_transcript_line(line_no=line_no)
             self.video.wait_for_position('0:0{}'.format(line_no))
-- 
GitLab