diff --git a/.editorconfig b/.editorconfig
index 92cf9dc59..84ba69407 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,5 +8,5 @@ trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
-[json]
+[*.json]
indent_size = 2
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 73f40aaca..c51cd6b31 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -36,6 +36,7 @@
- [MrTimscampi](https://github.com/MrTimscampi)
- [Sarab Singh](https://github.com/sarab97)
- [Andrei Oanca](https://github.com/OancaAndrei)
+ - [Cromefire_](https://github.com/cromefire)
# Emby Contributors
diff --git a/package.json b/package.json
index 00b9f70f5..9ce8db2e4 100644
--- a/package.json
+++ b/package.json
@@ -148,6 +148,7 @@
"src/components/prompt/prompt.js",
"src/components/sanatizefilename.js",
"src/components/scrollManager.js",
+ "src/plugins/htmlVideoPlayer/plugin.js",
"src/components/search/searchfields.js",
"src/components/search/searchresults.js",
"src/components/settingshelper.js",
diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js
index f9d0e1909..083a61670 100644
--- a/src/plugins/htmlVideoPlayer/plugin.js
+++ b/src/plugins/htmlVideoPlayer/plugin.js
@@ -1,15 +1,43 @@
+import browser from 'browser';
+import events from 'events';
+import appHost from 'apphost';
+import loading from 'loading';
+import dom from 'dom';
+import playbackManager from 'playbackManager';
+import appRouter from 'appRouter';
+import connectionManager from 'connectionManager';
+import {
+ bindEventsToHlsPlayer,
+ destroyHlsPlayer,
+ destroyFlvPlayer,
+ destroyCastPlayer,
+ getCrossOriginValue,
+ enableHlsJsPlayer,
+ applySrc,
+ playWithPromise,
+ onEndedInternal,
+ saveVolume,
+ seekOnPlaybackStart,
+ onErrorInternal,
+ handleHlsJsMediaError,
+ getSavedVolume,
+ isValidDuration,
+ getBufferedRanges
+} from 'htmlMediaHelper';
+import itemHelper from 'itemHelper';
+import screenfull from 'screenfull';
+import globalize from 'globalize';
-define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'screenfull', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, screenfull, globalize) {
- 'use strict';
+/* eslint-disable indent */
- function tryRemoveElement(elem) {
- var parentNode = elem.parentNode;
+function tryRemoveElement(elem) {
+ const parentNode = elem.parentNode;
if (parentNode) {
// Seeing crashes in edge webview
try {
parentNode.removeChild(elem);
} catch (err) {
- console.error('error removing dialog element: ' + err);
+ console.error(`error removing dialog element: ${err}`);
}
}
}
@@ -22,7 +50,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
if (browser.firefox) {
- if ((currentSrc || '').toLowerCase().indexOf('.m3u8') !== -1) {
+ if ((currentSrc || '').toLowerCase().includes('.m3u8')) {
return false;
}
}
@@ -48,7 +76,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
if (track) {
- var format = (track.Codec || '').toLowerCase();
+ const format = (track.Codec || '').toLowerCase();
if (format === 'ssa' || format === 'ass') {
return false;
}
@@ -58,7 +86,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
function requireHlsPlayer(callback) {
- require(['hlsjs'], function (hls) {
+ import('hlsjs').then(({default: hls}) => {
window.Hls = hls;
callback();
});
@@ -84,9 +112,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
function zoomIn(elem) {
- return new Promise(function (resolve, reject) {
- var duration = 240;
- elem.style.animation = 'htmlvideoplayer-zoomin ' + duration + 'ms ease-in normal';
+ return new Promise(resolve => {
+ const duration = 240;
+ elem.style.animation = `htmlvideoplayer-zoomin ${duration}ms ease-in normal`;
hidePrePlaybackPage();
dom.addEventListener(elem, dom.whichAnimationEvent(), resolve, {
once: true
@@ -95,7 +123,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
function normalizeTrackEventText(text, useHtml) {
- var result = text.replace(/\\N/gi, '\n').replace(/\r/gi, '');
+ const result = text.replace(/\\N/gi, '\n').replace(/\r/gi, '');
return useHtml ? result.replace(/\n/gi, '
') : result;
}
@@ -104,7 +132,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
return track.Path;
}
- var url = playbackManager.getSubtitleUrl(track, item.ServerId);
+ let url = playbackManager.getSubtitleUrl(track, item.ServerId);
if (format) {
url = url.replace('.vtt', format);
}
@@ -113,84 +141,189 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
function getDefaultProfile() {
- return new Promise(function (resolve, reject) {
- require(['browserdeviceprofile'], function (profileBuilder) {
- resolve(profileBuilder({}));
- });
+ return import('browserdeviceprofile').then(({default: profileBuilder}) => {
+ return profileBuilder({});
});
}
- function HtmlVideoPlayer() {
- if (browser.edgeUwp) {
- this.name = 'Windows Video Player';
- } else {
- this.name = 'Html Video Player';
- }
+ export class HtmlVideoPlayer {
+ /**
+ * @type {string}
+ */
+ name
+ /**
+ * @type {string}
+ */
+ type = 'mediaplayer';
+ /**
+ * @type {string}
+ */
+ id = 'htmlvideoplayer';
+ /**
+ * Let any players created by plugins take priority
+ *
+ * @type {number}
+ */
+ priority = 1;
+ /**
+ * @type {boolean}
+ */
+ isFetching = false;
- this.type = 'mediaplayer';
- this.id = 'htmlvideoplayer';
+ /**
+ * @type {HTMLDivElement | null | undefined}
+ */
+ #videoDialog;
+ /**
+ * @type {number | undefined}
+ */
+ #subtitleTrackIndexToSetOnPlaying;
+ /**
+ * @type {number | null}
+ */
+ #audioTrackIndexToSetOnPlaying;
+ /**
+ * @type {null | undefined}
+ */
+ #currentClock;
+ /**
+ * @type {any | null | undefined}
+ */
+ #currentSubtitlesOctopus;
+ /**
+ * @type {null | undefined}
+ */
+ #currentAssRenderer;
+ /**
+ * @type {number | undefined}
+ */
+ #customTrackIndex;
+ /**
+ * @type {boolean | undefined}
+ */
+ #showTrackOffset;
+ /**
+ * @type {number | undefined}
+ */
+ #currentTrackOffset;
+ /**
+ * @type {HTMLElement | null | undefined}
+ */
+ #videoSubtitlesElem;
+ /**
+ * @type {any | null | undefined}
+ */
+ #currentTrackEvents;
+ /**
+ * @type {string[] | undefined}
+ */
+ #supportedFeatures;
+ /**
+ * @type {HTMLVideoElement | null | undefined}
+ */
+ #mediaElement;
+ /**
+ * @type {number}
+ */
+ #fetchQueue = 0;
+ /**
+ * @type {string | undefined}
+ */
+ #currentSrc;
+ /**
+ * @type {boolean | undefined}
+ */
+ #started;
+ /**
+ * @type {boolean | undefined}
+ */
+ #timeUpdated;
+ /**
+ * @type {number | null | undefined}
+ */
+ #currentTime;
+ /**
+ * @type {any | undefined}
+ */
+ #flvPlayer;
+ /**
+ * @private (used in other files)
+ * @type {any | undefined}
+ */
+ _hlsPlayer;
+ /**
+ * @private (used in other files)
+ * @type {any | null | undefined}
+ */
+ _castPlayer;
+ /**
+ * @private (used in other files)
+ * @type {any | undefined}
+ */
+ _currentPlayOptions;
+ /**
+ * @type {any | undefined}
+ */
+ #lastProfile;
+ /**
+ * @type {MutationObserver | IntersectionObserver | undefined} (Unclear observer typing)
+ */
+ #resizeObserver;
- // Let any players created by plugins take priority
- this.priority = 1;
-
- var videoDialog;
-
- var subtitleTrackIndexToSetOnPlaying;
- var audioTrackIndexToSetOnPlaying;
-
- var currentClock;
- var currentSubtitlesOctopus;
- var currentAssRenderer;
- var customTrackIndex = -1;
-
- var showTrackOffset;
- var currentTrackOffset;
-
- var videoSubtitlesElem;
- var currentTrackEvents;
-
- var self = this;
-
- self.currentSrc = function () {
- return self._currentSrc;
- };
-
- self._fetchQueue = 0;
- self.isFetching = false;
-
- function incrementFetchQueue() {
- if (self._fetchQueue <= 0) {
- self.isFetching = true;
- events.trigger(self, 'beginFetch');
- }
-
- self._fetchQueue++;
- }
-
- function decrementFetchQueue() {
- self._fetchQueue--;
-
- if (self._fetchQueue <= 0) {
- self.isFetching = false;
- events.trigger(self, 'endFetch');
+ constructor() {
+ if (browser.edgeUwp) {
+ this.name = 'Windows Video Player';
+ } else {
+ this.name = 'Html Video Player';
}
}
- function updateVideoUrl(streamInfo) {
- var isHls = streamInfo.url.toLowerCase().indexOf('.m3u8') !== -1;
+ currentSrc() {
+ return this.#currentSrc;
+ }
- var mediaSource = streamInfo.mediaSource;
- var item = streamInfo.item;
+ /**
+ * @private
+ */
+ incrementFetchQueue() {
+ if (this.#fetchQueue <= 0) {
+ this.isFetching = true;
+ events.trigger(this, 'beginFetch');
+ }
+
+ this.#fetchQueue++;
+ }
+
+ /**
+ * @private
+ */
+ decrementFetchQueue() {
+ this.#fetchQueue--;
+
+ if (this.#fetchQueue <= 0) {
+ this.isFetching = false;
+ events.trigger(this, 'endFetch');
+ }
+ }
+
+ /**
+ * @private
+ */
+ updateVideoUrl(streamInfo) {
+ const isHls = streamInfo.url.toLowerCase().includes('.m3u8');
+
+ const mediaSource = streamInfo.mediaSource;
+ const item = streamInfo.item;
// Huge hack alert. Safari doesn't seem to like if the segments aren't available right away when playback starts
// This will start the transcoding process before actually feeding the video url into the player
// Edit: Also seeing stalls from hls.js
if (mediaSource && item && !mediaSource.RunTimeTicks && isHls && streamInfo.playMethod === 'Transcode' && (browser.iOS || browser.osx)) {
- var hlsPlaylistUrl = streamInfo.url.replace('master.m3u8', 'live.m3u8');
+ const hlsPlaylistUrl = streamInfo.url.replace('master.m3u8', 'live.m3u8');
loading.show();
- console.debug('prefetching hls playlist: ' + hlsPlaylistUrl);
+ console.debug(`prefetching hls playlist: ${hlsPlaylistUrl}`);
return connectionManager.getApiClient(item.ServerId).ajax({
@@ -198,42 +331,41 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
url: hlsPlaylistUrl
}).then(function () {
- console.debug('completed prefetching hls playlist: ' + hlsPlaylistUrl);
+ console.debug(`completed prefetching hls playlist: ${hlsPlaylistUrl}`);
loading.hide();
streamInfo.url = hlsPlaylistUrl;
-
- return Promise.resolve();
}, function () {
- console.error('error prefetching hls playlist: ' + hlsPlaylistUrl);
+ console.error(`error prefetching hls playlist: ${hlsPlaylistUrl}`);
loading.hide();
- return Promise.resolve();
});
} else {
return Promise.resolve();
}
}
- self.play = function (options) {
- self._started = false;
- self._timeUpdated = false;
+ play(options) {
+ this.#started = false;
+ this.#timeUpdated = false;
- self._currentTime = null;
+ this.#currentTime = null;
- self.resetSubtitleOffset();
+ this.resetSubtitleOffset();
- return createMediaElement(options).then(function (elem) {
- return updateVideoUrl(options).then(function () {
- return setCurrentSrc(elem, options);
+ return this.createMediaElement(options).then(elem => {
+ return this.updateVideoUrl(options).then(() => {
+ return this.setCurrentSrc(elem, options);
});
});
- };
+ }
- function setSrcWithFlvJs(instance, elem, options, url) {
- return new Promise(function (resolve, reject) {
- require(['flvjs'], function (flvjs) {
- var flvPlayer = flvjs.createPlayer({
+ /**
+ * @private
+ */
+ setSrcWithFlvJs(elem, options, url) {
+ return import('flvjs').then(({default: flvjs}) => {
+ const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: url
},
@@ -242,117 +374,126 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
lazyLoad: false
});
- flvPlayer.attachMediaElement(elem);
- flvPlayer.load();
+ flvPlayer.attachMediaElement(elem);
+ flvPlayer.load();
- flvPlayer.play().then(resolve, reject);
- instance._flvPlayer = flvPlayer;
+ this.#flvPlayer = flvPlayer;
- // This is needed in setCurrentTrackElement
- self._currentSrc = url;
- });
+ // This is needed in setCurrentTrackElement
+ this.#currentSrc = url;
+
+ return flvPlayer.play();
});
}
- function setSrcWithHlsJs(instance, elem, options, url) {
- return new Promise(function (resolve, reject) {
- requireHlsPlayer(function () {
- var hls = new Hls({
+ /**
+ * @private
+ */
+ setSrcWithHlsJs(elem, options, url) {
+ return new Promise((resolve, reject) => {
+ requireHlsPlayer(() => {
+ const hls = new Hls({
manifestLoadingTimeOut: 20000,
- xhrSetup: function(xhr, xhr_url) {
+ xhrSetup(xhr) {
xhr.withCredentials = true;
}
});
hls.loadSource(url);
hls.attachMedia(elem);
- htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject);
+ bindEventsToHlsPlayer(this, hls, elem, this.onError, resolve, reject);
- self._hlsPlayer = hls;
+ this._hlsPlayer = hls;
// This is needed in setCurrentTrackElement
- self._currentSrc = url;
+ this.#currentSrc = url;
});
});
}
- function setCurrentSrc(elem, options) {
- elem.removeEventListener('error', onError);
+ /**
+ * @private
+ */
+ setCurrentSrc(elem, options) {
+ elem.removeEventListener('error', this.onError);
- var val = options.url;
- console.debug('playing url: ' + val);
+ let val = options.url;
+ console.debug(`playing url: ${val}`);
// Convert to seconds
- var seconds = (options.playerStartPositionTicks || 0) / 10000000;
+ const seconds = (options.playerStartPositionTicks || 0) / 10000000;
if (seconds) {
- val += '#t=' + seconds;
+ val += `#t=${seconds}`;
}
- htmlMediaHelper.destroyHlsPlayer(self);
- htmlMediaHelper.destroyFlvPlayer(self);
- htmlMediaHelper.destroyCastPlayer(self);
+ destroyHlsPlayer(this);
+ destroyFlvPlayer(this);
+ destroyCastPlayer(this);
- subtitleTrackIndexToSetOnPlaying = options.mediaSource.DefaultSubtitleStreamIndex == null ? -1 : options.mediaSource.DefaultSubtitleStreamIndex;
- if (subtitleTrackIndexToSetOnPlaying != null && subtitleTrackIndexToSetOnPlaying >= 0) {
- var initialSubtitleStream = options.mediaSource.MediaStreams[subtitleTrackIndexToSetOnPlaying];
+ this.#subtitleTrackIndexToSetOnPlaying = options.mediaSource.DefaultSubtitleStreamIndex == null ? -1 : options.mediaSource.DefaultSubtitleStreamIndex;
+ if (this.#subtitleTrackIndexToSetOnPlaying != null && this.#subtitleTrackIndexToSetOnPlaying >= 0) {
+ const initialSubtitleStream = options.mediaSource.MediaStreams[this.#subtitleTrackIndexToSetOnPlaying];
if (!initialSubtitleStream || initialSubtitleStream.DeliveryMethod === 'Encode') {
- subtitleTrackIndexToSetOnPlaying = -1;
+ this.#subtitleTrackIndexToSetOnPlaying = -1;
}
}
- audioTrackIndexToSetOnPlaying = options.playMethod === 'Transcode' ? null : options.mediaSource.DefaultAudioStreamIndex;
+ this.#audioTrackIndexToSetOnPlaying = options.playMethod === 'Transcode' ? null : options.mediaSource.DefaultAudioStreamIndex;
- self._currentPlayOptions = options;
+ this._currentPlayOptions = options;
- var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
+ const crossOrigin = getCrossOriginValue(options.mediaSource);
if (crossOrigin) {
elem.crossOrigin = crossOrigin;
}
- if (htmlMediaHelper.enableHlsJsPlayer(options.mediaSource.RunTimeTicks, 'Video') && val.indexOf('.m3u8') !== -1) {
- return setSrcWithHlsJs(self, elem, options, val);
+ if (enableHlsJsPlayer(options.mediaSource.RunTimeTicks, 'Video') && val.includes('.m3u8')) {
+ return this.setSrcWithHlsJs(elem, options, val);
} else if (options.playMethod !== 'Transcode' && options.mediaSource.Container === 'flv') {
- return setSrcWithFlvJs(self, elem, options, val);
+ return this.setSrcWithFlvJs(elem, options, val);
} else {
elem.autoplay = true;
// Safari will not send cookies without this
elem.crossOrigin = 'use-credentials';
- return htmlMediaHelper.applySrc(elem, val, options).then(function () {
- self._currentSrc = val;
+ return applySrc(elem, val, options).then(() => {
+ this.#currentSrc = val;
- return htmlMediaHelper.playWithPromise(elem, onError);
+ return playWithPromise(elem, this.onError);
});
}
}
- self.setSubtitleStreamIndex = function (index) {
- setCurrentTrackElement(index);
- };
+ setSubtitleStreamIndex(index) {
+ this.setCurrentTrackElement(index);
+ }
- self.resetSubtitleOffset = function() {
- currentTrackOffset = 0;
- showTrackOffset = false;
- };
+ resetSubtitleOffset() {
+ this.#currentTrackOffset = 0;
+ this.#showTrackOffset = false;
+ }
- self.enableShowingSubtitleOffset = function() {
- showTrackOffset = true;
- };
+ enableShowingSubtitleOffset() {
+ this.#showTrackOffset = true;
+ }
- self.disableShowingSubtitleOffset = function() {
- showTrackOffset = false;
- };
+ disableShowingSubtitleOffset() {
+ this.#showTrackOffset = false;
+ }
- self.isShowingSubtitleOffsetEnabled = function() {
- return showTrackOffset;
- };
+ isShowingSubtitleOffsetEnabled() {
+ return this.#showTrackOffset;
+ }
- function getTextTrack() {
- var videoElement = self._mediaElement;
+ /**
+ * @private
+ */
+ getTextTrack() {
+ const videoElement = this.#mediaElement;
if (videoElement) {
return Array.from(videoElement.textTracks)
- .find(function(trackElement) {
+ .find(function (trackElement) {
// get showing .vtt textTack
return trackElement.mode === 'showing';
});
@@ -361,64 +502,79 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
}
}
- self.setSubtitleOffset = function(offset) {
- var offsetValue = parseFloat(offset);
+ /**
+ * @private
+ */
+ setSubtitleOffset(offset) {
+ const offsetValue = parseFloat(offset);
// if .ass currently rendering
- if (currentSubtitlesOctopus) {
- updateCurrentTrackOffset(offsetValue);
- currentSubtitlesOctopus.timeOffset = (self._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue;
+ if (this.#currentSubtitlesOctopus) {
+ this.updateCurrentTrackOffset(offsetValue);
+ this.#currentSubtitlesOctopus.timeOffset = (this._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue;
} else {
- var trackElement = getTextTrack();
+ const trackElement = this.getTextTrack();
// if .vtt currently rendering
if (trackElement) {
- setTextTrackSubtitleOffset(trackElement, offsetValue);
- } else if (currentTrackEvents) {
- setTrackEventsSubtitleOffset(currentTrackEvents, offsetValue);
+ this.setTextTrackSubtitleOffset(trackElement, offsetValue);
+ } else if (this.#currentTrackEvents) {
+ this.setTrackEventsSubtitleOffset(this.#currentTrackEvents, offsetValue);
} else {
console.debug('No available track, cannot apply offset: ', offsetValue);
}
}
- };
+ }
- function updateCurrentTrackOffset(offsetValue) {
- var relativeOffset = offsetValue;
- var newTrackOffset = offsetValue;
- if (currentTrackOffset) {
- relativeOffset -= currentTrackOffset;
+ /**
+ * @private
+ */
+ updateCurrentTrackOffset(offsetValue) {
+ let relativeOffset = offsetValue;
+ const newTrackOffset = offsetValue;
+ if (this.#currentTrackOffset) {
+ relativeOffset -= this.#currentTrackOffset;
}
- currentTrackOffset = newTrackOffset;
+ this.#currentTrackOffset = newTrackOffset;
// relative to currentTrackOffset
return relativeOffset;
}
- function setTextTrackSubtitleOffset(currentTrack, offsetValue) {
+ /**
+ * @private
+ */
+ setTextTrackSubtitleOffset(currentTrack, offsetValue) {
if (currentTrack.cues) {
- offsetValue = updateCurrentTrackOffset(offsetValue);
+ offsetValue = this.updateCurrentTrackOffset(offsetValue);
Array.from(currentTrack.cues)
- .forEach(function(cue) {
+ .forEach(function (cue) {
cue.startTime -= offsetValue;
cue.endTime -= offsetValue;
});
}
}
- function setTrackEventsSubtitleOffset(trackEvents, offsetValue) {
+ /**
+ * @private
+ */
+ setTrackEventsSubtitleOffset(trackEvents, offsetValue) {
if (Array.isArray(trackEvents)) {
- offsetValue = updateCurrentTrackOffset(offsetValue) * 1e7; // ticks
- trackEvents.forEach(function(trackEvent) {
+ offsetValue = this.updateCurrentTrackOffset(offsetValue) * 1e7; // ticks
+ trackEvents.forEach(function (trackEvent) {
trackEvent.StartPositionTicks -= offsetValue;
trackEvent.EndPositionTicks -= offsetValue;
});
}
}
- self.getSubtitleOffset = function() {
- return currentTrackOffset;
- };
+ getSubtitleOffset() {
+ return this.#currentTrackOffset;
+ }
- function isAudioStreamSupported(stream, deviceProfile) {
- var codec = (stream.Codec || '').toLowerCase();
+ /**
+ * @private
+ */
+ isAudioStreamSupported(stream, deviceProfile) {
+ const codec = (stream.Codec || '').toLowerCase();
if (!codec) {
return true;
@@ -429,7 +585,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
return true;
}
- var profiles = deviceProfile.DirectPlayProfiles || [];
+ const profiles = deviceProfile.DirectPlayProfiles || [];
return profiles.filter(function (p) {
if (p.Type === 'Video') {
@@ -437,37 +593,35 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
return true;
}
- return p.AudioCodec.toLowerCase().indexOf(codec) !== -1;
+ return p.AudioCodec.toLowerCase().includes(codec);
}
return false;
}).length > 0;
}
- function getSupportedAudioStreams() {
- var profile = self._lastProfile;
+ /**
+ * @private
+ */
+ getSupportedAudioStreams() {
+ const profile = this.#lastProfile;
- return getMediaStreamAudioTracks(self._currentPlayOptions.mediaSource).filter(function (stream) {
- return isAudioStreamSupported(stream, profile);
+ return getMediaStreamAudioTracks(this._currentPlayOptions.mediaSource).filter((stream) => {
+ return this.isAudioStreamSupported(stream, profile);
});
}
- self.setAudioStreamIndex = function (index) {
- var streams = getSupportedAudioStreams();
+ setAudioStreamIndex(index) {
+ const streams = this.getSupportedAudioStreams();
if (streams.length < 2) {
// If there's only one supported stream then trust that the player will handle it on it's own
return;
}
- var audioIndex = -1;
- var i;
- var length;
- var stream;
-
- for (i = 0, length = streams.length; i < length; i++) {
- stream = streams[i];
+ let audioIndex = -1;
+ for (const stream of streams) {
audioIndex++;
if (stream.Index === index) {
@@ -479,76 +633,79 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
return;
}
- var elem = self._mediaElement;
+ const elem = this.#mediaElement;
if (!elem) {
return;
}
- // https://msdn.microsoft.com/en-us/library/hh772507(v=vs.85).aspx
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/audioTracks
- var elemAudioTracks = elem.audioTracks || [];
- console.debug('found ' + elemAudioTracks.length + ' audio tracks');
+ /**
+ * @type {ArrayLike|any[]}
+ */
+ const elemAudioTracks = elem.audioTracks || [];
+ console.debug(`found ${elemAudioTracks.length} audio tracks`);
- for (i = 0, length = elemAudioTracks.length; i < length; i++) {
+ for (const [i, audioTrack] of Array.from(elemAudioTracks).entries()) {
if (audioIndex === i) {
- console.debug('setting audio track ' + i + ' to enabled');
- elemAudioTracks[i].enabled = true;
+ console.debug(`setting audio track ${i} to enabled`);
+ audioTrack.enabled = true;
} else {
- console.debug('setting audio track ' + i + ' to disabled');
- elemAudioTracks[i].enabled = false;
+ console.debug(`setting audio track ${i} to disabled`);
+ audioTrack.enabled = false;
}
}
- };
+ }
- self.stop = function (destroyPlayer) {
- var elem = self._mediaElement;
- var src = self._currentSrc;
+ stop(destroyPlayer) {
+ const elem = this.#mediaElement;
+ const src = this.#currentSrc;
if (elem) {
if (src) {
elem.pause();
}
- htmlMediaHelper.onEndedInternal(self, elem, onError);
+ onEndedInternal(this, elem, this.onError);
if (destroyPlayer) {
- self.destroy();
+ this.destroy();
}
}
- destroyCustomTrack(elem);
+ this.destroyCustomTrack(elem);
return Promise.resolve();
- };
+ }
- self.destroy = function () {
- htmlMediaHelper.destroyHlsPlayer(self);
- htmlMediaHelper.destroyFlvPlayer(self);
+ destroy() {
+ destroyHlsPlayer(this);
+ destroyFlvPlayer(this);
appRouter.setTransparency('none');
- var videoElement = self._mediaElement;
+ const videoElement = this.#mediaElement;
if (videoElement) {
- self._mediaElement = null;
+ this.#mediaElement = null;
- destroyCustomTrack(videoElement);
- videoElement.removeEventListener('timeupdate', onTimeUpdate);
- videoElement.removeEventListener('ended', onEnded);
- videoElement.removeEventListener('volumechange', onVolumeChange);
- videoElement.removeEventListener('pause', onPause);
- videoElement.removeEventListener('playing', onPlaying);
- videoElement.removeEventListener('play', onPlay);
- videoElement.removeEventListener('click', onClick);
- videoElement.removeEventListener('dblclick', onDblClick);
- videoElement.removeEventListener('waiting', onWaiting);
+ this.destroyCustomTrack(videoElement);
+ videoElement.removeEventListener('timeupdate', this.onTimeUpdate);
+ videoElement.removeEventListener('ended', this.onEnded);
+ videoElement.removeEventListener('volumechange', this.onVolumeChange);
+ videoElement.removeEventListener('pause', this.onPause);
+ videoElement.removeEventListener('playing', this.onPlaying);
+ videoElement.removeEventListener('play', this.onPlay);
+ videoElement.removeEventListener('click', this.onClick);
+ videoElement.removeEventListener('dblclick', this.onDblClick);
+ videoElement.removeEventListener('waiting', this.onWaiting);
videoElement.parentNode.removeChild(videoElement);
}
- var dlg = videoDialog;
+ const dlg = this.#videoDialog;
if (dlg) {
- videoDialog = null;
+ this.#videoDialog = null;
dlg.parentNode.removeChild(dlg);
}
@@ -560,128 +717,188 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
document.webkitCancelFullscreen();
}
}
- };
-
- function onEnded() {
- destroyCustomTrack(this);
- htmlMediaHelper.onEndedInternal(self, this, onError);
}
- function onTimeUpdate(e) {
- // get the player position and the transcoding offset
- var time = this.currentTime;
+ /**
+ * @private
+ * @param e {Event} The event received from the `