mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #2610 from shortspider/ContinueReading
Add a Continue Reading Section
This commit is contained in:
commit
660ee65559
4 changed files with 53 additions and 106 deletions
|
@ -24,6 +24,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -50,6 +52,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -63,6 +66,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -76,6 +80,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -89,6 +94,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
@ -102,6 +108,7 @@
|
||||||
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
<option value="activerecordings">${HeaderActiveRecordings}</option>
|
||||||
<option value="resume">${HeaderContinueWatching}</option>
|
<option value="resume">${HeaderContinueWatching}</option>
|
||||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||||
|
<option value="resumebook">${HeaderContinueReading}</option>
|
||||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||||
<option value="nextup">${NextUp}</option>
|
<option value="nextup">${NextUp}</option>
|
||||||
<option value="livetv">${LiveTV}</option>
|
<option value="livetv">${LiveTV}</option>
|
||||||
|
|
|
@ -24,12 +24,14 @@ import ServerConnections from '../ServerConnections';
|
||||||
case 2:
|
case 2:
|
||||||
return 'resumeaudio';
|
return 'resumeaudio';
|
||||||
case 3:
|
case 3:
|
||||||
return 'livetv';
|
return 'resumebook';
|
||||||
case 4:
|
case 4:
|
||||||
return 'nextup';
|
return 'livetv';
|
||||||
case 5:
|
case 5:
|
||||||
return 'latestmedia';
|
return 'nextup';
|
||||||
case 6:
|
case 6:
|
||||||
|
return 'latestmedia';
|
||||||
|
case 7:
|
||||||
return 'none';
|
return 'none';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
|
@ -142,15 +144,17 @@ import ServerConnections from '../ServerConnections';
|
||||||
} else if (section === 'librarybuttons') {
|
} else if (section === 'librarybuttons') {
|
||||||
loadlibraryButtons(elem, apiClient, user, userSettings, userViews);
|
loadlibraryButtons(elem, apiClient, user, userSettings, userViews);
|
||||||
} else if (section === 'resume') {
|
} else if (section === 'resume') {
|
||||||
loadResumeVideo(elem, apiClient);
|
return loadResume(elem, apiClient, 'HeaderContinueWatching', 'Video');
|
||||||
} else if (section === 'resumeaudio') {
|
} else if (section === 'resumeaudio') {
|
||||||
loadResumeAudio(elem, apiClient);
|
return loadResume(elem, apiClient, 'HeaderContinueListening', 'Audio');
|
||||||
} else if (section === 'activerecordings') {
|
} else if (section === 'activerecordings') {
|
||||||
loadLatestLiveTvRecordings(elem, true, apiClient);
|
loadLatestLiveTvRecordings(elem, true, apiClient);
|
||||||
} else if (section === 'nextup') {
|
} else if (section === 'nextup') {
|
||||||
loadNextUp(elem, apiClient);
|
loadNextUp(elem, apiClient);
|
||||||
} else if (section === 'onnow' || section === 'livetv') {
|
} else if (section === 'onnow' || section === 'livetv') {
|
||||||
return loadOnNow(elem, apiClient, user);
|
return loadOnNow(elem, apiClient, user);
|
||||||
|
} else if (section === 'resumebook') {
|
||||||
|
return loadResume(elem, apiClient, 'HeaderContinueReading', 'Book');
|
||||||
} else {
|
} else {
|
||||||
elem.innerHTML = '';
|
elem.innerHTML = '';
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -365,7 +369,39 @@ import ServerConnections from '../ServerConnections';
|
||||||
imageLoader.lazyChildren(elem);
|
imageLoader.lazyChildren(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContinueWatchingFetchFn(serverId) {
|
const dataMonitorHints = {
|
||||||
|
'Audio': 'audioplayback,markplayed',
|
||||||
|
'Video': 'videoplayback,markplayed'
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadResume(elem, apiClient, headerText, mediaType) {
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
const dataMonitor = dataMonitorHints[mediaType] || 'markplayed';
|
||||||
|
|
||||||
|
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate(headerText) + '</h2>';
|
||||||
|
if (enableScrollX()) {
|
||||||
|
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
|
||||||
|
html += `<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="${dataMonitor}">`;
|
||||||
|
} else {
|
||||||
|
html += `<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-monitor="${dataMonitor}">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableScrollX()) {
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
elem.classList.add('hide');
|
||||||
|
elem.innerHTML = html;
|
||||||
|
|
||||||
|
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||||
|
itemsContainer.fetchData = getItemsToResumeFn(mediaType, apiClient.serverId());
|
||||||
|
itemsContainer.getItemsHtml = getItemsToResumeHtml;
|
||||||
|
itemsContainer.parentContainer = elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemsToResumeFn(mediaType, serverId) {
|
||||||
return function () {
|
return function () {
|
||||||
const apiClient = ServerConnections.getApiClient(serverId);
|
const apiClient = ServerConnections.getApiClient(serverId);
|
||||||
const screenWidth = dom.getWindowSize().innerWidth;
|
const screenWidth = dom.getWindowSize().innerWidth;
|
||||||
|
@ -385,14 +421,14 @@ import ServerConnections from '../ServerConnections';
|
||||||
ImageTypeLimit: 1,
|
ImageTypeLimit: 1,
|
||||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
||||||
EnableTotalRecordCount: false,
|
EnableTotalRecordCount: false,
|
||||||
MediaTypes: 'Video'
|
MediaTypes: mediaType
|
||||||
};
|
};
|
||||||
|
|
||||||
return apiClient.getResumableItems(apiClient.getCurrentUserId(), options);
|
return apiClient.getResumableItems(apiClient.getCurrentUserId(), options);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContinueWatchingItemsHtml(items) {
|
function getItemsToResumeHtml(items) {
|
||||||
const cardLayout = false;
|
const cardLayout = false;
|
||||||
return cardBuilder.getCardsHtml({
|
return cardBuilder.getCardsHtml({
|
||||||
items: items,
|
items: items,
|
||||||
|
@ -413,104 +449,6 @@ import ServerConnections from '../ServerConnections';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadResumeVideo(elem, apiClient) {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
|
|
||||||
if (enableScrollX()) {
|
|
||||||
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
|
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="videoplayback,markplayed">';
|
|
||||||
} else {
|
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-monitor="videoplayback,markplayed">';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableScrollX()) {
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
elem.classList.add('hide');
|
|
||||||
elem.innerHTML = html;
|
|
||||||
|
|
||||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
|
||||||
itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId());
|
|
||||||
itemsContainer.getItemsHtml = getContinueWatchingItemsHtml;
|
|
||||||
itemsContainer.parentContainer = elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getContinueListeningFetchFn(serverId) {
|
|
||||||
return function () {
|
|
||||||
const apiClient = ServerConnections.getApiClient(serverId);
|
|
||||||
const screenWidth = dom.getWindowSize().innerWidth;
|
|
||||||
|
|
||||||
let limit;
|
|
||||||
if (enableScrollX()) {
|
|
||||||
limit = 12;
|
|
||||||
} else {
|
|
||||||
limit = screenWidth >= 1920 ? 8 : (screenWidth >= 1600 ? 8 : (screenWidth >= 1200 ? 9 : 6));
|
|
||||||
limit = Math.min(limit, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
Limit: limit,
|
|
||||||
Recursive: true,
|
|
||||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
|
||||||
ImageTypeLimit: 1,
|
|
||||||
EnableImageTypes: 'Primary,Backdrop,Thumb',
|
|
||||||
EnableTotalRecordCount: false,
|
|
||||||
MediaTypes: 'Audio'
|
|
||||||
};
|
|
||||||
|
|
||||||
return apiClient.getResumableItems(apiClient.getCurrentUserId(), options);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getContinueListeningItemsHtml(items) {
|
|
||||||
const cardLayout = false;
|
|
||||||
return cardBuilder.getCardsHtml({
|
|
||||||
items: items,
|
|
||||||
preferThumb: true,
|
|
||||||
shape: getThumbShape(),
|
|
||||||
overlayText: false,
|
|
||||||
showTitle: true,
|
|
||||||
showParentTitle: true,
|
|
||||||
lazy: true,
|
|
||||||
showDetailsMenu: true,
|
|
||||||
overlayPlayButton: true,
|
|
||||||
context: 'home',
|
|
||||||
centerText: !cardLayout,
|
|
||||||
allowBottomPadding: false,
|
|
||||||
cardLayout: cardLayout,
|
|
||||||
showYear: true,
|
|
||||||
lines: 2
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadResumeAudio(elem, apiClient) {
|
|
||||||
let html = '';
|
|
||||||
|
|
||||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueListening') + '</h2>';
|
|
||||||
if (enableScrollX()) {
|
|
||||||
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
|
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x" data-monitor="audioplayback,markplayed">';
|
|
||||||
} else {
|
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-monitor="audioplayback,markplayed">';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableScrollX()) {
|
|
||||||
html += '</div>';
|
|
||||||
}
|
|
||||||
html += '</div>';
|
|
||||||
|
|
||||||
elem.classList.add('hide');
|
|
||||||
elem.innerHTML = html;
|
|
||||||
|
|
||||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
|
||||||
itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId());
|
|
||||||
itemsContainer.getItemsHtml = getContinueListeningItemsHtml;
|
|
||||||
itemsContainer.parentContainer = elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOnNowFetchFn(serverId) {
|
function getOnNowFetchFn(serverId) {
|
||||||
return function () {
|
return function () {
|
||||||
const apiClient = ServerConnections.getApiClient(serverId);
|
const apiClient = ServerConnections.getApiClient(serverId);
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"Folders": "Folders",
|
"Folders": "Folders",
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"HeaderAlbumArtists": "Album Artists",
|
"HeaderAlbumArtists": "Album Artists",
|
||||||
|
"HeaderContinueReading": "Continue Reading",
|
||||||
"HeaderContinueWatching": "Continue Watching",
|
"HeaderContinueWatching": "Continue Watching",
|
||||||
"Movies": "Movies",
|
"Movies": "Movies",
|
||||||
"Photos": "Photos",
|
"Photos": "Photos",
|
||||||
|
|
|
@ -321,6 +321,7 @@
|
||||||
"HeaderContainerProfileHelp": "Container profiles indicate the limitations of a device when playing specific formats. If a limitation applies then the media will be transcoded, even if the format is configured for direct play.",
|
"HeaderContainerProfileHelp": "Container profiles indicate the limitations of a device when playing specific formats. If a limitation applies then the media will be transcoded, even if the format is configured for direct play.",
|
||||||
"HeaderContinueListening": "Continue Listening",
|
"HeaderContinueListening": "Continue Listening",
|
||||||
"HeaderContinueWatching": "Continue Watching",
|
"HeaderContinueWatching": "Continue Watching",
|
||||||
|
"HeaderContinueReading": "Continue Reading",
|
||||||
"HeaderCustomDlnaProfiles": "Custom Profiles",
|
"HeaderCustomDlnaProfiles": "Custom Profiles",
|
||||||
"HeaderDateIssued": "Date Issued",
|
"HeaderDateIssued": "Date Issued",
|
||||||
"HeaderDebugging": "Debugging and Tracing",
|
"HeaderDebugging": "Debugging and Tracing",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue