Add api route for changing sorting prefixes, update default sorting prefixes to include a

This commit is contained in:
advplyr 2023-09-08 12:32:30 -05:00
parent 39b6ede1e9
commit 826963bf00
4 changed files with 134 additions and 10 deletions

View File

@ -36,7 +36,10 @@
</ui-tooltip> </ui-tooltip>
</div> </div>
<div v-if="newServerSettings.sortingIgnorePrefix" class="w-72 ml-14 mb-2"> <div v-if="newServerSettings.sortingIgnorePrefix" class="w-72 ml-14 mb-2">
<ui-multi-select v-model="newServerSettings.sortingPrefixes" small :items="newServerSettings.sortingPrefixes" :label="$strings.LabelPrefixesToIgnore" @input="updateSortingPrefixes" :disabled="updatingServerSettings" /> <ui-multi-select v-model="newServerSettings.sortingPrefixes" small :items="newServerSettings.sortingPrefixes" :label="$strings.LabelPrefixesToIgnore" @input="sortingPrefixesUpdated" :disabled="savingPrefixes" />
<div class="flex justify-end py-1">
<ui-btn v-if="hasPrefixesChanged" color="success" :loading="savingPrefixes" small @click="updateSortingPrefixes">Save</ui-btn>
</div>
</div> </div>
<div class="flex items-center py-2 mb-2"> <div class="flex items-center py-2 mb-2">
@ -260,8 +263,10 @@ export default {
homepageUseBookshelfView: false, homepageUseBookshelfView: false,
useBookshelfView: false, useBookshelfView: false,
isPurgingCache: false, isPurgingCache: false,
hasPrefixesChanged: false,
newServerSettings: {}, newServerSettings: {},
showConfirmPurgeCache: false, showConfirmPurgeCache: false,
savingPrefixes: false,
metadataFileFormats: [ metadataFileFormats: [
{ {
text: '.json', text: '.json',
@ -304,14 +309,35 @@ export default {
} }
}, },
methods: { methods: {
updateSortingPrefixes(val) { sortingPrefixesUpdated(val) {
if (!val || !val.length) { const prefixes = [...new Set(val?.map((prefix) => prefix.trim().toLowerCase()) || [])]
this.newServerSettings.sortingPrefixes = prefixes
const serverPrefixes = this.serverSettings.sortingPrefixes || []
this.hasPrefixesChanged = prefixes.some((p) => !serverPrefixes.includes(p)) || serverPrefixes.some((p) => !prefixes.includes(p))
},
updateSortingPrefixes() {
const prefixes = [...new Set(this.newServerSettings.sortingPrefixes.map((prefix) => prefix.trim().toLowerCase()) || [])]
if (!prefixes.length) {
this.$toast.error('Must have at least 1 prefix') this.$toast.error('Must have at least 1 prefix')
return return
} }
var prefixes = val.map((prefix) => prefix.trim().toLowerCase())
this.updateServerSettings({ this.savingPrefixes = true
sortingPrefixes: prefixes this.$axios
.$patch(`/api/sorting-prefixes`, { sortingPrefixes: prefixes })
.then((data) => {
this.$toast.success(`Sorting prefixes updated. ${data.rowsUpdated} rows`)
if (data.serverSettings) {
this.$store.commit('setServerSettings', data.serverSettings)
}
this.hasPrefixesChanged = false
})
.catch((error) => {
console.error('Failed to update prefixes', error)
this.$toast.error('Failed to update sorting prefixes')
})
.finally(() => {
this.savingPrefixes = false
}) })
}, },
updateScannerCoverProvider(val) { updateScannerCoverProvider(val) {

View File

@ -7,7 +7,7 @@ const Database = require('../Database')
const libraryItemFilters = require('../utils/queries/libraryItemFilters') const libraryItemFilters = require('../utils/queries/libraryItemFilters')
const patternValidation = require('../libs/nodeCron/pattern-validation') const patternValidation = require('../libs/nodeCron/pattern-validation')
const { isObject } = require('../utils/index') const { isObject, getTitleIgnorePrefix } = require('../utils/index')
// //
// This is a controller for routes that don't have a home yet :( // This is a controller for routes that don't have a home yet :(
@ -127,7 +127,7 @@ class MiscController {
} }
const settingsUpdate = req.body const settingsUpdate = req.body
if (!settingsUpdate || !isObject(settingsUpdate)) { if (!settingsUpdate || !isObject(settingsUpdate)) {
return res.status(500).send('Invalid settings update object') return res.status(400).send('Invalid settings update object')
} }
const madeUpdates = Database.serverSettings.update(settingsUpdate) const madeUpdates = Database.serverSettings.update(settingsUpdate)
@ -145,6 +145,103 @@ class MiscController {
}) })
} }
/**
* PATCH: /api/sorting-prefixes
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async updateSortingPrefixes(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('User other than admin attempting to update server sorting prefixes', req.user)
return res.sendStatus(403)
}
let sortingPrefixes = req.body.sortingPrefixes
if (!sortingPrefixes?.length || !Array.isArray(sortingPrefixes)) {
return res.status(400).send('Invalid request body')
}
sortingPrefixes = [...new Set(sortingPrefixes.map(p => p?.trim?.().toLowerCase()).filter(p => p))]
if (!sortingPrefixes.length) {
return res.status(400).send('Invalid sortingPrefixes in request body')
}
Logger.debug(`[MiscController] Updating sorting prefixes ${sortingPrefixes.join(', ')}`)
Database.serverSettings.sortingPrefixes = sortingPrefixes
await Database.updateServerSettings()
let rowsUpdated = 0
// Update titleIgnorePrefix column on books
const books = await Database.bookModel.findAll({
attributes: ['id', 'title', 'titleIgnorePrefix']
})
const bulkUpdateBooks = []
books.forEach((book) => {
const titleIgnorePrefix = getTitleIgnorePrefix(book.title)
if (titleIgnorePrefix !== book.titleIgnorePrefix) {
bulkUpdateBooks.push({
id: book.id,
titleIgnorePrefix
})
}
})
if (bulkUpdateBooks.length) {
Logger.info(`[MiscController] Updating titleIgnorePrefix on ${bulkUpdateBooks.length} books`)
rowsUpdated += bulkUpdateBooks.length
await Database.bookModel.bulkCreate(bulkUpdateBooks, {
updateOnDuplicate: ['titleIgnorePrefix']
})
}
// Update titleIgnorePrefix column on podcasts
const podcasts = await Database.podcastModel.findAll({
attributes: ['id', 'title', 'titleIgnorePrefix']
})
const bulkUpdatePodcasts = []
podcasts.forEach((podcast) => {
const titleIgnorePrefix = getTitleIgnorePrefix(podcast.title)
if (titleIgnorePrefix !== podcast.titleIgnorePrefix) {
bulkUpdatePodcasts.push({
id: podcast.id,
titleIgnorePrefix
})
}
})
if (bulkUpdatePodcasts.length) {
Logger.info(`[MiscController] Updating titleIgnorePrefix on ${bulkUpdatePodcasts.length} podcasts`)
rowsUpdated += bulkUpdatePodcasts.length
await Database.podcastModel.bulkCreate(bulkUpdatePodcasts, {
updateOnDuplicate: ['titleIgnorePrefix']
})
}
// Update nameIgnorePrefix column on series
const allSeries = await Database.seriesModel.findAll({
attributes: ['id', 'name', 'nameIgnorePrefix']
})
const bulkUpdateSeries = []
allSeries.forEach((series) => {
const nameIgnorePrefix = getTitleIgnorePrefix(series.name)
if (nameIgnorePrefix !== series.nameIgnorePrefix) {
bulkUpdateSeries.push({
id: series.id,
nameIgnorePrefix
})
}
})
if (bulkUpdateSeries.length) {
Logger.info(`[MiscController] Updating nameIgnorePrefix on ${bulkUpdateSeries.length} series`)
rowsUpdated += bulkUpdateSeries.length
await Database.seriesModel.bulkCreate(bulkUpdateSeries, {
updateOnDuplicate: ['nameIgnorePrefix']
})
}
res.json({
rowsUpdated,
serverSettings: Database.serverSettings.toJSONForBrowser()
})
}
/** /**
* POST: /api/authorize * POST: /api/authorize
* Used to authorize an API token * Used to authorize an API token

View File

@ -43,7 +43,7 @@ class ServerSettings {
// Sorting // Sorting
this.sortingIgnorePrefix = false this.sortingIgnorePrefix = false
this.sortingPrefixes = ['the'] this.sortingPrefixes = ['the', 'a']
// Misc Flags // Misc Flags
this.chromecastEnabled = false this.chromecastEnabled = false

View File

@ -297,6 +297,7 @@ class ApiRouter {
this.router.post('/upload', MiscController.handleUpload.bind(this)) this.router.post('/upload', MiscController.handleUpload.bind(this))
this.router.get('/tasks', MiscController.getTasks.bind(this)) this.router.get('/tasks', MiscController.getTasks.bind(this))
this.router.patch('/settings', MiscController.updateServerSettings.bind(this)) this.router.patch('/settings', MiscController.updateServerSettings.bind(this))
this.router.patch('/sorting-prefixes', MiscController.updateSortingPrefixes.bind(this))
this.router.post('/authorize', MiscController.authorize.bind(this)) this.router.post('/authorize', MiscController.authorize.bind(this))
this.router.get('/tags', MiscController.getAllTags.bind(this)) this.router.get('/tags', MiscController.getAllTags.bind(this))
this.router.post('/tags/rename', MiscController.renameTag.bind(this)) this.router.post('/tags/rename', MiscController.renameTag.bind(this))