diff --git a/server/Server.js b/server/Server.js index 57b717f6..29e748aa 100644 --- a/server/Server.js +++ b/server/Server.js @@ -17,15 +17,18 @@ const Auth = require('./Auth') const Watcher = require('./Watcher') const Scanner = require('./scanner/Scanner') const Db = require('./Db') -const BackupManager = require('./BackupManager') -const LogManager = require('./LogManager') + const ApiRouter = require('./routers/ApiRouter') const HlsRouter = require('./routers/HlsRouter') const StaticRouter = require('./routers/StaticRouter') -const PlaybackSessionManager = require('./PlaybackSessionManager') -const DownloadManager = require('./DownloadManager') -const CoverController = require('./CoverController') -const CacheManager = require('./CacheManager') + +const CoverManager = require('./managers/CoverManager') +const DownloadManager = require('./managers/DownloadManager') +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 { constructor(PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) { @@ -48,18 +51,22 @@ class Server { fs.ensureDirSync(global.AudiobookPath, 0o774) this.db = new Db() + this.watcher = new Watcher() this.auth = new Auth(this.db) + + // Managers this.backupManager = new BackupManager(this.db, this.emitter.bind(this)) this.logManager = new LogManager(this.db) 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.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 - 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.staticRouter = new StaticRouter(this.db) diff --git a/server/controllers/AuthorController.js b/server/controllers/AuthorController.js index f009144c..0da182ea 100644 --- a/server/controllers/AuthorController.js +++ b/server/controllers/AuthorController.js @@ -16,7 +16,7 @@ class AuthorController { this.cacheManager.purgeImageCache(req.author.id) if (!payload.imagePath) { // If removing image then remove file var currentImagePath = req.author.imagePath - await this.coverController.removeFile(currentImagePath) + await this.coverManager.removeFile(currentImagePath) } } diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 9b015224..75b02bf9 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -68,10 +68,10 @@ class LibraryItemController { var result = null if (req.body && 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) { 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 { 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') } - var validationResult = await this.coverController.validateCoverPath(req.body.cover, libraryItem) + var validationResult = await this.coverManager.validateCoverPath(req.body.cover, libraryItem) if (validationResult.error) { return res.status(500).send(validationResult.error) } diff --git a/server/BackupManager.js b/server/managers/BackupManager.js similarity index 98% rename from server/BackupManager.js rename to server/managers/BackupManager.js index 6093dcdf..5c56fd13 100644 --- a/server/BackupManager.js +++ b/server/managers/BackupManager.js @@ -6,11 +6,11 @@ const archiver = require('archiver') const StreamZip = require('node-stream-zip') // Utils -const { getFileSize } = require('./utils/fileUtils') -const filePerms = require('./utils/filePerms') -const Logger = require('./Logger') +const { getFileSize } = require('../utils/fileUtils') +const filePerms = require('../utils/filePerms') +const Logger = require('../Logger') -const Backup = require('./objects/Backup') +const Backup = require('../objects/Backup') class BackupManager { constructor(db, emitter) { diff --git a/server/CacheManager.js b/server/managers/CacheManager.js similarity index 97% rename from server/CacheManager.js rename to server/managers/CacheManager.js index 1421830b..3de493b5 100644 --- a/server/CacheManager.js +++ b/server/managers/CacheManager.js @@ -1,8 +1,8 @@ const Path = require('path') const fs = require('fs-extra') const stream = require('stream') -const Logger = require('./Logger') -const { resizeImage } = require('./utils/ffmpegHelpers') +const Logger = require('../Logger') +const { resizeImage } = require('../utils/ffmpegHelpers') class CacheManager { constructor() { diff --git a/server/CoverController.js b/server/managers/CoverManager.js similarity index 77% rename from server/CoverController.js rename to server/managers/CoverManager.js index d4ec94b6..d7407d1e 100644 --- a/server/CoverController.js +++ b/server/managers/CoverManager.js @@ -1,16 +1,16 @@ const fs = require('fs-extra') const Path = require('path') const axios = require('axios') -const Logger = require('./Logger') +const Logger = require('../Logger') const readChunk = require('read-chunk') const imageType = require('image-type') -const filePerms = require('./utils/filePerms') +const filePerms = require('../utils/filePerms') -const globals = require('./utils/globals') -const { downloadFile } = require('./utils/fileUtils') -const { extractCoverArt } = require('./utils/ffmpegHelpers') +const globals = require('../utils/globals') +const { downloadFile } = require('../utils/fileUtils') +const { extractCoverArt } = require('../utils/ffmpegHelpers') -class CoverController { +class CoverManager { constructor(db, cacheManager) { this.db = db this.cacheManager = cacheManager @@ -30,7 +30,7 @@ class CoverController { try { return fs.readdir(dir) } 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 [] } } @@ -38,11 +38,11 @@ class CoverController { removeFile(filepath) { try { 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 }) } catch (error) { - Logger.error(`[CoverController] Failed to remove file "${filepath}"`, error) + Logger.error(`[CoverManager] Failed to remove file "${filepath}"`, error) return false } } @@ -57,7 +57,7 @@ class CoverController { var _filename = Path.basename(file, _extname) if (_filename === 'cover' && _extname !== newCoverExt) { 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) } } @@ -97,7 +97,7 @@ class CoverController { // Move cover from temp upload dir to destination 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 }) @@ -110,7 +110,7 @@ class CoverController { await this.removeOldCovers(coverDirPath, extname) 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) return { @@ -125,7 +125,7 @@ class CoverController { var temppath = Path.posix.join(coverDirPath, 'cover') 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 }) if (!success) { @@ -147,14 +147,14 @@ class CoverController { await this.removeOldCovers(coverDirPath, '.' + imgtype.ext) 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) return { cover: coverFullPath } } 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 { error: 'Failed to fetch image from url' } @@ -164,7 +164,7 @@ class CoverController { async validateCoverPath(coverPath, libraryItem) { // Invalid cover path 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 { error: 'Invalid cover path' } @@ -172,7 +172,7 @@ class CoverController { coverPath = coverPath.replace(/\\/g, '/') // Cover path already set on media if (libraryItem.media.coverPath == coverPath) { - Logger.debug(`[CoverController] validate cover path already set "${coverPath}"`) + Logger.debug(`[CoverManager] validate cover path already set "${coverPath}"`) return { cover: coverPath, updated: false @@ -180,7 +180,7 @@ class CoverController { } // Cover path does not exist 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 { error: 'Cover path does not exist' } @@ -199,10 +199,10 @@ class CoverController { var coverFilename = `cover.${imgtype.ext}` 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) => { - Logger.error(`[CoverController] validate cover path failed to copy cover`, error) + Logger.error(`[CoverManager] validate cover path failed to copy cover`, error) return false }) if (!copySuccess) { @@ -212,7 +212,7 @@ class CoverController { } await filePerms.setDefault(newCoverPath) await this.removeOldCovers(coverDirPath, '.' + imgtype.ext) - Logger.debug(`[CoverController] cover copy success`) + Logger.debug(`[CoverManager] cover copy success`) coverPath = newCoverPath } @@ -237,7 +237,7 @@ class CoverController { var coverAlreadyExists = await fs.pathExists(coverFilePath) 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 } @@ -249,4 +249,4 @@ class CoverController { return false } } -module.exports = CoverController \ No newline at end of file +module.exports = CoverManager \ No newline at end of file diff --git a/server/DownloadManager.js b/server/managers/DownloadManager.js similarity index 97% rename from server/DownloadManager.js rename to server/managers/DownloadManager.js index fff84d21..05ae72fd 100644 --- a/server/DownloadManager.js +++ b/server/managers/DownloadManager.js @@ -3,13 +3,14 @@ const fs = require('fs-extra') const archiver = require('archiver') const workerThreads = require('worker_threads') -const Logger = require('./Logger') -const Download = require('./objects/Download') -const filePerms = require('./utils/filePerms') -const { getId } = require('./utils/index') -const { writeConcatFile, writeMetadataFile } = require('./utils/ffmpegHelpers') -const { getFileSize } = require('./utils/fileUtils') +const Logger = require('../Logger') +const Download = require('../objects/Download') +const filePerms = require('../utils/filePerms') +const { getId } = require('../utils/index') +const { writeConcatFile, writeMetadataFile } = require('../utils/ffmpegHelpers') +const { getFileSize } = require('../utils/fileUtils') const TAG = 'DownloadManager' + class DownloadManager { constructor(db) { this.db = db diff --git a/server/LogManager.js b/server/managers/LogManager.js similarity index 97% rename from server/LogManager.js rename to server/managers/LogManager.js index 0b7d6604..0a459a68 100644 --- a/server/LogManager.js +++ b/server/managers/LogManager.js @@ -1,9 +1,9 @@ const Path = require('path') 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]' diff --git a/server/PlaybackSessionManager.js b/server/managers/PlaybackSessionManager.js similarity index 96% rename from server/PlaybackSessionManager.js rename to server/managers/PlaybackSessionManager.js index 3e0190e2..4a3866d9 100644 --- a/server/PlaybackSessionManager.js +++ b/server/managers/PlaybackSessionManager.js @@ -1,8 +1,8 @@ const Path = require('path') -const { PlayMethod } = require('./utils/constants') -const PlaybackSession = require('./objects/PlaybackSession') -const Stream = require('./objects/Stream') -const Logger = require('./Logger') +const { PlayMethod } = require('../utils/constants') +const PlaybackSession = require('../objects/PlaybackSession') +const Stream = require('../objects/Stream') +const Logger = require('../Logger') class PlaybackSessionManager { constructor(db, emitter, clientEmitter) { diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js new file mode 100644 index 00000000..c276c05d --- /dev/null +++ b/server/managers/PodcastManager.js @@ -0,0 +1,12 @@ +class PodcastManager { + constructor(db) { + this.db = db + + this.downloadQueue = [] + } + + async downloadPodcasts(podcasts, targetDir) { + + } +} +module.exports = PodcastManager \ No newline at end of file diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index d3f1a71d..f7261ad3 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -26,16 +26,17 @@ const Series = require('../objects/entities/Series') const FileSystemController = require('../controllers/FileSystemController') 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.auth = auth this.scanner = scanner this.playbackSessionManager = playbackSessionManager this.downloadManager = downloadManager this.backupManager = backupManager - this.coverController = coverController + this.coverManager = coverManager this.watcher = watcher this.cacheManager = cacheManager + this.podcastManager = podcastManager this.emitter = emitter this.clientEmitter = clientEmitter diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 40aa658f..1a1dcbaa 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -17,11 +17,11 @@ const Author = require('../objects/entities/Author') const Series = require('../objects/entities/Series') class Scanner { - constructor(db, coverController, emitter) { + constructor(db, coverManager, emitter) { this.ScanLogPath = Path.posix.join(global.MetadataPath, 'logs', 'scans') this.db = db - this.coverController = coverController + this.coverManager = coverManager this.emitter = emitter this.cancelLibraryScan = {} @@ -84,7 +84,7 @@ class Scanner { // Extract embedded cover art if cover is not already in directory if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { - var coverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) + var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem) if (coverPath) { Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`) 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 (newAudioFiles.length || libraryScan.scanOptions.forceRescan) { if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { - var savedCoverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) + var savedCoverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem) if (savedCoverPath) { hasUpdated = true 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 if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) { - var coverPath = await this.coverController.saveEmbeddedCoverArt(libraryItem) + var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem) if (coverPath) { if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `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++) { // 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) { 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 if (matchData.cover && (!libraryItem.media.coverPath || options.overrideCover)) { 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) { Logger.warn(`[Scanner] Match cover "${matchData.cover}" failed to use: ${coverResult ? coverResult.error : 'Unknown Error'}`) } else {