Add:Server setting to ignore "The" infront of titles and series when sorting #361

This commit is contained in:
advplyr 2022-02-13 15:00:59 -06:00
parent e0a6631396
commit f15be4c96e
6 changed files with 93 additions and 20 deletions

View File

@ -4,7 +4,7 @@
<div :key="shelf" :id="`shelf-${shelf - 1}`" class="w-full px-4 sm:px-8 relative" :class="{ bookshelfRow: !isAlternativeBookshelfView }" :style="{ height: shelfHeight + 'px' }">
<!-- <div class="absolute top-0 left-0 bottom-0 p-4 z-10">
<p class="text-white text-2xl">{{ shelf }}</p>
</div> -->
</div>-->
<div v-if="!isAlternativeBookshelfView" class="bookshelfDivider w-full absolute bottom-0 left-0 right-0 z-20" :class="`h-${shelfDividerHeightIndex}`" />
</div>
</template>
@ -26,7 +26,9 @@
<widgets-cover-size-widget class="fixed bottom-4 right-4 z-30" />
<!-- Experimental Bookshelf Texture -->
<div v-show="showExperimentalFeatures" class="fixed bottom-4 right-28 z-40">
<div class="rounded-full py-1 bg-primary hover:bg-bg cursor-pointer px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent @click="showBookshelfTextureModal"><p class="text-sm py-0.5">Texture</p></div>
<div class="rounded-full py-1 bg-primary hover:bg-bg cursor-pointer px-2 border border-black-100 text-center flex items-center box-shadow-md" @mousedown.prevent @mouseup.prevent @click="showBookshelfTextureModal">
<p class="text-sm py-0.5">Texture</p>
</div>
</div>
</div>
</template>
@ -245,7 +247,7 @@ export default {
console.error('failed to fetch books', error)
return null
})
console.log('payload', payload)
this.isFetchingEntities = false
if (this.pendingReset) {
this.pendingReset = false

View File

@ -10,24 +10,38 @@
<div class="flex items-center py-2">
<ui-toggle-switch v-model="storeCoversInAudiobookDir" :disabled="updatingServerSettings" @input="updateCoverStorageDestination" />
<ui-tooltip :text="coverDestinationTooltip">
<p class="pl-4 text-lg">Store covers with audiobook <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Store covers with audiobook
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch v-model="useSquareBookCovers" :disabled="updatingServerSettings" @input="updateBookCoverAspectRatio" />
<ui-tooltip :text="coverAspectRatioTooltip">
<p class="pl-4 text-lg">Use square book covers <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Use square book covers
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch v-model="useAlternativeBookshelfView" :disabled="updatingServerSettings" @input="updateAlternativeBookshelfView" />
<ui-tooltip :text="bookshelfViewTooltip">
<p class="pl-4 text-lg">Use alternative library bookshelf view <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Use alternative library bookshelf view
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch v-model="newServerSettings.sortingIgnorePrefix" :disabled="updatingServerSettings" @input="updateSortIgnorePrefix" />
<p class="pl-4 text-lg">Ignore prefix "The" when sorting title and series</p>
</div>
<div class="flex items-center mb-2 mt-8">
<h1 class="text-xl">Scanner Settings</h1>
</div>
@ -35,14 +49,20 @@
<div class="flex items-center py-2">
<ui-toggle-switch v-model="newServerSettings.scannerParseSubtitle" small :disabled="updatingServerSettings" @input="updateScannerParseSubtitle" />
<ui-tooltip :text="parseSubtitleTooltip">
<p class="pl-4 text-lg">Scanner parse subtitles <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Scanner parse subtitles
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch v-model="newServerSettings.scannerFindCovers" :disabled="updatingServerSettings" @input="updateScannerFindCovers" />
<ui-tooltip :text="scannerFindCoversTooltip">
<p class="pl-4 text-lg">Scanner find covers <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Scanner find covers
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
<div class="flex-grow" />
</div>
@ -53,14 +73,20 @@
<div class="flex items-center py-2">
<ui-toggle-switch v-model="newServerSettings.scannerPreferAudioMetadata" :disabled="updatingServerSettings" @input="updateScannerPreferAudioMeta" />
<ui-tooltip :text="scannerPreferAudioMetaTooltip">
<p class="pl-4 text-lg">Scanner prefer audio metadata <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Scanner prefer audio metadata
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch v-model="newServerSettings.scannerPreferOpfMetadata" :disabled="updatingServerSettings" @input="updateScannerPreferOpfMeta" />
<ui-tooltip :text="scannerPreferOpfMetaTooltip">
<p class="pl-4 text-lg">Scanner prefer OPF metadata <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Scanner prefer OPF metadata
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
</div>
@ -71,7 +97,10 @@
<ui-btn color="bg" small :padding-x="4" class="hidden lg:block mr-2" :loading="isPurgingCache" @click="purgeCache">Purge Cache</ui-btn>
<ui-btn color="bg" small :padding-x="4" class="hidden lg:block" :loading="isResettingAudiobooks" @click="resetAudiobooks">Remove All Audiobooks</ui-btn>
<div class="flex-grow" />
<p class="pr-2 text-sm font-book text-yellow-400">Report bugs, request features, provide feedback, and contribute on <a class="underline" href="https://github.com/advplyr/audiobookshelf" target="_blank">github</a>.</p>
<p class="pr-2 text-sm font-book text-yellow-400">
Report bugs, request features, provide feedback, and contribute on
<a class="underline" href="https://github.com/advplyr/audiobookshelf" target="_blank">github</a>.
</p>
<a href="https://github.com/advplyr/audiobookshelf" target="_blank" class="text-white hover:text-gray-200 hover:scale-150 hover:rotate-6 transform duration-500">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="24" height="24" viewBox="0 0 24 24">
<path
@ -89,13 +118,16 @@
<div class="flex items-center">
<ui-toggle-switch v-model="showExperimentalFeatures" />
<ui-tooltip :text="experimentalFeaturesTooltip">
<p class="pl-4 text-lg">Experimental Features <span class="material-icons icon-text">info_outlined</span></p>
<p class="pl-4 text-lg">
Experimental Features
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
</div>
<!-- <div class="hidden md:block">
<a href="https://github.com/advplyr/audiobookshelf/discussions/75#discussion-3604812" target="_blank" class="text-blue-500 hover:text-blue-300 underline">Join the discussion</a>
</div> -->
</div>-->
</div>
</div>
</div>
@ -166,6 +198,11 @@ export default {
}
},
methods: {
updateSortIgnorePrefix(val) {
this.updateServerSettings({
sortingIgnorePrefix: val
})
},
updateScannerFindCovers(val) {
this.updateServerSettings({
scannerFindCovers: !!val

View File

@ -144,10 +144,19 @@ class LibraryController {
}
if (payload.sortBy) {
var sortKey = payload.sortBy
// Handle server setting sortingIgnorePrefix
if ((sortKey === 'book.series' || sortKey === 'book.title') && this.db.serverSettings.sortingIgnorePrefix) {
// Book.js has seriesIgnorePrefix and titleIgnorePrefix getters
sortKey += 'IgnorePrefix'
}
var direction = payload.sortDesc ? 'desc' : 'asc'
audiobooks = naturalSort(audiobooks)[direction]((ab) => {
// Supports dot notation strings i.e. "book.title"
return payload.sortBy.split('.').reduce((a, b) => a[b], ab)
return sortKey.split('.').reduce((a, b) => a[b], ab)
})
}
@ -202,7 +211,14 @@ class LibraryController {
}
var series = libraryHelpers.getSeriesFromBooks(audiobooks, payload.minified)
series = sort(series).asc(s => s.name)
var sortingIgnorePrefix = this.db.serverSettings.sortingIgnorePrefix
series = sort(series).asc(s => {
if (sortingIgnorePrefix && s.name.toLowerCase().startsWith('the')) {
return s.name.substr(4)
}
return s.name
})
payload.total = series.length
if (payload.limit) {

View File

@ -49,6 +49,20 @@ class Book {
get _asin() { return this.asin || '' }
get genresCommaSeparated() { return this._genres.join(', ') }
get titleIgnorePrefix() {
if (this._title.toLowerCase().startsWith('the ')) {
return this._title.substr(4) + ', The'
}
return this._title
}
get seriesIgnorePrefix() {
if (this._series.toLowerCase().startsWith('the ')) {
return this._series.substr(4) + ', The'
}
return this._series
}
get shouldSearchForCover() {
if (this.cover) return false
if (this.authorFL !== this.lastCoverSearchAuthor || this.title !== this.lastCoverSearchTitle || !this.lastCoverSearch) return true

View File

@ -38,6 +38,8 @@ class ServerSettings {
this.coverAspectRatio = BookCoverAspectRatio.SQUARE
this.bookshelfView = BookshelfView.STANDARD
this.sortingIgnorePrefix = false
this.logLevel = Logger.logLevel
this.version = null
@ -70,6 +72,8 @@ class ServerSettings {
this.coverAspectRatio = !isNaN(settings.coverAspectRatio) ? settings.coverAspectRatio : BookCoverAspectRatio.SQUARE
this.bookshelfView = settings.bookshelfView || BookshelfView.STANDARD
this.sortingIgnorePrefix = !!settings.sortingIgnorePrefix
this.logLevel = settings.logLevel || Logger.logLevel
this.version = settings.version || null
@ -99,6 +103,7 @@ class ServerSettings {
loggerScannerLogsToKeep: this.loggerScannerLogsToKeep,
coverAspectRatio: this.coverAspectRatio,
bookshelfView: this.bookshelfView,
sortingIgnorePrefix: this.sortingIgnorePrefix,
logLevel: this.logLevel,
version: this.version
}

View File

@ -1,9 +1,4 @@
const ffprobe = require('node-ffprobe')
if (process.env.FFPROBE_PATH) {
ffprobe.FFPROBE_PATH = process.env.FFPROBE_PATH
}
const AudioProbeData = require('../scanner/AudioProbeData')
const Logger = require('../Logger')
@ -281,6 +276,10 @@ function parseProbeData(data, verbose = false) {
// Updated probe returns AudioProbeData object
function probe(filepath, verbose = false) {
if (process.env.FFPROBE_PATH) {
ffprobe.FFPROBE_PATH = process.env.FFPROBE_PATH
}
return ffprobe(filepath)
.then(raw => {
var rawProbeData = parseProbeData(raw, verbose)