Update:Continue Reading and Read Again home page shelves for ebook only items #1782

This commit is contained in:
advplyr 2023-05-27 08:20:09 -05:00
parent 1da471e136
commit 3e4c94e2b4
16 changed files with 132 additions and 95 deletions

View File

@ -256,14 +256,14 @@ export default {
}, },
booksInSeries() { booksInSeries() {
// Only added to item object when collapseSeries is enabled // Only added to item object when collapseSeries is enabled
return this.collapsedSeries ? this.collapsedSeries.numBooks : 0 return this.collapsedSeries?.numBooks || 0
}, },
seriesSequenceList() { seriesSequenceList() {
return this.collapsedSeries ? this.collapsedSeries.seriesSequenceList : null return this.collapsedSeries?.seriesSequenceList || null
}, },
libraryItemIdsInSeries() { libraryItemIdsInSeries() {
// Only added to item object when collapseSeries is enabled // Only added to item object when collapseSeries is enabled
return this.collapsedSeries ? this.collapsedSeries.libraryItemIds || [] : [] return this.collapsedSeries?.libraryItemIds || []
}, },
hasCover() { hasCover() {
return !!this.media.coverPath return !!this.media.coverPath

View File

@ -197,6 +197,7 @@
"LabelComplete": "Vollständig", "LabelComplete": "Vollständig",
"LabelConfirmPassword": "Passwort bestätigen", "LabelConfirmPassword": "Passwort bestätigen",
"LabelContinueListening": "Weiterhören", "LabelContinueListening": "Weiterhören",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Serien fortsetzen", "LabelContinueSeries": "Serien fortsetzen",
"LabelCover": "Titelbild", "LabelCover": "Titelbild",
"LabelCoverImageURL": "URL des Titelbildes", "LabelCoverImageURL": "URL des Titelbildes",
@ -331,6 +332,7 @@
"LabelPubDate": "Veröffentlichungsdatum", "LabelPubDate": "Veröffentlichungsdatum",
"LabelPublisher": "Herausgeber", "LabelPublisher": "Herausgeber",
"LabelPublishYear": "Jahr", "LabelPublishYear": "Jahr",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Kürzlich hinzugefügt", "LabelRecentlyAdded": "Kürzlich hinzugefügt",
"LabelRecentSeries": "Aktuelle Serien", "LabelRecentSeries": "Aktuelle Serien",
"LabelRecommended": "Empfohlen", "LabelRecommended": "Empfohlen",
@ -654,4 +656,4 @@
"ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen", "ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen",
"ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden", "ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden",
"ToastUserDeleteSuccess": "Benutzer gelöscht" "ToastUserDeleteSuccess": "Benutzer gelöscht"
} }

View File

@ -197,6 +197,7 @@
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
"LabelContinueListening": "Continue Listening", "LabelContinueListening": "Continue Listening",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continue Series", "LabelContinueSeries": "Continue Series",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Cover Image URL", "LabelCoverImageURL": "Cover Image URL",
@ -331,6 +332,7 @@
"LabelPubDate": "Pub Date", "LabelPubDate": "Pub Date",
"LabelPublisher": "Publisher", "LabelPublisher": "Publisher",
"LabelPublishYear": "Publish Year", "LabelPublishYear": "Publish Year",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Recently Added", "LabelRecentlyAdded": "Recently Added",
"LabelRecentSeries": "Recent Series", "LabelRecentSeries": "Recent Series",
"LabelRecommended": "Recommended", "LabelRecommended": "Recommended",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Completo", "LabelComplete": "Completo",
"LabelConfirmPassword": "Confirmar Contraseña", "LabelConfirmPassword": "Confirmar Contraseña",
"LabelContinueListening": "Continuar Escuchando", "LabelContinueListening": "Continuar Escuchando",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continuar Series", "LabelContinueSeries": "Continuar Series",
"LabelCover": "Portada", "LabelCover": "Portada",
"LabelCoverImageURL": "URL de Imagen de Portada", "LabelCoverImageURL": "URL de Imagen de Portada",
@ -331,6 +332,7 @@
"LabelPubDate": "Fecha de Publicación", "LabelPubDate": "Fecha de Publicación",
"LabelPublisher": "Editor", "LabelPublisher": "Editor",
"LabelPublishYear": "Año de Publicación", "LabelPublishYear": "Año de Publicación",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Agregado Reciente", "LabelRecentlyAdded": "Agregado Reciente",
"LabelRecentSeries": "Series Recientes", "LabelRecentSeries": "Series Recientes",
"LabelRecommended": "Recomendados", "LabelRecommended": "Recomendados",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Complet", "LabelComplete": "Complet",
"LabelConfirmPassword": "Confirmer le mot de passe", "LabelConfirmPassword": "Confirmer le mot de passe",
"LabelContinueListening": "Continuer la lecture", "LabelContinueListening": "Continuer la lecture",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continuer la série", "LabelContinueSeries": "Continuer la série",
"LabelCover": "Couverture", "LabelCover": "Couverture",
"LabelCoverImageURL": "URL vers limage de couverture", "LabelCoverImageURL": "URL vers limage de couverture",
@ -331,6 +332,7 @@
"LabelPubDate": "Date de publication", "LabelPubDate": "Date de publication",
"LabelPublisher": "Éditeur", "LabelPublisher": "Éditeur",
"LabelPublishYear": "Année dédition", "LabelPublishYear": "Année dédition",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Derniers ajouts", "LabelRecentlyAdded": "Derniers ajouts",
"LabelRecentSeries": "Séries récentes", "LabelRecentSeries": "Séries récentes",
"LabelRecommended": "Recommandé", "LabelRecommended": "Recommandé",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
"LabelContinueListening": "Continue Listening", "LabelContinueListening": "Continue Listening",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continue Series", "LabelContinueSeries": "Continue Series",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Cover Image URL", "LabelCoverImageURL": "Cover Image URL",
@ -331,6 +332,7 @@
"LabelPubDate": "Pub Date", "LabelPubDate": "Pub Date",
"LabelPublisher": "Publisher", "LabelPublisher": "Publisher",
"LabelPublishYear": "Publish Year", "LabelPublishYear": "Publish Year",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Recently Added", "LabelRecentlyAdded": "Recently Added",
"LabelRecentSeries": "Recent Series", "LabelRecentSeries": "Recent Series",
"LabelRecommended": "Recommended", "LabelRecommended": "Recommended",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
"LabelContinueListening": "Continue Listening", "LabelContinueListening": "Continue Listening",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continue Series", "LabelContinueSeries": "Continue Series",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Cover Image URL", "LabelCoverImageURL": "Cover Image URL",
@ -331,6 +332,7 @@
"LabelPubDate": "Pub Date", "LabelPubDate": "Pub Date",
"LabelPublisher": "Publisher", "LabelPublisher": "Publisher",
"LabelPublishYear": "Publish Year", "LabelPublishYear": "Publish Year",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Recently Added", "LabelRecentlyAdded": "Recently Added",
"LabelRecentSeries": "Recent Series", "LabelRecentSeries": "Recent Series",
"LabelRecommended": "Recommended", "LabelRecommended": "Recommended",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Potvrdi lozinku", "LabelConfirmPassword": "Potvrdi lozinku",
"LabelContinueListening": "Nastavi slušanje", "LabelContinueListening": "Nastavi slušanje",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Nastavi seriju", "LabelContinueSeries": "Nastavi seriju",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "URL od covera", "LabelCoverImageURL": "URL od covera",
@ -331,6 +332,7 @@
"LabelPubDate": "Datam izdavanja", "LabelPubDate": "Datam izdavanja",
"LabelPublisher": "Izdavač", "LabelPublisher": "Izdavač",
"LabelPublishYear": "Godina izdavanja", "LabelPublishYear": "Godina izdavanja",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Nedavno dodano", "LabelRecentlyAdded": "Nedavno dodano",
"LabelRecentSeries": "Nedavne serije", "LabelRecentSeries": "Nedavne serije",
"LabelRecommended": "Recommended", "LabelRecommended": "Recommended",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Completo", "LabelComplete": "Completo",
"LabelConfirmPassword": "Conferma Password", "LabelConfirmPassword": "Conferma Password",
"LabelContinueListening": "Continua ad Ascoltare", "LabelContinueListening": "Continua ad Ascoltare",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Continua Serie", "LabelContinueSeries": "Continua Serie",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Cover Image URL", "LabelCoverImageURL": "Cover Image URL",
@ -331,6 +332,7 @@
"LabelPubDate": "Data Pubblicazione", "LabelPubDate": "Data Pubblicazione",
"LabelPublisher": "Editore", "LabelPublisher": "Editore",
"LabelPublishYear": "Anno Pubblicazione", "LabelPublishYear": "Anno Pubblicazione",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Aggiunti Recentemente", "LabelRecentlyAdded": "Aggiunti Recentemente",
"LabelRecentSeries": "Serie Recenti", "LabelRecentSeries": "Serie Recenti",
"LabelRecommended": "Raccomandati", "LabelRecommended": "Raccomandati",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Compleet", "LabelComplete": "Compleet",
"LabelConfirmPassword": "Bevestig wachtwoord", "LabelConfirmPassword": "Bevestig wachtwoord",
"LabelContinueListening": "Verder luisteren", "LabelContinueListening": "Verder luisteren",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Ga verder met serie", "LabelContinueSeries": "Ga verder met serie",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Coverafbeelding URL", "LabelCoverImageURL": "Coverafbeelding URL",
@ -331,6 +332,7 @@
"LabelPubDate": "Publicatiedatum", "LabelPubDate": "Publicatiedatum",
"LabelPublisher": "Uitgever", "LabelPublisher": "Uitgever",
"LabelPublishYear": "Jaar van uitgave", "LabelPublishYear": "Jaar van uitgave",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Recent toegevoegd", "LabelRecentlyAdded": "Recent toegevoegd",
"LabelRecentSeries": "Recente series", "LabelRecentSeries": "Recente series",
"LabelRecommended": "Aangeraden", "LabelRecommended": "Aangeraden",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Ukończone", "LabelComplete": "Ukończone",
"LabelConfirmPassword": "Potwierdź hasło", "LabelConfirmPassword": "Potwierdź hasło",
"LabelContinueListening": "Kontynuuj odtwarzanie", "LabelContinueListening": "Kontynuuj odtwarzanie",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Kontynuuj serię", "LabelContinueSeries": "Kontynuuj serię",
"LabelCover": "Okładka", "LabelCover": "Okładka",
"LabelCoverImageURL": "URL okładki", "LabelCoverImageURL": "URL okładki",
@ -331,6 +332,7 @@
"LabelPubDate": "Data publikacji", "LabelPubDate": "Data publikacji",
"LabelPublisher": "Wydawca", "LabelPublisher": "Wydawca",
"LabelPublishYear": "Rok publikacji", "LabelPublishYear": "Rok publikacji",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Niedawno dodany", "LabelRecentlyAdded": "Niedawno dodany",
"LabelRecentSeries": "Ostatnie serie", "LabelRecentSeries": "Ostatnie serie",
"LabelRecommended": "Recommended", "LabelRecommended": "Recommended",

