(function (window) { function getDeviceProfile(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) { var bitrateSetting = AppSettings.maxStreamingBitrate(); var profile = {}; profile.MaxStreamingBitrate = bitrateSetting; profile.MaxStaticBitrate = 40000000; profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000); profile.DirectPlayProfiles = []; profile.DirectPlayProfiles.push({ Container: 'mkv,mov,mp4,m4v,wmv', Type: 'Video' }); profile.DirectPlayProfiles.push({ Container: 'aac,mp3,flac,wma', Type: 'Audio' }); profile.TranscodingProfiles = []; profile.TranscodingProfiles.push({ Container: 'ts', Type: 'Video', AudioCodec: 'aac', VideoCodec: 'h264', Context: 'Streaming', Protocol: 'hls' }); profile.TranscodingProfiles.push({ Container: 'aac', Type: 'Audio', AudioCodec: 'aac', Context: 'Streaming', Protocol: 'hls' }); profile.ContainerProfiles = []; var audioConditions = []; var maxAudioChannels = '6'; audioConditions.push({ Condition: 'LessThanEqual', Property: 'AudioChannels', Value: maxAudioChannels }); profile.CodecProfiles = []; profile.CodecProfiles.push({ Type: 'Audio', Conditions: audioConditions }); profile.CodecProfiles.push({ Type: 'VideoAudio', Codec: 'mp3', Conditions: [{ Condition: 'LessThanEqual', Property: 'AudioChannels', Value: maxAudioChannels }] }); profile.CodecProfiles.push({ Type: 'VideoAudio', Codec: 'aac', Conditions: [ { Condition: 'LessThanEqual', Property: 'AudioChannels', Value: maxAudioChannels } ] }); profile.CodecProfiles.push({ Type: 'Video', Codec: 'h264', Conditions: [ { Condition: 'EqualsAny', Property: 'VideoProfile', Value: 'high|main|baseline|constrained baseline' }, { Condition: 'LessThanEqual', Property: 'VideoLevel', Value: '50' }] }); // Subtitle profiles profile.SubtitleProfiles = []; profile.SubtitleProfiles.push({ Format: 'srt', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'subrip', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'ass', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'ssa', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'pgs', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'pgssub', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'dvdsub', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'vtt', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'sub', Method: 'Embed' }); profile.SubtitleProfiles.push({ Format: 'idx', Method: 'Embed' }); profile.ResponseProfiles = []; return profile; } var currentMediaSource; var currentItem; var basePlayerState; var progressInterval; function getVideoStreamInfo(item) { var deferred = $.Deferred(); var deviceProfile = getDeviceProfile(); var startPosition = 0; MediaPlayer.tryStartPlayback(deviceProfile, item, startPosition, function (mediaSource) { playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred); }); return deferred.promise(); } function playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred) { Dashboard.hideLoadingMsg(); currentItem = item; currentMediaSource = mediaSource; basePlayerState = { PlayState: { } }; MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition).then(function (streamInfo) { var currentSrc = streamInfo.url; var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc); if (audioStreamIndex) { basePlayerState.PlayState.AudioStreamIndex = parseInt(audioStreamIndex); } basePlayerState.PlayState.SubtitleStreamIndex = self.currentSubtitleStreamIndex; basePlayerState.PlayState.PlayMethod = getParameterByName('static', currentSrc) == 'true' ? 'DirectStream' : 'Transcode'; basePlayerState.PlayState.LiveStreamId = getParameterByName('LiveStreamId', currentSrc); basePlayerState.PlayState.PlaySessionId = getParameterByName('PlaySessionId', currentSrc); basePlayerState.PlayState.MediaSourceId = mediaSource.Id; basePlayerState.PlayState.CanSeek = false; basePlayerState.NowPlayingItem = MediaPlayer.getNowPlayingItemForReporting(item, mediaSource); deferred.resolveWith(null, [streamInfo]); }); } function getPlayerState(positionTicks) { var state = basePlayerState; state.PlayState.PositionTicks = positionTicks; return state; } function onPlaybackStart() { closePlayMenu(); var state = getPlayerState(); var info = { ItemId: state.NowPlayingItem.Id, NowPlayingItem: state.NowPlayingItem }; info = $.extend(info, state.PlayState); ApiClient.reportPlaybackStart(info); // This is really just a ping to let the server know we're still playing progressInterval = setInterval(function () { onPlaybackProgress(null); }, 10000); // Need a timeout because we can't show a popup at the same time as the previous one is closing // Bumping it up to 1000 because the post play menu is hiding for some reason on android setTimeout(function () { showPostPlayMenu(currentItem); }, 1000); } function onPlaybackProgress(positionTicks) { var state = getPlayerState(positionTicks); var info = { ItemId: state.NowPlayingItem.Id, NowPlayingItem: state.NowPlayingItem }; info = $.extend(info, state.PlayState); ApiClient.reportPlaybackProgress(info); } function onPlaybackStopped(positionTicks) { var state = getPlayerState(positionTicks); var stopInfo = { itemId: state.NowPlayingItem.Id, mediaSourceId: state.PlayState.MediaSourceId, positionTicks: state.PlayState.PositionTicks }; if (state.PlayState.LiveStreamId) { stopInfo.LiveStreamId = state.PlayState.LiveStreamId; } if (state.PlayState.PlaySessionId) { stopInfo.PlaySessionId = state.PlayState.PlaySessionId; } ApiClient.reportPlaybackStopped(stopInfo); if (progressInterval) { clearInterval(progressInterval); progressInterval = null; } } function showPostPlayMenu(item) { require(['jqmpopup', 'jqmlistview'], function () { $('.externalPlayerPostPlayFlyout').popup("close").remove(); var html = '
' + Globalize.translate('LabelResumePoint') + '
'; html += ' '; html += ' '; html += '