From 34ac97213016356874d189908a1f26d699146d67 Mon Sep 17 00:00:00 2001 From: mfcar Date: Mon, 27 Feb 2023 02:56:07 +0000 Subject: [PATCH 1/3] Add download queue --- client/components/app/SideRail.vue | 13 +- client/components/app/StreamContainer.vue | 20 ++- .../components/modals/podcast/EpisodeFeed.vue | 11 +- .../tables/podcast/DownloadQueueTable.vue | 68 ++++++++++ .../tables/podcast/EpisodeTableRow.vue | 9 +- .../widgets/PodcastTypeIndicator.vue | 31 +++++ .../_library/podcast/download-queue.vue | 125 ++++++++++++++++++ .../pages/library/_library/podcast/latest.vue | 11 +- client/strings/de.json | 7 +- client/strings/en-us.json | 5 + client/strings/es.json | 5 + client/strings/fr.json | 5 + client/strings/hr.json | 5 + client/strings/it.json | 5 + client/strings/pl.json | 5 + client/strings/ru.json | 5 + client/strings/zh-cn.json | 5 + server/controllers/LibraryController.js | 7 + server/managers/PodcastManager.js | 23 +++- server/objects/PodcastEpisodeDownload.js | 13 +- server/routers/ApiRouter.js | 3 +- 21 files changed, 359 insertions(+), 22 deletions(-) create mode 100644 client/components/tables/podcast/DownloadQueueTable.vue create mode 100644 client/components/widgets/PodcastTypeIndicator.vue create mode 100644 client/pages/library/_library/podcast/download-queue.vue diff --git a/client/components/app/SideRail.vue b/client/components/app/SideRail.vue index bf58e341..25350d24 100644 --- a/client/components/app/SideRail.vue +++ b/client/components/app/SideRail.vue @@ -86,6 +86,14 @@
+ + file_download + +

{{ $strings.ButtonDownloadQueue }}

+ +
+ + warning @@ -149,6 +157,9 @@ export default { isMusicLibrary() { return this.currentLibraryMediaType === 'music' }, + isPodcastDownloadQueuePage() { + return this.$route.name === 'library-library-podcast-download-queue' + }, isPodcastSearchPage() { return this.$route.name === 'library-library-podcast-search' }, @@ -212,4 +223,4 @@ export default { }, mounted() {} } - \ No newline at end of file + diff --git a/client/components/app/StreamContainer.vue b/client/components/app/StreamContainer.vue index 95e29554..27e79d8f 100644 --- a/client/components/app/StreamContainer.vue +++ b/client/components/app/StreamContainer.vue @@ -11,12 +11,15 @@
person -

{{ podcastAuthor }}

-

{{ musicArtists }}

-

- {{ author.name }} -

-

{{ $strings.LabelUnknown }}

+
+
{{ podcastAuthor }}
+
{{ musicArtists }}
+
+ {{ author.name }} +
+
{{ $strings.LabelUnknown }}
+ +
@@ -129,6 +132,9 @@ export default { isMusic() { return this.streamLibraryItem ? this.streamLibraryItem.mediaType === 'music' : false }, + isExplicit() { + return this.mediaMetadata.explicit || false + }, mediaMetadata() { return this.media.metadata || {} }, @@ -474,4 +480,4 @@ export default { #streamContainer { box-shadow: 0px -6px 8px #1111113f; } - \ No newline at end of file + diff --git a/client/components/modals/podcast/EpisodeFeed.vue b/client/components/modals/podcast/EpisodeFeed.vue index be701f3a..91f0b34a 100644 --- a/client/components/modals/podcast/EpisodeFeed.vue +++ b/client/components/modals/podcast/EpisodeFeed.vue @@ -19,8 +19,15 @@
-

#{{ episode.episode }}

-

{{ episode.title }}

+
+
#
+
{{ episode.season }}x
+
{{ episode.episode }}
+
+
+
{{ episode.title }}
+ +

{{ episode.subtitle }}

Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}

diff --git a/client/components/tables/podcast/DownloadQueueTable.vue b/client/components/tables/podcast/DownloadQueueTable.vue new file mode 100644 index 00000000..2dfe87f0 --- /dev/null +++ b/client/components/tables/podcast/DownloadQueueTable.vue @@ -0,0 +1,68 @@ + + + diff --git a/client/components/tables/podcast/EpisodeTableRow.vue b/client/components/tables/podcast/EpisodeTableRow.vue index a184b3c8..dfb80248 100644 --- a/client/components/tables/podcast/EpisodeTableRow.vue +++ b/client/components/tables/podcast/EpisodeTableRow.vue @@ -2,9 +2,10 @@
-

- {{ title }} -

+
+ {{ title }} + +

{{ subtitle }}

@@ -205,4 +206,4 @@ export default { } } } - \ No newline at end of file + diff --git a/client/components/widgets/PodcastTypeIndicator.vue b/client/components/widgets/PodcastTypeIndicator.vue new file mode 100644 index 00000000..d914d283 --- /dev/null +++ b/client/components/widgets/PodcastTypeIndicator.vue @@ -0,0 +1,31 @@ + + + diff --git a/client/pages/library/_library/podcast/download-queue.vue b/client/pages/library/_library/podcast/download-queue.vue new file mode 100644 index 00000000..11785887 --- /dev/null +++ b/client/pages/library/_library/podcast/download-queue.vue @@ -0,0 +1,125 @@ + + diff --git a/client/pages/library/_library/podcast/latest.vue b/client/pages/library/_library/podcast/latest.vue index 344b327e..693d957a 100644 --- a/client/pages/library/_library/podcast/latest.vue +++ b/client/pages/library/_library/podcast/latest.vue @@ -30,7 +30,16 @@

