Update:Encode & embed metadata API endpoints, separate cache & search endpoints into controllers

This commit is contained in:
advplyr 2022-11-19 13:28:06 -06:00
parent cd92a22f4d
commit e3ba739db5
8 changed files with 183 additions and 136 deletions

View File

@ -247,7 +247,7 @@ export default {
cancelEncodeClick() {
this.isCancelingEncode = true
this.$axios
.$post(`/api/encode-m4b/${this.libraryItemId}/cancel`)
.$delete(`/api/tools/item/${this.libraryItemId}/encode-m4b`)
.then(() => {
this.$toast.success('Encode canceled')
})
@ -262,7 +262,7 @@ export default {
encodeM4bClick() {
this.processing = true
this.$axios
.$get(`/api/encode-m4b/${this.libraryItemId}`)
.$post(`/api/tools/item/${this.libraryItemId}/encode-m4b`)
.then(() => {
console.log('Ab m4b merge started')
})
@ -287,7 +287,7 @@ export default {
updateAudioFileMetadata() {
this.processing = true
this.$axios
.$get(`/api/items/${this.libraryItemId}/audio-metadata?tone=1`)
.$post(`/api/tools/item/${this.libraryItemId}/embed-metadata?tone=1`)
.then(() => {
console.log('Audio metadata encode started')
})

View File

@ -0,0 +1,26 @@
const Logger = require('../Logger')
class CacheController {
constructor() { }
// POST: api/cache/purge
async purgeCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
Logger.info(`[MiscController] Purging all cache`)
await this.cacheManager.purgeAll()
res.sendStatus(200)
}
// POST: api/cache/items/purge
async purgeItemsCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
Logger.info(`[MiscController] Purging items cache`)
await this.cacheManager.purgeItems()
res.sendStatus(200)
}
}
module.exports = new CacheController()

View File

@ -389,24 +389,6 @@ class LibraryItemController {
res.json(this.audioMetadataManager.getToneMetadataObjectForApi(req.libraryItem))
}
// GET: api/items/:id/audio-metadata
async updateAudioFileMetadata(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-root user attempted to update audio metadata`, req.user)
return res.sendStatus(403)
}
if (req.libraryItem.isMissing || !req.libraryItem.hasAudioFiles || !req.libraryItem.isBook) {
Logger.error(`[LibraryItemController] Invalid library item`)
return res.sendStatus(500)
}
const useTone = req.query.tone === '1'
const forceEmbedChapters = req.query.forceEmbedChapters === '1'
this.audioMetadataManager.updateMetadataForItem(req.user, req.libraryItem, useTone, forceEmbedChapters)
res.sendStatus(200)
}
// POST: api/items/:id/chapters
async updateMediaChapters(req, res) {
if (!req.user.canUpdate) {

View File

@ -82,49 +82,6 @@ class MiscController {
res.sendStatus(200)
}
// GET: api/encode-m4b/:id
async encodeM4b(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('[MiscController] encodeM4b: Non-admin user attempting to make m4b', req.user)
return res.sendStatus(403)
}
var libraryItem = this.db.getLibraryItem(req.params.id)
if (!libraryItem || libraryItem.isMissing || libraryItem.isInvalid) {
Logger.error(`[MiscController] encodeM4b: library item not found or invalid ${req.params.id}`)
return res.status(404).send('Audiobook not found')
}
if (libraryItem.mediaType !== 'book') {
Logger.error(`[MiscController] encodeM4b: Invalid library item ${req.params.id}: not a book`)
return res.status(500).send('Invalid library item: not a book')
}
if (libraryItem.media.tracks.length <= 0) {
Logger.error(`[MiscController] encodeM4b: Invalid audiobook ${req.params.id}: no audio tracks`)
return res.status(500).send('Invalid audiobook: no audio tracks')
}
this.abMergeManager.startAudiobookMerge(req.user, libraryItem)
res.sendStatus(200)
}
// POST: api/encode-m4b/:id/cancel
async cancelM4bEncode(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('[MiscController] cancelM4bEncode: Non-admin user attempting to cancel m4b encode', req.user)
return res.sendStatus(403)
}
const workerTask = this.abMergeManager.getPendingTaskByLibraryItemId(req.params.id)
if (!workerTask) return res.sendStatus(404)
this.abMergeManager.cancelEncode(workerTask.task)
res.sendStatus(200)
}
// GET: api/tasks
getTasks(req, res) {
res.json({
@ -158,66 +115,6 @@ class MiscController {
})
}
// POST: api/cache/purge (admin)
async purgeCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
Logger.info(`[MiscController] Purging all cache`)
await this.cacheManager.purgeAll()
res.sendStatus(200)
}
// POST: api/cache/items/purge
async purgeItemsCache(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(403)
}
Logger.info(`[MiscController] Purging items cache`)
await this.cacheManager.purgeItems()
res.sendStatus(200)
}
async findBooks(req, res) {
var provider = req.query.provider || 'google'
var title = req.query.title || ''
var author = req.query.author || ''
var results = await this.bookFinder.search(provider, title, author)
res.json(results)
}
async findCovers(req, res) {
var query = req.query
var podcast = query.podcast == 1
var result = null
if (podcast) result = await this.podcastFinder.findCovers(query.title)
else result = await this.bookFinder.findCovers(query.provider, query.title, query.author || null)
res.json(result)
}
async findPodcasts(req, res) {
var term = req.query.term
var results = await this.podcastFinder.search(term)
res.json(results)
}
async findAuthor(req, res) {
var query = req.query.q
var author = await this.authorFinder.findAuthorByName(query)
res.json(author)
}
async findChapters(req, res) {
var asin = req.query.asin
var region = (req.query.region || 'us').toLowerCase()
var chapterData = await this.bookFinder.findChapters(asin, region)
if (!chapterData) {
return res.json({ error: 'Chapters not found' })
}
res.json(chapterData)
}
authorize(req, res) {
if (!req.user) {
Logger.error('Invalid user in authorize')

View File

@ -0,0 +1,44 @@
class SearchController {
constructor() { }
async findBooks(req, res) {
var provider = req.query.provider || 'google'
var title = req.query.title || ''
var author = req.query.author || ''
var results = await this.bookFinder.search(provider, title, author)
res.json(results)
}
async findCovers(req, res) {
var query = req.query
var podcast = query.podcast == 1
var result = null
if (podcast) result = await this.podcastFinder.findCovers(query.title)
else result = await this.bookFinder.findCovers(query.provider, query.title, query.author || null)
res.json(result)
}
async findPodcasts(req, res) {
var term = req.query.term
var results = await this.podcastFinder.search(term)
res.json(results)
}
async findAuthor(req, res) {
var query = req.query.q
var author = await this.authorFinder.findAuthorByName(query)
res.json(author)
}
async findChapters(req, res) {
var asin = req.query.asin
var region = (req.query.region || 'us').toLowerCase()
var chapterData = await this.bookFinder.findChapters(asin, region)
if (!chapterData) {
return res.json({ error: 'Chapters not found' })
}
res.json(chapterData)
}
}
module.exports = new SearchController()

View File

@ -0,0 +1,81 @@
const Logger = require('../Logger')
class ToolsController {
constructor() { }
// POST: api/tools/item/:id/encode-m4b
async encodeM4b(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('[MiscController] encodeM4b: Non-admin user attempting to make m4b', req.user)
return res.sendStatus(403)
}
if (req.libraryItem.isMissing || req.libraryItem.isInvalid) {
Logger.error(`[MiscController] encodeM4b: library item not found or invalid ${req.params.id}`)
return res.status(404).send('Audiobook not found')
}
if (req.libraryItem.mediaType !== 'book') {
Logger.error(`[MiscController] encodeM4b: Invalid library item ${req.params.id}: not a book`)
return res.status(500).send('Invalid library item: not a book')
}
if (req.libraryItem.media.tracks.length <= 0) {
Logger.error(`[MiscController] encodeM4b: Invalid audiobook ${req.params.id}: no audio tracks`)
return res.status(500).send('Invalid audiobook: no audio tracks')
}
this.abMergeManager.startAudiobookMerge(req.user, req.libraryItem)
res.sendStatus(200)
}
// DELETE: api/tools/item/:id/encode-m4b
async cancelM4bEncode(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('[MiscController] cancelM4bEncode: Non-admin user attempting to cancel m4b encode', req.user)
return res.sendStatus(403)
}
const workerTask = this.abMergeManager.getPendingTaskByLibraryItemId(req.params.id)
if (!workerTask) return res.sendStatus(404)
this.abMergeManager.cancelEncode(workerTask.task)
res.sendStatus(200)
}
// POST: api/tools/item/:id/embed-metadata
async embedAudioFileMetadata(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[LibraryItemController] Non-root user attempted to update audio metadata`, req.user)
return res.sendStatus(403)
}
if (req.libraryItem.isMissing || !req.libraryItem.hasAudioFiles || !req.libraryItem.isBook) {
Logger.error(`[LibraryItemController] Invalid library item`)
return res.sendStatus(500)
}
const useTone = req.query.tone === '1'
const forceEmbedChapters = req.query.forceEmbedChapters === '1'
this.audioMetadataManager.updateMetadataForItem(req.user, req.libraryItem, useTone, forceEmbedChapters)
res.sendStatus(200)
}
itemMiddleware(req, res, next) {
var item = this.db.libraryItems.find(li => li.id === req.params.id)
if (!item || !item.media) return res.sendStatus(404)
// Check user can access this library item
if (!req.user.checkCanAccessLibraryItem(item)) {
return res.sendStatus(403)
}
req.libraryItem = item
next()
}
}
module.exports = new ToolsController()

View File

@ -224,14 +224,16 @@ class AbMergeManager {
const pendingDl = this.pendingTasks.find(d => d.id === task.id)
if (pendingDl) {
this.pendingTasks = this.pendingTasks.filter(d => d.id !== task.id)
Logger.warn(`[AbMergeManager] Removing download in progress - stopping worker`)
if (pendingDl.worker) {
Logger.warn(`[AbMergeManager] Removing download in progress - stopping worker`)
try {
pendingDl.worker.postMessage('STOP')
return
} catch (error) {
Logger.error('[AbMergeManager] Error posting stop message to worker', error)
}
} else {
Logger.debug(`[AbMergeManager] Removing download in progress - no worker`)
}
}

View File

@ -11,10 +11,14 @@ const MeController = require('../controllers/MeController')
const BackupController = require('../controllers/BackupController')
const LibraryItemController = require('../controllers/LibraryItemController')
const SeriesController = require('../controllers/SeriesController')
const FileSystemController = require('../controllers/FileSystemController')
const AuthorController = require('../controllers/AuthorController')
const SessionController = require('../controllers/SessionController')
const PodcastController = require('../controllers/PodcastController')
const NotificationController = require('../controllers/NotificationController')
const SearchController = require('../controllers/SearchController')
const CacheController = require('../controllers/CacheController')
const ToolsController = require('../controllers/ToolsController')
const MiscController = require('../controllers/MiscController')
const BookFinder = require('../finders/BookFinder')
@ -23,7 +27,6 @@ const PodcastFinder = require('../finders/PodcastFinder')
const Author = require('../objects/entities/Author')
const Series = require('../objects/entities/Series')
const FileSystemController = require('../controllers/FileSystemController')
class ApiRouter {
constructor(db, auth, scanner, playbackSessionManager, abMergeManager, coverManager, backupManager, watcher, cacheManager, podcastManager, audioMetadataManager, rssFeedManager, cronManager, notificationManager, taskManager, getUsersOnline, emitter, clientEmitter) {
@ -98,7 +101,6 @@ class ApiRouter {
this.router.patch('/items/:id/tracks', LibraryItemController.middleware.bind(this), LibraryItemController.updateTracks.bind(this))
this.router.get('/items/:id/scan', LibraryItemController.middleware.bind(this), LibraryItemController.scan.bind(this))
this.router.get('/items/:id/tone-object', LibraryItemController.middleware.bind(this), LibraryItemController.getToneMetadataObject.bind(this))
this.router.get('/items/:id/audio-metadata', LibraryItemController.middleware.bind(this), LibraryItemController.updateAudioFileMetadata.bind(this))
this.router.post('/items/:id/chapters', LibraryItemController.middleware.bind(this), LibraryItemController.updateMediaChapters.bind(this))
this.router.post('/items/:id/open-feed', LibraryItemController.middleware.bind(this), LibraryItemController.openRSSFeed.bind(this))
this.router.post('/items/:id/close-feed', LibraryItemController.middleware.bind(this), LibraryItemController.closeRSSFeed.bind(this))
@ -224,22 +226,35 @@ class ApiRouter {
this.router.patch('/notifications/:id', NotificationController.middleware.bind(this), NotificationController.updateNotification.bind(this))
this.router.get('/notifications/:id/test', NotificationController.middleware.bind(this), NotificationController.sendNotificationTest.bind(this))
//
// Search Routes
//
this.router.get('/search/covers', SearchController.findCovers.bind(this))
this.router.get('/search/books', SearchController.findBooks.bind(this))
this.router.get('/search/podcast', SearchController.findPodcasts.bind(this))
this.router.get('/search/authors', SearchController.findAuthor.bind(this))
this.router.get('/search/chapters', SearchController.findChapters.bind(this))
//
// Cache Routes
//
this.router.post('/cache/purge', CacheController.purgeCache.bind(this))
this.router.post('/cache/items/purge', CacheController.purgeItemsCache.bind(this))
//
// Tools Routes
//
this.router.post('/tools/item/:id/encode-m4b', ToolsController.itemMiddleware.bind(this), ToolsController.encodeM4b.bind(this))
this.router.delete('/tools/item/:id/encode-m4b', ToolsController.itemMiddleware.bind(this), ToolsController.cancelM4bEncode.bind(this))
this.router.post('/tools/item/:id/embed-metadata', ToolsController.itemMiddleware.bind(this), ToolsController.embedAudioFileMetadata.bind(this))
//
// Misc Routes
//
this.router.post('/upload', MiscController.handleUpload.bind(this))
this.router.get('/encode-m4b/:id', MiscController.encodeM4b.bind(this))
this.router.post('/encode-m4b/:id/cancel', MiscController.cancelM4bEncode.bind(this))
this.router.get('/tasks', MiscController.getTasks.bind(this))
this.router.patch('/settings', MiscController.updateServerSettings.bind(this))
this.router.post('/cache/purge', MiscController.purgeCache.bind(this))
this.router.post('/cache/items/purge', MiscController.purgeItemsCache.bind(this))
this.router.post('/authorize', MiscController.authorize.bind(this))
this.router.get('/search/covers', MiscController.findCovers.bind(this))
this.router.get('/search/books', MiscController.findBooks.bind(this))
this.router.get('/search/podcast', MiscController.findPodcasts.bind(this))
this.router.get('/search/authors', MiscController.findAuthor.bind(this))
this.router.get('/search/chapters', MiscController.findChapters.bind(this))
this.router.get('/tags', MiscController.getAllTags.bind(this))
this.router.post('/validate-cron', MiscController.validateCronExpression.bind(this))
}