View File

@ -197,6 +197,7 @@
"LabelComplete": "Завершить", "LabelComplete": "Завершить",
"LabelConfirmPassword": "Подтвердить пароль", "LabelConfirmPassword": "Подтвердить пароль",
"LabelContinueListening": "Продолжить слушать", "LabelContinueListening": "Продолжить слушать",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "Продолжить серию", "LabelContinueSeries": "Продолжить серию",
"LabelCover": "Обложка", "LabelCover": "Обложка",
"LabelCoverImageURL": "URL изображения обложки", "LabelCoverImageURL": "URL изображения обложки",
@ -331,6 +332,7 @@
"LabelPubDate": "Дата публикации", "LabelPubDate": "Дата публикации",
"LabelPublisher": "Издатель", "LabelPublisher": "Издатель",
"LabelPublishYear": "Год публикации", "LabelPublishYear": "Год публикации",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "Недавно добавленные", "LabelRecentlyAdded": "Недавно добавленные",
"LabelRecentSeries": "Последние серии", "LabelRecentSeries": "Последние серии",
"LabelRecommended": "Рекомендованное", "LabelRecommended": "Рекомендованное",

View File

@ -197,6 +197,7 @@
"LabelComplete": "已完成", "LabelComplete": "已完成",
"LabelConfirmPassword": "确认密码", "LabelConfirmPassword": "确认密码",
"LabelContinueListening": "继续收听", "LabelContinueListening": "继续收听",
"LabelContinueReading": "Continue Reading",
"LabelContinueSeries": "继续收听系列", "LabelContinueSeries": "继续收听系列",
"LabelCover": "封面", "LabelCover": "封面",
"LabelCoverImageURL": "封面图像 URL", "LabelCoverImageURL": "封面图像 URL",
@ -331,6 +332,7 @@
"LabelPubDate": "出版日期", "LabelPubDate": "出版日期",
"LabelPublisher": "出版商", "LabelPublisher": "出版商",
"LabelPublishYear": "发布年份", "LabelPublishYear": "发布年份",
"LabelReadAgain": "Read Again",
"LabelRecentlyAdded": "最近添加", "LabelRecentlyAdded": "最近添加",
"LabelRecentSeries": "最近添加系列", "LabelRecentSeries": "最近添加系列",
"LabelRecommended": "推荐内容", "LabelRecommended": "推荐内容",