{{ $dateDistanceFromNow(episode.publishedAt) }}

-

{{ episode.title }}

+
+
#
+
{{ episode.season }}x
+
{{ episode.episode }}
+
+ +
+
{{ episode.title }}
+ +

{{ episode.subtitle }}

diff --git a/client/strings/de.json b/client/strings/de.json index 57915ccd..e1c3b02f 100644 --- a/client/strings/de.json +++ b/client/strings/de.json @@ -20,6 +20,7 @@ "ButtonCreate": "Erstellen", "ButtonCreateBackup": "Sicherung erstellen", "ButtonDelete": "Löschen", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Bearbeiten", "ButtonEditChapters": "Kapitel bearbeiten", "ButtonEditPodcast": "Podcast bearbeiten", @@ -92,7 +93,9 @@ "HeaderCollection": "Sammlungen", "HeaderCollectionItems": "Sammlungseinträge", "HeaderCover": "Titelbild", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Details", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Episoden", "HeaderFiles": "Dateien", "HeaderFindChapters": "Kapitel suchen", @@ -493,6 +496,8 @@ "MessageNoCollections": "Keine Sammlungen", "MessageNoCoversFound": "Keine Titelbilder gefunden", "MessageNoDescription": "Keine Beschreibung", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Keine Episodenübereinstimmungen gefunden", "MessageNoEpisodes": "Keine Episoden", "MessageNoFoldersAvailable": "Keine Ordner verfügbar", @@ -623,4 +628,4 @@ "ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen", "ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden", "ToastUserDeleteSuccess": "Benutzer gelöscht" -} \ No newline at end of file +} diff --git a/client/strings/en-us.json b/client/strings/en-us.json index 710d5ef8..c8e87d28 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -20,6 +20,7 @@ "ButtonCreate": "Create", "ButtonCreateBackup": "Create Backup", "ButtonDelete": "Delete", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Edit", "ButtonEditChapters": "Edit Chapters", "ButtonEditPodcast": "Edit Podcast", @@ -92,7 +93,9 @@ "HeaderCollection": "Collection", "HeaderCollectionItems": "Collection Items", "HeaderCover": "Cover", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Details", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Episodes", "HeaderFiles": "Files", "HeaderFindChapters": "Find Chapters", @@ -493,6 +496,8 @@ "MessageNoCollections": "No Collections", "MessageNoCoversFound": "No Covers Found", "MessageNoDescription": "No description", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "No episode matches found", "MessageNoEpisodes": "No Episodes", "MessageNoFoldersAvailable": "No Folders Available", diff --git a/client/strings/es.json b/client/strings/es.json index 710d5ef8..c8e87d28 100644 --- a/client/strings/es.json +++ b/client/strings/es.json @@ -20,6 +20,7 @@ "ButtonCreate": "Create", "ButtonCreateBackup": "Create Backup", "ButtonDelete": "Delete", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Edit", "ButtonEditChapters": "Edit Chapters", "ButtonEditPodcast": "Edit Podcast", @@ -92,7 +93,9 @@ "HeaderCollection": "Collection", "HeaderCollectionItems": "Collection Items", "HeaderCover": "Cover", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Details", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Episodes", "HeaderFiles": "Files", "HeaderFindChapters": "Find Chapters", @@ -493,6 +496,8 @@ "MessageNoCollections": "No Collections", "MessageNoCoversFound": "No Covers Found", "MessageNoDescription": "No description", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "No episode matches found", "MessageNoEpisodes": "No Episodes", "MessageNoFoldersAvailable": "No Folders Available", diff --git a/client/strings/fr.json b/client/strings/fr.json index 47f84209..2393110b 100644 --- a/client/strings/fr.json +++ b/client/strings/fr.json @@ -20,6 +20,7 @@ "ButtonCreate": "Créer", "ButtonCreateBackup": "Créer une sauvegarde", "ButtonDelete": "Effacer", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Modifier", "ButtonEditChapters": "Modifier les chapitres", "ButtonEditPodcast": "Modifier les podcasts", @@ -92,7 +93,9 @@ "HeaderCollection": "Collection", "HeaderCollectionItems": "Entrées de la Collection", "HeaderCover": "Couverture", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Détails", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Épisodes", "HeaderFiles": "Fichiers", "HeaderFindChapters": "Trouver les chapitres", @@ -493,6 +496,8 @@ "MessageNoCollections": "Pas de collections", "MessageNoCoversFound": "Aucune couverture trouvée", "MessageNoDescription": "Pas de description", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Pas de correspondance d'épisode trouvée", "MessageNoEpisodes": "Aucun épisode", "MessageNoFoldersAvailable": "Aucun dossier disponible", diff --git a/client/strings/hr.json b/client/strings/hr.json index 36e67444..00d27566 100644 --- a/client/strings/hr.json +++ b/client/strings/hr.json @@ -20,6 +20,7 @@ "ButtonCreate": "Napravi", "ButtonCreateBackup": "Napravi backup", "ButtonDelete": "Obriši", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Edit", "ButtonEditChapters": "Uredi poglavlja", "ButtonEditPodcast": "Uredi podcast", @@ -92,7 +93,9 @@ "HeaderCollection": "Kolekcija", "HeaderCollectionItems": "Stvari u kolekciji", "HeaderCover": "Cover", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Detalji", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Epizode", "HeaderFiles": "Datoteke", "HeaderFindChapters": "Pronađi poglavlja", @@ -493,6 +496,8 @@ "MessageNoCollections": "Nema kolekcija", "MessageNoCoversFound": "Covers nisu pronađeni", "MessageNoDescription": "Nema opisa", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Nijedna epizoda pronađena", "MessageNoEpisodes": "Nema epizoda", "MessageNoFoldersAvailable": "Nema dostupnih foldera", diff --git a/client/strings/it.json b/client/strings/it.json index 21bc3ae9..8818f8fd 100644 --- a/client/strings/it.json +++ b/client/strings/it.json @@ -20,6 +20,7 @@ "ButtonCreate": "Crea", "ButtonCreateBackup": "Crea un Backup", "ButtonDelete": "Elimina", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Edit", "ButtonEditChapters": "Modifica Capitoli", "ButtonEditPodcast": "Modifica Podcast", @@ -92,7 +93,9 @@ "HeaderCollection": "Raccolta", "HeaderCollectionItems": "Elementi della Raccolta", "HeaderCover": "Cover", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Dettagli", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Episodi", "HeaderFiles": "File", "HeaderFindChapters": "Trova Capitoli", @@ -493,6 +496,8 @@ "MessageNoCollections": "Nessuna Raccolta", "MessageNoCoversFound": "Nessuna Cover Trovata", "MessageNoDescription": "Nessuna descrizione", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Nessun episodio corrispondente trovato", "MessageNoEpisodes": "Nessun Episodio", "MessageNoFoldersAvailable": "Nessuna Cartella disponibile", diff --git a/client/strings/pl.json b/client/strings/pl.json index c907e612..4ecdcff9 100644 --- a/client/strings/pl.json +++ b/client/strings/pl.json @@ -20,6 +20,7 @@ "ButtonCreate": "Utwórz", "ButtonCreateBackup": "Utwórz kopię zapasową", "ButtonDelete": "Usuń", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Edit", "ButtonEditChapters": "Edytuj rozdziały", "ButtonEditPodcast": "Edytuj podcast", @@ -92,7 +93,9 @@ "HeaderCollection": "Kolekcja", "HeaderCollectionItems": "Elementy kolekcji", "HeaderCover": "Okładka", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Szczegóły", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Rozdziały", "HeaderFiles": "Pliki", "HeaderFindChapters": "Wyszukaj rozdziały", @@ -493,6 +496,8 @@ "MessageNoCollections": "Brak kolekcji", "MessageNoCoversFound": "Okładki nieznalezione", "MessageNoDescription": "Brak opisu", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Nie znaleziono pasujących odcinków", "MessageNoEpisodes": "Brak odcinków", "MessageNoFoldersAvailable": "Brak dostępnych folderów", diff --git a/client/strings/ru.json b/client/strings/ru.json index a1a34f70..dd50a169 100644 --- a/client/strings/ru.json +++ b/client/strings/ru.json @@ -20,6 +20,7 @@ "ButtonCreate": "Создать", "ButtonCreateBackup": "Создать бэкап", "ButtonDelete": "Удалить", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "Редактировать", "ButtonEditChapters": "Редактировать Главы", "ButtonEditPodcast": "Редактировать Подкаст", @@ -92,7 +93,9 @@ "HeaderCollection": "Коллекция", "HeaderCollectionItems": "Элементы Коллекции", "HeaderCover": "Обложка", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "Подробности", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "Эпизоды", "HeaderFiles": "Файлы", "HeaderFindChapters": "Найти Главы", @@ -493,6 +496,8 @@ "MessageNoCollections": "Нет Коллекций", "MessageNoCoversFound": "Обложек не найдено", "MessageNoDescription": "Нет описания", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "Совпадения эпизодов не найдены", "MessageNoEpisodes": "Нет Эпизодов", "MessageNoFoldersAvailable": "Нет доступных папок", diff --git a/client/strings/zh-cn.json b/client/strings/zh-cn.json index 433a87bc..671fde5a 100644 --- a/client/strings/zh-cn.json +++ b/client/strings/zh-cn.json @@ -20,6 +20,7 @@ "ButtonCreate": "创建", "ButtonCreateBackup": "创建备份", "ButtonDelete": "删除", + "ButtonDownloadQueue": "Queue", "ButtonEdit": "编辑", "ButtonEditChapters": "编辑章节", "ButtonEditPodcast": "编辑播客", @@ -92,7 +93,9 @@ "HeaderCollection": "收藏", "HeaderCollectionItems": "收藏项目", "HeaderCover": "封面", + "HeaderCurrentDownloads": "Current Downloads", "HeaderDetails": "详情", + "HeaderDownloadQueue": "Download Queue", "HeaderEpisodes": "剧集", "HeaderFiles": "文件", "HeaderFindChapters": "查找章节", @@ -493,6 +496,8 @@ "MessageNoCollections": "没有收藏", "MessageNoCoversFound": "没有找到封面", "MessageNoDescription": "没有描述", + "MessageNoDownloadsQueued": "No downloads queued", + "MessageNoDownloadsInProgress": "No downloads currently in progress", "MessageNoEpisodeMatchesFound": "没有找到任何剧集匹配项", "MessageNoEpisodes": "没有剧集", "MessageNoFoldersAvailable": "没有可用文件夹", diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js index ece93ca2..7f814591 100644 --- a/server/controllers/LibraryController.js +++ b/server/controllers/LibraryController.js @@ -82,6 +82,13 @@ class LibraryController { return res.json(req.library) } + async getDownloadQueue(req, res) { + const library = req.library + + let queue = this.podcastManager.getDownloadQueueDetails().filter(q => q.libraryId === library.id) + return res.json(queue) + } + async update(req, res) { const library = req.library diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js index 74751d45..3b7e352b 100644 --- a/server/managers/PodcastManager.js +++ b/server/managers/PodcastManager.js @@ -56,12 +56,13 @@ class PodcastManager { newPe.setData(ep, index++) newPe.libraryItemId = libraryItem.id var newPeDl = new PodcastEpisodeDownload() - newPeDl.setData(newPe, libraryItem, isAutoDownload) + newPeDl.setData(newPe, libraryItem, isAutoDownload, libraryItem.libraryId) this.startPodcastEpisodeDownload(newPeDl) }) } async startPodcastEpisodeDownload(podcastEpisodeDownload) { + SocketAuthority.emitter('download_queue_updated', this.getDownloadQueueDetails()) if (this.currentDownload) { this.downloadQueue.push(podcastEpisodeDownload) SocketAuthority.emitter('episode_download_queued', podcastEpisodeDownload.toJSONForClient()) @@ -99,6 +100,7 @@ class PodcastManager { } SocketAuthority.emitter('episode_download_finished', this.currentDownload.toJSONForClient()) + SocketAuthority.emitter('download_queue_updated', this.getDownloadQueueDetails()) this.watcher.removeIgnoreDir(this.currentDownload.libraryItem.path) this.currentDownload = null @@ -329,5 +331,22 @@ class PodcastManager { feeds: rssFeedData } } + + getDownloadQueueDetails() { + return this.downloadQueue.map(item => { + return { + id: item.id, + libraryId: item.libraryId || null, + libraryItemId: item.libraryItemId || null, + podcastTitle: item.libraryItem.media.metadata.title || null, + podcastExplicit: item.libraryItem.media.metadata.explicit || false, + episodeDisplayTitle: item.podcastEpisode.title || null, + season: item.podcastEpisode.season || null, + episode: item.podcastEpisode.episode || null, + episodeType: item.podcastEpisode.episodeType || 'full', + publishedAt: item.podcastEpisode.publishedAt || null + } + }) + } } -module.exports = PodcastManager \ No newline at end of file +module.exports = PodcastManager diff --git a/server/objects/PodcastEpisodeDownload.js b/server/objects/PodcastEpisodeDownload.js index 38a371e5..c5ee99ab 100644 --- a/server/objects/PodcastEpisodeDownload.js +++ b/server/objects/PodcastEpisodeDownload.js @@ -8,6 +8,7 @@ class PodcastEpisodeDownload { this.podcastEpisode = null this.url = null this.libraryItem = null + this.libraryId = null this.isAutoDownload = false this.isDownloading = false @@ -25,12 +26,17 @@ class PodcastEpisodeDownload { episodeDisplayTitle: this.podcastEpisode ? this.podcastEpisode.title : null, url: this.url, libraryItemId: this.libraryItem ? this.libraryItem.id : null, + libraryId: this.libraryId || null, isDownloading: this.isDownloading, isFinished: this.isFinished, failed: this.failed, startedAt: this.startedAt, createdAt: this.createdAt, - finishedAt: this.finishedAt + finishedAt: this.finishedAt, + season: this.podcastEpisode ? this.podcastEpisode.season : null, + episode: this.podcastEpisode ? this.podcastEpisode.episode : null, + episodeType: this.podcastEpisode ? this.podcastEpisode.episodeType : 'full', + publishedAt: this.podcastEpisode ? this.podcastEpisode.publishedAt : null } } @@ -47,13 +53,14 @@ class PodcastEpisodeDownload { return this.libraryItem ? this.libraryItem.id : null } - setData(podcastEpisode, libraryItem, isAutoDownload) { + setData(podcastEpisode, libraryItem, isAutoDownload, libraryId) { this.id = getId('epdl') this.podcastEpisode = podcastEpisode this.url = encodeURI(podcastEpisode.enclosure.url) this.libraryItem = libraryItem this.isAutoDownload = isAutoDownload this.createdAt = Date.now() + this.libraryId = libraryId } setFinished(success) { @@ -62,4 +69,4 @@ class PodcastEpisodeDownload { this.failed = !success } } -module.exports = PodcastEpisodeDownload \ No newline at end of file +module.exports = PodcastEpisodeDownload diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 41c26769..6e1837b3 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -76,6 +76,7 @@ class ApiRouter { this.router.get('/libraries/:id/items', LibraryController.middleware.bind(this), LibraryController.getLibraryItems.bind(this)) this.router.delete('/libraries/:id/issues', LibraryController.middleware.bind(this), LibraryController.removeLibraryItemsWithIssues.bind(this)) + this.router.get('/libraries/:id/downloads', LibraryController.middleware.bind(this), LibraryController.getDownloadQueue.bind(this)) this.router.get('/libraries/:id/series', LibraryController.middleware.bind(this), LibraryController.getAllSeriesForLibrary.bind(this)) this.router.get('/libraries/:id/collections', LibraryController.middleware.bind(this), LibraryController.getCollectionsForLibrary.bind(this)) this.router.get('/libraries/:id/playlists', LibraryController.middleware.bind(this), LibraryController.getUserPlaylistsForLibrary.bind(this)) @@ -553,4 +554,4 @@ class ApiRouter { } } } -module.exports = ApiRouter \ No newline at end of file +module.exports = ApiRouter From 61c759e0c43b4e8e92fd56b99176fee9eedd8f8e Mon Sep 17 00:00:00 2001 From: mfcar Date: Sun, 5 Mar 2023 11:15:36 +0000 Subject: [PATCH 2/3] Add tasks queue dropdown --- .../components/cards/ItemTaskRunningCard.vue | 85 +++++++++++++++++++ .../components/widgets/NotificationWidget.vue | 78 +++++++++++++++-- .../_library/podcast/download-queue.vue | 26 ++++-- client/strings/de.json | 2 + client/strings/en-us.json | 2 + client/strings/es.json | 2 + client/strings/fr.json | 2 + client/strings/hr.json | 2 + client/strings/it.json | 2 + client/strings/pl.json | 2 + client/strings/ru.json | 2 + client/strings/zh-cn.json | 2 + server/Server.js | 2 +- server/managers/PodcastManager.js | 25 +++++- 14 files changed, 213 insertions(+), 21 deletions(-) create mode 100644 client/components/cards/ItemTaskRunningCard.vue diff --git a/client/components/cards/ItemTaskRunningCard.vue b/client/components/cards/ItemTaskRunningCard.vue new file mode 100644 index 00000000..f7ee4095 --- /dev/null +++ b/client/components/cards/ItemTaskRunningCard.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/client/components/widgets/NotificationWidget.vue b/client/components/widgets/NotificationWidget.vue index 6c3e82fd..f1fd6dc6 100644 --- a/client/components/widgets/NotificationWidget.vue +++ b/client/components/widgets/NotificationWidget.vue @@ -1,15 +1,51 @@ \ No newline at end of file + + + diff --git a/client/pages/library/_library/podcast/download-queue.vue b/client/pages/library/_library/podcast/download-queue.vue index 11785887..53160c73 100644 --- a/client/pages/library/_library/podcast/download-queue.vue +++ b/client/pages/library/_library/podcast/download-queue.vue @@ -57,6 +57,15 @@ import DownloadQueueTable from "~/components/tables/podcast/DownloadQueueTable.v export default { components: {DownloadQueueTable}, + async asyncData({ params, redirect }) { + if (!params.library) { + console.error('No library...', params.library) + return redirect('/') + } + return { + libraryId: params.library + } + }, data() { return { episodesDownloading: [], @@ -70,45 +79,44 @@ export default { }, streamLibraryItem() { return this.$store.state.streamLibraryItem - }, - currentLibraryId() { - return this.$store.state.libraries.currentLibraryId } }, methods: { episodeDownloadQueued(episodeDownload) { - if (episodeDownload.libraryId === this.currentLibraryId) { + if (episodeDownload.libraryId === this.libraryId) { this.episodeDownloadsQueued.push(episodeDownload) } }, episodeDownloadStarted(episodeDownload) { - if (episodeDownload.libraryId === this.currentLibraryId) { + if (episodeDownload.libraryId === this.libraryId) { this.episodeDownloadsQueued = this.episodeDownloadsQueued.filter((d) => d.id !== episodeDownload.id) this.episodesDownloading.push(episodeDownload) } }, episodeDownloadFinished(episodeDownload) { - if (episodeDownload.libraryId === this.currentLibraryId) { + if (episodeDownload.libraryId === this.libraryId) { this.episodeDownloadsQueued = this.episodeDownloadsQueued.filter((d) => d.id !== episodeDownload.id) this.episodesDownloading = this.episodesDownloading.filter((d) => d.id !== episodeDownload.id) } }, downloadQueueUpdated(downloadQueue) { - this.episodeDownloadsQueued = downloadQueue.filter((q) => q.libraryId == this.currentLibraryId) + this.episodeDownloadsQueued = downloadQueue.filter((q) => q.libraryId == this.libraryId) }, async loadInitialDownloadQueue() { this.processing = true - const queuePayload = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/downloads`).catch((error) => { + const queuePayload = await this.$axios.$get(`/api/libraries/${this.libraryId}/downloads`).catch((error) => { console.error('Failed to get download queue', error) this.$toast.error('Failed to get download queue') return null }) this.processing = false - console.log('Episodes', queuePayload) this.episodeDownloadsQueued = queuePayload || [] } }, mounted() { + if (this.libraryId) { + this.$store.commit('libraries/setCurrentLibrary', this.libraryId) + } this.loadInitialDownloadQueue() this.$root.socket.on('episode_download_queued', this.episodeDownloadQueued) this.$root.socket.on('episode_download_started', this.episodeDownloadStarted) diff --git a/client/strings/de.json b/client/strings/de.json index e1c3b02f..32de2cfe 100644 --- a/client/strings/de.json +++ b/client/strings/de.json @@ -395,6 +395,7 @@ "LabelTag": "Schlagwort", "LabelTags": "Schlagwörter", "LabelTagsAccessibleToUser": "Für Benutzer zugängliche Schlagwörter", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Gehörte Zeit", "LabelTimeListenedToday": "Heute gehörte Zeit", "LabelTimeRemaining": "{0} verbleibend", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Keine Suchergebnisse für \"{0}\"", "MessageNoSeries": "Keine Serien", "MessageNoTags": "Keine Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Noch nicht implementiert", "MessageNoUpdateNecessary": "Keine Aktualisierung erforderlich", "MessageNoUpdatesWereNecessary": "Keine Aktualisierungen waren notwendig", diff --git a/client/strings/en-us.json b/client/strings/en-us.json index c8e87d28..a76db534 100644 --- a/client/strings/en-us.json +++ b/client/strings/en-us.json @@ -395,6 +395,7 @@ "LabelTag": "Tag", "LabelTags": "Tags", "LabelTagsAccessibleToUser": "Tags Accessible to User", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Time Listened", "LabelTimeListenedToday": "Time Listened Today", "LabelTimeRemaining": "{0} remaining", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "No search results for \"{0}\"", "MessageNoSeries": "No Series", "MessageNoTags": "No Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Not yet implemented", "MessageNoUpdateNecessary": "No update necessary", "MessageNoUpdatesWereNecessary": "No updates were necessary", diff --git a/client/strings/es.json b/client/strings/es.json index c8e87d28..a76db534 100644 --- a/client/strings/es.json +++ b/client/strings/es.json @@ -395,6 +395,7 @@ "LabelTag": "Tag", "LabelTags": "Tags", "LabelTagsAccessibleToUser": "Tags Accessible to User", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Time Listened", "LabelTimeListenedToday": "Time Listened Today", "LabelTimeRemaining": "{0} remaining", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "No search results for \"{0}\"", "MessageNoSeries": "No Series", "MessageNoTags": "No Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Not yet implemented", "MessageNoUpdateNecessary": "No update necessary", "MessageNoUpdatesWereNecessary": "No updates were necessary", diff --git a/client/strings/fr.json b/client/strings/fr.json index 2393110b..a4cdbfc9 100644 --- a/client/strings/fr.json +++ b/client/strings/fr.json @@ -395,6 +395,7 @@ "LabelTag": "Étiquette", "LabelTags": "Étiquettes", "LabelTagsAccessibleToUser": "Étiquettes accessibles à l'utilisateur", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Temps d'écoute", "LabelTimeListenedToday": "Nombres d'écoutes Aujourd'hui", "LabelTimeRemaining": "{0} restantes", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Pas de résultats de recherche pour \"{0}\"", "MessageNoSeries": "Pas de séries", "MessageNoTags": "Pas d'étiquettes", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Non implémenté", "MessageNoUpdateNecessary": "Pas de mise à jour nécessaire", "MessageNoUpdatesWereNecessary": "Aucune mise à jour n'était nécessaire", diff --git a/client/strings/hr.json b/client/strings/hr.json index 00d27566..404c4d78 100644 --- a/client/strings/hr.json +++ b/client/strings/hr.json @@ -395,6 +395,7 @@ "LabelTag": "Tag", "LabelTags": "Tags", "LabelTagsAccessibleToUser": "Tags dostupni korisniku", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Vremena odslušano", "LabelTimeListenedToday": "Vremena odslušano danas", "LabelTimeRemaining": "{0} preostalo", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Nema rezultata pretragee za \"{0}\"", "MessageNoSeries": "No Series", "MessageNoTags": "No Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Not yet implemented", "MessageNoUpdateNecessary": "Aktualiziranje nije potrebno", "MessageNoUpdatesWereNecessary": "Aktualiziranje nije bilo potrebno", diff --git a/client/strings/it.json b/client/strings/it.json index 8818f8fd..f6c2b528 100644 --- a/client/strings/it.json +++ b/client/strings/it.json @@ -395,6 +395,7 @@ "LabelTag": "Tag", "LabelTags": "Tags", "LabelTagsAccessibleToUser": "Tags permessi agli Utenti", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Tempo di Ascolto", "LabelTimeListenedToday": "Tempo di Ascolto Oggi", "LabelTimeRemaining": "{0} rimanente", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Nessun risultato per \"{0}\"", "MessageNoSeries": "Nessuna Serie", "MessageNoTags": "No Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Non Ancora Implementato", "MessageNoUpdateNecessary": "Nessun aggiornamento necessario", "MessageNoUpdatesWereNecessary": "Nessun aggiornamento necessario", diff --git a/client/strings/pl.json b/client/strings/pl.json index 4ecdcff9..db18a20f 100644 --- a/client/strings/pl.json +++ b/client/strings/pl.json @@ -395,6 +395,7 @@ "LabelTag": "Tag", "LabelTags": "Tagi", "LabelTagsAccessibleToUser": "Tagi dostępne dla użytkownika", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Czas odtwarzania", "LabelTimeListenedToday": "Czas odtwarzania dzisiaj", "LabelTimeRemaining": "Pozostało {0}", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Brak wyników wyszukiwania dla \"{0}\"", "MessageNoSeries": "No Series", "MessageNoTags": "No Tags", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Jeszcze nie zaimplementowane", "MessageNoUpdateNecessary": "Brak konieczności aktualizacji", "MessageNoUpdatesWereNecessary": "Brak aktualizacji", diff --git a/client/strings/ru.json b/client/strings/ru.json index dd50a169..dd5d36d2 100644 --- a/client/strings/ru.json +++ b/client/strings/ru.json @@ -395,6 +395,7 @@ "LabelTag": "Тег", "LabelTags": "Теги", "LabelTagsAccessibleToUser": "Теги Доступные для Пользователя", + "LabelTasks": "Tasks Running", "LabelTimeListened": "Время Прослушивания", "LabelTimeListenedToday": "Время Прослушивания Сегодня", "LabelTimeRemaining": "{0} осталось", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "Нет результатов поиска для \"{0}\"", "MessageNoSeries": "Нет Серий", "MessageNoTags": "Нет Тегов", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "Пока не реализовано", "MessageNoUpdateNecessary": "Обновление не требуется", "MessageNoUpdatesWereNecessary": "Обновления не требовались", diff --git a/client/strings/zh-cn.json b/client/strings/zh-cn.json index 671fde5a..16234d90 100644 --- a/client/strings/zh-cn.json +++ b/client/strings/zh-cn.json @@ -395,6 +395,7 @@ "LabelTag": "标签", "LabelTags": "标签", "LabelTagsAccessibleToUser": "用户可访问的标签", + "LabelTasks": "Tasks Running", "LabelTimeListened": "收听时间", "LabelTimeListenedToday": "今日收听的时间", "LabelTimeRemaining": "剩余 {0}", @@ -514,6 +515,7 @@ "MessageNoSearchResultsFor": "没有搜索到结果 \"{0}\"", "MessageNoSeries": "无系列", "MessageNoTags": "无标签", + "MessageNoTasksRunning": "No Tasks Running", "MessageNotYetImplemented": "尚未实施", "MessageNoUpdateNecessary": "无需更新", "MessageNoUpdatesWereNecessary": "无需更新", diff --git a/server/Server.js b/server/Server.js index a5a0b8b5..4a900a68 100644 --- a/server/Server.js +++ b/server/Server.js @@ -72,7 +72,7 @@ class Server { this.abMergeManager = new AbMergeManager(this.db, this.taskManager) this.playbackSessionManager = new PlaybackSessionManager(this.db) this.coverManager = new CoverManager(this.db, this.cacheManager) - this.podcastManager = new PodcastManager(this.db, this.watcher, this.notificationManager) + this.podcastManager = new PodcastManager(this.db, this.watcher, this.notificationManager, this.taskManager) this.audioMetadataManager = new AudioMetadataMangaer(this.db, this.taskManager) this.rssFeedManager = new RssFeedManager(this.db) this.eBookManager = new EBookManager(this.db) diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js index 3b7e352b..6c974591 100644 --- a/server/managers/PodcastManager.js +++ b/server/managers/PodcastManager.js @@ -14,12 +14,15 @@ const LibraryFile = require('../objects/files/LibraryFile') const PodcastEpisodeDownload = require('../objects/PodcastEpisodeDownload') const PodcastEpisode = require('../objects/entities/PodcastEpisode') const AudioFile = require('../objects/files/AudioFile') +const Task = require("../objects/Task"); +const Path = require("path"); class PodcastManager { - constructor(db, watcher, notificationManager) { + constructor(db, watcher, notificationManager, taskManager) { this.db = db this.watcher = watcher this.notificationManager = notificationManager + this.taskManager = taskManager this.downloadQueue = [] this.currentDownload = null @@ -57,11 +60,11 @@ class PodcastManager { newPe.libraryItemId = libraryItem.id var newPeDl = new PodcastEpisodeDownload() newPeDl.setData(newPe, libraryItem, isAutoDownload, libraryItem.libraryId) - this.startPodcastEpisodeDownload(newPeDl) + this.startPodcastEpisodeDownload(newPeDl, libraryItem) }) } - async startPodcastEpisodeDownload(podcastEpisodeDownload) { + async startPodcastEpisodeDownload(podcastEpisodeDownload, libraryItem) { SocketAuthority.emitter('download_queue_updated', this.getDownloadQueueDetails()) if (this.currentDownload) { this.downloadQueue.push(podcastEpisodeDownload) @@ -69,6 +72,15 @@ class PodcastManager { return } + const task = new Task() + const taskDescription = `Downloading episode "${podcastEpisodeDownload.podcastEpisode.title}".` + const taskData = { + libraryId: libraryItem.libraryId, + libraryItemId: libraryItem.id, + } + task.setData('download-podcast-episode', 'Downloading Episode', taskDescription, taskData) + this.taskManager.addTask(task) + SocketAuthority.emitter('episode_download_started', podcastEpisodeDownload.toJSONForClient()) this.currentDownload = podcastEpisodeDownload @@ -91,21 +103,26 @@ class PodcastManager { if (!success) { await fs.remove(this.currentDownload.targetPath) this.currentDownload.setFinished(false) + task.setFailed('Failed to download episode') } else { Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`) this.currentDownload.setFinished(true) + task.setFinished() } } else { + task.setFailed('Failed to download episode') this.currentDownload.setFinished(false) } + this.taskManager.taskFinished(task) + SocketAuthority.emitter('episode_download_finished', this.currentDownload.toJSONForClient()) SocketAuthority.emitter('download_queue_updated', this.getDownloadQueueDetails()) this.watcher.removeIgnoreDir(this.currentDownload.libraryItem.path) this.currentDownload = null if (this.downloadQueue.length) { - this.startPodcastEpisodeDownload(this.downloadQueue.shift()) + this.startPodcastEpisodeDownload(this.downloadQueue.shift(), libraryItem) } } From 022bf9d0efd0ba76a875795774db0947dc491c14 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 5 Mar 2023 10:35:34 -0600 Subject: [PATCH 3/3] Show current episode download on init and download queue page updates --- .../tables/podcast/DownloadQueueTable.vue | 11 ++--- .../components/widgets/NotificationWidget.vue | 4 +- client/pages/item/_id/index.vue | 7 ++- .../_library/podcast/download-queue.vue | 43 +++++++++++-------- .../pages/library/_library/podcast/latest.vue | 8 +++- server/controllers/LibraryController.js | 8 ++-- server/controllers/LibraryItemController.js | 7 ++- server/managers/PodcastManager.js | 42 ++++++++---------- server/objects/PodcastEpisodeDownload.js | 16 +++---- server/routers/ApiRouter.js | 2 +- 10 files changed, 74 insertions(+), 74 deletions(-) diff --git a/client/components/tables/podcast/DownloadQueueTable.vue b/client/components/tables/podcast/DownloadQueueTable.vue index 2dfe87f0..4b911229 100644 --- a/client/components/tables/podcast/DownloadQueueTable.vue +++ b/client/components/tables/podcast/DownloadQueueTable.vue @@ -10,7 +10,7 @@
- + @@ -58,11 +58,8 @@ export default { data() { return {} }, - computed: { - }, - methods: { - }, - mounted() { - } + computed: {}, + methods: {}, + mounted() {} } diff --git a/client/components/widgets/NotificationWidget.vue b/client/components/widgets/NotificationWidget.vue index f1fd6dc6..f70f840d 100644 --- a/client/components/widgets/NotificationWidget.vue +++ b/client/components/widgets/NotificationWidget.vue @@ -14,8 +14,8 @@
{{ $strings.LabelPodcast }}{{ $strings.LabelPodcast }} {{ $strings.LabelEpisode }} {{ $strings.LabelEpisodeTitle }} {{ $strings.LabelPubDate }}