mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-05-31 04:05:40 -04:00
Add remaining personalized shelf queries, update book libraries home page to use new API endpoint
This commit is contained in:
parent
80b3bfea51
commit
09eefae808
@ -68,6 +68,9 @@ export default {
|
|||||||
currentLibraryId() {
|
currentLibraryId() {
|
||||||
return this.$store.state.libraries.currentLibraryId
|
return this.$store.state.libraries.currentLibraryId
|
||||||
},
|
},
|
||||||
|
currentLibraryMediaType() {
|
||||||
|
return this.$store.getters['libraries/getCurrentLibraryMediaType']
|
||||||
|
},
|
||||||
libraryName() {
|
libraryName() {
|
||||||
return this.$store.getters['libraries/getCurrentLibraryName']
|
return this.$store.getters['libraries/getCurrentLibraryName']
|
||||||
},
|
},
|
||||||
@ -167,8 +170,9 @@ export default {
|
|||||||
this.loaded = true
|
this.loaded = true
|
||||||
},
|
},
|
||||||
async fetchCategories() {
|
async fetchCategories() {
|
||||||
|
const endpoint = this.currentLibraryMediaType === 'book' ? 'personalized2' : 'personalized'
|
||||||
const categories = await this.$axios
|
const categories = await this.$axios
|
||||||
.$get(`/api/libraries/${this.currentLibraryId}/personalized?include=rssfeed,numEpisodesIncomplete`)
|
.$get(`/api/libraries/${this.currentLibraryId}/${endpoint}?include=rssfeed,numEpisodesIncomplete`)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
@ -346,8 +350,6 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
episodeAdded(episodeWithLibraryItem) {
|
episodeAdded(episodeWithLibraryItem) {
|
||||||
console.log('Podcast episode added', episodeWithLibraryItem)
|
|
||||||
|
|
||||||
const isThisLibrary = episodeWithLibraryItem.libraryItem?.libraryId === this.currentLibraryId
|
const isThisLibrary = episodeWithLibraryItem.libraryItem?.libraryId === this.currentLibraryId
|
||||||
if (!this.search && isThisLibrary) {
|
if (!this.search && isThisLibrary) {
|
||||||
this.fetchCategories()
|
this.fetchCategories()
|
||||||
|
@ -348,6 +348,10 @@ export default {
|
|||||||
},
|
},
|
||||||
tracks() {
|
tracks() {
|
||||||
return [
|
return [
|
||||||
|
{
|
||||||
|
id: 'none',
|
||||||
|
name: this.$strings.LabelTracksNone
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'single',
|
id: 'single',
|
||||||
name: this.$strings.LabelTracksSingleTrack
|
name: this.$strings.LabelTracksSingleTrack
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Verzeichnis",
|
"LabelDirectory": "Verzeichnis",
|
||||||
"LabelDiscFromFilename": "CD aus dem Dateinamen",
|
"LabelDiscFromFilename": "CD aus dem Dateinamen",
|
||||||
"LabelDiscFromMetadata": "CD aus den Metadaten",
|
"LabelDiscFromMetadata": "CD aus den Metadaten",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Herunterladen",
|
"LabelDownload": "Herunterladen",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Laufzeit",
|
"LabelDuration": "Laufzeit",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Titel aus Metadaten",
|
"LabelTrackFromMetadata": "Titel aus Metadaten",
|
||||||
"LabelTracks": "Dateien",
|
"LabelTracks": "Dateien",
|
||||||
"LabelTracksMultiTrack": "Mehrfachdatei",
|
"LabelTracksMultiTrack": "Mehrfachdatei",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Einzeldatei",
|
"LabelTracksSingleTrack": "Einzeldatei",
|
||||||
"LabelType": "Typ",
|
"LabelType": "Typ",
|
||||||
"LabelUnabridged": "Ungekürzt",
|
"LabelUnabridged": "Ungekürzt",
|
||||||
@ -702,4 +704,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"
|
||||||
}
|
}
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Directory",
|
"LabelDirectory": "Directory",
|
||||||
"LabelDiscFromFilename": "Disc from Filename",
|
"LabelDiscFromFilename": "Disc from Filename",
|
||||||
"LabelDiscFromMetadata": "Disc from Metadata",
|
"LabelDiscFromMetadata": "Disc from Metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Track from Metadata",
|
"LabelTrackFromMetadata": "Track from Metadata",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Directorio",
|
"LabelDirectory": "Directorio",
|
||||||
"LabelDiscFromFilename": "Disco a partir del Nombre del Archivo",
|
"LabelDiscFromFilename": "Disco a partir del Nombre del Archivo",
|
||||||
"LabelDiscFromMetadata": "Disco a partir de Metadata",
|
"LabelDiscFromMetadata": "Disco a partir de Metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Descargar",
|
"LabelDownload": "Descargar",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Duración",
|
"LabelDuration": "Duración",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Pista desde Metadata",
|
"LabelTrackFromMetadata": "Pista desde Metadata",
|
||||||
"LabelTracks": "Pistas",
|
"LabelTracks": "Pistas",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Tipo",
|
"LabelType": "Tipo",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Répertoire",
|
"LabelDirectory": "Répertoire",
|
||||||
"LabelDiscFromFilename": "Disque depuis le fichier",
|
"LabelDiscFromFilename": "Disque depuis le fichier",
|
||||||
"LabelDiscFromMetadata": "Disque depuis les métadonnées",
|
"LabelDiscFromMetadata": "Disque depuis les métadonnées",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Téléchargement",
|
"LabelDownload": "Téléchargement",
|
||||||
"LabelDownloadNEpisodes": "Télécharger {0} épisode(s)",
|
"LabelDownloadNEpisodes": "Télécharger {0} épisode(s)",
|
||||||
"LabelDuration": "Durée",
|
"LabelDuration": "Durée",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Piste depuis les métadonnées",
|
"LabelTrackFromMetadata": "Piste depuis les métadonnées",
|
||||||
"LabelTracks": "Pistes",
|
"LabelTracks": "Pistes",
|
||||||
"LabelTracksMultiTrack": "Piste multiple",
|
"LabelTracksMultiTrack": "Piste multiple",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Piste simple",
|
"LabelTracksSingleTrack": "Piste simple",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Version intégrale",
|
"LabelUnabridged": "Version intégrale",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Directory",
|
"LabelDirectory": "Directory",
|
||||||
"LabelDiscFromFilename": "Disc from Filename",
|
"LabelDiscFromFilename": "Disc from Filename",
|
||||||
"LabelDiscFromMetadata": "Disc from Metadata",
|
"LabelDiscFromMetadata": "Disc from Metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Track from Metadata",
|
"LabelTrackFromMetadata": "Track from Metadata",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Directory",
|
"LabelDirectory": "Directory",
|
||||||
"LabelDiscFromFilename": "Disc from Filename",
|
"LabelDiscFromFilename": "Disc from Filename",
|
||||||
"LabelDiscFromMetadata": "Disc from Metadata",
|
"LabelDiscFromMetadata": "Disc from Metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Duration",
|
"LabelDuration": "Duration",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Track from Metadata",
|
"LabelTrackFromMetadata": "Track from Metadata",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Direktorij",
|
"LabelDirectory": "Direktorij",
|
||||||
"LabelDiscFromFilename": "CD iz imena datoteke",
|
"LabelDiscFromFilename": "CD iz imena datoteke",
|
||||||
"LabelDiscFromMetadata": "CD iz metapodataka",
|
"LabelDiscFromMetadata": "CD iz metapodataka",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Preuzmi",
|
"LabelDownload": "Preuzmi",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Trajanje",
|
"LabelDuration": "Trajanje",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Track iz metapodataka",
|
"LabelTrackFromMetadata": "Track iz metapodataka",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Tip",
|
"LabelType": "Tip",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Elenco",
|
"LabelDirectory": "Elenco",
|
||||||
"LabelDiscFromFilename": "Disco dal nome file",
|
"LabelDiscFromFilename": "Disco dal nome file",
|
||||||
"LabelDiscFromMetadata": "Disco dal Metadata",
|
"LabelDiscFromMetadata": "Disco dal Metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Durata",
|
"LabelDuration": "Durata",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Traccia da Metadata",
|
"LabelTrackFromMetadata": "Traccia da Metadata",
|
||||||
"LabelTracks": "Traccia",
|
"LabelTracks": "Traccia",
|
||||||
"LabelTracksMultiTrack": "Multi-traccia",
|
"LabelTracksMultiTrack": "Multi-traccia",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Traccia-singola",
|
"LabelTracksSingleTrack": "Traccia-singola",
|
||||||
"LabelType": "Tipo",
|
"LabelType": "Tipo",
|
||||||
"LabelUnabridged": "Integrale",
|
"LabelUnabridged": "Integrale",
|
||||||
@ -702,4 +704,4 @@
|
|||||||
"ToastSocketFailedToConnect": "Socket non riesce a connettersi",
|
"ToastSocketFailedToConnect": "Socket non riesce a connettersi",
|
||||||
"ToastUserDeleteFailed": "Errore eliminazione utente",
|
"ToastUserDeleteFailed": "Errore eliminazione utente",
|
||||||
"ToastUserDeleteSuccess": "Utente eliminato"
|
"ToastUserDeleteSuccess": "Utente eliminato"
|
||||||
}
|
}
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Katalogas",
|
"LabelDirectory": "Katalogas",
|
||||||
"LabelDiscFromFilename": "Diskas pagal failo pavadinimą",
|
"LabelDiscFromFilename": "Diskas pagal failo pavadinimą",
|
||||||
"LabelDiscFromMetadata": "Diskas pagal metaduomenis",
|
"LabelDiscFromMetadata": "Diskas pagal metaduomenis",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Atsisiųsti",
|
"LabelDownload": "Atsisiųsti",
|
||||||
"LabelDownloadNEpisodes": "Atsisiųsti {0} epizodų",
|
"LabelDownloadNEpisodes": "Atsisiųsti {0} epizodų",
|
||||||
"LabelDuration": "Trukmė",
|
"LabelDuration": "Trukmė",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Takelis iš metaduomenų",
|
"LabelTrackFromMetadata": "Takelis iš metaduomenų",
|
||||||
"LabelTracks": "Takeliai",
|
"LabelTracks": "Takeliai",
|
||||||
"LabelTracksMultiTrack": "Keli takeliai",
|
"LabelTracksMultiTrack": "Keli takeliai",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Vienas takelis",
|
"LabelTracksSingleTrack": "Vienas takelis",
|
||||||
"LabelType": "Tipas",
|
"LabelType": "Tipas",
|
||||||
"LabelUnabridged": "Neprikurptas",
|
"LabelUnabridged": "Neprikurptas",
|
||||||
@ -702,4 +704,4 @@
|
|||||||
"ToastSocketFailedToConnect": "Nepavyko prisijungti prie serverio",
|
"ToastSocketFailedToConnect": "Nepavyko prisijungti prie serverio",
|
||||||
"ToastUserDeleteFailed": "Nepavyko ištrinti naudotojo",
|
"ToastUserDeleteFailed": "Nepavyko ištrinti naudotojo",
|
||||||
"ToastUserDeleteSuccess": "Naudotojas ištrintas"
|
"ToastUserDeleteSuccess": "Naudotojas ištrintas"
|
||||||
}
|
}
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Map",
|
"LabelDirectory": "Map",
|
||||||
"LabelDiscFromFilename": "Schijf uit bestandsnaam",
|
"LabelDiscFromFilename": "Schijf uit bestandsnaam",
|
||||||
"LabelDiscFromMetadata": "Schijf uit metadata",
|
"LabelDiscFromMetadata": "Schijf uit metadata",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Download",
|
"LabelDownload": "Download",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Duur",
|
"LabelDuration": "Duur",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Track vanuit metadata",
|
"LabelTrackFromMetadata": "Track vanuit metadata",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Type",
|
"LabelType": "Type",
|
||||||
"LabelUnabridged": "Onverkort",
|
"LabelUnabridged": "Onverkort",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Katalog",
|
"LabelDirectory": "Katalog",
|
||||||
"LabelDiscFromFilename": "Oznaczenie dysku z nazwy pliku",
|
"LabelDiscFromFilename": "Oznaczenie dysku z nazwy pliku",
|
||||||
"LabelDiscFromMetadata": "Oznaczenie dysku z metadanych",
|
"LabelDiscFromMetadata": "Oznaczenie dysku z metadanych",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Pobierz",
|
"LabelDownload": "Pobierz",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Czas trwania",
|
"LabelDuration": "Czas trwania",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Ścieżka z metadanych",
|
"LabelTrackFromMetadata": "Ścieżka z metadanych",
|
||||||
"LabelTracks": "Tracks",
|
"LabelTracks": "Tracks",
|
||||||
"LabelTracksMultiTrack": "Multi-track",
|
"LabelTracksMultiTrack": "Multi-track",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Single-track",
|
"LabelTracksSingleTrack": "Single-track",
|
||||||
"LabelType": "Typ",
|
"LabelType": "Typ",
|
||||||
"LabelUnabridged": "Unabridged",
|
"LabelUnabridged": "Unabridged",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "Каталог",
|
"LabelDirectory": "Каталог",
|
||||||
"LabelDiscFromFilename": "Диск из Имени файла",
|
"LabelDiscFromFilename": "Диск из Имени файла",
|
||||||
"LabelDiscFromMetadata": "Диск из Метаданных",
|
"LabelDiscFromMetadata": "Диск из Метаданных",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "Скачать",
|
"LabelDownload": "Скачать",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "Длина",
|
"LabelDuration": "Длина",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "Трек из Метаданных",
|
"LabelTrackFromMetadata": "Трек из Метаданных",
|
||||||
"LabelTracks": "Треков",
|
"LabelTracks": "Треков",
|
||||||
"LabelTracksMultiTrack": "Мультитрек",
|
"LabelTracksMultiTrack": "Мультитрек",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "Один трек",
|
"LabelTracksSingleTrack": "Один трек",
|
||||||
"LabelType": "Тип",
|
"LabelType": "Тип",
|
||||||
"LabelUnabridged": "Полное издание",
|
"LabelUnabridged": "Полное издание",
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"LabelDirectory": "目录",
|
"LabelDirectory": "目录",
|
||||||
"LabelDiscFromFilename": "从文件名获取光盘",
|
"LabelDiscFromFilename": "从文件名获取光盘",
|
||||||
"LabelDiscFromMetadata": "从元数据获取光盘",
|
"LabelDiscFromMetadata": "从元数据获取光盘",
|
||||||
|
"LabelDiscover": "Discover",
|
||||||
"LabelDownload": "下载",
|
"LabelDownload": "下载",
|
||||||
"LabelDownloadNEpisodes": "Download {0} episodes",
|
"LabelDownloadNEpisodes": "Download {0} episodes",
|
||||||
"LabelDuration": "持续时间",
|
"LabelDuration": "持续时间",
|
||||||
@ -474,6 +475,7 @@
|
|||||||
"LabelTrackFromMetadata": "从源数据获取音轨",
|
"LabelTrackFromMetadata": "从源数据获取音轨",
|
||||||
"LabelTracks": "音轨",
|
"LabelTracks": "音轨",
|
||||||
"LabelTracksMultiTrack": "多轨",
|
"LabelTracksMultiTrack": "多轨",
|
||||||
|
"LabelTracksNone": "No tracks",
|
||||||
"LabelTracksSingleTrack": "单轨",
|
"LabelTracksSingleTrack": "单轨",
|
||||||
"LabelType": "类型",
|
"LabelType": "类型",
|
||||||
"LabelUnabridged": "未删节",
|
"LabelUnabridged": "未删节",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const { DataTypes, Model, literal } = require('sequelize')
|
const { DataTypes, Model } = require('sequelize')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const oldLibraryItem = require('../objects/LibraryItem')
|
const oldLibraryItem = require('../objects/LibraryItem')
|
||||||
const libraryFilters = require('../utils/queries/libraryFilters')
|
const libraryFilters = require('../utils/queries/libraryFilters')
|
||||||
@ -447,32 +447,40 @@ module.exports = (sequelize) => {
|
|||||||
*/
|
*/
|
||||||
static async getPersonalizedShelves(library, userId, include, limit) {
|
static async getPersonalizedShelves(library, userId, include, limit) {
|
||||||
const isPodcastLibrary = library.mediaType === 'podcast'
|
const isPodcastLibrary = library.mediaType === 'podcast'
|
||||||
|
|
||||||
|
const fullStart = Date.now() // Used for testing load times
|
||||||
|
|
||||||
const shelves = []
|
const shelves = []
|
||||||
const itemsInProgressPayload = await libraryFilters.getLibraryItemsInProgress(library, userId, include, limit, false)
|
|
||||||
if (itemsInProgressPayload.libraryItems.length) {
|
const itemsInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, userId, include, limit, false)
|
||||||
|
if (itemsInProgressPayload.items.length) {
|
||||||
shelves.push({
|
shelves.push({
|
||||||
id: 'continue-listening',
|
id: 'continue-listening',
|
||||||
label: 'Continue Listening',
|
label: 'Continue Listening',
|
||||||
labelStringKey: 'LabelContinueListening',
|
labelStringKey: 'LabelContinueListening',
|
||||||
type: isPodcastLibrary ? 'episode' : 'book',
|
type: isPodcastLibrary ? 'episode' : 'book',
|
||||||
entities: itemsInProgressPayload.libraryItems,
|
entities: itemsInProgressPayload.items,
|
||||||
total: itemsInProgressPayload.count
|
total: itemsInProgressPayload.count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Logger.debug(`Loaded ${itemsInProgressPayload.items.length} items for "Continue Listening" in ${((Date.now() - fullStart) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
let start = Date.now()
|
||||||
if (library.mediaType === 'book') {
|
if (library.mediaType === 'book') {
|
||||||
const ebooksInProgressPayload = await libraryFilters.getLibraryItemsInProgress(library, userId, include, limit, true)
|
const ebooksInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, userId, include, limit, true)
|
||||||
if (ebooksInProgressPayload.libraryItems.length) {
|
if (ebooksInProgressPayload.items.length) {
|
||||||
shelves.push({
|
shelves.push({
|
||||||
id: 'continue-reading',
|
id: 'continue-reading',
|
||||||
label: 'Continue Reading',
|
label: 'Continue Reading',
|
||||||
labelStringKey: 'LabelContinueReading',
|
labelStringKey: 'LabelContinueReading',
|
||||||
type: 'book',
|
type: 'book',
|
||||||
entities: ebooksInProgressPayload.libraryItems,
|
entities: ebooksInProgressPayload.items,
|
||||||
total: ebooksInProgressPayload.count
|
total: ebooksInProgressPayload.count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Logger.debug(`Loaded ${ebooksInProgressPayload.items.length} items for "Continue Reading" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
const continueSeriesPayload = await libraryFilters.getLibraryItemsContinueSeries(library, userId, include, limit)
|
const continueSeriesPayload = await libraryFilters.getLibraryItemsContinueSeries(library, userId, include, limit)
|
||||||
if (continueSeriesPayload.libraryItems.length) {
|
if (continueSeriesPayload.libraryItems.length) {
|
||||||
shelves.push({
|
shelves.push({
|
||||||
@ -484,6 +492,8 @@ module.exports = (sequelize) => {
|
|||||||
total: continueSeriesPayload.count
|
total: continueSeriesPayload.count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Logger.debug(`Loaded ${continueSeriesPayload.libraryItems.length} items for "Continue Series" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
start = Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
const mostRecentPayload = await libraryFilters.getLibraryItemsMostRecentlyAdded(library, userId, include, limit)
|
const mostRecentPayload = await libraryFilters.getLibraryItemsMostRecentlyAdded(library, userId, include, limit)
|
||||||
@ -497,7 +507,9 @@ module.exports = (sequelize) => {
|
|||||||
total: mostRecentPayload.count
|
total: mostRecentPayload.count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Logger.debug(`Loaded ${mostRecentPayload.libraryItems.length} items for "Recently Added" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
const seriesMostRecentPayload = await libraryFilters.getSeriesMostRecentlyAdded(library, include, 5)
|
const seriesMostRecentPayload = await libraryFilters.getSeriesMostRecentlyAdded(library, include, 5)
|
||||||
if (seriesMostRecentPayload.series.length) {
|
if (seriesMostRecentPayload.series.length) {
|
||||||
shelves.push({
|
shelves.push({
|
||||||
@ -509,6 +521,65 @@ module.exports = (sequelize) => {
|
|||||||
total: seriesMostRecentPayload.count
|
total: seriesMostRecentPayload.count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Logger.debug(`Loaded ${seriesMostRecentPayload.series.length} items for "Recent Series" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
|
const discoverLibraryItemsPayload = await libraryFilters.getLibraryItemsToDiscover(library, userId, include, limit)
|
||||||
|
if (discoverLibraryItemsPayload.libraryItems.length) {
|
||||||
|
shelves.push({
|
||||||
|
id: 'discover',
|
||||||
|
label: 'Discover',
|
||||||
|
labelStringKey: 'LabelDiscover',
|
||||||
|
type: library.mediaType,
|
||||||
|
entities: discoverLibraryItemsPayload.libraryItems,
|
||||||
|
total: discoverLibraryItemsPayload.count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Logger.debug(`Loaded ${discoverLibraryItemsPayload.libraryItems.length} items for "Discover" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
|
const listenAgainPayload = await libraryFilters.getMediaFinished(library, userId, include, limit, false)
|
||||||
|
if (listenAgainPayload.items.length) {
|
||||||
|
shelves.push({
|
||||||
|
id: 'listen-again',
|
||||||
|
label: 'Listen Again',
|
||||||
|
labelStringKey: 'LabelListenAgain',
|
||||||
|
type: isPodcastLibrary ? 'episode' : 'book',
|
||||||
|
entities: listenAgainPayload.items,
|
||||||
|
total: listenAgainPayload.count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Logger.debug(`Loaded ${listenAgainPayload.items.length} items for "Listen Again" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
|
const readAgainPayload = await libraryFilters.getMediaFinished(library, userId, include, limit, true)
|
||||||
|
if (readAgainPayload.items.length) {
|
||||||
|
shelves.push({
|
||||||
|
id: 'read-again',
|
||||||
|
label: 'Read Again',
|
||||||
|
labelStringKey: 'LabelReadAgain',
|
||||||
|
type: 'book',
|
||||||
|
entities: readAgainPayload.items,
|
||||||
|
total: readAgainPayload.count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Logger.debug(`Loaded ${readAgainPayload.items.length} items for "Read Again" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
start = Date.now()
|
||||||
|
const newestAuthorsPayload = await libraryFilters.getNewestAuthors(library, limit)
|
||||||
|
if (newestAuthorsPayload.authors.length) {
|
||||||
|
shelves.push({
|
||||||
|
id: 'newest-authors',
|
||||||
|
label: 'Newest Authors',
|
||||||
|
labelStringKey: 'LabelNewestAuthors',
|
||||||
|
type: 'authors',
|
||||||
|
entities: newestAuthorsPayload.authors,
|
||||||
|
total: newestAuthorsPayload.count
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Logger.debug(`Loaded ${newestAuthorsPayload.authors.length} authors for "Newest Authors" in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
|
Logger.debug(`Loaded ${shelves.length} personalized shelves in ${((Date.now() - fullStart) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
return shelves
|
return shelves
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,8 @@ module.exports = {
|
|||||||
} else if (group === 'languages') {
|
} else if (group === 'languages') {
|
||||||
filtered = filtered.filter(li => li.media.metadata.language === filter)
|
filtered = filtered.filter(li => li.media.metadata.language === filter)
|
||||||
} else if (group === 'tracks') {
|
} else if (group === 'tracks') {
|
||||||
if (filter === 'single') filtered = filtered.filter(li => li.isBook && li.media.numTracks === 1)
|
if (filter === 'none') filtered = filtered.filter(li => li.isBook && !li.media.numTracks)
|
||||||
|
else if (filter === 'single') filtered = filtered.filter(li => li.isBook && li.media.numTracks === 1)
|
||||||
else if (filter === 'multi') filtered = filtered.filter(li => li.isBook && li.media.numTracks > 1)
|
else if (filter === 'multi') filtered = filtered.filter(li => li.isBook && li.media.numTracks > 1)
|
||||||
} else if (group === 'ebooks') {
|
} else if (group === 'ebooks') {
|
||||||
if (filter === 'ebook') filtered = filtered.filter(li => li.media.ebookFile)
|
if (filter === 'ebook') filtered = filtered.filter(li => li.media.ebookFile)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
const Sequelize = require('sequelize')
|
||||||
const Database = require('../../Database')
|
const Database = require('../../Database')
|
||||||
const Logger = require('../../Logger')
|
const Logger = require('../../Logger')
|
||||||
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
|
||||||
@ -41,14 +42,14 @@ module.exports = {
|
|||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @param {boolean} ebook true if continue reading shelf
|
* @param {boolean} ebook true if continue reading shelf
|
||||||
* @returns {object} { libraryItems:LibraryItem[], count:number }
|
* @returns {object} { items:LibraryItem[], count:number }
|
||||||
*/
|
*/
|
||||||
async getLibraryItemsInProgress(library, userId, include, limit, ebook = false) {
|
async getMediaItemsInProgress(library, userId, include, limit, ebook = false) {
|
||||||
if (library.mediaType === 'book') {
|
if (library.mediaType === 'book') {
|
||||||
const filterValue = ebook ? 'ebook-in-progress' : 'audio-in-progress'
|
const filterValue = ebook ? 'ebook-in-progress' : 'audio-in-progress'
|
||||||
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, 'progress', filterValue, 'progress', true, false, include, limit, 0)
|
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, 'progress', filterValue, 'progress', true, false, include, limit, 0)
|
||||||
return {
|
return {
|
||||||
libraryItems: libraryItems.map(li => {
|
items: libraryItems.map(li => {
|
||||||
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
|
||||||
if (li.rssFeed) {
|
if (li.rssFeed) {
|
||||||
oldLibraryItem.rssFeed = Database.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
oldLibraryItem.rssFeed = Database.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
||||||
@ -58,9 +59,10 @@ module.exports = {
|
|||||||
count
|
count
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: Get episodes in progress
|
||||||
return {
|
return {
|
||||||
count: 0,
|
count: 0,
|
||||||
libraryItems: []
|
items: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -132,6 +134,40 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get library items or podcast episodes for the "Listen Again" or "Read Again" shelf
|
||||||
|
* @param {oldLibrary} library
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {string[]} include
|
||||||
|
* @param {number} limit
|
||||||
|
* @param {boolean} ebook true if "Read Again" shelf
|
||||||
|
* @returns {object} { items:object[], count:number }
|
||||||
|
*/
|
||||||
|
async getMediaFinished(library, userId, include, limit, ebook = false) {
|
||||||
|
if (ebook && library.mediaType !== 'book') return { items: [], count: 0 }
|
||||||
|
|
||||||
|
if (library.mediaType === 'book') {
|
||||||
|
const filterValue = ebook ? 'ebook-finished' : 'finished'
|
||||||
|
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, userId, 'progress', filterValue, 'progress', true, false, include, limit, 0)
|
||||||
|
return {
|
||||||
|
items: libraryItems.map(li => {
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
|
||||||
|
if (li.rssFeed) {
|
||||||
|
oldLibraryItem.rssFeed = Database.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
||||||
|
}
|
||||||
|
return oldLibraryItem
|
||||||
|
}),
|
||||||
|
count
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Get podcast episodes finished
|
||||||
|
return {
|
||||||
|
items: [],
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get series for recent series shelf
|
* Get series for recent series shelf
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
@ -140,6 +176,8 @@ module.exports = {
|
|||||||
* @returns {object} { series:oldSeries[], count:number}
|
* @returns {object} { series:oldSeries[], count:number}
|
||||||
*/
|
*/
|
||||||
async getSeriesMostRecentlyAdded(library, include, limit) {
|
async getSeriesMostRecentlyAdded(library, include, limit) {
|
||||||
|
if (library.mediaType !== 'book') return { series: [], count: 0 }
|
||||||
|
|
||||||
const seriesIncludes = []
|
const seriesIncludes = []
|
||||||
if (include.includes('rssfeed')) {
|
if (include.includes('rssfeed')) {
|
||||||
seriesIncludes.push({
|
seriesIncludes.push({
|
||||||
@ -172,8 +210,6 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
Logger.debug(`Found ${series.length} series recently added (${count} total)`)
|
|
||||||
|
|
||||||
const allOldSeries = []
|
const allOldSeries = []
|
||||||
for (const s of series) {
|
for (const s of series) {
|
||||||
const oldSeries = s.getOldSeries().toJSON()
|
const oldSeries = s.getOldSeries().toJSON()
|
||||||
@ -205,5 +241,63 @@ module.exports = {
|
|||||||
series: allOldSeries,
|
series: allOldSeries,
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get most recently created authors for "Newest Authors" shelf
|
||||||
|
* Author must be linked to at least 1 book
|
||||||
|
* @param {oldLibrary} library
|
||||||
|
* @param {number} limit
|
||||||
|
* @returns {object} { authors:oldAuthor[], count:number }
|
||||||
|
*/
|
||||||
|
async getNewestAuthors(library, limit) {
|
||||||
|
if (library.mediaType !== 'book') return { authors: [], count: 0 }
|
||||||
|
|
||||||
|
const { rows: authors, count } = await Database.models.author.findAndCountAll({
|
||||||
|
where: {
|
||||||
|
libraryId: library.id
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
model: Database.models.bookAuthor,
|
||||||
|
required: true // Must belong to a book
|
||||||
|
},
|
||||||
|
limit,
|
||||||
|
distinct: true,
|
||||||
|
order: [
|
||||||
|
['createdAt', 'DESC']
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
authors: authors.map((au) => {
|
||||||
|
const numBooks = au.bookAuthors?.length || 0
|
||||||
|
return au.getOldAuthor().toJSONExpanded(numBooks)
|
||||||
|
}),
|
||||||
|
count
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get book library items for the "Discover" shelf
|
||||||
|
* @param {oldLibrary} library
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {string[]} include
|
||||||
|
* @param {number} limit
|
||||||
|
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
|
||||||
|
*/
|
||||||
|
async getLibraryItemsToDiscover(library, userId, include, limit) {
|
||||||
|
if (library.mediaType !== 'book') return { libraryItems: [], count: 0 }
|
||||||
|
|
||||||
|
const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, userId, include, limit)
|
||||||
|
return {
|
||||||
|
libraryItems: libraryItems.map(li => {
|
||||||
|
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(li).toJSONMinified()
|
||||||
|
if (li.rssFeed) {
|
||||||
|
oldLibraryItem.rssFeed = Database.models.feed.getOldFeed(li.rssFeed).toJSONMinified()
|
||||||
|
}
|
||||||
|
return oldLibraryItem
|
||||||
|
}),
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -119,7 +119,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
} else if (value === 'ebook-in-progress') {
|
} else if (value === 'ebook-in-progress') {
|
||||||
mediaWhere[Sequelize.Op.and] = [
|
// Filters for ebook only
|
||||||
|
mediaWhere = [
|
||||||
|
Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('audioFiles')), 0),
|
||||||
{
|
{
|
||||||
'$mediaProgresses.ebookProgress$': {
|
'$mediaProgresses.ebookProgress$': {
|
||||||
[Sequelize.Op.gt]: 0
|
[Sequelize.Op.gt]: 0
|
||||||
@ -129,6 +131,17 @@ module.exports = {
|
|||||||
'$mediaProgresses.isFinished$': false
|
'$mediaProgresses.isFinished$': false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
} else if (value === 'ebook-finished') {
|
||||||
|
// Filters for ebook only
|
||||||
|
mediaWhere = [
|
||||||
|
Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('audioFiles')), 0),
|
||||||
|
{
|
||||||
|
'$mediaProgresses.isFinished$': true,
|
||||||
|
'ebookFile': {
|
||||||
|
[Sequelize.Op.not]: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
} else if (group === 'series' && value === 'no-series') {
|
} else if (group === 'series' && value === 'no-series') {
|
||||||
mediaWhere['$series.id$'] = null
|
mediaWhere['$series.id$'] = null
|
||||||
@ -144,7 +157,9 @@ module.exports = {
|
|||||||
} else if (group === 'languages') {
|
} else if (group === 'languages') {
|
||||||
mediaWhere['language'] = value
|
mediaWhere['language'] = value
|
||||||
} else if (group === 'tracks') {
|
} else if (group === 'tracks') {
|
||||||
if (value === 'multi') {
|
if (value === 'none') {
|
||||||
|
mediaWhere = Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('audioFiles')), 0)
|
||||||
|
} else if (value === 'multi') {
|
||||||
mediaWhere = Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('audioFiles')), {
|
mediaWhere = Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('audioFiles')), {
|
||||||
[Sequelize.Op.gt]: 1
|
[Sequelize.Op.gt]: 1
|
||||||
})
|
})
|
||||||
@ -542,7 +557,7 @@ module.exports = {
|
|||||||
|
|
||||||
return libraryItem
|
return libraryItem
|
||||||
})
|
})
|
||||||
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
|
||||||
return {
|
return {
|
||||||
libraryItems,
|
libraryItems,
|
||||||
count
|
count
|
||||||
@ -663,8 +678,6 @@ module.exports = {
|
|||||||
offset
|
offset
|
||||||
})
|
})
|
||||||
|
|
||||||
Logger.debug('Found', series.length, 'series to continue', 'total=', count)
|
|
||||||
|
|
||||||
// Step 3: Map series to library items by selecting the first unfinished book in the series
|
// Step 3: Map series to library items by selecting the first unfinished book in the series
|
||||||
const libraryItems = series.map(s => {
|
const libraryItems = series.map(s => {
|
||||||
// Natural sort sequence, nulls last
|
// Natural sort sequence, nulls last
|
||||||
@ -695,6 +708,128 @@ module.exports = {
|
|||||||
libraryItem.media = bookSeries.book
|
libraryItem.media = bookSeries.book
|
||||||
return libraryItem
|
return libraryItem
|
||||||
})
|
})
|
||||||
|
return {
|
||||||
|
libraryItems,
|
||||||
|
count
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get book library items for the "Discover" shelf
|
||||||
|
* Random selection of books that are not started
|
||||||
|
* - only includes the first book of a not-started series
|
||||||
|
* @param {string} libraryId
|
||||||
|
* @param {string} userId
|
||||||
|
* @param {string[]} include
|
||||||
|
* @param {number} limit
|
||||||
|
* @returns {object} {libraryItems:LibraryItem, count:number}
|
||||||
|
*/
|
||||||
|
async getDiscoverLibraryItems(libraryId, userId, include, limit) {
|
||||||
|
// Step 1: Get the first book of every series that hasnt been started yet
|
||||||
|
const seriesNotStarted = await Database.models.series.findAll({
|
||||||
|
where: [
|
||||||
|
{
|
||||||
|
libraryId
|
||||||
|
},
|
||||||
|
Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM bookSeries bs LEFT OUTER JOIN mediaProgresses mp ON mp.mediaItemId = bs.bookId WHERE bs.seriesId = series.id AND mp.userId = :userId AND (mp.isFinished = 1 OR mp.currentTime > 0))`), 0)
|
||||||
|
],
|
||||||
|
replacements: {
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
attributes: ['id'],
|
||||||
|
include: {
|
||||||
|
model: Database.models.bookSeries,
|
||||||
|
attributes: ['bookId', 'sequence'],
|
||||||
|
separate: true,
|
||||||
|
required: true,
|
||||||
|
order: [
|
||||||
|
[Sequelize.literal('CAST(sequence AS INTEGER) ASC NULLS LAST')]
|
||||||
|
],
|
||||||
|
limit: 1
|
||||||
|
},
|
||||||
|
subQuery: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const booksFromSeriesToInclude = seriesNotStarted.map(se => se.bookSeries?.[0]?.bookId).filter(bid => bid)
|
||||||
|
|
||||||
|
// optional include rssFeed
|
||||||
|
const libraryItemIncludes = []
|
||||||
|
if (include.includes('rssfeed')) {
|
||||||
|
libraryItemIncludes.push({
|
||||||
|
model: Database.models.feed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Get books not started and not in a series OR is the first book of a series not started (ordered randomly)
|
||||||
|
const { rows: books, count } = await Database.models.book.findAndCountAll({
|
||||||
|
where: {
|
||||||
|
'$mediaProgresses.isFinished$': {
|
||||||
|
[Sequelize.Op.or]: [null, 0]
|
||||||
|
},
|
||||||
|
'$mediaProgresses.currentTime$': {
|
||||||
|
[Sequelize.Op.or]: [null, 0]
|
||||||
|
},
|
||||||
|
[Sequelize.Op.or]: [
|
||||||
|
Sequelize.where(Sequelize.literal(`(SELECT COUNT(*) FROM bookSeries bs where bs.bookId = book.id)`), 0),
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
[Sequelize.Op.in]: booksFromSeriesToInclude
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Database.models.libraryItem,
|
||||||
|
where: {
|
||||||
|
libraryId
|
||||||
|
},
|
||||||
|
include: libraryItemIncludes
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.mediaProgress,
|
||||||
|
where: {
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.bookAuthor,
|
||||||
|
attributes: ['authorId'],
|
||||||
|
include: {
|
||||||
|
model: Database.models.author
|
||||||
|
},
|
||||||
|
separate: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Database.models.bookSeries,
|
||||||
|
attributes: ['seriesId', 'sequence'],
|
||||||
|
include: {
|
||||||
|
model: Database.models.series
|
||||||
|
},
|
||||||
|
separate: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
subQuery: false,
|
||||||
|
distinct: true,
|
||||||
|
limit,
|
||||||
|
order: Database.sequelize.random()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Step 3: Map books to library items
|
||||||
|
const libraryItems = books.map((bookExpanded) => {
|
||||||
|
const libraryItem = bookExpanded.libraryItem.toJSON()
|
||||||
|
const book = bookExpanded.toJSON()
|
||||||
|
delete book.libraryItem
|
||||||
|
libraryItem.media = book
|
||||||
|
|
||||||
|
if (libraryItem.feeds?.length) {
|
||||||
|
libraryItem.rssFeed = libraryItem.feeds[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return libraryItem
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
libraryItems,
|
libraryItems,
|
||||||
count
|
count
|
||||||
|
@ -147,7 +147,7 @@ module.exports = {
|
|||||||
|
|
||||||
return libraryItem
|
return libraryItem
|
||||||
})
|
})
|
||||||
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
|
||||||
return {
|
return {
|
||||||
libraryItems,
|
libraryItems,
|
||||||
count
|
count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user