mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-18 02:49:44 +02:00
Update library stats API route to load from db
This commit is contained in:
69
server/utils/queries/authorFilters.js
Normal file
69
server/utils/queries/authorFilters.js
Normal file
@@ -0,0 +1,69 @@
|
||||
const Sequelize = require('sequelize')
|
||||
const Logger = require('../../Logger')
|
||||
const Database = require('../../Database')
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Get authors with count of num books
|
||||
* @param {string} libraryId
|
||||
* @returns {{id:string, name:string, count:number}}
|
||||
*/
|
||||
async getAuthorsWithCount(libraryId) {
|
||||
const authors = await Database.authorModel.findAll({
|
||||
where: [
|
||||
{
|
||||
libraryId
|
||||
},
|
||||
Sequelize.where(Sequelize.literal('count'), {
|
||||
[Sequelize.Op.gt]: 0
|
||||
})
|
||||
],
|
||||
attributes: [
|
||||
'id',
|
||||
'name',
|
||||
[Sequelize.literal('(SELECT count(*) FROM bookAuthors ba WHERE ba.authorId = author.id)'), 'count']
|
||||
],
|
||||
order: [
|
||||
['count', 'DESC']
|
||||
]
|
||||
})
|
||||
return authors.map(au => {
|
||||
return {
|
||||
id: au.id,
|
||||
name: au.name,
|
||||
count: au.dataValues.count
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Search authors
|
||||
* @param {string} libraryId
|
||||
* @param {string} query
|
||||
* @returns {object[]} oldAuthor with numBooks
|
||||
*/
|
||||
async search(libraryId, query) {
|
||||
const authors = await Database.authorModel.findAll({
|
||||
where: {
|
||||
name: {
|
||||
[Sequelize.Op.substring]: query
|
||||
},
|
||||
libraryId
|
||||
},
|
||||
attributes: {
|
||||
include: [
|
||||
[Sequelize.literal('(SELECT count(*) FROM bookAuthors ba WHERE ba.authorId = author.id)'), 'numBooks']
|
||||
]
|
||||
},
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
const authorMatches = []
|
||||
for (const author of authors) {
|
||||
const oldAuthor = author.getOldAuthor().toJSON()
|
||||
oldAuthor.numBooks = author.dataValues.numBooks
|
||||
authorMatches.push(oldAuthor)
|
||||
}
|
||||
return authorMatches
|
||||
}
|
||||
}
|
@@ -180,5 +180,41 @@ module.exports = {
|
||||
} else {
|
||||
return libraryItemsPodcastFilters.search(oldUser, oldLibrary, query, limit, 0)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get largest items in library
|
||||
* @param {string} libraryId
|
||||
* @param {number} limit
|
||||
* @returns {Promise<{ id:string, title:string, size:number }[]>}
|
||||
*/
|
||||
async getLargestItems(libraryId, limit) {
|
||||
const libraryItems = await Database.libraryItemModel.findAll({
|
||||
attributes: ['id', 'mediaId', 'mediaType', 'size'],
|
||||
where: {
|
||||
libraryId
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Database.bookModel,
|
||||
attributes: ['id', 'title']
|
||||
},
|
||||
{
|
||||
model: Database.podcastModel,
|
||||
attributes: ['id', 'title']
|
||||
}
|
||||
],
|
||||
order: [
|
||||
['size', 'DESC']
|
||||
],
|
||||
limit
|
||||
})
|
||||
return libraryItems.map(libraryItem => {
|
||||
return {
|
||||
id: libraryItem.id,
|
||||
title: libraryItem.media.title,
|
||||
size: libraryItem.size
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
const Sequelize = require('sequelize')
|
||||
const Database = require('../../Database')
|
||||
const Logger = require('../../Logger')
|
||||
const authorFilters = require('./authorFilters')
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
@@ -1098,27 +1099,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
// Search authors
|
||||
const authors = await Database.authorModel.findAll({
|
||||
where: {
|
||||
name: {
|
||||
[Sequelize.Op.substring]: query
|
||||
},
|
||||
libraryId: oldLibrary.id
|
||||
},
|
||||
attributes: {
|
||||
include: [
|
||||
[Sequelize.literal('(SELECT count(*) FROM bookAuthors ba WHERE ba.authorId = author.id)'), 'numBooks']
|
||||
]
|
||||
},
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
const authorMatches = []
|
||||
for (const author of authors) {
|
||||
const oldAuthor = author.getOldAuthor().toJSON()
|
||||
oldAuthor.numBooks = author.dataValues.numBooks
|
||||
authorMatches.push(oldAuthor)
|
||||
}
|
||||
const authorMatches = await authorFilters.search(oldLibrary.id, query)
|
||||
|
||||
return {
|
||||
book: itemMatches,
|
||||
@@ -1127,5 +1108,71 @@ module.exports = {
|
||||
series: seriesMatches,
|
||||
authors: authorMatches
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Genres with num books
|
||||
* @param {string} libraryId
|
||||
* @returns {{genre:string, count:number}[]}
|
||||
*/
|
||||
async getGenresWithCount(libraryId) {
|
||||
const genres = []
|
||||
const [genreResults] = await Database.sequelize.query(`SELECT value, count(*) AS numItems FROM books b, libraryItems li, json_each(b.genres) WHERE json_valid(b.genres) AND b.id = li.mediaId AND li.libraryId = :libraryId GROUP BY value ORDER BY numItems DESC;`, {
|
||||
replacements: {
|
||||
libraryId
|
||||
},
|
||||
raw: true
|
||||
})
|
||||
for (const row of genreResults) {
|
||||
genres.push({
|
||||
genre: row.value,
|
||||
count: row.numItems
|
||||
})
|
||||
}
|
||||
return genres
|
||||
},
|
||||
|
||||
/**
|
||||
* Get stats for book library
|
||||
* @param {string} libraryId
|
||||
* @returns {Promise<{ totalSize:number, totalDuration:number, numAudioFiles:number, totalItems:number}>}
|
||||
*/
|
||||
async getBookLibraryStats(libraryId) {
|
||||
const [statResults] = await Database.sequelize.query(`SELECT SUM(li.size) AS totalSize, SUM(b.duration) AS totalDuration, SUM(json_array_length(b.audioFiles)) AS numAudioFiles, COUNT(*) AS totalItems FROM libraryItems li, books b WHERE b.id = li.mediaId AND li.libraryId = :libraryId;`, {
|
||||
replacements: {
|
||||
libraryId
|
||||
}
|
||||
})
|
||||
return statResults[0]
|
||||
},
|
||||
|
||||
/**
|
||||
* Get longest books in library
|
||||
* @param {string} libraryId
|
||||
* @param {number} limit
|
||||
* @returns {Promise<{ id:string, title:string, duration:number }[]>}
|
||||
*/
|
||||
async getLongestBooks(libraryId, limit) {
|
||||
const books = await Database.bookModel.findAll({
|
||||
attributes: ['id', 'title', 'duration'],
|
||||
include: {
|
||||
model: Database.libraryItemModel,
|
||||
attributes: ['id', 'libraryId'],
|
||||
where: {
|
||||
libraryId
|
||||
}
|
||||
},
|
||||
order: [
|
||||
['duration', 'DESC']
|
||||
],
|
||||
limit
|
||||
})
|
||||
return books.map(book => {
|
||||
return {
|
||||
id: book.libraryItem.id,
|
||||
title: book.title,
|
||||
duration: book.duration
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -455,5 +455,75 @@ module.exports = {
|
||||
})
|
||||
|
||||
return episodeResults
|
||||
},
|
||||
|
||||
/**
|
||||
* Get stats for podcast library
|
||||
* @param {string} libraryId
|
||||
* @returns {Promise<{ totalSize:number, totalDuration:number, numAudioFiles:number, totalItems:number}>}
|
||||
*/
|
||||
async getPodcastLibraryStats(libraryId) {
|
||||
const [statResults] = await Database.sequelize.query(`SELECT SUM(json_extract(pe.audioFile, '$.duration')) AS totalDuration, SUM(li.size) AS totalSize, COUNT(DISTINCT(li.id)) AS totalItems, COUNT(pe.id) AS numAudioFiles FROM libraryItems li, podcasts p LEFT OUTER JOIN podcastEpisodes pe ON pe.podcastId = p.id WHERE p.id = li.mediaId AND li.libraryId = :libraryId;`, {
|
||||
replacements: {
|
||||
libraryId
|
||||
}
|
||||
})
|
||||
return statResults[0]
|
||||
},
|
||||
|
||||
/**
|
||||
* Genres with num podcasts
|
||||
* @param {string} libraryId
|
||||
* @returns {{genre:string, count:number}[]}
|
||||
*/
|
||||
async getGenresWithCount(libraryId) {
|
||||
const genres = []
|
||||
const [genreResults] = await Database.sequelize.query(`SELECT value, count(*) AS numItems FROM podcasts p, libraryItems li, json_each(p.genres) WHERE json_valid(p.genres) AND p.id = li.mediaId AND li.libraryId = :libraryId GROUP BY value ORDER BY numItems DESC;`, {
|
||||
replacements: {
|
||||
libraryId
|
||||
},
|
||||
raw: true
|
||||
})
|
||||
for (const row of genreResults) {
|
||||
genres.push({
|
||||
genre: row.value,
|
||||
count: row.numItems
|
||||
})
|
||||
}
|
||||
return genres
|
||||
},
|
||||
|
||||
/**
|
||||
* Get longest podcasts in library
|
||||
* @param {string} libraryId
|
||||
* @param {number} limit
|
||||
* @returns {Promise<{ id:string, title:string, duration:number }[]>}
|
||||
*/
|
||||
async getLongestPodcasts(libraryId, limit) {
|
||||
const podcasts = await Database.podcastModel.findAll({
|
||||
attributes: [
|
||||
'id',
|
||||
'title',
|
||||
[Sequelize.literal(`(SELECT SUM(json_extract(pe.audioFile, '$.duration')) FROM podcastEpisodes pe WHERE pe.podcastId = podcast.id)`), 'duration']
|
||||
],
|
||||
include: {
|
||||
model: Database.libraryItemModel,
|
||||
attributes: ['id', 'libraryId'],
|
||||
where: {
|
||||
libraryId
|
||||
}
|
||||
},
|
||||
order: [
|
||||
['duration', 'DESC']
|
||||
],
|
||||
limit
|
||||
})
|
||||
return podcasts.map(podcast => {
|
||||
return {
|
||||
id: podcast.libraryItem.id,
|
||||
title: podcast.title,
|
||||
duration: podcast.dataValues.duration
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user