@gcorevideo/player 2.22.31 → 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -43303,7 +43303,7 @@ class Player {
43303
43303
  }
43304
43304
  }
43305
43305
 
43306
- var version$1 = "2.22.31";
43306
+ var version$1 = "2.23.0";
43307
43307
 
43308
43308
  var packages = {
43309
43309
  "node_modules/@clappr/core": {
@@ -43727,8 +43727,8 @@ class MediaControl extends UICorePlugin {
43727
43727
  return this.userDisabled || playbackIsNOOP;
43728
43728
  }
43729
43729
  /**
43730
+ * Use in mediacontrol-based plugins to access the active container
43730
43731
  * @internal
43731
- * @deprecated Use core.activeContainer directly
43732
43732
  */
43733
43733
  get container() {
43734
43734
  return this.core.activeContainer;
@@ -43995,16 +43995,16 @@ class MediaControl extends UICorePlugin {
43995
43995
  this.applyButtonStyle(this.$playStopToggle);
43996
43996
  }
43997
43997
  mousemoveOnSeekBar(event) {
43998
+ const offset = MediaControl.getPageX(event) -
43999
+ (this.$seekBarContainer.offset().left ?? 0); // TODO check if the result can be negative
44000
+ const hoverOffset = offset -
44001
+ (this.$seekBarHover.width() ?? 0) / 2;
44002
+ const pos = offset ? Math.min(1, Math.max(offset / this.$seekBarContainer.width(), 0)) : 0;
43998
44003
  if (this.settings.seekEnabled) {
43999
- // assert.ok(this.$seekBarHover && this.$seekBarContainer, 'seek bar elements must be present');
44000
- if (this.$seekBarHover && this.$seekBarContainer) {
44001
- const offsetX = MediaControl.getPageX(event) -
44002
- this.$seekBarContainer.offset().left -
44003
- this.$seekBarHover.width() / 2;
44004
- this.$seekBarHover.css({ left: offsetX });
44005
- }
44004
+ // TODO test that it works when the element does not exist
44005
+ this.$seekBarHover.css({ left: hoverOffset });
44006
44006
  }
44007
- this.trigger(Events$1.MEDIACONTROL_MOUSEMOVE_SEEKBAR, event);
44007
+ this.trigger(Events$1.MEDIACONTROL_MOUSEMOVE_SEEKBAR, event, pos);
44008
44008
  }
44009
44009
  mouseleaveOnSeekBar(event) {
44010
44010
  this.trigger(Events$1.MEDIACONTROL_MOUSELEAVE_SEEKBAR, event);
@@ -44428,17 +44428,8 @@ class MediaControl extends UICorePlugin {
44428
44428
  else {
44429
44429
  panel.append(element);
44430
44430
  }
44431
- return;
44432
44431
  }
44433
44432
  }
44434
- /**
44435
- * @deprecated Use {@link MediaControl.mount} instead
44436
- * @param name
44437
- * @param element
44438
- */
44439
- putElement(name, element) {
44440
- this.mount(name, element);
44441
- }
44442
44433
  /**
44443
44434
  * Toggle the visibility of a media control element
44444
44435
  * @param name - The name of the media control element
@@ -48377,6 +48368,14 @@ class Clips extends UICorePlugin {
48377
48368
  this.render();
48378
48369
  return super.enable();
48379
48370
  }
48371
+ /**
48372
+ * Get the text of the clip at the given time
48373
+ * @param time - The time to get the text for
48374
+ * @returns The text of the clip at the given time
48375
+ */
48376
+ getText(time) {
48377
+ return this.clips.find((clip) => clip.start <= time && clip.end >= time)?.text;
48378
+ }
48380
48379
  onCoreReady() {
48381
48380
  trace(`${T$d} onCoreReady`);
48382
48381
  const mediaControl = this.core.getPlugin('media_control');
@@ -51967,12 +51966,31 @@ function requireParseSrt () {
51967
51966
  var parseSrtExports = requireParseSrt();
51968
51967
  const parseSRT = /*@__PURE__*/getDefaultExportFromCjs$1(parseSrtExports);
51969
51968
 
51970
- const pluginHtml = "<div class=\"thumbnails-text\"></div>\n<% if (backdropHeight) { %>\n <div class=\"backdrop\" style=\"height: <%= backdropHeight %>px;\">\n <div class=\"carousel\"></div>\n </div>\n<% }; %>\n<% if (spotlightHeight) { %>\n <div class=\"spotlight\" style=\"height: <%= spotlightHeight %>px;\">\n </div>\n<% }; %>\n";
51969
+ const pluginHtml = "<div class=\"thumbnails-text\" id=\"thumbnails-text\"></div>\n<div class=\"backdrop\" id=\"thumbnails-backdrop\">\n <div class=\"carousel\" id=\"thumbnails-carousel\"></div>\n</div>\n<div class=\"spotlight\" id=\"thumbnails-spotlight\"></div>\n";
51970
+
51971
+ function loadImageDimensions(url) {
51972
+ return new Promise((resolve, reject) => {
51973
+ const img = new Image();
51974
+ img.src = url;
51975
+ img.onload = () => {
51976
+ resolve({ width: img.width, height: img.height });
51977
+ };
51978
+ img.onerror = () => {
51979
+ reject(new Error('Failed to load image'));
51980
+ };
51981
+ });
51982
+ }
51971
51983
 
51972
51984
  const T$1 = 'plugins.thumbnails';
51973
51985
  /**
51974
51986
  * `PLUGIN` that displays the thumbnails of the video when available.
51975
51987
  * @beta
51988
+ * @remarks
51989
+ * The plugin needs specially crafted VTT file with a thumbnail sprite sheet to work.
51990
+ * The VTT consist of timestamp records followed by a thumbnail area
51991
+ *
51992
+ * Configuration options - {@link ThumbnailsPluginSettings}
51993
+ *
51976
51994
  * @example
51977
51995
  * ```ts
51978
51996
  * import { Thumbnails } from '@gcorevideo/player'
@@ -51993,19 +52011,15 @@ const T$1 = 'plugins.thumbnails';
51993
52011
  * ```
51994
52012
  */
51995
52013
  class Thumbnails extends UICorePlugin {
51996
- _$spotlight = null;
51997
- _$backdrop = null;
51998
- $container = null;
51999
- $img = null;
52000
- _$carousel = null;
52001
- $textThumbnail = null;
52002
- _$backdropCarouselImgs = [];
52014
+ $backdropCarouselImgs = [];
52003
52015
  spriteSheetHeight = 0;
52004
- _hoverPosition = 0;
52005
- _show = false;
52006
- _thumbsLoaded = false;
52007
- _oldContainer = null;
52008
- _thumbs = [];
52016
+ spriteSheetWidth = 0;
52017
+ hoverPosition = 0;
52018
+ showing = false;
52019
+ thumbsLoaded = false;
52020
+ spotlightHeight = 0;
52021
+ backdropHeight = 0;
52022
+ thumbs = [];
52009
52023
  /**
52010
52024
  * @internal
52011
52025
  */
@@ -52023,10 +52037,14 @@ class Thumbnails extends UICorePlugin {
52023
52037
  */
52024
52038
  get attributes() {
52025
52039
  return {
52026
- class: this.name,
52040
+ class: 'scrub-thumbnails',
52027
52041
  };
52028
52042
  }
52029
52043
  static template = tmpl(pluginHtml);
52044
+ constructor(core) {
52045
+ super(core);
52046
+ this.backdropHeight = this.options.thumbnails?.backdropHeight ?? 0;
52047
+ }
52030
52048
  /*
52031
52049
  * Helper to build the "thumbs" property for a sprite sheet.
52032
52050
  *
@@ -52038,25 +52056,21 @@ class Thumbnails extends UICorePlugin {
52038
52056
  * timeInterval- The interval (in seconds) between the thumbnails.
52039
52057
  * startTime- The time (in seconds) that the first thumbnail represents. (defaults to 0)
52040
52058
  */
52041
- // buildSpriteConfig(vtt, spriteSheetUrl, numThumbs, thumbWidth, thumbHeight, numColumns, timeInterval, startTime) {
52042
- buildSpriteConfig(vtt, spriteSheetUrl) {
52059
+ buildSpriteConfig(vtt, baseUrl) {
52043
52060
  const thumbs = [];
52044
- // let coor: string[] = [];
52045
52061
  for (const vt of vtt) {
52046
52062
  const el = vt.text;
52047
- // if (el && el.search(/\d*,\d*,\d*,\d*/g) > -1) {
52048
- // el = el.match(/\d*,\d*,\d*,\d*/g)[0];
52049
- // coor = el.split(',');
52050
- // }
52051
52063
  if (el) {
52052
- const m = el.match(/xywh=\d*,\d*,\d*,\d*/g);
52064
+ const m = el.match(/(\w+)#xywh=(\d+,\d+,\d+,\d+)/);
52053
52065
  if (m) {
52054
- const coor = m[0].split(',');
52066
+ const coor = m[2].split(',');
52055
52067
  const w = parseInt(coor[2], 10);
52056
52068
  const h = parseInt(coor[3], 10);
52057
52069
  if (w > 0 && h > 0) {
52058
52070
  thumbs.push({
52059
- url: spriteSheetUrl,
52071
+ // TODO handle relative URLs
52072
+ // url: new URL(m[0], baseUrl).toString(),
52073
+ url: baseUrl,
52060
52074
  time: vt.start,
52061
52075
  w,
52062
52076
  h,
@@ -52069,242 +52083,147 @@ class Thumbnails extends UICorePlugin {
52069
52083
  }
52070
52084
  return thumbs;
52071
52085
  }
52072
- // TODO check if seek enabled
52073
52086
  /**
52074
52087
  * @internal
52075
52088
  */
52076
52089
  bindEvents() {
52077
- this.listenToOnce(this.core, Events$1.CORE_READY, this._onCoreReady);
52078
- this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_MOUSEMOVE_SEEKBAR, this._onMouseMove);
52079
- this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_MOUSELEAVE_SEEKBAR, this._onMouseLeave);
52080
- this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_RENDERED, this._init);
52081
- this.listenTo(this.core.mediaControl, Events$1.MEDIACONTROL_CONTAINERCHANGED, this._onMediaControlContainerChanged);
52090
+ this.listenToOnce(this.core, Events$1.CORE_READY, this.onCoreReady);
52082
52091
  }
52083
- _bindContainerEvents() {
52084
- if (this._oldContainer) {
52085
- this.stopListening(this._oldContainer, Events$1.CONTAINER_TIMEUPDATE, this._renderPlugin);
52086
- }
52087
- this._oldContainer = this.core.mediaControl.container;
52088
- this.listenTo(this.core.mediaControl.container, Events$1.CONTAINER_TIMEUPDATE, this._renderPlugin);
52092
+ bindContainerEvents(container) {
52093
+ this.listenTo(container, Events$1.CONTAINER_TIMEUPDATE, this.update);
52089
52094
  }
52090
- _onCoreReady() {
52091
- try {
52092
- if (!this.options.thumbnails ||
52093
- !this.options.thumbnails.sprite ||
52094
- !this.options.thumbnails.vtt) {
52095
- this.destroy();
52096
- return;
52097
- }
52098
- }
52099
- catch (error) {
52100
- reportError(error);
52095
+ onCoreReady() {
52096
+ const mediaControl = this.core.getPlugin('media_control');
52097
+ assert(mediaControl, `MediaControl is required for ${this.name} plugin to work`);
52098
+ if (!this.options.thumbnails ||
52099
+ !this.options.thumbnails.sprite ||
52100
+ !this.options.thumbnails.vtt) {
52101
+ trace(`${T$1} misconfigured: options.thumbnails.sprite and options.thumbnails.vtt are required`);
52102
+ this.destroy();
52101
52103
  return;
52102
52104
  }
52103
- // TODO options
52104
- const spriteSheet = this.options.thumbnails.sprite;
52105
- this._thumbs = this.buildSpriteConfig(parseSRT(this.options.thumbnails.vtt), spriteSheet);
52106
- if (!this._thumbs.length) {
52105
+ const { sprite: spriteSheet, vtt } = this.options.thumbnails;
52106
+ this.thumbs = this.buildSpriteConfig(parseSRT(vtt), spriteSheet);
52107
+ if (!this.thumbs.length) {
52108
+ trace(`${T$1} failed to parse the sprite sheet`);
52107
52109
  this.destroy();
52108
52110
  return;
52109
52111
  }
52112
+ this.spotlightHeight = this.options.thumbnails?.spotlightHeight ?? 0;
52110
52113
  this.loadSpriteSheet(spriteSheet).then(() => {
52111
- this._thumbsLoaded = true;
52112
- this.core.options.thumbnails.spotlightHeight = this._thumbs[0].h;
52113
- this._init();
52114
+ this.thumbsLoaded = true;
52115
+ this.spotlightHeight = this.spotlightHeight
52116
+ ? Math.min(this.spotlightHeight, this.thumbs[0].h)
52117
+ : this.thumbs[0].h;
52118
+ this.init();
52114
52119
  });
52120
+ this.listenTo(mediaControl, Events$1.MEDIACONTROL_MOUSEMOVE_SEEKBAR, this.onMouseMoveSeekbar);
52121
+ this.listenTo(mediaControl, Events$1.MEDIACONTROL_MOUSELEAVE_SEEKBAR, this.onMouseLeave);
52122
+ this.listenTo(mediaControl, Events$1.MEDIACONTROL_RENDERED, this.init);
52123
+ this.listenTo(mediaControl, Events$1.MEDIACONTROL_CONTAINERCHANGED, () => this.onContainerChanged(mediaControl.container));
52115
52124
  }
52116
52125
  async loadSpriteSheet(spriteSheetUrl) {
52117
- return new Promise((resolve, reject) => {
52118
- const img = new Image();
52119
- img.onload = () => {
52120
- this.spriteSheetHeight = img.height;
52121
- resolve();
52122
- };
52123
- img.onerror = reject;
52124
- img.src = spriteSheetUrl;
52126
+ return loadImageDimensions(spriteSheetUrl).then(({ height, width }) => {
52127
+ this.spriteSheetHeight = height;
52128
+ this.spriteSheetWidth = width;
52125
52129
  });
52126
52130
  }
52127
- _onMediaControlContainerChanged() {
52128
- this._bindContainerEvents();
52131
+ onContainerChanged(container) {
52132
+ this.bindContainerEvents(container);
52129
52133
  }
52130
- _init() {
52131
- if (!this._thumbsLoaded) {
52132
- // _init() will be called when the thumbs are loaded,
52134
+ init() {
52135
+ if (!this.thumbsLoaded) {
52136
+ // init() will be called when the thumbs are loaded,
52133
52137
  // and whenever the media control rendered event is fired as just before this the dom elements get wiped in IE (https://github.com/tjenkinson/clappr-thumbnails-plugin/issues/5)
52134
52138
  return;
52135
52139
  }
52136
52140
  // Init the backdropCarousel as array to keep reference of thumbnail images
52137
- this._$backdropCarouselImgs = [];
52138
- // create/recreate the dom elements for the plugin
52139
- this._createElements();
52140
- this._loadBackdrop();
52141
- this._renderPlugin();
52142
- }
52143
- _getOptions() {
52144
- if (!('thumbnails' in this.core.options)) {
52145
- throw "'thumbnail property missing from options object.";
52146
- }
52147
- return this.core.options.thumbnails;
52148
- }
52149
- _appendElToMediaControl() {
52150
- // insert after the background
52151
- this.core.mediaControl.$el.find('.seek-time').css('bottom', 56);
52152
- this.core.mediaControl.$el.first().after(this.el);
52153
- }
52154
- _onMouseMove(e) {
52155
- // trace(`${T} _onMouseMove`, {
52156
- // e: (e as any).name,
52157
- // t: typeof e,
52158
- // t2: typeof arguments[1],
52159
- // });
52160
- this._calculateHoverPosition(e);
52161
- this._show = true;
52162
- this._renderPlugin();
52163
- }
52164
- _onMouseLeave() {
52165
- this._show = false;
52166
- this._renderPlugin();
52167
- }
52168
- _calculateHoverPosition(e) {
52169
- const offset = getPageX(e) - this.core.mediaControl.$seekBarContainer.offset().left;
52170
- // proportion into the seek bar that the mouse is hovered over 0-1
52171
- this._hoverPosition = Math.min(1, Math.max(offset / this.core.mediaControl.$seekBarContainer.width(), 0));
52172
- }
52173
- // private _buildThumbsFromOptions() {
52174
- // const thumbs = this._thumbs;
52175
- // const promises = thumbs.map((thumb) => {
52176
- // return this._addThumbFromSrc(thumb);
52177
- // });
52178
- // return Promise.all(promises);
52179
- // }
52180
- // private _addThumbFromSrc(thumbSrc) {
52181
- // return new Promise((resolve, reject) => {
52182
- // const img = new Image();
52183
- // img.onload = () => {
52184
- // resolve(img);
52185
- // };
52186
- // img.onerror = reject;
52187
- // img.src = thumbSrc.url;
52188
- // }).then((img) => {
52189
- // const startTime = thumbSrc.time;
52190
- // // determine the thumb index
52191
- // let index = null;
52192
- // this._thumbs.some((thumb, i) => {
52193
- // if (startTime < thumb.time) {
52194
- // index = i;
52195
- // return true;
52196
- // }
52197
- // return false;
52198
- // });
52199
- // if (index === null) {
52200
- // index = this._thumbs.length;
52201
- // }
52202
- // const next = index < this._thumbs.length ? this._thumbs[index] : null;
52203
- // const prev = index > 0 ? this._thumbs[index - 1] : null;
52204
- // if (prev) {
52205
- // // update the duration of the previous thumbnail
52206
- // prev.duration = startTime - prev.time;
52207
- // }
52208
- // // the duration this thumb lasts for
52209
- // // if it is the last thumb then duration will be null
52210
- // const duration = next ? next.time - thumbSrc.time : null;
52211
- // const imageW = img.width;
52212
- // const imageH = img.height;
52213
- // const thumb = {
52214
- // imageW: imageW, // actual width of image
52215
- // imageH: imageH, // actual height of image
52216
- // x: thumbSrc.x || 0, // x coord in image of sprite
52217
- // y: thumbSrc.y || 0, // y coord in image of sprite
52218
- // w: thumbSrc.w || imageW, // width of sprite
52219
- // h: thumbSrc.h || imageH, // height of sprite
52220
- // url: thumbSrc.url,
52221
- // time: startTime, // time this thumb represents
52222
- // duration: duration, // how long (from time) this thumb represents
52223
- // src: thumbSrc
52224
- // };
52225
- // this._thumbs.splice(index, 0, thumb);
52226
- // return thumb;
52227
- // });
52228
- // }
52141
+ this.$backdropCarouselImgs = [];
52142
+ this.fixElements();
52143
+ this.loadBackdrop();
52144
+ this.update();
52145
+ }
52146
+ mount() {
52147
+ // insert after the background TODO figure out why
52148
+ const mediaControl = this.core.getPlugin('media_control');
52149
+ mediaControl.$el.find('.seek-time').css('bottom', 56); // TODO check
52150
+ // TODO use mediaControl.mount? into the `layer`
52151
+ mediaControl.$el.append(this.$el);
52152
+ }
52153
+ onMouseMoveSeekbar(_, pos) {
52154
+ this.hoverPosition = pos;
52155
+ this.showing = true;
52156
+ this.update();
52157
+ }
52158
+ onMouseLeave() {
52159
+ this.showing = false;
52160
+ this.update();
52161
+ }
52229
52162
  // builds a dom element which represents the thumbnail
52230
- // scaled to the provided height
52231
- _buildImg(thumb, height) {
52163
+ // scaled to the given height
52164
+ buildThumbImage(thumb, height) {
52232
52165
  const scaleFactor = height / thumb.h;
52233
- if (!this.$img) {
52234
- this.$img = $('<img />').addClass('thumbnail-img').attr('src', thumb.url);
52235
- }
52236
- // the container will contain the image positioned so that the correct sprite
52237
- // is visible
52238
- if (!this.$container) {
52239
- this.$container = $('<div />').addClass('thumbnail-container');
52240
- }
52241
- this.$container.css('width', thumb.w * scaleFactor);
52242
- this.$container.css('height', height);
52243
- this.$img.css({
52244
- height: this.spriteSheetHeight * scaleFactor,
52245
- left: -1 * thumb.x * scaleFactor,
52246
- top: -1 * thumb.y * scaleFactor,
52166
+ const $container = $('<div />').addClass('thumbnail-container');
52167
+ $container.css('width', thumb.w * scaleFactor);
52168
+ $container.css('height', height);
52169
+ $container.css({
52170
+ backgroundImage: `url(${thumb.url})`,
52171
+ backgroundSize: `${Math.floor(this.spriteSheetWidth * scaleFactor)}px ${Math.floor(this.spriteSheetHeight * scaleFactor)}px`,
52172
+ backgroundPosition: `-${Math.floor(thumb.x * scaleFactor)}px -${Math.floor(thumb.y * scaleFactor)}px`,
52247
52173
  });
52248
- if (this.$container.find(this.$img).length === 0) {
52249
- this.$container.append(this.$img);
52250
- }
52251
- return this.$container;
52174
+ return $container;
52252
52175
  }
52253
- _loadBackdrop() {
52254
- if (!this._getOptions().backdropHeight) {
52176
+ loadBackdrop() {
52177
+ if (!this.backdropHeight) {
52255
52178
  // disabled
52256
52179
  return;
52257
52180
  }
52258
52181
  // append each of the thumbnails to the backdrop carousel
52259
- const $carousel = this._$carousel;
52260
- for (const thumb of this._thumbs) {
52261
- const $img = this._buildImg(thumb, this._getOptions().backdropHeight);
52262
- // Keep reference to thumbnail
52263
- this._$backdropCarouselImgs.push($img);
52182
+ const $carousel = this.$el.find('#thumbnails-carousel');
52183
+ for (const thumb of this.thumbs) {
52184
+ const $img = this.buildThumbImage(thumb, this.backdropHeight);
52185
+ // Keep reference to the thumbnail
52186
+ this.$backdropCarouselImgs.push($img);
52264
52187
  // Add thumbnail to DOM
52265
52188
  $carousel.append($img);
52266
52189
  }
52267
52190
  }
52268
52191
  setText(time) {
52269
- if (this.core.getPlugin('clips')) {
52270
- const txt = this.core.getPlugin('clips').getText(time);
52271
- this.$textThumbnail.text(txt);
52192
+ const clips = this.core.getPlugin('clips');
52193
+ if (clips) {
52194
+ const txt = clips.getText(time);
52195
+ this.$el.find('#thumbnails-text').text(txt ?? '');
52272
52196
  }
52273
52197
  }
52274
52198
  // calculate how far along the carousel should currently be slid
52275
52199
  // depending on where the user is hovering on the progress bar
52276
- _updateCarousel() {
52277
- trace(`${T$1} _updateCarousel`, {
52278
- backdropHeight: this._getOptions().backdropHeight,
52279
- });
52280
- if (!this._getOptions().backdropHeight) {
52200
+ updateCarousel() {
52201
+ if (!this.backdropHeight) {
52281
52202
  // disabled
52282
52203
  return;
52283
52204
  }
52284
- const hoverPosition = this._hoverPosition;
52285
- const videoDuration = this.core.mediaControl.container.getDuration();
52286
- const startTimeOffset = this.core.mediaControl.container.getStartTimeOffset();
52205
+ const mediaControl = this.core.getPlugin('media_control');
52206
+ const videoDuration = mediaControl.container.getDuration();
52207
+ const startTimeOffset = mediaControl.container.getStartTimeOffset();
52287
52208
  // the time into the video at the current hover position
52288
- const hoverTime = startTimeOffset + videoDuration * hoverPosition;
52289
- const backdropWidth = this._$backdrop.width();
52290
- const $carousel = this._$carousel;
52209
+ const hoverTime = startTimeOffset + videoDuration * this.hoverPosition;
52210
+ const $backdrop = this.$el.find('#thumbnails-backdrop');
52211
+ const backdropWidth = $backdrop.width();
52212
+ const $carousel = this.$el.find('#thumbnails-carousel');
52291
52213
  const carouselWidth = $carousel.width();
52292
52214
  // slide the carousel so that the image on the carousel that is above where the person
52293
52215
  // is hovering maps to that position in time.
52294
52216
  // Thumbnails may not be distributed at even times along the video
52295
- const thumbs = this._thumbs;
52296
52217
  // assuming that each thumbnail has the same width
52297
- const thumbWidth = carouselWidth / thumbs.length;
52218
+ const thumbWidth = carouselWidth / this.thumbs.length;
52298
52219
  // determine which thumbnail applies to the current time
52299
- const thumbIndex = this._getThumbIndexForTime(hoverTime);
52300
- const thumb = thumbs[thumbIndex];
52301
- let thumbDuration = thumb.duration;
52302
- if (!thumbDuration) {
52303
- // the last thumbnail duration will be null as it can't be determined
52304
- // e.g the duration of the video may increase over time (live stream)
52305
- // so calculate the duration now so this last thumbnail lasts till the end
52306
- thumbDuration = Math.max(videoDuration + startTimeOffset - thumb.time, 0);
52307
- }
52220
+ const thumbIndex = this.getThumbIndexForTime(hoverTime);
52221
+ const thumb = this.thumbs[thumbIndex];
52222
+ // the last thumbnail duration will be null as it can't be determined
52223
+ // e.g the duration of the video may increase over time (live stream)
52224
+ // so calculate the duration now so this last thumbnail lasts till the end
52225
+ const thumbDuration = thumb.duration ??
52226
+ Math.max(videoDuration + startTimeOffset - thumb.time, 0);
52308
52227
  // determine how far accross that thumbnail we are
52309
52228
  const timeIntoThumb = hoverTime - thumb.time;
52310
52229
  const positionInThumb = timeIntoThumb / thumbDuration;
@@ -52312,12 +52231,12 @@ class Thumbnails extends UICorePlugin {
52312
52231
  // now calculate the position along carousel that we want to be above the hover position
52313
52232
  const xCoordInCarousel = thumbIndex * thumbWidth + xCoordInThumb;
52314
52233
  // and finally the position of the carousel when the hover position is taken in to consideration
52315
- const carouselXCoord = xCoordInCarousel - hoverPosition * backdropWidth;
52316
- $carousel.css('left', -carouselXCoord);
52317
- const maxOpacity = this._getOptions().backdropMaxOpacity || 0.6;
52318
- const minOpacity = this._getOptions().backdropMinOpacity || 0.08;
52234
+ const carouselXCoord = xCoordInCarousel - this.hoverPosition * backdropWidth;
52235
+ $carousel.css('left', -carouselXCoord); // TODO +px
52236
+ const maxOpacity = this.options.thumbnails.backdropMaxOpacity ?? 0.6;
52237
+ const minOpacity = this.options.thumbnails.backdropMinOpacity ?? 0.08;
52319
52238
  // now update the transparencies so that they fade in around the active one
52320
- for (let i = 0; i < thumbs.length; i++) {
52239
+ for (let i = 0; i < this.thumbs.length; i++) {
52321
52240
  const thumbXCoord = thumbWidth * i;
52322
52241
  let distance = thumbXCoord - xCoordInCarousel;
52323
52242
  if (distance < 0) {
@@ -52329,47 +52248,43 @@ class Thumbnails extends UICorePlugin {
52329
52248
  }
52330
52249
  // fade over the width of 2 thumbnails
52331
52250
  const opacity = Math.max(maxOpacity - Math.abs(distance) / (2 * thumbWidth), minOpacity);
52332
- this._$backdropCarouselImgs[i].css('opacity', opacity);
52251
+ this.$backdropCarouselImgs[i].css('opacity', opacity);
52333
52252
  }
52334
52253
  }
52335
- _updateSpotlightThumb() {
52336
- trace(`${T$1} _updateSpotlightThumb`, {
52337
- spotlightHeight: this._getOptions().spotlightHeight,
52338
- });
52339
- if (!this._getOptions().spotlightHeight) {
52254
+ updateSpotlightThumb() {
52255
+ if (!this.spotlightHeight) {
52340
52256
  // disabled
52341
52257
  return;
52342
52258
  }
52343
- const hoverPosition = this._hoverPosition;
52344
- const videoDuration = this.core.mediaControl.container.getDuration();
52259
+ const mediaControl = this.core.getPlugin('media_control');
52260
+ const videoDuration = mediaControl.container.getDuration();
52345
52261
  // the time into the video at the current hover position
52346
- const startTimeOffset = this.core.mediaControl.container.getStartTimeOffset();
52347
- const hoverTime = startTimeOffset + videoDuration * hoverPosition;
52262
+ const startTimeOffset = mediaControl.container.getStartTimeOffset();
52263
+ const hoverTime = startTimeOffset + videoDuration * this.hoverPosition;
52348
52264
  this.setText(hoverTime);
52349
52265
  // determine which thumbnail applies to the current time
52350
- const thumbIndex = this._getThumbIndexForTime(hoverTime);
52351
- const thumb = this._thumbs[thumbIndex];
52266
+ const thumbIndex = this.getThumbIndexForTime(hoverTime);
52267
+ const thumb = this.thumbs[thumbIndex];
52352
52268
  // update thumbnail
52353
- const $spotlight = this._$spotlight;
52269
+ const $spotlight = this.$el.find('#thumbnails-spotlight');
52354
52270
  $spotlight.empty();
52355
- $spotlight.append(this._buildImg(thumb, this._getOptions().spotlightHeight));
52271
+ $spotlight.append(this.buildThumbImage(thumb, this.spotlightHeight));
52356
52272
  const elWidth = this.$el.width();
52357
52273
  const thumbWidth = $spotlight.width();
52358
52274
  const thumbHeight = $spotlight.height();
52359
- let spotlightXPos = elWidth * hoverPosition - thumbWidth / 2;
52360
52275
  // adjust so the entire thumbnail is always visible
52361
- spotlightXPos = Math.max(Math.min(spotlightXPos, elWidth - thumbWidth), 0);
52276
+ const spotlightXPos = Math.max(Math.min(elWidth * this.hoverPosition - thumbWidth / 2, elWidth - thumbWidth), 0);
52362
52277
  $spotlight.css('left', spotlightXPos);
52363
- this.$textThumbnail.css('left', spotlightXPos);
52364
- this.$textThumbnail.css('width', thumbWidth);
52365
- this.$textThumbnail.css('bottom', thumbHeight + 1);
52278
+ const $textThumbnail = this.$el.find('#thumbnails-text');
52279
+ $textThumbnail.css('left', spotlightXPos);
52280
+ $textThumbnail.css('width', thumbWidth);
52281
+ $textThumbnail.css('bottom', thumbHeight + 1);
52366
52282
  }
52367
52283
  // returns the thumbnail which represents a time in the video
52368
52284
  // or null if there is no thumbnail that can represent the time
52369
- _getThumbIndexForTime(time) {
52370
- const thumbs = this._thumbs;
52371
- for (let i = thumbs.length - 1; i >= 0; i--) {
52372
- const thumb = thumbs[i];
52285
+ getThumbIndexForTime(time) {
52286
+ for (let i = this.thumbs.length - 1; i >= 0; i--) {
52287
+ const thumb = this.thumbs[i];
52373
52288
  if (thumb.time <= time) {
52374
52289
  return i;
52375
52290
  }
@@ -52377,37 +52292,48 @@ class Thumbnails extends UICorePlugin {
52377
52292
  // stretch the first thumbnail back to the start
52378
52293
  return 0;
52379
52294
  }
52380
- _renderPlugin() {
52381
- trace(`${T$1} _renderPlugin`, {
52382
- show: this._show,
52383
- thumbsLoaded: this._thumbsLoaded,
52384
- thumbs: this._thumbs.length,
52385
- });
52386
- if (!this._thumbsLoaded) {
52295
+ update() {
52296
+ if (!this.thumbsLoaded) {
52387
52297
  return;
52388
52298
  }
52389
- if (this._show && this._thumbs.length > 0) {
52299
+ if (this.showing && this.thumbs.length > 0) {
52300
+ this.updateCarousel();
52301
+ this.updateSpotlightThumb();
52390
52302
  this.$el.removeClass('hidden');
52391
- this._updateCarousel();
52392
- this._updateSpotlightThumb();
52393
52303
  }
52394
52304
  else {
52395
52305
  this.$el.addClass('hidden');
52396
52306
  }
52397
52307
  }
52398
- _createElements() {
52399
- trace(`${T$1} _createElements`);
52400
- this.$el.html(Thumbnails.template({
52401
- backdropHeight: this._getOptions().backdropHeight,
52402
- spotlightHeight: this._getOptions().spotlightHeight,
52403
- }));
52404
- // cache dom references
52405
- this._$spotlight = this.$el.find('.spotlight');
52406
- this._$backdrop = this.$el.find('.backdrop');
52407
- this._$carousel = this._$backdrop.find('.carousel');
52408
- this.$textThumbnail = this.$el.find('.thumbnails-text');
52308
+ fixElements() {
52309
+ const $spotlight = this.$el.find('#thumbnails-spotlight');
52310
+ if (this.spotlightHeight) {
52311
+ $spotlight.css('height', this.spotlightHeight);
52312
+ }
52313
+ else {
52314
+ $spotlight.remove();
52315
+ }
52316
+ const $backdrop = this.$el.find('#thumbnails-backdrop');
52317
+ if (this.backdropHeight) {
52318
+ $backdrop.css('height', this.backdropHeight);
52319
+ }
52320
+ else {
52321
+ $backdrop.remove();
52322
+ }
52323
+ this.mount();
52324
+ }
52325
+ get shouldRender() {
52326
+ return (this.options.thumbnails &&
52327
+ this.options.thumbnails.sprite &&
52328
+ this.options.thumbnails.vtt);
52329
+ }
52330
+ render() {
52331
+ if (!this.shouldRender) {
52332
+ return this;
52333
+ }
52334
+ this.$el.html(Thumbnails.template());
52409
52335
  this.$el.addClass('hidden');
52410
- this._appendElToMediaControl();
52336
+ return this;
52411
52337
  }
52412
52338
  }
52413
52339