@srgssr/pillarbox-web 1.35.1 → 1.36.1

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.
@@ -94,7 +94,7 @@ function _toPropertyKey(t) {
94
94
  return "symbol" == typeof i ? i : i + "";
95
95
  }
96
96
 
97
- const version = "1.35.0";
97
+ const version = "1.36.0";
98
98
 
99
99
  /** @import VJSPlayer from 'video.js/dist/types/player' */
100
100
  /** @import AudioTrack from 'video.js/dist/types/tracks/audio-track' */
@@ -191,6 +191,79 @@ class Player extends vjsPlayer {
191
191
  return ranges;
192
192
  }
193
193
 
194
+ /**
195
+ * Create a floating video window always on top of other windows so that users may
196
+ * continue consuming media while they interact with other content sites, or
197
+ * applications on their device.
198
+ *
199
+ * This can use document picture-in-picture or element picture in picture
200
+ *
201
+ * Set `enableDocumentPictureInPicture` to `true` to use docPiP on a supported browser
202
+ * Else set `disablePictureInPicture` to `false` to disable elPiP on a supported browser
203
+ *
204
+ *
205
+ * @see [Spec]{@link https://w3c.github.io/picture-in-picture/}
206
+ * @see [Spec]{@link https://wicg.github.io/document-picture-in-picture/}
207
+ *
208
+ * @fires Player#enterpictureinpicture
209
+ *
210
+ * @return {Promise}
211
+ * A promise with a Picture-in-Picture window.
212
+ */
213
+ /* eslint-disable */
214
+ requestPictureInPicture() {
215
+ if (this.options_.enableDocumentPictureInPicture && window.documentPictureInPicture) {
216
+ const pipContainer = document.createElement(this.el().tagName);
217
+ pipContainer.classList = this.el().classList;
218
+ pipContainer.classList.add('vjs-pip-container');
219
+ if (this.posterImage) {
220
+ pipContainer.appendChild(this.posterImage.el().cloneNode(true));
221
+ }
222
+ if (this.titleBar) {
223
+ pipContainer.appendChild(this.titleBar.el().cloneNode(true));
224
+ }
225
+ pipContainer.appendChild(videojs.dom.createEl('p', {
226
+ className: 'vjs-pip-text'
227
+ }, {}, this.localize('Playing in picture-in-picture')));
228
+ return window.documentPictureInPicture.requestWindow({
229
+ // The aspect ratio won't be correct, Chrome bug https://crbug.com/1407629
230
+ width: this.videoWidth(),
231
+ height: this.videoHeight()
232
+ }).then(pipWindow => {
233
+ videojs.dom.copyStyleSheetsToWindow(pipWindow);
234
+ this.el_.parentNode.insertBefore(pipContainer, this.el_);
235
+ pipWindow.document.body.appendChild(this.el_);
236
+ pipWindow.document.body.classList.add('vjs-pip-window');
237
+ this.player_.isInPictureInPicture(true);
238
+ this.player_.trigger({
239
+ type: 'enterpictureinpicture',
240
+ pipWindow
241
+ });
242
+
243
+ // Listen for the PiP closing event to move the video back.
244
+ pipWindow.addEventListener('pagehide', event => {
245
+ console.log(event.target);
246
+ const pipVideo = event.target.querySelector('.vjs-v8');
247
+ pipContainer.parentNode.replaceChild(pipVideo, pipContainer);
248
+ this.player_.isInPictureInPicture(false);
249
+ this.player_.trigger('leavepictureinpicture');
250
+ });
251
+ return pipWindow;
252
+ });
253
+ }
254
+ if ('pictureInPictureEnabled' in document && this.disablePictureInPicture() === false) {
255
+ /**
256
+ * This event fires when the player enters picture in picture mode
257
+ *
258
+ * @event Player#enterpictureinpicture
259
+ * @type {Event}
260
+ */
261
+ return this.techGet_('requestPictureInPicture');
262
+ }
263
+ return Promise.reject('No PiP mode is available');
264
+ }
265
+ /* eslint-enable */
266
+
194
267
  /**
195
268
  * Get the percent (as a decimal) of the media that's been played.
196
269
  * This method is not a part of the native HTML video API.
@@ -455,6 +528,45 @@ class AudioTrackButton extends VJSAudioTrackButton {
455
528
  videojs.registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
456
529
  videojs.registerComponent('AudioTrackButton', AudioTrackButton);
457
530
 
531
+ /**
532
+ * @ignore
533
+ */
534
+ const VJSPictureInPictureToggle = videojs.getComponent('PictureInPictureToggle');
535
+ class PictureInPictureToggle extends VJSPictureInPictureToggle {
536
+ /**
537
+ * Displays or hides the button depending on the audio mode detection.
538
+ * Exits picture-in-picture if it is enabled when switching to audio mode.
539
+ */
540
+ /* eslint-disable */
541
+ handlePictureInPictureAudioModeChange() {
542
+ // This audio detection will not detect HLS or DASH audio-only streams because there was no reliable way to detect them at the time
543
+ const isSourceAudio = this.player_.currentType().substring(0, 5) === 'audio';
544
+ const isAudioMode = isSourceAudio || this.player_.audioPosterMode() || this.player_.audioOnlyMode();
545
+ if (!isAudioMode || this.player_.options_.enableDocumentPictureInPicture && 'documentPictureInPicture' in window) {
546
+ this.show();
547
+ return;
548
+ }
549
+ if (this.player_.isInPictureInPicture()) {
550
+ this.player_.exitPictureInPicture();
551
+ }
552
+ this.hide();
553
+ }
554
+ /* eslint-enable */
555
+
556
+ /**
557
+ * Show the `Component`s element if it is hidden by removing the
558
+ * 'vjs-hidden' class name from it only in browsers that support the Picture-in-Picture API.
559
+ */
560
+ show() {
561
+ // Does not allow to display the pictureInPictureToggle in browsers that do not support the Picture-in-Picture or DocumentPictureInPicture API.
562
+ if (typeof document.exitPictureInPicture !== 'function' && !(this.player_.options_.enableDocumentPictureInPicture && 'documentPictureInPicture' in window)) {
563
+ return;
564
+ }
565
+ this.removeClass('vjs-hidden');
566
+ }
567
+ }
568
+ videojs.registerComponent('PictureInPictureToggle', PictureInPictureToggle);
569
+
458
570
  /**
459
571
  * Pillarbox is an alias for the video.js namespace with additional options.
460
572
  *
@@ -4096,25 +4208,23 @@ class SrgSsr {
4096
4208
  */
