From a72c843b13453a4c9020d18adc46c9337cdcaf75 Mon Sep 17 00:00:00 2001 From: Cameron Date: Fri, 31 Jul 2020 09:12:30 +0100 Subject: [PATCH] Migration of playbackmanager to ES6 module --- package.json | 1 + src/components/playback/playbackmanager.js | 2080 ++++++++++---------- 2 files changed, 1036 insertions(+), 1045 deletions(-) diff --git a/package.json b/package.json index a18eb8e0fb..e785ae2ebd 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "src/components/playback/mediasession.js", "src/components/playback/nowplayinghelper.js", "src/components/playback/playbackorientation.js", + "src/components/playback/playbackmanager.js", "src/components/playback/playerSelectionMenu.js", "src/components/playback/playersettingsmenu.js", "src/components/playback/playmethodhelper.js", diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 1d74cd69f5..99a21dd3e2 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1,729 +1,738 @@ -define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) { - 'use strict'; - - PlayQueueManager = PlayQueueManager.default || PlayQueueManager; - - function enableLocalPlaylistManagement(player) { - if (player.getPlaylist) { - return false; - } - - if (player.isLocalPlayer) { - return true; - } +import events from 'events'; +import datetime from 'datetime'; +import appSettings from 'appSettings'; +import itemHelper from 'itemHelper'; +import pluginManager from 'pluginManager'; +import PlayQueueManager from 'playQueueManager'; +import * as userSettings from 'userSettings'; +import globalize from 'globalize'; +import connectionManager from 'connectionManager'; +import loading from 'loading'; +import apphost from 'apphost'; +import screenfull from 'screenfull'; +function enableLocalPlaylistManagement(player) { + if (player.getPlaylist) { return false; } - function bindToFullscreenChange(player) { - if (screenfull.isEnabled) { - screenfull.on('change', function () { - events.trigger(player, 'fullscreenchange'); - }); - } else { - // iOS Safari - document.addEventListener('webkitfullscreenchange', function () { - events.trigger(player, 'fullscreenchange'); - }, false); - } - } - - function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) { - if (!newPlayer && !previousPlayer) { - return; - } - - if (newTarget && previousTargetInfo) { - if (newTarget.id === previousTargetInfo.id) { - return; - } - } - - events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]); - } - - function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) { - if (!serverId) { - // Not a server item - // We can expand on this later and possibly report them - events.trigger(playbackManagerInstance, 'reportplayback', [false]); - return; - } - - var info = Object.assign({}, state.PlayState); - info.ItemId = state.NowPlayingItem.Id; - - if (progressEventName) { - info.EventName = progressEventName; - } - - if (reportPlaylist) { - addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId); - } - - var apiClient = connectionManager.getApiClient(serverId); - var reportPlaybackPromise = apiClient[method](info); - // Notify that report has been sent - reportPlaybackPromise.then(() => { - events.trigger(playbackManagerInstance, 'reportplayback', [true]); - }); - } - - function getPlaylistSync(playbackManagerInstance, player) { - player = player || playbackManagerInstance._currentPlayer; - if (player && !enableLocalPlaylistManagement(player)) { - return player.getPlaylistSync(); - } - - return playbackManagerInstance._playQueueManager.getPlaylist(); - } - - function addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId) { - info.NowPlayingQueue = getPlaylistSync(playbackManagerInstance, player).map(function (i) { - var itemInfo = { - Id: i.Id, - PlaylistItemId: i.PlaylistItemId - }; - - if (i.ServerId !== serverId) { - itemInfo.ServerId = i.ServerId; - } - - return itemInfo; - }); - } - - function normalizeName(t) { - return t.toLowerCase().replace(' ', ''); - } - - function getItemsForPlayback(serverId, query) { - var apiClient = connectionManager.getApiClient(serverId); - - if (query.Ids && query.Ids.split(',').length === 1) { - var itemId = query.Ids.split(','); - - return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { - return { - Items: [item], - TotalRecordCount: 1 - }; - }); - } else { - query.Limit = query.Limit || 300; - query.Fields = 'Chapters'; - query.ExcludeLocationTypes = 'Virtual'; - query.EnableTotalRecordCount = false; - query.CollapseBoxSetItems = false; - - return apiClient.getItems(apiClient.getCurrentUserId(), query); - } - } - - function createStreamInfoFromUrlItem(item) { - // Check item.Path for games - return { - url: item.Url || item.Path, - playMethod: 'DirectPlay', - item: item, - textTracks: [], - mediaType: item.MediaType - }; - } - - function mergePlaybackQueries(obj1, obj2) { - var query = Object.assign(obj1, obj2); - - var filters = query.Filters ? query.Filters.split(',') : []; - if (filters.indexOf('IsNotFolder') === -1) { - filters.push('IsNotFolder'); - } - query.Filters = filters.join(','); - return query; - } - - function backdropImageUrl(apiClient, item, options) { - options = options || {}; - options.type = options.type || 'Backdrop'; - - // If not resizing, get the original image - if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { - options.quality = 100; - } - - if (item.BackdropImageTags && item.BackdropImageTags.length) { - options.tag = item.BackdropImageTags[0]; - return apiClient.getScaledImageUrl(item.Id, options); - } - - if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { - options.tag = item.ParentBackdropImageTags[0]; - return apiClient.getScaledImageUrl(item.ParentBackdropItemId, options); - } - - return null; - } - - function getMimeType(type, container) { - container = (container || '').toLowerCase(); - - if (type === 'audio') { - if (container === 'opus') { - return 'audio/ogg'; - } - if (container === 'webma') { - return 'audio/webm'; - } - if (container === 'm4a') { - return 'audio/mp4'; - } - } else if (type === 'video') { - if (container === 'mkv') { - return 'video/x-matroska'; - } - if (container === 'm4v') { - return 'video/mp4'; - } - if (container === 'mov') { - return 'video/quicktime'; - } - if (container === 'mpg') { - return 'video/mpeg'; - } - if (container === 'flv') { - return 'video/x-flv'; - } - } - - return type + '/' + container; - } - - function getParam(name, url) { - name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); - var regexS = '[\\?&]' + name + '=([^&#]*)'; - var regex = new RegExp(regexS, 'i'); - - var results = regex.exec(url); - if (results == null) { - return ''; - } else { - return decodeURIComponent(results[1].replace(/\+/g, ' ')); - } - } - - function isAutomaticPlayer(player) { - if (player.isLocalPlayer) { - return true; - } - - return false; - } - - function getAutomaticPlayers(instance, forceLocalPlayer) { - if (!forceLocalPlayer) { - var player = instance._currentPlayer; - if (player && !isAutomaticPlayer(player)) { - return [player]; - } - } - - return instance.getPlayers().filter(isAutomaticPlayer); - } - - function isServerItem(item) { - if (!item.Id) { - return false; - } + if (player.isLocalPlayer) { return true; } - function enableIntros(item) { - if (item.MediaType !== 'Video') { - return false; - } - if (item.Type === 'TvChannel') { - return false; - } - // disable for in-progress recordings - if (item.Status === 'InProgress') { - return false; - } + return false; +} - return isServerItem(item); +function bindToFullscreenChange(player) { + if (screenfull.isEnabled) { + screenfull.on('change', function () { + events.trigger(player, 'fullscreenchange'); + }); + } else { + // iOS Safari + document.addEventListener('webkitfullscreenchange', function () { + events.trigger(player, 'fullscreenchange'); + }, false); + } +} + +function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) { + if (!newPlayer && !previousPlayer) { + return; } - function getIntros(firstItem, apiClient, options) { - if (options.startPositionTicks || options.startIndex || options.fullscreen === false || !enableIntros(firstItem) || !userSettings.enableCinemaMode()) { - return Promise.resolve({ - Items: [] - }); + if (newTarget && previousTargetInfo) { + if (newTarget.id === previousTargetInfo.id) { + return; } - - return apiClient.getIntros(firstItem.Id).then(function (result) { - return result; - }, function (err) { - return Promise.resolve({ - Items: [] - }); - }); } - function getAudioMaxValues(deviceProfile) { - // TODO - this could vary per codec and should be done on the server using the entire profile - var maxAudioSampleRate = null; - var maxAudioBitDepth = null; - var maxAudioBitrate = null; + events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]); +} - deviceProfile.CodecProfiles.map(function (codecProfile) { - if (codecProfile.Type === 'Audio') { - (codecProfile.Conditions || []).map(function (condition) { - if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitDepth') { - return maxAudioBitDepth = condition.Value; - } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioSampleRate') { - return maxAudioSampleRate = condition.Value; - } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitrate') { - return maxAudioBitrate = condition.Value; - } - }); - } - }); +function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) { + if (!serverId) { + // Not a server item + // We can expand on this later and possibly report them + events.trigger(playbackManagerInstance, 'reportplayback', [false]); + return; + } - return { - maxAudioSampleRate: maxAudioSampleRate, - maxAudioBitDepth: maxAudioBitDepth, - maxAudioBitrate: maxAudioBitrate + const info = Object.assign({}, state.PlayState); + info.ItemId = state.NowPlayingItem.Id; + + if (progressEventName) { + info.EventName = progressEventName; + } + + if (reportPlaylist) { + addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId); + } + + const apiClient = connectionManager.getApiClient(serverId); + const reportPlaybackPromise = apiClient[method](info); + // Notify that report has been sent + reportPlaybackPromise.then(() => { + events.trigger(playbackManagerInstance, 'reportplayback', [true]); + }); +} + +function getPlaylistSync(playbackManagerInstance, player) { + player = player || playbackManagerInstance._currentPlayer; + if (player && !enableLocalPlaylistManagement(player)) { + return player.getPlaylistSync(); + } + + return playbackManagerInstance._playQueueManager.getPlaylist(); +} + +function addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId) { + info.NowPlayingQueue = getPlaylistSync(playbackManagerInstance, player).map(function (i) { + const itemInfo = { + Id: i.Id, + PlaylistItemId: i.PlaylistItemId }; + + if (i.ServerId !== serverId) { + itemInfo.ServerId = i.ServerId; + } + + return itemInfo; + }); +} + +function normalizeName(t) { + return t.toLowerCase().replace(' ', ''); +} + +function getItemsForPlayback(serverId, query) { + const apiClient = connectionManager.getApiClient(serverId); + + if (query.Ids && query.Ids.split(',').length === 1) { + const itemId = query.Ids.split(','); + + return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) { + return { + Items: [item], + TotalRecordCount: 1 + }; + }); + } else { + query.Limit = query.Limit || 300; + query.Fields = 'Chapters'; + query.ExcludeLocationTypes = 'Virtual'; + query.EnableTotalRecordCount = false; + query.CollapseBoxSetItems = false; + + return apiClient.getItems(apiClient.getCurrentUserId(), query); + } +} + +function createStreamInfoFromUrlItem(item) { + // Check item.Path for games + return { + url: item.Url || item.Path, + playMethod: 'DirectPlay', + item: item, + textTracks: [], + mediaType: item.MediaType + }; +} + +function mergePlaybackQueries(obj1, obj2) { + const query = Object.assign(obj1, obj2); + + const filters = query.Filters ? query.Filters.split(',') : []; + if (filters.indexOf('IsNotFolder') === -1) { + filters.push('IsNotFolder'); + } + query.Filters = filters.join(','); + return query; +} + +function backdropImageUrl(apiClient, item, options) { + options = options || {}; + options.type = options.type || 'Backdrop'; + + // If not resizing, get the original image + if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { + options.quality = 100; } - var startingPlaySession = new Date().getTime(); - function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) { - var url = 'Audio/' + item.Id + '/universal'; + if (item.BackdropImageTags && item.BackdropImageTags.length) { + options.tag = item.BackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.Id, options); + } - startingPlaySession++; - return apiClient.getUrl(url, { - UserId: apiClient.getCurrentUserId(), - DeviceId: apiClient.deviceId(), - MaxStreamingBitrate: maxAudioBitrate || maxBitrate, - Container: directPlayContainers, - TranscodingContainer: transcodingProfile.Container || null, - TranscodingProtocol: transcodingProfile.Protocol || null, - AudioCodec: transcodingProfile.AudioCodec, - MaxAudioSampleRate: maxAudioSampleRate, - MaxAudioBitDepth: maxAudioBitDepth, - api_key: apiClient.accessToken(), - PlaySessionId: startingPlaySession, - StartTimeTicks: startPosition || 0, - EnableRedirection: true, - EnableRemoteMedia: apphost.supports('remoteaudio') + if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + options.tag = item.ParentBackdropImageTags[0]; + return apiClient.getScaledImageUrl(item.ParentBackdropItemId, options); + } + + return null; +} + +function getMimeType(type, container) { + container = (container || '').toLowerCase(); + + if (type === 'audio') { + if (container === 'opus') { + return 'audio/ogg'; + } + if (container === 'webma') { + return 'audio/webm'; + } + if (container === 'm4a') { + return 'audio/mp4'; + } + } else if (type === 'video') { + if (container === 'mkv') { + return 'video/x-matroska'; + } + if (container === 'm4v') { + return 'video/mp4'; + } + if (container === 'mov') { + return 'video/quicktime'; + } + if (container === 'mpg') { + return 'video/mpeg'; + } + if (container === 'flv') { + return 'video/x-flv'; + } + } + + return type + '/' + container; +} + +function getParam(name, url) { + name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); + const regexS = '[\\?&]' + name + '=([^&#]*)'; + const regex = new RegExp(regexS, 'i'); + + const results = regex.exec(url); + if (results == null) { + return ''; + } else { + return decodeURIComponent(results[1].replace(/\+/g, ' ')); + } +} + +function isAutomaticPlayer(player) { + if (player.isLocalPlayer) { + return true; + } + + return false; +} + +function getAutomaticPlayers(instance, forceLocalPlayer) { + if (!forceLocalPlayer) { + const player = instance._currentPlayer; + if (player && !isAutomaticPlayer(player)) { + return [player]; + } + } + + return instance.getPlayers().filter(isAutomaticPlayer); +} + +function isServerItem(item) { + if (!item.Id) { + return false; + } + return true; +} + +function enableIntros(item) { + if (item.MediaType !== 'Video') { + return false; + } + if (item.Type === 'TvChannel') { + return false; + } + // disable for in-progress recordings + if (item.Status === 'InProgress') { + return false; + } + + return isServerItem(item); +} + +function getIntros(firstItem, apiClient, options) { + if (options.startPositionTicks || options.startIndex || options.fullscreen === false || !enableIntros(firstItem) || !userSettings.enableCinemaMode()) { + return Promise.resolve({ + Items: [] }); } - function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition) { - var transcodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { - return p.Type === 'Audio' && p.Context === 'Streaming'; + return apiClient.getIntros(firstItem.Id).then(function (result) { + return result; + }, function (err) { + return Promise.resolve({ + Items: [] + }); + }); +} + +function getAudioMaxValues(deviceProfile) { + // TODO - this could vary per codec and should be done on the server using the entire profile + let maxAudioSampleRate = null; + let maxAudioBitDepth = null; + let maxAudioBitrate = null; + + deviceProfile.CodecProfiles.map(function (codecProfile) { + if (codecProfile.Type === 'Audio') { + (codecProfile.Conditions || []).map(function (condition) { + if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitDepth') { + return maxAudioBitDepth = condition.Value; + } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioSampleRate') { + return maxAudioSampleRate = condition.Value; + } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitrate') { + return maxAudioBitrate = condition.Value; + } + }); + } + }); + + return { + maxAudioSampleRate: maxAudioSampleRate, + maxAudioBitDepth: maxAudioBitDepth, + maxAudioBitrate: maxAudioBitrate + }; +} + +let startingPlaySession = new Date().getTime(); +function getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxAudioSampleRate, maxAudioBitDepth, maxAudioBitrate, startPosition) { + const url = 'Audio/' + item.Id + '/universal'; + + startingPlaySession++; + return apiClient.getUrl(url, { + UserId: apiClient.getCurrentUserId(), + DeviceId: apiClient.deviceId(), + MaxStreamingBitrate: maxAudioBitrate || maxBitrate, + Container: directPlayContainers, + TranscodingContainer: transcodingProfile.Container || null, + TranscodingProtocol: transcodingProfile.Protocol || null, + AudioCodec: transcodingProfile.AudioCodec, + MaxAudioSampleRate: maxAudioSampleRate, + MaxAudioBitDepth: maxAudioBitDepth, + api_key: apiClient.accessToken(), + PlaySessionId: startingPlaySession, + StartTimeTicks: startPosition || 0, + EnableRedirection: true, + EnableRemoteMedia: apphost.supports('remoteaudio') + }); +} + +function getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition) { + const transcodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { + return p.Type === 'Audio' && p.Context === 'Streaming'; + })[0]; + + let directPlayContainers = ''; + + deviceProfile.DirectPlayProfiles.map(function (p) { + if (p.Type === 'Audio') { + if (directPlayContainers) { + directPlayContainers += ',' + p.Container; + } else { + directPlayContainers = p.Container; + } + + if (p.AudioCodec) { + directPlayContainers += '|' + p.AudioCodec; + } + } + }); + + const maxValues = getAudioMaxValues(deviceProfile); + + return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); +} + +function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { + const audioTranscodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { + return p.Type === 'Audio' && p.Context === 'Streaming'; + })[0]; + + let audioDirectPlayContainers = ''; + + deviceProfile.DirectPlayProfiles.map(function (p) { + if (p.Type === 'Audio') { + if (audioDirectPlayContainers) { + audioDirectPlayContainers += ',' + p.Container; + } else { + audioDirectPlayContainers = p.Container; + } + + if (p.AudioCodec) { + audioDirectPlayContainers += '|' + p.AudioCodec; + } + } + }); + + const maxValues = getAudioMaxValues(deviceProfile); + + const streamUrls = []; + + for (let i = 0, length = items.length; i < length; i++) { + const item = items[i]; + let streamUrl; + + if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) { + streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); + } + + streamUrls.push(streamUrl || ''); + + if (i === 0) { + startPosition = 0; + } + } + + return Promise.resolve(streamUrls); +} + +function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { + return getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition).then(function (streamUrls) { + for (let i = 0, length = items.length; i < length; i++) { + const item = items[i]; + const streamUrl = streamUrls[i]; + + if (streamUrl) { + item.PresetMediaSource = { + StreamUrl: streamUrl, + Id: item.Id, + MediaStreams: [], + RunTimeTicks: item.RunTimeTicks + }; + } + } + }); +} + +function getPlaybackInfo(player, + apiClient, + item, + deviceProfile, + maxBitrate, + startPosition, + isPlayback, + mediaSourceId, + audioStreamIndex, + subtitleStreamIndex, + liveStreamId, + enableDirectPlay, + enableDirectStream, + allowVideoStreamCopy, + allowAudioStreamCopy) { + if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio') { + return Promise.resolve({ + MediaSources: [ + { + StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition), + Id: item.Id, + MediaStreams: [], + RunTimeTicks: item.RunTimeTicks + }] + }); + } + + if (item.PresetMediaSource) { + return Promise.resolve({ + MediaSources: [item.PresetMediaSource] + }); + } + + const itemId = item.Id; + + const query = { + UserId: apiClient.getCurrentUserId(), + StartTimeTicks: startPosition || 0 + }; + + if (isPlayback) { + query.IsPlayback = true; + query.AutoOpenLiveStream = true; + } else { + query.IsPlayback = false; + query.AutoOpenLiveStream = false; + } + + if (audioStreamIndex != null) { + query.AudioStreamIndex = audioStreamIndex; + } + if (subtitleStreamIndex != null) { + query.SubtitleStreamIndex = subtitleStreamIndex; + } + if (enableDirectPlay != null) { + query.EnableDirectPlay = enableDirectPlay; + } + + if (enableDirectStream != null) { + query.EnableDirectStream = enableDirectStream; + } + if (allowVideoStreamCopy != null) { + query.AllowVideoStreamCopy = allowVideoStreamCopy; + } + if (allowAudioStreamCopy != null) { + query.AllowAudioStreamCopy = allowAudioStreamCopy; + } + if (mediaSourceId) { + query.MediaSourceId = mediaSourceId; + } + if (liveStreamId) { + query.LiveStreamId = liveStreamId; + } + if (maxBitrate) { + query.MaxStreamingBitrate = maxBitrate; + } + if (player.enableMediaProbe && !player.enableMediaProbe(item)) { + query.EnableMediaProbe = false; + } + + // lastly, enforce player overrides for special situations + if (query.EnableDirectStream !== false) { + if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { + query.EnableDirectStream = false; + } + } + + if (player.getDirectPlayProtocols) { + query.DirectPlayProtocols = player.getDirectPlayProtocols(); + } + + return apiClient.getPlaybackInfo(itemId, query, deviceProfile); +} + +function getOptimalMediaSource(apiClient, item, versions) { + const promises = versions.map(function (v) { + return supportsDirectPlay(apiClient, item, v); + }); + + if (!promises.length) { + return Promise.reject(); + } + + return Promise.all(promises).then(function (results) { + for (let i = 0, length = versions.length; i < length; i++) { + versions[i].enableDirectPlay = results[i] || false; + } + let optimalVersion = versions.filter(function (v) { + return v.enableDirectPlay; })[0]; - var directPlayContainers = ''; + if (!optimalVersion) { + optimalVersion = versions.filter(function (v) { + return v.SupportsDirectStream; + })[0]; + } - deviceProfile.DirectPlayProfiles.map(function (p) { - if (p.Type === 'Audio') { - if (directPlayContainers) { - directPlayContainers += ',' + p.Container; - } else { - directPlayContainers = p.Container; - } - - if (p.AudioCodec) { - directPlayContainers += '|' + p.AudioCodec; - } - } - }); - - var maxValues = getAudioMaxValues(deviceProfile); - - return getAudioStreamUrl(item, transcodingProfile, directPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); - } - - function getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { - var audioTranscodingProfile = deviceProfile.TranscodingProfiles.filter(function (p) { - return p.Type === 'Audio' && p.Context === 'Streaming'; + optimalVersion = optimalVersion || versions.filter(function (s) { + return s.SupportsTranscoding; })[0]; - var audioDirectPlayContainers = ''; + return optimalVersion || versions[0]; + }); +} - deviceProfile.DirectPlayProfiles.map(function (p) { - if (p.Type === 'Audio') { - if (audioDirectPlayContainers) { - audioDirectPlayContainers += ',' + p.Container; - } else { - audioDirectPlayContainers = p.Container; - } +function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) { + const postData = { + DeviceProfile: deviceProfile, + OpenToken: mediaSource.OpenToken + }; - if (p.AudioCodec) { - audioDirectPlayContainers += '|' + p.AudioCodec; + const query = { + UserId: apiClient.getCurrentUserId(), + StartTimeTicks: startPosition || 0, + ItemId: item.Id, + PlaySessionId: playSessionId + }; + + if (maxBitrate) { + query.MaxStreamingBitrate = maxBitrate; + } + if (audioStreamIndex != null) { + query.AudioStreamIndex = audioStreamIndex; + } + if (subtitleStreamIndex != null) { + query.SubtitleStreamIndex = subtitleStreamIndex; + } + + // lastly, enforce player overrides for special situations + if (query.EnableDirectStream !== false) { + if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { + query.EnableDirectStream = false; + } + } + + return apiClient.ajax({ + url: apiClient.getUrl('LiveStreams/Open', query), + type: 'POST', + data: JSON.stringify(postData), + contentType: 'application/json', + dataType: 'json' + + }); +} + +function isHostReachable(mediaSource, apiClient) { + if (mediaSource.IsRemote) { + return Promise.resolve(true); + } + + return apiClient.getEndpointInfo().then(function (endpointInfo) { + if (endpointInfo.IsInNetwork) { + if (!endpointInfo.IsLocal) { + const path = (mediaSource.Path || '').toLowerCase(); + if (path.indexOf('localhost') !== -1 || path.indexOf('127.0.0.1') !== -1) { + // This will only work if the app is on the same machine as the server + return Promise.resolve(false); } } - }); - var maxValues = getAudioMaxValues(deviceProfile); - - var streamUrls = []; - - for (var i = 0, length = items.length; i < length; i++) { - var item = items[i]; - var streamUrl; - - if (item.MediaType === 'Audio' && !itemHelper.isLocalItem(item)) { - streamUrl = getAudioStreamUrl(item, audioTranscodingProfile, audioDirectPlayContainers, maxBitrate, apiClient, maxValues.maxAudioSampleRate, maxValues.maxAudioBitDepth, maxValues.maxAudioBitrate, startPosition); - } - - streamUrls.push(streamUrl || ''); - - if (i === 0) { - startPosition = 0; - } - } - - return Promise.resolve(streamUrls); - } - - function setStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition) { - return getStreamUrls(items, deviceProfile, maxBitrate, apiClient, startPosition).then(function (streamUrls) { - for (var i = 0, length = items.length; i < length; i++) { - var item = items[i]; - var streamUrl = streamUrls[i]; - - if (streamUrl) { - item.PresetMediaSource = { - StreamUrl: streamUrl, - Id: item.Id, - MediaStreams: [], - RunTimeTicks: item.RunTimeTicks - }; - } - } - }); - } - - function getPlaybackInfo(player, - apiClient, - item, - deviceProfile, - maxBitrate, - startPosition, - isPlayback, - mediaSourceId, - audioStreamIndex, - subtitleStreamIndex, - liveStreamId, - enableDirectPlay, - enableDirectStream, - allowVideoStreamCopy, - allowAudioStreamCopy) { - if (!itemHelper.isLocalItem(item) && item.MediaType === 'Audio') { - return Promise.resolve({ - MediaSources: [ - { - StreamUrl: getAudioStreamUrlFromDeviceProfile(item, deviceProfile, maxBitrate, apiClient, startPosition), - Id: item.Id, - MediaStreams: [], - RunTimeTicks: item.RunTimeTicks - }] - }); - } - - if (item.PresetMediaSource) { - return Promise.resolve({ - MediaSources: [item.PresetMediaSource] - }); - } - - var itemId = item.Id; - - var query = { - UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0 - }; - - if (isPlayback) { - query.IsPlayback = true; - query.AutoOpenLiveStream = true; - } else { - query.IsPlayback = false; - query.AutoOpenLiveStream = false; - } - - if (audioStreamIndex != null) { - query.AudioStreamIndex = audioStreamIndex; - } - if (subtitleStreamIndex != null) { - query.SubtitleStreamIndex = subtitleStreamIndex; - } - if (enableDirectPlay != null) { - query.EnableDirectPlay = enableDirectPlay; - } - - if (enableDirectStream != null) { - query.EnableDirectStream = enableDirectStream; - } - if (allowVideoStreamCopy != null) { - query.AllowVideoStreamCopy = allowVideoStreamCopy; - } - if (allowAudioStreamCopy != null) { - query.AllowAudioStreamCopy = allowAudioStreamCopy; - } - if (mediaSourceId) { - query.MediaSourceId = mediaSourceId; - } - if (liveStreamId) { - query.LiveStreamId = liveStreamId; - } - if (maxBitrate) { - query.MaxStreamingBitrate = maxBitrate; - } - if (player.enableMediaProbe && !player.enableMediaProbe(item)) { - query.EnableMediaProbe = false; - } - - // lastly, enforce player overrides for special situations - if (query.EnableDirectStream !== false) { - if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { - query.EnableDirectStream = false; - } - } - - if (player.getDirectPlayProtocols) { - query.DirectPlayProtocols = player.getDirectPlayProtocols(); - } - - return apiClient.getPlaybackInfo(itemId, query, deviceProfile); - } - - function getOptimalMediaSource(apiClient, item, versions) { - var promises = versions.map(function (v) { - return supportsDirectPlay(apiClient, item, v); - }); - - if (!promises.length) { - return Promise.reject(); - } - - return Promise.all(promises).then(function (results) { - for (var i = 0, length = versions.length; i < length; i++) { - versions[i].enableDirectPlay = results[i] || false; - } - var optimalVersion = versions.filter(function (v) { - return v.enableDirectPlay; - })[0]; - - if (!optimalVersion) { - optimalVersion = versions.filter(function (v) { - return v.SupportsDirectStream; - })[0]; - } - - optimalVersion = optimalVersion || versions.filter(function (s) { - return s.SupportsTranscoding; - })[0]; - - return optimalVersion || versions[0]; - }); - } - - function getLiveStream(player, apiClient, item, playSessionId, deviceProfile, maxBitrate, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) { - var postData = { - DeviceProfile: deviceProfile, - OpenToken: mediaSource.OpenToken - }; - - var query = { - UserId: apiClient.getCurrentUserId(), - StartTimeTicks: startPosition || 0, - ItemId: item.Id, - PlaySessionId: playSessionId - }; - - if (maxBitrate) { - query.MaxStreamingBitrate = maxBitrate; - } - if (audioStreamIndex != null) { - query.AudioStreamIndex = audioStreamIndex; - } - if (subtitleStreamIndex != null) { - query.SubtitleStreamIndex = subtitleStreamIndex; - } - - // lastly, enforce player overrides for special situations - if (query.EnableDirectStream !== false) { - if (player.supportsPlayMethod && !player.supportsPlayMethod('DirectStream', item)) { - query.EnableDirectStream = false; - } - } - - return apiClient.ajax({ - url: apiClient.getUrl('LiveStreams/Open', query), - type: 'POST', - data: JSON.stringify(postData), - contentType: 'application/json', - dataType: 'json' - - }); - } - - function isHostReachable(mediaSource, apiClient) { - if (mediaSource.IsRemote) { return Promise.resolve(true); } - return apiClient.getEndpointInfo().then(function (endpointInfo) { - if (endpointInfo.IsInNetwork) { - if (!endpointInfo.IsLocal) { - var path = (mediaSource.Path || '').toLowerCase(); - if (path.indexOf('localhost') !== -1 || path.indexOf('127.0.0.1') !== -1) { - // This will only work if the app is on the same machine as the server - return Promise.resolve(false); - } - } + // media source is in network, but connection is out of network + return Promise.resolve(false); + }); +} - return Promise.resolve(true); - } +function supportsDirectPlay(apiClient, item, mediaSource) { + // folder rip hacks due to not yet being supported by the stream building engine + const isFolderRip = mediaSource.VideoType === 'BluRay' || mediaSource.VideoType === 'Dvd' || mediaSource.VideoType === 'HdDvd'; - // media source is in network, but connection is out of network + if (mediaSource.SupportsDirectPlay || isFolderRip) { + if (mediaSource.IsRemote && !apphost.supports('remotevideo')) { return Promise.resolve(false); - }); - } + } - function supportsDirectPlay(apiClient, item, mediaSource) { - // folder rip hacks due to not yet being supported by the stream building engine - var isFolderRip = mediaSource.VideoType === 'BluRay' || mediaSource.VideoType === 'Dvd' || mediaSource.VideoType === 'HdDvd'; - - if (mediaSource.SupportsDirectPlay || isFolderRip) { - if (mediaSource.IsRemote && !apphost.supports('remotevideo')) { - return Promise.resolve(false); + if (mediaSource.Protocol === 'Http' && !mediaSource.RequiredHttpHeaders.length) { + // If this is the only way it can be played, then allow it + if (!mediaSource.SupportsDirectStream && !mediaSource.SupportsTranscoding) { + return Promise.resolve(true); + } else { + return isHostReachable(mediaSource, apiClient); } + } else if (mediaSource.Protocol === 'File') { + return new Promise(function (resolve, reject) { + // Determine if the file can be accessed directly + import('filesystem').then(({ default: filesystem }) => { + const method = isFolderRip ? + 'directoryExists' : + 'fileExists'; - if (mediaSource.Protocol === 'Http' && !mediaSource.RequiredHttpHeaders.length) { - // If this is the only way it can be played, then allow it - if (!mediaSource.SupportsDirectStream && !mediaSource.SupportsTranscoding) { - return Promise.resolve(true); - } else { - return isHostReachable(mediaSource, apiClient); - } - } else if (mediaSource.Protocol === 'File') { - return new Promise(function (resolve, reject) { - // Determine if the file can be accessed directly - require(['filesystem'], function (filesystem) { - var method = isFolderRip ? - 'directoryExists' : - 'fileExists'; - - filesystem[method](mediaSource.Path).then(function () { - resolve(true); - }, function () { - resolve(false); - }); + filesystem[method](mediaSource.Path).then(function () { + resolve(true); + }, function () { + resolve(false); }); }); - } - } - - return Promise.resolve(false); - } - - function validatePlaybackInfoResult(instance, result) { - if (result.ErrorCode) { - showPlaybackInfoErrorMessage(instance, result.ErrorCode); - return false; - } - - return true; - } - - function showPlaybackInfoErrorMessage(instance, errorCode, playNextTrack) { - require(['alert'], function (alert) { - alert.default({ - text: globalize.translate('PlaybackError' + errorCode), - title: globalize.translate('HeaderPlaybackError') - }).then(function () { - if (playNextTrack) { - instance.nextTrack(); - } }); + } + } + + return Promise.resolve(false); +} + +function validatePlaybackInfoResult(instance, result) { + if (result.ErrorCode) { + showPlaybackInfoErrorMessage(instance, result.ErrorCode); + return false; + } + + return true; +} + +function showPlaybackInfoErrorMessage(instance, errorCode, playNextTrack) { + import('alert').then(({ default: alert }) => { + alert({ + text: globalize.translate('PlaybackError' + errorCode), + title: globalize.translate('HeaderPlaybackError') + }).then(function () { + if (playNextTrack) { + instance.nextTrack(); + } }); + }); +} + +function normalizePlayOptions(playOptions) { + playOptions.fullscreen = playOptions.fullscreen !== false; +} + +function truncatePlayOptions(playOptions) { + return { + fullscreen: playOptions.fullscreen, + mediaSourceId: playOptions.mediaSourceId, + audioStreamIndex: playOptions.audioStreamIndex, + subtitleStreamIndex: playOptions.subtitleStreamIndex, + startPositionTicks: playOptions.startPositionTicks + }; +} + +function getNowPlayingItemForReporting(player, item, mediaSource) { + const nowPlayingItem = Object.assign({}, item); + + if (mediaSource) { + nowPlayingItem.RunTimeTicks = mediaSource.RunTimeTicks; + nowPlayingItem.MediaStreams = mediaSource.MediaStreams; + + // not needed + nowPlayingItem.MediaSources = null; } - function normalizePlayOptions(playOptions) { - playOptions.fullscreen = playOptions.fullscreen !== false; + nowPlayingItem.RunTimeTicks = nowPlayingItem.RunTimeTicks || player.duration() * 10000; + + return nowPlayingItem; +} + +function displayPlayerIndividually(player) { + return !player.isLocalPlayer; +} + +function createTarget(instance, player) { + return { + name: player.name, + id: player.id, + playerName: player.name, + playableMediaTypes: ['Audio', 'Video', 'Photo', 'Book'].map(player.canPlayMediaType), + isLocalPlayer: player.isLocalPlayer, + supportedCommands: instance.getSupportedCommands(player) + }; +} + +function getPlayerTargets(player) { + if (player.getTargets) { + return player.getTargets(); } - function truncatePlayOptions(playOptions) { - return { - fullscreen: playOptions.fullscreen, - mediaSourceId: playOptions.mediaSourceId, - audioStreamIndex: playOptions.audioStreamIndex, - subtitleStreamIndex: playOptions.subtitleStreamIndex, - startPositionTicks: playOptions.startPositionTicks - }; - } + return Promise.resolve([createTarget(player)]); +} - function getNowPlayingItemForReporting(player, item, mediaSource) { - var nowPlayingItem = Object.assign({}, item); +function sortPlayerTargets(a, b) { + let aVal = a.isLocalPlayer ? 0 : 1; + let bVal = b.isLocalPlayer ? 0 : 1; - if (mediaSource) { - nowPlayingItem.RunTimeTicks = mediaSource.RunTimeTicks; - nowPlayingItem.MediaStreams = mediaSource.MediaStreams; + aVal = aVal.toString() + a.name; + bVal = bVal.toString() + b.name; - // not needed - nowPlayingItem.MediaSources = null; - } + return aVal.localeCompare(bVal); +} - nowPlayingItem.RunTimeTicks = nowPlayingItem.RunTimeTicks || player.duration() * 10000; +class PlaybackManager { + constructor() { + const self = this; - return nowPlayingItem; - } - - function displayPlayerIndividually(player) { - return !player.isLocalPlayer; - } - - function createTarget(instance, player) { - return { - name: player.name, - id: player.id, - playerName: player.name, - playableMediaTypes: ['Audio', 'Video', 'Photo', 'Book'].map(player.canPlayMediaType), - isLocalPlayer: player.isLocalPlayer, - supportedCommands: instance.getSupportedCommands(player) - }; - } - - function getPlayerTargets(player) { - if (player.getTargets) { - return player.getTargets(); - } - - return Promise.resolve([createTarget(player)]); - } - - function sortPlayerTargets(a, b) { - var aVal = a.isLocalPlayer ? 0 : 1; - var bVal = b.isLocalPlayer ? 0 : 1; - - aVal = aVal.toString() + a.name; - bVal = bVal.toString() + b.name; - - return aVal.localeCompare(bVal); - } - - function PlaybackManager() { - var self = this; - - var players = []; - var currentTargetInfo; - var currentPairingId = null; + const players = []; + let currentTargetInfo; + let currentPairingId = null; this._playNextAfterEnded = true; - var playerStates = {}; + const playerStates = {}; this._playQueueManager = new PlayQueueManager(); @@ -736,7 +745,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.currentItem(); } - var data = getPlayerData(player); + const data = getPlayerData(player); return data.streamInfo ? data.streamInfo.item : null; }; @@ -749,7 +758,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.currentMediaSource(); } - var data = getPlayerData(player); + const data = getPlayerData(player); return data.streamInfo ? data.streamInfo.mediaSource : null; }; @@ -762,7 +771,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.playMethod(); } - var data = getPlayerData(player); + const data = getPlayerData(player); return data.streamInfo ? data.streamInfo.playMethod : null; }; @@ -775,21 +784,20 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.playSessionId(); } - var data = getPlayerData(player); + const data = getPlayerData(player); return data.streamInfo ? data.streamInfo.playSessionId : null; }; self.getPlayerInfo = function () { - var player = self._currentPlayer; + const player = self._currentPlayer; if (!player) { return null; } - var target = currentTargetInfo || {}; + const target = currentTargetInfo || {}; return { - name: player.name, isLocalPlayer: player.isLocalPlayer, id: target.id, @@ -845,7 +853,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla currentPairingId = targetInfo.id; - var promise = player.tryPair ? + const promise = player.tryPair ? player.tryPair(targetInfo) : Promise.resolve(); @@ -863,11 +871,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; self.getTargets = function () { - var promises = players.filter(displayPlayerIndividually).map(getPlayerTargets); + const promises = players.filter(displayPlayerIndividually).map(getPlayerTargets); return Promise.all(promises).then(function (responses) { return connectionManager.currentApiClient().getCurrentUser().then(function (user) { - var targets = []; + const targets = []; targets.push({ name: globalize.translate('HeaderMyDevice'), @@ -881,10 +889,10 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla user: user }); - for (var i = 0; i < responses.length; i++) { - var subTargets = responses[i]; + for (let i = 0; i < responses.length; i++) { + const subTargets = responses[i]; - for (var j = 0; j < subTargets.length; j++) { + for (let j = 0; j < subTargets.length; j++) { targets.push(subTargets[j]); } } @@ -899,7 +907,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla throw new Error('player cannot be null'); } - var index = getPlayerData(player).subtitleStreamIndex; + const index = getPlayerData(player).subtitleStreamIndex; if (index == null || index === -1) { return null; @@ -928,7 +936,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; function removeCurrentPlayer(player) { - var previousPlayer = self._currentPlayer; + const previousPlayer = self._currentPlayer; if (!previousPlayer || player.id === previousPlayer.id) { setCurrentPlayerInternal(null); @@ -936,8 +944,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function setCurrentPlayerInternal(player, targetInfo) { - var previousPlayer = self._currentPlayer; - var previousTargetInfo = currentTargetInfo; + const previousPlayer = self._currentPlayer; + const previousTargetInfo = currentTargetInfo; if (player && !targetInfo && player.isLocalPlayer) { targetInfo = createTarget(self, player); @@ -988,7 +996,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } if (self.isPlaying(player)) { - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); return playerData.streamInfo.mediaType === mediaType; } @@ -1027,7 +1035,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } self.canPlay = function (item) { - var itemType = item.Type; + const itemType = item.Type; if (itemType === 'PhotoAlbum' || itemType === 'MusicGenre' || itemType === 'Season' || itemType === 'Series' || itemType === 'BoxSet' || itemType === 'MusicAlbum' || itemType === 'MusicArtist' || itemType === 'Playlist') { return true; @@ -1057,12 +1065,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla player = player || self._currentPlayer; if (player) { - var current = self.getAspectRatio(player); + const current = self.getAspectRatio(player); - var supported = self.getSupportedAspectRatios(player); + const supported = self.getSupportedAspectRatios(player); - var index = -1; - for (var i = 0, length = supported.length; i < length; i++) { + let index = -1; + for (let i = 0, length = supported.length; i < length; i++) { if (supported[i].id === current) { index = i; break; @@ -1104,7 +1112,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } }; - var brightnessOsdLoaded; + let brightnessOsdLoaded; self.setBrightness = function (val, player) { player = player || self._currentPlayer; @@ -1112,7 +1120,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (!brightnessOsdLoaded) { brightnessOsdLoaded = true; // TODO: Have this trigger an event instead to get the osd out of here - require(['brightnessOsd']); + import('brightnessOsd').then(); } player.setBrightness(val); } @@ -1168,11 +1176,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var currentMediaSource = self.currentMediaSource(player); - var mediaStreams = []; - var i; - var length; - for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { + const currentMediaSource = self.currentMediaSource(player); + const mediaStreams = []; + for (let i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { if (currentMediaSource.MediaStreams[i].Type === 'Audio') { mediaStreams.push(currentMediaSource.MediaStreams[i]); } @@ -1183,16 +1189,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var currentStreamIndex = self.getAudioStreamIndex(player); - var indexInList = -1; - for (i = 0, length = mediaStreams.length; i < length; i++) { + const currentStreamIndex = self.getAudioStreamIndex(player); + let indexInList = -1; + for (let i = 0, length = mediaStreams.length; i < length; i++) { if (mediaStreams[i].Index === currentStreamIndex) { indexInList = i; break; } } - var nextIndex = indexInList + 1; + let nextIndex = indexInList + 1; if (nextIndex >= mediaStreams.length) { nextIndex = 0; } @@ -1212,11 +1218,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var currentMediaSource = self.currentMediaSource(player); - var mediaStreams = []; - var i; - var length; - for (i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { + const currentMediaSource = self.currentMediaSource(player); + const mediaStreams = []; + for (let i = 0, length = currentMediaSource.MediaStreams.length; i < length; i++) { if (currentMediaSource.MediaStreams[i].Type === 'Subtitle') { mediaStreams.push(currentMediaSource.MediaStreams[i]); } @@ -1227,16 +1231,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var currentStreamIndex = self.getSubtitleStreamIndex(player); - var indexInList = -1; - for (i = 0, length = mediaStreams.length; i < length; i++) { + const currentStreamIndex = self.getSubtitleStreamIndex(player); + let indexInList = -1; + for (let i = 0, length = mediaStreams.length; i < length; i++) { if (mediaStreams[i].Index === currentStreamIndex) { indexInList = i; break; } } - var nextIndex = indexInList + 1; + let nextIndex = indexInList + 1; if (nextIndex >= mediaStreams.length) { nextIndex = -1; } @@ -1256,12 +1260,10 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; function isAudioStreamSupported(mediaSource, index, deviceProfile) { - var mediaStream; - var i; - var length; - var mediaStreams = mediaSource.MediaStreams; + let mediaStream; + const mediaStreams = mediaSource.MediaStreams; - for (i = 0, length = mediaStreams.length; i < length; i++) { + for (let i = 0, length = mediaStreams.length; i < length; i++) { if (mediaStreams[i].Type === 'Audio' && mediaStreams[i].Index === index) { mediaStream = mediaStreams[i]; break; @@ -1272,13 +1274,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return false; } - var codec = (mediaStream.Codec || '').toLowerCase(); + const codec = (mediaStream.Codec || '').toLowerCase(); if (!codec) { return false; } - var profiles = deviceProfile.DirectPlayProfiles || []; + const profiles = deviceProfile.DirectPlayProfiles || []; return profiles.filter(function (p) { if (p.Type === 'Video') { @@ -1327,7 +1329,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla apiClient = connectionManager.currentApiClient(); } - var endpointInfo = apiClient.getSavedEndpointInfo() || {}; + const endpointInfo = apiClient.getSavedEndpointInfo() || {}; return appSettings.maxStreamingBitrate(endpointInfo.IsInNetwork, mediaType); } @@ -1338,16 +1340,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.getMaxStreamingBitrate(); } - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); if (playerData.maxStreamingBitrate) { return playerData.maxStreamingBitrate; } - var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; - var currentItem = self.currentItem(player); + const mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + const currentItem = self.currentItem(player); - var apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); + const apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); return getSavedMaxStreamingBitrate(apiClient, mediaType); }; @@ -1357,12 +1359,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.enableAutomaticBitrateDetection(); } - var playerData = getPlayerData(player); - var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; - var currentItem = self.currentItem(player); + const playerData = getPlayerData(player); + const mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + const currentItem = self.currentItem(player); - var apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); - var endpointInfo = apiClient.getSavedEndpointInfo() || {}; + const apiClient = currentItem ? connectionManager.getApiClient(currentItem.ServerId) : connectionManager.currentApiClient(); + const endpointInfo = apiClient.getSavedEndpointInfo() || {}; return appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType); }; @@ -1373,13 +1375,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.setMaxStreamingBitrate(options); } - var apiClient = connectionManager.getApiClient(self.currentItem(player).ServerId); + const apiClient = connectionManager.getApiClient(self.currentItem(player).ServerId); apiClient.getEndpointInfo().then(function (endpointInfo) { - var playerData = getPlayerData(player); - var mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; + const playerData = getPlayerData(player); + const mediaType = playerData.streamInfo ? playerData.streamInfo.mediaType : null; - var promise; + let promise; if (options.enableAutomaticBitrateDetection) { appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType, true); promise = apiClient.detectBitrate(true); @@ -1472,17 +1474,17 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.setSubtitleStreamIndex(index); } - var currentStream = getCurrentSubtitleStream(player); + const currentStream = getCurrentSubtitleStream(player); - var newStream = getSubtitleStream(player, index); + const newStream = getSubtitleStream(player, index); if (!currentStream && !newStream) { return; } - var selectedTrackElementIndex = -1; + let selectedTrackElementIndex = -1; - var currentPlayMethod = self.playMethod(player); + const currentPlayMethod = self.playMethod(player); if (currentStream && !newStream) { if (getDeliveryMethod(currentStream) === 'Encode' || (getDeliveryMethod(currentStream) === 'Embed' && currentPlayMethod === 'Transcode')) { @@ -1519,30 +1521,30 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla getPlayerData(player).subtitleStreamIndex = index; }; - self.supportSubtitleOffset = function(player) { + self.supportSubtitleOffset = function (player) { player = player || self._currentPlayer; return player && 'setSubtitleOffset' in player; }; - self.enableShowingSubtitleOffset = function(player) { + self.enableShowingSubtitleOffset = function (player) { player = player || self._currentPlayer; player.enableShowingSubtitleOffset(); }; - self.disableShowingSubtitleOffset = function(player) { + self.disableShowingSubtitleOffset = function (player) { player = player || self._currentPlayer; if (player.disableShowingSubtitleOffset) { player.disableShowingSubtitleOffset(); } }; - self.isShowingSubtitleOffsetEnabled = function(player) { + self.isShowingSubtitleOffsetEnabled = function (player) { player = player || self._currentPlayer; return player.isShowingSubtitleOffsetEnabled(); }; - self.isSubtitleStreamExternal = function(index, player) { - var stream = getSubtitleStream(player, index); + self.isSubtitleStreamExternal = function (index, player) { + const stream = getSubtitleStream(player, index); return stream ? getDeliveryMethod(stream) === 'External' : false; }; @@ -1553,15 +1555,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } }; - self.getPlayerSubtitleOffset = function(player) { + self.getPlayerSubtitleOffset = function (player) { player = player || self._currentPlayer; if (player.getSubtitleOffset) { return player.getSubtitleOffset(); } }; - self.canHandleOffsetOnCurrentSubtitle = function(player) { - var index = self.getSubtitleStreamIndex(player); + self.canHandleOffsetOnCurrentSubtitle = function (player) { + const index = self.getSubtitleStreamIndex(player); return index !== -1 && self.isSubtitleStreamExternal(index, player); }; @@ -1590,7 +1592,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } } - var ticks = getCurrentTicks(player) + offsetTicks; + const ticks = getCurrentTicks(player) + offsetTicks; return this.seek(ticks, player); }; @@ -1600,9 +1602,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla throw new Error('player cannot be null'); } - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); - var currentSrc = (playerData.streamInfo.url || '').toLowerCase(); + const currentSrc = (playerData.streamInfo.url || '').toLowerCase(); if (currentSrc.indexOf('.m3u8') !== -1) { return true; @@ -1612,7 +1614,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.seekable(); } - var isPlayMethodTranscode = self.playMethod(player) === 'Transcode'; + const isPlayMethodTranscode = self.playMethod(player) === 'Transcode'; if (isPlayMethodTranscode) { return false; @@ -1629,37 +1631,35 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla params = params || {}; - var liveStreamId = getPlayerData(player).streamInfo.liveStreamId; - var lastMediaInfoQuery = getPlayerData(player).streamInfo.lastMediaInfoQuery; + const liveStreamId = getPlayerData(player).streamInfo.liveStreamId; + const lastMediaInfoQuery = getPlayerData(player).streamInfo.lastMediaInfoQuery; - var playSessionId = self.playSessionId(player); + const playSessionId = self.playSessionId(player); - var currentItem = self.currentItem(player); + const currentItem = self.currentItem(player); player.getDeviceProfile(currentItem, { - isRetry: params.EnableDirectPlay === false - }).then(function (deviceProfile) { - var audioStreamIndex = params.AudioStreamIndex == null ? getPlayerData(player).audioStreamIndex : params.AudioStreamIndex; - var subtitleStreamIndex = params.SubtitleStreamIndex == null ? getPlayerData(player).subtitleStreamIndex : params.SubtitleStreamIndex; + const audioStreamIndex = params.AudioStreamIndex == null ? getPlayerData(player).audioStreamIndex : params.AudioStreamIndex; + const subtitleStreamIndex = params.SubtitleStreamIndex == null ? getPlayerData(player).subtitleStreamIndex : params.SubtitleStreamIndex; - var currentMediaSource = self.currentMediaSource(player); - var apiClient = connectionManager.getApiClient(currentItem.ServerId); + let currentMediaSource = self.currentMediaSource(player); + const apiClient = connectionManager.getApiClient(currentItem.ServerId); if (ticks) { ticks = parseInt(ticks); } - var maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player); + const maxBitrate = params.MaxStreamingBitrate || self.getMaxStreamingBitrate(player); - var currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); + const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); getPlaybackInfo(player, apiClient, currentItem, deviceProfile, maxBitrate, ticks, true, currentMediaSource.Id, audioStreamIndex, subtitleStreamIndex, liveStreamId, params.EnableDirectPlay, params.EnableDirectStream, params.AllowVideoStreamCopy, params.AllowAudioStreamCopy).then(function (result) { if (validatePlaybackInfoResult(self, result)) { currentMediaSource = result.MediaSources[0]; - var streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks); + const streamInfo = createStreamInfo(apiClient, currentItem.MediaType, currentItem, currentMediaSource, ticks); streamInfo.fullscreen = currentPlayOptions.fullscreen; streamInfo.lastMediaInfoQuery = lastMediaInfoQuery; @@ -1679,14 +1679,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function changeStreamToUrl(apiClient, player, playSessionId, streamInfo, newPositionTicks) { - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); playerData.isChangingStream = true; if (playerData.streamInfo && playSessionId) { apiClient.stopActiveEncodings(playSessionId).then(function () { // Stop the first transcoding afterwards because the player may still send requests to the original url - var afterSetSrc = function () { + const afterSetSrc = function () { apiClient.stopActiveEncodings(playSessionId); }; setSrcIntoPlayer(apiClient, player, streamInfo).then(afterSetSrc, afterSetSrc); @@ -1698,7 +1698,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla function setSrcIntoPlayer(apiClient, player, streamInfo) { return player.play(streamInfo).then(function () { - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); playerData.isChangingStream = false; playerData.streamInfo = streamInfo; @@ -1707,7 +1707,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla sendProgressUpdate(player, 'timeupdate'); }, function (e) { - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); playerData.isChangingStream = false; onPlaybackError.call(player, e, { @@ -1725,12 +1725,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }); } - var firstItem = items[0]; - var promise; + const firstItem = items[0]; + let promise; - var serverId = firstItem.ServerId; + const serverId = firstItem.ServerId; - var queryOptions = options.queryOptions || {}; + const queryOptions = options.queryOptions || {}; if (firstItem.Type === 'Program') { promise = getItemsForPlayback(serverId, { @@ -1758,9 +1758,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Photo,Video' }).then(function (result) { - var items = result.Items; + const items = result.Items; - var index = items.map(function (i) { + let index = items.map(function (i) { return i.Id; }).indexOf(firstItem.Id); @@ -1781,7 +1781,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Photo,Video', Limit: 1000 - }); } else if (firstItem.Type === 'MusicGenre') { promise = getItemsForPlayback(serverId, { @@ -1793,18 +1792,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }); } else if (firstItem.IsFolder) { promise = getItemsForPlayback(serverId, mergePlaybackQueries({ - ParentId: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, // These are pre-sorted SortBy: options.shuffle ? 'Random' : (['BoxSet'].indexOf(firstItem.Type) === -1 ? 'SortName' : null), MediaTypes: 'Audio,Video' - }, queryOptions)); } else if (firstItem.Type === 'Episode' && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) { promise = new Promise(function (resolve, reject) { - var apiClient = connectionManager.getApiClient(firstItem.ServerId); + const apiClient = connectionManager.getApiClient(firstItem.ServerId); apiClient.getCurrentUser().then(function (user) { if (!user.Configuration.EnableNextEpisodeAutoPlay || !firstItem.SeriesId) { @@ -1817,9 +1814,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla IsMissing: false, UserId: apiClient.getCurrentUserId(), Fields: 'Chapters' - }).then(function (episodesResult) { - var foundItem = false; + let foundItem = false; episodesResult.Items = episodesResult.Items.filter(function (e) { if (foundItem) { return true; @@ -1874,9 +1870,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return getItemsForPlayback(options.serverId, { - Ids: options.ids.join(',') - }).then(function (result) { return translateItemsForPlayback(result.Items, options).then(function (items) { return playWithIntros(items, options); @@ -1892,7 +1886,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (!player.name) { throw new Error('player name cannot be null'); } - var state = playerStates[player.name]; + let state = playerStates[player.name]; if (!state) { playerStates[player.name] = {}; @@ -1916,7 +1910,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla item = item || self.currentItem(player); mediaSource = mediaSource || self.currentMediaSource(player); - var state = { + const state = { PlayState: {} }; @@ -1974,13 +1968,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla throw new Error('player cannot be null'); } - var mediaSource = self.currentMediaSource(player); + const mediaSource = self.currentMediaSource(player); if (mediaSource && mediaSource.RunTimeTicks) { return mediaSource.RunTimeTicks; } - var playerDuration = player.duration(); + let playerDuration = player.duration(); if (playerDuration) { playerDuration *= 10000; @@ -1994,9 +1988,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla throw new Error('player cannot be null'); } - var playerTime = Math.floor(10000 * (player || self._currentPlayer).currentTime()); + let playerTime = Math.floor(10000 * (player || self._currentPlayer).currentTime()); - var streamInfo = getPlayerData(player).streamInfo; + const streamInfo = getPlayerData(player).streamInfo; if (streamInfo) { playerTime += getPlayerData(player).streamInfo.transcodingOffsetTicks || 0; } @@ -2008,8 +2002,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.getCurrentTicks = getCurrentTicks; function playOther(items, options, user) { - var playStartIndex = options.startIndex || 0; - var player = getPlayer(items[playStartIndex], options); + const playStartIndex = options.startIndex || 0; + const player = getPlayer(items[playStartIndex], options); loading.hide(); @@ -2019,8 +2013,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function playWithIntros(items, options, user) { - var playStartIndex = options.startIndex || 0; - var firstItem = items[playStartIndex]; + let playStartIndex = options.startIndex || 0; + let firstItem = items[playStartIndex]; // If index was bad, reset it if (!firstItem) { @@ -2038,11 +2032,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return playOther(items, options, user); } - var apiClient = connectionManager.getApiClient(firstItem.ServerId); + const apiClient = connectionManager.getApiClient(firstItem.ServerId); return getIntros(firstItem, apiClient, options).then(function (introsResult) { - var introItems = introsResult.Items; - var introPlayOptions; + const introItems = introsResult.Items; + let introPlayOptions; firstItem.playOptions = truncatePlayOptions(options); @@ -2098,9 +2092,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } // TODO: This should be the media type requested, not the original media type - var mediaType = item.MediaType; + const mediaType = item.MediaType; - var onBitrateDetectionFailure = function () { + const onBitrateDetectionFailure = function () { return playAfterBitrateDetect(getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType), item, playOptions, onPlaybackStartedFn); }; @@ -2108,7 +2102,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return onBitrateDetectionFailure(); } - var apiClient = connectionManager.getApiClient(item.ServerId); + const apiClient = connectionManager.getApiClient(item.ServerId); apiClient.getEndpointInfo().then(function (endpointInfo) { if ((mediaType === 'Video' || mediaType === 'Audio') && appSettings.enableAutomaticBitrateDetection(endpointInfo.IsInNetwork, mediaType)) { return apiClient.detectBitrate().then(function (bitrate) { @@ -2124,7 +2118,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onInterceptorRejection() { - var player = self._currentPlayer; + const player = self._currentPlayer; if (player) { destroyPlayer(player); @@ -2142,7 +2136,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla function runInterceptors(item, playOptions) { return new Promise(function (resolve, reject) { - var interceptors = pluginManager.ofType('preplayintercept'); + const interceptors = pluginManager.ofType('preplayintercept'); interceptors.sort(function (a, b) { return (a.order || 0) - (b.order || 0); @@ -2155,7 +2149,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla loading.hide(); - var options = Object.assign({}, playOptions); + const options = Object.assign({}, playOptions); options.mediaType = item.MediaType; options.item = item; @@ -2170,7 +2164,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var interceptor = interceptors[index]; + const interceptor = interceptors[index]; interceptor.intercept(options).then(function () { runNextPrePlay(interceptors, index + 1, options, resolve, reject); @@ -2193,12 +2187,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function playAfterBitrateDetect(maxBitrate, item, playOptions, onPlaybackStartedFn) { - var startPosition = playOptions.startPositionTicks; + const startPosition = playOptions.startPositionTicks; - var player = getPlayer(item, playOptions); - var activePlayer = self._currentPlayer; + const player = getPlayer(item, playOptions); + const activePlayer = self._currentPlayer; - var promise; + let promise; if (activePlayer) { // TODO: if changing players within the same playlist, this will cause nextItem to be null @@ -2210,7 +2204,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (!isServerItem(item) || item.MediaType === 'Book') { return promise.then(function () { - var streamInfo = createStreamInfoFromUrlItem(item); + const streamInfo = createStreamInfoFromUrlItem(item); streamInfo.fullscreen = playOptions.fullscreen; getPlayerData(player).isChangingStream = false; return player.play(streamInfo).then(function () { @@ -2225,13 +2219,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return Promise.all([promise, player.getDeviceProfile(item)]).then(function (responses) { - var deviceProfile = responses[1]; + const deviceProfile = responses[1]; - var apiClient = connectionManager.getApiClient(item.ServerId); + const apiClient = connectionManager.getApiClient(item.ServerId); - var mediaSourceId = playOptions.mediaSourceId; - var audioStreamIndex = playOptions.audioStreamIndex; - var subtitleStreamIndex = playOptions.subtitleStreamIndex; + const mediaSourceId = playOptions.mediaSourceId; + const audioStreamIndex = playOptions.audioStreamIndex; + const subtitleStreamIndex = playOptions.subtitleStreamIndex; if (player && !enableLocalPlaylistManagement(player)) { return sendPlaybackListToPlayer(player, playOptions.items, deviceProfile, maxBitrate, apiClient, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex, playOptions.startIndex); @@ -2241,7 +2235,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla playOptions.items = null; return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, mediaSourceId, audioStreamIndex, subtitleStreamIndex).then(function (mediaSource) { - var streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition); + const streamInfo = createStreamInfo(apiClient, item.MediaType, item, mediaSource, startPosition); streamInfo.fullscreen = playOptions.fullscreen; @@ -2269,14 +2263,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.getPlaybackInfo = function (item, options) { options = options || {}; - var startPosition = options.startPositionTicks || 0; - var mediaType = options.mediaType || item.MediaType; - var player = getPlayer(item, options); - var apiClient = connectionManager.getApiClient(item.ServerId); + const startPosition = options.startPositionTicks || 0; + const mediaType = options.mediaType || item.MediaType; + const player = getPlayer(item, options); + const apiClient = connectionManager.getApiClient(item.ServerId); // Call this just to ensure the value is recorded, it is needed with getSavedMaxStreamingBitrate return apiClient.getEndpointInfo().then(function () { - var maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); + const maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); return player.getDeviceProfile(item).then(function (deviceProfile) { return getPlaybackMediaSource(player, apiClient, deviceProfile, maxBitrate, item, startPosition, options.mediaSourceId, options.audioStreamIndex, options.subtitleStreamIndex).then(function (mediaSource) { @@ -2288,15 +2282,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.getPlaybackMediaSources = function (item, options) { options = options || {}; - var startPosition = options.startPositionTicks || 0; - var mediaType = options.mediaType || item.MediaType; + const startPosition = options.startPositionTicks || 0; + const mediaType = options.mediaType || item.MediaType; // TODO: Remove the true forceLocalPlayer hack - var player = getPlayer(item, options, true); - var apiClient = connectionManager.getApiClient(item.ServerId); + const player = getPlayer(item, options, true); + const apiClient = connectionManager.getApiClient(item.ServerId); // Call this just to ensure the value is recorded, it is needed with getSavedMaxStreamingBitrate return apiClient.getEndpointInfo().then(function () { - var maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); + const maxBitrate = getSavedMaxStreamingBitrate(connectionManager.getApiClient(item.ServerId), mediaType); return player.getDeviceProfile(item).then(function (deviceProfile) { return getPlaybackInfo(player, apiClient, item, deviceProfile, maxBitrate, startPosition, false, null, null, null, null).then(function (playbackInfoResult) { @@ -2307,16 +2301,16 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; function createStreamInfo(apiClient, type, item, mediaSource, startPosition) { - var mediaUrl; - var contentType; - var transcodingOffsetTicks = 0; - var playerStartPositionTicks = startPosition; - var liveStreamId = mediaSource.LiveStreamId; + let mediaUrl; + let contentType; + let transcodingOffsetTicks = 0; + const playerStartPositionTicks = startPosition; + const liveStreamId = mediaSource.LiveStreamId; - var playMethod = 'Transcode'; + let playMethod = 'Transcode'; - var mediaSourceContainer = (mediaSource.Container || '').toLowerCase(); - var directOptions; + const mediaSourceContainer = (mediaSource.Container || '').toLowerCase(); + let directOptions; if (type === 'Video' || type === 'Audio') { contentType = getMimeType(type.toLowerCase(), mediaSourceContainer); @@ -2345,7 +2339,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla directOptions.LiveStreamId = mediaSource.LiveStreamId; } - var prefix = type === 'Video' ? 'Videos' : 'Audio'; + const prefix = type === 'Video' ? 'Videos' : 'Audio'; mediaUrl = apiClient.getUrl(prefix + '/' + item.Id + '/stream.' + mediaSourceContainer, directOptions); playMethod = 'DirectStream'; @@ -2374,7 +2368,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla playMethod = 'DirectPlay'; } - var resultInfo = { + const resultInfo = { url: mediaUrl, mimeType: contentType, transcodingOffsetTicks: transcodingOffsetTicks, @@ -2391,7 +2385,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla title: item.Name }; - var backdropUrl = backdropImageUrl(apiClient, item, {}); + const backdropUrl = backdropImageUrl(apiClient, item, {}); if (backdropUrl) { resultInfo.backdropUrl = backdropUrl; } @@ -2400,19 +2394,19 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function getTextTracks(apiClient, item, mediaSource) { - var subtitleStreams = mediaSource.MediaStreams.filter(function (s) { + const subtitleStreams = mediaSource.MediaStreams.filter(function (s) { return s.Type === 'Subtitle'; }); - var textStreams = subtitleStreams.filter(function (s) { + const textStreams = subtitleStreams.filter(function (s) { return s.DeliveryMethod === 'External'; }); - var tracks = []; + const tracks = []; - for (var i = 0, length = textStreams.length; i < length; i++) { - var textStream = textStreams[i]; - var textStreamUrl; + for (let i = 0, length = textStreams.length; i < length; i++) { + const textStream = textStreams[i]; + let textStreamUrl; if (itemHelper.isLocalItem(item)) { textStreamUrl = textStream.Path; @@ -2459,7 +2453,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function getPlayer(item, playOptions, forceLocalPlayers) { - var serverItem = isServerItem(item); + const serverItem = isServerItem(item); return getAutomaticPlayers(self, forceLocalPlayers).filter(function (p) { if (p.canPlayMediaType(item.MediaType)) { if (serverItem) { @@ -2482,11 +2476,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.setCurrentPlaylistItem(playlistItemId); } - var newItem; - var newItemIndex; - var playlist = self._playQueueManager.getPlaylist(); + let newItem; + let newItemIndex; + const playlist = self._playQueueManager.getPlaylist(); - for (var i = 0, length = playlist.length; i < length; i++) { + for (let i = 0, length = playlist.length; i < length; i++) { if (playlist[i].PlaylistItemId === playlistItemId) { newItem = playlist[i]; newItemIndex = i; @@ -2495,7 +2489,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } if (newItem) { - var newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); + const newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); playInternal(newItem, newItemPlayOptions, function () { setPlaylistState(newItem.PlaylistItemId, newItemIndex); @@ -2513,18 +2507,19 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.removeFromPlaylist(playlistItemIds); } - var removeResult = self._playQueueManager.removeFromPlaylist(playlistItemIds); + const removeResult = self._playQueueManager.removeFromPlaylist(playlistItemIds); if (removeResult.result === 'empty') { return self.stop(player); } - var isCurrentIndex = removeResult.isCurrentIndex; + const isCurrentIndex = removeResult.isCurrentIndex; events.trigger(player, 'playlistitemremove', [ { playlistItemIds: playlistItemIds - }]); + } + ]); if (isCurrentIndex) { return self.setCurrentPlaylistItem(self._playQueueManager.getPlaylist()[0].PlaylistItemId, player); @@ -2539,7 +2534,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.movePlaylistItem(playlistItemId, newIndex); } - var moveResult = self._playQueueManager.movePlaylistItem(playlistItemId, newIndex); + const moveResult = self._playQueueManager.movePlaylistItem(playlistItemId, newIndex); if (moveResult.result === 'noop') { return; @@ -2549,7 +2544,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla { playlistItemId: moveResult.playlistItemId, newIndex: moveResult.newIndex - }]); + } + ]); }; self.getCurrentPlaylistIndex = function (player) { @@ -2586,12 +2582,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.nextTrack(); } - var newItemInfo = self._playQueueManager.getNextItemInfo(); + const newItemInfo = self._playQueueManager.getNextItemInfo(); if (newItemInfo) { console.debug('playing next track'); - var newItemPlayOptions = newItemInfo.item.playOptions || getDefaultPlayOptions(); + const newItemPlayOptions = newItemInfo.item.playOptions || getDefaultPlayOptions(); playInternal(newItemInfo.item, newItemPlayOptions, function () { setPlaylistState(newItemInfo.item.PlaylistItemId, newItemInfo.index); @@ -2605,13 +2601,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.previousTrack(); } - var newIndex = self.getCurrentPlaylistIndex(player) - 1; + const newIndex = self.getCurrentPlaylistIndex(player) - 1; if (newIndex >= 0) { - var playlist = self._playQueueManager.getPlaylist(); - var newItem = playlist[newIndex]; + const playlist = self._playQueueManager.getPlaylist(); + const newItem = playlist[newIndex]; if (newItem) { - var newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); + const newItemPlayOptions = newItem.playOptions || getDefaultPlayOptions(); newItemPlayOptions.startPositionTicks = 0; playInternal(newItem, newItemPlayOptions, function () { @@ -2647,9 +2643,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return getItemsForPlayback(options.serverId, { - Ids: options.ids.join(',') - }).then(function (result) { return translateItemsForPlayback(result.Items, options).then(function (items) { // TODO: Handle options.startIndex for photos @@ -2677,10 +2671,10 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return; } - var queueDirectToPlayer = player && !enableLocalPlaylistManagement(player); + const queueDirectToPlayer = player && !enableLocalPlaylistManagement(player); if (queueDirectToPlayer) { - var apiClient = connectionManager.getApiClient(items[0].ServerId); + const apiClient = connectionManager.getApiClient(items[0].ServerId); player.getDeviceProfile(items[0]).then(function (profile) { setStreamUrls(items, profile, self.getMaxStreamingBitrate(player), apiClient, 0).then(function () { @@ -2704,7 +2698,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlayerProgressInterval() { - var player = this; + const player = this; sendProgressUpdate(player, 'timeupdate'); } @@ -2728,7 +2722,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla setCurrentPlayerInternal(player); - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); playerData.streamInfo = streamInfo; @@ -2743,10 +2737,10 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } self._playNextAfterEnded = true; - var isFirstItem = playOptions.isFirstItem; - var fullscreen = playOptions.fullscreen; + const isFirstItem = playOptions.isFirstItem; + const fullscreen = playOptions.fullscreen; - var state = self.getPlayerState(player, streamInfo.item, streamInfo.mediaSource); + const state = self.getPlayerState(player, streamInfo.item, streamInfo.mediaSource); reportPlayback(self, state, player, true, state.NowPlayingItem.ServerId, 'reportPlaybackStart'); @@ -2762,22 +2756,22 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlaybackStartedFromSelfManagingPlayer(e, item, mediaSource) { - var player = this; + const player = this; setCurrentPlayerInternal(player); - var playOptions = item.playOptions || getDefaultPlayOptions(); - var isFirstItem = playOptions.isFirstItem; - var fullscreen = playOptions.fullscreen; + const playOptions = item.playOptions || getDefaultPlayOptions(); + const isFirstItem = playOptions.isFirstItem; + const fullscreen = playOptions.fullscreen; playOptions.isFirstItem = false; - var playerData = getPlayerData(player); + const playerData = getPlayerData(player); playerData.streamInfo = {}; - var streamInfo = playerData.streamInfo; + const streamInfo = playerData.streamInfo; streamInfo.playbackStartTimeTicks = new Date().getTime() * 10000; - var state = self.getPlayerState(player, item, mediaSource); + const state = self.getPlayerState(player, item, mediaSource); reportPlayback(self, state, player, true, state.NowPlayingItem.ServerId, 'reportPlaybackStart'); @@ -2793,15 +2787,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlaybackStoppedFromSelfManagingPlayer(e, playerStopInfo) { - var player = this; + const player = this; stopPlaybackProgressTimer(player); - var state = self.getPlayerState(player, playerStopInfo.item, playerStopInfo.mediaSource); + const state = self.getPlayerState(player, playerStopInfo.item, playerStopInfo.mediaSource); - var nextItem = playerStopInfo.nextItem; - var nextMediaType = playerStopInfo.nextMediaType; + const nextItem = playerStopInfo.nextItem; + const nextMediaType = playerStopInfo.nextMediaType; - var playbackStopInfo = { + const playbackStopInfo = { player: player, state: state, nextItem: (nextItem ? nextItem.item : null), @@ -2810,7 +2804,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla state.NextMediaType = nextMediaType; - var streamInfo = getPlayerData(player).streamInfo; + const streamInfo = getPlayerData(player).streamInfo; // only used internally as a safeguard to avoid reporting other events to the server after playback stopped streamInfo.ended = true; @@ -2826,8 +2820,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla events.trigger(player, 'playbackstop', [state]); events.trigger(self, 'playbackstop', [playbackStopInfo]); - var nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); - var newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; + const nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); + const newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; if (newPlayer !== player) { destroyPlayer(player); @@ -2837,7 +2831,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla function enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy) { // mediadecodeerror, medianotsupported, network, servererror - if (streamInfo.mediaSource.SupportsTranscoding && (!currentlyPreventsVideoStreamCopy || !currentlyPreventsAudioStreamCopy)) { return true; } @@ -2846,46 +2839,44 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlaybackError(e, error) { - var player = this; + const player = this; error = error || {}; // network // mediadecodeerror // medianotsupported - var errorType = error.type; + const errorType = error.type; console.debug('playbackmanager playback error type: ' + (errorType || '')); - var streamInfo = error.streamInfo || getPlayerData(player).streamInfo; + const streamInfo = error.streamInfo || getPlayerData(player).streamInfo; if (streamInfo) { - var currentlyPreventsVideoStreamCopy = streamInfo.url.toLowerCase().indexOf('allowvideostreamcopy=false') !== -1; - var currentlyPreventsAudioStreamCopy = streamInfo.url.toLowerCase().indexOf('allowaudiostreamcopy=false') !== -1; + const currentlyPreventsVideoStreamCopy = streamInfo.url.toLowerCase().indexOf('allowvideostreamcopy=false') !== -1; + const currentlyPreventsAudioStreamCopy = streamInfo.url.toLowerCase().indexOf('allowaudiostreamcopy=false') !== -1; // Auto switch to transcoding if (enablePlaybackRetryWithTranscoding(streamInfo, errorType, currentlyPreventsVideoStreamCopy, currentlyPreventsAudioStreamCopy)) { - var startTime = getCurrentTicks(player) || streamInfo.playerStartPositionTicks; + const startTime = getCurrentTicks(player) || streamInfo.playerStartPositionTicks; changeStream(player, startTime, { - // force transcoding EnableDirectPlay: false, EnableDirectStream: false, AllowVideoStreamCopy: false, AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null - }); return; } } - var displayErrorCode = 'NoCompatibleStream'; + const displayErrorCode = 'NoCompatibleStream'; onPlaybackStopped.call(player, e, displayErrorCode); } function onPlaybackStopped(e, displayErrorCode) { - var player = this; + const player = this; if (getPlayerData(player).isChangingStream) { return; @@ -2894,15 +2885,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla stopPlaybackProgressTimer(player); // User clicked stop or content ended - var state = self.getPlayerState(player); - var data = getPlayerData(player); - var streamInfo = data.streamInfo; + const state = self.getPlayerState(player); + const data = getPlayerData(player); + const streamInfo = data.streamInfo; - var nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null; + const nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null; - var nextMediaType = (nextItem ? nextItem.item.MediaType : null); + const nextMediaType = (nextItem ? nextItem.item.MediaType : null); - var playbackStopInfo = { + const playbackStopInfo = { player: player, state: state, nextItem: (nextItem ? nextItem.item : null), @@ -2931,8 +2922,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla events.trigger(player, 'playbackstop', [state]); events.trigger(self, 'playbackstop', [playbackStopInfo]); - var nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); - var newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; + const nextItemPlayOptions = nextItem ? (nextItem.item.playOptions || getDefaultPlayOptions()) : getDefaultPlayOptions(); + const newPlayer = nextItem ? getPlayer(nextItem.item, nextItemPlayOptions) : null; if (newPlayer !== player) { destroyPlayer(player); @@ -2950,12 +2941,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlaybackChanging(activePlayer, newPlayer, newItem) { - var state = self.getPlayerState(activePlayer); + const state = self.getPlayerState(activePlayer); - var serverId = self.currentItem(activePlayer).ServerId; + const serverId = self.currentItem(activePlayer).ServerId; // User started playing something new while existing content is playing - var promise; + let promise; stopPlaybackProgressTimer(activePlayer); unbindStopped(activePlayer); @@ -2992,47 +2983,47 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function onPlaybackTimeUpdate(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'timeupdate'); } function onPlaybackPause(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'pause'); } function onPlaybackUnpause(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'unpause'); } function onPlaybackVolumeChange(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'volumechange'); } function onRepeatModeChange(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'repeatmodechange'); } function onShuffleQueueModeChange() { - var player = this; + const player = this; sendProgressUpdate(player, 'shufflequeuemodechange'); } function onPlaylistItemMove(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'playlistitemmove', true); } function onPlaylistItemRemove(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'playlistitemremove', true); } function onPlaylistItemAdd(e) { - var player = this; + const player = this; sendProgressUpdate(player, 'playlistitemadd', true); } @@ -3109,12 +3100,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla throw new Error('player cannot be null'); } - var state = self.getPlayerState(player); + const state = self.getPlayerState(player); if (state.NowPlayingItem) { - var serverId = state.NowPlayingItem.ServerId; + const serverId = state.NowPlayingItem.ServerId; - var streamInfo = getPlayerData(player).streamInfo; + const streamInfo = getPlayerData(player).streamInfo; if (streamInfo && streamInfo.started && !streamInfo.ended) { reportPlayback(self, state, player, reportPlaylist, serverId, 'reportPlaybackProgress', progressEventName); @@ -3133,7 +3124,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla streamInfo.lastMediaInfoQuery = new Date().getTime(); - var apiClient = connectionManager.getApiClient(serverId); + const apiClient = connectionManager.getApiClient(serverId); if (!apiClient.isMinServerVersion('3.2.70.7')) { return; @@ -3143,12 +3134,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla mediaSource.MediaStreams = info.MediaStreams; events.trigger(player, 'mediastreamschange'); }, function () { - }); } self.onAppClose = function () { - var player = this._currentPlayer; + const player = this._currentPlayer; // Try to report playback stopped before the app closes if (player && this.isPlaying(player)) { @@ -3163,64 +3153,64 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.playbackStartTime(); } - var streamInfo = getPlayerData(player).streamInfo; + const streamInfo = getPlayerData(player).streamInfo; return streamInfo ? streamInfo.playbackStartTimeTicks : null; }; if (apphost.supports('remotecontrol')) { - require(['serverNotifications'], function (serverNotifications) { + import('serverNotifications').then(({ default: serverNotifications }) => { events.on(serverNotifications, 'ServerShuttingDown', self.setDefaultPlayerActive.bind(self)); events.on(serverNotifications, 'ServerRestarting', self.setDefaultPlayerActive.bind(self)); }); } } - PlaybackManager.prototype.getCurrentPlayer = function () { + getCurrentPlayer() { return this._currentPlayer; - }; + } - PlaybackManager.prototype.currentTime = function (player) { + currentTime(player) { player = player || this._currentPlayer; if (player && !enableLocalPlaylistManagement(player) && !player.isLocalPlayer) { return player.currentTime(); } return this.getCurrentTicks(player); - }; + } - PlaybackManager.prototype.nextItem = function (player) { + nextItem(player) { player = player || this._currentPlayer; if (player && !enableLocalPlaylistManagement(player)) { return player.nextItem(); } - var nextItem = this._playQueueManager.getNextItemInfo(); + const nextItem = this._playQueueManager.getNextItemInfo(); if (!nextItem || !nextItem.item) { return Promise.reject(); } - var apiClient = connectionManager.getApiClient(nextItem.item.ServerId); + const apiClient = connectionManager.getApiClient(nextItem.item.ServerId); return apiClient.getItem(apiClient.getCurrentUserId(), nextItem.item.Id); - }; + } - PlaybackManager.prototype.canQueue = function (item) { + canQueue(item) { if (item.Type === 'MusicAlbum' || item.Type === 'MusicArtist' || item.Type === 'MusicGenre') { return this.canQueueMediaType('Audio'); } return this.canQueueMediaType(item.MediaType); - }; + } - PlaybackManager.prototype.canQueueMediaType = function (mediaType) { + canQueueMediaType(mediaType) { if (this._currentPlayer) { return this._currentPlayer.canPlayMediaType(mediaType); } return false; - }; + } - PlaybackManager.prototype.isMuted = function (player) { + isMuted(player) { player = player || this._currentPlayer; if (player) { @@ -3228,17 +3218,17 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return false; - }; + } - PlaybackManager.prototype.setMute = function (mute, player) { + setMute(mute, player) { player = player || this._currentPlayer; if (player) { player.setMute(mute); } - }; + } - PlaybackManager.prototype.toggleMute = function (mute, player) { + toggleMute(mute, player) { player = player || this._currentPlayer; if (player) { if (player.toggleMute) { @@ -3247,29 +3237,29 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla player.setMute(!player.isMuted()); } } - }; + } - PlaybackManager.prototype.toggleDisplayMirroring = function () { + toggleDisplayMirroring() { this.enableDisplayMirroring(!this.enableDisplayMirroring()); - }; + } - PlaybackManager.prototype.enableDisplayMirroring = function (enabled) { + enableDisplayMirroring(enabled) { if (enabled != null) { - var val = enabled ? '1' : '0'; + const val = enabled ? '1' : '0'; appSettings.set('displaymirror', val); return; } return (appSettings.get('displaymirror') || '') !== '0'; - }; + } - PlaybackManager.prototype.nextChapter = function (player) { + nextChapter(player) { player = player || this._currentPlayer; - var item = this.currentItem(player); + const item = this.currentItem(player); - var ticks = this.getCurrentTicks(player); + const ticks = this.getCurrentTicks(player); - var nextChapter = (item.Chapters || []).filter(function (i) { + const nextChapter = (item.Chapters || []).filter(function (i) { return i.StartPositionTicks > ticks; })[0]; @@ -3278,13 +3268,13 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } else { this.nextTrack(player); } - }; + } - PlaybackManager.prototype.previousChapter = function (player) { + previousChapter(player) { player = player || this._currentPlayer; - var item = this.currentItem(player); + const item = this.currentItem(player); - var ticks = this.getCurrentTicks(player); + let ticks = this.getCurrentTicks(player); // Go back 10 seconds ticks -= 100000000; @@ -3294,7 +3284,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla ticks = Math.max(ticks, 0); } - var previousChapters = (item.Chapters || []).filter(function (i) { + const previousChapters = (item.Chapters || []).filter(function (i) { return i.StartPositionTicks <= ticks; }); @@ -3303,9 +3293,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } else { this.previousTrack(player); } - }; + } - PlaybackManager.prototype.fastForward = function (player) { + fastForward(player) { player = player || this._currentPlayer; if (player.fastForward != null) { @@ -3314,12 +3304,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } // Go back 15 seconds - var offsetTicks = userSettings.skipForwardLength() * 10000; + const offsetTicks = userSettings.skipForwardLength() * 10000; this.seekRelative(offsetTicks, player); - }; + } - PlaybackManager.prototype.rewind = function (player) { + rewind(player) { player = player || this._currentPlayer; if (player.rewind != null) { @@ -3328,38 +3318,38 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } // Go back 15 seconds - var offsetTicks = 0 - (userSettings.skipBackLength() * 10000); + const offsetTicks = 0 - (userSettings.skipBackLength() * 10000); this.seekRelative(offsetTicks, player); - }; + } - PlaybackManager.prototype.seekPercent = function (percent, player) { + seekPercent(percent, player) { player = player || this._currentPlayer; - var ticks = this.duration(player) || 0; + let ticks = this.duration(player) || 0; percent /= 100; ticks *= percent; this.seek(parseInt(ticks), player); - }; + } - PlaybackManager.prototype.seekMs = function (ms, player) { + seekMs(ms, player) { player = player || this._currentPlayer; - var ticks = ms * 10000; + const ticks = ms * 10000; this.seek(ticks, player); - }; + } - PlaybackManager.prototype.playTrailers = function (item) { - var player = this._currentPlayer; + playTrailers(item) { + const player = this._currentPlayer; if (player && player.playTrailers) { return player.playTrailers(item); } - var apiClient = connectionManager.getApiClient(item.ServerId); + const apiClient = connectionManager.getApiClient(item.ServerId); - var instance = this; + const instance = this; if (item.LocalTrailerCount) { return apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function (result) { @@ -3368,7 +3358,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }); }); } else { - var remoteTrailers = item.RemoteTrailers || []; + const remoteTrailers = item.RemoteTrailers || []; if (!remoteTrailers.length) { return Promise.reject(); @@ -3386,15 +3376,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }) }); } - }; + } - PlaybackManager.prototype.getSubtitleUrl = function (textStream, serverId) { - var apiClient = connectionManager.getApiClient(serverId); + getSubtitleUrl(textStream, serverId) { + const apiClient = connectionManager.getApiClient(serverId); return !textStream.IsExternalUrl ? apiClient.getUrl(textStream.DeliveryUrl) : textStream.DeliveryUrl; - }; + } - PlaybackManager.prototype.stop = function (player) { + stop(player) { player = player || this._currentPlayer; if (player) { @@ -3407,9 +3397,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return Promise.resolve(); - }; + } - PlaybackManager.prototype.getBufferedRanges = function (player) { + getBufferedRanges(player) { player = player || this._currentPlayer; if (player) { @@ -3419,9 +3409,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } return []; - }; + } - PlaybackManager.prototype.playPause = function (player) { + playPause(player) { player = player || this._currentPlayer; if (player) { @@ -3435,115 +3425,115 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return this.pause(player); } } - }; + } - PlaybackManager.prototype.paused = function (player) { + paused(player) { player = player || this._currentPlayer; if (player) { return player.paused(); } - }; + } - PlaybackManager.prototype.pause = function (player) { + pause(player) { player = player || this._currentPlayer; if (player) { player.pause(); } - }; + } - PlaybackManager.prototype.unpause = function (player) { + unpause(player) { player = player || this._currentPlayer; if (player) { player.unpause(); } - }; + } - PlaybackManager.prototype.setPlaybackRate = function (value, player = this._currentPlayer) { + setPlaybackRate(value, player = this._currentPlayer) { if (player && player.setPlaybackRate) { player.setPlaybackRate(value); } - }; + } - PlaybackManager.prototype.getPlaybackRate = function (player = this._currentPlayer) { + getPlaybackRate(player = this._currentPlayer) { if (player && player.getPlaybackRate) { return player.getPlaybackRate(); } return null; - }; + } - PlaybackManager.prototype.instantMix = function (item, player) { + instantMix(item, player) { player = player || this._currentPlayer; if (player && player.instantMix) { return player.instantMix(item); } - var apiClient = connectionManager.getApiClient(item.ServerId); + const apiClient = connectionManager.getApiClient(item.ServerId); - var options = {}; + const options = {}; options.UserId = apiClient.getCurrentUserId(); options.Limit = 200; - var instance = this; + const instance = this; apiClient.getInstantMixFromItem(item.Id, options).then(function (result) { instance.play({ items: result.Items }); }); - }; + } - PlaybackManager.prototype.shuffle = function (shuffleItem, player) { + shuffle(shuffleItem, player) { player = player || this._currentPlayer; if (player && player.shuffle) { return player.shuffle(shuffleItem); } return this.play({ items: [shuffleItem], shuffle: true }); - }; + } - PlaybackManager.prototype.audioTracks = function (player) { + audioTracks(player) { player = player || this._currentPlayer; if (player.audioTracks) { - var result = player.audioTracks(); + const result = player.audioTracks(); if (result) { return result; } } - var mediaSource = this.currentMediaSource(player); + const mediaSource = this.currentMediaSource(player); - var mediaStreams = (mediaSource || {}).MediaStreams || []; + const mediaStreams = (mediaSource || {}).MediaStreams || []; return mediaStreams.filter(function (s) { return s.Type === 'Audio'; }); - }; + } - PlaybackManager.prototype.subtitleTracks = function (player) { + subtitleTracks(player) { player = player || this._currentPlayer; if (player.subtitleTracks) { - var result = player.subtitleTracks(); + const result = player.subtitleTracks(); if (result) { return result; } } - var mediaSource = this.currentMediaSource(player); + const mediaSource = this.currentMediaSource(player); - var mediaStreams = (mediaSource || {}).MediaStreams || []; + const mediaStreams = (mediaSource || {}).MediaStreams || []; return mediaStreams.filter(function (s) { return s.Type === 'Subtitle'; }); - }; + } - PlaybackManager.prototype.getSupportedCommands = function (player) { + getSupportedCommands(player) { player = player || this._currentPlayer || { isLocalPlayer: true }; if (player.isLocalPlayer) { - var list = [ + const list = [ 'GoHome', 'GoToSettings', 'VolumeUp', @@ -3589,45 +3579,45 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return list; } - var info = this.getPlayerInfo(); + const info = this.getPlayerInfo(); return info ? info.supportedCommands : []; - }; + } - PlaybackManager.prototype.setRepeatMode = function (value, player = this._currentPlayer) { + setRepeatMode(value, player = this._currentPlayer) { if (player && !enableLocalPlaylistManagement(player)) { return player.setRepeatMode(value); } this._playQueueManager.setRepeatMode(value); events.trigger(player, 'repeatmodechange'); - }; + } - PlaybackManager.prototype.getRepeatMode = function (player = this._currentPlayer) { + getRepeatMode(player = this._currentPlayer) { if (player && !enableLocalPlaylistManagement(player)) { return player.getRepeatMode(); } return this._playQueueManager.getRepeatMode(); - }; + } - PlaybackManager.prototype.setQueueShuffleMode = function (value, player = this._currentPlayer) { + setQueueShuffleMode(value, player = this._currentPlayer) { if (player && !enableLocalPlaylistManagement(player)) { return player.setQueueShuffleMode(value); } this._playQueueManager.setShuffleMode(value); events.trigger(player, 'shufflequeuemodechange'); - }; + } - PlaybackManager.prototype.getQueueShuffleMode = function (player = this._currentPlayer) { + getQueueShuffleMode(player = this._currentPlayer) { if (player && !enableLocalPlaylistManagement(player)) { return player.getQueueShuffleMode(); } return this._playQueueManager.getShuffleMode(); - }; + } - PlaybackManager.prototype.toggleQueueShuffleMode = function (player = this._currentPlayer) { + toggleQueueShuffleMode(player = this._currentPlayer) { let currentvalue; if (player && !enableLocalPlaylistManagement(player)) { currentvalue = player.getQueueShuffleMode(); @@ -3645,23 +3635,23 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla this._playQueueManager.toggleShuffleMode(); } events.trigger(player, 'shufflequeuemodechange'); - }; + } - PlaybackManager.prototype.clearQueue = function (clearCurrentItem = false, player = this._currentPlayer) { + clearQueue(clearCurrentItem = false, player = this._currentPlayer) { if (player && !enableLocalPlaylistManagement(player)) { return player.clearQueue(clearCurrentItem); } this._playQueueManager.clearPlaylist(clearCurrentItem); events.trigger(player, 'playlistitemremove'); - }; + } - PlaybackManager.prototype.trySetActiveDeviceName = function (name) { + trySetActiveDeviceName(name) { name = normalizeName(name); - var instance = this; + const instance = this; instance.getTargets().then(function (result) { - var target = result.filter(function (p) { + const target = result.filter(function (p) { return normalizeName(p.name) === name; })[0]; @@ -3669,50 +3659,50 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla instance.trySetActivePlayer(target.playerName, target); } }); - }; + } - PlaybackManager.prototype.displayContent = function (options, player) { + displayContent(options, player) { player = player || this._currentPlayer; if (player && player.displayContent) { player.displayContent(options); } - }; + } - PlaybackManager.prototype.beginPlayerUpdates = function (player) { + beginPlayerUpdates(player) { if (player.beginPlayerUpdates) { player.beginPlayerUpdates(); } - }; + } - PlaybackManager.prototype.endPlayerUpdates = function (player) { + endPlayerUpdates(player) { if (player.endPlayerUpdates) { player.endPlayerUpdates(); } - }; + } - PlaybackManager.prototype.setDefaultPlayerActive = function () { + setDefaultPlayerActive() { this.setActivePlayer('localplayer'); - }; + } - PlaybackManager.prototype.removeActivePlayer = function (name) { - var playerInfo = this.getPlayerInfo(); + removeActivePlayer(name) { + const playerInfo = this.getPlayerInfo(); if (playerInfo) { if (playerInfo.name === name) { this.setDefaultPlayerActive(); } } - }; + } - PlaybackManager.prototype.removeActiveTarget = function (id) { - var playerInfo = this.getPlayerInfo(); + removeActiveTarget(id) { + const playerInfo = this.getPlayerInfo(); if (playerInfo) { if (playerInfo.id === id) { this.setDefaultPlayerActive(); } } - }; + } - PlaybackManager.prototype.sendCommand = function (cmd, player) { + sendCommand(cmd, player) { console.debug('MediaController received command: ' + cmd.Name); switch (cmd.Name) { case 'SetRepeatMode': @@ -3763,7 +3753,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } break; } - }; + } +} - return new PlaybackManager(); -}); +export default new PlaybackManager();