diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 10fc04fea3..951f6213be 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -165,7 +165,7 @@ /****************************************/ @media all and (max-width: 1200px), all and (max-height: 720px) { - #mediaPlayer .chaptersButton, #mediaPlayer .audioTracksButton, #mediaPlayer .sendMediaButton { + #mediaPlayer .chaptersButton, #mediaPlayer .audioTracksButton { display: none!important; } @@ -179,7 +179,7 @@ } @media all and (max-width: 960px), all and (max-height: 550px) { - #mediaPlayer .nowPlayingBarImage, #mediaPlayer .qualityButton, #mediaPlayer .audioTracksButton, #mediaPlayer .chaptersButton, #mediaPlayer .sendMediaButton { + #mediaPlayer .nowPlayingBarImage, #mediaPlayer .qualityButton, #mediaPlayer .audioTracksButton, #mediaPlayer .chaptersButton { display: none!important; } @@ -193,7 +193,7 @@ } @media all and (max-width: 800px), all and (max-height: 460px) { - #mediaPlayer .muteButton, #mediaPlayer .unmuteButton, #mediaPlayer .nowPlayingMediaInfo, #mediaPlayer .sendMediaButton { + #mediaPlayer .muteButton, #mediaPlayer .unmuteButton, #mediaPlayer .nowPlayingMediaInfo { display: none!important; } diff --git a/dashboard-ui/css/mediaplayer.css b/dashboard-ui/css/mediaplayer.css index d37ae0230b..4affbc40c3 100644 --- a/dashboard-ui/css/mediaplayer.css +++ b/dashboard-ui/css/mediaplayer.css @@ -135,7 +135,7 @@ input[type="range"]::-ms-fill-upper { } @media all and (max-width: 600px) { - .chaptersButton, .audioTracksButton, .sendMediaButton { + .chaptersButton, .audioTracksButton { display: none!important; } diff --git a/dashboard-ui/dlnaprofile.html b/dashboard-ui/dlnaprofile.html index a8eeb735d4..274977b65e 100644 --- a/dashboard-ui/dlnaprofile.html +++ b/dashboard-ui/dlnaprofile.html @@ -120,11 +120,13 @@
-

Add direct play profiles to indicate what formats the device can handle natively.

+

Add direct play profiles to indicate which formats the device can handle natively.

+ +
-

Add transcoding profiles to indicate what formats should be used when transcoding is required.

+

Add transcoding profiles to indicate which formats should be used when transcoding is required.

diff --git a/dashboard-ui/itembynamedetails.html b/dashboard-ui/itembynamedetails.html index 004e622757..ac2fa11905 100644 --- a/dashboard-ui/itembynamedetails.html +++ b/dashboard-ui/itembynamedetails.html @@ -145,9 +145,6 @@ - - - diff --git a/dashboard-ui/itemdetails.html b/dashboard-ui/itemdetails.html index 8ebed78750..e341ee3ac1 100644 --- a/dashboard-ui/itemdetails.html +++ b/dashboard-ui/itemdetails.html @@ -131,9 +131,6 @@ - diff --git a/dashboard-ui/livetvchannel.html b/dashboard-ui/livetvchannel.html index 426a0b3eee..52abc92969 100644 --- a/dashboard-ui/livetvchannel.html +++ b/dashboard-ui/livetvchannel.html @@ -30,9 +30,6 @@ - - - diff --git a/dashboard-ui/livetvprogram.html b/dashboard-ui/livetvprogram.html index 28daefb570..531ac3a5a9 100644 --- a/dashboard-ui/livetvprogram.html +++ b/dashboard-ui/livetvprogram.html @@ -47,9 +47,6 @@ - - -
diff --git a/dashboard-ui/livetvrecording.html b/dashboard-ui/livetvrecording.html index a1375e3d20..7e35119e94 100644 --- a/dashboard-ui/livetvrecording.html +++ b/dashboard-ui/livetvrecording.html @@ -41,9 +41,6 @@ - - - diff --git a/dashboard-ui/scripts/dlnaprofile.js b/dashboard-ui/scripts/dlnaprofile.js index 9c1897a9f3..2704172efd 100644 --- a/dashboard-ui/scripts/dlnaprofile.js +++ b/dashboard-ui/scripts/dlnaprofile.js @@ -67,7 +67,7 @@ } function renderSubProfiles(page, profile) { - + renderDirectPlayProfiles(page, profile.DirectPlayProfiles); renderTranscodingProfiles(page, profile.TranscodingProfiles); renderContainerProfiles(page, profile.ContainerProfiles); @@ -75,10 +75,11 @@ renderMediaProfiles(page, profile.MediaProfiles); } - function editDirectPlayProfile(page, directPlayProfile, isNew) { + function editDirectPlayProfile(page, directPlayProfile) { + isSubProfileNew = directPlayProfile == null; + directPlayProfile = directPlayProfile || {}; currentSubProfile = directPlayProfile; - isSubProfileNew = isNew; var popup = $('#popupEditDirectPlayProfile', page).popup('open'); @@ -94,16 +95,16 @@ currentSubProfile.Container = $('#txtDirectPlayContainer', page).val(); currentSubProfile.AudioCodec = $('#txtDirectPlayAudioCodec', page).val(); currentSubProfile.VideoCodec = $('#txtDirectPlayVideoCodec', page).val(); - + if (isSubProfileNew) { currentProfile.DirectPlayProfiles.push(currentSubProfile); - } + } renderSubProfiles(page, currentProfile); currentSubProfile = null; - + $('#popupEditDirectPlayProfile', page).popup('close'); } @@ -432,7 +433,7 @@ }).done(function () { - Dashboard.navigate('dlnaprofiles.html'); + Dashboard.alert('Settings saved.'); }); } else { @@ -503,6 +504,12 @@ }); + $('.btnAddDirectPlayProfile', page).on('click', function () { + + editDirectPlayProfile(page); + + }); + }).on('pageshow', "#dlnaProfilePage", function () { var page = this; diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js index b1d7b4901a..7852a86d3e 100644 --- a/dashboard-ui/scripts/itembynamedetailpage.js +++ b/dashboard-ui/scripts/itembynamedetailpage.js @@ -81,7 +81,7 @@ Dashboard.getCurrentUser().done(function (user) { - if (MediaPlayer.canPlay(item, user)) { + if (MediaController.canPlay(item)) { $('#playButtonContainer', page).show(); } else { $('#playButtonContainer', page).hide(); @@ -518,12 +518,7 @@ $('#btnPlay', page).on('click', function () { var userdata = currentItem.UserData || {}; - LibraryBrowser.showPlayMenu(this, currentItem.Name, currentItem.Type, "Audio", userdata.PlaybackPositionTicks); - }); - - $('#btnRemote', page).on('click', function () { - - RemoteControl.showMenuForItem({ item: currentItem, context: getParameterByName('context') || '' }); + LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, false, "Audio", userdata.PlaybackPositionTicks); }); }).on('pageshow', "#itemByNameDetailPage", function () { diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index cc95f465a4..50b0ec2a27 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -29,8 +29,6 @@ renderDetails(page, item, context); LibraryBrowser.renderDetailPageBackdrop(page, item); - $("#remoteButtonContainer", page).show(); - if (user.Configuration.IsAdministrator) { $('#editButtonContainer', page).show(); @@ -38,21 +36,18 @@ $('#editButtonContainer', page).hide(); } - if (MediaPlayer.canPlay(item, user)) { + var externalPlayUrl = getExternalPlayUrl(item); + $('#btnPlayExternal', page).attr('href', externalPlayUrl || '#'); - var url = MediaPlayer.getPlayUrl(item); - - if (url) { - $('#playExternalButtonContainer', page).show(); - $('#playButtonContainer', page).hide(); - } else { - $('#playButtonContainer', page).show(); - $('#playExternalButtonContainer', page).hide(); - } - - $('#btnPlayExternal', page).attr('href', url || '#'); - - } else { + if (externalPlayUrl) { + $('#playExternalButtonContainer', page).show(); + $('#playButtonContainer', page).hide(); + } + else if (MediaController.canPlay(item)) { + $('#playButtonContainer', page).show(); + $('#playExternalButtonContainer', page).hide(); + } + else { $('#playButtonContainer', page).hide(); $('#playExternalButtonContainer', page).hide(); } @@ -124,6 +119,22 @@ $('#btnEdit', page).attr('href', "edititemmetadata.html?id=" + id); } + function getExternalPlayUrl(item) { + + + if (item.GameSystem == "Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { + + return "http://nesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom; + } + + if (item.GameSystem == "Super Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { + + return "http://snesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom; + } + + return null; + }; + function setPeopleHeader(page, item) { if (item.Type == "Audio" || item.Type == "MusicAlbum" || item.MediaType == "Book" || item.MediaType == "Photo") { @@ -1107,7 +1118,7 @@ attributes.push(createAttribute("Layout", stream.ChannelLayout)); } else if (stream.Channels) { - attributes.push(createAttribute("Channels", stream.Channels + ' ch')); + attributes.push(createAttribute("Channels", stream.Channels + ' ch')); } if (stream.BitRate && stream.Codec != "mjpeg") { @@ -1138,7 +1149,7 @@ if (version.Path) { html += '
Path' + version.Path + ''; } - + return html; } @@ -1162,7 +1173,7 @@ var href = "itemdetails.html?id=" + item.Id; - var onclick = item.PlayAccess == 'Full' ? ' onclick="MediaPlayer.playById(\'' + item.Id + '\'); return false;"' : ""; + var onclick = item.PlayAccess == 'Full' ? ' onclick="MediaController.play(\'' + item.Id + '\'); return false;"' : ""; html += ''; @@ -1286,7 +1297,10 @@ function play(startPosition) { - MediaPlayer.play([currentItem], startPosition); + MediaController.play({ + items: [currentItem], + startPositionTicks: startPosition + }); } function splitVersions(page) { @@ -1317,7 +1331,7 @@ ApiClient.getLocalTrailers(Dashboard.getCurrentUserId(), currentItem.Id).done(function (trailers) { - MediaPlayer.play(trailers); + MediaController.play({ items: trailers }); }); } @@ -1335,7 +1349,7 @@ mediaType = "Audio"; } - LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, mediaType, userdata.PlaybackPositionTicks); + LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, currentItem.IsFolder, mediaType, userdata.PlaybackPositionTicks); }); $('#btnPlayTrailer', page).on('click', function () { @@ -1347,19 +1361,6 @@ ApiClient.markPlayed(Dashboard.getCurrentUserId(), currentItem.Id, new Date()); }); - $('#btnRemote', page).on('click', function () { - - RemoteControl.showMenuForItem({ - - item: currentItem, - context: getContext(currentItem), - - themeSongs: $('#themeSongsCollapsible:visible', page).length > 0, - - themeVideos: $('#themeVideosCollapsible:visible', page).length > 0 - }); - }); - $('.btnSplitVersions', page).on('click', function () { splitVersions(page); diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 91b3369f87..f4dd3911bd 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -211,7 +211,7 @@ html += ''; html += ''; - html += ''; + html += ''; html += ''; var num = item.IndexNumber; @@ -287,12 +287,12 @@ return html; }, - showPlayMenu: function (positionTo, itemId, itemType, mediaType, resumePositionTicks) { + showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks) { var isPlaying = MediaPlayer.isPlaying(); - if (!isPlaying && !resumePositionTicks && mediaType != "Audio") { - MediaPlayer.playById(itemId); + if (!isPlaying && !resumePositionTicks && mediaType != "Audio" && !isFolder) { + MediaController.play(itemId); return; } @@ -303,38 +303,22 @@ html += ''; diff --git a/dashboard-ui/scripts/librarylist.js b/dashboard-ui/scripts/librarylist.js index 23488ac7a2..5fab7b43cf 100644 --- a/dashboard-ui/scripts/librarylist.js +++ b/dashboard-ui/scripts/librarylist.js @@ -102,16 +102,16 @@ var buttonCount = 0; - if (MediaPlayer.canPlay(item, currentUser)) { + if (MediaController.canPlay(item)) { var resumePosition = (item.UserData || {}).PlaybackPositionTicks || 0; - var onPlayClick = 'LibraryBrowser.showPlayMenu(this, \'' + item.Id + '\', \'' + item.Type + '\', \'' + item.MediaType + '\', ' + resumePosition + ');return false;'; + var onPlayClick = 'LibraryBrowser.showPlayMenu(this, \'' + item.Id + '\', \'' + item.Type + '\', ' + item.IsFolder + ', \'' + item.MediaType + '\', ' + resumePosition + ');return false;'; html += ''; buttonCount++; if (item.MediaType == "Audio" || item.Type == "MusicAlbum") { - html += ''; + html += ''; buttonCount++; } } @@ -126,10 +126,6 @@ buttonCount++; } - if (!isPortrait || buttonCount < 3) { - html += ''; - } - html += '
'; html += '
'; @@ -142,22 +138,7 @@ var id = this.getAttribute('data-itemid'); ApiClient.getLocalTrailers(Dashboard.getCurrentUserId(), id).done(function (trailers) { - MediaPlayer.play(trailers); - }); - - return false; - } - - function onRemoteControlButtonClick() { - - var id = this.getAttribute('data-itemid'); - - ApiClient.getItem(Dashboard.getCurrentUserId(), id).done(function (item) { - - RemoteControl.showMenuForItem({ - item: item - }); - + MediaController.play({ items: trailers }); }); return false; @@ -248,7 +229,6 @@ innerElem.html(getOverlayHtml(item, user, elem)).trigger('create'); $('.btnPlayTrailer', innerElem).on('click', onTrailerButtonClick); - $('.btnRemoteControl', innerElem).on('click', onRemoteControlButtonClick); }); innerElem.show().each(function () { diff --git a/dashboard-ui/scripts/livetvchannel.js b/dashboard-ui/scripts/livetvchannel.js index b76c896987..12b93a7c9c 100644 --- a/dashboard-ui/scripts/livetvchannel.js +++ b/dashboard-ui/scripts/livetvchannel.js @@ -146,7 +146,7 @@ Dashboard.getCurrentUser().done(function (user) { - if (MediaPlayer.canPlay(item, user)) { + if (MediaController.canPlay(item)) { $('#playButtonContainer', page).show(); } else { $('#playButtonContainer', page).hide(); @@ -296,12 +296,7 @@ $('#btnPlay', page).on('click', function () { var userdata = currentItem.UserData || {}; - LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, currentItem.MediaType, userdata.PlaybackPositionTicks); - }); - - $('#btnRemote', page).on('click', function () { - - RemoteControl.showMenuForItem({ item: currentItem, context: 'livetv' }); + LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, false, currentItem.MediaType, userdata.PlaybackPositionTicks); }); $('#btnEdit', page).on('click', function () { diff --git a/dashboard-ui/scripts/livetvprogram.js b/dashboard-ui/scripts/livetvprogram.js index 230b3fb9b0..8a43bf9885 100644 --- a/dashboard-ui/scripts/livetvprogram.js +++ b/dashboard-ui/scripts/livetvprogram.js @@ -114,7 +114,7 @@ ApiClient.getLiveTvChannel(currentItem.ChannelId, Dashboard.getCurrentUserId()).done(function (channel) { var userdata = channel.UserData || {}; - LibraryBrowser.showPlayMenu(this, channel.Id, channel.Type, channel.MediaType, userdata.PlaybackPositionTicks); + LibraryBrowser.showPlayMenu(this, channel.Id, channel.Type, false, channel.MediaType, userdata.PlaybackPositionTicks); }); }); @@ -123,15 +123,6 @@ deleteTimer(page, currentItem.TimerId); }); - $('#btnRemote', page).on('click', function () { - - RemoteControl.showMenuForItem({ - - item: currentItem, - context: 'livetv' - }); - }); - }).on('pageshow', "#liveTvProgramPage", function () { var page = this; diff --git a/dashboard-ui/scripts/livetvrecording.js b/dashboard-ui/scripts/livetvrecording.js index af5875d4c6..6ecf639520 100644 --- a/dashboard-ui/scripts/livetvrecording.js +++ b/dashboard-ui/scripts/livetvrecording.js @@ -27,7 +27,7 @@ var mediaType = currentItem.MediaType; - LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, mediaType, userdata.PlaybackPositionTicks); + LibraryBrowser.showPlayMenu(this, currentItem.Id, currentItem.Type, false, mediaType, userdata.PlaybackPositionTicks); } function renderRecording(page, item) { @@ -68,7 +68,7 @@ Dashboard.getCurrentUser().done(function (user) { - if (MediaPlayer.canPlay(item, user)) { + if (MediaController.canPlay(item)) { $('#playButtonContainer', page).show(); } else { $('#playButtonContainer', page).hide(); @@ -107,15 +107,6 @@ $('#btnDelete', page).on('click', deleteRecording); $('#btnPlay', page).on('click', play); - $('#btnRemote', page).on('click', function () { - - RemoteControl.showMenuForItem({ - - item: currentItem, - context: 'livetv' - }); - }); - }).on('pagebeforeshow', "#liveTvRecordingPage", function () { var page = this; diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js new file mode 100644 index 0000000000..b97a79b2e1 --- /dev/null +++ b/dashboard-ui/scripts/mediacontroller.js @@ -0,0 +1,145 @@ +(function ($, window) { + + function mediaController() { + + var self = this; + var currentPlayer; + + var players = []; + + self.registerPlayer = function (player) { + + players.push(player); + + if (!currentPlayer) { + currentPlayer = player; + } + }; + + self.play = function (options) { + + if (typeof (options) === 'string') { + options = { ids: [options] }; + } + + currentPlayer.play(options); + }; + + self.shuffle = function (id) { + + currentPlayer.shuffle(id); + }; + + self.instantMix = function (id) { + currentPlayer.instantMix(id); + }; + + self.queue = function (options) { + + if (typeof (options) === 'string') { + options = { ids: [options] }; + } + + currentPlayer.queue(options); + }; + + self.queueNext = function (options) { + + if (typeof (options) === 'string') { + options = { ids: [options] }; + } + + currentPlayer.queueNext(options); + }; + + self.canPlay = function (item) { + + if (item.PlayAccess != 'Full') { + return false; + } + + if (item.LocationType == "Virtual" || item.IsPlaceHolder) { + return false; + } + + if (item.IsFolder || item.Type == "MusicGenre") { + return true; + } + + return currentPlayer.canPlayMediaType(item.MediaType); + }; + + self.canQueueMediaType = function (mediaType) { + + return currentPlayer.canQueueMediaType(mediaType); + }; + + self.isPlaying = function () { + + return currentPlayer.isPlaying(); + }; + + self.getLocalPlayer = function () { + + return currentPlayer.isLocalPlayer ? + + currentPlayer : + + players.filter(function (p) { + return p.isLocalPlayer; + })[0]; + }; + } + + window.MediaController = new mediaController(); + + function onWebSocketMessageReceived() { + + var msg = data; + + var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Play" ? + MediaController.getLocalPlayer() : + null; + + if (msg.MessageType === "Play") { + + if (msg.Data.PlayCommand == "PlayNext") { + localPlayer.queueNext({ ids: msg.Data.ItemIds }); + } + else if (msg.Data.PlayCommand == "PlayLast") { + localPlayer.queue({ ids: msg.Data.ItemIds }); + } + else { + localPlayer.play({ ids: msg.Data.ItemIds, startPositionTicks: msg.Data.StartPositionTicks }); + } + + } + else if (msg.MessageType === "Playstate") { + + if (msg.Data.Command === 'Stop') { + localPlayer.stop(); + } + else if (msg.Data.Command === 'Pause') { + localPlayer.pause(); + } + else if (msg.Data.Command === 'Unpause') { + localPlayer.unpause(); + } + else if (msg.Data.Command === 'Seek') { + localPlayer.seek(msg.Data.SeekPositionTicks); + } + else if (msg.Data.Command === 'NextTrack') { + localPlayer.nextTrack(); + } + else if (msg.Data.Command === 'PreviousTrack') { + localPlayer.previousTrack(); + } + else if (msg.Data.Command === 'Fullscreen') { + localPlayer.remoteFullscreen(); + } + } + } + + $(ApiClient).on("websocketmessage", onWebSocketMessageReceived); + +})(jQuery, window); \ No newline at end of file diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index d5466e6825..804f672599 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -453,8 +453,6 @@ html += ""; } - html += '
Preferences
'; - return html; }; @@ -528,8 +526,6 @@ html += ""; } - html += '
Preferences
'; - return html; }; diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index bfee22ca17..d8f3ae585b 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -13,15 +13,18 @@ var canClientSeek; var currentPlaylistIndex = 0; - self.currentTimeElement; - self.unmuteButton; - self.muteButton; - self.positionSlider; - self.isPositionSliderActive; - self.volumeSlider; - self.startTimeTicksOffset; + self.currentTimeElement = null; + self.unmuteButton = null; + self.muteButton = null; + self.positionSlider = null; + self.isPositionSliderActive = null; + self.volumeSlider = null; + self.startTimeTicksOffset = null; + self.playlist = []; + self.isLocalPlayer = true; + self.updateCanClientSeek = function (elem) { var duration = elem.duration; canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY; @@ -275,7 +278,7 @@ audioBitrate: audioBitrate, videoBitrate: videoBitrate }; - + if (params.videoCodec == 'h264') { params.profile = 'baseline'; params.level = '3'; @@ -284,46 +287,6 @@ return params; }; - self.canPlay = function (item, user) { - - if (item.PlayAccess != 'Full') { - return false; - } - - if (item.LocationType == "Virtual" || item.IsPlaceHolder) { - return false; - } - if (item.Type == "MusicAlbum" || item.Type == "MusicArtist" || item.Type == "MusicGenre") { - return true; - } - - if (item.GameSystem == "Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { - return true; - } - - if (item.GameSystem == "Super Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { - return true; - } - - return self.canPlayMediaType(item.MediaType); - }; - - self.getPlayUrl = function (item) { - - - if (item.GameSystem == "Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { - - return "http://nesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom; - } - - if (item.GameSystem == "Super Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) { - - return "http://snesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom; - } - - return null; - }; - self.canPlayMediaType = function (mediaType) { if (mediaType === "Video") { @@ -337,84 +300,45 @@ return false; }; - self.play = function (items, startPosition) { + self.canQueueMediaType = function (mediaType) { + + return currentItem && currentItem.MediaType == mediaType; + }; + + self.play = function (options) { Dashboard.getCurrentUser().done(function (user) { - var item = items[0]; + if (options.items) { - var videoType = (item.VideoType || "").toLowerCase(); + self.playInternal(options.items[0], options.startPositionTicks, user); - var expirementalText = "This feature is experimental. It may not work at all with some titles. Do you wish to continue?"; + self.playlist = options.items; + currentPlaylistIndex = 0; - if (videoType == "dvd") { + } else { - self.playWithWarning(items, startPosition, user, "dvdstreamconfirmed", "Dvd Folder Streaming", expirementalText); - return; - } - else if (videoType == "bluray") { + self.getItemsForPlayback({ - self.playWithWarning(items, startPosition, user, "bluraystreamconfirmed", "Blu-ray Folder Streaming", expirementalText); - return; - } - else if (videoType == "iso") { + Ids: options.ids.join(',') - var isoType = (item.IsoType || "").toLowerCase(); + }).done(function (result) { - if (isoType == "dvd") { + options.items = result.Items; - self.playWithWarning(items, startPosition, user, "dvdisostreamconfirmed", "Dvd Iso Streaming", expirementalText); - return; - } - else if (isoType == "bluray") { + self.playInternal(options.items[0], options.startPositionTicks, user); - self.playWithWarning(items, startPosition, user, "blurayisostreamconfirmed", "Blu-ray Iso Streaming", expirementalText); - return; - } - } + self.playlist = options.items; + currentPlaylistIndex = 0; - self.playInternal(items[0], startPosition, user); - self.onPlaybackStarted(items); - }); - }; - - self.playWithWarning = function (items, startPosition, user, localStorageKeyName, header, text) { - - // Increment this version when changes are made and we want users to see the prompts again - var warningVersion = "2"; - localStorageKeyName += new Date().getMonth() + warningVersion; - - if (localStorage.getItem(localStorageKeyName) == "1") { - - self.playInternal(items[0], startPosition, user); - - self.onPlaybackStarted(items); - - return; - } - - Dashboard.confirm(text, header, function (result) { - - if (result) { - - localStorage.setItem(localStorageKeyName, "1"); - - self.playInternal(items[0], startPosition, user); - - self.onPlaybackStarted(items); + }); } }); }; - self.onPlaybackStarted = function (items) { - - self.playlist = items; - currentPlaylistIndex = 0; - }; - - self.getBitrateSetting = function() { + self.getBitrateSetting = function () { return parseInt(localStorage.getItem('preferredVideoBitrate') || '') || 1500000; }; @@ -569,163 +493,11 @@ query.Limit = query.Limit || 100; query.Fields = getItemFields; + query.ExcludeLocationTypes = "Virtual"; return ApiClient.getItems(userId, query); }; - self.playById = function (id, startPositionTicks) { - - ApiClient.getItem(Dashboard.getCurrentUserId(), id).done(function (item) { - - if (item.IsFolder) { - - self.getItemsForPlayback({ - - ParentId: id, - Recursive: true, - SortBy: "SortName" - - }).done(function (result) { - - self.play(result.Items, startPositionTicks); - - }); - - } else { - self.play([item], startPositionTicks); - } - - }); - - }; - - self.playInstantMixFromSong = function (id) { - - ApiClient.getInstantMixFromSong(id, { - - UserId: Dashboard.getCurrentUserId(), - Fields: getItemFields, - Limit: 50 - - }).done(function (result) { - - self.play(result.Items); - }); - - }; - - self.playInstantMixFromAlbum = function (id) { - - ApiClient.getInstantMixFromAlbum(id, { - - UserId: Dashboard.getCurrentUserId(), - Fields: getItemFields, - Limit: 50 - - }).done(function (result) { - - self.play(result.Items); - }); - - }; - - self.playInstantMixFromArtist = function (name) { - - ApiClient.getInstantMixFromArtist(name, { - - UserId: Dashboard.getCurrentUserId(), - Fields: getItemFields, - Limit: 50 - - }).done(function (result) { - - self.play(result.Items); - }); - - }; - - self.playInstantMixFromMusicGenre = function (name) { - - ApiClient.getInstantMixFromMusicGenre(name, { - - UserId: Dashboard.getCurrentUserId(), - Fields: getItemFields, - Limit: 50 - - }).done(function (result) { - - self.play(result.Items); - }); - - }; - - self.playArtist = function (artist) { - - self.getItemsForPlayback({ - - Artists: artist, - Recursive: true, - SortBy: "Album,SortName", - IncludeItemTypes: "Audio" - - }).done(function (result) { - - self.play(result.Items); - - }); - - }; - - self.shuffleArtist = function (artist) { - - self.getItemsForPlayback({ - - Artists: artist, - Recursive: true, - SortBy: "Random", - IncludeItemTypes: "Audio" - - }).done(function (result) { - - self.play(result.Items); - - }); - - }; - - self.shuffleMusicGenre = function (genre) { - - self.getItemsForPlayback({ - - Genres: genre, - Recursive: true, - SortBy: "Random", - IncludeItemTypes: "Audio" - - }).done(function (result) { - - self.play(result.Items); - - }); - - }; - - self.shuffleFolder = function (id) { - - self.getItemsForPlayback({ - - ParentId: id, - Recursive: true, - SortBy: "Random" - - }).done(function (result) { - - self.play(result.Items); - - }); - - }; - self.removeFromPlaylist = function (index) { self.playlist.remove(index); @@ -797,51 +569,66 @@ } }; - self.queue = function (id) { + self.queue = function (options) { if (!currentMediaElement) { - self.playById(id); + self.play(options); return; } - ApiClient.getItem(Dashboard.getCurrentUserId(), id).done(function (item) { + Dashboard.getCurrentUser().done(function (user) { - if (item.IsFolder) { + if (options.items) { + + self.queueItems(options.items); + + } else { self.getItemsForPlayback({ - ParentId: id, - Recursive: true, - SortBy: "SortName" + Ids: options.ids.join(',') }).done(function (result) { - self.queueItems(result.Items); + options.items = result.Items; + + self.queueItems(options.items); }); - - } else { - self.queueItems([item]); } }); }; - self.queueArtist = function (artist) { + self.queueNext = function (options) { - self.getItemsForPlayback({ + if (!currentMediaElement) { + self.play(options); + return; + } - Artists: artist, - Recursive: true, - SortBy: "Album,SortName", - IncludeItemTypes: "Audio" + Dashboard.getCurrentUser().done(function (user) { - }).done(function (result) { + if (options.items) { - self.queueItems(result.Items); + self.queueItemsNext(options.items); + + } else { + + self.getItemsForPlayback({ + + Ids: options.ids.join(',') + + }).done(function (result) { + + options.items = result.Items; + + self.queueItemsNext(options.items); + + }); + } }); - }; self.pause = function () { @@ -905,6 +692,108 @@ } }; + self.shuffle = function (id) { + + var userId = Dashboard.getCurrentUserId(); + + ApiClient.getItem(userId, id).done(function (item) { + + var query = { + UserId: userId, + Fields: getItemFields, + Limit: 50, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "Random" + }; + + if (item.IsFolder) { + query.ParentId = id; + + } + else if (item.Type == "MusicArtist") { + + query.MediaTypes = "Audio"; + query.Artists = item.Name; + + } + else if (item.Type == "MusicGenre") { + + query.MediaTypes = "Audio"; + query.Genres = item.Name; + + } else { + return; + } + + self.getItemsForPlayback(query).done(function (result) { + + self.play({ items: result.Items }); + + }); + + }); + + }; + + self.instantMix = function (id) { + + var userId = Dashboard.getCurrentUserId(); + + ApiClient.getItem(userId, id).done(function (item) { + + var promise; + + if (item.Type == "MusicArtist") { + + promise = ApiClient.getInstantMixFromArtist(name, { + UserId: Dashboard.getCurrentUserId(), + Fields: getItemFields, + Limit: 50 + }); + + } + else if (item.Type == "MusicGenre") { + + promise = ApiClient.getInstantMixFromMusicGenre(name, { + UserId: Dashboard.getCurrentUserId(), + Fields: getItemFields, + Limit: 50 + }); + + } + else if (item.Type == "MusicAlbum") { + + promise = ApiClient.getInstantMixFromAlbum(id, { + UserId: Dashboard.getCurrentUserId(), + Fields: getItemFields, + Limit: 50 + }); + + } + else if (item.Type == "Audio") { + + promise = ApiClient.getInstantMixFromSong(id, { + UserId: Dashboard.getCurrentUserId(), + Fields: getItemFields, + Limit: 50 + }); + + } + else { + return; + } + + promise.done(function (result) { + + self.play({ items: result.Items }); + + }); + + }); + + }; + self.stop = function () { var elem = currentMediaElement; @@ -933,14 +822,6 @@ return currentMediaElement; }; - self.showSendMediaMenu = function () { - - RemoteControl.showMenuForItem({ - item: currentItem - }); - - }; - self.bindPositionSlider = function () { self.positionSlider.on('slidestart', function (e) { @@ -1220,4 +1101,7 @@ window.MediaPlayer = new mediaPlayer(); + window.MediaController.registerPlayer(window.MediaPlayer); + + })(document, setTimeout, clearTimeout, screen, localStorage, $, setInterval, window); \ No newline at end of file diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 11fafbeeb6..5169d8ceb6 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -1,570 +1,5 @@ (function (window, document, $) { - function sendPlayFolderCommand(item, sessionId, popup) { - - ApiClient.getItems(Dashboard.getCurrentUserId(), { - - ParentId: item.Id, - Filters: "IsNotFolder", - SortBy: "SortName", - Recursive: true, - Limit: 100 - - }).done(function (result) { - - ApiClient.sendPlayCommand(sessionId, { - - ItemIds: result.Items.map(function (i) { - return i.Id; - }).join(','), - - PlayCommand: $('#fldPlayCommand', popup).val() - }); - - popup.popup("close"); - - }); - - } - - function sendPlayArtistCommand(item, sessionId, popup) { - - ApiClient.getItems(Dashboard.getCurrentUserId(), { - - Artists: item.Name, - SortBy: "SortName", - IncludeItemTypes: "Audio", - Recursive: true, - Limit: 100 - - }).done(function (result) { - - ApiClient.sendPlayCommand(sessionId, { - - ItemIds: result.Items.map(function (i) { - return i.Id; - }).join(','), - - PlayCommand: $('#fldPlayCommand', popup).val() - }); - - popup.popup("close"); - - }); - - } - - function showMenuForItem(options, sessionsPromise) { - - var playFromRendered; - var trailersRendered; - var specialFeaturesRendered; - var themeVideosRendered; - var themeSongsRendered; - - var item = options.item; - - var html = '
'; - - html += 'Close'; - - html += '
'; - html += '
Remote Control
'; - html += '
'; - - html += '
'; - - html += '
'; - 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(); - - $('.remoteControlFlyout').popup("destroy").remove(); - }); - - popup.on('click', '.trSession', function () { - - $('input', this).checked(true); - - - }).on('click', '.trSelectPlayTime', function () { - - $('input', this).checked(true); - - }).on('click', '.trItem', function () { - - $('input', this).checked(true); - - }); - - $('#sendToForm', popup).on('submit', function () { - - var checkboxes = $('.chkClient', popup); - - if (!checkboxes.length) { - $('.remoteControlFlyout').popup("close"); - return false; - } - - checkboxes = $('.chkClient:checked', popup); - - if (!checkboxes.length) { - Dashboard.alert('Please select a device to control.'); - return false; - } - - var sessionIds = []; - - checkboxes.parents('.trSession').each(function () { - - sessionIds.push(this.getAttribute('data-sessionid')); - - }); - - var command = $('#selectCommand', popup).val(); - - var promise; - var showRemoteControlMenuAfterCommand = true; - - if (command == "Play") { - - if (item.IsFolder) { - - sendPlayFolderCommand(item, sessionIds[0], popup); - - return false; - } - if (item.Type == "MusicArtist") { - - sendPlayArtistCommand(item, sessionIds[0], popup); - - return false; - } - - var playCommand = $('#fldPlayCommand', popup).val(); - - if (playCommand == "Resume") { - - promise = ApiClient.sendPlayCommand(sessionIds[0], { - - ItemIds: [item.Id].join(','), - PlayCommand: 'PlayNow', - StartPositionTicks: item.UserData.PlaybackPositionTicks - }); - - } - else if (playCommand == "Browse") { - - promise = ApiClient.sendBrowseCommand(sessionIds[0], { - - ItemId: item.Id, - ItemName: item.Name, - ItemType: item.Type, - Context: options.context - - }); - - showRemoteControlMenuAfterCommand = false; - } - else { - promise = ApiClient.sendPlayCommand(sessionIds[0], { - - ItemIds: [item.Id].join(','), - PlayCommand: playCommand - }); - } - } - else if (command == "PlayFromChapter") { - - var checkedChapter = $('.chkSelectPlayTime:checked', popup); - - var ticks = checkedChapter.length ? checkedChapter.parents('.trSelectPlayTime').attr('data-ticks') : 0; - - promise = ApiClient.sendPlayCommand(sessionIds[0], { - - ItemIds: [item.Id].join(','), - PlayCommand: $('#fldPlayCommand', popup).val(), - StartPositionTicks: ticks - - }); - } - else if (command == "Trailer" || command == "SpecialFeature" || command == "ThemeSong" || command == "ThemeVideo") { - - var id = $('.chkSelectItem:checked', popup).parents('.trItem').attr('data-id'); - - if (!id) { - Dashboard.alert('Please select an item.'); - return false; - } - promise = ApiClient.sendPlayCommand(sessionIds[0], { - - ItemIds: [id].join(','), - PlayCommand: $('#fldPlayCommand', popup).val() - - }); - } - - promise.done(function () { - - popup.popup("close"); - - if (showRemoteControlMenuAfterCommand) { - RemoteControl.showMenu(); - } - }); - - return false; - }); - - var elem = $('.sessionsPopupContent'); - - sessionsPromise.done(function (sessions) { - - var deviceId = ApiClient.deviceId(); - - // don't display the current session - sessions = sessions.filter(function (s) { - return s.DeviceId != deviceId; - }); - - renderSessionsInPlayMenu(sessions, options, elem, popup); - - if (ApiClient.isWebSocketOpen()) { - ApiClient.sendWebSocketMessage("SessionsStart", "1000,1000"); - - $(ApiClient).on("websocketmessage.remotecontrol", function (e, msg) { - - if (msg.MessageType === "Sessions") { - updateSessionsInPlayMenu(msg.Data, elem); - } - }); - - } - - $('#selectCommand', popup).on('change', function () { - - var playFromMenu = $('.playFromMenu', popup).hide(); - var trailersElem = $('.trailers', popup).hide(); - var specialFeaturesElem = $('.specialFeatures', popup).hide(); - var themeSongsElem = $('.themeSongs', popup).hide(); - var themeVideosElem = $('.themeVideos', popup).hide(); - var playButtonContainer = $('#playButtonContainer', popup).hide(); - var queueButtonContainer = $('#queueButtonContainer', popup).hide(); - var resumeButtonContainer = $('#resumeButtonContainer', popup).hide(); - var browseButtonContainer = $('#browseButtonContainer', popup).hide(); - - var value = this.value; - - if (value == "Play") { - - browseButtonContainer.show(); - - if (item.Type != 'Person' && item.Type != 'Genre' && item.Type != 'Studio' && item.Type != 'GameGenre' && item.Type != 'MusicGenre' && item.LocationType != 'Virtual') { - playButtonContainer.show(); - queueButtonContainer.show(); - } - - if (!item.IsFolder && item.UserData && item.UserData.PlaybackPositionTicks) { - resumeButtonContainer.show(); - } - } - else if (value == "Trailer") { - - trailersElem.show(); - playButtonContainer.show(); - queueButtonContainer.show(); - - if (!trailersRendered) { - trailersRendered = true; - - ApiClient.getLocalTrailers(Dashboard.getCurrentUserId(), item.Id).done(function (trailers) { - - renderVideos(trailersElem, trailers, 'Trailers'); - - popup.popup("reposition", { tolerance: 0 }); - }); - } - } - else if (value == "SpecialFeature") { - - specialFeaturesElem.show(); - playButtonContainer.show(); - queueButtonContainer.show(); - - if (!specialFeaturesRendered) { - specialFeaturesRendered = true; - - ApiClient.getSpecialFeatures(Dashboard.getCurrentUserId(), item.Id).done(function (videos) { - - renderVideos(specialFeaturesElem, videos, 'Special Features'); - - popup.popup("reposition", { tolerance: 0 }); - }); - } - } - else if (value == "ThemeSong") { - - themeSongsElem.show(); - playButtonContainer.show(); - queueButtonContainer.show(); - - if (!themeSongsRendered) { - themeSongsRendered = true; - - ApiClient.getThemeSongs(Dashboard.getCurrentUserId(), item.Id).done(function (result) { - - renderVideos(themeSongsElem, result.Items, 'Theme Songs'); - - $('.remoteControlFlyout').popup("reposition", { tolerance: 0 }); - }); - } - } - else if (value == "ThemeVideo") { - - themeVideosElem.show(); - playButtonContainer.show(); - queueButtonContainer.show(); - - if (!themeVideosRendered) { - themeVideosRendered = true; - - ApiClient.getThemeVideos(Dashboard.getCurrentUserId(), item.Id).done(function (result) { - - renderVideos(themeVideosElem, result.Items, 'Theme Videos'); - - popup.popup("reposition", { tolerance: 0 }); - }); - } - } - - }).trigger('change'); - }); - } - - function renderSessionsInPlayMenu(sessions, options, elem, popup) { - - if (!sessions.length) { - elem.html('

There are currently no available media browser sessions to control.

'); - $('.remoteControlFlyout').popup("reposition", {}); - return; - } - - var item = options.item; - - var html = ''; - - html += '
'; - html += ''; - html += '
'; - - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - - html += '

Select Device

'; - - html += ''; - - html += ''; - html += ''; - html += ''; - html += ''; - - html += ''; - - for (var i = 0, length = sessions.length; i < length; i++) { - - var session = sessions[i]; - - html += ''; - - html += ''; - html += ''; - - html += ''; - } - - html += ''; - - html += '
Device
' + session.DeviceName; - - if (session.UserName) { - html += ' - ' + session.UserName; - } - html += '
'; - - html += ''; - - elem.html(html).trigger('create'); - - $('.tdSelectSession', elem).html(''); - - $('.chkClient:first', elem).checked(true); - } - - function getSessionNowPlayingTime(session) { - - var html = ''; - - if (session.NowPlayingItem) { - - html += Dashboard.getDisplayTime(session.NowPlayingPositionTicks || 0); - - if (session.NowPlayingItem.RunTimeTicks) { - - html += " / "; - html += Dashboard.getDisplayTime(session.NowPlayingItem.RunTimeTicks); - } - } - - return html; - } - - function updateSessionsInPlayMenu(sessions, elem) { - - for (var i = 0, length = sessions.length; i < length; i++) { - - var session = sessions[i]; - - var sessionElem = $('.trSession[data-sessionid=' + session.Id + ']', elem); - - $('.tdUserName', sessionElem).html(session.UserName || ''); - $('.tdNowPlayingTime', sessionElem).html(getSessionNowPlayingTime(session)); - $('.tdNowPlayingName', sessionElem).html(session.NowPlayingItem ? session.NowPlayingItem.Name : ''); - - } - - } - - function renderVideos(elem, videos, header) { - - var html = ''; - - html += '

' + header + '

'; - - html += '
'; - html += ''; - - html += ''; - - for (var i = 0, length = videos.length; i < length; i++) { - - var video = videos[i]; - - html += ''; - - - html += ''; - - html += ''; - - html += ''; - - html += ''; - } - - html += ''; - - html += '
'; - - var imgUrl; - - if (video.ImageTags && video.ImageTags.Primary) { - - imgUrl = ApiClient.getImageUrl(video.Id, { - maxheight: 80, - tag: video.ImageTags.Primary, - type: "Primary" - }); - - html += ''; - } - - html += '' + video.Name; - - if (video.RunTimeTicks) { - html += '
' + Dashboard.getDisplayTime(video.RunTimeTicks); - } - - html += '
'; - html += '
'; - - elem.html(html); - - $('.tdSelectItem', elem).html(''); - - $('.chkSelectItem:first', elem).checked(true); - } - function showMenu(sessions, options) { var html = '
'; @@ -965,10 +400,6 @@ ControllableByUserId: Dashboard.getCurrentUserId() }; - self.showMenuForItem = function (options) { - showMenuForItem(options, ApiClient.getSessions(sessionQuery)); - }; - self.showMenu = function (options) { ApiClient.getSessions(sessionQuery).done(function (sessions) { diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js index 09fe482556..00948fb807 100644 --- a/dashboard-ui/scripts/site.js +++ b/dashboard-ui/scripts/site.js @@ -882,51 +882,6 @@ var Dashboard = { Dashboard.onBrowseCommand(msg.Data); } - else if (msg.MessageType === "Play") { - - MediaPlayer.getItemsForPlayback({ - - Ids: msg.Data.ItemIds.join(',') - - }).done(function (result) { - - if (msg.Data.PlayCommand == "PlayNext") { - MediaPlayer.queueItemsNext(result.Items); - } - else if (msg.Data.PlayCommand == "PlayLast") { - MediaPlayer.queueItems(result.Items); - } - else { - MediaPlayer.play(result.Items, msg.Data.StartPositionTicks); - } - - }); - - } - else if (msg.MessageType === "Playstate") { - - if (msg.Data.Command === 'Stop') { - MediaPlayer.stop(); - } - else if (msg.Data.Command === 'Pause') { - MediaPlayer.pause(); - } - else if (msg.Data.Command === 'Unpause') { - MediaPlayer.unpause(); - } - else if (msg.Data.Command === 'Seek') { - MediaPlayer.seek(msg.Data.SeekPositionTicks); - } - else if (msg.Data.Command === 'NextTrack') { - MediaPlayer.nextTrack(); - } - else if (msg.Data.Command === 'PreviousTrack') { - MediaPlayer.previousTrack(); - } - else if (msg.Data.Command === 'Fullscreen') { - MediaPlayer.remoteFullscreen(); - } - } else if (msg.MessageType === "SystemCommand") { if (msg.Data === 'GoHome') { @@ -1365,8 +1320,6 @@ $(function () { videoPlayerHtml += ''; videoPlayerHtml += '
'; - videoPlayerHtml += ''; - videoPlayerHtml += ''; videoPlayerHtml += '
'; // videoControls @@ -1422,8 +1375,6 @@ $(function () { footerHtml += ''; - footerHtml += ''; - footerHtml += ''; footerHtml += '
';