From cfe27dff800b742645767a5bebc48dcc8fa4d125 Mon Sep 17 00:00:00 2001 From: advplyr Date: Thu, 31 Mar 2022 15:07:50 -0500 Subject: [PATCH] Add:Server setting to set custom sorting prefixes to ignore #358 --- client/components/cards/CollectionCard.vue | 112 --------------------- client/components/cards/GroupCard.vue | 12 --- client/components/cards/LazyBookCard.vue | 17 +--- client/pages/config/index.vue | 27 ++++- server/objects/ServerSettings.js | 12 ++- server/objects/mediaTypes/Book.js | 2 +- server/objects/metadata/BookMetadata.js | 30 +++++- 7 files changed, 69 insertions(+), 143 deletions(-) delete mode 100644 client/components/cards/CollectionCard.vue diff --git a/client/components/cards/CollectionCard.vue b/client/components/cards/CollectionCard.vue deleted file mode 100644 index a24ed47c..00000000 --- a/client/components/cards/CollectionCard.vue +++ /dev/null @@ -1,112 +0,0 @@ - - - \ No newline at end of file diff --git a/client/components/cards/GroupCard.vue b/client/components/cards/GroupCard.vue index ec92669e..5b31ed0e 100644 --- a/client/components/cards/GroupCard.vue +++ b/client/components/cards/GroupCard.vue @@ -12,9 +12,6 @@

{{ bookItems.length }}

