1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Tim Hobbs 2014-03-30 01:29:17 -07:00
commit e9b554b932
24 changed files with 848 additions and 1094 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -135,7 +135,7 @@ input[type="range"]::-ms-fill-upper {
}
@media all and (max-width: 600px) {
.chaptersButton, .audioTracksButton, .sendMediaButton {
.chaptersButton, .audioTracksButton {
display: none!important;
}

View file

@ -120,11 +120,13 @@
</div>
<div class="profileTab tabDirectPlayProfiles">
<p>Add direct play profiles to indicate what formats the device can handle natively.</p>
<p>Add direct play profiles to indicate which formats the device can handle natively.</p>
<button class="btnAddDirectPlayProfile" type="button" data-mini="true" data-icon="plus">New</button>
<br />
<div class="directPlayProfiles"></div>
</div>
<div class="profileTab tabTranscodingProfiles">
<p>Add transcoding profiles to indicate what formats should be used when transcoding is required.</p>
<p>Add transcoding profiles to indicate which formats should be used when transcoding is required.</p>
<div class="transcodingProfiles"></div>
</div>
<div class="profileTab tabContainerProfiles">
@ -155,8 +157,57 @@
</div>
</div>
<div data-role="popup" data-transition="slidefade" id="popupEditDirectPlayProfile" class="popup">
<div class="ui-bar-a" style="text-align: center; padding: 0 20px;">
<h3>Direct Play Profile</h3>
</div>
<div data-role="content">
<form class="editDirectPlayProfileForm">
<div style="margin: 1em 0;">
<label for="selectDirectPlayProfileType">Type:</label>
<select id="selectDirectPlayProfileType" data-mini="true">
<option value="Audio">Audio</option>
<option value="Photo">Photo</option>
<option value="Video">Video</option>
</select>
</div>
<div style="margin: 1em 0;">
<label for="txtDirectPlayContainer">Containers:</label>
<input type="text" id="txtDirectPlayContainer" data-mini="true" />
<div>Separated by comma. This can be left empty to apply to all containers</div>
</div>
<div id="fldDirectPlayVideoCodec" style="margin: 1em 0;">
<label for="txtDirectPlayVideoCodec">Video codecs:</label>
<input type="text" id="txtDirectPlayVideoCodec" data-mini="true" />
<div>Separated by comma. This can be left empty to apply to all containers</div>
</div>
<div id="fldDirectPlayAudioCodec" style="margin: 1em 0 2em;">
<label for="txtDirectPlayAudioCodec">Audio codecs:</label>
<input type="text" id="txtDirectPlayAudioCodec" data-mini="true" />
<div>Separated by comma. This can be left empty to apply to all containers</div>
</div>
<p>
<button type="submit" data-theme="b" data-icon="check" data-mini="true">
Ok
</button>
<button type="button" data-icon="delete" onclick="$(this).parents('.popup').popup('close');" data-mini="true">
Cancel
</button>
</p>
</form>
</div>
</div>
<script type="text/javascript">
$('.dlnaProfileForm').off('submit', DlnaProfilePage.onSubmit).on('submit', DlnaProfilePage.onSubmit);
$('.editDirectPlayProfileForm').off('submit', DlnaProfilePage.onDirectPlayFormSubmit).on('submit', DlnaProfilePage.onDirectPlayFormSubmit);
</script>
</div>
</body>

View file

@ -145,9 +145,6 @@
<span id="playButtonContainer" style="display: none;">
<button id="btnPlay" type="button" data-icon="play" data-inline="true" data-mini="true">Play</button>
</span>
<span>
<button id="btnRemote" type="button" data-icon="wireless" data-inline="true" data-mini="true">Remote</button>
</span>
<span id="editButtonContainer" style="display: none;">
<a id="btnEdit" data-role="button" data-icon="edit" data-inline="true" data-mini="true" href="#">Edit</a>
</span>

View file

@ -131,9 +131,6 @@
<span id="playExternalButtonContainer" style="display: none;">
<a id="btnPlayExternal" data-role="button" data-icon="play" data-inline="true" data-mini="true" href="#" target="_blank">Play</a>
</span>
<span id="remoteButtonContainer" style="display: none;">
<button id="btnRemote" type="button" data-icon="wireless" data-inline="true" data-mini="true">Remote</button>
</span>
<span id="editButtonContainer" style="display: none;">
<a id="btnEdit" data-role="button" data-icon="edit" data-inline="true" data-mini="true" href="#">Edit</a>
</span>

View file

@ -30,9 +30,6 @@
<span id="playButtonContainer" style="display: none;">
<button id="btnPlay" type="button" data-icon="play" data-inline="true" data-mini="true">Play</button>
</span>
<span>
<button id="btnRemote" type="button" data-icon="wireless" data-inline="true" data-mini="true">Remote</button>
</span>
<span id="editButtonContainer" style="display: none;">
<button id="btnEdit" type="button" data-icon="edit" data-inline="true" data-mini="true">Edit</button>
</span>

View file

@ -47,9 +47,6 @@
<span id="recordButtonContainer" style="display: none;">
<button id="btnRecord" type="button" data-icon="video" data-inline="true" data-mini="true">Record</button>
</span>
<span>
<button id="btnRemote" type="button" data-icon="wireless" data-inline="true" data-mini="true">Remote</button>
</span>
</div>
<div data-role="content">
<div class="detailPageContent">

View file

@ -41,9 +41,6 @@
<span id="playButtonContainer" style="display: none;">
<button id="btnPlay" type="button" data-icon="play" data-inline="true" data-mini="true">Play</button>
</span>
<span>
<button id="btnRemote" type="button" data-icon="wireless" data-inline="true" data-mini="true">Remote</button>
</span>
<span id="deleteButtonContainer" style="display: none;">
<button id="btnDelete" type="button" data-icon="delete" data-inline="true" data-mini="true">Delete</button>
</span>

View file

@ -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);

View file

@ -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,39 @@
renderMediaProfiles(page, profile.MediaProfiles);
}
function editDirectPlayProfile(page, directPlayProfile) {
isSubProfileNew = directPlayProfile == null;
directPlayProfile = directPlayProfile || {};
currentSubProfile = directPlayProfile;
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 +127,7 @@
}
html += '<li>';
html += '<a href="#">';
html += '<a data-profileindex="' + i + '" class="lnkEditSubProfile" href="#">';
html += '<p>Container: ' + (profile.Container || 'All') + '</p>';
@ -101,7 +142,7 @@
html += '</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileIndex="' + i + '">Delete</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileindex="' + i + '">Delete</a>';
html += '</li>';
}
@ -112,9 +153,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 +208,7 @@
html += '</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileIndex="' + i + '">Delete</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileindex="' + i + '">Delete</a>';
html += '</li>';
}
@ -171,7 +219,7 @@
$('.btnDeleteProfile', elem).on('click', function () {
var index = this.getAttribute('data-profileIndex');
var index = this.getAttribute('data-profileindex');
deleteTranscodingProfile(page, index);
});
}
@ -218,7 +266,7 @@
html += '</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileIndex="' + i + '">Delete</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileindex="' + i + '">Delete</a>';
html += '</li>';
}
@ -229,7 +277,7 @@
$('.btnDeleteProfile', elem).on('click', function () {
var index = this.getAttribute('data-profileIndex');
var index = this.getAttribute('data-profileindex');
deleteContainerProfile(page, index);
});
}
@ -278,7 +326,7 @@
html += '</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileIndex="' + i + '">Delete</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileindex="' + i + '">Delete</a>';
html += '</li>';
}
@ -289,7 +337,7 @@
$('.btnDeleteProfile', elem).on('click', function () {
var index = this.getAttribute('data-profileIndex');
var index = this.getAttribute('data-profileindex');
deleteCodecProfile(page, index);
});
}
@ -345,7 +393,7 @@
html += '</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileIndex="' + i + '">Delete</a>';
html += '<a href="#" data-icon="delete" class="btnDeleteProfile" data-profileindex="' + i + '">Delete</a>';
html += '</li>';
}
@ -356,7 +404,7 @@
$('.btnDeleteProfile', elem).on('click', function () {
var index = this.getAttribute('data-profileIndex');
var index = this.getAttribute('data-profileindex');
deleteMediaProfile(page, index);
});
}
@ -440,6 +488,28 @@
});
$('#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();
}
});
$('.btnAddDirectPlayProfile', page).on('click', function () {
editDirectPlayProfile(page);
});
}).on('pageshow', "#dlnaProfilePage", function () {
var page = this;
@ -466,6 +536,16 @@
saveProfile(page, currentProfile);
return false;
},
onDirectPlayFormSubmit: function () {
var form = this;
var page = $(form).parents('.page');
saveDirectPlayProfile(page);
return false;
}
};