View File

@ -142,6 +142,9 @@ class Book {
get numTracks() { get numTracks() {
return this.tracks.length return this.tracks.length
} }
get isEBookOnly() {
return this.ebookFile && !this.numTracks
}
update(payload) { update(payload) {
const json = this.toJSON() const json = this.toJSON()

View File

@ -57,7 +57,7 @@ class MediaProgress {
} }
get inProgress() { get inProgress() {
return !this.isFinished && (this.progress > 0 || this.ebookLocation != null) return !this.isFinished && (this.progress > 0 || (this.ebookLocation != null && this.ebookProgress > 0))
} }
setData(libraryItemId, progress, episodeId = null) { setData(libraryItemId, progress, episodeId = null) {

View File

@ -346,71 +346,77 @@ module.exports = {
label: 'Continue Listening', label: 'Continue Listening',
labelStringKey: 'LabelContinueListening', labelStringKey: 'LabelContinueListening',
type: isPodcastLibrary ? 'episode' : mediaType, type: isPodcastLibrary ? 'episode' : mediaType,
entities: [], entities: []
category: 'recentlyListened' },
{
id: 'continue-reading',
label: 'Continue Reading',
labelStringKey: 'LabelContinueReading',
type: 'book',
entities: []
}, },
{ {
id: 'continue-series', id: 'continue-series',
label: 'Continue Series', label: 'Continue Series',
labelStringKey: 'LabelContinueSeries', labelStringKey: 'LabelContinueSeries',
type: mediaType, type: mediaType,
entities: [], entities: []
category: 'continueSeries'
}, },
{ {
id: 'episodes-recently-added', id: 'episodes-recently-added',
label: 'Newest Episodes', label: 'Newest Episodes',
labelStringKey: 'LabelNewestEpisodes', labelStringKey: 'LabelNewestEpisodes',
type: 'episode', type: 'episode',
entities: [], entities: []
category: 'newestEpisodes'
}, },
{ {
id: 'recently-added', id: 'recently-added',
label: 'Recently Added', label: 'Recently Added',
labelStringKey: 'LabelRecentlyAdded', labelStringKey: 'LabelRecentlyAdded',
type: mediaType, type: mediaType,
entities: [], entities: []
category: 'newestItems'
}, },
{ {
id: 'recent-series', id: 'recent-series',
label: 'Recent Series', label: 'Recent Series',
labelStringKey: 'LabelRecentSeries', labelStringKey: 'LabelRecentSeries',
type: 'series', type: 'series',
entities: [], entities: []
category: 'newestSeries'
}, },
{ {
id: 'recommended', id: 'recommended',
label: 'Recommended', label: 'Recommended',
labelStringKey: 'LabelRecommended', labelStringKey: 'LabelRecommended',
type: mediaType, type: mediaType,
entities: [], entities: []
category: 'recommended'
}, },
{ {
id: 'listen-again', id: 'listen-again',
label: 'Listen Again', label: 'Listen Again',
labelStringKey: 'LabelListenAgain', labelStringKey: 'LabelListenAgain',
type: isPodcastLibrary ? 'episode' : mediaType, type: isPodcastLibrary ? 'episode' : mediaType,
entities: [], entities: []
category: 'recentlyFinished' },
{
id: 'read-again',
label: 'Read Again',
labelStringKey: 'LabelReadAgain',
type: 'book',
entities: []
}, },
{ {
id: 'newest-authors', id: 'newest-authors',
label: 'Newest Authors', label: 'Newest Authors',
labelStringKey: 'LabelNewestAuthors', labelStringKey: 'LabelNewestAuthors',
type: 'authors', type: 'authors',
entities: [], entities: []
category: 'newestAuthors'
} }
] ]
const categoryMap = {} const categoryMap = {}
shelves.forEach((shelf) => { shelves.forEach((shelf) => {
categoryMap[shelf.category] = { categoryMap[shelf.id] = {
category: shelf.category, id: shelf.id,
biggest: 0, biggest: 0,
smallest: 0, smallest: 0,
items: [] items: []
@ -427,21 +433,21 @@ module.exports = {
const notStartedBooks = [] const notStartedBooks = []
for (const libraryItem of libraryItems) { for (const libraryItem of libraryItems) {
if (libraryItem.addedAt > categoryMap.newestItems.smallest) { if (libraryItem.addedAt > categoryMap['recently-added'].smallest) {
const indexToPut = categoryMap.newestItems.items.findIndex(i => libraryItem.addedAt > i.addedAt) const indexToPut = categoryMap['recently-added'].items.findIndex(i => libraryItem.addedAt > i.addedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.newestItems.items.splice(indexToPut, 0, libraryItem.toJSONMinified()) categoryMap['recently-added'].items.splice(indexToPut, 0, libraryItem.toJSONMinified())
} else { } else {
categoryMap.newestItems.items.push(libraryItem.toJSONMinified()) categoryMap['recently-added'].items.push(libraryItem.toJSONMinified())
} }
if (categoryMap.newestItems.items.length > maxEntitiesPerShelf) { if (categoryMap['recently-added'].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.newestItems.items.pop() categoryMap['recently-added'].items.pop()
categoryMap.newestItems.smallest = categoryMap.newestItems.items[categoryMap.newestItems.items.length - 1].addedAt categoryMap['recently-added'].smallest = categoryMap['recently-added'].items[categoryMap['recently-added'].items.length - 1].addedAt
} }
categoryMap.newestItems.biggest = categoryMap.newestItems.items[0].addedAt categoryMap['recently-added'].biggest = categoryMap['recently-added'].items[0].addedAt
} }
const allItemProgress = user.getAllMediaProgressForLibraryItem(libraryItem.id) const allItemProgress = user.getAllMediaProgressForLibraryItem(libraryItem.id)
@ -450,74 +456,74 @@ module.exports = {
const podcastEpisodes = libraryItem.media.episodes || [] const podcastEpisodes = libraryItem.media.episodes || []
for (const episode of podcastEpisodes) { for (const episode of podcastEpisodes) {
// Newest episodes // Newest episodes
if (episode.addedAt > categoryMap.newestEpisodes.smallest) { if (episode.addedAt > categoryMap['episodes-recently-added'].smallest) {
const libraryItemWithEpisode = { const libraryItemWithEpisode = {
...libraryItem.toJSONMinified(), ...libraryItem.toJSONMinified(),
recentEpisode: episode.toJSON() recentEpisode: episode.toJSON()
} }
const indexToPut = categoryMap.newestEpisodes.items.findIndex(i => episode.addedAt > i.recentEpisode.addedAt) const indexToPut = categoryMap['episodes-recently-added'].items.findIndex(i => episode.addedAt > i.recentEpisode.addedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.newestEpisodes.items.splice(indexToPut, 0, libraryItemWithEpisode) categoryMap['episodes-recently-added'].items.splice(indexToPut, 0, libraryItemWithEpisode)
} else { } else {
categoryMap.newestEpisodes.items.push(libraryItemWithEpisode) categoryMap['episodes-recently-added'].items.push(libraryItemWithEpisode)
} }
if (categoryMap.newestEpisodes.items.length > maxEntitiesPerShelf) { if (categoryMap['episodes-recently-added'].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.newestEpisodes.items.pop() categoryMap['episodes-recently-added'].items.pop()
categoryMap.newestEpisodes.smallest = categoryMap.newestEpisodes.items[categoryMap.newestEpisodes.items.length - 1].recentEpisode.addedAt categoryMap['episodes-recently-added'].smallest = categoryMap['episodes-recently-added'].items[categoryMap['episodes-recently-added'].items.length - 1].recentEpisode.addedAt
} }
categoryMap.newestEpisodes.biggest = categoryMap.newestEpisodes.items[0].recentEpisode.addedAt categoryMap['episodes-recently-added'].biggest = categoryMap['episodes-recently-added'].items[0].recentEpisode.addedAt
} }
// Episode recently listened and finished // Episode recently listened and finished
const mediaProgress = allItemProgress.find(mp => mp.episodeId === episode.id) const mediaProgress = allItemProgress.find(mp => mp.episodeId === episode.id)
if (mediaProgress) { if (mediaProgress) {
if (mediaProgress.isFinished) { if (mediaProgress.isFinished) {
if (mediaProgress.finishedAt > categoryMap.recentlyFinished.smallest) { // Item belongs on shelf if (mediaProgress.finishedAt > categoryMap['listen-again'].smallest) { // Item belongs on shelf
const libraryItemWithEpisode = { const libraryItemWithEpisode = {
...libraryItem.toJSONMinified(), ...libraryItem.toJSONMinified(),
recentEpisode: episode.toJSON(), recentEpisode: episode.toJSON(),
finishedAt: mediaProgress.finishedAt finishedAt: mediaProgress.finishedAt
} }
const indexToPut = categoryMap.recentlyFinished.items.findIndex(i => mediaProgress.finishedAt > i.finishedAt) const indexToPut = categoryMap['listen-again'].items.findIndex(i => mediaProgress.finishedAt > i.finishedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.recentlyFinished.items.splice(indexToPut, 0, libraryItemWithEpisode) categoryMap['listen-again'].items.splice(indexToPut, 0, libraryItemWithEpisode)
} else { } else {
categoryMap.recentlyFinished.items.push(libraryItemWithEpisode) categoryMap['listen-again'].items.push(libraryItemWithEpisode)
} }
if (categoryMap.recentlyFinished.items.length > maxEntitiesPerShelf) { if (categoryMap['listen-again'].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.recentlyFinished.items.pop() categoryMap['listen-again'].items.pop()
categoryMap.recentlyFinished.smallest = categoryMap.recentlyFinished.items[categoryMap.recentlyFinished.items.length - 1].finishedAt categoryMap['listen-again'].smallest = categoryMap['listen-again'].items[categoryMap['listen-again'].items.length - 1].finishedAt
} }
categoryMap.recentlyFinished.biggest = categoryMap.recentlyFinished.items[0].finishedAt categoryMap['listen-again'].biggest = categoryMap['listen-again'].items[0].finishedAt
} }
} else if (mediaProgress.inProgress && !mediaProgress.hideFromContinueListening) { // Handle most recently listened } else if (mediaProgress.inProgress && !mediaProgress.hideFromContinueListening) { // Handle most recently listened
if (mediaProgress.lastUpdate > categoryMap.recentlyListened.smallest) { // Item belongs on shelf if (mediaProgress.lastUpdate > categoryMap['continue-listening'].smallest) { // Item belongs on shelf
const libraryItemWithEpisode = { const libraryItemWithEpisode = {
...libraryItem.toJSONMinified(), ...libraryItem.toJSONMinified(),
recentEpisode: episode.toJSON(), recentEpisode: episode.toJSON(),
progressLastUpdate: mediaProgress.lastUpdate progressLastUpdate: mediaProgress.lastUpdate
} }
const indexToPut = categoryMap.recentlyListened.items.findIndex(i => mediaProgress.lastUpdate > i.progressLastUpdate) const indexToPut = categoryMap['continue-listening'].items.findIndex(i => mediaProgress.lastUpdate > i.progressLastUpdate)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.recentlyListened.items.splice(indexToPut, 0, libraryItemWithEpisode) categoryMap['continue-listening'].items.splice(indexToPut, 0, libraryItemWithEpisode)
} else { } else {
categoryMap.recentlyListened.items.push(libraryItemWithEpisode) categoryMap['continue-listening'].items.push(libraryItemWithEpisode)
} }
if (categoryMap.recentlyListened.items.length > maxEntitiesPerShelf) { if (categoryMap['continue-listening'].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.recentlyListened.items.pop() categoryMap['continue-listening'].items.pop()
categoryMap.recentlyListened.smallest = categoryMap.recentlyListened.items[categoryMap.recentlyListened.items.length - 1].progressLastUpdate categoryMap['continue-listening'].smallest = categoryMap['continue-listening'].items[categoryMap['continue-listening'].items.length - 1].progressLastUpdate
} }
categoryMap.recentlyListened.biggest = categoryMap.recentlyListened.items[0].progressLastUpdate categoryMap['continue-listening'].biggest = categoryMap['continue-listening'].items[0].progressLastUpdate
} }
} }
} }
@ -568,21 +574,21 @@ module.exports = {
} }
seriesMap[librarySeries.id] = series seriesMap[librarySeries.id] = series
if (series.addedAt > categoryMap.newestSeries.smallest) { if (series.addedAt > categoryMap['recent-series'].smallest) {
const indexToPut = categoryMap.newestSeries.items.findIndex(i => series.addedAt > i.addedAt) const indexToPut = categoryMap['recent-series'].items.findIndex(i => series.addedAt > i.addedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.newestSeries.items.splice(indexToPut, 0, series) categoryMap['recent-series'].items.splice(indexToPut, 0, series)
} else { } else {
categoryMap.newestSeries.items.push(series) categoryMap['recent-series'].items.push(series)
} }
// Max series is 5 // Max series is 5
if (categoryMap.newestSeries.items.length > 5) { if (categoryMap['recent-series'].items.length > 5) {
categoryMap.newestSeries.items.pop() categoryMap['recent-series'].items.pop()
categoryMap.newestSeries.smallest = categoryMap.newestSeries.items[categoryMap.newestSeries.items.length - 1].addedAt categoryMap['recent-series'].smallest = categoryMap['recent-series'].items[categoryMap['recent-series'].items.length - 1].addedAt
} }
categoryMap.newestSeries.biggest = categoryMap.newestSeries.items[0].addedAt categoryMap['recent-series'].biggest = categoryMap['recent-series'].items[0].addedAt
} }
} }
} else { } else {
@ -624,22 +630,22 @@ module.exports = {
numBooks: 1 numBooks: 1
} }
if (author.addedAt > categoryMap.newestAuthors.smallest) { if (author.addedAt > categoryMap['newest-authors'].smallest) {
const indexToPut = categoryMap.newestAuthors.items.findIndex(i => author.addedAt > i.addedAt) const indexToPut = categoryMap['newest-authors'].items.findIndex(i => author.addedAt > i.addedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.newestAuthors.items.splice(indexToPut, 0, author) categoryMap['newest-authors'].items.splice(indexToPut, 0, author)
} else { } else {
categoryMap.newestAuthors.items.push(author) categoryMap['newest-authors'].items.push(author)
} }
// Max authors is 10 // Max authors is 10
if (categoryMap.newestAuthors.items.length > 10) { if (categoryMap['newest-authors'].items.length > 10) {
categoryMap.newestAuthors.items.pop() categoryMap['newest-authors'].items.pop()
categoryMap.newestAuthors.smallest = categoryMap.newestAuthors.items[categoryMap.newestAuthors.items.length - 1].addedAt categoryMap['newest-authors'].smallest = categoryMap['newest-authors'].items[categoryMap['newest-authors'].items.length - 1].addedAt
} }
categoryMap.newestAuthors.biggest = categoryMap.newestAuthors.items[0].addedAt categoryMap['newest-authors'].biggest = categoryMap['newest-authors'].items[0].addedAt
} }
authorMap[libraryAuthor.id] = author authorMap[libraryAuthor.id] = author
@ -652,46 +658,50 @@ module.exports = {
// Book listening and finished // Book listening and finished
if (mediaProgress) { if (mediaProgress) {
const categoryId = libraryItem.media.isEBookOnly ? 'read-again' : 'listen-again'
// Handle most recently finished // Handle most recently finished
if (mediaProgress.isFinished) { if (mediaProgress.isFinished) {
if (mediaProgress.finishedAt > categoryMap.recentlyFinished.smallest) { // Item belongs on shelf if (mediaProgress.finishedAt > categoryMap[categoryId].smallest) { // Item belongs on shelf
const libraryItemObj = { const libraryItemObj = {
...libraryItem.toJSONMinified(), ...libraryItem.toJSONMinified(),
finishedAt: mediaProgress.finishedAt finishedAt: mediaProgress.finishedAt
} }
const indexToPut = categoryMap.recentlyFinished.items.findIndex(i => mediaProgress.finishedAt > i.finishedAt) const indexToPut = categoryMap[categoryId].items.findIndex(i => mediaProgress.finishedAt > i.finishedAt)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.recentlyFinished.items.splice(indexToPut, 0, libraryItemObj) categoryMap[categoryId].items.splice(indexToPut, 0, libraryItemObj)
} else { } else {
categoryMap.recentlyFinished.items.push(libraryItemObj) categoryMap[categoryId].items.push(libraryItemObj)
} }
if (categoryMap.recentlyFinished.items.length > maxEntitiesPerShelf) { if (categoryMap[categoryId].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.recentlyFinished.items.pop() categoryMap[categoryId].items.pop()
categoryMap.recentlyFinished.smallest = categoryMap.recentlyFinished.items[categoryMap.recentlyFinished.items.length - 1].finishedAt categoryMap[categoryId].smallest = categoryMap[categoryId].items[categoryMap[categoryId].items.length - 1].finishedAt
} }
categoryMap.recentlyFinished.biggest = categoryMap.recentlyFinished.items[0].finishedAt categoryMap[categoryId].biggest = categoryMap[categoryId].items[0].finishedAt
} }
} else if (mediaProgress.inProgress && !mediaProgress.hideFromContinueListening) { // Handle most recently listened } else if (mediaProgress.inProgress && !mediaProgress.hideFromContinueListening) { // Handle most recently listened
if (mediaProgress.lastUpdate > categoryMap.recentlyListened.smallest) { // Item belongs on shelf const categoryId = libraryItem.media.isEBookOnly ? 'continue-reading' : 'continue-listening'
if (mediaProgress.lastUpdate > categoryMap[categoryId].smallest) { // Item belongs on shelf
const libraryItemObj = { const libraryItemObj = {
...libraryItem.toJSONMinified(), ...libraryItem.toJSONMinified(),
progressLastUpdate: mediaProgress.lastUpdate progressLastUpdate: mediaProgress.lastUpdate
} }
const indexToPut = categoryMap.recentlyListened.items.findIndex(i => mediaProgress.lastUpdate > i.progressLastUpdate) const indexToPut = categoryMap[categoryId].items.findIndex(i => mediaProgress.lastUpdate > i.progressLastUpdate)
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.recentlyListened.items.splice(indexToPut, 0, libraryItemObj) categoryMap[categoryId].items.splice(indexToPut, 0, libraryItemObj)
} else { // Should only happen when array is < max } else { // Should only happen when array is < max
categoryMap.recentlyListened.items.push(libraryItemObj) categoryMap[categoryId].items.push(libraryItemObj)
} }
if (categoryMap.recentlyListened.items.length > maxEntitiesPerShelf) { if (categoryMap[categoryId].items.length > maxEntitiesPerShelf) {
// Remove last item // Remove last item
categoryMap.recentlyListened.items.pop() categoryMap[categoryId].items.pop()
categoryMap.recentlyListened.smallest = categoryMap.recentlyListened.items[categoryMap.recentlyListened.items.length - 1].progressLastUpdate categoryMap[categoryId].smallest = categoryMap[categoryId].items[categoryMap[categoryId].items.length - 1].progressLastUpdate
} }
categoryMap.recentlyListened.biggest = categoryMap.recentlyListened.items[0].progressLastUpdate categoryMap[categoryId].biggest = categoryMap[categoryId].items[0].progressLastUpdate
} }
} }
} }
@ -719,12 +729,12 @@ module.exports = {
sequence: nextBookInSeries.seriesSequence sequence: nextBookInSeries.seriesSequence
} }
const indexToPut = categoryMap.continueSeries.items.findIndex(i => i.prevBookInProgressLastUpdate < bookForContinueSeries.prevBookInProgressLastUpdate) const indexToPut = categoryMap['continue-series'].items.findIndex(i => i.prevBookInProgressLastUpdate < bookForContinueSeries.prevBookInProgressLastUpdate)
if (!categoryMap.continueSeries.items.find(book => book.id === bookForContinueSeries.id)) { if (!categoryMap['continue-series'].items.find(book => book.id === bookForContinueSeries.id)) {
if (indexToPut >= 0) { if (indexToPut >= 0) {
categoryMap.continueSeries.items.splice(indexToPut, 0, bookForContinueSeries) categoryMap['continue-series'].items.splice(indexToPut, 0, bookForContinueSeries)
} else if (categoryMap.continueSeries.items.length < 10) { // Max 10 books } else if (categoryMap['continue-series'].items.length < 10) { // Max 10 books
categoryMap.continueSeries.items.push(bookForContinueSeries) categoryMap['continue-series'].items.push(bookForContinueSeries)
} }
} }
} }
@ -802,8 +812,8 @@ module.exports = {
} }
// Sort series books by sequence // Sort series books by sequence
if (categoryMap.newestSeries.items.length) { if (categoryMap['recent-series'].items.length) {
for (const seriesItem of categoryMap.newestSeries.items) { for (const seriesItem of categoryMap['recent-series'].items) {
seriesItem.books = naturalSort(seriesItem.books).asc(li => li.seriesSequence) seriesItem.books = naturalSort(seriesItem.books).asc(li => li.seriesSequence)
} }
} }
@ -811,7 +821,7 @@ module.exports = {
const categoriesWithItems = Object.values(categoryMap).filter(cat => cat.items.length) const categoriesWithItems = Object.values(categoryMap).filter(cat => cat.items.length)
return categoriesWithItems.map(cat => { return categoriesWithItems.map(cat => {
const shelf = shelves.find(s => s.category === cat.category) const shelf = shelves.find(s => s.id === cat.id)
shelf.entities = cat.items shelf.entities = cat.items
// Add rssFeed to entities if query string "include=rssfeed" was on request // Add rssFeed to entities if query string "include=rssfeed" was on request