import videojs from 'video.js';
import '@videojs/http-streaming';
import 'videojs-contrib-eme';
import 'videojs-contrib-dash';
import 'videojs-contrib-quality-levels';
import './mediaPlayer/middlewares/srgssr-middleware.js';
import './mediaPlayer/middlewares/videojs-mediacomposition-middleware.js';
import './mediaPlayer/components/header-component.js';
import './mediaPlayer/components/picture-in-picture-toggle.js';
import './mediaPlayer/components/image-copyright.js';
import './mediaPlayer/components/play-toggle-component.js';
import './mediaPlayer/components/overlay-component.js';
import './mediaPlayer/components/current-time-display-component.js';
import './mediaPlayer/components/skip-credits.js';
import './mediaPlayer/components/menu/srg-menu-close-button.js';
import './mediaPlayer/components/menu/srg-menu.js';
import './mediaPlayer/components/menu/srg-menu-button.js';
import './mediaPlayer/components/menu/settings/settings-menu.js';
import './mediaPlayer/components/menu/settings/settings-button.js';
import './mediaPlayer/components/menu/subtitles/subtitles-menu.js';
import './mediaPlayer/components/menu/subtitles/subtitles-button.js';
import './mediaPlayer/components/menu/playbackRate/playback-rate-menu.js';
import './mediaPlayer/components/menu/playbackRate/playback-rate-button.js';
import './mediaPlayer/components/chromecast-toggle-component.js';
import './mediaPlayer/components/SRGSSR-button-component.js';
import './mediaPlayer/components/endScreen/end-screen-component.js';
import './mediaPlayer/components/error-display-component.js';
import './mediaPlayer/components/time-tool-tip-component.js';
import './mediaPlayer/components/subdivisions/subdivisions-container.js';
import './mediaPlayer/components/warning-message-component.js';
import './mediaPlayer/components/airplay-button.js';
import './mediaPlayer/components/backward-button.js';
import './mediaPlayer/components/forward-button.js';
import './mediaPlayer/components/text-track-display.js';
import './mediaPlayer/components/seek-bar.js';
import './mediaPlayer/components/thumbnail-seeking-component.js';
import './mediaPlayer/utils/chromecastPlayer.js';
import './mediaPlayer/scss/imports.scss';
import * as Events from './utils/Events.js';
import * as PlayerEvents from './utils/PlayerEvents.js';
import * as SRGEvents from './utils/SRGEvents.js';
import * as VideojsEvents from './utils/VideojsEvents.js';
import * as videojsDELanguage from './lang/de-CH.json';
import * as videojsENLanguage from './lang/en-US.json';
import * as videojsFRLanguage from './lang/fr-CH.json';
import * as videojsITLanguage from './lang/it-CH.json';
import * as videojsRMLanguage from './lang/rm-CH.json';
import MediaComposition from './dataProvider/model/MediaComposition.js';
import SRGLetterboxComponents from './utils/SRGLetterboxComponents.js';
import SRGLetterboxConfiguration from './utils/SRGLetterboxConfiguration.js';
import SRGPlaybackSettings from './utils/SRGPlaybackSettings.js';
import SupportedDevices from './utils/SupportedDevices.js';
import Utils from './utils/Utils.js';
import build from '../generated/build.json';
import PlayerUtils from './utils/PlayerUtils.js';
import { version } from '../package.json';
import SRGStreamType from './utils/SRGStreamType.js';
import TextTracksUtils from './utils/TextTracksUtils.js';
import AudioTracksUtils from './utils/AudioTracksUtils.js';
videojs.addLanguage('fr', videojsFRLanguage);
videojs.addLanguage('en', videojsENLanguage);
videojs.addLanguage('it', videojsITLanguage);
videojs.addLanguage('rm', videojsRMLanguage);
videojs.addLanguage('de', videojsDELanguage);
videojs.hook('beforesetup', (videoEl, options) => {
if (!options.SRGPlayerConfiguration.noUI) {
return options;
}
videoEl.classList.add('srgssr-no-ui');
const noUIOptions = videojs.mergeOptions(options, {
children: ['mediaLoader', 'textTrackDisplay'],
controlBar: false,
html5: {
nativeTextTracks: videojs.browser.IS_SAFARI,
vhs: {
overrideNative: !videojs.browser.IS_SAFARI,
},
},
});
return noUIOptions;
});
const LETTERBOX_INSTANCES = [];
/**
* @class SRGLetterbox
*
* The SRGLetterbox class provides a simple way to create a web player.
*/
class SRGLetterbox {
/**
* @constructor
*
* @param {LetterboxConfiguration} options Letterbox configuration object. The parameter object is merged with the default options.
* @param {String} options.container query selector of the HTMLElement where the player will be created.
*
* @see SRGLetterbox.LETTERBOX_DEFAULT_OPTIONS and its documentation for available options.
*/
constructor(options = {}, ConfigurationHandler = SRGLetterboxConfiguration) {
this.ConfigurationHandler = ConfigurationHandler;
this.player = this.ConfigurationHandler.initializePlayer(options, version);
this.playbackSettings = new SRGPlaybackSettings(
this.player,
ConfigurationHandler,
);
this.player.options({
SRGProviders: {
letterbox: this,
},
});
SRGLetterbox.addInstance(this);
}
/**
* A getter/setter for the `Player`'s aspect ratio.
*
* @param {string} [ratio]
* The value to set the Player's aspect ratio to.
*
* @see fill
* @see https://docs.videojs.com/player#aspectRatio
* @see https://docs.videojs.com/tutorial-layout.html
*
* @return {string|undefined}
* - The current aspect ratio of the `Player` when getting.
* - undefined when setting
*/
aspectRatio(ratio) {
return this.player.aspectRatio(ratio);
}
/**
* Get or set the audio track language.
* The value should be the language code of the audio track
* or an object containing at least the language property
*
* @param {undefined|string|object} value
*
* @example audioTrackLanguage()
* @example audioTrackLanguage('de')
* @example audioTrackLanguage({language: 'de'})
* @example audioTrackLanguage({language: 'de', description: true})
* @example audioTrackLanguage({language: 'de', description: false})
*
* @returns {object}
*/
audioTrackLanguage(value) {
const audioTrackValue = AudioTracksUtils.sanitizeParameter(value);
return PlayerUtils.audioTrackLanguage(audioTrackValue, this.player);
}
/**
* Get the AudioTrackList.
*
* @see https://docs.videojs.com/player#audioTracks
* @see https://docs.videojs.com/audiotracklist
* @see https://html.spec.whatwg.org/multipage/media.html#dom-media-audiotracks
*
* @param {*} safety
* Anything passed in to silence the warning.
*
* @returns {AudioTrackList} The current audio track list.
*/
audioTracks(safety) {
if (!safety) {
console.warn( // eslint-disable-line no-console
'If you want to get or set the current audio track prefer the use of %caudioTrackLanguage',
'font-weight:bold; font-size:1.1em; background: #ff0000; color:#fff;',
'https://letterbox-web.srgssr.ch/production/api/SRGLetterbox.html#audioTrackLanguage',
);
}
return this.player.audioTracks();
}
/**
* Get or set the autoplay option.
* - true: autoplay using the browser behavior
* - false: do not autoplay
* - 'play': call play() on every loadstart
* - 'muted': call muted() then play() on every loadstart
* - 'any': call play() on every loadstart. if that fails call muted() then play().
* - *: values other than those listed here will be set `autoplay` to true
*
* @param {boolean|string} value
*
* @see https://docs.videojs.com/player#autoplay
*/
autoplay(value) {
return PlayerUtils.autoplay(this.player, value);
}
/**
* Get or set the current date.
*
* It allows to seek in a DVR live stream using a date as an absolute position.
*
* @param {Date} [date] The date to seek to
*
* @return {Date} The current date when getting
*/
currentDate(date) {
if (!SRGStreamType.isDvr(this.player.currentSource().streamType)) {
throw new Error('The streamType must be DVR');
}
if (date !== undefined && !(date instanceof Date)) {
throw new Error('The date parameter must be an instance of Date');
}
return PlayerUtils.currentDate(date, this.player);
}
/**
* Get or set the current time (in seconds)
*
* @param {number|string} [seconds] The time to seek to in seconds
*
* @return {number} The current time in seconds when getting
*/
currentTime(seconds) {
return this.player.currentTime(seconds);
}
/**
* Disable Picture-in-Picture mode.
*
* __FYI: Firefox doesn't provide any PiP API at the moment.__
*
* @param {boolean} value
* - true will disable Picture-in-Picture mode
* - false will enable Picture-in-Picture mode
*/
disablePictureInPicture(value) {
this.player.disablePictureInPicture(value);
}
/**
* Destroys the video player and does any necessary cleanup.
* This is especially helpful if you are dynamically adding and removing videos to/from the DOM.
*
* @see https://docs.videojs.com/player#dispose
*
* @fires videojs#event:dispose
*/
dispose() {
this.player.dispose();
SRGLetterbox.removeInstance(this);
}
/**
* Return letterbox duration of the currently playing stream. This is videojs duration
* ( @see https://docs.videojs.com/player#paused ) when the player is initialized,
* or the mediacomposition duration if the player is not yet playing.
*
* @returns {number | undefined} duration in seconds
*/
/** TODO: Investigate the use case : Why do we return duration from mediacomposition */
duration() {
const playerDuration = this.player.duration();
if (playerDuration) {
return playerDuration;
}
const mediaComposition = this.getMediaComposition();
if (mediaComposition) {
const mainChapter = mediaComposition.getMainChapter();
return Utils.millisecondsToSeconds(mainChapter.duration);
}
return undefined;
}
/**
* Get the value of the `error` from the media element.
* `error` indicates any MediaError that may have occurred during playback.
* If error returns null there is no current error.
*
* __FYI__: video.js error method allows a `MediaError` object as a parameter, Letterbox don't.
*
* @returns MediaError | null
*
* @see https://docs.videojs.com/html5#error
*/
error() {
return this.player.error();
}
/**
* Exit Picture-in-Picture mode.
*
* __FYI: Firefox doesn't provide any PiP API at the moment.__
*
* @see [Spec]{@link https://wicg.github.io/picture-in-picture}
*
* @fires Player#leavepictureinpicture
*
* @return {Promise}
* A promise.
*/
exitPictureInPicture() {
return this.player.exitPictureInPicture();
}
/**
* A getter/setter/toggler for the vjs-fill `className` on the `Player`.
*
* Turning this on will turn off fluid mode.
*
* By default Letterbox uses the fill mode.
* This means the player will take all the available space in his container.
*
* @see https://docs.videojs.com/player#fill
*
* @param {boolean} [bool]
* - A value of true adds the class.
* - A value of false removes the class.
* - No value will be a getter.
*
* @return {boolean|undefined}
* - The value of fluid when getting.
* - `undefined` when setting.
*/
fill(bool) {
return this.player.fill(bool);
}
/**
* A getter/setter/toggler for the vjs-fluid `className` on the `Player`.
*
* Turning this on will turn off fill mode.
*
* @see https://docs.videojs.com/player#fluid
*
* @param {boolean} [bool]
* - A value of true adds the class.
* - A value of false removes the class.
* - No value will be a getter.
*
* @return {boolean|undefined}
* - The value of fluid when getting.
* - `undefined` when setting.
*/
fluid(bool) {
return this.player.fluid(bool);
}
/**
* Return the video to its normal size after having been in full screen mode
*
* @fires Player#fullscreenchange
*/
exitFullscreen() {
return this.player.exitFullscreen();
}
/**
* Get the current player configuration object
*
* @see SRGLetterboxConfiguration.getPlayerConfiguration
*
* @return {PlayerConfiguration} SRG player configuration
*/
getConfiguration() {
return this.ConfigurationHandler.getPlayerConfiguration(this.player);
}
/**
* Get the debug information.
*
* @returns {Object}
*/
getDebugInformation() {
return PlayerUtils.getDebugInformation(this.player);
}
/**
* Get the currently playing Media Composition.
*
* @returns {MediaComposition}
*/
getMediaComposition() {
return this.player.options().SRGProviders.mediaComposition;
}
/**
* Get the current playback settings.
*
* @returns {Object}
* TODO: Check playbackSettings that shouldn't be merged in the mediaComposition in the middleware
*/
getPlaybackSettings() {
return this.player.currentSource().playbackSettings;
}
/**
* @returns {String} currently playing URN
*/
getUrn() {
return PlayerUtils.getUrn(this.player);
}
/**
* Check if the MediaComposition has subdivisions.
*
* @returns {Boolean}
*/
hasSubdivisions() {
const mediaComposition = this.getMediaComposition();
return mediaComposition
? mediaComposition.getSubdivisions().length > 0 : false;
}
/**
* Check if the player is in fullscreen mode or tell the player that it is or is not in fullscreen mode.
*
* @see https://docs.videojs.com/player#isFullscreen
*
* @returns {Boolean}
*/
isFullscreen() {
return this.player.isFullscreen();
}
/**
* Check if the player is in Picture-in-Picture mode or tell the player that it
* is or is not in Picture-in-Picture mode.
*
* __FYI: Firefox doesn't provide any PiP API at the moment.__
*
* @param {boolean} [isPiP]
* Set the players current Picture-in-Picture state
*
* @return {boolean}
* - true if Picture-in-Picture is on and getting
* - false if Picture-in-Picture is off and getting
*/
isInPictureInPicture(isPiP) {
return this.player.isInPictureInPicture(isPiP);
}
/**
* Load a media provided as a mediacomposition.
*
* @param {Object} mediaComposition data or mediaComposition object
* @param {Object} param1
* @param {Number} [param1.pendingSeek=undefined] position to play at in seconds or undefined to play at stream default position
* @param {Object} [param1.playbackSettings=undefined] options to be stored with the playback context,
* can be used for application specific information
* they can be read back in getPlaybackSettings
* @param {boolean|string} [param1.autoplay=undefined] value
*
* @see autoplay autoplay value
* @see getPlaybackSettings
* @see getMediaComposition
*/
loadMediaComposition(
mediaComposition,
{
autoplay = undefined,
pendingSeek = undefined,
playbackSettings = undefined,
} = {},
) {
PlayerUtils.loadMedia(this.player, {
autoplay,
mediaComposition: MediaComposition.cleanCache(mediaComposition),
pendingSeek,
playbackSettings,
urn: mediaComposition.segmentUrn || mediaComposition.chapterUrn,
});
}
/**
* Load an URN.
*
* @param {String} urn string
* @param {Object} param1
* @param {Number} [param1.pendingSeek=undefined] position to play at in seconds or undefined to play at stream default position
* @param {Object} [param1.playbackSettings=undefined] options to be stored with the playback context,
* can be used for application specific information
* they can be read back in getPlaybackSettings
* @param {boolean|string} [param1.autoplay=undefined] value
* @param {bolean} [param1.standalone=false] allow to switch between onlyChapters true/false.
* The default value is false.
*
* @see autoplay autoplay value
* @see getPlaybackSettings
* @see getMediaComposition
* */
loadUrn(urn, {
autoplay = undefined,
pendingSeek = undefined,
playbackSettings = undefined,
standalone = false,
} = {}) {
PlayerUtils.loadMedia(this.player, {
autoplay,
pendingSeek,
playbackSettings,
standalone,
urn,
});
}
/**
* Get or set the loop attribute on the video element.
*
* @see https://docs.videojs.com/player#loop
*
* @param {boolean} [value]
* - true means that we should loop the video
* - false means that we should not loop the video
*
* @return {boolean}
* The current value of loop when getting
*/
loop(value) {
return this.player.loop(value);
}
/**
* Get the current muted state, or turn mute on or off
*
* @see https://docs.videojs.com/player#muted
*
* @param {boolean} [muted]
* - true to mute
* - false to unmute
*
* @return {boolean}
* - true if mute is on and getting
* - false if mute is off and getting
*/
muted(muted) {
return this.player.muted(muted);
}
/**
* Removes listener(s) from event(s) on an evented object.
*
* @param {string|Array|Element|Object} [targetOrType]
* If this is a string or array, it represents the event type(s).
*
* Another evented object can be passed here instead, in which case
* ALL 3 arguments are _required_.
*
* @param {string|Array|Function} [typeOrListener]
* If the first argument was a string or array, this may be the
* listener function. Otherwise, this is a string or array of event
* type(s).
*
* @param {Function} [listener]
* If the first argument was another evented object, this will be
* the listener function; otherwise, _all_ listeners bound to the
* event type(s) will be removed.
*
* @see https://github.com/videojs/video.js/blob/v7.7.4/src/js/mixins/evented.js#L337
*/
off(elem, typeopt, fnopt) {
this.player.off(elem, typeopt, fnopt);
}
/**
* Add a listener to an event (or events) on this object or another evented
* object.
*
* @param {string|Array|Element|Object} targetOrType
* If this is a string or array, it represents the event type(s)
* that will trigger the listener.
*
* Another evented object can be passed here instead, which will
* cause the listener to listen for events on _that_ object.
*
* In either case, the listener's `this` value will be bound to
* this object.
*
* @param {string|Array|Function} typeOrListener
* If the first argument was a string or array, this should be the
* listener function. Otherwise, this is a string or array of event
* type(s).
*
* @param {Function} [listener]
* If the first argument was another evented object, this will be
* the listener function.
*
* @see https://github.com/videojs/video.js/blob/v7.7.4/src/js/mixins/evented.js#L192
*/
on(...args) {
this.player.on(...args);
}
/**
* Add a listener to an event (or events) on this object or another evented
* object. The listener will be called once per event and then removed.
*
* @param {string|Array|Element|Object} targetOrType
* If this is a string or array, it represents the event type(s)
* that will trigger the listener.
*
* Another evented object can be passed here instead, which will
* cause the listener to listen for events on _that_ object.
*
* In either case, the listener's `this` value will be bound to
* this object.
*
* @param {string|Array|Function} typeOrListener
* If the first argument was a string or array, this should be the
* listener function. Otherwise, this is a string or array of event
* type(s).
*
* @param {Function} [listener]
* If the first argument was another evented object, this will be
* the listener function.
*
* @see https://github.com/videojs/video.js/blob/v7.7.4/src/js/mixins/evented.js#L244
*/
one(...args) {
this.player.one(...args);
}
/**
* Pause the video playback.
*
* @see https://docs.videojs.com/player#pause
*/
pause() {
this.player.pause();
}
/**
* Check if the player is paused.
*
* @see https://docs.videojs.com/player#paused
*
* @returns {Boolean}
*/
paused() {
return this.player.paused();
}
/**
* Attempt to begin playback.
*
* @see https://docs.videojs.com/player#play
*
* @return {Promise|undefined}
*/
play() {
return this.player.play();
}
/**
* Gets or sets the current playback rate. A playback rate of 1.0 represents normal speed and 0.5 would indicate half-speed playback, for instance.
*
* @param {Number} rateopt New playback rate to set.
*
* @see https://docs.videojs.com/player#playbackRate
*
* @returns {Number} The current playback rate when getting or 1.0
*/
playbackRate(rateopt) {
return this.player.playbackRate(rateopt);
}
/**
* Restart the playback session.
*
* @param autoplay autoplay property
*
* @see autoplay
*/
restart(autoplay = true) {
this.loadUrn(this.getUrn(), { autoplay });
}
/**
* Increase the size of the video to full screen
* In some browsers, full screen is not supported natively, so it enters
* "full window mode", where the video fills the browser window.
* In browsers and devices that support native full screen, sometimes the
* browser's default controls will be shown, and not the Video.js custom skin.
* This includes most mobile devices (iOS, Android) and older versions of
* Safari.
*
* __FYI__: Be aware of the potential error "Request for fullscreen was denied
* because Element.requestFullscreen() was not called from inside a short running user-generated event handler."
*
* @param {Object} [fullscreenOptions]
* Override the player fullscreen options
*
* @fires Player#fullscreenchange
*
* @see https://docs.videojs.com/player#requestFullscreen
* @see https://docs.videojs.com/tutorial-options.html#fullscreen
* @see https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen
* @see https://fullscreen.spec.whatwg.org/#dom-fullscreenoptions-navigationui
*/
requestFullscreen(fullscreenOptions) {
return this.player.requestFullscreen(fullscreenOptions);
}
/**
* Create a floating video window always on top of other windows so that users may
* continue consuming media while they interact with other content sites, or
* applications on their device.
*
* __FYI: Firefox doesn't provide any PiP API at the moment.__
*
* @see [Spec]{@link https://wicg.github.io/picture-in-picture}
*
* @fires Player#enterpictureinpicture
*
* @return {Promise}
* A promise with a Picture-in-Picture window.
*/
requestPictureInPicture() {
return this.player.requestPictureInPicture();
}
/**
* Switch URN. Play a different URN in the same context.
*
* - Switch to segment if urn is within segment list of the current mediacomposition
* (e.g.: full DVR highlight or live). Will start at the beginning of the segment,
* or at the edge of live for live.
* - Switch to chapter if urn is within chapter list of the current mediacomposition
* (e.g.: limited DVR highlight or live). Will start at the beginning of the segment,
* or at the edge of live for live.
*
* This will start playing if player is not currently playing.
*
* @param {String} urn to play
*/
switchToUrn(urn) {
PlayerUtils.switchToUrn(this.player, urn);
}
/**
* Get or set the text track language.
* The value should be the language code of the text track
* Or an object containing at least the language property
*
* @param {undefined|string|object} value
*
* @example textTrackLanguage()
* @example textTrackLanguage('de')
* @example textTrackLanguage({language: 'de'})
* @example textTrackLanguage({language: 'de', caption: true})
* @example textTrackLanguage({language: 'de', caption: false})
*
* @returns {object}
*/
textTrackLanguage(value) {
const textTrackValue = TextTracksUtils.sanitizeParameter(value);
return PlayerUtils.textTrackLanguage(textTrackValue, this.player);
}
/**
* Get the TextTrackList.
*
* @see https://docs.videojs.com/player#textTracks
* @see https://docs.videojs.com/texttracklist
* @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks
*
* @param {*} safety
* Anything passed in to silence the warning.
*
* @example
* //Allows to filter the metadata type tracks
* Array.from(letterboxInstance.textTracks()).filter(({kind}) => kind !== 'metadata');
*
* @return {TextTrackList}
* The current text track list.
*/
textTracks(safety) {
if (!safety) {
console.warn( // eslint-disable-line no-console
'If you want to get or set the current text track prefer the use of %ctextTrackLanguage',
'font-weight:bold; font-size:1.1em; background: #ff0000; color:#fff;',
'https://letterbox-web.srgssr.ch/production/api/SRGLetterbox.html#textTrackLanguage',
);
}
return this.player.textTracks();
}
/**
* Get or set the text track font size.
*
* @param {Number} sizeLevel is a size level between 1 and 8.
* @returns {Number|undefined} The font size in percent.
*/
textTrackSizeLevel(sizeLevel) {
return PlayerUtils.textTrackSizeLevel(sizeLevel, this.player);
}
/**
* Fire an event on this evented object, causing its listeners to be called.
*
* @param {string|Object} event
* An event type or an object with a type property.
*
* @param {Object} [hash]
* An additional object to pass along to listeners.
*
* @return {boolean}
* Whether or not the default behavior was prevented.
*
* @see https://github.com/videojs/video.js/blob/v7.7.4/src/js/mixins/evented.js#L389
*/
trigger(event, hash) {
this.player.trigger(event, hash);
}
/**
* Update the current player configration object.
*
* @param {object} configuration
*
* @example
* // Set the continuousPlayback with a default value set to true and disable the local storage.
* letterboxInstance.updateConfiguration({
* continuousPlayback : {
* default: true,
* storage : false,
* }
* });
*
* @example
* // Set the continuousPlayback with a default value set to false and enable the local storage.
* letterboxInstance.updateConfiguration({
* continuousPlayback : {
* default: false,
* storage : true,
* }
* });
*
* @example
* // Activates the continuousPlayback but removes the UI component so that the user can't change it
* letterboxInstance.updateConfiguration({
* continuousPlayback : true
* });
*/
updateConfiguration(configuration) {
this.ConfigurationHandler.updateConfiguration(this.player, configuration);
}
/**
* Get or set the current volume of the media
*
* @see https://docs.videojs.com/player#volume
*
* @param {number} [percentAsDecimal]
* The new volume as a decimal percent:
* - 0 is muted/0%/off
* - 1.0 is 100%/full
* - 0.5 is half volume or 50%
*
* @return {number}
* The current volume as a percent when getting
*/
volume(percentAsDecimal) {
return this.player.volume(percentAsDecimal);
}
/**
* Add Letterbox instance.
*/
static addInstance(instance) {
if (instance instanceof SRGLetterbox) {
LETTERBOX_INSTANCES.push(instance);
return;
}
throw new Error('The instance parameter must be a SRGLetterbox instance');
}
/**
* Object with detailed build information.
*/
static get BUILD() {
return build;
}
/**
* Aggregates all available event properties
*
* @type {Object}
* @event
* @see Events
*
* @linkcode SRGLetterbox#playerEvents
* @linkcode SRGLetterbox#srgEvents
* @linkcode SRGLetterbox#videojsEvents
*/
static get events() {
return Events;
}
/**
* Get Letterbox instances.
*
* @returns {Array} array of SRGLetterbox instances
*/
static getInstances() {
return LETTERBOX_INSTANCES;
}
/**
* Letterbox default options. Those options can be overridden in the constructor.
*
* @returns {LetterboxConfiguration} SRGLetterboxConfiguration.defaultLetterboxConfiguration
*/
static get LETTERBOX_DEFAULT_OPTIONS() {
return SRGLetterboxConfiguration.defaultLetterboxConfiguration;
}
/**
* Long string with detailed version and build information.
* @returns {string} displayable string
*/
static get LONG_VERSION() {
const date = new Date(parseInt(build.date, 10));
return `${version} built at ${date} from ${build.commit} using ${build.runner} by ${build.initiator}`;
}
/**
* Standard player events.
*
* @see https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
* @event
* @type {Object}
* @see PlayerEvents
*/
static get playerEvents() {
return PlayerEvents;
}
/**
* Remove a specific Letterbox instance.
*
* @param {SRGLetterbox} instance
*/
static removeInstance(instance) {
if (instance instanceof SRGLetterbox
&& SRGLetterbox.getInstances().includes(instance)) {
SRGLetterbox.getInstances().splice(SRGLetterbox.getInstances().indexOf(instance), 1);
return;
}
throw new Error('The instance parameter must be a SRGLetterbox instance');
}
/**
* SRG events.
*
* @event
* @type {Object}
* @see SRGEvents
*/
static get srgEvents() {
return SRGEvents;
}
/**
* SupportedDevices allows to detect browser's version
* and some features compatibilities.
*
* @returns {supportedDevices} supportedDevices class
*/
static get supportedDevices() {
return SupportedDevices;
}
/**
* Represents the Letterbox version.
*
* @returns {String}
*/
static get VERSION() {
return version;
}
/**
* Video.js events.
*
* FYI: Not all Video.js are exposed.
*
* @event
* @type {Object}
*
* @see VideojsEvents
*/
static get videojsEvents() {
return VideojsEvents;
}
/**
* @returns {SRGLetterboxComponents} Components list
*/
static get srgLetterboxComponents() {
return SRGLetterboxComponents;
}
}
export default SRGLetterbox;
window.videojs = videojs;
window.SRGLetterbox = SRGLetterbox;
window.SRGLetterboxConfiguration = SRGLetterboxConfiguration;