View file

@ -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 () {

View file

@ -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 += '<br/><span class="mediaInfoLabel">Path</span><span class="mediaInfoAttribute">' + version.Path + '</span>';
}
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 += '<a class="' + cssClass + '" href="' + href + '"' + onclick + '>';
@ -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);

View file

@ -211,7 +211,7 @@
html += '<td class="detailTableButtonsCell">';
html += '<button class="btnPlay" data-icon="play" type="button" data-iconpos="notext" onclick="LibraryBrowser.showPlayMenu(this, \'' + item.Id + '\', \'Audio\', \'Audio\');" data-inline="true" title="Play">Play</button>';
html += '<button class="btnQueue" data-icon="plus" type="button" data-iconpos="notext" onclick="MediaPlayer.queue(\'' + item.Id + '\');" data-inline="true" title="Queue">Queue</button>';
html += '<button class="btnQueue" data-icon="plus" type="button" data-iconpos="notext" onclick="MediaController.queue(\'' + item.Id + '\');" data-inline="true" title="Queue">Queue</button>';
html += '</td>';
var num = item.IndexNumber;
@ -287,12 +287,10 @@
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 (!resumePositionTicks && mediaType != "Audio" && !isFolder) {
MediaController.play(itemId);
return;
}
@ -303,38 +301,22 @@
html += '<ul data-role="listview" style="min-width: 150px;">';
html += '<li data-role="list-divider" data-theme="b">Play Menu</li>';
if (itemType == "MusicArtist") {
html += '<li><a href="#" onclick="MediaPlayer.playArtist(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Play</a></li>';
} else if (itemType != "MusicGenre") {
html += '<li><a href="#" onclick="MediaPlayer.playById(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Play</a></li>';
html += '<li><a href="#" onclick="MediaController.play(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Play</a></li>';
if (itemType == "Audio" || itemType == "MusicAlbum" || itemType == "MusicArtist" || itemType == "MusicGenre") {
html += '<li><a href="#" onclick="MediaController.instantMix(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Instant Mix</a></li>';
}
if (itemType == "Audio") {
html += '<li><a href="#" onclick="MediaPlayer.playInstantMixFromSong(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Instant Mix</a></li>';
}
else if (itemType == "MusicAlbum") {
html += '<li><a href="#" onclick="MediaPlayer.playInstantMixFromAlbum(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Instant Mix</a></li>';
html += '<li><a href="#" onclick="MediaPlayer.shuffleFolder(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Shuffle</a></li>';
}
else if (itemType == "MusicArtist") {
html += '<li><a href="#" onclick="MediaPlayer.playInstantMixFromArtist(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Instant Mix</a></li>';
html += '<li><a href="#" onclick="MediaPlayer.shuffleArtist(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Shuffle</a></li>';
}
else if (itemType == "MusicGenre") {
html += '<li><a href="#" onclick="MediaPlayer.playInstantMixFromMusicGenre(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Instant Mix</a></li>';
html += '<li><a href="#" onclick="MediaPlayer.shuffleMusicGenre(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Shuffle</a></li>';
if (isFolder || itemType == "MusicArtist" || itemType == "MusicGenre") {
html += '<li><a href="#" onclick="MediaController.shuffle(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Shuffle</a></li>';
}
if (resumePositionTicks) {
html += '<li><a href="#" onclick="MediaPlayer.playById(\'' + itemId + '\', ' + resumePositionTicks + ');LibraryBrowser.closePlayMenu();">Resume</a></li>';
html += '<li><a href="#" onclick="MediaController.play({ids:[\'' + itemId + '\'],startPositionTicks:' + resumePositionTicks + '});LibraryBrowser.closePlayMenu();">Resume</a></li>';
}
if (isPlaying) {
if (itemType == "MusicArtist") {
html += '<li><a href="#" onclick="MediaPlayer.queueArtist(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Queue</a></li>';
} else if (itemType != "MusicGenre") {
html += '<li><a href="#" onclick="MediaPlayer.queue(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Queue</a></li>';
}
if (MediaController.canQueueMediaType(mediaType)) {
html += '<li><a href="#" onclick="MediaController.queue(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">Queue</a></li>';
}
html += '</ul>';

View file

@ -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 += '<button type="button" data-mini="true" data-inline="true" data-icon="play" data-iconpos="notext" title="Play" onclick="' + onPlayClick + '" style="' + buttonMargin + '">Play</button>';
buttonCount++;
if (item.MediaType == "Audio" || item.Type == "MusicAlbum") {
html += '<button type="button" data-mini="true" data-inline="true" data-icon="plus" data-iconpos="notext" title="Queue" onclick="MediaPlayer.queue(\'' + item.Id + '\');return false;" style="' + buttonMargin + '">Queue</button>';
html += '<button type="button" data-mini="true" data-inline="true" data-icon="plus" data-iconpos="notext" title="Queue" onclick="MediaController.queue(\'' + item.Id + '\');return false;" style="' + buttonMargin + '">Queue</button>';
buttonCount++;
}
}
@ -126,10 +126,6 @@
buttonCount++;
}
if (!isPortrait || buttonCount < 3) {
html += '<button type="button" data-mini="true" data-inline="true" data-icon="wireless" data-iconpos="notext" title="Remote" class="btnRemoteControl" data-itemid="' + item.Id + '" style="' + buttonMargin + '">Remote</button>';
}
html += '</div>';
html += '</div>';
@ -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 () {

View file

@ -24,7 +24,7 @@
html += '<div class="viewMenuSecondary">';
html += '<button class="btnCast btnDefaultCast" type="button" data-role="none" style="display:none;"></button>';
html += '<button class="btnCast btnDefaultCast" type="button" data-role="none"></button>';
html += '<a class="viewMenuLink btnCurrentUser" href="#" onclick="Dashboard.showUserFlyout(this);">';
@ -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 () {
@ -210,6 +224,9 @@
});
});
}
updateCastIcon();
}).on('pageshow', ".libraryPage", function () {
var page = this;
@ -224,4 +241,13 @@
}
});
$(function() {
$(MediaController).on('playerchange', function () {
updateCastIcon();
});
});
})(window, document, jQuery);

View file

@ -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 () {

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1,277 @@
(function ($, window) {
function mediaController() {
var self = this;
var currentPlayer;
var currentTargetInfo;
var players = [];
self.registerPlayer = function (player) {
players.push(player);
};
self.getPlayerInfo = function () {
return {
name: currentPlayer.name,
isLocalPlayer: currentPlayer.isLocalPlayer,
id: currentTargetInfo.id,
deviceName: currentTargetInfo.deviceName,
playableMediaTypes: currentTargetInfo.playableMediaTypes
};
};
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) {
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 self.getPlayerInfo().playableMediaTypes.indexOf(item.MediaType) != -1;
};
self.canQueueMediaType = function (mediaType) {
return currentPlayer.canQueueMediaType(mediaType);
};
self.getLocalPlayer = function () {
return currentPlayer.isLocalPlayer ?
currentPlayer :
players.filter(function (p) {
return p.isLocalPlayer;
})[0];
};
}
window.MediaController = new mediaController();
function onWebSocketMessageReceived(e, msg) {
var localPlayer = msg.MessageType === "Play" || msg.MessageType === "Playstate" ?
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);
function getTargetsHtml(targets) {
var playerInfo = MediaController.getPlayerInfo();
var html = '';
html += '<fieldset data-role="controlgroup" data-mini="true">';
html += '<legend>Select Player:</legend>';
for (var i = 0, length = targets.length; i < length; i++) {
var target = targets[i];
var id = 'radioPlayerTarget' + i;
var isChecked = target.id == playerInfo.id;
var checkedHtml = isChecked ? ' checked="checked"' : '';
html += '<input type="radio" class="radioSelectPlayerTarget" name="radioSelectPlayerTarget" data-mediatypes="' + target.playableMediaTypes.join(',') + '" data-playername="' + target.playerName + '" data-targetid="' + target.id + '" data-targetname="' + target.name + '" id="' + id + '" value="' + target.id + '"' + checkedHtml + '>';
html += '<label for="' + id + '" style="font-weight:normal;">' + target.name;
if (target.appName) {
html += '<br/><span style="color:#bbb;">' + target.appName + '</span>';
}
html += '</label>';
}
html += '</fieldset>';
return html;
}
function showPlayerSelection() {
var promise = MediaController.getTargets();
var html = '<div data-role="panel" data-position="right" data-display="overlay" id="playerFlyout" data-theme="b">';
html += '<div class="players"></div>';
html += '</div>';
$(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');
var playableMediaTypes = this.getAttribute('data-mediatypes').split(',');
MediaController.setActivePlayer(playerName, {
id: targetId,
name: targetName,
playableMediaTypes: playableMediaTypes
});
});
});
}
$(document).on('headercreated', ".libraryPage", function () {
var page = this;
$('.btnCast', page).on('click', function () {
showPlayerSelection();
});
});
})(jQuery, window);

