diff --git a/server/Server.js b/server/Server.js index 36780df4..f5bb85a0 100644 --- a/server/Server.js +++ b/server/Server.js @@ -31,7 +31,6 @@ const PodcastManager = require('./managers/PodcastManager') const AudioMetadataMangaer = require('./managers/AudioMetadataManager') const RssFeedManager = require('./managers/RssFeedManager') const CronManager = require('./managers/CronManager') -const TaskManager = require('./managers/TaskManager') const LibraryScanner = require('./scanner/LibraryScanner') class Server { @@ -58,15 +57,14 @@ class Server { this.auth = new Auth() // Managers - this.taskManager = new TaskManager() this.notificationManager = new NotificationManager() this.emailManager = new EmailManager() this.backupManager = new BackupManager() this.logManager = new LogManager() - this.abMergeManager = new AbMergeManager(this.taskManager) + this.abMergeManager = new AbMergeManager() this.playbackSessionManager = new PlaybackSessionManager() - this.podcastManager = new PodcastManager(this.watcher, this.notificationManager, this.taskManager) - this.audioMetadataManager = new AudioMetadataMangaer(this.taskManager) + this.podcastManager = new PodcastManager(this.watcher, this.notificationManager) + this.audioMetadataManager = new AudioMetadataMangaer() this.rssFeedManager = new RssFeedManager() this.cronManager = new CronManager(this.podcastManager) diff --git a/server/controllers/MiscController.js b/server/controllers/MiscController.js index 0fa1c62f..ffa4e2c2 100644 --- a/server/controllers/MiscController.js +++ b/server/controllers/MiscController.js @@ -9,6 +9,8 @@ const libraryItemFilters = require('../utils/queries/libraryItemFilters') const patternValidation = require('../libs/nodeCron/pattern-validation') const { isObject, getTitleIgnorePrefix } = require('../utils/index') +const TaskManager = require('../managers/TaskManager') + // // This is a controller for routes that don't have a home yet :( // @@ -102,7 +104,7 @@ class MiscController { const includeArray = (req.query.include || '').split(',') const data = { - tasks: this.taskManager.tasks.map(t => t.toJSON()) + tasks: TaskManager.tasks.map(t => t.toJSON()) } if (includeArray.includes('queue')) { diff --git a/server/managers/AbMergeManager.js b/server/managers/AbMergeManager.js index 4ced1390..8a87df2e 100644 --- a/server/managers/AbMergeManager.js +++ b/server/managers/AbMergeManager.js @@ -4,14 +4,13 @@ const fs = require('../libs/fsExtra') const workerThreads = require('worker_threads') const Logger = require('../Logger') +const TaskManager = require('./TaskManager') const Task = require('../objects/Task') const { writeConcatFile } = require('../utils/ffmpegHelpers') const toneHelpers = require('../utils/toneHelpers') class AbMergeManager { - constructor(taskManager) { - this.taskManager = taskManager - + constructor() { this.itemsCacheDir = Path.join(global.MetadataPath, 'cache/items') this.pendingTasks = [] @@ -45,7 +44,7 @@ class AbMergeManager { } const taskDescription = `Encoding audiobook "${libraryItem.media.metadata.title}" into a single m4b file.` task.setData('encode-m4b', 'Encoding M4b', taskDescription, false, taskData) - this.taskManager.addTask(task) + TaskManager.addTask(task) Logger.info(`Start m4b encode for ${libraryItem.id} - TaskId: ${task.id}`) if (!await fs.pathExists(taskData.itemCachePath)) { @@ -234,7 +233,7 @@ class AbMergeManager { } } - this.taskManager.taskFinished(task) + TaskManager.taskFinished(task) } } module.exports = AbMergeManager diff --git a/server/managers/AudioMetadataManager.js b/server/managers/AudioMetadataManager.js index 2f74bcbe..11c82822 100644 --- a/server/managers/AudioMetadataManager.js +++ b/server/managers/AudioMetadataManager.js @@ -7,12 +7,12 @@ const fs = require('../libs/fsExtra') const toneHelpers = require('../utils/toneHelpers') +const TaskManager = require('./TaskManager') + const Task = require('../objects/Task') class AudioMetadataMangaer { - constructor(taskManager) { - this.taskManager = taskManager - + constructor() { this.itemsCacheDir = Path.join(global.MetadataPath, 'cache/items') this.MAX_CONCURRENT_TASKS = 1 @@ -101,7 +101,7 @@ class AudioMetadataMangaer { async runMetadataEmbed(task) { this.tasksRunning.push(task) - this.taskManager.addTask(task) + TaskManager.addTask(task) Logger.info(`[AudioMetadataManager] Starting metadata embed task`, task.description) @@ -176,7 +176,7 @@ class AudioMetadataMangaer { } handleTaskFinished(task) { - this.taskManager.taskFinished(task) + TaskManager.taskFinished(task) this.tasksRunning = this.tasksRunning.filter(t => t.id !== task.id) if (this.tasksRunning.length < this.MAX_CONCURRENT_TASKS && this.tasksQueued.length) { diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js index b88a38af..7b6ff845 100644 --- a/server/managers/PodcastManager.js +++ b/server/managers/PodcastManager.js @@ -12,6 +12,8 @@ const opmlGenerator = require('../utils/generators/opmlGenerator') const prober = require('../utils/prober') const ffmpegHelpers = require('../utils/ffmpegHelpers') +const TaskManager = require('./TaskManager') + const LibraryFile = require('../objects/files/LibraryFile') const PodcastEpisodeDownload = require('../objects/PodcastEpisodeDownload') const PodcastEpisode = require('../objects/entities/PodcastEpisode') @@ -19,10 +21,9 @@ const AudioFile = require('../objects/files/AudioFile') const Task = require("../objects/Task") class PodcastManager { - constructor(watcher, notificationManager, taskManager) { + constructor(watcher, notificationManager) { this.watcher = watcher this.notificationManager = notificationManager - this.taskManager = taskManager this.downloadQueue = [] this.currentDownload = null @@ -76,7 +77,7 @@ class PodcastManager { libraryItemId: podcastEpisodeDownload.libraryItemId, } task.setData('download-podcast-episode', 'Downloading Episode', taskDescription, false, taskData) - this.taskManager.addTask(task) + TaskManager.addTask(task) SocketAuthority.emitter('episode_download_started', podcastEpisodeDownload.toJSONForClient()) this.currentDownload = podcastEpisodeDownload @@ -128,7 +129,7 @@ class PodcastManager { this.currentDownload.setFinished(false) } - this.taskManager.taskFinished(task) + TaskManager.taskFinished(task) SocketAuthority.emitter('episode_download_finished', this.currentDownload.toJSONForClient()) SocketAuthority.emitter('episode_download_queue_updated', this.getDownloadQueueDetails()) diff --git a/server/managers/TaskManager.js b/server/managers/TaskManager.js index 38e8b580..747ded08 100644 --- a/server/managers/TaskManager.js +++ b/server/managers/TaskManager.js @@ -1,15 +1,27 @@ const SocketAuthority = require('../SocketAuthority') +const Task = require('../objects/Task') class TaskManager { constructor() { + /** @type {Task[]} */ this.tasks = [] } + /** + * Add task and emit socket task_started event + * + * @param {Task} task + */ addTask(task) { this.tasks.push(task) SocketAuthority.emitter('task_started', task.toJSON()) } + /** + * Remove task and emit task_finished event + * + * @param {Task} task + */ taskFinished(task) { if (this.tasks.some(t => t.id === task.id)) { this.tasks = this.tasks.filter(t => t.id !== task.id) @@ -17,4 +29,4 @@ class TaskManager { } } } -module.exports = TaskManager \ No newline at end of file +module.exports = new TaskManager() \ No newline at end of file diff --git a/server/objects/Task.js b/server/objects/Task.js index 04c83d17..db7e490e 100644 --- a/server/objects/Task.js +++ b/server/objects/Task.js @@ -2,19 +2,30 @@ const uuidv4 = require("uuid").v4 class Task { constructor() { + /** @type {string} */ this.id = null + /** @type {string} */ this.action = null // e.g. embed-metadata, encode-m4b, etc + /** @type {Object} custom data */ this.data = null // additional info for the action like libraryItemId + /** @type {string} */ this.title = null + /** @type {string} */ this.description = null + /** @type {string} */ this.error = null - this.showSuccess = false // If true client side should keep the task visible after success + /** @type {boolean} client should keep the task visible after success */ + this.showSuccess = false + /** @type {boolean} */ this.isFailed = false + /** @type {boolean} */ this.isFinished = false + /** @type {number} */ this.startedAt = null + /** @type {number} */ this.finishedAt = null } @@ -34,6 +45,15 @@ class Task { } } + /** + * Set initial task data + * + * @param {string} action + * @param {string} title + * @param {string} description + * @param {boolean} showSuccess + * @param {Object} [data] + */ setData(action, title, description, showSuccess, data = {}) { this.id = uuidv4() this.action = action @@ -44,6 +64,11 @@ class Task { this.startedAt = Date.now() } + /** + * Set task as failed + * + * @param {string} message error message + */ setFailed(message) { this.error = message this.isFailed = true @@ -51,6 +76,11 @@ class Task { this.setFinished() } + /** + * Set task as finished + * + * @param {string} [newDescription] update description + */ setFinished(newDescription = null) { if (newDescription) { this.description = newDescription diff --git a/server/routers/ApiRouter.js b/server/routers/ApiRouter.js index 034951df..b40c3d80 100644 --- a/server/routers/ApiRouter.js +++ b/server/routers/ApiRouter.js @@ -46,7 +46,6 @@ class ApiRouter { this.cronManager = Server.cronManager this.notificationManager = Server.notificationManager this.emailManager = Server.emailManager - this.taskManager = Server.taskManager this.router = express() this.router.disable('x-powered-by')