(function (window, document, $) { function showMenu(sessions, options) { var html = '
'; html += 'Close'; html += '
'; html += '
Remote Control
'; html += '
'; html += '
'; html += '
'; // Add controls here html += '
'; html += '
'; html += '
'; html += '
'; html += ''; html += ''; html += '
'; html += ''; html += '
'; html += '
'; $(document.body).append(html); var popup = $('.remoteControlFlyout').popup({ history: false, tolerance: 0, corners: false }).trigger('create').popup("open").on("popupafterclose", function () { if (ApiClient.isWebSocketOpen()) { ApiClient.sendWebSocketMessage("SessionsStop"); } $(ApiClient).off("websocketmessage.remotecontrol"); $(this).off("popupafterclose").remove(); $('.remoteControlFlyout').popup("destroy").remove(); }); renderSessionsInControlMenu(popup, sessions, options); updateSessionInfo(popup, sessions, options); if (ApiClient.isWebSocketOpen()) { ApiClient.sendWebSocketMessage("SessionsStart", "1000,1000"); $(ApiClient).on("websocketmessage.remotecontrol", function (e, msg) { if (msg.MessageType === "Sessions") { // Update existing data updateSessionInfo(popup, msg.Data); } }); } $('.btnGoHome', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendCommand(id, 'GoHome'); }); $('.btnGoToSettings', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendCommand(id, 'GoToSettings'); }); $('.btnSendMessage', popup).on('click', function () { var id = $('#selectSession', popup).val(); var messageText = $('#txtMessage', popup).val(); if (messageText) { Dashboard.getCurrentUser().done(function (user) { ApiClient.sendMessageCommand(id, { Header: "Message from " + user.Name, Text: messageText }); }); } else { $('#txtMessage', popup)[0].focus(); } }); $('.btnVolumeDown', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendCommand(id, 'VolumeDown'); }); $('.btnVolumeUp', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendCommand(id, 'VolumeUp'); }); $('.btnToggleMute', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendCommand(id, 'ToggleMute'); }); $('.btnStop', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'Stop'); }); $('.btnPause', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'Pause'); }); $('.btnPlay', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'Unpause'); }); $('.btnNextTrack', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'NextTrack'); }); $('.btnPreviousTrack', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'PreviousTrack'); }); $("#positionSlider", popup).on("slidestart", function () { this.isSliding = true; }).on("slidestop", function () { var id = $('#selectSession', popup).val(); var percent = $(this).val(); var duration = parseInt($(this).attr('data-duration')); var position = duration * percent / 100; ApiClient.sendPlayStateCommand(id, 'Seek', { SeekPositionTicks: parseInt(position) }); this.isSliding = false; }); $('.btnFullscreen', popup).on('click', function () { var id = $('#selectSession', popup).val(); ApiClient.sendPlayStateCommand(id, 'Fullscreen'); }); } function getPlaybackHtml(session) { var html = ''; html += '

'; html += '

'; html += '
'; html += '
'; html += ''; html += ' / '; html += ''; html += '
'; html += '
'; html += '
'; html += '
'; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; if (session && session.SupportsFullscreenToggle) { html += ''; } html += '
'; return html; } function updateSessionInfo(popup, sessions) { var id = $('#selectSession', popup).val(); // don't display the current session var session = sessions.filter(function (s) { return s.Id == id; })[0]; if (!session) { $('.nothingPlaying', popup).hide(); $('.nowPlaying', popup).hide(); $('.commandsCollapsible', popup).hide(); } else if (session.NowPlayingItem) { $('.commandsCollapsible', popup).show(); $('.nothingPlaying', popup).hide(); var elem = $('.nowPlaying', popup).show(); updateNowPlaying(elem, session); } else { $('.commandsCollapsible', popup).show(); $('.nothingPlaying', popup).show(); $('.nowPlaying', popup).hide(); } } function updateNowPlaying(elem, session) { var item = session.NowPlayingItem; $('.nowPlayingTitle', elem).html(item.Name); var imageContainer = $('.nowPlayingImage', elem); if (item.PrimaryImageTag) { imageContainer.show(); var img = $('img', imageContainer)[0]; var imgUrl = ApiClient.getImageUrl(item.Id, { maxheight: 300, type: 'Primary', tag: item.PrimaryImageTag }); if (!img || img.src.toLowerCase().indexOf(imgUrl.toLowerCase()) == -1) { imageContainer.html(''); } } else { imageContainer.hide(); } if (session.CanSeek) { $('.remotePositionSliderContainer', elem).show(); } else { $('.remotePositionSliderContainer', elem).hide(); } var time = session.NowPlayingPositionTicks || 0; var duration = item.RunTimeTicks || 0; var percent = duration ? 100 * time / duration : 0; var slider = $('#positionSlider', elem); if (!slider[0].isSliding) { slider.val(percent).slider('refresh'); } slider.attr('data-duration', duration); $('.nowPlayingTime', elem).html(Dashboard.getDisplayTime(time)); $('.duration', elem).html(Dashboard.getDisplayTime(duration)); if (session.IsPaused) { $('.btnPauseParent', elem).hide(); $('.btnPlayParent', elem).show(); } else { $('.btnPauseParent', elem).show(); $('.btnPlayParent', elem).hide(); } } function renderSessionsInControlMenu(popup, sessions, options) { options = options || {}; var deviceId = ApiClient.deviceId(); // don't display the current session sessions = sessions.filter(function (s) { return s.DeviceId != deviceId && s.SupportsRemoteControl; }); var elem = $('#selectSession', popup); var currentValue = options.sessionId || elem.val(); if (currentValue) { // Make sure the session is still active var currentSession = sessions.filter(function (s) { return s.Id == currentValue; })[0]; if (!currentSession) { currentValue = null; } } if (!currentValue && sessions.length) { currentValue = sessions[0].Id; } var html = ''; for (var i = 0, length = sessions.length; i < length; i++) { var session = sessions[i]; var text = session.DeviceName; if (session.UserName) { text += ' - ' + session.UserName; } html += ''; } elem.html(html).val(currentValue).selectmenu('refresh'); } function remoteControl() { var self = this; var sessionQuery = { SupportsRemoteControl: true, ControllableByUserId: Dashboard.getCurrentUserId() }; self.showMenu = function (options) { ApiClient.getSessions(sessionQuery).done(function (sessions) { showMenu(sessions, options); }); }; } window.RemoteControl = new remoteControl(); function sendPlayCommand(options, playType) { var sessionId = MediaController.getPlayerInfo().id; var ids = options.ids || options.items.map(function (i) { return i.Id; }); var remoteOptions = { ItemIds: ids.join(','), PlayCommand: playType }; if (options.startPositionTicks) { remoteOptions.startPositionTicks = options.startPositionTicks; } ApiClient.sendPlayCommand(sessionId, remoteOptions); } function sendPlayStateCommand(command, options) { var sessionId = MediaController.getPlayerInfo().id; ApiClient.sendPlayStateCommand(sessionId, command, options); } function sendCommand(command, options) { var sessionId = MediaController.getPlayerInfo().id; ApiClient.sendCommand(sessionId, command, options); } function remoteControlPlayer() { var self = this; self.name = 'Remote Control'; self.play = function (options) { sendPlayCommand(options, 'PlayNow'); }; self.shuffle = function (id) { sendPlayCommand({ ids: [id] }, 'PlayShuffle'); }; self.instantMix = function (id) { sendPlayCommand({ ids: [id] }, 'PlayInstantMix'); }; self.queue = function (options) { sendPlayCommand(options, 'PlayNext'); }; self.queueNext = function (options) { sendPlayCommand(options, 'PlayLast'); }; self.canQueueMediaType = function (mediaType) { return mediaType == 'Audio' || mediaType == 'Video'; }; self.stop = function () { sendPlayStateCommand('stop'); }; self.nextTrack = function () { sendPlayStateCommand('nextTrack'); }; self.previousTrack = function () { sendPlayStateCommand('previousTrack'); }; self.seek = function (positionTicks) { sendPlayStateCommand('seek', { SeekPositionTicks: positionTicks }); }; self.pause = function () { sendPlayStateCommand('Pause'); }; self.unpause = function () { sendPlayStateCommand('Unpause'); }; self.mute = function () { sendCommand('Mute'); }; self.unMute = function () { sendCommand('Unmnute'); }; self.toggleMute = function () { sendCommand('ToggleMute'); }; self.setVolume = function (vol) { sendCommand('SetVolume', { Volume: vol }); }; self.displayContent = function (options) { sendCommand('DisplayContent', { ItemName: options.itemName, ItemType: options.itemType, ItemId: options.itemId, Context: options.context }); }; self.getPlayerState = function () { var deferred = $.Deferred(); ApiClient.getSessions().done(function (sessions) { var currentTargetId = MediaController.getPlayerInfo().id; // Update existing data //updateSessionInfo(popup, msg.Data); var session = sessions.filter(function (s) { return s.Id == currentTargetId; })[0]; if (session) { session = getPlayerState(session); } deferred.resolveWith(null, [session]); }); return deferred.promise(); }; function subscribeToPlayerUpdates() { if (ApiClient.isWebSocketOpen()) { ApiClient.sendWebSocketMessage("SessionsStart", "100,700"); } } function unsubscribeFromPlayerUpdates() { if (ApiClient.isWebSocketOpen()) { ApiClient.sendWebSocketMessage("SessionsStop"); } } var playerListenerCount = 0; self.beginPlayerUpdates = function () { if (playerListenerCount <= 0) { playerListenerCount = 0; subscribeToPlayerUpdates(); } playerListenerCount++; }; self.endPlayerUpdates = function () { playerListenerCount--; if (playerListenerCount <= 0) { unsubscribeFromPlayerUpdates(); playerListenerCount = 0; } }; self.getTargets = function () { var deferred = $.Deferred(); var sessionQuery = { SupportsRemoteControl: true, ControllableByUserId: Dashboard.getCurrentUserId() }; ApiClient.getSessions(sessionQuery).done(function (sessions) { var targets = sessions.filter(function (s) { return s.DeviceId != ApiClient.deviceId(); }).map(function (s) { return { name: s.DeviceName, id: s.Id, playerName: self.name, appName: s.Client, playableMediaTypes: s.PlayableMediaTypes, isLocalPlayer: false, supportedCommands: s.SupportedCommands }; }); deferred.resolveWith(null, [targets]); }).fail(function () { deferred.reject(); }); return deferred.promise(); }; } var player = new remoteControlPlayer(); MediaController.registerPlayer(player); function getPlayerState(session) { var state = { volumeLevel: session.VolumeLevel, isMuted: session.IsMuted, isPaused: session.IsPaused, canSeek: session.CanSeek }; var item = session.NowPlayingItem; if (item) { state.itemId = item.Id; state.mediaType = item.MediaType; state.itemType = item.Type; state.indexNumber = item.IndexNumber; state.indexNumberEnd = item.IndexNumberEnd; state.parentIndexNumber = item.ParentIndexNumber; state.productionYear = item.ProductionYear; state.premiereDate = item.PremiereDate; state.seriesName = item.SeriesName; state.album = item.Album; state.itemName = item.Name; state.artists = item.Artists; state.primaryImageItemId = item.PrimaryImageItemId; state.primaryImageTag = item.PrimaryImageTag; state.backdropItemId = item.BackdropItemId; state.backdropImageTag = item.BackdropImageTag; state.thumbItemId = item.ThumbItemId; state.thumbImageTag = item.ThumbImageTag; state.mediaSource = item.MediaSourceId; state.positionTicks = session.NowPlayingPositionTicks || 0; state.runtimeTicks = item.RunTimeTicks; } return state; } function firePlaybackEvent(name, session) { $(player).trigger(name, [getPlayerState(session)]); } function onWebSocketMessageReceived(e, msg) { if (msg.MessageType === "Sessions") { var currentTargetId = MediaController.getPlayerInfo().id; // Update existing data //updateSessionInfo(popup, msg.Data); var session = msg.Data.filter(function (s) { return s.Id == currentTargetId; })[0]; if (session) { firePlaybackEvent('playstatechange', session); } } else if (msg.MessageType === "SessionEnded") { console.log("Server reports another session ended"); if (MediaController.getPlayerInfo().id == msg.Data.Id) { MediaController.setDefaultPlayerActive(); } } else if (msg.MessageType === "PlaybackStart") { firePlaybackEvent('playbackstart', msg.Data); } else if (msg.MessageType === "PlaybackStopped") { firePlaybackEvent('playbackstop', msg.Data); } } $(ApiClient).on("websocketmessage", onWebSocketMessageReceived); })(window, document, jQuery);