View file

@ -453,8 +453,6 @@
html += "</div>";
}
html += '<div style="padding: 5px;"><a data-role="button" data-icon="gear" href="usersettings.html?userid=' + Dashboard.getCurrentUserId() + '" data-mini="true" data-theme="a">Preferences</a></div>';
return html;
};
@ -528,8 +526,6 @@
html += "</div>";
}
html += '<div style="padding: 5px;"><a data-role="button" data-icon="gear" href="usersettings.html?userid=' + Dashboard.getCurrentUserId() + '" data-mini="true" data-theme="a">Preferences</a></div>';
return html;
};

View file

@ -13,15 +13,31 @@
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.name = 'Html5 Player';
self.getTargets = function () {
var targets = [{
name: 'My Browser',
id: ApiClient.deviceId(),
playerName: self.name,
playableMediaTypes: ['Audio', 'Video']
}];
return targets;
};
self.updateCanClientSeek = function (elem) {
var duration = elem.duration;
canClientSeek = duration && !isNaN(duration) && duration != Number.POSITIVE_INFINITY && duration != Number.NEGATIVE_INFINITY;
@ -275,7 +291,7 @@
audioBitrate: audioBitrate,
videoBitrate: videoBitrate
};
if (params.videoCodec == 'h264') {
params.profile = 'baseline';
params.level = '3';
@ -284,137 +300,100 @@
return params;
};
self.canPlay = function (item, user) {
self.canQueueMediaType = function (mediaType) {
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);
return currentItem && currentItem.MediaType == mediaType;
};
self.getPlayUrl = function (item) {
function translateItemsForPlayback(items) {
var deferred = $.Deferred();
if (item.GameSystem == "Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) {
var firstItem = items[0];
var promise;
return "http://nesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom;
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 (item.GameSystem == "Super Nintendo" && item.MediaType == "Game" && item.ProviderIds.NesBox && item.ProviderIds.NesBoxRom) {
if (promise) {
promise.done(function (result) {
return "http://snesbox.com/game/" + item.ProviderIds.NesBox + '/rom/' + item.ProviderIds.NesBoxRom;
deferred.resolveWith(null, [result.Items]);
});
} else {
deferred.resolveWith(null, [items]);
}
return null;
};
return deferred.promise();
}
self.canPlayMediaType = function (mediaType) {
if (mediaType === "Video") {
return true;
}
if (mediaType === "Audio") {
return true;
}
return false;
};
self.play = function (items, startPosition) {
self.play = function (options) {
Dashboard.getCurrentUser().done(function (user) {
var item = items[0];
if (options.items) {
var videoType = (item.VideoType || "").toLowerCase();
translateItemsForPlayback(options.items).done(function (items) {
var expirementalText = "This feature is experimental. It may not work at all with some titles. Do you wish to continue?";
self.playInternal(items[0], options.startPositionTicks, user);
if (videoType == "dvd") {
self.playlist = items;
currentPlaylistIndex = 0;
});
self.playWithWarning(items, startPosition, user, "dvdstreamconfirmed", "Dvd Folder Streaming", expirementalText);
return;
}
else if (videoType == "bluray") {
} else {
self.playWithWarning(items, startPosition, user, "bluraystreamconfirmed", "Blu-ray Folder Streaming", expirementalText);
return;
}
else if (videoType == "iso") {
self.getItemsForPlayback({
var isoType = (item.IsoType || "").toLowerCase();
Ids: options.ids.join(',')
if (isoType == "dvd") {
}).done(function (result) {
self.playWithWarning(items, startPosition, user, "dvdisostreamconfirmed", "Dvd Iso Streaming", expirementalText);
return;
}
else if (isoType == "bluray") {
translateItemsForPlayback(result.Items).done(function (items) {
self.playWithWarning(items, startPosition, user, "blurayisostreamconfirmed", "Blu-ray Iso Streaming", expirementalText);
return;
}
}
self.playInternal(items[0], options.startPositionTicks, user);
self.playInternal(items[0], startPosition, user);
self.onPlaybackStarted(items);
});
};
self.playlist = items;
currentPlaylistIndex = 0;
});
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 +548,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 +624,69 @@
}
};
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.getItemsForPlayback({
ParentId: id,
Recursive: true,
SortBy: "SortName"
}).done(function (result) {
self.queueItems(result.Items);
translateItemsForPlayback(options.items).done(function (items) {
self.queueItems(items);
});
} else {
self.queueItems([item]);
}
self.getItemsForPlayback({
Ids: options.ids.join(',')
}).done(function (result) {
translateItemsForPlayback(result.Items).done(function (items) {
self.queueItems(items);
});
});
}
});
};
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 +750,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 +880,6 @@
return currentMediaElement;
};
self.showSendMediaMenu = function () {
RemoteControl.showMenuForItem({
item: currentItem
});
};
self.bindPositionSlider = function () {
self.positionSlider.on('slidestart', function (e) {
@ -1220,4 +1159,8 @@
window.MediaPlayer = new mediaPlayer();
window.MediaController.registerPlayer(window.MediaPlayer);
window.MediaController.setActivePlayer(window.MediaPlayer, window.MediaPlayer.getTargets()[0]);
})(document, setTimeout, clearTimeout, screen, localStorage, $, setInterval, window);

View file

@ -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 = '<div data-role="popup" class="remoteControlFlyout" data-transition="slidedown" data-theme="a">';
html += '<a href="#" data-rel="back" data-role="button" data-icon="delete" data-iconpos="notext" class="ui-btn-right" data-theme="b">Close</a>';
html += '<div class="ui-bar-b" style="text-align:center;">';
html += '<div style="margin:.5em 0;">Remote Control</div>';
html += '</div>';
html += '<div style="padding: 1em;">';
html += '<form id="sendToForm">';
html += '<input type="hidden" value="PlayNow" id="fldPlayCommand" />';
html += '<div class="sessionsPopupContent">';
html += '<div class="circle"></div><div class="circle1"></div>';
html += '</div>';
html += '<p style="text-align:center;margin:.75em 0 0;">';
html += '<span id="playButtonContainer" style="display:none;"><button onclick="$(\'#fldPlayCommand\').val(\'PlayNow\');" type="submit" data-icon="play" data-mini="true" data-inline="true">Play</button></span>';
html += '<span id="resumeButtonContainer" style="display:none;"><button onclick="$(\'#fldPlayCommand\').val(\'Resume\');" type="submit" data-icon="play" data-mini="true" data-inline="true">Resume</button></span>';
html += '<span id="queueButtonContainer" style="display:none;"><button onclick="$(\'#fldPlayCommand\').val(\'PlayLast\');" type="submit" data-icon="plus" data-mini="true" data-inline="true">Queue</button></span>';
html += '<span id="browseButtonContainer" style="display:none;"><button onclick="$(\'#fldPlayCommand\').val(\'Browse\');" type="submit" data-icon="eye" data-mini="true" data-inline="true">View</button></span>';
html += '</p>';
html += '</form></div>';
html += '</div>';
$(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('<p>There are currently no available media browser sessions to control.</p>');
$('.remoteControlFlyout').popup("reposition", {});
return;
}
var item = options.item;
var html = '';
html += '<div style="margin-top:0;">';
html += '<select id="selectCommand" data-mini="true">';
// Default for virtual & IBN types
var playLabel = 'View';
if (item.LocationType != "Virtual") {
if (item.IsFolder) {
playLabel = "Play All";
}
else if (item.MediaType == "Video") {
playLabel = "Play from beginning";
}
else if (item.MediaType) {
playLabel = "Play";
}
}
html += '<option value="Play" selected>' + playLabel + '</label>';
if (item.LocalTrailerCount) {
html += '<option value="Trailer">Play trailer</label>';
}
if (item.SpecialFeatureCount) {
html += '<option value="SpecialFeature">Play special feature</label>';
}
if (options.themeSongs) {
html += '<option value="ThemeSong">Play theme song</label>';
}
if (options.themeVideos) {
html += '<option value="ThemeVideo">Play theme video</label>';
}
html += '</select>';
html += '</div>';
html += '<div class="playFromMenu" style="display:none;"></div>';
html += '<div class="trailers" style="display:none;"></div>';
html += '<div class="specialFeatures" style="display:none;"></div>';
html += '<div class="themeSongs" style="display:none;"></div>';
html += '<div class="themeVideos" style="display:none;"></div>';
html += '<h4 style="margin: 1em 0 .5em;">Select Device</h4>';
html += '<table class="tblRemoteControl">';
html += '<thead><tr>';
html += '<th></th>';
html += '<th>Device</th>';
html += '</tr></thead>';
html += '<tbody>';
for (var i = 0, length = sessions.length; i < length; i++) {
var session = sessions[i];
html += '<tr class="trSession" data-queue="' + session.QueueableMediaTypes.join(',') + '" data-sessionid="' + session.Id + '">';
html += '<td class="tdSelectSession"></td>';
html += '<td>' + session.DeviceName;
if (session.UserName) {
html += ' - ' + session.UserName;
}
html += '</td>';
html += '</tr>';
}
html += '</tbody>';
html += '</table>';
html += '</div>';
elem.html(html).trigger('create');
$('.tdSelectSession', elem).html('<input type="radio" class="chkClient" name="chkClient" />');
$('.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 += '<h4 style="margin: 1em 0 .5em;">' + header + '</h4>';
html += '<div class="playMenuOptions">';
html += '<table class="tblRemoteControl tblRemoteControlNoHeader">';
html += '<tbody>';
for (var i = 0, length = videos.length; i < length; i++) {
var video = videos[i];
html += '<tr class="trItem" data-id="' + video.Id + '">';
html += '<td class="tdSelectItem"></td>';
html += '<td class="tdRemoteControlImage">';
var imgUrl;
if (video.ImageTags && video.ImageTags.Primary) {
imgUrl = ApiClient.getImageUrl(video.Id, {
maxheight: 80,
tag: video.ImageTags.Primary,
type: "Primary"
});
html += '<img src="' + imgUrl + '" />';
}
html += '</td>';
html += '<td>' + video.Name;
if (video.RunTimeTicks) {
html += '<br/>' + Dashboard.getDisplayTime(video.RunTimeTicks);
}
html += '</td>';
html += '</tr>';
}
html += '</tbody>';
html += '</table>';
html += '</div>';
elem.html(html);
$('.tdSelectItem', elem).html('<input type="radio" class="chkSelectItem" name="chkSelectItem" />');
$('.chkSelectItem:first', elem).checked(true);
}
function showMenu(sessions, options) {
var html = '<div data-role="popup" data-transition="slidedown" class="remoteControlFlyout" data-theme="a">';
@ -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) {
@ -980,4 +411,99 @@
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;
self.name = 'Remote Control';
self.play = function (options) {
sendPlayCommand(options, 'PlayNow');
};
self.shuffle = function (id) {
sendPlayCommand({ ids: [id] }, 'PlayShuffle');
};
self.instantMix = function (id) {
sendPlayCommand({ ids: [id] }, 'PlayInstantMix');
};
self.queue = function (options) {
sendPlayCommand(options, 'PlayNext');
};
self.queueNext = function (options) {
sendPlayCommand(options, 'PlayLast');
};
self.canQueueMediaType = function (mediaType) {
return mediaType == 'Audio' || mediaType == 'Video';
};
self.getTargets = function () {
var deferred = $.Deferred();
var sessionQuery = {
SupportsRemoteControl: true,
ControllableByUserId: Dashboard.getCurrentUserId()
};
ApiClient.getSessions(sessionQuery).done(function (sessions) {
var targets = sessions.filter(function (s) {
return s.DeviceId != ApiClient.deviceId();
}).map(function (s) {
return {
name: s.DeviceName,
id: s.Id,
playerName: self.name,
appName: s.Client,
playableMediaTypes: s.PlayableMediaTypes
};
});
deferred.resolveWith(null, [targets]);
}).fail(function () {
deferred.reject();
});
return deferred.promise();
};
}
MediaController.registerPlayer(new remoteControlPlayer());
})(window, document, jQuery);