4097
4209
  static createTextTrack(_x5, _x6) {
4098
4210
  return _asyncToGenerator(function* (player, trackId, cues = []) {
4099
- const removeTrack = player.textTracks().getTrackById(trackId);
4211
+ const removeTrack = player.remoteTextTracks().getTrackById(trackId);
4100
4212
  if (removeTrack) {
4101
- player.textTracks().removeTrack(removeTrack);
4213
+ player.removeRemoteTextTrack(removeTrack);
4102
4214
  }
4215
+ const textTrack = player.addRemoteTextTrack({
4216
+ id: trackId,
4217
+ kind: 'metadata',
4218
+ label: trackId
4219
+ });
4220
+
4221
+ // Safari
4222
+ textTrack.track.mode = 'hidden';
4103
4223
 
4104
4224
  // See https://github.com/videojs/video.js/issues/8519
4105
- const textTrack = yield new Promise(resolve => {
4106
- setTimeout(() => {
4107
- resolve(new pillarbox.TextTrack({
4108
- id: trackId,
4109
- kind: 'metadata',
4110
- label: trackId,
4111
- tech: player.tech(true)
4112
- }));
4113
- }, 100);
4114
- });
4115
- SrgSsr.addTextTrackCues(textTrack, cues);
4116
- player.textTracks().addTrack(textTrack);
4117
- return textTrack;
4225
+ yield new Promise(resolve => setTimeout(resolve, 100));
4226
+ SrgSsr.addTextTrackCues(textTrack.track, cues);
4227
+ return textTrack.track;
4118
4228
  }).apply(this, arguments);
4119
4229
  }
4120
4230
 
@@ -4124,12 +4234,12 @@ class SrgSsr {
4124
4234
  * @param {Player} player
4125
4235
  */
4126
4236
  static cuechangeEventProxy(player) {
4127
- player.textTracks().on('addtrack', ({
4237
+ player.textTracks().on('addtrack', /** @param {{ track: TextTrack }} */({
4128
4238
  track
4129
4239
  }) => {
4130
4240
  if (!['srgssr-chapters', 'srgssr-intervals'].includes(track.id)) return;
4131
- track.on('cuechange', () => {
4132
- const [cue] = Array.from(track.activeCues);
4241
+ track.addEventListener('cuechange', () => {
4242
+ const [cue] = Array.from(track.activeCues || []);
4133
4243
  const type = track.id.includes('srgssr-chapters') ? 'srgssr/chapter' : 'srgssr/interval';
4134
4244
  player.trigger({
4135
4245
  type,
@@ -4231,7 +4341,7 @@ class SrgSsr {
4231
4341
  if (!blockedSegmentsTrack) return;
4232
4342
 
4233
4343
  /** @type {VTTCue} */
4234
- const [blockedCue] = Array.from(blockedSegmentsTrack.activeCues);
4344
+ const [blockedCue] = Array.from(blockedSegmentsTrack.activeCues || []);
4235
4345
  return blockedCue;
4236
4346
  }
4237
4347