mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-04 10:14:36 +02:00
parent
8512d5e693
commit
1dec8ae122
13 changed files with 213 additions and 83 deletions
|
@ -335,7 +335,11 @@ class FolderWatcher extends EventEmitter {
|
|||
if (this.pendingFileUpdates.length) {
|
||||
LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask)
|
||||
} else {
|
||||
this.pendingTask.setFinished('Scan abandoned. No files to scan.')
|
||||
const taskFinishedString = {
|
||||
text: 'No files to scan',
|
||||
key: 'MessageTaskNoFilesToScan'
|
||||
}
|
||||
this.pendingTask.setFinished(taskFinishedString)
|
||||
TaskManager.taskFinished(this.pendingTask)
|
||||
}
|
||||
this.pendingTask = null
|
||||
|
|
|
@ -188,10 +188,11 @@ class AbMergeManager {
|
|||
if (error.message === 'FFMPEG_CANCELED') {
|
||||
Logger.info(`[AbMergeManager] Task cancelled ${task.id}`)
|
||||
} else {
|
||||
Logger.error(`[AbMergeManager] Failed to write metadata to file "${task.data.tempFilepath}"`)
|
||||
Logger.error(`[AbMergeManager] Failed to embed metadata in file "${task.data.tempFilepath}"`)
|
||||
const taskFailedString = {
|
||||
text: 'Failed to write metadata to m4b file',
|
||||
key: 'MessageTaskFailedToWriteMetadataToM4bFile'
|
||||
text: `Failed to embed metadata in file ${Path.basename(task.data.tempFilepath)}`,
|
||||
key: 'MessageTaskFailedToEmbedMetadataInFile',
|
||||
subs: [Path.basename(task.data.tempFilepath)]
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.removeTask(task, true)
|
||||
|
|
|
@ -121,6 +121,10 @@ class AudioMetadataMangaer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('../objects/Task')} task
|
||||
*/
|
||||
async runMetadataEmbed(task) {
|
||||
this.tasksRunning.push(task)
|
||||
TaskManager.addTask(task)
|
||||
|
@ -132,7 +136,11 @@ class AudioMetadataMangaer {
|
|||
Logger.debug(`[AudioMetadataManager] Target directory ${task.data.libraryItemDir} writable: ${targetDirWritable}`)
|
||||
if (!targetDirWritable) {
|
||||
Logger.error(`[AudioMetadataManager] Target directory is not writable: ${task.data.libraryItemDir}`)
|
||||
task.setFailedText('Target directory is not writable')
|
||||
const taskFailedString = {
|
||||
text: 'Target directory is not writable',
|
||||
key: 'MessageTaskTargetDirectoryNotWritable'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
@ -143,7 +151,12 @@ class AudioMetadataMangaer {
|
|||
await fs.access(af.path, fs.constants.W_OK)
|
||||
} catch (err) {
|
||||
Logger.error(`[AudioMetadataManager] Audio file is not writable: ${af.path}`)
|
||||
task.setFailedText(`Audio file "${Path.basename(af.path)}" is not writable`)
|
||||
const taskFailedString = {
|
||||
text: `Audio file "${Path.basename(af.path)}" is not writable`,
|
||||
key: 'MessageTaskAudioFileNotWritable',
|
||||
subs: [Path.basename(af.path)]
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
@ -157,7 +170,11 @@ class AudioMetadataMangaer {
|
|||
cacheDirCreated = true
|
||||
} catch (err) {
|
||||
Logger.error(`[AudioMetadataManager] Failed to create cache directory ${task.data.itemCachePath}`, err)
|
||||
task.setFailedText('Failed to create cache directory')
|
||||
const taskFailedString = {
|
||||
text: 'Failed to create cache directory',
|
||||
key: 'MessageTaskFailedToCreateCacheDirectory'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
@ -168,7 +185,11 @@ class AudioMetadataMangaer {
|
|||
const success = await ffmpegHelpers.writeFFMetadataFile(task.data.metadataObject, task.data.chapters, ffmetadataPath)
|
||||
if (!success) {
|
||||
Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`)
|
||||
task.setFailedText('Failed to write metadata file.')
|
||||
const taskFailedString = {
|
||||
text: 'Failed to write metadata file',
|
||||
key: 'MessageTaskFailedToWriteMetadataFile'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
@ -190,7 +211,12 @@ class AudioMetadataMangaer {
|
|||
Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`)
|
||||
} catch (err) {
|
||||
Logger.error(`[AudioMetadataManager] Failed to backup audio file "${af.path}"`, err)
|
||||
task.setFailedText(`Failed to backup audio file "${Path.basename(af.path)}"`)
|
||||
const taskFailedString = {
|
||||
text: `Failed to backup audio file "${Path.basename(af.path)}"`,
|
||||
key: 'MessageTaskFailedToBackupAudioFile',
|
||||
subs: [Path.basename(af.path)]
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
@ -204,7 +230,12 @@ class AudioMetadataMangaer {
|
|||
Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${af.path}"`)
|
||||
} catch (err) {
|
||||
Logger.error(`[AudioMetadataManager] Failed to tag audio file "${af.path}"`, err)
|
||||
task.setFailedText(`Failed to tag audio file "${Path.basename(af.path)}"`)
|
||||
const taskFailedString = {
|
||||
text: `Failed to embed metadata in file "${Path.basename(af.path)}"`,
|
||||
key: 'MessageTaskFailedToEmbedMetadataInFile',
|
||||
subs: [Path.basename(af.path)]
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.handleTaskFinished(task)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -127,14 +127,22 @@ class PodcastManager {
|
|||
if (!success) {
|
||||
await fs.remove(this.currentDownload.targetPath)
|
||||
this.currentDownload.setFinished(false)
|
||||
task.setFailedText('Failed to download episode')
|
||||
const taskFailedString = {
|
||||
text: 'Failed',
|
||||
key: 'MessageTaskFailed'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
} else {
|
||||
Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`)
|
||||
this.currentDownload.setFinished(true)
|
||||
task.setFinished()
|
||||
}
|
||||
} else {
|
||||
task.setFailedText('Failed to download episode')
|
||||
const taskFailedString = {
|
||||
text: 'Failed',
|
||||
key: 'MessageTaskFailed'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
this.currentDownload.setFinished(false)
|
||||
}
|
||||
|
||||
|
@ -560,7 +568,12 @@ class PodcastManager {
|
|||
|
||||
numPodcastsAdded++
|
||||
}
|
||||
task.setFinished(`Added ${numPodcastsAdded} podcasts`)
|
||||
const taskFinishedString = {
|
||||
text: `Added ${numPodcastsAdded} podcasts`,
|
||||
key: 'MessageTaskOpmlImportFinished',
|
||||
subs: [numPodcastsAdded]
|
||||
}
|
||||
task.setFinished(taskFinishedString)
|
||||
TaskManager.taskFinished(task)
|
||||
Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Finished OPML import. Created ${numPodcastsAdded} podcasts out of ${rssFeedUrls.length} RSS feed URLs`)
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ class TaskManager {
|
|||
createAndEmitFailedTask(action, titleString, descriptionString, errorMessageString) {
|
||||
const task = new Task()
|
||||
task.setData(action, titleString, descriptionString, false)
|
||||
task.setFailedText(errorMessageString)
|
||||
task.setFailed(errorMessageString)
|
||||
SocketAuthority.emitter('task_started', task.toJSON())
|
||||
return task
|
||||
}
|
||||
|
|
|
@ -57,8 +57,14 @@ class Task {
|
|||
action: this.action,
|
||||
data: this.data ? { ...this.data } : {},
|
||||
title: this.title,
|
||||
titleKey: this.titleKey,
|
||||
titleSubs: this.titleSubs,
|
||||
description: this.description,
|
||||
descriptionKey: this.descriptionKey,
|
||||
descriptionSubs: this.descriptionSubs,
|
||||
error: this.error,
|
||||
errorKey: this.errorKey,
|
||||
errorSubs: this.errorSubs,
|
||||
showSuccess: this.showSuccess,
|
||||
isFailed: this.isFailed,
|
||||
isFinished: this.isFinished,
|
||||
|
@ -104,30 +110,19 @@ class Task {
|
|||
this.setFinished()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set task as failed without translation key
|
||||
* TODO: Remove this method after all tasks are using translation keys
|
||||
*
|
||||
* @param {string} message
|
||||
*/
|
||||
setFailedText(message) {
|
||||
this.error = message
|
||||
this.errorKey = null
|
||||
this.errorSubs = null
|
||||
this.isFailed = true
|
||||
this.failedAt = Date.now()
|
||||
this.setFinished()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set task as finished
|
||||
* TODO: Update to use translation keys
|
||||
*
|
||||
* @param {string} [newDescription] update description
|
||||
* @param {TaskString} [newDescriptionString] update description
|
||||
* @param {boolean} [clearDescription] clear description
|
||||
*/
|
||||
setFinished(newDescription = null) {
|
||||
if (newDescription) {
|
||||
this.description = newDescription
|
||||
setFinished(newDescriptionString = null, clearDescription = false) {
|
||||
if (newDescriptionString) {
|
||||
this.description = newDescriptionString.text
|
||||
this.descriptionKey = newDescriptionString.key || null
|
||||
this.descriptionSubs = newDescriptionString.subs || null
|
||||
} else if (clearDescription) {
|
||||
this.description = null
|
||||
this.descriptionKey = null
|
||||
this.descriptionSubs = null
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ class LibraryScan {
|
|||
this.startedAt = null
|
||||
this.finishedAt = null
|
||||
this.elapsed = null
|
||||
this.error = null
|
||||
|
||||
this.resultsMissing = 0
|
||||
this.resultsAdded = 0
|
||||
|
@ -55,22 +54,6 @@ class LibraryScan {
|
|||
get elapsedTimestamp() {
|
||||
return secondsToTimestamp(this.elapsed / 1000)
|
||||
}
|
||||
get getScanEmitData() {
|
||||
return {
|
||||
id: this.libraryId,
|
||||
type: this.type,
|
||||
name: this.libraryName,
|
||||
error: this.error,
|
||||
results: {
|
||||
added: this.resultsAdded,
|
||||
updated: this.resultsUpdated,
|
||||
missing: this.resultsMissing
|
||||
}
|
||||
}
|
||||
}
|
||||
get totalResults() {
|
||||
return this.resultsAdded + this.resultsUpdated + this.resultsMissing
|
||||
}
|
||||
get logFilename() {
|
||||
return date.format(new Date(), 'YYYY-MM-DD') + '_' + this.id + '.txt'
|
||||
}
|
||||
|
@ -79,10 +62,19 @@ class LibraryScan {
|
|||
if (this.resultsAdded) strs.push(`${this.resultsAdded} added`)
|
||||
if (this.resultsUpdated) strs.push(`${this.resultsUpdated} updated`)
|
||||
if (this.resultsMissing) strs.push(`${this.resultsMissing} missing`)
|
||||
const changesDetected = strs.length > 0 ? strs.join(', ') : 'No changes detected'
|
||||
const changesDetected = strs.length > 0 ? strs.join(', ') : 'No changes needed'
|
||||
const timeElapsed = `(${elapsedPretty(this.elapsed / 1000)})`
|
||||
const error = this.error ? `${this.error}. ` : ''
|
||||
return `${error}${changesDetected} ${timeElapsed}`
|
||||
return `${changesDetected} ${timeElapsed}`
|
||||
}
|
||||
|
||||
get scanResults() {
|
||||
return {
|
||||
added: this.resultsAdded,
|
||||
updated: this.resultsUpdated,
|
||||
missing: this.resultsMissing,
|
||||
elapsed: this.elapsed,
|
||||
text: this.scanResultsString
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
|
@ -93,7 +85,6 @@ class LibraryScan {
|
|||
startedAt: this.startedAt,
|
||||
finishedAt: this.finishedAt,
|
||||
elapsed: this.elapsed,
|
||||
error: this.error,
|
||||
resultsAdded: this.resultsAdded,
|
||||
resultsUpdated: this.resultsUpdated,
|
||||
resultsMissing: this.resultsMissing
|
||||
|
@ -113,14 +104,9 @@ class LibraryScan {
|
|||
this.startedAt = Date.now()
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} error
|
||||
*/
|
||||
setComplete(error = null) {
|
||||
setComplete() {
|
||||
this.finishedAt = Date.now()
|
||||
this.elapsed = this.finishedAt - this.startedAt
|
||||
this.error = error
|
||||
}
|
||||
|
||||
getLogLevelString(level) {
|
||||
|
|
|
@ -18,6 +18,7 @@ const Task = require('../objects/Task')
|
|||
class LibraryScanner {
|
||||
constructor() {
|
||||
this.cancelLibraryScan = {}
|
||||
/** @type {string[]} - library ids */
|
||||
this.librariesScanning = []
|
||||
|
||||
this.scanningFilesChanged = false
|
||||
|
@ -30,7 +31,7 @@ class LibraryScanner {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
isLibraryScanning(libraryId) {
|
||||
return this.librariesScanning.some((ls) => ls.id === libraryId)
|
||||
return this.librariesScanning.some((lid) => lid === libraryId)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,8 +39,7 @@ class LibraryScanner {
|
|||
* @param {string} libraryId
|
||||
*/
|
||||
setCancelLibraryScan(libraryId) {
|
||||
const libraryScanning = this.librariesScanning.find((ls) => ls.id === libraryId)
|
||||
if (!libraryScanning) return
|
||||
if (!this.isLibraryScanning(libraryId)) return
|
||||
this.cancelLibraryScan[libraryId] = true
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ class LibraryScanner {
|
|||
const libraryScan = new LibraryScan()
|
||||
libraryScan.setData(library)
|
||||
libraryScan.verbose = true
|
||||
this.librariesScanning.push(libraryScan.getScanEmitData)
|
||||
this.librariesScanning.push(libraryScan.libraryId)
|
||||
|
||||
const taskData = {
|
||||
libraryId: library.id,
|
||||
|
@ -103,17 +103,31 @@ class LibraryScanner {
|
|||
await library.save()
|
||||
}
|
||||
|
||||
task.setFinished(`${canceled ? 'Canceled' : 'Completed'}. ${libraryScan.scanResultsString}`)
|
||||
task.data.scanResults = libraryScan.scanResults
|
||||
if (canceled) {
|
||||
const taskFinishedString = {
|
||||
text: 'Task canceled by user',
|
||||
key: 'MessageTaskCanceledByUser'
|
||||
}
|
||||
task.setFinished(taskFinishedString)
|
||||
} else {
|
||||
task.setFinished(null, true)
|
||||
}
|
||||
} catch (err) {
|
||||
libraryScan.setComplete(err)
|
||||
libraryScan.setComplete()
|
||||
|
||||
Logger.error(`[LibraryScanner] Library scan ${libraryScan.id} failed after ${libraryScan.elapsedTimestamp} | ${libraryScan.resultStats}.`, err)
|
||||
|
||||
task.setFailedText(`Failed. ${libraryScan.scanResultsString}`)
|
||||
task.data.scanResults = libraryScan.scanResults
|
||||
const taskFailedString = {
|
||||
text: 'Failed',
|
||||
key: 'MessageTaskFailed'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
}
|
||||
|
||||
if (this.cancelLibraryScan[libraryScan.libraryId]) delete this.cancelLibraryScan[libraryScan.libraryId]
|
||||
this.librariesScanning = this.librariesScanning.filter((ls) => ls.id !== library.id)
|
||||
this.librariesScanning = this.librariesScanning.filter((lid) => lid !== library.id)
|
||||
|
||||
TaskManager.taskFinished(task)
|
||||
|
||||
|
@ -446,9 +460,15 @@ class LibraryScanner {
|
|||
if (results.added) resultStrs.push(`${results.added} added`)
|
||||
if (results.updated) resultStrs.push(`${results.updated} updated`)
|
||||
if (results.removed) resultStrs.push(`${results.removed} missing`)
|
||||
let scanResultStr = 'Scan finished with no changes'
|
||||
let scanResultStr = 'No changes needed'
|
||||
if (resultStrs.length) scanResultStr = resultStrs.join(', ')
|
||||
pendingTask.setFinished(scanResultStr)
|
||||
|
||||
pendingTask.data.scanResults = {
|
||||
...results,
|
||||
text: scanResultStr,
|
||||
elapsed: Date.now() - pendingTask.startedAt
|
||||
}
|
||||
pendingTask.setFinished(null, true)
|
||||
TaskManager.taskFinished(pendingTask)
|
||||
|
||||
this.scanningFilesChanged = false
|
||||
|
|
|
@ -364,7 +364,7 @@ class Scanner {
|
|||
|
||||
const libraryScan = new LibraryScan()
|
||||
libraryScan.setData(library, 'match')
|
||||
LibraryScanner.librariesScanning.push(libraryScan.getScanEmitData)
|
||||
LibraryScanner.librariesScanning.push(libraryScan.libraryId)
|
||||
const taskData = {
|
||||
libraryId: library.id
|
||||
}
|
||||
|
@ -397,15 +397,29 @@ class Scanner {
|
|||
|
||||
if (offset === 0) {
|
||||
Logger.error(`[Scanner] matchLibraryItems: Library has no items ${library.id}`)
|
||||
libraryScan.setComplete('Library has no items')
|
||||
task.setFailedText(libraryScan.error)
|
||||
libraryScan.setComplete()
|
||||
const taskFailedString = {
|
||||
text: 'No items found',
|
||||
key: 'MessageNoItemsFound'
|
||||
}
|
||||
task.setFailed(taskFailedString)
|
||||
} else {
|
||||
libraryScan.setComplete()
|
||||
task.setFinished(isCanceled ? 'Canceled' : libraryScan.scanResultsString)
|
||||
|
||||
task.data.scanResults = libraryScan.scanResults
|
||||
if (isCanceled) {
|
||||
const taskFinishedString = {
|
||||
text: 'Task canceled by user',
|
||||
key: 'MessageTaskCanceledByUser'
|
||||
}
|
||||
task.setFinished(taskFinishedString)
|
||||
} else {
|
||||
task.setFinished(null, true)
|
||||
}
|
||||
}
|
||||
|
||||
delete LibraryScanner.cancelLibraryScan[libraryScan.libraryId]
|
||||
LibraryScanner.librariesScanning = LibraryScanner.librariesScanning.filter((ls) => ls.id !== library.id)
|
||||
LibraryScanner.librariesScanning = LibraryScanner.librariesScanning.filter((lid) => lid !== library.id)
|
||||
TaskManager.taskFinished(task)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue