From 19cbd1f8dec874b50fbb4ccc4c88264caec5e094 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 27 May 2024 11:35:54 +0200 Subject: [PATCH 1/7] Update de strings. Follow-up for: ce7f891b9b2cb57c6644aaf96f89a8bda6307664 and 6fad4521d43348c2263a9d9d53548512a0b653b3 --- client/strings/de.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/strings/de.json b/client/strings/de.json index 4ce822ddd..47de1af33 100644 --- a/client/strings/de.json +++ b/client/strings/de.json @@ -191,7 +191,7 @@ "LabelAbridged": "Gekürzt", "LabelAbridgedChecked": "Gekürzt (angehakt)", "LabelAbridgedUnchecked": "Ungekürzt (nicht angehakt)", - "LabelAccessibleBy": "Accessible by", + "LabelAccessibleBy": "Zugänglich für", "LabelAccountType": "Kontoart", "LabelAccountTypeAdmin": "Admin", "LabelAccountTypeGuest": "Gast", @@ -471,8 +471,8 @@ "LabelSettingsEnableWatcher": "Überwachung aktivieren", "LabelSettingsEnableWatcherForLibrary": "Ordnerüberwachung für die Bibliothek aktivieren", "LabelSettingsEnableWatcherHelp": "Aktiviert das automatische Hinzufügen/Aktualisieren von Elementen, wenn Dateiänderungen erkannt werden. *Erfordert einen Server-Neustart", - "LabelSettingsEpubsAllowScriptedContent": "Allow scripted content in epubs", - "LabelSettingsEpubsAllowScriptedContentHelp": "Allow epub files to execute scripts. It is recommended to keep this setting disabled unless you trust the source of the epub files.", + "LabelSettingsEpubsAllowScriptedContent": "Skriptinhalte in Epubs zulassen", + "LabelSettingsEpubsAllowScriptedContentHelp": "Erlaube Epub-Dateien, Skripte auszuführen. Es wird empfohlen, diese Einstellung deaktiviert zu lassen, es sei denn, du vertraust der Quelle der Epub-Dateien.", "LabelSettingsExperimentalFeatures": "Experimentelle Funktionen", "LabelSettingsExperimentalFeaturesHelp": "Funktionen welche sich in der Entwicklung befinden, benötigen dein Feedback und deine Hilfe beim Testen. Klicke hier, um die Github-Diskussion zu öffnen.", "LabelSettingsFindCovers": "Suche Titelbilder", @@ -633,7 +633,7 @@ "MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge", "MessageEmbedFinished": "Einbettung abgeschlossen!", "MessageEpisodesQueuedForDownload": "{0} Episode(n) in der Warteschlange zum Herunterladen", - "MessageEreaderDevices": "To ensure delivery of ebooks, you may need to add the above email address as a valid sender for each device listed below.", + "MessageEreaderDevices": "Um die Zustellung von E-Books sicherzustellen, musst du eventuell die oben genannte E-Mail-Adresse als gültigen Absender für jedes unten aufgeführte Gerät hinzufügen.", "MessageFeedURLWillBe": "Feed-URL wird {0} sein", "MessageFetching": "Abrufen...", "MessageForceReScanDescription": "Durchsucht alle Dateien erneut, wie bei einem frischen Scan. ID3-Tags von Audiodateien, OPF-Dateien und Textdateien werden neu durchsucht.", From 216139119b0c6c1be4afbf46370b756b8bf30775 Mon Sep 17 00:00:00 2001 From: Daniel Schosser Date: Mon, 27 May 2024 15:02:00 +0200 Subject: [PATCH 2/7] Update de.json --- client/strings/de.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/strings/de.json b/client/strings/de.json index 4ce822ddd..fa8d646bc 100644 --- a/client/strings/de.json +++ b/client/strings/de.json @@ -271,7 +271,7 @@ "LabelDownloadNEpisodes": "Download {0} Episoden", "LabelDuration": "Laufzeit", "LabelDurationComparisonExactMatch": "(genauer Treffer)", - "LabelDurationComparisonLonger": "({0} änger)", + "LabelDurationComparisonLonger": "({0} länger)", "LabelDurationComparisonShorter": "({0} kürzer)", "LabelDurationFound": "Gefundene Laufzeit:", "LabelEbook": "E-Book", @@ -384,7 +384,7 @@ "LabelNoEpisodesSelected": "Keine Episoden ausgewählt", "LabelNotes": "Notizen", "LabelNotFinished": "Nicht beendet", - "LabelNotificationAppriseURL": "Apprise URL(s)", + "LabelNotificationAppriseURL": "Informations URL(s)", "LabelNotificationAvailableVariables": "Verfügbare Variablen", "LabelNotificationBodyTemplate": "Textvorlage", "LabelNotificationEvent": "Benachrichtigungs Event", @@ -501,7 +501,7 @@ "LabelShowAll": "Alles anzeigen", "LabelShowSeconds": "Zeige Sekunden", "LabelSize": "Größe", - "LabelSleepTimer": "Sleep-Timer", + "LabelSleepTimer": "Schlummerfunktion", "LabelSlug": "URL Teil", "LabelStart": "Start", "LabelStarted": "Gestartet", @@ -807,4 +807,4 @@ "ToastSortingPrefixesUpdateSuccess": "Die Sortier-Prefixe wirden geupdated ({0} Einträge)", "ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden", "ToastUserDeleteSuccess": "Benutzer gelöscht" -} \ No newline at end of file +} From e9b4e07bd8c31f2e732d4c18c3495cd3b175f5ee Mon Sep 17 00:00:00 2001 From: Daniel Schosser Date: Mon, 27 May 2024 19:14:10 +0200 Subject: [PATCH 3/7] Update de.json Revert Apprise string change --- client/strings/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/strings/de.json b/client/strings/de.json index fa8d646bc..29eab79a7 100644 --- a/client/strings/de.json +++ b/client/strings/de.json @@ -384,7 +384,7 @@ "LabelNoEpisodesSelected": "Keine Episoden ausgewählt", "LabelNotes": "Notizen", "LabelNotFinished": "Nicht beendet", - "LabelNotificationAppriseURL": "Informations URL(s)", + "LabelNotificationAppriseURL": "Apprise URL(s)", "LabelNotificationAvailableVariables": "Verfügbare Variablen", "LabelNotificationBodyTemplate": "Textvorlage", "LabelNotificationEvent": "Benachrichtigungs Event", From 1337c60cdee4fed99909cfde17b2addaed3028f7 Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 27 May 2024 13:22:20 -0500 Subject: [PATCH 4/7] Fix:Debian pkg crash due to using toSorted that is only available in Node20+ #3024 --- server/utils/prober.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/utils/prober.js b/server/utils/prober.js index fc58937b8..9b4d34e91 100644 --- a/server/utils/prober.js +++ b/server/utils/prober.js @@ -153,7 +153,7 @@ function parseChapters(_chapters) { title } }) - .toSorted((a, b) => a.start - b.start) + .sort((a, b) => a.start - b.start) .map((chap, index) => { chap.id = index return chap From 157616421841b2535d108e5c4d402931429d4075 Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 27 May 2024 15:37:02 -0500 Subject: [PATCH 5/7] Update:Get all user playlists for library API endpoint performance improvement #2852 --- server/controllers/LibraryController.js | 3 +- server/models/Playlist.js | 151 +++++++++++++++--------- 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/server/controllers/LibraryController.js b/server/controllers/LibraryController.js index 8451de155..0f30c410d 100644 --- a/server/controllers/LibraryController.js +++ b/server/controllers/LibraryController.js @@ -512,8 +512,7 @@ class LibraryController { * @param {*} res */ async getUserPlaylistsForLibrary(req, res) { - let playlistsForUser = await Database.playlistModel.getPlaylistsForUserAndLibrary(req.user.id, req.library.id) - playlistsForUser = await Promise.all(playlistsForUser.map(async (p) => p.getOldJsonExpanded())) + let playlistsForUser = await Database.playlistModel.getOldPlaylistsForUserAndLibrary(req.user.id, req.library.id) const payload = { results: [], diff --git a/server/models/Playlist.js b/server/models/Playlist.js index d6a86d689..fedc83b2d 100644 --- a/server/models/Playlist.js +++ b/server/models/Playlist.js @@ -43,21 +43,24 @@ class Playlist extends Model { }, order: [['playlistMediaItems', 'order', 'ASC']] }) - return playlists.map(p => this.getOldPlaylist(p)) + return playlists.map((p) => this.getOldPlaylist(p)) } static getOldPlaylist(playlistExpanded) { - const items = playlistExpanded.playlistMediaItems.map(pmi => { - const libraryItemId = pmi.mediaItem?.podcast?.libraryItem?.id || pmi.mediaItem?.libraryItem?.id || null - if (!libraryItemId) { - Logger.error(`[Playlist] Invalid playlist media item - No library item id found`, JSON.stringify(pmi, null, 2)) - return null - } - return { - episodeId: pmi.mediaItemType === 'podcastEpisode' ? pmi.mediaItemId : '', - libraryItemId - } - }).filter(pmi => pmi) + const items = playlistExpanded.playlistMediaItems + .map((pmi) => { + const mediaItem = pmi.mediaItem || pmi.dataValues?.mediaItem + const libraryItemId = mediaItem?.podcast?.libraryItem?.id || mediaItem?.libraryItem?.id || null + if (!libraryItemId) { + Logger.error(`[Playlist] Invalid playlist media item - No library item id found`, JSON.stringify(pmi, null, 2)) + return null + } + return { + episodeId: pmi.mediaItemType === 'podcastEpisode' ? pmi.mediaItemId : '', + libraryItemId + } + }) + .filter((pmi) => pmi) return new oldPlaylist({ id: playlistExpanded.id, @@ -77,25 +80,26 @@ class Playlist extends Model { * @returns {Promise} oldPlaylist.toJSONExpanded */ async getOldJsonExpanded(include) { - this.playlistMediaItems = await this.getPlaylistMediaItems({ - include: [ - { - model: this.sequelize.models.book, - include: this.sequelize.models.libraryItem - }, - { - model: this.sequelize.models.podcastEpisode, - include: { - model: this.sequelize.models.podcast, + this.playlistMediaItems = + (await this.getPlaylistMediaItems({ + include: [ + { + model: this.sequelize.models.book, include: this.sequelize.models.libraryItem + }, + { + model: this.sequelize.models.podcastEpisode, + include: { + model: this.sequelize.models.podcast, + include: this.sequelize.models.libraryItem + } } - } - ], - order: [['order', 'ASC']] - }) || [] + ], + order: [['order', 'ASC']] + })) || [] const oldPlaylist = this.sequelize.models.playlist.getOldPlaylist(this) - const libraryItemIds = oldPlaylist.items.map(i => i.libraryItemId) + const libraryItemIds = oldPlaylist.items.map((i) => i.libraryItemId) let libraryItems = await this.sequelize.models.libraryItem.getAllOldLibraryItems({ id: libraryItemIds @@ -138,7 +142,7 @@ class Playlist extends Model { /** * Get playlist by id - * @param {string} playlistId + * @param {string} playlistId * @returns {Promise} returns null if not found */ static async getById(playlistId) { @@ -167,12 +171,13 @@ class Playlist extends Model { } /** - * Get playlists for user and optionally for library - * @param {string} userId - * @param {[string]} libraryId optional - * @returns {Promise} + * Get old playlists for user and optionally for library + * + * @param {string} userId + * @param {string} [libraryId] + * @returns {Promise} */ - static async getPlaylistsForUserAndLibrary(userId, libraryId = null) { + static async getOldPlaylistsForUserAndLibrary(userId, libraryId = null) { if (!userId && !libraryId) return [] const whereQuery = {} if (userId) { @@ -181,7 +186,7 @@ class Playlist extends Model { if (libraryId) { whereQuery.libraryId = libraryId } - const playlists = await this.findAll({ + const playlistsExpanded = await this.findAll({ where: whereQuery, include: { model: this.sequelize.models.playlistMediaItem, @@ -204,14 +209,44 @@ class Playlist extends Model { ['playlistMediaItems', 'order', 'ASC'] ] }) - return playlists + + const oldPlaylists = [] + for (const playlistExpanded of playlistsExpanded) { + const oldPlaylist = this.getOldPlaylist(playlistExpanded) + const libraryItems = [] + for (const pmi of playlistExpanded.playlistMediaItems) { + let mediaItem = pmi.mediaItem || pmi.dataValues.mediaItem + + if (!mediaItem) { + Logger.error(`[Playlist] Invalid playlist media item - No media item found`, JSON.stringify(mediaItem, null, 2)) + continue + } + let libraryItem = mediaItem.libraryItem || mediaItem.podcast?.libraryItem + + if (mediaItem.podcast) { + libraryItem.media = mediaItem.podcast + libraryItem.media.podcastEpisodes = [mediaItem] + delete mediaItem.podcast.libraryItem + } else { + libraryItem.media = mediaItem + delete mediaItem.libraryItem + } + + const oldLibraryItem = this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem) + libraryItems.push(oldLibraryItem) + } + const oldPlaylistJson = oldPlaylist.toJSONExpanded(libraryItems) + oldPlaylists.push(oldPlaylistJson) + } + + return oldPlaylists } /** * Get number of playlists for a user and library - * @param {string} userId - * @param {string} libraryId - * @returns + * @param {string} userId + * @param {string} libraryId + * @returns */ static async getNumPlaylistsForUserAndLibrary(userId, libraryId) { return this.count({ @@ -224,7 +259,7 @@ class Playlist extends Model { /** * Get all playlists for mediaItemIds - * @param {string[]} mediaItemIds + * @param {string[]} mediaItemIds * @returns {Promise} */ static async getPlaylistsForMediaItemIds(mediaItemIds) { @@ -263,9 +298,9 @@ class Playlist extends Model { const playlists = [] for (const playlistMediaItem of playlistMediaItemsExpanded) { const playlist = playlistMediaItem.playlist - if (playlists.some(p => p.id === playlist.id)) continue + if (playlists.some((p) => p.id === playlist.id)) continue - playlist.playlistMediaItems = playlist.playlistMediaItems.map(pmi => { + playlist.playlistMediaItems = playlist.playlistMediaItems.map((pmi) => { if (pmi.mediaItemType === 'book' && pmi.book !== undefined) { pmi.mediaItem = pmi.book pmi.dataValues.mediaItem = pmi.dataValues.book @@ -286,21 +321,24 @@ class Playlist extends Model { /** * Initialize model - * @param {import('../Database').sequelize} sequelize + * @param {import('../Database').sequelize} sequelize */ static init(sequelize) { - super.init({ - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true + super.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + name: DataTypes.STRING, + description: DataTypes.TEXT }, - name: DataTypes.STRING, - description: DataTypes.TEXT - }, { - sequelize, - modelName: 'playlist' - }) + { + sequelize, + modelName: 'playlist' + } + ) const { library, user } = sequelize.models library.hasMany(Playlist) @@ -311,14 +349,14 @@ class Playlist extends Model { }) Playlist.belongsTo(user) - Playlist.addHook('afterFind', findResult => { + Playlist.addHook('afterFind', (findResult) => { if (!findResult) return if (!Array.isArray(findResult)) findResult = [findResult] for (const instance of findResult) { if (instance.playlistMediaItems?.length) { - instance.playlistMediaItems = instance.playlistMediaItems.map(pmi => { + instance.playlistMediaItems = instance.playlistMediaItems.map((pmi) => { if (pmi.mediaItemType === 'book' && pmi.book !== undefined) { pmi.mediaItem = pmi.book pmi.dataValues.mediaItem = pmi.dataValues.book @@ -334,10 +372,9 @@ class Playlist extends Model { return pmi }) } - } }) } } -module.exports = Playlist \ No newline at end of file +module.exports = Playlist From ba6a88a5bfe316d2e66cc60da66eae453cedd5cf Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 27 May 2024 16:04:36 -0500 Subject: [PATCH 6/7] Fix:Edit author modal resetting form inputs on image change #2965 --- .../components/modals/authors/EditModal.vue | 24 +++++++++++-------- .../pages/library/_library/authors/index.vue | 3 --- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/client/components/modals/authors/EditModal.vue b/client/components/modals/authors/EditModal.vue index 09ca7806e..a31cfd872 100644 --- a/client/components/modals/authors/EditModal.vue +++ b/client/components/modals/authors/EditModal.vue @@ -9,7 +9,7 @@
- +
delete
@@ -30,9 +30,6 @@
-
@@ -106,9 +103,9 @@ export default { methods: { init() { this.imageUrl = '' - this.authorCopy.name = this.author.name - this.authorCopy.asin = this.author.asin - this.authorCopy.description = this.author.description + this.authorCopy = { + ...this.author + } }, removeClick() { const payload = { @@ -171,7 +168,9 @@ export default { .$delete(`/api/authors/${this.authorId}/image`) .then((data) => { this.$toast.success(this.$strings.ToastAuthorImageRemoveSuccess) - this.$store.commit('globals/showEditAuthorModal', data.author) + + this.authorCopy.updatedAt = data.author.updatedAt + this.authorCopy.imagePath = data.author.imagePath }) .catch((error) => { console.error('Failed', error) @@ -196,7 +195,9 @@ export default { .then((data) => { this.imageUrl = '' this.$toast.success('Author image updated') - this.$store.commit('globals/showEditAuthorModal', data.author) + + this.authorCopy.updatedAt = data.author.updatedAt + this.authorCopy.imagePath = data.author.imagePath }) .catch((error) => { console.error('Failed', error) @@ -231,8 +232,11 @@ export default { } else if (response.updated) { if (response.author.imagePath) { this.$toast.success(this.$strings.ToastAuthorUpdateSuccess) - this.$store.commit('globals/showEditAuthorModal', response.author) } else this.$toast.success(this.$strings.ToastAuthorUpdateSuccessNoImageFound) + + this.authorCopy = { + ...response.author + } } else { this.$toast.info('No updates were made for Author') } diff --git a/client/pages/library/_library/authors/index.vue b/client/pages/library/_library/authors/index.vue index 27ba3ffe1..9adcce5b0 100644 --- a/client/pages/library/_library/authors/index.vue +++ b/client/pages/library/_library/authors/index.vue @@ -79,9 +79,6 @@ export default { } }, authorUpdated(author) { - if (this.selectedAuthor && this.selectedAuthor.id === author.id) { - this.$store.commit('globals/setSelectedAuthor', author) - } this.authors = this.authors.map((au) => { if (au.id === author.id) { return author From 964ef910b670f90456d8405a2f1bc9c97cd59cae Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 27 May 2024 16:09:32 -0500 Subject: [PATCH 7/7] Version bump v2.10.1 --- client/package-lock.json | 4 ++-- client/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index d6fd749a0..6a9d04724 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "audiobookshelf-client", - "version": "2.10.0", + "version": "2.10.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "audiobookshelf-client", - "version": "2.10.0", + "version": "2.10.1", "license": "ISC", "dependencies": { "@nuxtjs/axios": "^5.13.6", diff --git a/client/package.json b/client/package.json index 9b2b4f11b..f26282a31 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-client", - "version": "2.10.0", + "version": "2.10.1", "buildNumber": 1, "description": "Self-hosted audiobook and podcast client", "main": "index.js", diff --git a/package-lock.json b/package-lock.json index cf38355c1..41bbdf54b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "audiobookshelf", - "version": "2.10.0", + "version": "2.10.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "audiobookshelf", - "version": "2.10.0", + "version": "2.10.1", "license": "GPL-3.0", "dependencies": { "axios": "^0.27.2", diff --git a/package.json b/package.json index 22357a8e8..e31a28fc1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "2.10.0", + "version": "2.10.1", "buildNumber": 1, "description": "Self-hosted audiobook and podcast server", "main": "index.js",