diff --git a/dashboard-ui/css/images/remote.png b/dashboard-ui/css/images/remote.png new file mode 100644 index 0000000000..66f8a55271 Binary files /dev/null and b/dashboard-ui/css/images/remote.png differ diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 5ab21f8bbe..08833be252 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -484,7 +484,7 @@ a.itemTag:hover { display: inline-block; } - .viewMenuImageLink { + .viewMenuImageLink:not(.remoteControlMenuLink) { display: none; } diff --git a/dashboard-ui/css/remotecontrol.css b/dashboard-ui/css/remotecontrol.css index 4a4d1ad376..56cb86ddf6 100644 --- a/dashboard-ui/css/remotecontrol.css +++ b/dashboard-ui/css/remotecontrol.css @@ -52,6 +52,10 @@ height: 50px; } +.nowPlaying .ui-slider-track { + margin-left: 15px!important; +} + @media all and (max-width: 550px) { .nowPlayingCell + .nowPlayingCell { display: none; diff --git a/dashboard-ui/scripts/Itemdetailpage.js b/dashboard-ui/scripts/Itemdetailpage.js index 84bb702f55..1ba81aa05a 100644 --- a/dashboard-ui/scripts/Itemdetailpage.js +++ b/dashboard-ui/scripts/Itemdetailpage.js @@ -883,7 +883,7 @@ $('#btnRemote', page).on('click', function () { - RemoteControl.showMenu({ + RemoteControl.showMenuForItem({ item: currentItem, context: getContext(currentItem), diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js index a70908315d..99223f9a9d 100644 --- a/dashboard-ui/scripts/itembynamedetailpage.js +++ b/dashboard-ui/scripts/itembynamedetailpage.js @@ -489,7 +489,7 @@ $('#btnRemote', page).on('click', function () { - RemoteControl.showMenu({ item: currentItem, context: getParameterByName('context') || '' }); + RemoteControl.showMenuForItem({ item: currentItem, context: getParameterByName('context') || '' }); }); $('#btnEdit', page).on('click', function () { diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 0c3fe87aeb..adb0b7fc9a 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -1815,6 +1815,8 @@ html += '' + (view == 'games' ? selectedHtml : '') + 'Games'; } + html += 'Remote Control'; + html += '
'; html += Search.getSearchHtml(); diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 079dcc5a74..6b36b28f3c 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -101,7 +101,7 @@ clearProgressInterval(); - var intervalTime = ApiClient.isWebSocketOpen() ? 10000 : 30000; + var intervalTime = ApiClient.isWebSocketOpen() ? 5000 : 20000; currentProgressInterval = setInterval(function () { @@ -831,6 +831,10 @@ self.playInternal = function (item, startPosition, user) { + if (item == null) { + throw new Error("item cannot be null"); + } + if (self.isPlaying()) { self.stop(); } diff --git a/dashboard-ui/scripts/moviegenres.js b/dashboard-ui/scripts/moviegenres.js index 46c50739c8..0f352d6137 100644 --- a/dashboard-ui/scripts/moviegenres.js +++ b/dashboard-ui/scripts/moviegenres.js @@ -5,7 +5,7 @@ SortBy: "SortName", SortOrder: "Ascending", - IncludeItemTypes: "Movie", + IncludeItemTypes: "Movie,Trailer", Recursive: true, Fields: "ItemCounts,DateCreated,UserData", StartIndex: 0 diff --git a/dashboard-ui/scripts/moviepeople.js b/dashboard-ui/scripts/moviepeople.js index 618cae0790..dc54635fb6 100644 --- a/dashboard-ui/scripts/moviepeople.js +++ b/dashboard-ui/scripts/moviepeople.js @@ -5,7 +5,7 @@ SortBy: "SortName", SortOrder: "Ascending", - IncludeItemTypes: "Movie", + IncludeItemTypes: "Movie,Trailer", Recursive: true, Fields: "ItemCounts,DateCreated,UserData", PersonTypes: "", diff --git a/dashboard-ui/scripts/moviestudios.js b/dashboard-ui/scripts/moviestudios.js index 7336b4bd3f..a3516f145f 100644 --- a/dashboard-ui/scripts/moviestudios.js +++ b/dashboard-ui/scripts/moviestudios.js @@ -5,7 +5,7 @@ SortBy: "SortName", SortOrder: "Ascending", - IncludeItemTypes: "Movie", + IncludeItemTypes: "Movie,Trailer", Recursive: true, Fields: "ItemCounts,DateCreated,UserData", StartIndex: 0 diff --git a/dashboard-ui/scripts/musicgenres.js b/dashboard-ui/scripts/musicgenres.js index bb46318561..b63545aec2 100644 --- a/dashboard-ui/scripts/musicgenres.js +++ b/dashboard-ui/scripts/musicgenres.js @@ -5,7 +5,7 @@ SortBy: "SortName", SortOrder: "Ascending", - IncludeItemTypes: "Audio", + IncludeItemTypes: "Audio,MusicVideo", Recursive: true, Fields: "ItemCounts,DateCreated,UserData", StartIndex: 0 diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 7895159dd3..a6b4ab7b14 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -27,7 +27,7 @@ } - function showMenu(options, sessionsPromise) { + function showMenuForItem(options, sessionsPromise) { var playFromRendered; var trailersRendered; @@ -204,11 +204,12 @@ var deviceId = ApiClient.deviceId(); + // don't display the current session sessions = sessions.filter(function (s) { return s.DeviceId != deviceId; }); - renderSessions(sessions, options, elem); + renderSessionsInPlayMenu(sessions, options, elem); if (ApiClient.isWebSocketOpen()) { ApiClient.sendWebSocketMessage("SessionsStart", "1500,1500"); @@ -216,7 +217,7 @@ $(ApiClient).on("websocketmessage.remotecontrol", function (e, msg) { if (msg.MessageType === "Sessions") { - refreshSessions(msg.Data, elem); + updateSessionsInPlayMenu(msg.Data, elem); } }); @@ -392,7 +393,7 @@ $('.chkSelectPlayTime:first', elem).checked(true); } - function renderSessions(sessions, options, elem) { + function renderSessionsInPlayMenu(sessions, options, elem) { if (!sessions.length) { elem.html('

There are currently no available media browser sessions to control.

'); @@ -536,7 +537,7 @@ return html; } - function refreshSessions(sessions, elem) { + function updateSessionsInPlayMenu(sessions, elem) { for (var i = 0, length = sessions.length; i < length; i++) { @@ -612,12 +613,240 @@ $('.chkSelectItem:first', elem).checked(true); } + function showMenu(sessions) { + + var html = '
'; + + html += '
'; + html += '
Remote Control
'; + html += '
'; + + html += '
'; + + html += '
'; + + // Add controls here + html += '
'; + html += '
'; + + 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(); + }); + + renderSessionsInControlMenu(popup, sessions); + updateSessionInfo(popup, sessions); + + if (ApiClient.isWebSocketOpen()) { + ApiClient.sendWebSocketMessage("SessionsStart", "1500,1500"); + + $(ApiClient).on("websocketmessage.remotecontrol", function (e, msg) { + + if (msg.MessageType === "Sessions") { + + // Update existing data + updateSessionInfo(popup, msg.Data); + } + }); + + } + } + + function getPlaybackHtml() { + + var html = ''; + + html += '

'; + + html += '

'; + + html += '
'; + + html += '
'; + html += ''; + html += ' / '; + html += ''; + html += '
'; + + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += ''; + html += ''; + html += ''; + 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 && session.NowPlayingItem) { + + $('.nothingPlaying', popup).hide(); + + var elem = $('.nowPlaying', popup).show(); + + updateNowPlaying(elem, session); + + } else { + + $('.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: 200, + type: 'Primary', + tag: item.PrimaryImageTag + }); + + if (!img || img.src.toLowerCase().indexOf(imgUrl.toLowerCase()) == -1) { + imageContainer.html(''); + } + + } else { + imageContainer.hide(); + } + + var time = session.NowPlayingPositionTicks || 0; + var duration = item.RunTimeTicks || 0; + + var percent = duration ? 100 * time / duration : 0; + + $('#positionSlider', elem).val(percent).slider('refresh'); + + $('.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) { + + 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 = 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.Client + ' - ' + session.DeviceName; + + if (session.UserName) { + text += ' - ' + session.UserName; + } + + html += ''; + } + + elem.html(html).val(currentValue).selectmenu('refresh'); + + } + function remoteControl() { var self = this; - self.showMenu = function (options) { - showMenu(options, ApiClient.getSessions({ SupportsRemoteControl: true })); + self.showMenuForItem = function (options) { + showMenuForItem(options, ApiClient.getSessions({ SupportsRemoteControl: true })); + }; + + self.showMenu = function () { + ApiClient.getSessions({ SupportsRemoteControl: true }).done(function (sessions) { + + showMenu(sessions); + + }); }; }