mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Cleanup scanner
This commit is contained in:
		
							parent
							
								
									591d8a8ab1
								
							
						
					
					
						commit
						0807146aab
					
				@ -107,7 +107,7 @@ class Db {
 | 
			
		||||
  checkPreviousVersion() {
 | 
			
		||||
    return this.settingsDb.select(() => true).then((results) => {
 | 
			
		||||
      if (results.data && results.data.length) {
 | 
			
		||||
        var serverSettings = results.data.find(s => s.id === 'server-settings')
 | 
			
		||||
        const serverSettings = results.data.find(s => s.id === 'server-settings')
 | 
			
		||||
        if (serverSettings && serverSettings.version && serverSettings.version !== version) {
 | 
			
		||||
          return serverSettings.version
 | 
			
		||||
        }
 | 
			
		||||
@ -163,7 +163,7 @@ class Db {
 | 
			
		||||
    const p4 = this.settingsDb.select(() => true).then(async (results) => {
 | 
			
		||||
      if (results.data && results.data.length) {
 | 
			
		||||
        this.settings = results.data
 | 
			
		||||
        var serverSettings = this.settings.find(s => s.id === 'server-settings')
 | 
			
		||||
        const serverSettings = this.settings.find(s => s.id === 'server-settings')
 | 
			
		||||
        if (serverSettings) {
 | 
			
		||||
          this.serverSettings = new ServerSettings(serverSettings)
 | 
			
		||||
 | 
			
		||||
@ -185,7 +185,7 @@ class Db {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var notificationSettings = this.settings.find(s => s.id === 'notification-settings')
 | 
			
		||||
        const notificationSettings = this.settings.find(s => s.id === 'notification-settings')
 | 
			
		||||
        if (notificationSettings) {
 | 
			
		||||
          this.notificationSettings = new NotificationSettings(notificationSettings)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -110,14 +110,14 @@ class MediaFileScanner {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Returns array of { MediaFile, elapsed, averageScanDuration } from audio file scan objects
 | 
			
		||||
  async executeMediaFileScans(libraryItem, mediaLibraryFiles, scanData) {
 | 
			
		||||
  async executeMediaFileScans(libraryItem, mediaLibraryFiles) {
 | 
			
		||||
    const mediaType = libraryItem.mediaType
 | 
			
		||||
 | 
			
		||||
    const scanStart = Date.now()
 | 
			
		||||
    const mediaMetadataFromScan = scanData.media.metadata || null
 | 
			
		||||
    const mediaMetadata = libraryItem.media.metadata || null
 | 
			
		||||
    const proms = []
 | 
			
		||||
    for (let i = 0; i < mediaLibraryFiles.length; i++) {
 | 
			
		||||
      proms.push(this.scan(mediaType, mediaLibraryFiles[i], mediaMetadataFromScan))
 | 
			
		||||
      proms.push(this.scan(mediaType, mediaLibraryFiles[i], mediaMetadata))
 | 
			
		||||
    }
 | 
			
		||||
    const results = await Promise.all(proms).then((scanResults) => scanResults.filter(sr => sr))
 | 
			
		||||
    return {
 | 
			
		||||
@ -206,10 +206,21 @@ class MediaFileScanner {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan = null) {
 | 
			
		||||
  /**
 | 
			
		||||
  * Scans media files for a library item and adds them as audio tracks and sets library item metadata
 | 
			
		||||
  * @async
 | 
			
		||||
  * @param {Array<LibraryFile>} mediaLibraryFiles - Media files for this library item
 | 
			
		||||
  * @param {LibraryItem} libraryItem
 | 
			
		||||
  * @param {LibraryScan} [libraryScan=null] - Optional when doing a library scan to use LibraryScan config/logs
 | 
			
		||||
  * @return {Promise<Boolean>} True if any updates were made
 | 
			
		||||
  */
 | 
			
		||||
  async scanMediaFiles(mediaLibraryFiles, libraryItem, libraryScan = null) {
 | 
			
		||||
    const preferAudioMetadata = libraryScan ? !!libraryScan.preferAudioMetadata : !!global.ServerSettings.scannerPreferAudioMetadata
 | 
			
		||||
    const preferOverdriveMediaMarker = libraryScan ? !!libraryScan.preferOverdriveMediaMarker : !!global.ServerSettings.scannerPreferOverdriveMediaMarker
 | 
			
		||||
 | 
			
		||||
    let hasUpdated = false
 | 
			
		||||
 | 
			
		||||
    const mediaScanResult = await this.executeMediaFileScans(libraryItem, mediaLibraryFiles, scanData)
 | 
			
		||||
    const mediaScanResult = await this.executeMediaFileScans(libraryItem, mediaLibraryFiles)
 | 
			
		||||
 | 
			
		||||
    if (libraryItem.mediaType === 'video') {
 | 
			
		||||
      if (mediaScanResult.videoFiles.length) {
 | 
			
		||||
@ -219,9 +230,9 @@ class MediaFileScanner {
 | 
			
		||||
      }
 | 
			
		||||
    } else if (mediaScanResult.audioFiles.length) {
 | 
			
		||||
      if (libraryScan) {
 | 
			
		||||
        libraryScan.addLog(LogLevel.DEBUG, `Library Item "${scanData.path}" Media file scan took ${mediaScanResult.elapsed}ms for ${mediaScanResult.audioFiles.length} with average time of ${mediaScanResult.averageScanDuration}ms per MB`)
 | 
			
		||||
        libraryScan.addLog(LogLevel.DEBUG, `Library Item "${libraryItem.path}" Media file scan took ${mediaScanResult.elapsed}ms for ${mediaScanResult.audioFiles.length} with average time of ${mediaScanResult.averageScanDuration}ms per MB`)
 | 
			
		||||
      }
 | 
			
		||||
      Logger.debug(`Library Item "${scanData.path}" Media file scan took ${mediaScanResult.elapsed}ms with ${mediaScanResult.audioFiles.length} audio files averaging ${mediaScanResult.averageScanDuration}ms per MB`)
 | 
			
		||||
      Logger.debug(`Library Item "${libraryItem.path}" Media file scan took ${mediaScanResult.elapsed}ms with ${mediaScanResult.audioFiles.length} audio files averaging ${mediaScanResult.averageScanDuration}ms per MB`)
 | 
			
		||||
 | 
			
		||||
      const newAudioFiles = mediaScanResult.audioFiles.filter(af => {
 | 
			
		||||
        return !libraryItem.media.findFileWithInode(af.ino)
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@ class Scanner {
 | 
			
		||||
    // Scan all audio files
 | 
			
		||||
    if (libraryItem.hasAudioFiles) {
 | 
			
		||||
      const libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata, this.db.serverSettings.scannerPreferOverdriveMediaMarker)) {
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItem)) {
 | 
			
		||||
        hasUpdated = true
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -168,7 +168,7 @@ class Scanner {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async scanLibrary(libraryScan) {
 | 
			
		||||
    var libraryItemDataFound = []
 | 
			
		||||
    let libraryItemDataFound = []
 | 
			
		||||
 | 
			
		||||
    // Scan each library
 | 
			
		||||
    for (let i = 0; i < libraryScan.folders.length; i++) {
 | 
			
		||||
@ -182,17 +182,17 @@ class Scanner {
 | 
			
		||||
 | 
			
		||||
    // Remove items with no inode
 | 
			
		||||
    libraryItemDataFound = libraryItemDataFound.filter(lid => lid.ino)
 | 
			
		||||
    var libraryItemsInLibrary = this.db.libraryItems.filter(li => li.libraryId === libraryScan.libraryId)
 | 
			
		||||
    const libraryItemsInLibrary = this.db.libraryItems.filter(li => li.libraryId === libraryScan.libraryId)
 | 
			
		||||
 | 
			
		||||
    const MaxSizePerChunk = 2.5e9
 | 
			
		||||
    const itemDataToRescanChunks = []
 | 
			
		||||
    const newItemDataToScanChunks = []
 | 
			
		||||
    var itemsToUpdate = []
 | 
			
		||||
    var itemDataToRescan = []
 | 
			
		||||
    var itemDataToRescanSize = 0
 | 
			
		||||
    var newItemDataToScan = []
 | 
			
		||||
    var newItemDataToScanSize = 0
 | 
			
		||||
    var itemsToFindCovers = []
 | 
			
		||||
    let itemsToUpdate = []
 | 
			
		||||
    let itemDataToRescan = []
 | 
			
		||||
    let itemDataToRescanSize = 0
 | 
			
		||||
    let newItemDataToScan = []
 | 
			
		||||
    let newItemDataToScanSize = 0
 | 
			
		||||
    const itemsToFindCovers = []
 | 
			
		||||
 | 
			
		||||
    // Check for existing & removed library items
 | 
			
		||||
    for (let i = 0; i < libraryItemsInLibrary.length; i++) {
 | 
			
		||||
@ -323,8 +323,8 @@ class Scanner {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async scanNewLibraryItemDataChunk(newLibraryItemsData, libraryScan) {
 | 
			
		||||
    var newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => {
 | 
			
		||||
      return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan.preferAudioMetadata, libraryScan.preferOpfMetadata, libraryScan.findCovers, libraryScan.preferOverdriveMediaMarker, libraryScan)
 | 
			
		||||
    let newLibraryItems = await Promise.all(newLibraryItemsData.map((lid) => {
 | 
			
		||||
      return this.scanNewLibraryItem(lid, libraryScan.libraryMediaType, libraryScan)
 | 
			
		||||
    }))
 | 
			
		||||
    newLibraryItems = newLibraryItems.filter(li => li) // Filter out nulls
 | 
			
		||||
 | 
			
		||||
@ -341,7 +341,7 @@ class Scanner {
 | 
			
		||||
  async rescanLibraryItem(libraryItemCheckData, libraryScan) {
 | 
			
		||||
    const { newLibraryFiles, filesRemoved, existingLibraryFiles, libraryItem, scanData, updated } = libraryItemCheckData
 | 
			
		||||
    libraryScan.addLog(LogLevel.DEBUG, `Library "${libraryScan.libraryName}" Re-scanning "${libraryItem.path}"`)
 | 
			
		||||
    var hasUpdated = updated
 | 
			
		||||
    let hasUpdated = updated
 | 
			
		||||
 | 
			
		||||
    // Sync other files first to use local images as cover before extracting audio file cover
 | 
			
		||||
    if (await libraryItem.syncFiles(libraryScan.preferOpfMetadata)) {
 | 
			
		||||
@ -349,24 +349,24 @@ class Scanner {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // forceRescan all existing audio files - will probe and update ID3 tag metadata
 | 
			
		||||
    var existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    const existingAudioFiles = existingLibraryFiles.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    if (libraryScan.scanOptions.forceRescan && existingAudioFiles.length) {
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) {
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(existingAudioFiles, libraryItem, libraryScan)) {
 | 
			
		||||
        hasUpdated = true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // Scan new audio files
 | 
			
		||||
    var newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    var removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    const newAudioFiles = newLibraryFiles.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    const removedAudioFiles = filesRemoved.filter(lf => lf.fileType === 'audio')
 | 
			
		||||
    if (newAudioFiles.length || removedAudioFiles.length) {
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(newAudioFiles, scanData, libraryItem, libraryScan.preferAudioMetadata, libraryScan.preferOverdriveMediaMarker, libraryScan)) {
 | 
			
		||||
      if (await MediaFileScanner.scanMediaFiles(newAudioFiles, libraryItem, libraryScan)) {
 | 
			
		||||
        hasUpdated = true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // If an audio file has embedded cover art and no cover is set yet, extract & use it
 | 
			
		||||
    if (newAudioFiles.length || libraryScan.scanOptions.forceRescan) {
 | 
			
		||||
      if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
 | 
			
		||||
        var savedCoverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
 | 
			
		||||
        const savedCoverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
 | 
			
		||||
        if (savedCoverPath) {
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
          libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${savedCoverPath}"`)
 | 
			
		||||
@ -385,7 +385,7 @@ class Scanner {
 | 
			
		||||
 | 
			
		||||
    // Scan for cover if enabled and has no cover (and author or title has changed OR has been 7 days since last lookup)
 | 
			
		||||
    if (libraryScan.findCovers && !libraryItem.media.coverPath && libraryItem.media.shouldSearchForCover) {
 | 
			
		||||
      var updatedCover = await this.searchForCover(libraryItem, libraryScan)
 | 
			
		||||
      const updatedCover = await this.searchForCover(libraryItem, libraryScan)
 | 
			
		||||
      libraryItem.media.updateLastCoverSearch(updatedCover)
 | 
			
		||||
      hasUpdated = true
 | 
			
		||||
    }
 | 
			
		||||
@ -393,16 +393,19 @@ class Scanner {
 | 
			
		||||
    return hasUpdated ? libraryItem : null
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async scanNewLibraryItem(libraryItemData, libraryMediaType, preferAudioMetadata, preferOpfMetadata, findCovers, preferOverdriveMediaMarker, libraryScan = null) {
 | 
			
		||||
  async scanNewLibraryItem(libraryItemData, libraryMediaType, libraryScan = null) {
 | 
			
		||||
    if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Scanning new library item "${libraryItemData.path}"`)
 | 
			
		||||
    else Logger.debug(`[Scanner] Scanning new item "${libraryItemData.path}"`)
 | 
			
		||||
 | 
			
		||||
    const preferOpfMetadata = libraryScan ? !!libraryScan.preferOpfMetadata : !!global.ServerSettings.scannerPreferOpfMetadata
 | 
			
		||||
    const findCovers = libraryScan ? !!libraryScan.findCovers : !!global.ServerSettings.scannerFindCovers
 | 
			
		||||
 | 
			
		||||
    const libraryItem = new LibraryItem()
 | 
			
		||||
    libraryItem.setData(libraryMediaType, libraryItemData)
 | 
			
		||||
 | 
			
		||||
    const mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video')
 | 
			
		||||
    if (mediaFiles.length) {
 | 
			
		||||
      await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan)
 | 
			
		||||
      await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItem, libraryScan)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await libraryItem.syncFiles(preferOpfMetadata)
 | 
			
		||||
@ -638,8 +641,7 @@ class Scanner {
 | 
			
		||||
  async scanPotentialNewLibraryItem(libraryMediaType, folder, fullPath, isSingleMediaItem = false) {
 | 
			
		||||
    const libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, fullPath, isSingleMediaItem, this.db.serverSettings)
 | 
			
		||||
    if (!libraryItemData) return null
 | 
			
		||||
    const serverSettings = this.db.serverSettings
 | 
			
		||||
    return this.scanNewLibraryItem(libraryItemData, libraryMediaType, serverSettings.scannerPreferAudioMetadata, serverSettings.scannerPreferOpfMetadata, serverSettings.scannerFindCovers, serverSettings.scannerPreferOverdriveMediaMarker)
 | 
			
		||||
    return this.scanNewLibraryItem(libraryItemData, libraryMediaType)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async searchForCover(libraryItem, libraryScan = null) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user