From 0700f128960c9fb163a72d9ebabb907ba590aeec Mon Sep 17 00:00:00 2001 From: advplyr Date: Sat, 3 Sep 2022 08:31:37 -0500 Subject: [PATCH 001/213] Fix:Podcast episode sort by published at --- server/objects/mediaTypes/Podcast.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/objects/mediaTypes/Podcast.js b/server/objects/mediaTypes/Podcast.js index 7e5e0f44b..54a382993 100644 --- a/server/objects/mediaTypes/Podcast.js +++ b/server/objects/mediaTypes/Podcast.js @@ -228,6 +228,7 @@ class Podcast { addPodcastEpisode(podcastEpisode) { this.episodes.push(podcastEpisode) + this.reorderEpisodes() } addNewEpisodeFromAudioFile(audioFile, index) { @@ -241,15 +242,13 @@ class Podcast { reorderEpisodes() { var hasUpdates = false - // TODO: Sort by published date - this.episodes = naturalSort(this.episodes).asc((ep) => ep.bestFilename) + this.episodes = naturalSort(this.episodes).desc((ep) => ep.publishedAt) for (let i = 0; i < this.episodes.length; i++) { if (this.episodes[i].index !== (i + 1)) { this.episodes[i].index = i + 1 hasUpdates = true } } - this.episodes.sort((a, b) => b.index - a.index) return hasUpdates } From 174decf8da21f3c86de420fc8bf299ce90edd333 Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 5 Sep 2022 15:45:44 -0500 Subject: [PATCH 002/213] Version bump 2.1.5 --- client/package-lock.json | 4 ++-- client/package.json | 2 +- package-lock.json | 6 +++--- package.json | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 238d6d367..8d5cd1008 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "audiobookshelf-client", - "version": "2.1.4", + "version": "2.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "audiobookshelf-client", - "version": "2.1.2", + "version": "2.1.5", "license": "ISC", "dependencies": { "@nuxtjs/axios": "^5.13.6", diff --git a/client/package.json b/client/package.json index 49bf642b8..bc2d5ed27 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-client", - "version": "2.1.4", + "version": "2.1.5", "description": "Self-hosted audiobook and podcast client", "main": "index.js", "scripts": { diff --git a/package-lock.json b/package-lock.json index 9dcf99dfa..6388098a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "audiobookshelf", - "version": "2.1.4", + "version": "2.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "audiobookshelf", - "version": "2.1.4", + "version": "2.1.5", "license": "GPL-3.0", "dependencies": { "axios": "^0.26.1", @@ -1602,4 +1602,4 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 4ef96a142..5fc15ffda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "2.1.4", + "version": "2.1.5", "description": "Self-hosted audiobook and podcast server", "main": "index.js", "scripts": { From baedced83f0cbdabc848827783d803211f7defee Mon Sep 17 00:00:00 2001 From: Zibbp Date: Thu, 8 Sep 2022 10:02:40 -0500 Subject: [PATCH 003/213] feat(player): persist volume in local storage --- client/components/controls/VolumeControl.vue | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/components/controls/VolumeControl.vue b/client/components/controls/VolumeControl.vue index b748f6537..7212357b4 100644 --- a/client/components/controls/VolumeControl.vue +++ b/client/components/controls/VolumeControl.vue @@ -37,6 +37,11 @@ export default { return this.value }, set(val) { + try { + localStorage.setItem("volume", val); + } catch(error) { + console.error('Failed to store volume', err) + } this.$emit('input', val) } }, @@ -141,6 +146,10 @@ export default { if (this.value === 0) { this.isMute = true } + const storageVolume = localStorage.getItem("volume") + if (storageVolume) { + this.volume = parseFloat(storageVolume) + } }, beforeDestroy() { window.removeEventListener('mousewheel', this.scroll) From e32f51f58aef256d87a2fa56dbfeef4ddfedea74 Mon Sep 17 00:00:00 2001 From: advplyr Date: Fri, 9 Sep 2022 17:40:06 -0500 Subject: [PATCH 004/213] Fix:Add podcast modal for mobile screen sizes #975 --- client/components/modals/podcast/NewModal.vue | 24 +++++++++---------- server/utils/scandir.js | 2 -- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/client/components/modals/podcast/NewModal.vue b/client/components/modals/podcast/NewModal.vue index ec577deda..59ad7276e 100644 --- a/client/components/modals/podcast/NewModal.vue +++ b/client/components/modals/podcast/NewModal.vue @@ -1,18 +1,18 @@
-
+
@@ -16,7 +16,7 @@ -
+

Enabled

@@ -25,105 +25,6 @@ Submit
-
@@ -195,6 +96,11 @@ export default { if (this.$refs.modal) this.$refs.modal.setHide() }, submitForm() { + if (!this.newNotification.urls.length) { + this.$toast.error('Must enter an Apprise URL') + return + } + if (this.isNew) { this.submitCreate() } else { @@ -263,11 +169,12 @@ export default { libraryId: null, eventName: 'onTest', urls: [], - titleTemplate: 'Test Title', - bodyTemplate: 'Test Body', + titleTemplate: '', + bodyTemplate: '', enabled: true, type: null } + this.eventOptionUpdated() } } }, diff --git a/client/pages/config/notifications.vue b/client/pages/config/notifications.vue index aed7df90f..7bda9d23d 100644 --- a/client/pages/config/notifications.vue +++ b/client/pages/config/notifications.vue @@ -59,6 +59,15 @@ export default { this.selectedNotification = null this.showEditModal = true }, + validateAppriseApiUrl() { + try { + return new URL(this.appriseApiUrl) + } catch (error) { + console.log('URL error', error) + this.$toast.error(error.message) + return false + } + }, submitForm() { if (this.notificationSettings && this.notificationSettings.appriseApiUrl == this.appriseApiUrl) { this.$toast.info('No update necessary') @@ -69,7 +78,10 @@ export default { this.$refs.apiUrlInput.blur() } - // TODO: Validate apprise api url + const isValid = this.validateAppriseApiUrl() + if (!isValid) { + return + } const updatePayload = { appriseApiUrl: this.appriseApiUrl || null @@ -99,14 +111,25 @@ export default { if (!notificationResponse) { return } - this.notificationSettings = notificationResponse.settings this.notificationData = notificationResponse.data - this.appriseApiUrl = this.notificationSettings.appriseApiUrl - this.notifications = this.notificationSettings.notifications || [] + this.setNotificationSettings(notificationResponse.settings) + }, + setNotificationSettings(notificationSettings) { + this.notificationSettings = notificationSettings + this.appriseApiUrl = notificationSettings.appriseApiUrl + this.notifications = notificationSettings.notifications || [] + }, + notificationsUpdated(notificationSettings) { + console.log('Notifications updated', notificationSettings) + this.setNotificationSettings(notificationSettings) } }, mounted() { this.init() + this.$root.socket.on('notifications_updated', this.notificationsUpdated) + }, + beforeDestroy() { + this.$root.socket.off('notifications_updated', this.notificationsUpdated) } } \ No newline at end of file diff --git a/server/Server.js b/server/Server.js index f494fc23a..0df379ee1 100644 --- a/server/Server.js +++ b/server/Server.js @@ -65,7 +65,7 @@ class Server { this.auth = new Auth(this.db) // Managers - this.notificationManager = new NotificationManager(this.db) + this.notificationManager = new NotificationManager(this.db, this.emitter.bind(this)) this.backupManager = new BackupManager(this.db, this.emitter.bind(this)) this.logManager = new LogManager(this.db) this.cacheManager = new CacheManager() diff --git a/server/controllers/NotificationController.js b/server/controllers/NotificationController.js index a51f35387..5714a8166 100644 --- a/server/controllers/NotificationController.js +++ b/server/controllers/NotificationController.js @@ -1,4 +1,5 @@ const Logger = require('../Logger') +const { version } = require('../../package.json') class NotificationController { constructor() { } @@ -22,6 +23,11 @@ class NotificationController { res.json(this.notificationManager.getData()) } + async fireTestEvent(req, res) { + await this.notificationManager.triggerNotification('onTest', { version: `v${version}` }, req.query.fail === '1') + res.sendStatus(200) + } + async createNotification(req, res) { const success = this.db.notificationSettings.createNotification(req.body) @@ -40,17 +46,18 @@ class NotificationController { async updateNotification(req, res) { const success = this.db.notificationSettings.updateNotification(req.body) - console.log('Update notification', success, req.body) if (success) { await this.db.updateEntity('settings', this.db.notificationSettings) } res.json(this.db.notificationSettings) } - sendNotificationTest(req, res) { - if (!this.db.notificationSettings.isUsable) return res.status(500).send('Apprise is not configured') - this.notificationManager.onTest() - res.sendStatus(200) + async sendNotificationTest(req, res) { + if (!this.db.notificationSettings.isUseable) return res.status(500).send('Apprise is not configured') + + const success = await this.notificationManager.sendTestNotification(req.notification) + if (success) res.sendStatus(200) + else res.sendStatus(500) } middleware(req, res, next) { diff --git a/server/managers/NotificationManager.js b/server/managers/NotificationManager.js index 63d273792..f947f668b 100644 --- a/server/managers/NotificationManager.js +++ b/server/managers/NotificationManager.js @@ -3,8 +3,9 @@ const Logger = require("../Logger") const { notificationData } = require('../utils/notifications') class NotificationManager { - constructor(db) { + constructor(db, emitter) { this.db = db + this.emitter = emitter this.notificationFailedMap = {} } @@ -17,38 +18,59 @@ class NotificationManager { if (!this.db.notificationSettings.isUseable) return Logger.debug(`[NotificationManager] onPodcastEpisodeDownloaded: Episode "${episode.title}" for podcast ${libraryItem.media.metadata.title}`) - this.triggerNotification('onPodcastEpisodeDownloaded', { libraryItem, episode }) + const library = this.db.libraries.find(lib => lib.id === libraryItem.libraryId) + const eventData = { + libraryItemId: libraryItem.id, + libraryId: libraryItem.libraryId, + libraryName: library ? library.name : 'Unknown', + podcastTitle: libraryItem.media.metadata.title, + episodeId: episode.id, + episodeTitle: episode.title + } + this.triggerNotification('onPodcastEpisodeDownloaded', eventData) } onTest() { this.triggerNotification('onTest') } - async triggerNotification(eventName, eventData) { - if (!this.db.notificationSettings.isUseable) return + async triggerNotification(eventName, eventData, intentionallyFail = false) { + if (!this.db.notificationSettings.isUseable) return false const notifications = this.db.notificationSettings.getNotificationsForEvent(eventName) for (const notification of notifications) { Logger.debug(`[NotificationManager] triggerNotification: Sending ${eventName} notification ${notification.id}`) - const success = await this.sendNotification(notification, eventData) + const success = intentionallyFail ? false : await this.sendNotification(notification, eventData) + notification.updateNotificationFired(success) if (!success) { // Failed notification - if (!this.notificationFailedMap[notification.id]) this.notificationFailedMap[notification.id] = 1 - else this.notificationFailedMap[notification.id]++ - - if (this.notificationFailedMap[notification.id] > 2) { + if (notification.numConsecutiveFailedAttempts > 2) { Logger.error(`[NotificationManager] triggerNotification: ${notification.eventName}/${notification.id} reached max failed attempts`) - // TODO: Do something like disable the notification + notification.enabled = false + } else { + Logger.error(`[NotificationManager] triggerNotification: ${notification.eventName}/${notification.id} ${notification.numConsecutiveFailedAttempts} failed attempts`) } - } else { // Successful notification - delete this.notificationFailedMap[notification.id] } } + + await this.db.updateEntity('settings', this.db.notificationSettings) + this.emitter('notifications_updated', this.db.notificationSettings) + return true + } + + sendTestNotification(notification) { + const eventData = notificationData.events.find(e => e.name === notification.eventName) + if (!eventData) { + Logger.error(`[NotificationManager] sendTestNotification: Event not found ${notification.eventName}`) + return false + } + + return this.sendNotification(notification, eventData.testData) } sendNotification(notification, eventData) { const payload = notification.getApprisePayload(eventData) - return axios.post(`${this.db.notificationSettings.appriseApiUrl}/notify`, payload, { timeout: 6000 }).then((response) => { + return axios.post(this.db.notificationSettings.appriseApiUrl, payload, { timeout: 6000 }).then((response) => { Logger.debug(`[NotificationManager] sendNotification: ${notification.eventName}/${notification.id} response=`, response.data) return true }).catch((error) => { diff --git a/server/objects/Notification.js b/server/objects/Notification.js index 202e4c7ea..4dffe040e 100644 --- a/server/objects/Notification.js +++ b/server/objects/Notification.js @@ -11,6 +11,10 @@ class Notification { this.type = 'info' this.enabled = false + this.lastFiredAt = null + this.lastAttemptFailed = false + this.numConsecutiveFailedAttempts = 0 + this.numTimesFired = 0 this.createdAt = null if (notification) { @@ -27,6 +31,10 @@ class Notification { this.bodyTemplate = notification.bodyTemplate || '' this.type = notification.type || 'info' this.enabled = !!notification.enabled + this.lastFiredAt = notification.lastFiredAt || null + this.lastAttemptFailed = !!notification.lastAttemptFailed + this.numConsecutiveFailedAttempts = notification.numConsecutiveFailedAttempts || 0 + this.numTimesFired = notification.numTimesFired || 0 this.createdAt = notification.createdAt } @@ -40,6 +48,10 @@ class Notification { bodyTemplate: this.bodyTemplate, enabled: this.enabled, type: this.type, + lastFiredAt: this.lastFiredAt, + lastAttemptFailed: this.lastAttemptFailed, + numConsecutiveFailedAttempts: this.numConsecutiveFailedAttempts, + numTimesFired: this.numTimesFired, createdAt: this.createdAt } } @@ -57,6 +69,13 @@ class Notification { } update(payload) { + if (!this.enabled && payload.enabled) { + // Reset + this.lastFiredAt = null + this.lastAttemptFailed = false + this.numConsecutiveFailedAttempts = 0 + } + const keysToUpdate = ['libraryId', 'eventName', 'urls', 'titleTemplate', 'bodyTemplate', 'enabled', 'type'] var hasUpdated = false for (const key of keysToUpdate) { @@ -75,14 +94,32 @@ class Notification { return hasUpdated } + updateNotificationFired(success) { + this.lastFiredAt = Date.now() + this.lastAttemptFailed = !success + this.numConsecutiveFailedAttempts = success ? 0 : this.numConsecutiveFailedAttempts + 1 + this.numTimesFired++ + } + + replaceVariablesInTemplate(templateText, data) { + const ptrn = /{{ ?([a-zA-Z]+) ?}}/mg + + var match + var updatedTemplate = templateText + while ((match = ptrn.exec(templateText)) != null) { + if (data[match[1]]) { + updatedTemplate = updatedTemplate.replace(match[0], data[match[1]]) + } + } + return updatedTemplate + } + parseTitleTemplate(data) { - // TODO: Implement template parsing - return 'Test Title' + return this.replaceVariablesInTemplate(this.titleTemplate, data) } parseBodyTemplate(data) { - // TODO: Implement template parsing - return 'Test Body' + return this.replaceVariablesInTemplate(this.bodyTemplate, data) } getApprisePayload(data) { diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 812aa2b5e..9f612cbef 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -207,6 +207,7 @@ class ApiRouter { this.router.get('/notifications', NotificationController.middleware.bind(this), NotificationController.get.bind(this)) this.router.patch('/notifications', NotificationController.middleware.bind(this), NotificationController.update.bind(this)) this.router.get('/notificationdata', NotificationController.middleware.bind(this), NotificationController.getData.bind(this)) + this.router.get('/notifications/test', NotificationController.middleware.bind(this), NotificationController.fireTestEvent.bind(this)) this.router.post('/notifications', NotificationController.middleware.bind(this), NotificationController.createNotification.bind(this)) this.router.delete('/notifications/:id', NotificationController.middleware.bind(this), NotificationController.deleteNotification.bind(this)) this.router.patch('/notifications/:id', NotificationController.middleware.bind(this), NotificationController.updateNotification.bind(this)) diff --git a/server/utils/notifications.js b/server/utils/notifications.js index 4972f8754..efbbe4d8c 100644 --- a/server/utils/notifications.js +++ b/server/utils/notifications.js @@ -1,12 +1,37 @@ +const { version } = require('../../package.json') + module.exports.notificationData = { events: [ + { + name: 'onPodcastEpisodeDownloaded', + requiresLibrary: true, + libraryMediaType: 'podcast', + description: 'Triggered when a podcast episode is auto-downloaded', + variables: ['libraryItemId', 'libraryId', 'podcastTitle', 'episodeTitle', 'libraryName', 'episodeId'], + defaults: { + title: 'New {{podcastTitle}} Episode!', + body: '{{episodeTitle}} has been added to {{libraryName}} library.' + }, + testData: { + libraryItemId: 'li_notification_test', + libraryId: 'lib_test', + libraryName: 'Podcasts', + podcastTitle: 'Abs Test Podcast', + episodeId: 'ep_notification_test', + episodeTitle: 'Successful Test' + } + }, { name: 'onTest', requiresLibrary: false, description: 'Notification for testing', + variables: ['version'], defaults: { - title: 'Test Title', - body: 'Test Body' + title: 'Test Notification on Abs {{version}}', + body: 'Test notificataion body for abs {{version}}.' + }, + testData: { + version: 'v' + version } } ] From 3e7a76574b3178f3f697979fcdf63392a9624545 Mon Sep 17 00:00:00 2001 From: Nick Thomson Date: Sat, 24 Sep 2022 22:17:36 +0100 Subject: [PATCH 034/213] Switch to using the websocket for confirmation of batch updates, allowing the main request to be done asynchronously --- client/components/modals/BatchQuickMatchModel.vue | 13 ++----------- client/layouts/default.vue | 14 ++++++++++++++ server/controllers/LibraryItemController.js | 13 ++++++++++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 77eb851ef..0df66dfd7 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -124,17 +124,8 @@ export default { options: this.options, libraryItemIds: this.selectedBookIds }) - .then((result) => { - var success = result.success || false - var toast = 'Batch quick match complete!\n' + result.updates + ' Updated' - if (result.unmatched && (result.unmatched > 0)) { - toast += '\n' + result.unmatched + ' with no matches' - } - if (success) { - this.$toast.success(toast) - } else { - this.$toast.info(toast) - } + .then(() => { + this.$toast.info('Batch quick match of ' + this.selectedBookIds.length + ' books started!') this.processing = false this.$store.commit('setProcessingBatch', false) this.show = false diff --git a/client/layouts/default.vue b/client/layouts/default.vue index 8998a92ce..1a23cde7f 100644 --- a/client/layouts/default.vue +++ b/client/layouts/default.vue @@ -359,6 +359,18 @@ export default { // Force refresh location.reload() }, + batchQuickMatchComplete(result) { + var success = result.success || false + var toast = 'Batch quick match complete!\n' + result.updates + ' Updated' + if (result.unmatched && (result.unmatched > 0)) { + toast += '\n' + result.unmatched + ' with no matches' + } + if (success) { + this.$toast.success(toast) + } else { + this.$toast.info(toast) + } + }, initializeSocket() { this.socket = this.$nuxtSocket({ name: process.env.NODE_ENV === 'development' ? 'dev' : 'prod', @@ -430,6 +442,8 @@ export default { this.socket.on('rss_feed_closed', this.rssFeedClosed) this.socket.on('backup_applied', this.backupApplied) + + this.socket.on('batch_quickmatch_complete', this.batchQuickMatchComplete) }, showUpdateToast(versionData) { var ignoreVersion = localStorage.getItem('ignoreVersion') diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 79e9c673b..32c297ec3 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -307,6 +307,11 @@ class LibraryItemController { // POST: api/items/batch/quickmatch async batchQuickMatch(req, res) { + if (!req.user.isAdminOrUp) { + Logger.warn('User other than admin attempted to batch quick match library items', req.user) + return res.sendStatus(403) + } + var itemsUpdated = 0 var itemsUnmatched = 0 @@ -316,6 +321,7 @@ class LibraryItemController { if (!items || !items.length) { return res.sendStatus(500) } + res.sendStatus(200); for (let i = 0; i < items.length; i++) { var libraryItem = this.db.libraryItems.find(_li => _li.id === items[i]) @@ -327,11 +333,12 @@ class LibraryItemController { } } - res.json({ + var result = { success: itemsUpdated > 0, updates: itemsUpdated, - unmatched: itemsUnmatched - }) + unmatched: itemsUnmatched + }; + this.clientEmitter(req.user.id, 'batch_quickmatch_complete', result) } // DELETE: api/items/all From dd8577354b8024a3e561f1685801e07c9c29ee09 Mon Sep 17 00:00:00 2001 From: Nick Thomson Date: Sat, 24 Sep 2022 22:20:49 +0100 Subject: [PATCH 035/213] Fixing tabs again. --- server/controllers/LibraryItemController.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 32c297ec3..4b6387464 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -311,9 +311,9 @@ class LibraryItemController { Logger.warn('User other than admin attempted to batch quick match library items', req.user) return res.sendStatus(403) } - + var itemsUpdated = 0 - var itemsUnmatched = 0 + var itemsUnmatched = 0 var matchData = req.body var options = matchData.options || {} @@ -321,7 +321,7 @@ class LibraryItemController { if (!items || !items.length) { return res.sendStatus(500) } - res.sendStatus(200); + res.sendStatus(200); for (let i = 0; i < items.length; i++) { var libraryItem = this.db.libraryItems.find(_li => _li.id === items[i]) @@ -329,16 +329,16 @@ class LibraryItemController { if (matchResult.updated) { itemsUpdated++ } else if (matchResult.warning) { - itemsUnmatched++ - } + itemsUnmatched++ + } } - var result = { + var result = { success: itemsUpdated > 0, updates: itemsUpdated, unmatched: itemsUnmatched }; - this.clientEmitter(req.user.id, 'batch_quickmatch_complete', result) + this.clientEmitter(req.user.id, 'batch_quickmatch_complete', result) } // DELETE: api/items/all From 022c506eda8312015219d91348f318866383967c Mon Sep 17 00:00:00 2001 From: Nick Thomson Date: Sat, 24 Sep 2022 22:50:21 +0100 Subject: [PATCH 036/213] Possible fix for issue #1004 --- server/libs/nodeFfprobe/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/server/libs/nodeFfprobe/index.js b/server/libs/nodeFfprobe/index.js index a6d78233f..ec52ef2a0 100644 --- a/server/libs/nodeFfprobe/index.js +++ b/server/libs/nodeFfprobe/index.js @@ -20,7 +20,14 @@ module.exports = (function () { proc.on('exit', code => { exitCode = code }) proc.on('error', err => reject(err)) - proc.on('close', () => resolve(JSON.parse(probeData.join('')))) + proc.on('close', () => { + try { + let result = JSON.parse(probeData.join('')) + resolve(result); + } catch (err) { + reject(err); + } + }) }) } From dd0d2e9f55fe032eecd1dffd3226d3a287af8593 Mon Sep 17 00:00:00 2001 From: Nick Thomson Date: Sat, 24 Sep 2022 22:51:17 +0100 Subject: [PATCH 037/213] Fix tabs --- server/libs/nodeFfprobe/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/libs/nodeFfprobe/index.js b/server/libs/nodeFfprobe/index.js index ec52ef2a0..e082d7a54 100644 --- a/server/libs/nodeFfprobe/index.js +++ b/server/libs/nodeFfprobe/index.js @@ -21,13 +21,13 @@ module.exports = (function () { proc.on('exit', code => { exitCode = code }) proc.on('error', err => reject(err)) proc.on('close', () => { - try { - let result = JSON.parse(probeData.join('')) - resolve(result); - } catch (err) { - reject(err); - } - }) + try { + let result = JSON.parse(probeData.join('')) + resolve(result); + } catch (err) { + reject(err); + } + }) }) } From 0f772fd3cf1b3ecc2f58942afe2b1205f9f94301 Mon Sep 17 00:00:00 2001 From: advplyr <67830747+advplyr@users.noreply.github.com> Date: Sat, 24 Sep 2022 17:36:29 -0500 Subject: [PATCH 038/213] Update server/libs/nodeFfprobe/index.js --- server/libs/nodeFfprobe/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/libs/nodeFfprobe/index.js b/server/libs/nodeFfprobe/index.js index e082d7a54..bdab89ad0 100644 --- a/server/libs/nodeFfprobe/index.js +++ b/server/libs/nodeFfprobe/index.js @@ -22,8 +22,7 @@ module.exports = (function () { proc.on('error', err => reject(err)) proc.on('close', () => { try { - let result = JSON.parse(probeData.join('')) - resolve(result); + resolve(JSON.parse(probeData.join(''))) } catch (err) { reject(err); } From 46a3974b79ba81f590817dfdcf149869af76c294 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:37:43 +0100 Subject: [PATCH 039/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 0df66dfd7..c14ca1f87 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -54,7 +54,6 @@ export default { data() { return { processing: false, - isScrollable: false, lastUsedLibrary: undefined, options: { provider: undefined, From 7fd70c1c86b7f1dbf37a3d0d9e267c5d562bdad3 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:37:54 +0100 Subject: [PATCH 040/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index c14ca1f87..09b8b9cc9 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -36,7 +36,7 @@

-
+
Cancel
From f3f2d614b1b886790edc101683fad1d46f8f57a2 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:37:59 +0100 Subject: [PATCH 041/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 09b8b9cc9..7fc7effa1 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -109,7 +109,7 @@ export default { // the selected provider to the current library default provider if (!this.options.provider || (this.options.lastUsedLibrary != this.currentLibraryId)) { this.options.lastUsedLibrary = this.currentLibraryId - this.options.provider = this.libraryProvider; + this.options.provider = this.libraryProvider } }, doBatchQuickMatch() { From 62c59c634cb8afd93b210fd20e0fe6902702c801 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:38:18 +0100 Subject: [PATCH 042/213] Update server/controllers/LibraryItemController.js Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- server/controllers/LibraryItemController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 4b6387464..90b1ec1d1 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -321,7 +321,7 @@ class LibraryItemController { if (!items || !items.length) { return res.sendStatus(500) } - res.sendStatus(200); + res.sendStatus(200) for (let i = 0; i < items.length; i++) { var libraryItem = this.db.libraryItems.find(_li => _li.id === items[i]) From 014ad668a54a0fceb86e95cbf4bdb367dcc3131c Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:38:44 +0100 Subject: [PATCH 043/213] Update server/controllers/LibraryItemController.js Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- server/controllers/LibraryItemController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 90b1ec1d1..acbc6926d 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -337,7 +337,7 @@ class LibraryItemController { success: itemsUpdated > 0, updates: itemsUpdated, unmatched: itemsUnmatched - }; + } this.clientEmitter(req.user.id, 'batch_quickmatch_complete', result) } From 066b6c13c6aff8caa5bf008871f943662c6dd937 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:38:51 +0100 Subject: [PATCH 044/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 7fc7effa1..8d82a34c8 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -62,8 +62,8 @@ export default { overrideDefaults: true }, tooltips: { - updateCovers: 'Allow overwriting of existing covers for the selected books when a match is located.', - updateDetails: 'Allow overwriting of existing details for the selected books when a match is located.' + updateCovers: 'Allow overwriting of existing covers for the selected books when a match is located.', + updateDetails: 'Allow overwriting of existing details for the selected books when a match is located.' } } }, From eb0ef8c696830a47f8c26393dec941ff5092b8a8 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:38:58 +0100 Subject: [PATCH 045/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 8d82a34c8..91be72cf6 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -101,7 +101,7 @@ export default { }, libraryProvider() { return this.$store.getters['libraries/getLibraryProvider'](this.currentLibraryId) || 'google' - }, + } }, methods: { init() { From 5e8979876fe635dd6473ab28dff2521485883de5 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:39:37 +0100 Subject: [PATCH 046/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 91be72cf6..233b0134f 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -17,7 +17,7 @@

Provider

-

Quick Match will attempt to add missing covers and metadata for the selected books. Enable the options below to allow Quick Match to overwrite existing covers and/or metadata.

+

Quick Match will attempt to add missing covers and metadata for the selected books. Enable the options below to allow Quick Match to overwrite existing covers and/or metadata.

From 951afaa568071511c5494f4d0777f0072bc3de64 Mon Sep 17 00:00:00 2001 From: Undergrid Date: Sat, 24 Sep 2022 23:40:07 +0100 Subject: [PATCH 047/213] Update client/components/modals/BatchQuickMatchModel.vue Co-authored-by: advplyr <67830747+advplyr@users.noreply.github.com> --- client/components/modals/BatchQuickMatchModel.vue | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/client/components/modals/BatchQuickMatchModel.vue b/client/components/modals/BatchQuickMatchModel.vue index 233b0134f..a80beefa7 100644 --- a/client/components/modals/BatchQuickMatchModel.vue +++ b/client/components/modals/BatchQuickMatchModel.vue @@ -125,13 +125,10 @@ export default { }) .then(() => { this.$toast.info('Batch quick match of ' + this.selectedBookIds.length + ' books started!') - this.processing = false - this.$store.commit('setProcessingBatch', false) - this.show = false - }) - .catch((error) => { + }).catch((error) => { this.$toast.error('Batch quick match failed') console.error('Failed to batch quick match', error) + }).finally(() => { this.processing = false this.$store.commit('setProcessingBatch', false) this.show = false From 88726bed86bef18c34a332c95bf6ca6e85796329 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 25 Sep 2022 09:46:45 -0500 Subject: [PATCH 048/213] Update:Notification system descriptions #996 --- client/components/cards/NotificationCard.vue | 2 +- .../modals/notification/NotificationEditModal.vue | 7 ++++++- client/components/ui/Dropdown.vue | 11 +++++++++-- client/pages/config/notifications.vue | 7 +++++-- server/managers/NotificationManager.js | 2 +- server/objects/settings/NotificationSettings.js | 4 ++-- server/utils/notifications.js | 2 +- 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/client/components/cards/NotificationCard.vue b/client/components/cards/NotificationCard.vue index 05bf66de9..7f74239e1 100644 --- a/client/components/cards/NotificationCard.vue +++ b/client/components/cards/NotificationCard.vue @@ -76,7 +76,7 @@ export default { }, sendTestClick() { const payload = { - message: `Send a test notification to event ${this.eventName}?`, + message: `Trigger this notification with test data?`, callback: (confirmed) => { if (confirmed) { this.sendTest() diff --git a/client/components/modals/notification/NotificationEditModal.vue b/client/components/modals/notification/NotificationEditModal.vue index a9382a688..3f53db05e 100644 --- a/client/components/modals/notification/NotificationEditModal.vue +++ b/client/components/modals/notification/NotificationEditModal.vue @@ -16,6 +16,8 @@ +

Available variables: {{ availableVariables.join(', ') }}

+
@@ -73,7 +75,7 @@ export default { return this.notificationData.events || [] }, eventOptions() { - return this.notificationEvents.map((e) => ({ value: e.name, text: e.name })) + return this.notificationEvents.map((e) => ({ value: e.name, text: e.name, subtext: e.description })) }, selectedEventData() { return this.notificationEvents.find((e) => e.name === this.newNotification.eventName) @@ -83,6 +85,9 @@ export default { }, title() { return this.isNew ? 'Create Notification' : 'Update Notification' + }, + availableVariables() { + return this.selectedEventData ? this.selectedEventData.variables || null : null } }, methods: { diff --git a/client/components/ui/Dropdown.vue b/client/components/ui/Dropdown.vue index 22eeed170..0a4b9c30a 100644 --- a/client/components/ui/Dropdown.vue +++ b/client/components/ui/Dropdown.vue @@ -3,7 +3,9 @@

{{ label }}