Change:Series volume numbers to use language sensitive sorting #261

This commit is contained in:
advplyr 2021-12-26 11:25:07 -06:00
parent 49fcaefd01
commit ef94a6bb29
4 changed files with 45 additions and 31 deletions

View File

@ -15,6 +15,7 @@ const BackupController = require('./controllers/BackupController')
const BookFinder = require('./BookFinder') const BookFinder = require('./BookFinder')
const AuthorFinder = require('./AuthorFinder') const AuthorFinder = require('./AuthorFinder')
const FileSystemController = require('./controllers/FileSystemController')
class ApiController { class ApiController {
constructor(MetadataPath, db, auth, streamManager, rssFeeds, downloadManager, coverController, backupManager, watcher, cacheManager, emitter, clientEmitter) { constructor(MetadataPath, db, auth, streamManager, rssFeeds, downloadManager, coverController, backupManager, watcher, cacheManager, emitter, clientEmitter) {
@ -145,6 +146,11 @@ class ApiController {
this.router.get('/search/covers', this.findCovers.bind(this)) this.router.get('/search/covers', this.findCovers.bind(this))
this.router.get('/search/books', this.findBooks.bind(this)) this.router.get('/search/books', this.findBooks.bind(this))
//
// File System Routes
//
this.router.get('/filesystem', FileSystemController.getPaths.bind(this))
// //
// Others // Others
// //
@ -163,8 +169,6 @@ class ApiController {
this.router.get('/download/:id', this.download.bind(this)) this.router.get('/download/:id', this.download.bind(this))
this.router.get('/filesystem', this.getFileSystemPaths.bind(this))
this.router.post('/syncUserAudiobookData', this.syncUserAudiobookData.bind(this)) this.router.post('/syncUserAudiobookData', this.syncUserAudiobookData.bind(this))
this.router.post('/purgecache', this.purgeCache.bind(this)) this.router.post('/purgecache', this.purgeCache.bind(this))
@ -339,25 +343,6 @@ class ApiController {
} }
} }
async getFileSystemPaths(req, res) {
var excludedDirs = ['node_modules', 'client', 'server', '.git', 'static', 'build', 'dist', 'metadata', 'config', 'sys', 'proc'].map(dirname => {
return Path.sep + dirname
})
// Do not include existing mapped library paths in response
this.db.libraries.forEach(lib => {
lib.folders.forEach((folder) => {
var dir = folder.fullPath
if (dir.includes(global.appRoot)) dir = dir.replace(global.appRoot, '')
excludedDirs.push(dir)
})
})
Logger.debug(`[Server] get file system paths, excluded: ${excludedDirs.join(', ')}`)
var dirs = await this.getDirectories(global.appRoot, '/', excludedDirs)
res.json(dirs)
}
async syncUserAudiobookData(req, res) { async syncUserAudiobookData(req, res) {
if (!req.body.data) { if (!req.body.data) {
return res.status(403).send('Invalid local user audiobook data') return res.status(403).send('Invalid local user audiobook data')

View File

@ -0,0 +1,25 @@
const Logger = require('../Logger')
class FileSystemController {
constructor() { }
async getPaths(req, res) {
var excludedDirs = ['node_modules', 'client', 'server', '.git', 'static', 'build', 'dist', 'metadata', 'config', 'sys', 'proc'].map(dirname => {
return Path.sep + dirname
})
// Do not include existing mapped library paths in response
this.db.libraries.forEach(lib => {
lib.folders.forEach((folder) => {
var dir = folder.fullPath
if (dir.includes(global.appRoot)) dir = dir.replace(global.appRoot, '')
excludedDirs.push(dir)
})
})
Logger.debug(`[Server] get file system paths, excluded: ${excludedDirs.join(', ')}`)
var dirs = await this.getDirectories(global.appRoot, '/', excludedDirs)
res.json(dirs)
}
}
module.exports = new FileSystemController()

View File

@ -189,12 +189,9 @@ class LibraryController {
if (!audiobooks.length) { if (!audiobooks.length) {
return res.status(404).send('Series not found') return res.status(404).send('Series not found')
} }
audiobooks = sort(audiobooks).asc(ab => { var sortedBooks = libraryHelpers.sortSeriesBooks(audiobooks, false)
if (!isNaN(ab.book.volumeNumber) && ab.book.volumeNumber !== null) return Number(ab.book.volumeNumber)
return ab.book.volumeNumber
})
res.json({ res.json({
results: audiobooks.map(ab => ab.toJSONExpanded()), results: sortedBooks,
total: audiobooks.length total: audiobooks.length
}) })
} }

View File

@ -1,4 +1,7 @@
const { sort } = require('fast-sort') const { sort, createNewSortInstance } = require('fast-sort')
const naturalSort = createNewSortInstance({
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
})
module.exports = { module.exports = {
decode(text) { decode(text) {
@ -92,14 +95,18 @@ module.exports = {
} }
}) })
return Object.values(_series).map((series) => { return Object.values(_series).map((series) => {
series.books = sort(series.books).asc(ab => { series.books = naturalSort(series.books).asc(ab => ab.book.volumeNumber)
if (!isNaN(ab.book.volumeNumber) && ab.book.volumeNumber !== null) return Number(ab.book.volumeNumber)
return ab.book.volumeNumber
})
return series return series
}) })
}, },
sortSeriesBooks(books, minified = false) {
return naturalSort(books).asc(ab => ab.book.volumeNumber).map(ab => {
if (minified) return ab.toJSONMinified()
return ab.toJSONExpanded()
})
},
getBooksWithUserAudiobook(user, books) { getBooksWithUserAudiobook(user, books) {
return books.map(book => { return books.map(book => {
return { return {