mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Fix:Podcast episodes duplicated when a scan runs while the episode is downloading #2785
This commit is contained in:
		
							parent
							
								
									a5ebd89817
								
							
						
					
					
						commit
						850ed48955
					
				| @ -149,6 +149,9 @@ class Server { | |||||||
|       Watcher.disabled = true |       Watcher.disabled = true | ||||||
|     } else { |     } else { | ||||||
|       Watcher.initWatcher(libraries) |       Watcher.initWatcher(libraries) | ||||||
|  |       Watcher.on('scanFilesChanged', (pendingFileUpdates, pendingTask) => { | ||||||
|  |         LibraryScanner.scanFilesChanged(pendingFileUpdates, pendingTask) | ||||||
|  |       }) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ const Path = require('path') | |||||||
| const EventEmitter = require('events') | const EventEmitter = require('events') | ||||||
| const Watcher = require('./libs/watcher/watcher') | const Watcher = require('./libs/watcher/watcher') | ||||||
| const Logger = require('./Logger') | const Logger = require('./Logger') | ||||||
| const LibraryScanner = require('./scanner/LibraryScanner') |  | ||||||
| const Task = require('./objects/Task') | const Task = require('./objects/Task') | ||||||
| const TaskManager = require('./managers/TaskManager') | const TaskManager = require('./managers/TaskManager') | ||||||
| 
 | 
 | ||||||
| @ -31,6 +30,8 @@ class FolderWatcher extends EventEmitter { | |||||||
| 
 | 
 | ||||||
|     this.filesBeingAdded = new Set() |     this.filesBeingAdded = new Set() | ||||||
| 
 | 
 | ||||||
|  |     /** @type {Set<string>} */ | ||||||
|  |     this.ignoreFilePathsDownloading = new Set() | ||||||
|     /** @type {string[]} */ |     /** @type {string[]} */ | ||||||
|     this.ignoreDirs = [] |     this.ignoreDirs = [] | ||||||
|     /** @type {string[]} */ |     /** @type {string[]} */ | ||||||
| @ -333,7 +334,7 @@ class FolderWatcher extends EventEmitter { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       if (this.pendingFileUpdates.length) { |       if (this.pendingFileUpdates.length) { | ||||||
|         LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask) |         this.emit('scanFilesChanged', this.pendingFileUpdates, this.pendingTask) | ||||||
|       } else { |       } else { | ||||||
|         const taskFinishedString = { |         const taskFinishedString = { | ||||||
|           text: 'No files to scan', |           text: 'No files to scan', | ||||||
| @ -348,12 +349,29 @@ class FolderWatcher extends EventEmitter { | |||||||
|     }, this.pendingDelay) |     }, this.pendingDelay) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * | ||||||
|  |    * @param {string} path | ||||||
|  |    * @returns {boolean} | ||||||
|  |    */ | ||||||
|   checkShouldIgnorePath(path) { |   checkShouldIgnorePath(path) { | ||||||
|     return !!this.ignoreDirs.find((dirpath) => { |     return !!this.ignoreDirs.find((dirpath) => { | ||||||
|       return isSameOrSubPath(dirpath, path) |       return isSameOrSubPath(dirpath, path) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** | ||||||
|  |    * When scanning a library item folder these files should be ignored | ||||||
|  |    * Either a podcast episode downloading or a file that is pending by the watcher | ||||||
|  |    * | ||||||
|  |    * @param {string} path | ||||||
|  |    * @returns {boolean} | ||||||
|  |    */ | ||||||
|  |   checkShouldIgnoreFilePath(path) { | ||||||
|  |     if (this.pendingFilePaths.includes(path)) return true | ||||||
|  |     return this.ignoreFilePathsDownloading.has(path) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   /** |   /** | ||||||
|    * Convert to POSIX and remove trailing slash |    * Convert to POSIX and remove trailing slash | ||||||
|    * @param {string} path |    * @param {string} path | ||||||
|  | |||||||
| @ -97,6 +97,7 @@ class PodcastManager { | |||||||
| 
 | 
 | ||||||
|     // Ignores all added files to this dir
 |     // Ignores all added files to this dir
 | ||||||
|     Watcher.addIgnoreDir(this.currentDownload.libraryItem.path) |     Watcher.addIgnoreDir(this.currentDownload.libraryItem.path) | ||||||
|  |     Watcher.ignoreFilePathsDownloading.add(this.currentDownload.targetPath) | ||||||
| 
 | 
 | ||||||
|     // Make sure podcast library item folder exists
 |     // Make sure podcast library item folder exists
 | ||||||
|     if (!(await fs.pathExists(this.currentDownload.libraryItem.path))) { |     if (!(await fs.pathExists(this.currentDownload.libraryItem.path))) { | ||||||
| @ -151,6 +152,8 @@ class PodcastManager { | |||||||
|     SocketAuthority.emitter('episode_download_queue_updated', this.getDownloadQueueDetails()) |     SocketAuthority.emitter('episode_download_queue_updated', this.getDownloadQueueDetails()) | ||||||
| 
 | 
 | ||||||
|     Watcher.removeIgnoreDir(this.currentDownload.libraryItem.path) |     Watcher.removeIgnoreDir(this.currentDownload.libraryItem.path) | ||||||
|  | 
 | ||||||
|  |     Watcher.ignoreFilePathsDownloading.delete(this.currentDownload.targetPath) | ||||||
|     this.currentDownload = null |     this.currentDownload = null | ||||||
|     if (this.downloadQueue.length) { |     if (this.downloadQueue.length) { | ||||||
|       this.startPodcastEpisodeDownload(this.downloadQueue.shift()) |       this.startPodcastEpisodeDownload(this.downloadQueue.shift()) | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| const Path = require('path') | const Path = require('path') | ||||||
| const uuidv4 = require("uuid").v4 | const uuidv4 = require('uuid').v4 | ||||||
| const { sanitizeFilename } = require('../utils/fileUtils') | const { sanitizeFilename, filePathToPOSIX } = require('../utils/fileUtils') | ||||||
| const globals = require('../utils/globals') | const globals = require('../utils/globals') | ||||||
| 
 | 
 | ||||||
| class PodcastEpisodeDownload { | class PodcastEpisodeDownload { | ||||||
| @ -60,7 +60,7 @@ class PodcastEpisodeDownload { | |||||||
|     return sanitizeFilename(filename) |     return sanitizeFilename(filename) | ||||||
|   } |   } | ||||||
|   get targetPath() { |   get targetPath() { | ||||||
|     return Path.join(this.libraryItem.path, this.targetFilename) |     return filePathToPOSIX(Path.join(this.libraryItem.path, this.targetFilename)) | ||||||
|   } |   } | ||||||
|   get targetRelPath() { |   get targetRelPath() { | ||||||
|     return this.targetFilename |     return this.targetFilename | ||||||
| @ -74,7 +74,8 @@ class PodcastEpisodeDownload { | |||||||
|     this.podcastEpisode = podcastEpisode |     this.podcastEpisode = podcastEpisode | ||||||
| 
 | 
 | ||||||
|     const url = podcastEpisode.enclosure.url |     const url = podcastEpisode.enclosure.url | ||||||
|     if (decodeURIComponent(url) !== url) { // Already encoded
 |     if (decodeURIComponent(url) !== url) { | ||||||
|  |       // Already encoded
 | ||||||
|       this.url = url |       this.url = url | ||||||
|     } else { |     } else { | ||||||
|       this.url = encodeURI(url) |       this.url = encodeURI(url) | ||||||
|  | |||||||
| @ -4,7 +4,9 @@ const { LogLevel, ScanResult } = require('../utils/constants') | |||||||
| const fileUtils = require('../utils/fileUtils') | const fileUtils = require('../utils/fileUtils') | ||||||
| const scanUtils = require('../utils/scandir') | const scanUtils = require('../utils/scandir') | ||||||
| const libraryFilters = require('../utils/queries/libraryFilters') | const libraryFilters = require('../utils/queries/libraryFilters') | ||||||
|  | const Logger = require('../Logger') | ||||||
| const Database = require('../Database') | const Database = require('../Database') | ||||||
|  | const Watcher = require('../Watcher') | ||||||
| const LibraryScan = require('./LibraryScan') | const LibraryScan = require('./LibraryScan') | ||||||
| const LibraryItemScanData = require('./LibraryItemScanData') | const LibraryItemScanData = require('./LibraryItemScanData') | ||||||
| const BookScanner = require('./BookScanner') | const BookScanner = require('./BookScanner') | ||||||
| @ -128,6 +130,13 @@ class LibraryItemScanner { | |||||||
|     const libraryFiles = [] |     const libraryFiles = [] | ||||||
|     for (let i = 0; i < fileItems.length; i++) { |     for (let i = 0; i < fileItems.length; i++) { | ||||||
|       const fileItem = fileItems[i] |       const fileItem = fileItems[i] | ||||||
|  | 
 | ||||||
|  |       if (Watcher.checkShouldIgnoreFilePath(fileItem.fullpath)) { | ||||||
|  |         // Skip file if it's pending
 | ||||||
|  |         Logger.info(`[LibraryItemScanner] Skipping watcher pending file "${fileItem.fullpath}" during scan of library item path "${libraryItemPath}"`) | ||||||
|  |         continue | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       const newLibraryFile = new LibraryFile() |       const newLibraryFile = new LibraryFile() | ||||||
|       // fileItem.path is the relative path
 |       // fileItem.path is the relative path
 | ||||||
|       await newLibraryFile.setDataFromPath(fileItem.fullpath, fileItem.path) |       await newLibraryFile.setDataFromPath(fileItem.fullpath, fileItem.path) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user