Create podcast manager and re-organize managers

This commit is contained in:
advplyr 2022-03-20 16:41:06 -05:00
parent 122f2a2556
commit e1e6b46456
12 changed files with 86 additions and 65 deletions

View File

@ -17,15 +17,18 @@ const Auth = require('./Auth')
const Watcher = require('./Watcher') const Watcher = require('./Watcher')
const Scanner = require('./scanner/Scanner') const Scanner = require('./scanner/Scanner')
const Db = require('./Db') const Db = require('./Db')
const BackupManager = require('./BackupManager')
const LogManager = require('./LogManager')
const ApiRouter = require('./routers/ApiRouter') const ApiRouter = require('./routers/ApiRouter')
const HlsRouter = require('./routers/HlsRouter') const HlsRouter = require('./routers/HlsRouter')
const StaticRouter = require('./routers/StaticRouter') const StaticRouter = require('./routers/StaticRouter')
const PlaybackSessionManager = require('./PlaybackSessionManager')
const DownloadManager = require('./DownloadManager') const CoverManager = require('./managers/CoverManager')
const CoverController = require('./CoverController') const DownloadManager = require('./managers/DownloadManager')
const CacheManager = require('./CacheManager') const CacheManager = require('./managers/CacheManager')
const LogManager = require('./managers/LogManager')
const BackupManager = require('./managers/BackupManager')
const PlaybackSessionManager = require('./managers/PlaybackSessionManager')
const PodcastManager = require('./managers/PodcastManager')
class Server { class Server {
constructor(PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) { constructor(PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) {
@ -48,18 +51,22 @@ class Server {
fs.ensureDirSync(global.AudiobookPath, 0o774) fs.ensureDirSync(global.AudiobookPath, 0o774)
this.db = new Db() this.db = new Db()
this.watcher = new Watcher()
this.auth = new Auth(this.db) this.auth = new Auth(this.db)
// Managers
this.backupManager = new BackupManager(this.db, this.emitter.bind(this)) this.backupManager = new BackupManager(this.db, this.emitter.bind(this))
this.logManager = new LogManager(this.db) this.logManager = new LogManager(this.db)
this.cacheManager = new CacheManager() this.cacheManager = new CacheManager()
this.watcher = new Watcher()
this.coverController = new CoverController(this.db, this.cacheManager)
this.scanner = new Scanner(this.db, this.coverController, this.emitter.bind(this))
this.playbackSessionManager = new PlaybackSessionManager(this.db, this.emitter.bind(this), this.clientEmitter.bind(this))
this.downloadManager = new DownloadManager(this.db) this.downloadManager = new DownloadManager(this.db)
this.playbackSessionManager = new PlaybackSessionManager(this.db, this.emitter.bind(this), this.clientEmitter.bind(this))
this.coverManager = new CoverManager(this.db, this.cacheManager)
this.podcastManager = new PodcastManager(this.db)
this.scanner = new Scanner(this.db, this.coverManager, this.emitter.bind(this))
// Routers // Routers
this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.downloadManager, this.coverController, this.backupManager, this.watcher, this.cacheManager, this.emitter.bind(this), this.clientEmitter.bind(this)) this.apiRouter = new ApiRouter(this.db, this.auth, this.scanner, this.playbackSessionManager, this.downloadManager, this.coverManager, this.backupManager, this.watcher, this.cacheManager, this.podcastManager, this.emitter.bind(this), this.clientEmitter.bind(this))
this.hlsRouter = new HlsRouter(this.db, this.auth, this.playbackSessionManager, this.emitter.bind(this)) this.hlsRouter = new HlsRouter(this.db, this.auth, this.playbackSessionManager, this.emitter.bind(this))
this.staticRouter = new StaticRouter(this.db) this.staticRouter = new StaticRouter(this.db)

View File

@ -16,7 +16,7 @@ class AuthorController {
this.cacheManager.purgeImageCache(req.author.id) this.cacheManager.purgeImageCache(req.author.id)
if (!payload.imagePath) { // If removing image then remove file if (!payload.imagePath) { // If removing image then remove file
var currentImagePath = req.author.imagePath var currentImagePath = req.author.imagePath
await this.coverController.removeFile(currentImagePath) await this.coverManager.removeFile(currentImagePath)
} }
} }

View File

@ -68,10 +68,10 @@ class LibraryItemController {
var result = null var result = null
if (req.body && req.body.url) { if (req.body && req.body.url) {
Logger.debug(`[LibraryItemController] Requesting download cover from url "${req.body.url}"`) Logger.debug(`[LibraryItemController] Requesting download cover from url "${req.body.url}"`)
result = await this.coverController.downloadCoverFromUrl(libraryItem, req.body.url) result = await this.coverManager.downloadCoverFromUrl(libraryItem, req.body.url)
} else if (req.files && req.files.cover) { } else if (req.files && req.files.cover) {
Logger.debug(`[LibraryItemController] Handling uploaded cover`) Logger.debug(`[LibraryItemController] Handling uploaded cover`)
result = await this.coverController.uploadCover(libraryItem, req.files.cover) result = await this.coverManager.uploadCover(libraryItem, req.files.cover)
} else { } else {
return res.status(400).send('Invalid request no file or url') return res.status(400).send('Invalid request no file or url')
} }
@ -97,7 +97,7 @@ class LibraryItemController {
return res.status(400).error('Invalid request no cover path') return res.status(400).error('Invalid request no cover path')
} }
var validationResult = await this.coverController.validateCoverPath(req.body.cover, libraryItem) var validationResult = await this.coverManager.validateCoverPath(req.body.cover, libraryItem)
if (validationResult.error) { if (validationResult.error) {
return res.status(500).send(validationResult.error) return res.status(500).send(validationResult.error)
} }

View File

@ -6,11 +6,11 @@ const archiver = require('archiver')
const StreamZip = require('node-stream-zip') const StreamZip = require('node-stream-zip')
// Utils // Utils
const { getFileSize } = require('./utils/fileUtils') const { getFileSize } = require('../utils/fileUtils')
const filePerms = require('./utils/filePerms') const filePerms = require('../utils/filePerms')
const Logger = require('./Logger') const Logger = require('../Logger')
const Backup = require('./objects/Backup') const Backup = require('../objects/Backup')
class BackupManager { class BackupManager {
constructor(db, emitter) { constructor(db, emitter) {

View File

@ -1,8 +1,8 @@
const Path = require('path') const Path = require('path')
const fs = require('fs-extra') const fs = require('fs-extra')
const stream = require('stream') const stream = require('stream')
const Logger = require('./Logger') const Logger = require('../Logger')
const { resizeImage } = require('./utils/ffmpegHelpers') const { resizeImage } = require('../utils/ffmpegHelpers')
class CacheManager { class CacheManager {
constructor() { constructor() {

View File

@ -1,16 +1,16 @@
const fs = require('fs-extra') const fs = require('fs-extra')
const Path = require('path') const Path = require('path')
const axios = require('axios') const axios = require('axios')
const Logger = require('./Logger') const Logger = require('../Logger')
const readChunk = require('read-chunk') const readChunk = require('read-chunk')
const imageType = require('image-type') const imageType = require('image-type')
const filePerms = require('./utils/filePerms') const filePerms = require('../utils/filePerms')
const globals = require('./utils/globals') const globals = require('../utils/globals')
const { downloadFile } = require('./utils/fileUtils') const { downloadFile } = require('../utils/fileUtils')
const { extractCoverArt } = require('./utils/ffmpegHelpers') const { extractCoverArt } = require('../utils/ffmpegHelpers')
class CoverController { class CoverManager {
constructor(db, cacheManager) { constructor(db, cacheManager) {
this.db = db this.db = db
this.cacheManager = cacheManager this.cacheManager = cacheManager
@ -30,7 +30,7 @@ class CoverController {
try { try {
return fs.readdir(dir) return fs.readdir(dir)
} catch (error) { } catch (error) {
Logger.error(`[CoverController] Failed to get files in dir ${dir}`, error) Logger.error(`[CoverManager] Failed to get files in dir ${dir}`, error)
return [] return []
} }
} }
@ -38,11 +38,11 @@ class CoverController {
removeFile(filepath) { removeFile(filepath) {
try { try {
return fs.pathExists(filepath).then((exists) => { return fs.pathExists(filepath).then((exists) => {
if (!exists) Logger.warn(`[CoverController] Attempting to remove file that does not exist ${filepath}`) if (!exists) Logger.warn(`[CoverManager] Attempting to remove file that does not exist ${filepath}`)
return exists ? fs.unlink(filepath) : false return exists ? fs.unlink(filepath) : false
}) })
} catch (error) { } catch (error) {
Logger.error(`[CoverController] Failed to remove file "${filepath}"`, error) Logger.error(`[CoverManager] Failed to remove file "${filepath}"`, error)
return false return false
} }
} }
@ -57,7 +57,7 @@ class CoverController {
var _filename = Path.basename(file, _extname) var _filename = Path.basename(file, _extname)
if (_filename === 'cover' && _extname !== newCoverExt) { if (_filename === 'cover' && _extname !== newCoverExt) {
var filepath = Path.join(dirpath, file) var filepath = Path.join(dirpath, file)
Logger.debug(`[CoverController] Removing old cover from metadata "${filepath}"`) Logger.debug(`[CoverManager] Removing old cover from metadata "${filepath}"`)
await this.removeFile(filepath) await this.removeFile(filepath)
} }
} }
@ -97,7 +97,7 @@ class CoverController {
// Move cover from temp upload dir to destination // Move cover from temp upload dir to destination
var success = await coverFile.mv(coverFullPath).then(() => true).catch((error) => { var success = await coverFile.mv(coverFullPath).then(() => true).catch((error) => {
Logger.error('[CoverController] Failed to move cover file', path, error) Logger.error('[CoverManager] Failed to move cover file', path, error)
return false return false
}) })
@ -110,7 +110,7 @@ class CoverController {
await this.removeOldCovers(coverDirPath, extname) await this.removeOldCovers(coverDirPath, extname)
await this.cacheManager.purgeCoverCache(libraryItem.id) await this.cacheManager.purgeCoverCache(libraryItem.id)
Logger.info(`[CoverController] Uploaded libraryItem cover "${coverFullPath}" for "${libraryItem.media.metadata.title}"`) Logger.info(`[CoverManager] Uploaded libraryItem cover "${coverFullPath}" for "${libraryItem.media.metadata.title}"`)
libraryItem.updateMediaCover(coverFullPath) libraryItem.updateMediaCover(coverFullPath)
return { return {
@ -125,7 +125,7 @@ class CoverController {
var temppath = Path.posix.join(coverDirPath, 'cover') var temppath = Path.posix.join(coverDirPath, 'cover')
var success = await downloadFile(url, temppath).then(() => true).catch((err) => { var success = await downloadFile(url, temppath).then(() => true).catch((err) => {
Logger.error(`[CoverController] Download image file failed for "${url}"`, err) Logger.error(`[CoverManager] Download image file failed for "${url}"`, err)
return false return false
}) })
if (!success) { if (!success) {
@ -147,14 +147,14 @@ class CoverController {
await this.removeOldCovers(coverDirPath, '.' + imgtype.ext) await this.removeOldCovers(coverDirPath, '.' + imgtype.ext)
await this.cacheManager.purgeCoverCache(libraryItem.id) await this.cacheManager.purgeCoverCache(libraryItem.id)
Logger.info(`[CoverController] Downloaded libraryItem cover "${coverFullPath}" from url "${url}" for "${libraryItem.media.metadata.title}"`) Logger.info(`[CoverManager] Downloaded libraryItem cover "${coverFullPath}" from url "${url}" for "${libraryItem.media.metadata.title}"`)
libraryItem.updateMediaCover(coverFullPath) libraryItem.updateMediaCover(coverFullPath)
return { return {
cover: coverFullPath cover: coverFullPath
} }
} catch (error) { } catch (error) {
Logger.error(`[CoverController] Fetch cover image from url "${url}" failed`, error) Logger.error(`[CoverManager] Fetch cover image from url "${url}" failed`, error)
return { return {
error: 'Failed to fetch image from url' error: 'Failed to fetch image from url'
} }
@ -164,7 +164,7 @@ class CoverController {
async validateCoverPath(coverPath, libraryItem) { async validateCoverPath(coverPath, libraryItem) {
// Invalid cover path // Invalid cover path
if (!coverPath || coverPath.startsWith('http:') || coverPath.startsWith('https:')) { if (!coverPath || coverPath.startsWith('http:') || coverPath.startsWith('https:')) {
Logger.error(`[CoverController] validate cover path invalid http url "${coverPath}"`) Logger.error(`[CoverManager] validate cover path invalid http url "${coverPath}"`)
return { return {
error: 'Invalid cover path' error: 'Invalid cover path'
} }
@ -172,7 +172,7 @@ class CoverController {
coverPath = coverPath.replace(/\\/g, '/') coverPath = coverPath.replace(/\\/g, '/')
// Cover path already set on media // Cover path already set on media
if (libraryItem.media.coverPath == coverPath) { if (libraryItem.media.coverPath == coverPath) {
Logger.debug(`[CoverController] validate cover path already set "${coverPath}"`) Logger.debug(`[CoverManager] validate cover path already set "${coverPath}"`)
return { return {
cover: coverPath, cover: coverPath,
updated: false updated: false
@ -180,7 +180,7 @@ class CoverController {
} }
// Cover path does not exist // Cover path does not exist
if (!await fs.pathExists(coverPath)) { if (!await fs.pathExists(coverPath)) {
Logger.error(`[CoverController] validate cover path does not exist "${coverPath}"`) Logger.error(`[CoverManager] validate cover path does not exist "${coverPath}"`)
return { return {
error: 'Cover path does not exist' error: 'Cover path does not exist'
} }
@ -199,10 +199,10 @@ class CoverController {
var coverFilename = `cover.${imgtype.ext}` var coverFilename = `cover.${imgtype.ext}`
var newCoverPath = Path.posix.join(coverDirPath, coverFilename) var newCoverPath = Path.posix.join(coverDirPath, coverFilename)
Logger.debug(`[CoverController] validate cover path copy cover from "${coverPath}" to "${newCoverPath}"`) Logger.debug(`[CoverManager] validate cover path copy cover from "${coverPath}" to "${newCoverPath}"`)
var copySuccess = await fs.copy(coverPath, newCoverPath, { overwrite: true }).then(() => true).catch((error) => { var copySuccess = await fs.copy(coverPath, newCoverPath, { overwrite: true }).then(() => true).catch((error) => {
Logger.error(`[CoverController] validate cover path failed to copy cover`, error) Logger.error(`[CoverManager] validate cover path failed to copy cover`, error)
return false return false
}) })
if (!copySuccess) { if (!copySuccess) {
@ -212,7 +212,7 @@ class CoverController {
} }
await filePerms.setDefault(newCoverPath) await filePerms.setDefault(newCoverPath)
await this.removeOldCovers(coverDirPath, '.' + imgtype.ext) await this.removeOldCovers(coverDirPath, '.' + imgtype.ext)
Logger.debug(`[CoverController] cover copy success`) Logger.debug(`[CoverManager] cover copy success`)
coverPath = newCoverPath coverPath = newCoverPath
} }
@ -237,7 +237,7 @@ class CoverController {
var coverAlreadyExists = await fs.pathExists(coverFilePath) var coverAlreadyExists = await fs.pathExists(coverFilePath)
if (coverAlreadyExists) { if (coverAlreadyExists) {
Logger.warn(`[CoverController] Extract embedded cover art but cover already exists for "${libraryItem.media.metadata.title}" - bail`) Logger.warn(`[CoverManager] Extract embedded cover art but cover already exists for "${libraryItem.media.metadata.title}" - bail`)
return false return false
} }
@ -249,4 +249,4 @@ class CoverController {
return false return false
} }
} }
module.exports = CoverController module.exports = CoverManager

View File

@ -3,13 +3,14 @@ const fs = require('fs-extra')
const archiver = require('archiver') const archiver = require('archiver')
const workerThreads = require('worker_threads') const workerThreads = require('worker_threads')
const Logger = require('./Logger') const Logger = require('../Logger')
const Download = require('./objects/Download') const Download = require('../objects/Download')
const filePerms = require('./utils/filePerms') const filePerms = require('../utils/filePerms')
const { getId } = require('./utils/index') const { getId } = require('../utils/index')
const { writeConcatFile, writeMetadataFile } = require('./utils/ffmpegHelpers') const { writeConcatFile, writeMetadataFile } = require('../utils/ffmpegHelpers')
const { getFileSize } = require('./utils/fileUtils') const { getFileSize } = require('../utils/fileUtils')
const TAG = 'DownloadManager' const TAG = 'DownloadManager'
class DownloadManager { class DownloadManager {
constructor(db) { constructor(db) {
this.db = db this.db = db

View File

@ -1,9 +1,9 @@
const Path = require('path') const Path = require('path')
const fs = require('fs-extra') const fs = require('fs-extra')
const DailyLog = require('./objects/DailyLog') const DailyLog = require('../objects/DailyLog')
const Logger = require('./Logger') const Logger = require('../Logger')
const TAG = '[LogManager]' const TAG = '[LogManager]'

View File

@ -1,8 +1,8 @@
const Path = require('path') const Path = require('path')
const { PlayMethod } = require('./utils/constants') const { PlayMethod } = require('../utils/constants')
const PlaybackSession = require('./objects/PlaybackSession') const PlaybackSession = require('../objects/PlaybackSession')
const Stream = require('./objects/Stream') const Stream = require('../objects/Stream')
const Logger = require('./Logger') const Logger = require('../Logger')
class PlaybackSessionManager { class PlaybackSessionManager {
constructor(db, emitter, clientEmitter) { constructor(db, emitter, clientEmitter) {

View File

@ -0,0 +1,12 @@
class PodcastManager {
constructor(db) {
this.db = db
this.downloadQueue = []
}
async downloadPodcasts(podcasts, targetDir) {
}
}
module.exports = PodcastManager

View File

@ -26,16 +26,17 @@ const Series = require('../objects/entities/Series')
const FileSystemController = require('../controllers/FileSystemController') const FileSystemController = require('../controllers/FileSystemController')
class ApiRouter { class ApiRouter {
constructor(db, auth, scanner, playbackSessionManager, downloadManager, coverController, backupManager, watcher, cacheManager, emitter, clientEmitter) { constructor(db, auth, scanner, playbackSessionManager, downloadManager, coverManager, backupManager, watcher, cacheManager, podcastManager, emitter, clientEmitter) {
this.db = db this.db = db
this.auth = auth this.auth = auth
this.scanner = scanner this.scanner = scanner
this.playbackSessionManager = playbackSessionManager this.playbackSessionManager = playbackSessionManager
this.downloadManager = downloadManager this.downloadManager = downloadManager
this.backupManager = backupManager this.backupManager = backupManager
this.coverController = coverController this.coverManager = coverManager
this.watcher = watcher this.watcher = watcher
this.cacheManager = cacheManager this.cacheManager = cacheManager
this.podcastManager = podcastManager
this.emitter = emitter this.emitter = emitter
this.clientEmitter = clientEmitter this.clientEmitter = clientEmitter

View File

@ -17,11 +17,11 @@ const Author = require('../objects/entities/Author')
const Series = require('../objects/entities/Series') const Series = require('../objects/entities/Series')
class Scanner { class Scanner {
constructor(db, coverController, emitter) { constructor(db, coverManager, emitter) {
this.ScanLogPath = Path.posix.join(global.MetadataPath, 'logs', 'scans') this.ScanLogPath = Path.posix.join(global.MetadataPath, 'logs', 'scans')
this.db = db this.db = db
this.coverController = coverController this.coverManager = coverManager
this.emitter = emitter this.emitter = emitter
this.cancelLibraryScan = {} this.cancelLibraryScan = {}
@ -84,7 +84,7 @@ class Scanner {
// Extract embedded cover art if cover is not already in directory // Extract embedded cover art if cover is not already in directory
if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
var coverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
if (coverPath) { if (coverPath) {
Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`) Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`)
hasUpdated = true hasUpdated = true
@ -348,7 +348,7 @@ class Scanner {
// If an audio file has embedded cover art and no cover is set yet, extract & use it // If an audio file has embedded cover art and no cover is set yet, extract & use it
if (newAudioFiles.length || libraryScan.scanOptions.forceRescan) { if (newAudioFiles.length || libraryScan.scanOptions.forceRescan) {
if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
var savedCoverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) var savedCoverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
if (savedCoverPath) { if (savedCoverPath) {
hasUpdated = true hasUpdated = true
libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${savedCoverPath}"`) libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${savedCoverPath}"`)
@ -395,7 +395,7 @@ class Scanner {
// Extract embedded cover art if cover is not already in directory // Extract embedded cover art if cover is not already in directory
if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
var coverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
if (coverPath) { if (coverPath) {
if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${coverPath}"`) if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${coverPath}"`)
else Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`) else Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`)
@ -600,7 +600,7 @@ class Scanner {
for (let i = 0; i < results.length && i < 2; i++) { for (let i = 0; i < results.length && i < 2; i++) {
// Downloads and updates the book cover // Downloads and updates the book cover
var result = await this.coverController.downloadCoverFromUrl(libraryItem, results[i]) var result = await this.coverManager.downloadCoverFromUrl(libraryItem, results[i])
if (result.error) { if (result.error) {
Logger.error(`[Scanner] Failed to download cover from url "${results[i]}" | Attempt ${i + 1}`, result.error) Logger.error(`[Scanner] Failed to download cover from url "${results[i]}" | Attempt ${i + 1}`, result.error)
@ -662,7 +662,7 @@ class Scanner {
var hasUpdated = false var hasUpdated = false
if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) { if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) {
Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`) Logger.debug(`[Scanner] Updating cover "${matchData.cover}"`)
var coverResult = await this.coverController.downloadCoverFromUrl(libraryItem, matchData.cover) var coverResult = await this.coverManager.downloadCoverFromUrl(libraryItem, matchData.cover)
if (!coverResult || coverResult.error || !coverResult.cover) { if (!coverResult || coverResult.error || !coverResult.cover) {
Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`) Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`)
} else { } else {