From f560b2983750a617c12bdbcd457b461981e17a11 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 28 Mar 2014 22:28:02 -0400 Subject: [PATCH 1/7] implement direct play profile edit --- dashboard-ui/dlnaprofile.html | 49 +++++++++++++++ dashboard-ui/scripts/dlnaprofile.js | 95 +++++++++++++++++++++++++---- 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/dashboard-ui/dlnaprofile.html b/dashboard-ui/dlnaprofile.html index 3936921353..a8eeb735d4 100644 --- a/dashboard-ui/dlnaprofile.html +++ b/dashboard-ui/dlnaprofile.html @@ -155,8 +155,57 @@ + diff --git a/dashboard-ui/scripts/dlnaprofile.js b/dashboard-ui/scripts/dlnaprofile.js index 8ad0194575..e6280d63d0 100644 --- a/dashboard-ui/scripts/dlnaprofile.js +++ b/dashboard-ui/scripts/dlnaprofile.js @@ -2,6 +2,9 @@ var currentProfile; + var currentSubProfile; + var isSubProfileNew; + function loadProfile(page) { Dashboard.showLoadingMsg(); @@ -60,6 +63,11 @@ profile.CodecProfiles = (profile.CodecProfiles || []); profile.MediaProfiles = (profile.MediaProfiles || []); + renderSubProfiles(page, profile); + } + + function renderSubProfiles(page, profile) { + renderDirectPlayProfiles(page, profile.DirectPlayProfiles); renderTranscodingProfiles(page, profile.TranscodingProfiles); renderContainerProfiles(page, profile.ContainerProfiles); @@ -67,6 +75,38 @@ renderMediaProfiles(page, profile.MediaProfiles); } + function editDirectPlayProfile(page, directPlayProfile, isNew) { + + currentSubProfile = directPlayProfile; + isSubProfileNew = isNew; + + var popup = $('#popupEditDirectPlayProfile', page).popup('open'); + + $('#selectDirectPlayProfileType', popup).val(directPlayProfile.Type || 'Video').selectmenu('refresh').trigger('change'); + $('#txtDirectPlayContainer', popup).val(directPlayProfile.Container || ''); + $('#txtDirectPlayAudioCodec', popup).val(directPlayProfile.AudioCodec || ''); + $('#txtDirectPlayVideoCodec', popup).val(directPlayProfile.VideoCodec || ''); + } + + function saveDirectPlayProfile(page) { + + currentSubProfile.Type = $('#selectDirectPlayProfileType', page).val(); + 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'); + } + function renderDirectPlayProfiles(page, profiles) { var html = ''; @@ -86,7 +126,7 @@ } html += '
  • '; - html += ''; + html += ''; html += '

    Container: ' + (profile.Container || 'All') + '

    '; @@ -101,7 +141,7 @@ html += '
    '; - html += 'Delete'; + html += 'Delete'; html += '
  • '; } @@ -112,9 +152,16 @@ $('.btnDeleteProfile', elem).on('click', function () { - var index = this.getAttribute('data-profileIndex'); + var index = this.getAttribute('data-profileindex'); deleteDirectPlayProfile(page, index); }); + + $('.lnkEditSubProfile', elem).on('click', function () { + + var index = parseInt(this.getAttribute('data-profileindex')); + + editDirectPlayProfile(page, currentProfile.DirectPlayProfiles[index]); + }); } function deleteDirectPlayProfile(page, index) { @@ -160,7 +207,7 @@ html += ''; - html += 'Delete'; + html += 'Delete'; html += ''; } @@ -171,7 +218,7 @@ $('.btnDeleteProfile', elem).on('click', function () { - var index = this.getAttribute('data-profileIndex'); + var index = this.getAttribute('data-profileindex'); deleteTranscodingProfile(page, index); }); } @@ -218,7 +265,7 @@ html += ''; - html += 'Delete'; + html += 'Delete'; html += ''; } @@ -229,7 +276,7 @@ $('.btnDeleteProfile', elem).on('click', function () { - var index = this.getAttribute('data-profileIndex'); + var index = this.getAttribute('data-profileindex'); deleteContainerProfile(page, index); }); } @@ -278,7 +325,7 @@ html += ''; - html += 'Delete'; + html += 'Delete'; html += ''; } @@ -289,7 +336,7 @@ $('.btnDeleteProfile', elem).on('click', function () { - var index = this.getAttribute('data-profileIndex'); + var index = this.getAttribute('data-profileindex'); deleteCodecProfile(page, index); }); } @@ -345,7 +392,7 @@ html += ''; - html += 'Delete'; + html += 'Delete'; html += ''; } @@ -356,7 +403,7 @@ $('.btnDeleteProfile', elem).on('click', function () { - var index = this.getAttribute('data-profileIndex'); + var index = this.getAttribute('data-profileindex'); deleteMediaProfile(page, index); }); } @@ -440,6 +487,22 @@ }); + $('#selectDirectPlayProfileType', page).on('change', function () { + + if (this.value == 'Video') { + $('#fldDirectPlayVideoCodec', page).show(); + } else { + $('#fldDirectPlayVideoCodec', page).hide(); + } + + if (this.value == 'Photo') { + $('#fldDirectPlayAudioCodec', page).hide(); + } else { + $('#fldDirectPlayAudioCodec', page).show(); + } + + }); + }).on('pageshow', "#dlnaProfilePage", function () { var page = this; @@ -466,6 +529,16 @@ saveProfile(page, currentProfile); + return false; + }, + + onDirectPlayFormSubmit: function () { + + var form = this; + var page = $(form).parents('.page'); + + saveDirectPlayProfile(page); + return false; } }; From 8842110e5464f0d2d1fccc92adc52b45ae8c5e6a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 28 Mar 2014 22:38:22 -0400 Subject: [PATCH 2/7] implement profile create/edit --- dashboard-ui/scripts/dlnaprofile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashboard-ui/scripts/dlnaprofile.js b/dashboard-ui/scripts/dlnaprofile.js index e6280d63d0..9c1897a9f3 100644 --- a/dashboard-ui/scripts/dlnaprofile.js +++ b/dashboard-ui/scripts/dlnaprofile.js @@ -432,7 +432,7 @@ }).done(function () { - Dashboard.alert('Settings saved.'); + Dashboard.navigate('dlnaprofiles.html'); }); } else { From 355c3dcb42a84ecd2673bf131905798d0035d950 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Mar 2014 11:40:32 -0400 Subject: [PATCH 3/7] stub out web client media controller --- dashboard-ui/css/mediaplayer-video.css | 6 +- dashboard-ui/css/mediaplayer.css | 2 +- dashboard-ui/dlnaprofile.html | 6 +- dashboard-ui/itembynamedetails.html | 3 - dashboard-ui/itemdetails.html | 3 - dashboard-ui/livetvchannel.html | 3 - dashboard-ui/livetvprogram.html | 3 - dashboard-ui/livetvrecording.html | 3 - dashboard-ui/scripts/dlnaprofile.js | 21 +- dashboard-ui/scripts/itembynamedetailpage.js | 9 +- dashboard-ui/scripts/itemdetailpage.js | 71 +-- dashboard-ui/scripts/librarybrowser.js | 42 +- dashboard-ui/scripts/librarylist.js | 28 +- dashboard-ui/scripts/livetvchannel.js | 9 +- dashboard-ui/scripts/livetvprogram.js | 11 +- dashboard-ui/scripts/livetvrecording.js | 13 +- dashboard-ui/scripts/mediacontroller.js | 145 +++++ dashboard-ui/scripts/mediaplayer-video.js | 4 - dashboard-ui/scripts/mediaplayer.js | 460 ++++++--------- dashboard-ui/scripts/remotecontrol.js | 569 ------------------- dashboard-ui/scripts/site.js | 49 -- 21 files changed, 399 insertions(+), 1061 deletions(-) create mode 100644 dashboard-ui/scripts/mediacontroller.js 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 += '
      '; html += '
    • Play Menu
    • '; - if (itemType == "MusicArtist") { - html += '
    • Play
    • '; - } else if (itemType != "MusicGenre") { - html += '
    • Play
    • '; + html += '
    • Play
    • '; + + if (itemType == "Audio" || itemType == "MusicAlbum" || itemType == "MusicArtist" || itemType == "MusicGenre") { + html += '
    • Instant Mix
    • '; } - if (itemType == "Audio") { - html += '
    • Instant Mix
    • '; - } - else if (itemType == "MusicAlbum") { - html += '
    • Instant Mix
    • '; - html += '
    • Shuffle
    • '; - } - else if (itemType == "MusicArtist") { - html += '
    • Instant Mix
    • '; - html += '
    • Shuffle
    • '; - } - else if (itemType == "MusicGenre") { - html += '
    • Instant Mix
    • '; - html += '
    • Shuffle
    • '; + if (isFolder || itemType == "MusicArtist" || itemType == "MusicGenre") { + html += '
    • Shuffle
    • '; } if (resumePositionTicks) { - html += '
    • Resume
    • '; + html += '
    • Resume
    • '; } - if (isPlaying) { - if (itemType == "MusicArtist") { - html += '
    • Queue
    • '; - } else if (itemType != "MusicGenre") { - html += '
    • Queue
    • '; - } + if (MediaController.canQueueMediaType(mediaType)) { + html += '
    • Queue
    • '; } 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 += '
    '; From 813826b03b8c3dc6adc9e4ceef6ba6c6b9b29406 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Mar 2014 12:58:49 -0400 Subject: [PATCH 4/7] stub out remote player --- dashboard-ui/css/librarybrowser.css | 4 +- dashboard-ui/scripts/librarymenu.js | 22 +++- dashboard-ui/scripts/mediacontroller.js | 145 ++++++++++++++++++++++-- dashboard-ui/scripts/mediaplayer.js | 18 +++ dashboard-ui/scripts/remotecontrol.js | 75 ++++++++++++ 5 files changed, 252 insertions(+), 12 deletions(-) diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 1ebe93d098..cef8cb3881 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -676,14 +676,14 @@ a.itemTag:hover { } } -@media all and (min-width: 800px) { +@media all and (min-width: 880px) { .libraryMenuButton { display: none; } } -@media all and (max-width: 800px) { +@media all and (max-width: 880px) { .desktopHomeLink { display: none; diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js index 98e7c2db12..2b905c9779 100644 --- a/dashboard-ui/scripts/librarymenu.js +++ b/dashboard-ui/scripts/librarymenu.js @@ -24,7 +24,7 @@ html += '
    '; - html += ''; + html += ''; html += ''; @@ -210,6 +210,7 @@ }); }); } + }).on('pageshow', ".libraryPage", function () { var page = this; @@ -224,4 +225,23 @@ } }); + $(function() { + + $(MediaController).on('playerchange', function () { + + var info = MediaController.getPlayerInfo(); + + if (info.isLocalPlayer) { + + $('.btnCast').addClass('btnDefaultCast').removeClass('btnActiveCast'); + + } else { + + $('.btnCast').removeClass('btnDefaultCast').addClass('btnActiveCast'); + } + }); + + }); + + })(window, document, jQuery); \ No newline at end of file diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index b97a79b2e1..6943a5f85d 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -4,16 +4,74 @@ var self = this; var currentPlayer; + var currentTargetInfo; var players = []; self.registerPlayer = function (player) { players.push(player); + }; - if (!currentPlayer) { - currentPlayer = player; + self.getPlayerInfo = function () { + + return { + + name: currentPlayer.name, + isLocalPlayer: currentPlayer.isLocalPlayer, + targetInfo: currentTargetInfo + }; + }; + + self.setActivePlayer = function (player, targetInfo) { + + if (typeof (player) === 'string') { + player = players.filter(function (p) { + return p.name == player; + })[0]; } + + if (!player) { + throw new Error('null player'); + } + + if (!targetInfo) { + throw new Error('null targetInfo'); + } + + currentPlayer = player; + currentTargetInfo = targetInfo; + + $(self).trigger('playerchange'); + }; + + self.getTargets = function () { + + var deferred = $.Deferred(); + + var promises = players.map(function (p) { + return p.getTargets(); + }); + + $.when.apply($, promises).done(function () { + + var targets = []; + + for (var i = 0; i < arguments.length; i++) { + + var subTargets = arguments[i]; + + for (var j = 0; j < subTargets.length; j++) { + + targets.push(subTargets[j]); + } + + } + + deferred.resolveWith(null, [targets]); + }); + + return deferred.promise(); }; self.play = function (options) { @@ -26,7 +84,7 @@ }; self.shuffle = function (id) { - + currentPlayer.shuffle(id); }; @@ -80,11 +138,11 @@ }; self.getLocalPlayer = function () { - + return currentPlayer.isLocalPlayer ? - + currentPlayer : - + players.filter(function (p) { return p.isLocalPlayer; })[0]; @@ -93,9 +151,7 @@ window.MediaController = new mediaController(); - function onWebSocketMessageReceived() { - - var msg = data; + function onWebSocketMessageReceived(msg) { var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Play" ? MediaController.getLocalPlayer() : @@ -142,4 +198,75 @@ $(ApiClient).on("websocketmessage", onWebSocketMessageReceived); + function getTargetsHtml(targets) { + + var playerInfo = MediaController.getPlayerInfo(); + + var html = ''; + html += '
    '; + html += 'Select Player:'; + + for (var i = 0, length = targets.length; i < length; i++) { + + var target = targets[i]; + + var id = 'radioPlayerTarget' + i; + + var isChecked = target.id == playerInfo.targetInfo.id; + var checkedHtml = isChecked ? ' checked="checked"' : ''; + + html += ''; + html += ''; + } + + html += '
    '; + return html; + } + + function showPlayerSelection() { + + var promise = MediaController.getTargets(); + + var html = '
    '; + + html += '
    '; + + html += '
    '; + + $(document.body).append(html); + + var elem = $('#playerFlyout').panel({}).trigger('create').panel("open").on("panelafterclose", function () { + + $(this).off("panelafterclose").remove(); + }); + + promise.done(function (targets) { + + $('.players', elem).html(getTargetsHtml(targets)).trigger('create'); + + $('.radioSelectPlayerTarget', elem).on('change', function () { + + var playerName = this.getAttribute('data-playername'); + var targetId = this.getAttribute('data-targetid'); + var targetName = this.getAttribute('data-targetname'); + + MediaController.setActivePlayer(playerName, { + id: targetId, + name: targetName + + }); + }); + }); + } + + $(document).on('headercreated', ".libraryPage", function () { + + var page = this; + + $('.btnCast', page).on('click', function () { + + showPlayerSelection(); + }); + }); + })(jQuery, window); \ No newline at end of file diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index d8f3ae585b..818bcff687 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -24,6 +24,18 @@ self.playlist = []; self.isLocalPlayer = true; + self.name = 'Html5 Player'; + + self.getTargets = function () { + + var targets = [{ + name: 'My Browser', + id: self.name, + playerName: self.name + }]; + + return targets; + }; self.updateCanClientSeek = function (elem) { var duration = elem.duration; @@ -1102,6 +1114,12 @@ window.MediaPlayer = new mediaPlayer(); window.MediaController.registerPlayer(window.MediaPlayer); + window.MediaController.setActivePlayer(window.MediaPlayer, { + + id: window.MediaPlayer.name, + name: window.MediaPlayer.name + + }); })(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 5169d8ceb6..0d133af075 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -411,4 +411,79 @@ window.RemoteControl = new remoteControl(); + function remoteControlPlayer() { + + var self = this; + + self.name = 'Remote Control'; + + self.play = function (options) { + + }; + + self.shuffle = function (id) { + + }; + + self.instantMix = function (id) { + + }; + + self.queue = function (options) { + + }; + + self.queueNext = function (options) { + + }; + + self.isPlaying = function () { + + }; + + self.canPlayMediaType = function (mediaType) { + + return false; + }; + + self.canQueueMediaType = function (mediaType) { + + return false; + }; + + self.getTargets = function () { + + var deferred = $.Deferred(); + + ApiClient.getSessions({ + + controllableByUserId: Dashboard.getCurrentUserId() + + }).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 + }; + }); + + deferred.resolveWith(null, [targets]); + + }).fail(function() { + + deferred.reject(); + }); + + return deferred.promise(); + }; + } + + MediaController.registerPlayer(new remoteControlPlayer()); + })(window, document, jQuery); \ No newline at end of file From 92050a79b1c54044c3bc73f7320fddec4dbd5ddf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Mar 2014 14:20:42 -0400 Subject: [PATCH 5/7] add shuffle and instant mix commands --- dashboard-ui/scripts/librarybrowser.js | 4 +- dashboard-ui/scripts/librarymenu.js | 28 ++++++++------ dashboard-ui/scripts/mediacontroller.js | 29 ++++++++------ dashboard-ui/scripts/mediaplayer.js | 25 ++---------- dashboard-ui/scripts/remotecontrol.js | 51 +++++++++++++++++-------- 5 files changed, 74 insertions(+), 63 deletions(-) diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index f4dd3911bd..9a29a6507a 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -289,9 +289,7 @@ showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks) { - var isPlaying = MediaPlayer.isPlaying(); - - if (!isPlaying && !resumePositionTicks && mediaType != "Audio" && !isFolder) { + if (!resumePositionTicks && mediaType != "Audio" && !isFolder) { MediaController.play(itemId); return; } diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js index 2b905c9779..314107964c 100644 --- a/dashboard-ui/scripts/librarymenu.js +++ b/dashboard-ui/scripts/librarymenu.js @@ -174,6 +174,20 @@ window.LibraryMenu = { showLibraryMenu: showLibraryMenu }; + + function updateCastIcon() { + + var info = MediaController.getPlayerInfo(); + + if (info.isLocalPlayer) { + + $('.btnCast').addClass('btnDefaultCast').removeClass('btnActiveCast'); + + } else { + + $('.btnCast').removeClass('btnDefaultCast').addClass('btnActiveCast'); + } + } $(document).on('pageinit', ".libraryPage", function () { @@ -211,6 +225,8 @@ }); } + updateCastIcon(); + }).on('pageshow', ".libraryPage", function () { var page = this; @@ -228,17 +244,7 @@ $(function() { $(MediaController).on('playerchange', function () { - - var info = MediaController.getPlayerInfo(); - - if (info.isLocalPlayer) { - - $('.btnCast').addClass('btnDefaultCast').removeClass('btnActiveCast'); - - } else { - - $('.btnCast').removeClass('btnDefaultCast').addClass('btnActiveCast'); - } + updateCastIcon(); }); }); diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 6943a5f85d..8f9f9c4892 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -19,7 +19,9 @@ name: currentPlayer.name, isLocalPlayer: currentPlayer.isLocalPlayer, - targetInfo: currentTargetInfo + id: currentTargetInfo.id, + deviceName: currentTargetInfo.deviceName, + playableMediaTypes: currentTargetInfo.playableMediaTypes }; }; @@ -124,7 +126,7 @@ return true; } - return currentPlayer.canPlayMediaType(item.MediaType); + return self.getPlayerInfo().playableMediaTypes.indexOf(item.MediaType) != -1; }; self.canQueueMediaType = function (mediaType) { @@ -132,11 +134,6 @@ return currentPlayer.canQueueMediaType(mediaType); }; - self.isPlaying = function () { - - return currentPlayer.isPlaying(); - }; - self.getLocalPlayer = function () { return currentPlayer.isLocalPlayer ? @@ -151,7 +148,7 @@ window.MediaController = new mediaController(); - function onWebSocketMessageReceived(msg) { + function onWebSocketMessageReceived(e, msg) { var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Play" ? MediaController.getLocalPlayer() : @@ -212,11 +209,17 @@ var id = 'radioPlayerTarget' + i; - var isChecked = target.id == playerInfo.targetInfo.id; + var isChecked = target.id == playerInfo.id; var checkedHtml = isChecked ? ' checked="checked"' : ''; - html += ''; - html += ''; + html += ''; + html += ''; } html += ''; @@ -249,10 +252,12 @@ var playerName = this.getAttribute('data-playername'); var targetId = this.getAttribute('data-targetid'); var targetName = this.getAttribute('data-targetname'); + var playableMediaTypes = this.getAttribute('data-mediatypes').split(','); MediaController.setActivePlayer(playerName, { id: targetId, - name: targetName + name: targetName, + playableMediaTypes: playableMediaTypes }); }); diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 818bcff687..6f9ffba5bc 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -30,8 +30,9 @@ var targets = [{ name: 'My Browser', - id: self.name, - playerName: self.name + id: ApiClient.deviceId(), + playerName: self.name, + playableMediaTypes: ['Audio', 'Video'] }]; return targets; @@ -299,19 +300,6 @@ return params; }; - self.canPlayMediaType = function (mediaType) { - - if (mediaType === "Video") { - return true; - } - - if (mediaType === "Audio") { - return true; - } - - return false; - }; - self.canQueueMediaType = function (mediaType) { return currentItem && currentItem.MediaType == mediaType; @@ -1114,12 +1102,7 @@ window.MediaPlayer = new mediaPlayer(); window.MediaController.registerPlayer(window.MediaPlayer); - window.MediaController.setActivePlayer(window.MediaPlayer, { - - id: window.MediaPlayer.name, - name: window.MediaPlayer.name - - }); + window.MediaController.setActivePlayer(window.MediaPlayer, window.MediaPlayer.getTargets()[0]); })(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 0d133af075..5458cd3a1f 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -411,6 +411,27 @@ 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 remoteControlPlayer() { var self = this; @@ -419,36 +440,32 @@ 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) { - }; - - self.isPlaying = function () { - - }; - - self.canPlayMediaType = function (mediaType) { - - return false; + sendPlayCommand(options, 'PlayLast'); }; self.canQueueMediaType = function (mediaType) { - return false; + return mediaType == 'Audio' || mediaType == 'Video'; }; self.getTargets = function () { @@ -460,23 +477,25 @@ controllableByUserId: Dashboard.getCurrentUserId() }).done(function (sessions) { - - var targets = sessions.filter(function(s) { + + var targets = sessions.filter(function (s) { return s.DeviceId != ApiClient.deviceId(); - }).map(function(s) { + }).map(function (s) { return { name: s.DeviceName, id: s.Id, - playerName: self.name + playerName: self.name, + appName: s.Client, + playableMediaTypes: s.PlayableMediaTypes }; }); deferred.resolveWith(null, [targets]); - }).fail(function() { - + }).fail(function () { + deferred.reject(); }); From ea0eb5c20759ed8c0ddd98092562e5774284bc32 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Mar 2014 15:02:43 -0400 Subject: [PATCH 6/7] support folder playback --- dashboard-ui/scripts/mediacontroller.js | 2 +- dashboard-ui/scripts/mediaplayer.js | 80 +++++++++++++++++++++---- dashboard-ui/scripts/remotecontrol.js | 9 +-- 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/dashboard-ui/scripts/mediacontroller.js b/dashboard-ui/scripts/mediacontroller.js index 8f9f9c4892..fc69934b96 100644 --- a/dashboard-ui/scripts/mediacontroller.js +++ b/dashboard-ui/scripts/mediacontroller.js @@ -150,7 +150,7 @@ function onWebSocketMessageReceived(e, msg) { - var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Play" ? + var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Playstate" ? MediaController.getLocalPlayer() : null; diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 6f9ffba5bc..d5c39289d9 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -305,16 +305,70 @@ return currentItem && currentItem.MediaType == mediaType; }; + function translateItemsForPlayback(items) { + + var deferred = $.Deferred(); + + var firstItem = items[0]; + var promise; + + if (firstItem.IsFolder) { + + promise = self.getItemsForPlayback({ + ParentId: firstItem.Id, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "SortName", + MediaTypes: "Audio,Video" + }); + } + else if (firstItem.Type == "MusicArtist") { + + promise = self.getItemsForPlayback({ + Artists: firstItem.Name, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "SortName", + MediaTypes: "Audio" + }); + + } + else if (firstItem.Type == "MusicGenre") { + + promise = self.getItemsForPlayback({ + Genres: firstItem.Name, + Filters: "IsNotFolder", + Recursive: true, + SortBy: "SortName", + MediaTypes: "Audio" + }); + } + + if (promise) { + promise.done(function (result) { + + deferred.resolveWith(null, [result.Items]); + }); + } else { + deferred.resolveWith(null, [items]); + } + + return deferred.promise(); + } + self.play = function (options) { Dashboard.getCurrentUser().done(function (user) { if (options.items) { - self.playInternal(options.items[0], options.startPositionTicks, user); + translateItemsForPlayback(options.items).done(function (items) { - self.playlist = options.items; - currentPlaylistIndex = 0; + self.playInternal(items[0], options.startPositionTicks, user); + + self.playlist = items; + currentPlaylistIndex = 0; + }); } else { @@ -324,12 +378,13 @@ }).done(function (result) { - options.items = result.Items; + translateItemsForPlayback(result.Items).done(function (items) { - self.playInternal(options.items[0], options.startPositionTicks, user); + self.playInternal(items[0], options.startPositionTicks, user); - self.playlist = options.items; - currentPlaylistIndex = 0; + self.playlist = items; + currentPlaylistIndex = 0; + }); }); } @@ -580,7 +635,10 @@ if (options.items) { - self.queueItems(options.items); + translateItemsForPlayback(options.items).done(function (items) { + + self.queueItems(items); + }); } else { @@ -590,13 +648,13 @@ }).done(function (result) { - options.items = result.Items; + translateItemsForPlayback(result.Items).done(function (items) { - self.queueItems(options.items); + self.queueItems(items); + }); }); } - }); }; diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js index 5458cd3a1f..7318926d99 100644 --- a/dashboard-ui/scripts/remotecontrol.js +++ b/dashboard-ui/scripts/remotecontrol.js @@ -472,11 +472,12 @@ var deferred = $.Deferred(); - ApiClient.getSessions({ + var sessionQuery = { + SupportsRemoteControl: true, + ControllableByUserId: Dashboard.getCurrentUserId() + }; - controllableByUserId: Dashboard.getCurrentUserId() - - }).done(function (sessions) { + ApiClient.getSessions(sessionQuery).done(function (sessions) { var targets = sessions.filter(function (s) { From 121107918dce3badc0cb07576a73e740ef94689a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Mar 2014 15:23:47 -0400 Subject: [PATCH 7/7] re-enable chromecast, although it's not doing anything yet --- dashboard-ui/scripts/chromecast.js | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/dashboard-ui/scripts/chromecast.js b/dashboard-ui/scripts/chromecast.js index f9b201b3ee..c72929ae1a 100644 --- a/dashboard-ui/scripts/chromecast.js +++ b/dashboard-ui/scripts/chromecast.js @@ -118,8 +118,7 @@ * Generic error callback function */ CastPlayer.prototype.onError = function () { - console.log("error"); - $('.btnCast').hide(); + console.log("chromecast error"); }; /** @@ -147,13 +146,11 @@ */ CastPlayer.prototype.receiverListener = function (e) { if (e === 'available') { - console.log("receiver found"); - $('.btnCast').show(); + console.log("chromecast receiver found"); this.hasReceivers = true; } else { - console.log("receiver list empty"); - $('.btnCast').hide(); + console.log("chromecast receiver list empty"); this.hasReceivers = false; } }; @@ -686,7 +683,7 @@ } else { } - $('.btnCast').attr('title', this.castPlayerState + " on " + this.session.receiver.friendlyName); + // this.session.receiver.friendlyName }; /** @@ -695,19 +692,15 @@ CastPlayer.prototype.updateMediaControlUI = function () { if (!chrome || !chrome.cast) { - $('.btnCast').hide(); return; } if (this.hasReceivers) { - $('.btnCast').show(); } if (this.deviceState == DEVICE_STATE.ACTIVE) { - $('.btnCast').removeClass('btnDefaultCast').addClass('btnActiveCast'); var playerState = this.castPlayerState; } else { - $('.btnCast').removeClass('btnActiveCast').addClass('btnDefaultCast'); var playerState = this.localPlayerState; } @@ -739,15 +732,6 @@ castPlayer.updateMediaControlUI(); - $('.btnCast', page).on('click', function () { - - if (castPlayer.deviceState == DEVICE_STATE.ACTIVE) { - castPlayer.stopApp(); - } else { - castPlayer.launchApp(); - } - }); - }); })(window, window.chrome, console); \ No newline at end of file