Update:Added string localization for tasks #3303 #3352

This commit is contained in:
advplyr 2024-09-21 14:02:57 -05:00
parent 8512d5e693
commit 1dec8ae122
13 changed files with 213 additions and 83 deletions

View File

@ -8,6 +8,7 @@
<p class="truncate text-sm">{{ title }}</p> <p class="truncate text-sm">{{ title }}</p>
<p class="truncate text-xs text-gray-300">{{ description }}</p> <p class="truncate text-xs text-gray-300">{{ description }}</p>
<p v-if="specialMessage" class="truncate text-xs text-gray-300">{{ specialMessage }}</p>
<p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p> <p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p>
<p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p> <p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p>
@ -26,7 +27,16 @@ export default {
}, },
data() { data() {
return { return {
cancelingScan: false cancelingScan: false,
specialMessage: ''
}
},
watch: {
task: {
immediate: true,
handler() {
this.initTask()
}
} }
}, },
computed: { computed: {
@ -34,14 +44,17 @@ export default {
return this.$store.getters['user/getIsAdminOrUp'] return this.$store.getters['user/getIsAdminOrUp']
}, },
title() { title() {
if (this.task.titleKey && this.$strings[this.task.titleKey]) {
return this.$getString(this.task.titleKey, this.task.titleSubs)
}
return this.task.title || 'No Title' return this.task.title || 'No Title'
}, },
description() { description() {
if (this.task.descriptionKey && this.$strings[this.task.descriptionKey]) {
return this.$getString(this.task.descriptionKey, this.task.descriptionSubs)
}
return this.task.description || '' return this.task.description || ''
}, },
details() {
return this.task.details || 'Unknown'
},
isFinished() { isFinished() {
return !!this.task.isFinished return !!this.task.isFinished
}, },
@ -52,6 +65,9 @@ export default {
return this.isFinished && !this.isFailed return this.isFinished && !this.isFailed
}, },
failedMessage() { failedMessage() {
if (this.task.errorKey && this.$strings[this.task.errorKey]) {
return this.$getString(this.task.errorKey, this.task.errorSubs)
}
return this.task.error || '' return this.task.error || ''
}, },
action() { action() {
@ -87,6 +103,21 @@ export default {
} }
}, },
methods: { methods: {
initTask() {
// special message for library scan tasks
if (this.task?.data?.scanResults) {
const scanResults = this.task.data.scanResults
const strs = []
if (scanResults.added) strs.push(this.$getString('MessageTaskScanItemsAdded', [scanResults.added]))
if (scanResults.updated) strs.push(this.$getString('MessageTaskScanItemsUpdated', [scanResults.updated]))
if (scanResults.missing) strs.push(this.$getString('MessageTaskScanItemsMissing', [scanResults.missing]))
const changesDetected = strs.length > 0 ? strs.join(', ') : this.$strings.MessageTaskScanNoChangesNeeded
const timeElapsed = scanResults.elapsed ? ` (${this.$elapsedPretty(scanResults.elapsed / 1000, false, true)})` : ''
this.specialMessage = `${changesDetected}${timeElapsed}`
} else {
this.specialMessage = ''
}
},
cancelScan() { cancelScan() {
const libraryId = this.task?.data?.libraryId const libraryId = this.task?.data?.libraryId
if (!libraryId) { if (!libraryId) {

View File

@ -89,10 +89,10 @@ Vue.prototype.$strings = { ...enUsStrings }
* Get string and substitute * Get string and substitute
* *
* @param {string} key * @param {string} key
* @param {string[]} subs * @param {string[]} [subs=[]]
* @returns {string} * @returns {string}
*/ */
Vue.prototype.$getString = (key, subs) => { Vue.prototype.$getString = (key, subs = []) => {
if (!Vue.prototype.$strings[key]) return '' if (!Vue.prototype.$strings[key]) return ''
if (subs?.length && Array.isArray(subs)) { if (subs?.length && Array.isArray(subs)) {
return supplant(Vue.prototype.$strings[key], subs) return supplant(Vue.prototype.$strings[key], subs)

View File

@ -18,7 +18,10 @@ Vue.prototype.$bytesPretty = (bytes, decimals = 2) => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i] return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
} }
Vue.prototype.$elapsedPretty = (seconds, useFullNames = false) => { Vue.prototype.$elapsedPretty = (seconds, useFullNames = false, useMilliseconds = false) => {
if (useMilliseconds && seconds > 0 && seconds < 1) {
return `${Math.floor(seconds * 1000)} ms`
}
if (seconds < 60) { if (seconds < 60) {
return `${Math.floor(seconds)} sec${useFullNames ? 'onds' : ''}` return `${Math.floor(seconds)} sec${useFullNames ? 'onds' : ''}`
} }

View File

@ -777,6 +777,38 @@
"MessageShareExpiresIn": "Expires in {0}", "MessageShareExpiresIn": "Expires in {0}",
"MessageShareURLWillBe": "Share URL will be <strong>{0}</strong>", "MessageShareURLWillBe": "Share URL will be <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?", "MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?",
"MessageTaskAudioFileNotWritable": "Audio file \"{0}\" is not writable",
"MessageTaskCanceledByUser": "Task canceled by user",
"MessageTaskDownloadingEpisodeDescription": "Downloading episode \"{0}\"",
"MessageTaskEmbeddingMetadata": "Embedding metadata",
"MessageTaskEmbeddingMetadataDescription": "Embedding metadata in audiobook \"{0}\"",
"MessageTaskEncodingM4b": "Encoding M4B",
"MessageTaskEncodingM4bDescription": "Encoding audiobook \"{0}\" into a single m4b file",
"MessageTaskFailed": "Failed",
"MessageTaskFailedToBackupAudioFile": "Failed to backup audio file \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "Failed to create cache directory",
"MessageTaskFailedToEmbedMetadataInFile": "Failed to embed metadata in file \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Failed to merge audio files",
"MessageTaskFailedToMoveM4bFile": "Failed to move m4b file",
"MessageTaskFailedToWriteMetadataFile": "Failed to write metadata file",
"MessageTaskMatchingBooksInLibrary": "Matching books in library \"{0}\"",
"MessageTaskNoFilesToScan": "No files to scan",
"MessageTaskOpmlImport": "OPML import",
"MessageTaskOpmlImportDescription": "Creating podcasts from {0} RSS feeds",
"MessageTaskOpmlImportFeed": "OPML import feed",
"MessageTaskOpmlImportFeedDescription": "Importing RSS feed \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Failed to get podcast feed",
"MessageTaskOpmlImportFeedPodcastDescription": "Creating podcast \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast already exists at path",
"MessageTaskOpmlImportFeedPodcastFailed": "Failed to create podcast",
"MessageTaskOpmlImportFinished": "Added {0} podcasts",
"MessageTaskScanItemsAdded": "{0} added",
"MessageTaskScanItemsMissing": "{0} missing",
"MessageTaskScanItemsUpdated": "{0} updated",
"MessageTaskScanNoChangesNeeded": "No changes needed",
"MessageTaskScanningFileChanges": "Scanning file changes in \"{0}\"",
"MessageTaskScanningLibrary": "Scanning \"{0}\" library",
"MessageTaskTargetDirectoryNotWritable": "Target directory is not writable",
"MessageThinking": "Thinking...", "MessageThinking": "Thinking...",
"MessageUploaderItemFailed": "Failed to upload", "MessageUploaderItemFailed": "Failed to upload",
"MessageUploaderItemSuccess": "Successfully Uploaded!", "MessageUploaderItemSuccess": "Successfully Uploaded!",

View File

@ -335,7 +335,11 @@ class FolderWatcher extends EventEmitter {
if (this.pendingFileUpdates.length) { if (this.pendingFileUpdates.length) {
LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask) LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask)
} else { } 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) TaskManager.taskFinished(this.pendingTask)
} }
this.pendingTask = null this.pendingTask = null

View File

@ -188,10 +188,11 @@ class AbMergeManager {
if (error.message === 'FFMPEG_CANCELED') { if (error.message === 'FFMPEG_CANCELED') {
Logger.info(`[AbMergeManager] Task cancelled ${task.id}`) Logger.info(`[AbMergeManager] Task cancelled ${task.id}`)
} else { } 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 = { const taskFailedString = {
text: 'Failed to write metadata to m4b file', text: `Failed to embed metadata in file ${Path.basename(task.data.tempFilepath)}`,
key: 'MessageTaskFailedToWriteMetadataToM4bFile' key: 'MessageTaskFailedToEmbedMetadataInFile',
subs: [Path.basename(task.data.tempFilepath)]
} }
task.setFailed(taskFailedString) task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)

View File

@ -121,6 +121,10 @@ class AudioMetadataMangaer {
} }
} }
/**
*
* @param {import('../objects/Task')} task
*/
async runMetadataEmbed(task) { async runMetadataEmbed(task) {
this.tasksRunning.push(task) this.tasksRunning.push(task)
TaskManager.addTask(task) TaskManager.addTask(task)
@ -132,7 +136,11 @@ class AudioMetadataMangaer {
Logger.debug(`[AudioMetadataManager] Target directory ${task.data.libraryItemDir} writable: ${targetDirWritable}`) Logger.debug(`[AudioMetadataManager] Target directory ${task.data.libraryItemDir} writable: ${targetDirWritable}`)
if (!targetDirWritable) { if (!targetDirWritable) {
Logger.error(`[AudioMetadataManager] Target directory is not writable: ${task.data.libraryItemDir}`) 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) this.handleTaskFinished(task)
return return
} }
@ -143,7 +151,12 @@ class AudioMetadataMangaer {
await fs.access(af.path, fs.constants.W_OK) await fs.access(af.path, fs.constants.W_OK)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Audio file is not writable: ${af.path}`) 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) this.handleTaskFinished(task)
return return
} }
@ -157,7 +170,11 @@ class AudioMetadataMangaer {
cacheDirCreated = true cacheDirCreated = true
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to create cache directory ${task.data.itemCachePath}`, 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) this.handleTaskFinished(task)
return return
} }
@ -168,7 +185,11 @@ class AudioMetadataMangaer {
const success = await ffmpegHelpers.writeFFMetadataFile(task.data.metadataObject, task.data.chapters, ffmetadataPath) const success = await ffmpegHelpers.writeFFMetadataFile(task.data.metadataObject, task.data.chapters, ffmetadataPath)
if (!success) { if (!success) {
Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`) 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) this.handleTaskFinished(task)
return return
} }
@ -190,7 +211,12 @@ class AudioMetadataMangaer {
Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`) Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to backup audio file "${af.path}"`, 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) this.handleTaskFinished(task)
return return
} }
@ -204,7 +230,12 @@ class AudioMetadataMangaer {
Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${af.path}"`) Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${af.path}"`)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to tag audio file "${af.path}"`, 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) this.handleTaskFinished(task)
return return
} }

View File

@ -127,14 +127,22 @@ class PodcastManager {
if (!success) { if (!success) {
await fs.remove(this.currentDownload.targetPath) await fs.remove(this.currentDownload.targetPath)
this.currentDownload.setFinished(false) this.currentDownload.setFinished(false)
task.setFailedText('Failed to download episode') const taskFailedString = {
text: 'Failed',
key: 'MessageTaskFailed'
}
task.setFailed(taskFailedString)
} else { } else {
Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`) Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`)
this.currentDownload.setFinished(true) this.currentDownload.setFinished(true)
task.setFinished() task.setFinished()
} }
} else { } else {
task.setFailedText('Failed to download episode') const taskFailedString = {
text: 'Failed',
key: 'MessageTaskFailed'
}
task.setFailed(taskFailedString)
this.currentDownload.setFinished(false) this.currentDownload.setFinished(false)
} }
@ -560,7 +568,12 @@ class PodcastManager {
numPodcastsAdded++ numPodcastsAdded++
} }
task.setFinished(`Added ${numPodcastsAdded} podcasts`) const taskFinishedString = {
text: `Added ${numPodcastsAdded} podcasts`,
key: 'MessageTaskOpmlImportFinished',
subs: [numPodcastsAdded]
}
task.setFinished(taskFinishedString)
TaskManager.taskFinished(task) TaskManager.taskFinished(task)
Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Finished OPML import. Created ${numPodcastsAdded} podcasts out of ${rssFeedUrls.length} RSS feed URLs`) Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Finished OPML import. Created ${numPodcastsAdded} podcasts out of ${rssFeedUrls.length} RSS feed URLs`)
} }

