mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 19:08:18 -07:00
more support for episodes directly in a series folder
This commit is contained in:
parent
b8c8a794f3
commit
e38caab270
@ -66,6 +66,10 @@
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.posterItemText + .posterItemProgress {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.posterItemDefaultText {
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
body {
|
||||
overflow-y: scroll!important;
|
||||
font-size: 90%;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.textlink {
|
||||
|
@ -11,6 +11,35 @@
|
||||
<a href="livetvrecordings.html" class="ui-btn-active">Recordings</a>
|
||||
<a href="livetvtimers.html">Timers</a>
|
||||
</div>
|
||||
<div id="itemBackdrop" class="itemBackdrop noBackdrop">
|
||||
<div class="itemBackdropContent">
|
||||
<table class="detailPageContent primaryDetailPageContent">
|
||||
<tr>
|
||||
<td style="vertical-align: top; padding: 10px 1em 10px 0;">
|
||||
<div id="itemImage" class="itemImageContainer"></div>
|
||||
</td>
|
||||
<td style="vertical-align: top; padding: 0;">
|
||||
<p><span class="itemName inlineItemName"></span><span class="itemMiscInfo" style="display: inline;"></span></p>
|
||||
<p class="itemChannelNumber"></p>
|
||||
<p style="margin: 2em 0;">
|
||||
<span class="userDataIcons"></span>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-body-a" style="text-align: center; padding: .25em 0 .5em;">
|
||||
<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="hand-up" 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>
|
||||
</div>
|
||||
<div data-role="content">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<th class="desktopColumn">Channel</th>
|
||||
<th>Date</th>
|
||||
<th>Start</th>
|
||||
<th class="tabletColumn">End</th>
|
||||
<th class="tabletColumn">Length</th>
|
||||
<th class="tabletColumn">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -364,14 +364,34 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var friendly = item.Type == "Audio" ? "song" : item.Type.toLowerCase();
|
||||
var promise;
|
||||
|
||||
ApiClient.getItems(Dashboard.getCurrentUserId(), {
|
||||
if (item.Type == "Season") {
|
||||
|
||||
promise = ApiClient.getSeasons(item.SeriesId, {
|
||||
|
||||
userId: Dashboard.getCurrentUserId(),
|
||||
AdjacentTo: item.Id
|
||||
});
|
||||
}
|
||||
else if (item.Type == "Episode") {
|
||||
|
||||
// Use dedicated episodes endpoint
|
||||
promise = ApiClient.getEpisodes(item.SeriesId, {
|
||||
|
||||
seasonId: item.SeasonId,
|
||||
userId: Dashboard.getCurrentUserId(),
|
||||
AdjacentTo: item.Id
|
||||
});
|
||||
|
||||
} else {
|
||||
promise = ApiClient.getItems(Dashboard.getCurrentUserId(), {
|
||||
AdjacentTo: item.Id,
|
||||
ParentId: item.ParentId
|
||||
});
|
||||
}
|
||||
|
||||
}).done(function (result) {
|
||||
promise.done(function (result) {
|
||||
|
||||
for (var i = 0, length = result.Items.length; i < length; i++) {
|
||||
|
||||
@ -381,13 +401,15 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
var friendlyTypeName = item.Type == "Audio" ? "song" : item.Type.toLowerCase();
|
||||
|
||||
if (curr.IndexNumber < item.IndexNumber) {
|
||||
|
||||
$('.lnkPreviousItem', page).removeClass('hide').attr('href', 'itemdetails.html?id=' + curr.Id).html('← Previous ' + friendly);
|
||||
$('.lnkPreviousItem', page).removeClass('hide').attr('href', 'itemdetails.html?id=' + curr.Id).html('← Previous ' + friendlyTypeName);
|
||||
}
|
||||
else if (curr.IndexNumber > item.IndexNumber) {
|
||||
|
||||
$('.lnkNextItem', page).removeClass('hide').attr('href', 'itemdetails.html?id=' + curr.Id).html('Next ' + friendly + ' →');
|
||||
$('.lnkNextItem', page).removeClass('hide').attr('href', 'itemdetails.html?id=' + curr.Id).html('Next ' + friendlyTypeName + ' →');
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -518,23 +540,12 @@
|
||||
}
|
||||
else if (item.Type == "Season") {
|
||||
|
||||
if (item.IndexNumber == null) {
|
||||
|
||||
// Use dedicated episodes endpoint
|
||||
promise = ApiClient.getEpisodes(item.SeriesId, {
|
||||
|
||||
seasonId: item.Id,
|
||||
userId: user.Id
|
||||
});
|
||||
} else {
|
||||
|
||||
// Use dedicated episodes endpoint
|
||||
promise = ApiClient.getEpisodes(item.SeriesId, {
|
||||
|
||||
season: item.IndexNumber,
|
||||
userId: user.Id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
promise = promise || ApiClient.getItems(Dashboard.getCurrentUserId(), query);
|
||||
|
@ -68,7 +68,8 @@
|
||||
for (var i = 0, length = result.Items.length; i < length; i++) {
|
||||
|
||||
urls.push(LibraryBrowser.getImageUrl(result.Items[i], 'Primary', 0, {
|
||||
width: 160
|
||||
width: 160,
|
||||
EnableImageEnhancers: false
|
||||
}));
|
||||
|
||||
}
|
||||
@ -96,7 +97,8 @@
|
||||
for (var i = 0, length = result.Items.length; i < length; i++) {
|
||||
|
||||
urls.push(LibraryBrowser.getImageUrl(result.Items[i], 'Primary', 0, {
|
||||
width: 160
|
||||
width: 160,
|
||||
EnableImageEnhancers: false
|
||||
}));
|
||||
|
||||
}
|
||||
@ -124,7 +126,8 @@
|
||||
for (var i = 0, length = result.Items.length; i < length; i++) {
|
||||
|
||||
urls.push(LibraryBrowser.getImageUrl(result.Items[i], 'Primary', 0, {
|
||||
width: 160
|
||||
width: 160,
|
||||
EnableImageEnhancers: false
|
||||
}));
|
||||
|
||||
}
|
||||
@ -152,7 +155,8 @@
|
||||
for (var i = 0, length = result.Items.length; i < length; i++) {
|
||||
|
||||
urls.push(LibraryBrowser.getImageUrl(result.Items[i], 'Primary', 0, {
|
||||
width: 160
|
||||
width: 160,
|
||||
EnableImageEnhancers: false
|
||||
}));
|
||||
|
||||
}
|
||||
|
@ -735,7 +735,7 @@
|
||||
else if (item.ImageTags && item.ImageTags.Primary) {
|
||||
|
||||
height = 300;
|
||||
width = primaryImageAspectRatio ? parseInt(height * primaryImageAspectRatio) : null;
|
||||
width = primaryImageAspectRatio ? (height * primaryImageAspectRatio).toFixed(0) : null;
|
||||
|
||||
imgUrl = ApiClient.getImageUrl(item.Id, {
|
||||
type: "Primary",
|
||||
@ -748,7 +748,7 @@
|
||||
else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
height = 300;
|
||||
width = primaryImageAspectRatio ? parseInt(height * primaryImageAspectRatio) : null;
|
||||
width = primaryImageAspectRatio ? (height * primaryImageAspectRatio).toFixed(0) : null;
|
||||
|
||||
imgUrl = ApiClient.getImageUrl(item.AlbumId, {
|
||||
type: "Primary",
|
||||
@ -1200,7 +1200,7 @@
|
||||
}
|
||||
else if (item.ParentIndexNumber && item.Type == "Episode") {
|
||||
|
||||
html.push('<a class="detailPageParentLink" href="itemdetails.html?id=' + item.ParentId + '">Season ' + item.ParentIndexNumber + '</a>');
|
||||
html.push('<a class="detailPageParentLink" href="itemdetails.html?id=' + item.SeasonId + '">Season ' + item.ParentIndexNumber + '</a>');
|
||||
}
|
||||
else if (item.Album && item.Type == "Audio" && (item.AlbumId || item.ParentId)) {
|
||||
html.push('<a class="detailPageParentLink" href="itemdetails.html?id=' + (item.AlbumId || item.ParentId) + '">' + item.Album + '</a>');
|
||||
@ -2009,20 +2009,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
var minutes;
|
||||
|
||||
if (item.RunTimeTicks && item.Type != "Series") {
|
||||
|
||||
if (item.Type == "Audio") {
|
||||
|
||||
miscInfo.push(Dashboard.getDisplayTime(item.RunTimeTicks));
|
||||
} else {
|
||||
var minutes = item.RunTimeTicks / 600000000;
|
||||
minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
miscInfo.push(parseInt(minutes) + "min");
|
||||
miscInfo.push(minutes.toFixed(0) + "min");
|
||||
}
|
||||
}
|
||||
|
||||
if (item.DurationMs) {
|
||||
|
||||
minutes = item.DurationMs / 60000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
miscInfo.push(minutes.toFixed(0) + "min");
|
||||
}
|
||||
|
||||
if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") {
|
||||
miscInfo.push(item.OfficialRating);
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
function deleteRecording(page, id) {
|
||||
(function ($, document, apiClient) {
|
||||
|
||||
var currentItem;
|
||||
|
||||
function deleteRecording() {
|
||||
|
||||
Dashboard.confirm("Are you sure you wish to delete this recording?", "Confirm Recording Deletion", function (result) {
|
||||
|
||||
@ -6,14 +10,90 @@
|
||||
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
ApiClient.deleteLiveTvRecording(id).done(function () {
|
||||
ApiClient.deleteLiveTvRecording(currentItem.Id).done(function () {
|
||||
|
||||
Dashboard.alert('Recording deleted');
|
||||
|
||||
reload(page);
|
||||
Dashboard.navigate('livetvrecordings.html');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderRecording(page, item) {
|
||||
|
||||
currentItem = item;
|
||||
|
||||
var name = item.Name;
|
||||
|
||||
$('#itemImage', page).html(LibraryBrowser.getDetailImageHtml(item));
|
||||
|
||||
Dashboard.setPageTitle(name);
|
||||
|
||||
$('.itemName', page).html(name);
|
||||
$('.itemChannelNumber', page).html(item.Number);
|
||||
|
||||
$('.userDataIcons', page).html(LibraryBrowser.getUserDataIconsHtml(item));
|
||||
|
||||
$('.itemMiscInfo', page).html(LibraryBrowser.getMiscInfoHtml(item));
|
||||
|
||||
if (ApiClient.isWebSocketOpen()) {
|
||||
|
||||
var vals = [item.Type, item.Id, item.Name];
|
||||
|
||||
vals.push('livetv');
|
||||
|
||||
ApiClient.sendWebSocketMessage("Context", vals.join('|'));
|
||||
}
|
||||
|
||||
if (MediaPlayer.canPlay(item)) {
|
||||
$('#playButtonContainer', page).show();
|
||||
} else {
|
||||
$('#playButtonContainer', page).hide();
|
||||
}
|
||||
|
||||
Dashboard.getCurrentUser().done(function (user) {
|
||||
|
||||
if (user.Configuration.IsAdministrator && item.LocationType !== "Offline") {
|
||||
$('#deleteButtonContainer', page).show();
|
||||
} else {
|
||||
$('#deleteButtonContainer', page).hide();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
}
|
||||
|
||||
function reload(page) {
|
||||
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var id = getParameterByName('id');
|
||||
|
||||
apiClient.getLiveTvRecording(id).done(function (result) {
|
||||
|
||||
renderRecording(page, result);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('pageinit', "#liveTvRecordingPage", function () {
|
||||
|
||||
var page = this;
|
||||
|
||||
$('#btnDelete', page).on('click', deleteRecording);
|
||||
|
||||
}).on('pagebeforeshow', "#liveTvRecordingPage", function () {
|
||||
|
||||
var page = this;
|
||||
|
||||
reload(page);
|
||||
|
||||
}).on('pagehide', "#liveTvRecordingPage", function () {
|
||||
|
||||
currentItem = null;
|
||||
});
|
||||
|
||||
})(jQuery, document, ApiClient);
|
@ -34,7 +34,13 @@
|
||||
html += '</td>';
|
||||
|
||||
html += '<td>';
|
||||
html += '<a href="livetvrecording.html?id=' + recording.Id + '">' + recording.Name + '</a>';
|
||||
html += '<a href="livetvrecording.html?id=' + recording.Id + '">';
|
||||
html += recording.Name;
|
||||
|
||||
if (recording.EpisodeTitle) {
|
||||
html += "<br/>" + recording.EpisodeTitle;
|
||||
}
|
||||
html += '</a>';
|
||||
html += '</td>';
|
||||
|
||||
html += '<td class="desktopColumn">';
|
||||
@ -57,7 +63,9 @@
|
||||
|
||||
html += '<td>' + LiveTvHelpers.getDisplayTime(recording.StartDate) + '</td>';
|
||||
|
||||
html += '<td class="tabletColumn">' + LiveTvHelpers.getDisplayTime(recording.EndDate) + '</td>';
|
||||
var minutes = recording.DurationMs / 60000;
|
||||
|
||||
html += '<td class="tabletColumn">' + minutes.toFixed(0) + ' mins</td>';
|
||||
|
||||
html += '<td class="tabletColumn">' + (recording.Status || '') + '</td>';
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
html += '<th class="desktopColumn">Channel</th>';
|
||||
html += '<th>Date</th>';
|
||||
html += '<th>Start</th>';
|
||||
html += '<th class="tabletColumn">End</th>';
|
||||
html += '<th class="tabletColumn">Length</th>';
|
||||
html += '<th class="tabletColumn">Status</th>';
|
||||
html += '<th class="desktopColumn">Recurring</th>';
|
||||
|
||||
@ -78,7 +78,9 @@
|
||||
|
||||
html += '<td>' + LiveTvHelpers.getDisplayTime(timer.StartDate) + '</td>';
|
||||
|
||||
html += '<td class="tabletColumn">' + LiveTvHelpers.getDisplayTime(timer.EndDate) + '</td>';
|
||||
var minutes = timer.DurationMs / 60000;
|
||||
|
||||
html += '<td class="tabletColumn">' + minutes.toFixed(0) + ' mins</td>';
|
||||
|
||||
html += '<td class="tabletColumn">' + (timer.Status || '') + '</td>';
|
||||
|
||||
|
@ -102,11 +102,11 @@
|
||||
hours = 0;
|
||||
}
|
||||
|
||||
hours = parseInt(hours);
|
||||
hours = hours.toFixed(0);
|
||||
|
||||
ticks -= (hours * 36000000000);
|
||||
|
||||
var minutes = parseInt(ticks / 600000000);
|
||||
var minutes = (ticks / 600000000).toFixed(0);
|
||||
|
||||
var suffix = "am";
|
||||
|
||||
|
@ -1100,7 +1100,7 @@ var Dashboard = {
|
||||
var parts = [];
|
||||
|
||||
var hours = ticks / ticksPerHour;
|
||||
hours = parseInt(hours);
|
||||
hours = hours.toFixed(0);
|
||||
|
||||
if (hours) {
|
||||
parts.push(hours);
|
||||
@ -1111,7 +1111,7 @@ var Dashboard = {
|
||||
var ticksPerMinute = 600000000;
|
||||
|
||||
var minutes = ticks / ticksPerMinute;
|
||||
minutes = parseInt(minutes);
|
||||
minutes = minutes.toFixed(0);
|
||||
|
||||
ticks -= (minutes * ticksPerMinute);
|
||||
|
||||
@ -1123,7 +1123,7 @@ var Dashboard = {
|
||||
var ticksPerSecond = 10000000;
|
||||
|
||||
var seconds = ticks / ticksPerSecond;
|
||||
seconds = parseInt(seconds);
|
||||
seconds = seconds.toFixed(0);
|
||||
|
||||
if (seconds < 10) {
|
||||
seconds = '0' + seconds;
|
||||
|
@ -9,7 +9,7 @@
|
||||
SortBy: "DateCreated",
|
||||
SortOrder: "Descending",
|
||||
IncludeItemTypes: "Episode",
|
||||
Limit: 8,
|
||||
Limit: 12,
|
||||
Recursive: true,
|
||||
Fields: "PrimaryImageAspectRatio,SeriesInfo,UserData",
|
||||
Filters: "IsUnplayed",
|
||||
@ -35,7 +35,7 @@
|
||||
SortOrder: "Descending",
|
||||
IncludeItemTypes: "Episode",
|
||||
Filters: "IsResumable",
|
||||
Limit: 8,
|
||||
Limit: 4,
|
||||
Recursive: true,
|
||||
Fields: "PrimaryImageAspectRatio,SeriesInfo,UserData",
|
||||
ExcludeLocationTypes: "Virtual"
|
||||
|
@ -7,7 +7,9 @@
|
||||
function getDateFormat(date) {
|
||||
|
||||
// yyyyMMddHHmmss
|
||||
var d = date;
|
||||
// Convert to UTC
|
||||
// http://stackoverflow.com/questions/948532/how-do-you-convert-a-javascript-date-to-utc/14610512#14610512
|
||||
var d = new Date(date.getTime());
|
||||
|
||||
return "" + d.getFullYear() + formatDigit(d.getMonth() + 1) + formatDigit(d.getDate()) + formatDigit(d.getHours()) + formatDigit(d.getMinutes()) + formatDigit(d.getSeconds());
|
||||
}
|
||||
@ -28,15 +30,15 @@
|
||||
|
||||
var missedItemsQuery = $.extend({
|
||||
|
||||
IsUnaired: false
|
||||
|
||||
}, query);
|
||||
|
||||
var yesterday = new Date();
|
||||
|
||||
yesterday.setHours(23, 50, 0, 0);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
missedItemsQuery.MaxPremiereDate = getDateFormat(yesterday);
|
||||
|
||||
yesterday.setHours(0, 0, 0, 0);
|
||||
|
||||
missedItemsQuery.MinPremiereDate = getDateFormat(yesterday);
|
||||
|
||||
var unairedQuery = $.extend({
|
||||
|
@ -19,10 +19,6 @@
|
||||
<table class="ehsContent">
|
||||
<tr>
|
||||
<td>
|
||||
<h1 class="listHeader firstListHeader">Latest Episodes</h1>
|
||||
|
||||
<div id="recentlyAddedItems">
|
||||
</div>
|
||||
|
||||
<div id="resumableSection" style="display: none;">
|
||||
<h1 class="listHeader">Resume</h1>
|
||||
@ -30,6 +26,11 @@
|
||||
<div id="resumableItems">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="listHeader">Latest Episodes</h1>
|
||||
|
||||
<div id="recentlyAddedItems">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
Loading…
Reference in New Issue
Block a user