View file

@ -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 += '<button onclick="MediaPlayer.showChaptersFlyout();" id="video-chaptersButton" class="mediaButton chaptersButton" title="Scenes" type="button" data-icon="video" data-iconpos="notext" data-inline="true">Scenes</button>';
videoPlayerHtml += '<div class="mediaFlyoutContainer"><div id="video-chaptersFlyout" style="display:none;" class="mediaPlayerFlyout chaptersFlyout"></div></div>';
videoPlayerHtml += '<button onclick="MediaPlayer.showSendMediaMenu();" id="video-sendMediaButton" class="mediaButton sendMediaButton" title="Remote" type="button" data-icon="wireless" data-iconpos="notext" data-inline="true">Remote</button>';
videoPlayerHtml += '<button onclick="MediaPlayer.toggleVideoPlayerMenu();" id="video-videoPlayerMenuButton" class="mediaButton videoPlayerMenuButton" title="Menu" type="button" data-icon="bars" data-iconpos="notext" data-inline="true">Menu</button>';
videoPlayerHtml += '</div>'; // videoControls
@ -1422,8 +1375,6 @@ $(function () {
footerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="fullscreenButton" class="mediaButton fullscreenButton" title="Fullscreen" type="button" data-icon="action" data-iconpos="notext" data-inline="true">Fullscreen</button>';
footerHtml += '<button onclick="MediaPlayer.showSendMediaMenu();" id="sendMediaButton" class="mediaButton sendMediaButton" title="Remote" type="button" data-icon="wireless" data-iconpos="notext" data-inline="true">Remote</button>';
footerHtml += '</div>';
footerHtml += '<div id="footerNotifications"></div>';