mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-31 16:24:45 +02:00
Update db migration for duration, size, lastFirst, and ignore prefix columns
This commit is contained in:
parent
0ca4ff4fca
commit
4dbe8d29d9
18 changed files with 777 additions and 26 deletions
154
server/utils/queries/libraryFilters.js
Normal file
154
server/utils/queries/libraryFilters.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
const { Op, literal, col, fn, where } = require('sequelize')
|
||||
const Database = require('../../Database')
|
||||
const libraryItemsSeriesFilters = require('./libraryItemsSeriesFilters')
|
||||
const libraryItemsProgressFilters = require('./libraryItemsProgressFilters')
|
||||
const Logger = require('../../Logger')
|
||||
|
||||
module.exports = {
|
||||
decode(text) {
|
||||
return Buffer.from(decodeURIComponent(text), 'base64').toString()
|
||||
},
|
||||
|
||||
getMediaGroupQuery(group, value) {
|
||||
let mediaWhere = {}
|
||||
|
||||
if (['genres', 'tags', 'narrators'].includes(group)) {
|
||||
mediaWhere[group] = {
|
||||
[Op.substring]: `"${value}"`
|
||||
}
|
||||
} else if (group === 'publishers') {
|
||||
mediaWhere['publisher'] = {
|
||||
[Op.substring]: `"${value}"`
|
||||
}
|
||||
} else if (group === 'languages') {
|
||||
mediaWhere['language'] = {
|
||||
[Op.substring]: `"${value}"`
|
||||
}
|
||||
} else if (group === 'tracks') {
|
||||
if (value === 'multi') {
|
||||
mediaWhere = where(fn('json_array_length', col('audioFiles')), {
|
||||
[Op.gt]: 1
|
||||
})
|
||||
} else {
|
||||
mediaWhere = where(fn('json_array_length', col('audioFiles')), 1)
|
||||
}
|
||||
} else if (group === 'ebooks') {
|
||||
if (value === 'ebook') {
|
||||
mediaWhere['ebookFile'] = {
|
||||
[Op.not]: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mediaWhere
|
||||
},
|
||||
|
||||
getOrder(sortBy, sortDesc) {
|
||||
const dir = sortDesc ? 'DESC' : 'ASC'
|
||||
if (sortBy === 'addedAt') {
|
||||
return [['createdAt', dir]]
|
||||
} else if (sortBy === 'size') {
|
||||
return [['size', dir]]
|
||||
} else if (sortBy === 'birthtimeMs') {
|
||||
return [['birthtime', dir]]
|
||||
} else if (sortBy === 'mtimeMs') {
|
||||
return [['mtime', dir]]
|
||||
} else if (sortBy === 'media.duration') {
|
||||
return [[literal('book.duration'), dir]]
|
||||
} else if (sortBy === 'media.metadata.publishedYear') {
|
||||
return [[literal('book.publishedYear'), dir]]
|
||||
} else if (sortBy === 'media.metadata.authorNameLF') {
|
||||
return [[literal('book.authors.lastFirst'), dir]]
|
||||
} else if (sortBy === 'media.metadata.authorName') {
|
||||
return [[literal('book.authors.name'), dir]]
|
||||
} else if (sortBy === 'media.metadata.title') {
|
||||
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||
return [[literal('book.titleIgnorePrefix'), dir]]
|
||||
} else {
|
||||
return [[literal('book.title'), dir]]
|
||||
}
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
async getFilteredLibraryItems(libraryId, filterBy, sortBy, sortDesc, limit, offset, userId) {
|
||||
const libraryItemModel = Database.models.libraryItem
|
||||
|
||||
let mediaWhereQuery = null
|
||||
let mediaAttributes = null
|
||||
let itemWhereQuery = {
|
||||
libraryId
|
||||
}
|
||||
|
||||
const itemIncludes = []
|
||||
|
||||
let authorInclude = {
|
||||
model: Database.models.author,
|
||||
through: {
|
||||
attributes: []
|
||||
}
|
||||
}
|
||||
let seriesInclude = {
|
||||
model: Database.models.series,
|
||||
through: {
|
||||
attributes: ['sequence']
|
||||
}
|
||||
}
|
||||
|
||||
const searchGroups = ['genres', 'tags', 'series', 'authors', 'progress', 'narrators', 'publishers', 'missing', 'languages', 'tracks', 'ebooks']
|
||||
const group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
|
||||
if (group) {
|
||||
// e.g. genre id
|
||||
const value = this.decode(filterBy.replace(`${group}.`, ''))
|
||||
|
||||
if (group === 'series' && value === 'no-series') {
|
||||
return libraryItemsSeriesFilters.getLibraryItemsWithNoSeries(libraryId, sortBy, sortDesc, limit, offset)
|
||||
} else if (group === 'progress') {
|
||||
return libraryItemsProgressFilters.getLibraryItemsWithProgressFilter(value, libraryId, userId, sortBy, sortDesc, limit, offset)
|
||||
}
|
||||
|
||||
if (group === 'authors') {
|
||||
authorInclude.where = {
|
||||
id: value
|
||||
}
|
||||
authorInclude.required = true
|
||||
} else if (group === 'series') {
|
||||
seriesInclude.where = {
|
||||
id: value
|
||||
}
|
||||
seriesInclude.required = true
|
||||
} else {
|
||||
mediaWhereQuery = this.getMediaGroupQuery(group, value)
|
||||
}
|
||||
} else if (filterBy === 'abridged') {
|
||||
mediaWhereQuery = {
|
||||
abridged: true
|
||||
}
|
||||
}
|
||||
|
||||
const { rows: libraryItems, count } = await libraryItemModel.findAndCountAll({
|
||||
where: itemWhereQuery,
|
||||
attributes: {
|
||||
include: [
|
||||
[fn('group_concat', col('book.author.name'), ', '), 'author_name']
|
||||
]
|
||||
},
|
||||
distinct: true,
|
||||
subQuery: false,
|
||||
include: [
|
||||
{
|
||||
model: Database.models.book,
|
||||
attributes: mediaAttributes,
|
||||
where: mediaWhereQuery,
|
||||
required: true,
|
||||
include: [authorInclude, seriesInclude, ...itemIncludes]
|
||||
}
|
||||
],
|
||||
order: this.getOrder(sortBy, sortDesc),
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
||||
return { libraryItems, count }
|
||||
}
|
||||
}
|
130
server/utils/queries/libraryItemsProgressFilters.js
Normal file
130
server/utils/queries/libraryItemsProgressFilters.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
const Sequelize = require('sequelize')
|
||||
const Database = require('../../Database')
|
||||
const Logger = require('../../Logger')
|
||||
|
||||
module.exports = {
|
||||
getOrder(sortBy, sortDesc) {
|
||||
const dir = sortDesc ? 'DESC' : 'ASC'
|
||||
if (sortBy === 'addedAt') {
|
||||
return [[Sequelize.literal('libraryItem.createdAt'), dir]]
|
||||
} else if (sortBy === 'size') {
|
||||
return [[Sequelize.literal('libraryItem.size'), dir]]
|
||||
} else if (sortBy === 'birthtimeMs') {
|
||||
return [[Sequelize.literal('libraryItem.birthtime'), dir]]
|
||||
} else if (sortBy === 'mtimeMs') {
|
||||
return [[Sequelize.literal('libraryItem.mtime'), dir]]
|
||||
} else if (sortBy === 'media.duration') {
|
||||
return [['duration', dir]]
|
||||
} else if (sortBy === 'media.metadata.publishedYear') {
|
||||
return [['publishedYear', dir]]
|
||||
} else if (sortBy === 'media.metadata.authorNameLF') {
|
||||
return [] // TODO: Handle author filter
|
||||
} else if (sortBy === 'media.metadata.authorName') {
|
||||
return [] // TODO: Handle author filter
|
||||
} else if (sortBy === 'media.metadata.title') {
|
||||
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||
return [['titleIgnorePrefix', dir]]
|
||||
} else {
|
||||
return [['title', dir]]
|
||||
}
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
async getLibraryItemsWithProgressFilter(filterValue, libraryId, userId, sortBy, sortDesc, limit, offset) {
|
||||
|
||||
const bookWhere = {}
|
||||
if (filterValue === 'not-finished') {
|
||||
bookWhere['$mediaProgresses.isFinished$'] = {
|
||||
[Sequelize.Op.or]: [null, false]
|
||||
}
|
||||
} else if (filterValue === 'not-started') {
|
||||
bookWhere['$mediaProgresses.currentTime$'] = {
|
||||
[Sequelize.Op.or]: [null, 0]
|
||||
}
|
||||
} else if (filterValue === 'finished') {
|
||||
bookWhere['$mediaProgresses.isFinished$'] = true
|
||||
} else { // in-progress
|
||||
bookWhere[Sequelize.Op.and] = [
|
||||
{
|
||||
'$book.mediaProgresses.currentTime$': {
|
||||
[Sequelize.Op.gt]: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
'$book.mediaProgresses.isFinished$': false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
const { rows: books, count } = await Database.models.book.findAndCountAll({
|
||||
where: bookWhere,
|
||||
distinct: true,
|
||||
include: [
|
||||
{
|
||||
model: Database.models.libraryItem,
|
||||
required: true,
|
||||
where: {
|
||||
libraryId
|
||||
}
|
||||
},
|
||||
{
|
||||
model: Database.models.bookSeries,
|
||||
attributes: ['seriesId', 'sequence'],
|
||||
include: {
|
||||
model: Database.models.series,
|
||||
attributes: ['id', 'name']
|
||||
},
|
||||
separate: true
|
||||
},
|
||||
{
|
||||
model: Database.models.bookAuthor,
|
||||
attributes: ['authorId'],
|
||||
include: {
|
||||
model: Database.models.author,
|
||||
attributes: ['id', 'name']
|
||||
},
|
||||
separate: true
|
||||
},
|
||||
{
|
||||
model: Database.models.mediaProgress,
|
||||
attributes: ['id', 'isFinished'],
|
||||
where: {
|
||||
userId
|
||||
},
|
||||
required: false
|
||||
}
|
||||
],
|
||||
order: this.getOrder(sortBy, sortDesc),
|
||||
subQuery: false,
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
|
||||
const libraryItems = books.map((bookExpanded) => {
|
||||
const libraryItem = bookExpanded.libraryItem.toJSON()
|
||||
const book = bookExpanded.toJSON()
|
||||
delete book.libraryItem
|
||||
|
||||
book.authors = []
|
||||
if (book.bookAuthors?.length) {
|
||||
book.bookAuthors.forEach((ba) => {
|
||||
if (ba.author) {
|
||||
book.authors.push(ba.author)
|
||||
}
|
||||
})
|
||||
}
|
||||
delete book.bookAuthors
|
||||
|
||||
libraryItem.media = book
|
||||
|
||||
return libraryItem
|
||||
})
|
||||
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
||||
return {
|
||||
libraryItems,
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
96
server/utils/queries/libraryItemsSeriesFilters.js
Normal file
96
server/utils/queries/libraryItemsSeriesFilters.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
const Sequelize = require('sequelize')
|
||||
const Database = require('../../Database')
|
||||
const Logger = require('../../Logger')
|
||||
|
||||
module.exports = {
|
||||
getOrder(sortBy, sortDesc) {
|
||||
const dir = sortDesc ? 'DESC' : 'ASC'
|
||||
if (sortBy === 'addedAt') {
|
||||
return [[Sequelize.literal('libraryItem.createdAt'), dir]]
|
||||
} else if (sortBy === 'size') {
|
||||
return [[Sequelize.literal('libraryItem.size'), dir]]
|
||||
} else if (sortBy === 'birthtimeMs') {
|
||||
return [[Sequelize.literal('libraryItem.birthtime'), dir]]
|
||||
} else if (sortBy === 'mtimeMs') {
|
||||
return [[Sequelize.literal('libraryItem.mtime'), dir]]
|
||||
} else if (sortBy === 'media.duration') {
|
||||
return [['duration', dir]]
|
||||
} else if (sortBy === 'media.metadata.publishedYear') {
|
||||
return [['publishedYear', dir]]
|
||||
} else if (sortBy === 'media.metadata.authorNameLF') {
|
||||
return [] // TODO: Handle author filter
|
||||
} else if (sortBy === 'media.metadata.authorName') {
|
||||
return [] // TODO: Handle author filter
|
||||
} else if (sortBy === 'media.metadata.title') {
|
||||
if (global.ServerSettings.sortingIgnorePrefix) {
|
||||
return [['titleIgnorePrefix', dir]]
|
||||
} else {
|
||||
return [['title', dir]]
|
||||
}
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
async getLibraryItemsWithNoSeries(libraryId, sortBy, sortDesc, limit, offset) {
|
||||
const { rows: books, count } = await Database.models.book.findAndCountAll({
|
||||
where: {
|
||||
'$series.id$': null
|
||||
},
|
||||
distinct: true,
|
||||
include: [
|
||||
{
|
||||
model: Database.models.libraryItem,
|
||||
required: true,
|
||||
where: {
|
||||
libraryId
|
||||
}
|
||||
},
|
||||
{
|
||||
model: Database.models.series,
|
||||
attributes: ['id', 'name'],
|
||||
through: {
|
||||
attributes: ['sequence']
|
||||
},
|
||||
},
|
||||
{
|
||||
model: Database.models.bookAuthor,
|
||||
attributes: ['authorId'],
|
||||
include: {
|
||||
model: Database.models.author,
|
||||
attributes: ['id', 'name']
|
||||
},
|
||||
separate: true
|
||||
}
|
||||
],
|
||||
order: this.getOrder(sortBy, sortDesc),
|
||||
subQuery: false,
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
|
||||
const libraryItems = books.map((bookExpanded) => {
|
||||
const libraryItem = bookExpanded.libraryItem.toJSON()
|
||||
const book = bookExpanded.toJSON()
|
||||
delete book.libraryItem
|
||||
|
||||
book.authors = []
|
||||
if (book.bookAuthors?.length) {
|
||||
book.bookAuthors.forEach((ba) => {
|
||||
if (ba.author) {
|
||||
book.authors.push(ba.author)
|
||||
}
|
||||
})
|
||||
}
|
||||
delete book.bookAuthors
|
||||
|
||||
libraryItem.media = book
|
||||
|
||||
return libraryItem
|
||||
})
|
||||
Logger.debug('Found', libraryItems.length, 'library items', 'total=', count)
|
||||
return {
|
||||
libraryItems,
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue