From dbb62069ef2c985e55afd9a4be68a3c4bceafbce Mon Sep 17 00:00:00 2001 From: Nick Thomson <nick-github@undergrid.org.uk> Date: Fri, 23 Sep 2022 17:51:34 +0100 Subject: [PATCH] Implementation of batch quick match API and related options dialog --- .../modals/BatchQuickMatchModel.vue | 89 +++++++++++++++---- client/layouts/default.vue | 1 + server/controllers/LibraryItemController.js | 25 ++++++ server/routers/ApiRouter.js | 1 + 4 files changed, 99 insertions(+), 17 deletions(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index d02c39f4..c424baaa 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -10,7 +10,39 @@ <div v-if="show" class="w-full h-full"> <div class="py-4 px-4"> <h1 class="text-2xl">Quick Match {{ selectedBookIds.length }} Books</h1> - </div> + </div> + + <div class="w-full overflow-y-auto overflow-x-hidden max-h-96"> + <div class="flex px-8 items-center py-2"> + <p class="pr-4">Provider</p> + <ui-dropdown v-model="options.provider" :items="providers" small /> + </div> + <div class="flex px-8 items-end py-2"> + <ui-toggle-switch v-model="options.overrideCover"/> + <ui-tooltip :text="tooltips.updateCovers"> + <p class="pl-4"> + Update Covers + <span class="material-icons icon-text text-sm">info_outlined</span> + </p> + </ui-tooltip> + </div> + <div class="flex px-8 items-end py-2"> + <ui-toggle-switch v-model="options.overrideDetails"/> + <ui-tooltip :text="tooltips.updateDetails"> + <p class="pl-4"> + Update Details + <span class="material-icons icon-text text-sm">info_outlined</span> + </p> + </ui-tooltip> + </div> + <div class="mt-4 py-4 border-b border-white border-opacity-10 text-white text-opacity-80" :class="isScrollable ? 'box-shadow-md-up' : 'border-t border-white border-opacity-5'"> + <div class="flex items-center px-4"> + <ui-btn type="button" @click="show = false">Cancel</ui-btn> + <div class="flex-grow" /> + <ui-btn color="success" @click="doBatchQuickMatch">Continue</ui-btn> + </div> + </div> + </div> </div> </div> </modals-modal> @@ -20,7 +52,16 @@ export default { data() { return { - processing: false + processing: false, + options: { + provider: 'google', + overrideDetails: true, + overrideCover: true + }, + tooltips: { + updateCovers: 'Update the selected book covers when a match is located.', + updateDetails: 'Update the selected book details when a match is located.' + } } }, computed: { @@ -45,26 +86,40 @@ export default { }, currentLibraryId() { return this.$store.state.libraries.currentLibraryId + }, + providers() { + if (this.isPodcast) return this.$store.state.scanners.podcastProviders + return this.$store.state.scanners.providers } }, methods: { + doBatchQuickMatch() { + if (!this.selectedBookIds.length) return + if (this.processing) return + + this.processing = true + this.$store.commit('setProcessingBatch', true) + this.$axios + .$post(`/api/items/batch/quickmatch`, { + options: this.options, + libraryItemIds: this.selectedBookIds + }) + .then(() => { + this.$toast.success('Batch quick match success!') + this.processing = false + this.$store.commit('setProcessingBatch', false) + this.show = false + }) + .catch((error) => { + this.$toast.error('Batch quick match failed') + console.error('Failed to batch quick match', error) + this.processing = false + this.$store.commit('setProcessingBatch', false) + this.show = false + }) + } }, mounted() {} } </script> -<style> -.list-complete-item { - transition: all 0.8s ease; -} - -.list-complete-enter-from, -.list-complete-leave-to { - opacity: 0; - transform: translateY(30px); -} - -.list-complete-leave-active { - position: absolute; -} -</style> \ No newline at end of file diff --git a/client/layouts/default.vue b/client/layouts/default.vue index 3e4202f2..89be096e 100644 --- a/client/layouts/default.vue +++ b/client/layouts/default.vue @@ -15,6 +15,7 @@ <modals-podcast-edit-episode /> <modals-podcast-view-episode /> <modals-authors-edit-modal /> + <modals-batch-quick-match-model /> <prompt-confirm /> <readers-reader /> </div> diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 328e75a5..9eba9cc6 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -305,6 +305,31 @@ class LibraryItemController { res.json(libraryItems) } + // POST: api/items/batch/quickmatch + async batchQuickMatch(req, res) { + var itemsUpdated = 0 + + var matchData = req.body + var options = matchData.options || {} + var items = matchData.libraryItemIds + if (!items || !items.length) { + return res.sendStatus(500) + } + + for (let i = 0; i < items.length; i++) { + var libraryItem = this.db.libraryItems.find(_li => _li.id === items[i]) + var matchResult = await this.scanner.quickMatchLibraryItem(libraryItem, options) + if (matchResult.updated) { + itemsUpdated++ + } + } + + res.json({ + success: itemsUpdated > 0, + updates: itemsUpdated + }) + } + // DELETE: api/items/all async deleteAll(req, res) { if (!req.user.isAdminOrUp) { diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index edb293df..27b8233c 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -101,6 +101,7 @@ class ApiRouter { this.router.post('/items/batch/delete', LibraryItemController.batchDelete.bind(this)) this.router.post('/items/batch/update', LibraryItemController.batchUpdate.bind(this)) this.router.post('/items/batch/get', LibraryItemController.batchGet.bind(this)) + this.router.post('/items/batch/quickmatch', LibraryItemController.batchQuickMatch.bind(this)) // // User Routes