mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-11-07 08:34:10 +01:00
parent
8512d5e693
commit
1dec8ae122
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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' : ''}`
|
||||||
}
|
}
|
||||||
|
@ -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!",
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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`)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user