From 33096b46b0b85ef9884756c133f117afc28535ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Fri, 18 Aug 2023 17:03:18 +0200 Subject: [PATCH 1/9] feat(UI): Add thumbnails to the UI --- ui/controls.less | 1 + ui/less/thumbnails.less | 26 ++++ ui/seek_bar.js | 272 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 ui/less/thumbnails.less diff --git a/ui/controls.less b/ui/controls.less index 71bd923a07..5661f6072f 100644 --- a/ui/controls.less +++ b/ui/controls.less @@ -13,6 +13,7 @@ @import "less/overflow_menu.less"; @import "less/ad_controls.less"; @import "less/tooltip.less"; +@import "less/thumbnails.less"; @import (css, inline) "https://fonts.googleapis.com/css?family=Roboto"; // NOTE: Working around google/material-design-icons#958 @import (css, inline) "https://fonts.googleapis.com/icon?family=Material+Icons+Round"; diff --git a/ui/less/thumbnails.less b/ui/less/thumbnails.less new file mode 100644 index 0000000000..1e9d638d9e --- /dev/null +++ b/ui/less/thumbnails.less @@ -0,0 +1,26 @@ +#shaka-player-ui-thumbnail-container { + background-color: black; + border: 1px solid black; + box-shadow: 0 8px 8px 0 rgb(0 0 0 / 50%); + min-width: 150px; + overflow: hidden; + position: absolute; + visibility: hidden; + width: 15%; + z-index: 1; + + #shaka-player-ui-thumbnail-image { + position: absolute; + } + + #shaka-player-ui-thumbnail-time { + background-color: rgb(0 0 0 / 50%); + bottom: 0; + color: white; + font-size: 16px; + left: 0; + position: absolute; + right: 0; + text-align: center; + } +} diff --git a/ui/seek_bar.js b/ui/seek_bar.js index b815d8115b..027812f20d 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -83,6 +83,49 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { */ this.wasPlaying_ = false; + + /** @private {!HTMLElement} */ + this.thumbnailContainer_ = shaka.util.Dom.createHTMLElement('div'); + this.thumbnailContainer_.id = 'shaka-player-ui-thumbnail-container'; + + /** @private {!HTMLImageElement} */ + this.thumbnailImage_ = /** @type {!HTMLImageElement} */ ( + shaka.util.Dom.createHTMLElement('img')); + this.thumbnailImage_.id = 'shaka-player-ui-thumbnail-image'; + this.thumbnailImage_.draggable = false; + + /** @private {!HTMLElement} */ + this.thumbnailTime_ = shaka.util.Dom.createHTMLElement('div'); + this.thumbnailTime_.id = 'shaka-player-ui-thumbnail-time'; + + this.thumbnailContainer_.appendChild(this.thumbnailImage_); + this.thumbnailContainer_.appendChild(this.thumbnailTime_); + this.container.appendChild(this.thumbnailContainer_); + + /** + * Use to see is the bar is moving with touch o keys. + * + * @private {boolean} + */ + this.isMoving_ = false; + + /** + * Thumbnails cache. + * + * @private {Object} + */ + this.thumbnails_ = {}; + + + /** + * The timer is activated to hide the thumbnail. + * + * @private {shaka.util.Timer} + */ + this.hideThumbnailTimer_ = new shaka.util.Timer(() => { + this.hideThumbnail_(); + }); + /** @private {!Array.} */ this.adCuePoints_ = []; @@ -120,6 +163,97 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.onAdCuePointsChanged_(); }); + this.eventManager.listen(this.bar, 'mousemove', (event) => { + if (!this.player.getImageTracks().length) { + this.hideThumbnail_(); + return; + } + const rect = this.bar.getBoundingClientRect(); + const min = parseFloat(this.bar.min); + const max = parseFloat(this.bar.max); + // Pixels from the left of the range element + const mousePosition = event.clientX - rect.left; + // Pixels per unit value of the range element. + const scale = (max - min) / rect.width; + // Mouse position in units, which may be outside the allowed range. + const value = Math.round(min + scale * mousePosition); + // Show Thumbnail + this.showThumbnail_(mousePosition, value); + }); + + this.eventManager.listen(this.bar, 'keydown', (event) => { + this.hideThumbnailTimer_.stop(); + const leftKeyCode = 37; + const rightKeyCode = 39; + // Left and Right only + if (event.keyCode != leftKeyCode && event.keyCode != rightKeyCode) { + return; + } + this.isMoving_ = true; + const min = parseFloat(this.bar.min); + const max = parseFloat(this.bar.max); + if (event.keyCode == leftKeyCode) { + this.bar.value = parseFloat(this.bar.value) - (max - min) * 0.025; + } else if (event.keyCode == rightKeyCode) { + this.bar.value = parseFloat(this.bar.value) + (max - min) * 0.025; + } + const rect = this.bar.getBoundingClientRect(); + const value = Math.round(this.bar.value); + const scale = (max - min) / rect.width; + const position = (value - min) / scale; + this.showThumbnail_(position, value); + event.preventDefault(); + }); + + this.eventManager.listen(this.bar, 'keyup', () => { + if (this.isMoving_) { + this.isMoving_ = false; + this.hideThumbnailTimer_.stop(); + this.hideThumbnailTimer_.tickAfter(/* seconds= */ 0.25); + } + }); + + if (navigator.maxTouchPoints > 0) { + const touchMove = (event) => { + this.isMoving_ = true; + const rect = this.bar.getBoundingClientRect(); + const min = parseFloat(this.bar.min); + const max = parseFloat(this.bar.max); + // Pixels from the left of the range element + const touchPosition = event.changedTouches[0].clientX - rect.left; + // Pixels per unit value of the range element. + const scale = (max - min) / rect.width; + // Mouse position in units, which may be outside the allowed range. + const value = Math.round(min + scale * touchPosition); + // Show Thumbnail + this.showThumbnail_(touchPosition, value); + // Update the bar + this.bar.value = value; + event.preventDefault(); + }; + const touchEnd = () => { + if (this.isMoving_) { + this.isMoving_ = false; + this.hideThumbnail_(); + } + }; + this.eventManager.listen(this.bar, 'touchstart', touchMove); + this.eventManager.listen(this.bar, 'touchmove', touchMove); + this.eventManager.listen(this.bar, 'touchend', touchEnd); + this.eventManager.listen(this.bar, 'touchcancel', touchEnd); + } + + this.eventManager.listen(this.bar, 'blur', () => { + if (this.isMoving_) { + this.isMoving_ = false; + this.hideThumbnail_(); + } + }); + + this.eventManager.listen(this.container, 'mouseleave', () => { + this.hideThumbnail_(); + }); + // Initialize seek state and label. this.setValue(this.video.currentTime); this.update(); @@ -376,6 +510,144 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { updateAriaLabel_() { this.bar.ariaLabel = this.localization.resolve(shaka.ui.Locales.Ids.SEEK); } + + + /** + * @private + */ + async showThumbnail_(pixelPosition, value) { + const thumbnailTrack = this.getThumbnailTrack_(); + if (!thumbnailTrack) { + this.hideThumbnail_(); + return; + } + if (value < 0) { + value = 0; + } + let thumbnail = this.thumbnails_[value]; + this.thumbnailTime_.textContent = this.timeFormater_(value); + const offsetTop = -10; + const width = this.thumbnailContainer_.clientWidth; + let height = Math.floor(width * 9 / 16); + this.thumbnailContainer_.style.height = height + 'px'; + this.thumbnailContainer_.style.top = -(height - offsetTop) + 'px'; + const leftPosition = Math.min(this.bar.offsetWidth - width, + Math.max(0, pixelPosition - (width / 2))); + this.thumbnailContainer_.style.left = leftPosition + 'px'; + this.thumbnailContainer_.style.visibility = 'visible'; + if (!thumbnail) { + const seekRange = this.player.seekRange(); + const playerValue = Math.max(Math.ceil(seekRange.start), + Math.min(Math.floor(seekRange.end), value)); + thumbnail = + await this.player.getThumbnails(thumbnailTrack.id, playerValue); + this.thumbnails_[value] = thumbnail; + } + if (!thumbnail || !thumbnail.uris.length) { + this.hideThumbnail_(); + return; + } + const uri = thumbnail.uris[0].split('#xywh=')[0]; + if (uri !== this.thumbnailImage_.src) { + try { + this.thumbnailContainer_.removeChild(this.thumbnailImage_); + } catch (e) { + // The image is not a child + } + this.thumbnailImage_ = /** @type {!HTMLImageElement} */ ( + shaka.util.Dom.createHTMLElement('img')); + this.thumbnailImage_.id = 'shaka-player-ui-thumbnail-image'; + this.thumbnailImage_.draggable = false; + this.thumbnailImage_.src = uri; + this.thumbnailContainer_.insertBefore(this.thumbnailImage_, + this.thumbnailContainer_.firstChild); + } + const scale = width / thumbnail.width; + if (thumbnail.imageHeight) { + this.thumbnailImage_.height = thumbnail.imageHeight; + } else if (!thumbnail.sprite) { + this.thumbnailImage_.style.height = '100%'; + this.thumbnailImage_.style.objectFit = 'contain'; + } + if (thumbnail.imageWidth) { + this.thumbnailImage_.width = thumbnail.imageWidth; + } else if (!thumbnail.sprite) { + this.thumbnailImage_.style.width = '100%'; + this.thumbnailImage_.style.objectFit = 'contain'; + } + this.thumbnailImage_.style.left = '-' + scale * thumbnail.positionX + 'px'; + this.thumbnailImage_.style.top = '-' + scale * thumbnail.positionY + 'px'; + this.thumbnailImage_.style.transform = 'scale(' + scale + ')'; + this.thumbnailImage_.style.transformOrigin = 'left top'; + // Update container height and top + height = Math.floor(width * thumbnail.height / thumbnail.width); + this.thumbnailContainer_.style.height = height + 'px'; + this.thumbnailContainer_.style.top = -(height - offsetTop) + 'px'; + } + + + /** + * @return {?shaka.extern.Track} The thumbnail track. + * @private + */ + getThumbnailTrack_() { + const imageTracks = this.player.getImageTracks(); + if (!imageTracks.length) { + return null; + } + const mimeTypesPreference = [ + 'image/avif', + 'image/webp', + 'image/jpeg', + 'image/png', + 'image/svg+xml', + ]; + for (const mimeType of mimeTypesPreference) { + const estimatedBandwidth = this.player.getStats().estimatedBandwidth; + const bestOptions = imageTracks.filter((track) => { + return track.mimeType.toLowerCase() === mimeType && + track.bandwidth < estimatedBandwidth * 0.01; + }).sort((a, b) => { + return a.bandwidth - b.bandwidth; + }).reverse(); + if (bestOptions && bestOptions.length) { + return bestOptions[0]; + } + } + return imageTracks[0]; + } + + + /** + * @private + */ + hideThumbnail_() { + this.thumbnailContainer_.style.visibility = 'hidden'; + this.thumbnailTime_.textContent = ''; + } + + + /** + * @param {number} totalSeconds + * @private + */ + timeFormater_(totalSeconds) { + const secondsNumber = Math.round(totalSeconds); + const hours = Math.floor(secondsNumber / 3600); + let minutes = Math.floor((secondsNumber - (hours * 3600)) / 60); + let seconds = secondsNumber - (hours * 3600) - (minutes * 60); + if (seconds < 10) { + seconds = '0' + seconds; + } + if (hours > 0) { + if (minutes < 10) { + minutes = '0' + minutes; + } + return hours + ':' + minutes + ':' + seconds; + } else { + return minutes + ':' + seconds; + } + } }; From 38ecbf26bfcdad0ce7eda4f43bb6c40e010ef61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Fri, 18 Aug 2023 17:16:23 +0200 Subject: [PATCH 2/9] Add live support --- ui/seek_bar.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/seek_bar.js b/ui/seek_bar.js index 027812f20d..75c8ec511f 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -525,7 +525,13 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { value = 0; } let thumbnail = this.thumbnails_[value]; - this.thumbnailTime_.textContent = this.timeFormater_(value); + const seekRange = this.player.seekRange(); + if (this.player.isLive()) { + this.thumbnailTime_.textContent = + '-' + this.timeFormater_(seekRange.end - value); + } else { + this.thumbnailTime_.textContent = this.timeFormater_(value); + } const offsetTop = -10; const width = this.thumbnailContainer_.clientWidth; let height = Math.floor(width * 9 / 16); @@ -536,7 +542,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.thumbnailContainer_.style.left = leftPosition + 'px'; this.thumbnailContainer_.style.visibility = 'visible'; if (!thumbnail) { - const seekRange = this.player.seekRange(); const playerValue = Math.max(Math.ceil(seekRange.start), Math.min(Math.floor(seekRange.end), value)); thumbnail = From 3922db3c7f31fa71eed91356041b95facab6795e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 11:18:21 +0200 Subject: [PATCH 3/9] Fixes part 1 --- ui/seek_bar.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ui/seek_bar.js b/ui/seek_bar.js index 75c8ec511f..fc7b715826 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -103,7 +103,7 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.container.appendChild(this.thumbnailContainer_); /** - * Use to see is the bar is moving with touch o keys. + * True if the bar is moving due to touchscreen or keyboard events. * * @private {boolean} */ @@ -527,10 +527,16 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { let thumbnail = this.thumbnails_[value]; const seekRange = this.player.seekRange(); if (this.player.isLive()) { - this.thumbnailTime_.textContent = - '-' + this.timeFormater_(seekRange.end - value); + const totalSeconds = seekRange.end - value; + if (totalSeconds < 1) { + this.thumbnailTime_.textContent = + this.localization.resolve(shaka.ui.Locales.Ids.LIVE); + } else { + this.thumbnailTime_.textContent = + '-' + this.timeFormatter_(totalSeconds); + } } else { - this.thumbnailTime_.textContent = this.timeFormater_(value); + this.thumbnailTime_.textContent = this.timeFormatter_(value); } const offsetTop = -10; const width = this.thumbnailContainer_.clientWidth; @@ -613,8 +619,8 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { return track.mimeType.toLowerCase() === mimeType && track.bandwidth < estimatedBandwidth * 0.01; }).sort((a, b) => { - return a.bandwidth - b.bandwidth; - }).reverse(); + return b.bandwidth - a.bandwidth; + }); if (bestOptions && bestOptions.length) { return bestOptions[0]; } @@ -636,7 +642,7 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { * @param {number} totalSeconds * @private */ - timeFormater_(totalSeconds) { + timeFormatter_(totalSeconds) { const secondsNumber = Math.round(totalSeconds); const hours = Math.floor(secondsNumber / 3600); let minutes = Math.floor((secondsNumber - (hours * 3600)) / 60); From 68366a9a20688293cf3ac292e825b94ed04de257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 11:47:16 +0200 Subject: [PATCH 4/9] Fixes part 2 --- ui/range_element.js | 8 +++++ ui/seek_bar.js | 81 ++++++++++----------------------------------- 2 files changed, 26 insertions(+), 63 deletions(-) diff --git a/ui/range_element.js b/ui/range_element.js index dd930e421e..6c0601f754 100644 --- a/ui/range_element.js +++ b/ui/range_element.js @@ -104,6 +104,14 @@ shaka.ui.RangeElement = class extends shaka.ui.Element { } }); + this.eventManager.listen(this.bar, 'touchcancel', (e) => { + if (this.isChanging_) { + this.isChanging_ = false; + this.setBarValueForTouch_(e); + this.onChangeEnd(); + } + }); + this.eventManager.listen(this.bar, 'mouseup', () => { if (this.isChanging_) { this.isChanging_ = false; diff --git a/ui/seek_bar.js b/ui/seek_bar.js index fc7b715826..f6bc275c59 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -181,68 +181,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.showThumbnail_(mousePosition, value); }); - this.eventManager.listen(this.bar, 'keydown', (event) => { - this.hideThumbnailTimer_.stop(); - const leftKeyCode = 37; - const rightKeyCode = 39; - // Left and Right only - if (event.keyCode != leftKeyCode && event.keyCode != rightKeyCode) { - return; - } - this.isMoving_ = true; - const min = parseFloat(this.bar.min); - const max = parseFloat(this.bar.max); - if (event.keyCode == leftKeyCode) { - this.bar.value = parseFloat(this.bar.value) - (max - min) * 0.025; - } else if (event.keyCode == rightKeyCode) { - this.bar.value = parseFloat(this.bar.value) + (max - min) * 0.025; - } - const rect = this.bar.getBoundingClientRect(); - const value = Math.round(this.bar.value); - const scale = (max - min) / rect.width; - const position = (value - min) / scale; - this.showThumbnail_(position, value); - event.preventDefault(); - }); - - this.eventManager.listen(this.bar, 'keyup', () => { - if (this.isMoving_) { - this.isMoving_ = false; - this.hideThumbnailTimer_.stop(); - this.hideThumbnailTimer_.tickAfter(/* seconds= */ 0.25); - } - }); - - if (navigator.maxTouchPoints > 0) { - const touchMove = (event) => { - this.isMoving_ = true; - const rect = this.bar.getBoundingClientRect(); - const min = parseFloat(this.bar.min); - const max = parseFloat(this.bar.max); - // Pixels from the left of the range element - const touchPosition = event.changedTouches[0].clientX - rect.left; - // Pixels per unit value of the range element. - const scale = (max - min) / rect.width; - // Mouse position in units, which may be outside the allowed range. - const value = Math.round(min + scale * touchPosition); - // Show Thumbnail - this.showThumbnail_(touchPosition, value); - // Update the bar - this.bar.value = value; - event.preventDefault(); - }; - const touchEnd = () => { - if (this.isMoving_) { - this.isMoving_ = false; - this.hideThumbnail_(); - } - }; - this.eventManager.listen(this.bar, 'touchstart', touchMove); - this.eventManager.listen(this.bar, 'touchmove', touchMove); - this.eventManager.listen(this.bar, 'touchend', touchEnd); - this.eventManager.listen(this.bar, 'touchcancel', touchEnd); - } - this.eventManager.listen(this.bar, 'blur', () => { if (this.isMoving_) { this.isMoving_ = false; @@ -251,7 +189,8 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { }); this.eventManager.listen(this.container, 'mouseleave', () => { - this.hideThumbnail_(); + this.hideThumbnailTimer_.stop(); + this.hideThumbnailTimer_.tickAfter(/* seconds= */ 0.25); }); // Initialize seek state and label. @@ -287,6 +226,8 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.wasPlaying_ = !this.video.paused; this.controls.setSeeking(true); this.video.pause(); + this.hideThumbnailTimer_.stop(); + this.isMoving_ = true; } /** @@ -314,6 +255,14 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { // Calling |start| on an already pending timer will cancel the old request // and start the new one. this.seekTimer_.tickAfter(/* seconds= */ 0.125); + + const min = parseFloat(this.bar.min); + const max = parseFloat(this.bar.max); + const rect = this.bar.getBoundingClientRect(); + const value = Math.round(this.getValue()); + const scale = (max - min) / rect.width; + const position = (value - min) / scale; + this.showThumbnail_(position, value); } /** @@ -331,6 +280,12 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { if (this.wasPlaying_) { this.video.play(); } + + if (this.isMoving_) { + this.isMoving_ = false; + this.hideThumbnailTimer_.stop(); + this.hideThumbnailTimer_.tickAfter(/* seconds= */ 0.25); + } } /** From 3827bad33806b6d683f557f4233f7a1c53a8fad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 12:17:37 +0200 Subject: [PATCH 5/9] More simplifications --- ui/range_element.js | 7 +++++++ ui/seek_bar.js | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/range_element.js b/ui/range_element.js index 6c0601f754..4157400829 100644 --- a/ui/range_element.js +++ b/ui/range_element.js @@ -119,6 +119,13 @@ shaka.ui.RangeElement = class extends shaka.ui.Element { } }); + this.eventManager.listen(this.bar, 'blur', () => { + if (this.isChanging_) { + this.isChanging_ = false; + this.onChangeEnd(); + } + }); + this.eventManager.listen(this.bar, 'contextmenu', (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/ui/seek_bar.js b/ui/seek_bar.js index f6bc275c59..868861288f 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -181,13 +181,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { this.showThumbnail_(mousePosition, value); }); - this.eventManager.listen(this.bar, 'blur', () => { - if (this.isMoving_) { - this.isMoving_ = false; - this.hideThumbnail_(); - } - }); - this.eventManager.listen(this.container, 'mouseleave', () => { this.hideThumbnailTimer_.stop(); this.hideThumbnailTimer_.tickAfter(/* seconds= */ 0.25); From 6eb6266fd088f1c7c40efb201101cd3e3c3a0c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 12:19:36 +0200 Subject: [PATCH 6/9] Fix non-thumbnails streams --- ui/seek_bar.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ui/seek_bar.js b/ui/seek_bar.js index 868861288f..7b4e74b6fb 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -249,13 +249,17 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { // and start the new one. this.seekTimer_.tickAfter(/* seconds= */ 0.125); - const min = parseFloat(this.bar.min); - const max = parseFloat(this.bar.max); - const rect = this.bar.getBoundingClientRect(); - const value = Math.round(this.getValue()); - const scale = (max - min) / rect.width; - const position = (value - min) / scale; - this.showThumbnail_(position, value); + if (this.player.getImageTracks().length) { + const min = parseFloat(this.bar.min); + const max = parseFloat(this.bar.max); + const rect = this.bar.getBoundingClientRect(); + const value = Math.round(this.getValue()); + const scale = (max - min) / rect.width; + const position = (value - min) / scale; + this.showThumbnail_(position, value); + } else { + this.hideThumbnail_(); + } } /** From dbc2fcc7dc99a1e2ccf1edce79e8a0de868bdd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 12:34:42 +0200 Subject: [PATCH 7/9] Remove the thumbnails cache --- ui/seek_bar.js | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/ui/seek_bar.js b/ui/seek_bar.js index 7b4e74b6fb..70999a1dc1 100644 --- a/ui/seek_bar.js +++ b/ui/seek_bar.js @@ -109,14 +109,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { */ this.isMoving_ = false; - /** - * Thumbnails cache. - * - * @private {Object} - */ - this.thumbnails_ = {}; - - /** * The timer is activated to hide the thumbnail. * @@ -476,8 +468,15 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { if (value < 0) { value = 0; } - let thumbnail = this.thumbnails_[value]; const seekRange = this.player.seekRange(); + const playerValue = Math.max(Math.ceil(seekRange.start), + Math.min(Math.floor(seekRange.end), value)); + const thumbnail = + await this.player.getThumbnails(thumbnailTrack.id, playerValue); + if (!thumbnail || !thumbnail.uris.length) { + this.hideThumbnail_(); + return; + } if (this.player.isLive()) { const totalSeconds = seekRange.end - value; if (totalSeconds < 1) { @@ -499,17 +498,6 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement { Math.max(0, pixelPosition - (width / 2))); this.thumbnailContainer_.style.left = leftPosition + 'px'; this.thumbnailContainer_.style.visibility = 'visible'; - if (!thumbnail) { - const playerValue = Math.max(Math.ceil(seekRange.start), - Math.min(Math.floor(seekRange.end), value)); - thumbnail = - await this.player.getThumbnails(thumbnailTrack.id, playerValue); - this.thumbnails_[value] = thumbnail; - } - if (!thumbnail || !thumbnail.uris.length) { - this.hideThumbnail_(); - return; - } const uri = thumbnail.uris[0].split('#xywh=')[0]; if (uri !== this.thumbnailImage_.src) { try { From ec5a4a36e2e347d1a5585966b1a2e8f94e1c1819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 12:53:12 +0200 Subject: [PATCH 8/9] Add new asset with external thumbnails --- demo/common/asset.js | 11 +++++++++++ demo/common/assets.js | 10 ++++++++++ demo/main.js | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/demo/common/asset.js b/demo/common/asset.js index 201e9e0a84..c1da276790 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -45,6 +45,8 @@ const ShakaDemoAssetInfo = class { this.disabled = false; /** @type {!Array.} */ this.extraText = []; + /** @type {!Array.} */ + this.extraThumbnail = []; /** @type {?string} */ this.certificateUri = null; /** @type {?string} */ @@ -302,6 +304,15 @@ const ShakaDemoAssetInfo = class { return this; } + /** + * @param {string} ) + * @return {!ShakaDemoAssetInfo} + */ + addExtraThumbnail(uri) { + this.extraThumbnail.push(uri); + return this; + } + /** * If this is called, the asset will be focused on by the integration tests. * @return {!ShakaDemoAssetInfo} diff --git a/demo/common/assets.js b/demo/common/assets.js index b68bde0174..0002ea3323 100644 --- a/demo/common/assets.js +++ b/demo/common/assets.js @@ -963,6 +963,16 @@ shakaAssets.testAssets = [ .addFeature(shakaAssets.Feature.HLS) .addFeature(shakaAssets.Feature.MP2TS) .addFeature(shakaAssets.Feature.OFFLINE), + new ShakaDemoAssetInfo( + /* name= */ 'Art of Motion (DASH) (external thumbnails)', + /* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/art_of_motion.png', + /* manifestUri= */ 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + /* source= */ shakaAssets.Source.BITCODIN) + .addFeature(shakaAssets.Feature.DASH) + .addFeature(shakaAssets.Feature.HIGH_DEFINITION) + .addFeature(shakaAssets.Feature.MP4) + .addFeature(shakaAssets.Feature.THUMBNAILS) + .addExtraThumbnail('https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/thumbnails/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.vtt'), // End bitcodin assets }}} // MetaCDN assets {{{ diff --git a/demo/main.js b/demo/main.js index abe7142531..83a3193daa 100644 --- a/demo/main.js +++ b/demo/main.js @@ -1358,6 +1358,10 @@ shakaDemo.Main = class { this.video_.poster = shakaDemo.Main.audioOnlyPoster_; } + for (const extraThumbnail of asset.extraThumbnail) { + this.player_.addThumbnailsTrack(extraThumbnail); + } + // If the asset has an ad tag attached to it, load the ads const adManager = this.player_.getAdManager(); if (adManager && asset.adTagUri) { From 9926df0526b0e12a1232d3d5385432a7bf96e997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=81lvaro=20Velad=20Galva=CC=81n?= Date: Tue, 22 Aug 2023 13:00:56 +0200 Subject: [PATCH 9/9] Fix build error --- demo/common/asset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/common/asset.js b/demo/common/asset.js index c1da276790..199e050644 100644 --- a/demo/common/asset.js +++ b/demo/common/asset.js @@ -305,7 +305,7 @@ const ShakaDemoAssetInfo = class { } /** - * @param {string} ) + * @param {string} uri * @return {!ShakaDemoAssetInfo} */ addExtraThumbnail(uri) {