diff --git a/package.json b/package.json index fa27f5b951..0c83a52571 100644 --- a/package.json +++ b/package.json @@ -165,6 +165,7 @@ "src/components/remotecontrol/remotecontrol.js", "src/components/sanatizefilename.js", "src/components/scrollManager.js", + "src/plugins/htmlAudioPlayer/plugin.js", "src/plugins/chromecastPlayer/plugin.js", "src/components/slideshow/slideshow.js", "src/components/sortmenu/sortmenu.js", diff --git a/src/plugins/htmlAudioPlayer/plugin.js b/src/plugins/htmlAudioPlayer/plugin.js index 16fce8c9d1..acce15df88 100644 --- a/src/plugins/htmlAudioPlayer/plugin.js +++ b/src/plugins/htmlAudioPlayer/plugin.js @@ -1,91 +1,92 @@ -define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) { - 'use strict'; +import events from 'events'; +import browser from 'browser'; +import appHost from 'apphost'; +import * as htmlMediaHelper from 'htmlMediaHelper'; - function getDefaultProfile() { - return new Promise(function (resolve, reject) { - require(['browserdeviceprofile'], function (profileBuilder) { - resolve(profileBuilder({})); - }); +function getDefaultProfile() { + return import('browserdeviceprofile').then(({ default: profileBuilder }) => { + return profileBuilder({}); + }); +} + +let fadeTimeout; +function fade(instance, elem, startingVolume) { + instance._isFadingOut = true; + + // Need to record the starting volume on each pass rather than querying elem.volume + // This is due to iOS safari not allowing volume changes and always returning the system volume value + const newVolume = Math.max(0, startingVolume - 0.15); + console.debug('fading volume to ' + newVolume); + elem.volume = newVolume; + + if (newVolume <= 0) { + instance._isFadingOut = false; + return Promise.resolve(); + } + + return new Promise(function (resolve, reject) { + cancelFadeTimeout(); + fadeTimeout = setTimeout(function () { + fade(instance, elem, newVolume).then(resolve, reject); + }, 100); + }); +} + +function cancelFadeTimeout() { + const timeout = fadeTimeout; + if (timeout) { + clearTimeout(timeout); + fadeTimeout = null; + } +} + +function supportsFade() { + if (browser.tv) { + // Not working on tizen. + // We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive + return false; + } + + return true; +} + +function requireHlsPlayer(callback) { + import('hlsjs').then(({ default: hls }) => { + window.Hls = hls; + callback(); + }); +} + +function enableHlsPlayer(url, item, mediaSource, mediaType) { + if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) { + return Promise.reject(); + } + + if (url.indexOf('.m3u8') !== -1) { + return Promise.resolve(); + } + + // issue head request to get content type + return new Promise(function (resolve, reject) { + import('fetchHelper').then((fetchHelper) => { + fetchHelper.ajax({ + url: url, + type: 'HEAD' + }).then(function (response) { + const contentType = (response.headers.get('Content-Type') || '').toLowerCase(); + if (contentType === 'application/x-mpegurl') { + resolve(); + } else { + reject(); + } + }, reject); }); - } + }); +} - var fadeTimeout; - function fade(instance, elem, startingVolume) { - instance._isFadingOut = true; - - // Need to record the starting volume on each pass rather than querying elem.volume - // This is due to iOS safari not allowing volume changes and always returning the system volume value - var newVolume = Math.max(0, startingVolume - 0.15); - console.debug('fading volume to ' + newVolume); - elem.volume = newVolume; - - if (newVolume <= 0) { - instance._isFadingOut = false; - return Promise.resolve(); - } - - return new Promise(function (resolve, reject) { - cancelFadeTimeout(); - fadeTimeout = setTimeout(function () { - fade(instance, elem, newVolume).then(resolve, reject); - }, 100); - }); - } - - function cancelFadeTimeout() { - var timeout = fadeTimeout; - if (timeout) { - clearTimeout(timeout); - fadeTimeout = null; - } - } - - function supportsFade() { - if (browser.tv) { - // Not working on tizen. - // We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive - return false; - } - - return true; - } - - function requireHlsPlayer(callback) { - require(['hlsjs'], function (hls) { - window.Hls = hls; - callback(); - }); - } - - function enableHlsPlayer(url, item, mediaSource, mediaType) { - if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) { - return Promise.reject(); - } - - if (url.indexOf('.m3u8') !== -1) { - return Promise.resolve(); - } - - // issue head request to get content type - return new Promise(function (resolve, reject) { - require(['fetchHelper'], function (fetchHelper) { - fetchHelper.ajax({ - url: url, - type: 'HEAD' - }).then(function (response) { - var contentType = (response.headers.get('Content-Type') || '').toLowerCase(); - if (contentType === 'application/x-mpegurl') { - resolve(); - } else { - reject(); - } - }, reject); - }); - }); - } - - function HtmlAudioPlayer() { - var self = this; +class HtmlAudioPlayer { + constructor() { + const self = this; self.name = 'Html Audio Player'; self.type = 'mediaplayer'; @@ -99,7 +100,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp self._timeUpdated = false; self._currentTime = null; - var elem = createMediaElement(); + const elem = createMediaElement(); return setCurrentSrc(elem, options); }; @@ -109,11 +110,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp unBindEvents(elem); bindEvents(elem); - var val = options.url; + 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; } @@ -122,7 +123,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp self._currentPlayOptions = options; - var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource); + const crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource); if (crossOrigin) { elem.crossOrigin = crossOrigin; } @@ -130,9 +131,9 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () { return new Promise(function (resolve, reject) { requireHlsPlayer(function () { - var hls = new Hls({ + const hls = new Hls({ manifestLoadingTimeOut: 20000, - xhrSetup: function(xhr, url) { + xhrSetup: function (xhr, url) { xhr.withCredentials = true; } }); @@ -183,8 +184,8 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp self.stop = function (destroyPlayer) { cancelFadeTimeout(); - var elem = self._mediaElement; - var src = self._currentSrc; + const elem = self._mediaElement; + const src = self._currentSrc; if (elem && src) { if (!destroyPlayer || !supportsFade()) { @@ -198,7 +199,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp return Promise.resolve(); } - var originalVolume = elem.volume; + const originalVolume = elem.volume; return fade(self, elem, elem.volume).then(function () { elem.pause(); @@ -219,7 +220,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp }; function createMediaElement() { - var elem = self._mediaElement; + let elem = self._mediaElement; if (elem) { return elem; @@ -248,7 +249,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp function onTimeUpdate() { // Get the player position + the transcoding offset - var time = this.currentTime; + const time = this.currentTime; // Don't trigger events after user stop if (!self._isFadingOut) { @@ -287,11 +288,11 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp } function onError() { - var errorCode = this.error ? (this.error.code || 0) : 0; - var errorMessage = this.error ? (this.error.message || '') : ''; + const errorCode = this.error ? (this.error.code || 0) : 0; + const errorMessage = this.error ? (this.error.message || '') : ''; console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage); - var type; + let type; switch (errorCode) { case 1: @@ -325,59 +326,59 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp } } - HtmlAudioPlayer.prototype.currentSrc = function () { + currentSrc() { return this._currentSrc; - }; + } - HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) { + canPlayMediaType(mediaType) { return (mediaType || '').toLowerCase() === 'audio'; - }; + } - HtmlAudioPlayer.prototype.getDeviceProfile = function (item) { + getDeviceProfile(item) { if (appHost.getDeviceProfile) { return appHost.getDeviceProfile(item); } return getDefaultProfile(); - }; + } // Save this for when playback stops, because querying the time at that point might return 0 - HtmlAudioPlayer.prototype.currentTime = function (val) { - var mediaElement = this._mediaElement; + currentTime(val) { + const mediaElement = this._mediaElement; if (mediaElement) { if (val != null) { mediaElement.currentTime = val / 1000; return; } - var currentTime = this._currentTime; + const currentTime = this._currentTime; if (currentTime) { return currentTime * 1000; } return (mediaElement.currentTime || 0) * 1000; } - }; + } - HtmlAudioPlayer.prototype.duration = function (val) { - var mediaElement = this._mediaElement; + duration(val) { + const mediaElement = this._mediaElement; if (mediaElement) { - var duration = mediaElement.duration; + const duration = mediaElement.duration; if (htmlMediaHelper.isValidDuration(duration)) { return duration * 1000; } } return null; - }; + } - HtmlAudioPlayer.prototype.seekable = function () { - var mediaElement = this._mediaElement; + seekable() { + const mediaElement = this._mediaElement; if (mediaElement) { - var seekable = mediaElement.seekable; + const seekable = mediaElement.seekable; if (seekable && seekable.length) { - var start = seekable.start(0); - var end = seekable.end(0); + let start = seekable.start(0); + let end = seekable.end(0); if (!htmlMediaHelper.isValidDuration(start)) { start = 0; @@ -391,124 +392,120 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp return false; } - }; + } - HtmlAudioPlayer.prototype.getBufferedRanges = function () { - var mediaElement = this._mediaElement; + getBufferedRanges() { + const mediaElement = this._mediaElement; if (mediaElement) { return htmlMediaHelper.getBufferedRanges(this, mediaElement); } return []; - }; + } - HtmlAudioPlayer.prototype.pause = function () { - var mediaElement = this._mediaElement; + pause() { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.pause(); } - }; + } // This is a retry after error - HtmlAudioPlayer.prototype.resume = function () { - var mediaElement = this._mediaElement; + resume() { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.play(); } - }; + } - HtmlAudioPlayer.prototype.unpause = function () { - var mediaElement = this._mediaElement; + unpause() { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.play(); } - }; + } - HtmlAudioPlayer.prototype.paused = function () { - var mediaElement = this._mediaElement; + paused() { + const mediaElement = this._mediaElement; if (mediaElement) { return mediaElement.paused; } return false; - }; + } - HtmlAudioPlayer.prototype.setPlaybackRate = function (value) { - var mediaElement = this._mediaElement; + setPlaybackRate(value) { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.playbackRate = value; } - }; + } - HtmlAudioPlayer.prototype.getPlaybackRate = function () { - var mediaElement = this._mediaElement; + getPlaybackRate() { + const mediaElement = this._mediaElement; if (mediaElement) { return mediaElement.playbackRate; } return null; - }; + } - HtmlAudioPlayer.prototype.setVolume = function (val) { - var mediaElement = this._mediaElement; + setVolume(val) { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.volume = val / 100; } - }; + } - HtmlAudioPlayer.prototype.getVolume = function () { - var mediaElement = this._mediaElement; + getVolume() { + const mediaElement = this._mediaElement; if (mediaElement) { return Math.min(Math.round(mediaElement.volume * 100), 100); } - }; + } - HtmlAudioPlayer.prototype.volumeUp = function () { + volumeUp() { this.setVolume(Math.min(this.getVolume() + 2, 100)); - }; + } - HtmlAudioPlayer.prototype.volumeDown = function () { + volumeDown() { this.setVolume(Math.max(this.getVolume() - 2, 0)); - }; + } - HtmlAudioPlayer.prototype.setMute = function (mute) { - var mediaElement = this._mediaElement; + setMute(mute) { + const mediaElement = this._mediaElement; if (mediaElement) { mediaElement.muted = mute; } - }; + } - HtmlAudioPlayer.prototype.isMuted = function () { - var mediaElement = this._mediaElement; + isMuted() { + const mediaElement = this._mediaElement; if (mediaElement) { return mediaElement.muted; } return false; - }; - - HtmlAudioPlayer.prototype.destroy = function () { - - }; - - var supportedFeatures; - - function getSupportedFeatures() { - var list = []; - var audio = document.createElement('audio'); - - if (typeof audio.playbackRate === 'number') { - list.push('PlaybackRate'); - } - - return list; } - HtmlAudioPlayer.prototype.supports = function (feature) { + supports(feature) { if (!supportedFeatures) { supportedFeatures = getSupportedFeatures(); } return supportedFeatures.indexOf(feature) !== -1; - }; + } +} - return HtmlAudioPlayer; -}); +let supportedFeatures; + +function getSupportedFeatures() { + const list = []; + const audio = document.createElement('audio'); + + if (typeof audio.playbackRate === 'number') { + list.push('PlaybackRate'); + } + + return list; +} + +export default HtmlAudioPlayer;