-
-
-
@@ -100,15 +97,6 @@ export default { bookItems() { return this._group.books || [] }, - userAudiobooks() { - return Object.values(this.$store.state.user.user ? this.$store.state.user.user.audiobooks || {} : {}) - }, - userProgressItems() { - return this.bookItems.map((item) => { - var userAudiobook = this.userAudiobooks.find((ab) => ab.audiobookId === item.id) - return userAudiobook || {} - }) - }, groupName() { return this._group.name || 'No Name' }, diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue index c1c08a71..f0f62f29 100644 --- a/client/components/cards/LazyBookCard.vue +++ b/client/components/cards/LazyBookCard.vue @@ -197,28 +197,19 @@ export default { playIconFontSize() { return Math.max(2, 3 * this.sizeMultiplier) }, - authors() { - return this.mediaMetadata.authors || [] - }, author() { if (this.isPodcast) return this.mediaMetadata.author - return this.authors.map((au) => au.name).join(', ') + return this.mediaMetadata.authorName }, authorLF() { - return this.authors - .map((au) => { - var parts = au.name.split(' ') - if (parts.length === 1) return parts[0] - return `${parts[1]}, ${parts[0]}` - }) - .join(', ') + return this.mediaMetadata.authorNameLF }, volumeNumber() { return this.mediaMetadata.volumeNumber || null }, displayTitle() { - if (this.orderBy === 'media.metadata.title' && this.sortingIgnorePrefix && this.title.toLowerCase().startsWith('the ')) { - return this.title.substr(4) + ', The' + if (this.orderBy === 'media.metadata.title' && this.sortingIgnorePrefix) { + return this.mediaMetadata.titleIgnorePrefix } return this.title }, diff --git a/client/pages/config/index.vue b/client/pages/config/index.vue index c6d141cc..fd413136 100644 --- a/client/pages/config/index.vue +++ b/client/pages/config/index.vue @@ -47,9 +47,21 @@ +
-

Ignore prefix "The" when sorting title and series

+ +

+ Ignore prefixes when sorting title and series + info_outlined +

+
+
+
+
@@ -203,6 +215,7 @@ export default { scannerPreferOpfMetadata: 'OPF file metadata will be used for book details over folder names', scannerPreferAudioMetadata: 'Audio file ID3 meta tags will be used for book details over folder names', scannerParseSubtitle: 'Extract subtitles from audiobook folder names.
Subtitle must be seperated by " - "
i.e. "Book Title - A Subtitle Here" has the subtitle "A Subtitle Here"', + sortingIgnorePrefix: 'i.e. for prefix "the" book title "The Book Title" would sort as "Book Title, The"', scannerFindCovers: 'If your audiobook does not have an embedded cover or a cover image inside the folder, the scanner will attempt to find a cover.
Note: This will extend scan time', bookshelfView: 'Alternative bookshelf view that shows title & author under book covers', storeCoverWithBook: 'By default covers are stored in /metadata/books, enabling this setting will store covers in the books folder. Only one file named "cover" will be kept', @@ -215,7 +228,6 @@ export default { watch: { serverSettings(newVal, oldVal) { if (newVal && !oldVal) { - this.newServerSettings = { ...this.serverSettings } this.initServerSettings() } } @@ -243,6 +255,16 @@ export default { updateEnableChromecast(val) { this.updateServerSettings({ enableChromecast: val }) }, + updateSortingPrefixes(val) { + if (!val || !val.length) { + this.$toast.error('Must have at least 1 prefix') + return + } + var prefixes = val.map((prefix) => prefix.trim().toLowerCase()) + this.updateServerSettings({ + sortingPrefixes: prefixes + }) + }, updateScannerCoverProvider(val) { this.updateServerSettings({ scannerCoverProvider: val @@ -278,6 +300,7 @@ export default { }, initServerSettings() { this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {} + this.newServerSettings.sortingPrefixes = [...(this.newServerSettings.sortingPrefixes || [])] this.useSquareBookCovers = this.newServerSettings.coverAspectRatio === this.$constants.BookCoverAspectRatio.SQUARE diff --git a/server/objects/ServerSettings.js b/server/objects/ServerSettings.js index d76344ef..1c7e0089 100644 --- a/server/objects/ServerSettings.js +++ b/server/objects/ServerSettings.js @@ -43,6 +43,8 @@ class ServerSettings { this.podcastEpisodeSchedule = '0 * * * *' // Every hour this.sortingIgnorePrefix = false + this.sortingPrefixes = ['the', 'a'] + this.chromecastEnabled = false this.logLevel = Logger.logLevel this.version = null @@ -82,6 +84,7 @@ class ServerSettings { this.bookshelfView = settings.bookshelfView || BookshelfView.STANDARD this.sortingIgnorePrefix = !!settings.sortingIgnorePrefix + this.sortingPrefixes = settings.sortingPrefixes || ['the', 'a'] this.chromecastEnabled = !!settings.chromecastEnabled this.logLevel = settings.logLevel || Logger.logLevel this.version = settings.version || null @@ -114,6 +117,7 @@ class ServerSettings { coverAspectRatio: this.coverAspectRatio, bookshelfView: this.bookshelfView, sortingIgnorePrefix: this.sortingIgnorePrefix, + sortingPrefixes: [...this.sortingPrefixes], chromecastEnabled: this.chromecastEnabled, logLevel: this.logLevel, version: this.version @@ -123,7 +127,13 @@ class ServerSettings { update(payload) { var hasUpdates = false for (const key in payload) { - if (this[key] !== payload[key]) { + if (key === 'sortingPrefixes' && payload[key] && payload[key].length) { + var prefixesCleaned = payload[key].filter(prefix => !!prefix).map(prefix => prefix.toLowerCase()) + if (prefixesCleaned.join(',') !== this[key].join(',')) { + this[key] = [...prefixesCleaned] + hasUpdates = true + } + } else if (this[key] !== payload[key]) { if (key === 'logLevel') { Logger.setLogLevel(payload[key]) } diff --git a/server/objects/mediaTypes/Book.js b/server/objects/mediaTypes/Book.js index 00a5090d..890cc9b3 100644 --- a/server/objects/mediaTypes/Book.js +++ b/server/objects/mediaTypes/Book.js @@ -55,7 +55,7 @@ class Book { toJSONMinified() { return { - metadata: this.metadata.toJSON(), + metadata: this.metadata.toJSONMinified(), coverPath: this.coverPath, tags: [...this.tags], numTracks: this.tracks.length, diff --git a/server/objects/metadata/BookMetadata.js b/server/objects/metadata/BookMetadata.js index aea32206..7c1e1003 100644 --- a/server/objects/metadata/BookMetadata.js +++ b/server/objects/metadata/BookMetadata.js @@ -59,9 +59,31 @@ class BookMetadata { } } + toJSONMinified() { + return { + title: this.title, + titleIgnorePrefix: this.titleIgnorePrefix, + subtitle: this.subtitle, + authorName: this.authorName, + authorNameLF: this.authorNameLF, + narratorName: this.narratorName, + seriesName: this.seriesName, + genres: [...this.genres], + publishedYear: this.publishedYear, + publishedDate: this.publishedDate, + publisher: this.publisher, + description: this.description, + isbn: this.isbn, + asin: this.asin, + language: this.language, + explicit: this.explicit + } + } + toJSONExpanded() { return { title: this.title, + titleIgnorePrefix: this.titleIgnorePrefix, subtitle: this.subtitle, authors: this.authors.map(a => ({ ...a })), // Author JSONMinimal with name and id narrators: [...this.narrators], @@ -88,8 +110,12 @@ class BookMetadata { get titleIgnorePrefix() { if (!this.title) return '' - if (this.title.toLowerCase().startsWith('the ')) { - return this.title.substr(4) + ', The' + var prefixesToIgnore = global.ServerSettings.sortingPrefixes || [] + for (const prefix of prefixesToIgnore) { + // e.g. for prefix "the". If title is "The Book Title" return "Book Title, The" + if (this.title.toLowerCase().startsWith(`${prefix} `)) { + return this.title.substr(prefix.length + 1) + `, ${prefix.substr(0, 1).toUpperCase() + prefix.substr(1)}` + } } return this.title }