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