View File

@ -63,7 +63,7 @@ class TaskManager {
createAndEmitFailedTask(action, titleString, descriptionString, errorMessageString) { createAndEmitFailedTask(action, titleString, descriptionString, errorMessageString) {
const task = new Task() const task = new Task()
task.setData(action, titleString, descriptionString, false) task.setData(action, titleString, descriptionString, false)
task.setFailedText(errorMessageString) task.setFailed(errorMessageString)
SocketAuthority.emitter('task_started', task.toJSON()) SocketAuthority.emitter('task_started', task.toJSON())
return task return task
} }

View File

@ -57,8 +57,14 @@ class Task {
action: this.action, action: this.action,
data: this.data ? { ...this.data } : {}, data: this.data ? { ...this.data } : {},
title: this.title, title: this.title,
titleKey: this.titleKey,
titleSubs: this.titleSubs,
description: this.description, description: this.description,
descriptionKey: this.descriptionKey,
descriptionSubs: this.descriptionSubs,
error: this.error, error: this.error,
errorKey: this.errorKey,
errorSubs: this.errorSubs,
showSuccess: this.showSuccess, showSuccess: this.showSuccess,
isFailed: this.isFailed, isFailed: this.isFailed,
isFinished: this.isFinished, isFinished: this.isFinished,
@ -104,30 +110,19 @@ class Task {
this.setFinished() 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 * 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) { setFinished(newDescriptionString = null, clearDescription = false) {
if (newDescription) { if (newDescriptionString) {
this.description = newDescription this.description = newDescriptionString.text
this.descriptionKey = newDescriptionString.key || null
this.descriptionSubs = newDescriptionString.subs || null
} else if (clearDescription) {
this.description = null
this.descriptionKey = null this.descriptionKey = null
this.descriptionSubs = null this.descriptionSubs = null
} }

View File

@ -18,7 +18,6 @@ class LibraryScan {
this.startedAt = null this.startedAt = null
this.finishedAt = null this.finishedAt = null
this.elapsed = null this.elapsed = null
this.error = null
this.resultsMissing = 0 this.resultsMissing = 0
this.resultsAdded = 0 this.resultsAdded = 0
@ -55,22 +54,6 @@ class LibraryScan {
get elapsedTimestamp() { get elapsedTimestamp() {
return secondsToTimestamp(this.elapsed / 1000) 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() { get logFilename() {
return date.format(new Date(), 'YYYY-MM-DD') + '_' + this.id + '.txt' 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.resultsAdded) strs.push(`${this.resultsAdded} added`)
if (this.resultsUpdated) strs.push(`${this.resultsUpdated} updated`) if (this.resultsUpdated) strs.push(`${this.resultsUpdated} updated`)
if (this.resultsMissing) strs.push(`${this.resultsMissing} missing`) 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 timeElapsed = `(${elapsedPretty(this.elapsed / 1000)})`
const error = this.error ? `${this.error}. ` : '' return `${changesDetected} ${timeElapsed}`
return `${error}${changesDetected} ${timeElapsed}` }
get scanResults() {
return {
added: this.resultsAdded,
updated: this.resultsUpdated,
missing: this.resultsMissing,
elapsed: this.elapsed,
text: this.scanResultsString
}
} }
toJSON() { toJSON() {
@ -93,7 +85,6 @@ class LibraryScan {
startedAt: this.startedAt, startedAt: this.startedAt,
finishedAt: this.finishedAt, finishedAt: this.finishedAt,
elapsed: this.elapsed, elapsed: this.elapsed,
error: this.error,
resultsAdded: this.resultsAdded, resultsAdded: this.resultsAdded,
resultsUpdated: this.resultsUpdated, resultsUpdated: this.resultsUpdated,
resultsMissing: this.resultsMissing resultsMissing: this.resultsMissing
@ -113,14 +104,9 @@ class LibraryScan {
this.startedAt = Date.now() this.startedAt = Date.now()
} }
/** setComplete() {
*
* @param {string} error
*/
setComplete(error = null) {
this.finishedAt = Date.now() this.finishedAt = Date.now()
this.elapsed = this.finishedAt - this.startedAt this.elapsed = this.finishedAt - this.startedAt
this.error = error
} }
getLogLevelString(level) { getLogLevelString(level) {

View File

@ -18,6 +18,7 @@ const Task = require('../objects/Task')
class LibraryScanner { class LibraryScanner {
constructor() { constructor() {
this.cancelLibraryScan = {} this.cancelLibraryScan = {}
/** @type {string[]} - library ids */
this.librariesScanning = [] this.librariesScanning = []
this.scanningFilesChanged = false this.scanningFilesChanged = false
@ -30,7 +31,7 @@ class LibraryScanner {
* @returns {boolean} * @returns {boolean}
*/ */
isLibraryScanning(libraryId) { 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 * @param {string} libraryId
*/ */
setCancelLibraryScan(libraryId) { setCancelLibraryScan(libraryId) {
const libraryScanning = this.librariesScanning.find((ls) => ls.id === libraryId) if (!this.isLibraryScanning(libraryId)) return
if (!libraryScanning) return
this.cancelLibraryScan[libraryId] = true this.cancelLibraryScan[libraryId] = true
} }
@ -69,7 +69,7 @@ class LibraryScanner {
const libraryScan = new LibraryScan() const libraryScan = new LibraryScan()
libraryScan.setData(library) libraryScan.setData(library)
libraryScan.verbose = true libraryScan.verbose = true
this.librariesScanning.push(libraryScan.getScanEmitData) this.librariesScanning.push(libraryScan.libraryId)
const taskData = { const taskData = {
libraryId: library.id, libraryId: library.id,
@ -103,17 +103,31 @@ class LibraryScanner {
await library.save() 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) { } catch (err) {
libraryScan.setComplete(err) libraryScan.setComplete()
Logger.error(`[LibraryScanner] Library scan ${libraryScan.id} failed after ${libraryScan.elapsedTimestamp} | ${libraryScan.resultStats}.`, err) 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] 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) TaskManager.taskFinished(task)
@ -446,9 +460,15 @@ class LibraryScanner {
if (results.added) resultStrs.push(`${results.added} added`) if (results.added) resultStrs.push(`${results.added} added`)
if (results.updated) resultStrs.push(`${results.updated} updated`) if (results.updated) resultStrs.push(`${results.updated} updated`)
if (results.removed) resultStrs.push(`${results.removed} missing`) 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(', ') 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) TaskManager.taskFinished(pendingTask)
this.scanningFilesChanged = false this.scanningFilesChanged = false

View File

@ -364,7 +364,7 @@ class Scanner {
const libraryScan = new LibraryScan() const libraryScan = new LibraryScan()
libraryScan.setData(library, 'match') libraryScan.setData(library, 'match')
LibraryScanner.librariesScanning.push(libraryScan.getScanEmitData) LibraryScanner.librariesScanning.push(libraryScan.libraryId)
const taskData = { const taskData = {
libraryId: library.id libraryId: library.id
} }
@ -397,15 +397,29 @@ class Scanner {
if (offset === 0) { if (offset === 0) {
Logger.error(`[Scanner] matchLibraryItems: Library has no items ${library.id}`) Logger.error(`[Scanner] matchLibraryItems: Library has no items ${library.id}`)
libraryScan.setComplete('Library has no items') libraryScan.setComplete()
task.setFailedText(libraryScan.error) const taskFailedString = {
text: 'No items found',
key: 'MessageNoItemsFound'
}
task.setFailed(taskFailedString)
} else { } else {
libraryScan.setComplete() 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] 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) TaskManager.taskFinished(task)
} }
} }