mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-10 19:31:39 +00:00
Compare commits
No commits in common. "8bea5d83f5d66bb21b8db579f99bbc40fc5d9c68" and "f853cff920f291ef59179226244c01c21b2ac221" have entirely different histories.
8bea5d83f5
...
f853cff920
3 changed files with 3 additions and 128 deletions
|
|
@ -1,75 +0,0 @@
|
||||||
const { Request, Response, NextFunction } = require('express')
|
|
||||||
const Logger = require('../Logger')
|
|
||||||
|
|
||||||
const adminStats = require('../utils/queries/adminStats')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef RequestUserObject
|
|
||||||
* @property {import('../models/User')} user
|
|
||||||
*
|
|
||||||
* @typedef {Request & RequestUserObject} RequestWithUser
|
|
||||||
*/
|
|
||||||
|
|
||||||
class StatsController {
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET: /api/stats/server
|
|
||||||
* Currently not in use
|
|
||||||
*
|
|
||||||
* @param {RequestWithUser} req
|
|
||||||
* @param {Response} res
|
|
||||||
*/
|
|
||||||
async getServerStats(req, res) {
|
|
||||||
Logger.debug('[StatsController] getServerStats')
|
|
||||||
const totalSize = await adminStats.getTotalSize()
|
|
||||||
const numAudioFiles = await adminStats.getNumAudioFiles()
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
books: {
|
|
||||||
...totalSize.books,
|
|
||||||
numAudioFiles: numAudioFiles.numBookAudioFiles
|
|
||||||
},
|
|
||||||
podcasts: {
|
|
||||||
...totalSize.podcasts,
|
|
||||||
numAudioFiles: numAudioFiles.numPodcastAudioFiles
|
|
||||||
},
|
|
||||||
total: {
|
|
||||||
...totalSize.total,
|
|
||||||
numAudioFiles: numAudioFiles.numAudioFiles
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GET: /api/stats/year/:year
|
|
||||||
*
|
|
||||||
* @param {RequestWithUser} req
|
|
||||||
* @param {Response} res
|
|
||||||
*/
|
|
||||||
async getAdminStatsForYear(req, res) {
|
|
||||||
const year = Number(req.params.year)
|
|
||||||
if (isNaN(year) || year < 2000 || year > 9999) {
|
|
||||||
Logger.error(`[StatsController] Invalid year "${year}"`)
|
|
||||||
return res.status(400).send('Invalid year')
|
|
||||||
}
|
|
||||||
const stats = await adminStats.getStatsForYear(year)
|
|
||||||
res.json(stats)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {RequestWithUser} req
|
|
||||||
* @param {Response} res
|
|
||||||
* @param {NextFunction} next
|
|
||||||
*/
|
|
||||||
async middleware(req, res, next) {
|
|
||||||
if (!req.user.isAdminOrUp) {
|
|
||||||
Logger.error(`[StatsController] Non-admin user "${req.user.username}" attempted to access stats route`)
|
|
||||||
return res.sendStatus(403)
|
|
||||||
}
|
|
||||||
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = new StatsController()
|
|
||||||
|
|
@ -33,7 +33,8 @@ const RSSFeedController = require('../controllers/RSSFeedController')
|
||||||
const CustomMetadataProviderController = require('../controllers/CustomMetadataProviderController')
|
const CustomMetadataProviderController = require('../controllers/CustomMetadataProviderController')
|
||||||
const MiscController = require('../controllers/MiscController')
|
const MiscController = require('../controllers/MiscController')
|
||||||
const ShareController = require('../controllers/ShareController')
|
const ShareController = require('../controllers/ShareController')
|
||||||
const StatsController = require('../controllers/StatsController')
|
|
||||||
|
const { getTitleIgnorePrefix } = require('../utils/index')
|
||||||
|
|
||||||
class ApiRouter {
|
class ApiRouter {
|
||||||
constructor(Server) {
|
constructor(Server) {
|
||||||
|
|
@ -319,12 +320,6 @@ class ApiRouter {
|
||||||
this.router.post('/share/mediaitem', ShareController.createMediaItemShare.bind(this))
|
this.router.post('/share/mediaitem', ShareController.createMediaItemShare.bind(this))
|
||||||
this.router.delete('/share/mediaitem/:id', ShareController.deleteMediaItemShare.bind(this))
|
this.router.delete('/share/mediaitem/:id', ShareController.deleteMediaItemShare.bind(this))
|
||||||
|
|
||||||
//
|
|
||||||
// Stats Routes
|
|
||||||
//
|
|
||||||
this.router.get('/stats/year/:year', StatsController.middleware.bind(this), StatsController.getAdminStatsForYear.bind(this))
|
|
||||||
this.router.get('/stats/server', StatsController.middleware.bind(this), StatsController.getServerStats.bind(this))
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Misc Routes
|
// Misc Routes
|
||||||
//
|
//
|
||||||
|
|
@ -343,6 +338,7 @@ class ApiRouter {
|
||||||
this.router.get('/auth-settings', MiscController.getAuthSettings.bind(this))
|
this.router.get('/auth-settings', MiscController.getAuthSettings.bind(this))
|
||||||
this.router.patch('/auth-settings', MiscController.updateAuthSettings.bind(this))
|
this.router.patch('/auth-settings', MiscController.updateAuthSettings.bind(this))
|
||||||
this.router.post('/watcher/update', MiscController.updateWatchedPath.bind(this))
|
this.router.post('/watcher/update', MiscController.updateWatchedPath.bind(this))
|
||||||
|
this.router.get('/stats/year/:year', MiscController.getAdminStatsForYear.bind(this))
|
||||||
this.router.get('/logger-data', MiscController.getLoggerData.bind(this))
|
this.router.get('/logger-data', MiscController.getLoggerData.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,51 +167,5 @@ module.exports = {
|
||||||
topNarrators,
|
topNarrators,
|
||||||
topGenres
|
topGenres
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get total file size and number of items for books and podcasts
|
|
||||||
*
|
|
||||||
* @typedef {Object} SizeObject
|
|
||||||
* @property {number} totalSize
|
|
||||||
* @property {number} numItems
|
|
||||||
*
|
|
||||||
* @returns {Promise<{books: SizeObject, podcasts: SizeObject, total: SizeObject}}>}
|
|
||||||
*/
|
|
||||||
async getTotalSize() {
|
|
||||||
const [mediaTypeStats] = await Database.sequelize.query(`SELECT li.mediaType, SUM(li.size) AS totalSize, COUNT(*) AS numItems FROM libraryItems li group by li.mediaType;`)
|
|
||||||
const bookStats = mediaTypeStats.find((m) => m.mediaType === 'book')
|
|
||||||
const podcastStats = mediaTypeStats.find((m) => m.mediaType === 'podcast')
|
|
||||||
|
|
||||||
return {
|
|
||||||
books: {
|
|
||||||
totalSize: bookStats?.totalSize || 0,
|
|
||||||
numItems: bookStats?.numItems || 0
|
|
||||||
},
|
|
||||||
podcasts: {
|
|
||||||
totalSize: podcastStats?.totalSize || 0,
|
|
||||||
numItems: podcastStats?.numItems || 0
|
|
||||||
},
|
|
||||||
total: {
|
|
||||||
totalSize: (bookStats?.totalSize || 0) + (podcastStats?.totalSize || 0),
|
|
||||||
numItems: (bookStats?.numItems || 0) + (podcastStats?.numItems || 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get total number of audio files for books and podcasts
|
|
||||||
*
|
|
||||||
* @returns {Promise<{numBookAudioFiles: number, numPodcastAudioFiles: number, numAudioFiles: number}>}
|
|
||||||
*/
|
|
||||||
async getNumAudioFiles() {
|
|
||||||
const [numBookAudioFilesRow] = await Database.sequelize.query(`SELECT SUM(json_array_length(b.audioFiles)) AS numAudioFiles FROM books b;`)
|
|
||||||
const numBookAudioFiles = numBookAudioFilesRow[0]?.numAudioFiles || 0
|
|
||||||
const numPodcastAudioFiles = await Database.podcastEpisodeModel.count()
|
|
||||||
return {
|
|
||||||
numBookAudioFiles,
|
|
||||||
numPodcastAudioFiles,
|
|
||||||
numAudioFiles: numBookAudioFiles + numPodcastAudioFiles
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue