mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-01-04 01:59:36 +00:00
Merge branch 'master' into socket-fixes
This commit is contained in:
commit
33e183b802
18 changed files with 491 additions and 134 deletions
|
|
@ -57,9 +57,9 @@ class MediaFileScanner {
|
|||
}
|
||||
|
||||
async scan(mediaType, libraryFile, mediaMetadataFromScan, verbose = false) {
|
||||
var probeStart = Date.now()
|
||||
const probeStart = Date.now()
|
||||
|
||||
var probeData = null
|
||||
let probeData = null
|
||||
// TODO: Temp not using tone for probing until more testing can be done
|
||||
// if (global.ServerSettings.scannerUseTone) {
|
||||
// Logger.debug(`[MediaFileScanner] using tone to probe audio file "${libraryFile.metadata.path}"`)
|
||||
|
|
@ -79,7 +79,7 @@ class MediaFileScanner {
|
|||
return null
|
||||
}
|
||||
|
||||
var videoFile = new VideoFile()
|
||||
const videoFile = new VideoFile()
|
||||
videoFile.setDataFromProbe(libraryFile, probeData)
|
||||
|
||||
return {
|
||||
|
|
@ -92,7 +92,7 @@ class MediaFileScanner {
|
|||
return null
|
||||
}
|
||||
|
||||
var audioFile = new AudioFile()
|
||||
const audioFile = new AudioFile()
|
||||
audioFile.trackNumFromMeta = probeData.trackNumber
|
||||
audioFile.discNumFromMeta = probeData.discNumber
|
||||
if (mediaType === 'book') {
|
||||
|
|
@ -113,13 +113,13 @@ class MediaFileScanner {
|
|||
async executeMediaFileScans(libraryItem, mediaLibraryFiles, scanData) {
|
||||
const mediaType = libraryItem.mediaType
|
||||
|
||||
var scanStart = Date.now()
|
||||
var mediaMetadataFromScan = scanData.media.metadata || null
|
||||
var proms = []
|
||||
const scanStart = Date.now()
|
||||
const mediaMetadataFromScan = scanData.media.metadata || null
|
||||
const proms = []
|
||||
for (let i = 0; i < mediaLibraryFiles.length; i++) {
|
||||
proms.push(this.scan(mediaType, mediaLibraryFiles[i], mediaMetadataFromScan))
|
||||
}
|
||||
var results = await Promise.all(proms).then((scanResults) => scanResults.filter(sr => sr))
|
||||
const results = await Promise.all(proms).then((scanResults) => scanResults.filter(sr => sr))
|
||||
return {
|
||||
audioFiles: results.filter(r => r.audioFile).map(r => r.audioFile),
|
||||
videoFiles: results.filter(r => r.videoFile).map(r => r.videoFile),
|
||||
|
|
@ -131,7 +131,7 @@ class MediaFileScanner {
|
|||
isSequential(nums) {
|
||||
if (!nums || !nums.length) return false
|
||||
if (nums.length === 1) return true
|
||||
var prev = nums[0]
|
||||
let prev = nums[0]
|
||||
for (let i = 1; i < nums.length; i++) {
|
||||
if (nums[i] - prev > 1) return false
|
||||
prev = nums[i]
|
||||
|
|
@ -207,9 +207,9 @@ class MediaFileScanner {
|
|||
}
|
||||
|
||||
async scanMediaFiles(mediaLibraryFiles, scanData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan = null) {
|
||||
var hasUpdated = false
|
||||
let hasUpdated = false
|
||||
|
||||
var mediaScanResult = await this.executeMediaFileScans(libraryItem, mediaLibraryFiles, scanData)
|
||||
const mediaScanResult = await this.executeMediaFileScans(libraryItem, mediaLibraryFiles, scanData)
|
||||
|
||||
if (libraryItem.mediaType === 'video') {
|
||||
if (mediaScanResult.videoFiles.length) {
|
||||
|
|
@ -223,32 +223,32 @@ class MediaFileScanner {
|
|||
}
|
||||
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`)
|
||||
|
||||
var newAudioFiles = mediaScanResult.audioFiles.filter(af => {
|
||||
const newAudioFiles = mediaScanResult.audioFiles.filter(af => {
|
||||
return !libraryItem.media.findFileWithInode(af.ino)
|
||||
})
|
||||
|
||||
// Book: Adding audio files to book media
|
||||
if (libraryItem.mediaType === 'book') {
|
||||
var mediaScanFileInodes = mediaScanResult.audioFiles.map(af => af.ino)
|
||||
const mediaScanFileInodes = mediaScanResult.audioFiles.map(af => af.ino)
|
||||
// Filter for existing valid track audio files not included in the audio files scanned
|
||||
var existingAudioFiles = libraryItem.media.audioFiles.filter(af => af.isValidTrack && !mediaScanFileInodes.includes(af.ino))
|
||||
const existingAudioFiles = libraryItem.media.audioFiles.filter(af => af.isValidTrack && !mediaScanFileInodes.includes(af.ino))
|
||||
|
||||
if (newAudioFiles.length) {
|
||||
// Single Track Audiobooks
|
||||
if (mediaScanFileInodes.length + existingAudioFiles.length === 1) {
|
||||
var af = mediaScanResult.audioFiles[0]
|
||||
const af = mediaScanResult.audioFiles[0]
|
||||
af.index = 1
|
||||
libraryItem.media.addAudioFile(af)
|
||||
hasUpdated = true
|
||||
} else {
|
||||
var allAudioFiles = existingAudioFiles.concat(mediaScanResult.audioFiles)
|
||||
const allAudioFiles = existingAudioFiles.concat(mediaScanResult.audioFiles)
|
||||
this.runSmartTrackOrder(libraryItem, allAudioFiles)
|
||||
hasUpdated = true
|
||||
}
|
||||
} else {
|
||||
// Only update metadata not index
|
||||
mediaScanResult.audioFiles.forEach((af) => {
|
||||
var existingAF = libraryItem.media.findFileWithInode(af.ino)
|
||||
const existingAF = libraryItem.media.findFileWithInode(af.ino)
|
||||
if (existingAF) {
|
||||
af.index = existingAF.index
|
||||
if (existingAF.updateFromScan && existingAF.updateFromScan(af)) {
|
||||
|
|
@ -266,11 +266,11 @@ class MediaFileScanner {
|
|||
if (hasUpdated) {
|
||||
libraryItem.media.rebuildTracks(preferOverdriveMediaMarker)
|
||||
}
|
||||
} else { // Podcast Media Type
|
||||
var existingAudioFiles = mediaScanResult.audioFiles.filter(af => libraryItem.media.findFileWithInode(af.ino))
|
||||
} else if (libraryItem.mediaType === 'podcast') { // Podcast Media Type
|
||||
const existingAudioFiles = mediaScanResult.audioFiles.filter(af => libraryItem.media.findFileWithInode(af.ino))
|
||||
|
||||
if (newAudioFiles.length) {
|
||||
var newIndex = libraryItem.media.episodes.length + 1
|
||||
let newIndex = libraryItem.media.episodes.length + 1
|
||||
newAudioFiles.forEach((newAudioFile) => {
|
||||
libraryItem.media.addNewEpisodeFromAudioFile(newAudioFile, newIndex++)
|
||||
})
|
||||
|
|
@ -280,11 +280,19 @@ class MediaFileScanner {
|
|||
|
||||
// Update audio file metadata for audio files already there
|
||||
existingAudioFiles.forEach((af) => {
|
||||
var peAudioFile = libraryItem.media.findFileWithInode(af.ino)
|
||||
const peAudioFile = libraryItem.media.findFileWithInode(af.ino)
|
||||
if (peAudioFile.updateFromScan && peAudioFile.updateFromScan(af)) {
|
||||
hasUpdated = true
|
||||
}
|
||||
})
|
||||
} else if (libraryItem.mediaType === 'music') { // Music
|
||||
// Only one audio file in library item
|
||||
if (newAudioFiles.length) { // New audio file
|
||||
libraryItem.media.setAudioFile(newAudioFiles[0])
|
||||
hasUpdated = true
|
||||
} else if (libraryItem.media.audioFile && libraryItem.media.audioFile.updateFromScan(mediaScanResult.audioFiles[0])) {
|
||||
hasUpdated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Scanner {
|
|||
}
|
||||
|
||||
async scanLibraryItemById(libraryItemId) {
|
||||
var libraryItem = this.db.libraryItems.find(li => li.id === libraryItemId)
|
||||
const libraryItem = this.db.libraryItems.find(li => li.id === libraryItemId)
|
||||
if (!libraryItem) {
|
||||
Logger.error(`[Scanner] Scan libraryItem by id not found ${libraryItemId}`)
|
||||
return ScanResult.NOTHING
|
||||
|
|
@ -68,13 +68,13 @@ class Scanner {
|
|||
|
||||
async scanLibraryItem(libraryMediaType, folder, libraryItem) {
|
||||
// TODO: Support for single media item
|
||||
var libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, libraryItem.path, false, this.db.serverSettings)
|
||||
const libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, libraryItem.path, false, this.db.serverSettings)
|
||||
if (!libraryItemData) {
|
||||
return ScanResult.NOTHING
|
||||
}
|
||||
var hasUpdated = false
|
||||
let hasUpdated = false
|
||||
|
||||
var checkRes = libraryItem.checkScanData(libraryItemData)
|
||||
const checkRes = libraryItem.checkScanData(libraryItemData)
|
||||
if (checkRes.updated) hasUpdated = true
|
||||
|
||||
// Sync other files first so that local images are used as cover art
|
||||
|
|
@ -84,14 +84,14 @@ class Scanner {
|
|||
|
||||
// Scan all audio files
|
||||
if (libraryItem.hasAudioFiles) {
|
||||
var libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio')
|
||||
const libraryAudioFiles = libraryItem.libraryFiles.filter(lf => lf.fileType === 'audio')
|
||||
if (await MediaFileScanner.scanMediaFiles(libraryAudioFiles, libraryItemData, libraryItem, this.db.serverSettings.scannerPreferAudioMetadata, this.db.serverSettings.scannerPreferOverdriveMediaMarker)) {
|
||||
hasUpdated = true
|
||||
}
|
||||
|
||||
// Extract embedded cover art if cover is not already in directory
|
||||
if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
|
||||
var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
|
||||
const coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
|
||||
if (coverPath) {
|
||||
Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`)
|
||||
hasUpdated = true
|
||||
|
|
@ -172,8 +172,8 @@ class Scanner {
|
|||
|
||||
// Scan each library
|
||||
for (let i = 0; i < libraryScan.folders.length; i++) {
|
||||
var folder = libraryScan.folders[i]
|
||||
var itemDataFoundInFolder = await scanFolder(libraryScan.libraryMediaType, folder, this.db.serverSettings)
|
||||
const folder = libraryScan.folders[i]
|
||||
const itemDataFoundInFolder = await scanFolder(libraryScan.libraryMediaType, folder, this.db.serverSettings)
|
||||
libraryScan.addLog(LogLevel.INFO, `${itemDataFoundInFolder.length} item data found in folder "${folder.fullPath}"`)
|
||||
libraryItemDataFound = libraryItemDataFound.concat(itemDataFoundInFolder)
|
||||
}
|
||||
|
|
@ -196,16 +196,16 @@ class Scanner {
|
|||
|
||||
// Check for existing & removed library items
|
||||
for (let i = 0; i < libraryItemsInLibrary.length; i++) {
|
||||
var libraryItem = libraryItemsInLibrary[i]
|
||||
const libraryItem = libraryItemsInLibrary[i]
|
||||
// Find library item folder with matching inode or matching path
|
||||
var dataFound = libraryItemDataFound.find(lid => lid.ino === libraryItem.ino || comparePaths(lid.relPath, libraryItem.relPath))
|
||||
const dataFound = libraryItemDataFound.find(lid => lid.ino === libraryItem.ino || comparePaths(lid.relPath, libraryItem.relPath))
|
||||
if (!dataFound) {
|
||||
libraryScan.addLog(LogLevel.WARN, `Library Item "${libraryItem.media.metadata.title}" is missing`)
|
||||
libraryScan.resultsMissing++
|
||||
libraryItem.setMissing()
|
||||
itemsToUpdate.push(libraryItem)
|
||||
} else {
|
||||
var checkRes = libraryItem.checkScanData(dataFound)
|
||||
const checkRes = libraryItem.checkScanData(dataFound)
|
||||
if (checkRes.newLibraryFiles.length || libraryScan.scanOptions.forceRescan) { // Item has new files
|
||||
checkRes.libraryItem = libraryItem
|
||||
checkRes.scanData = dataFound
|
||||
|
|
@ -244,15 +244,15 @@ class Scanner {
|
|||
|
||||
// Potential NEW Library Items
|
||||
for (let i = 0; i < libraryItemDataFound.length; i++) {
|
||||
var dataFound = libraryItemDataFound[i]
|
||||
const dataFound = libraryItemDataFound[i]
|
||||
|
||||
var hasMediaFile = dataFound.libraryFiles.some(lf => lf.isMediaFile)
|
||||
const hasMediaFile = dataFound.libraryFiles.some(lf => lf.isMediaFile)
|
||||
if (!hasMediaFile) {
|
||||
libraryScan.addLog(LogLevel.WARN, `Item found "${libraryItemDataFound.path}" has no media files`)
|
||||
} else {
|
||||
if (global.ServerSettings.scannerUseSingleThreadedProber) {
|
||||
// If this item will go over max size then push current chunk
|
||||
var mediaFileSize = 0
|
||||
let mediaFileSize = 0
|
||||
dataFound.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video').forEach(lf => mediaFileSize += lf.metadata.size)
|
||||
if (mediaFileSize + newItemDataToScanSize > MaxSizePerChunk && newItemDataToScan.length > 0) {
|
||||
newItemDataToScanChunks.push(newItemDataToScan)
|
||||
|
|
@ -277,8 +277,8 @@ class Scanner {
|
|||
|
||||
// Library Items not requiring a scan but require a search for cover
|
||||
for (let i = 0; i < itemsToFindCovers.length; i++) {
|
||||
var libraryItem = itemsToFindCovers[i]
|
||||
var updatedCover = await this.searchForCover(libraryItem, libraryScan)
|
||||
const libraryItem = itemsToFindCovers[i]
|
||||
const updatedCover = await this.searchForCover(libraryItem, libraryScan)
|
||||
libraryItem.media.updateLastCoverSearch(updatedCover)
|
||||
}
|
||||
|
||||
|
|
@ -397,10 +397,10 @@ class Scanner {
|
|||
if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Scanning new library item "${libraryItemData.path}"`)
|
||||
else Logger.debug(`[Scanner] Scanning new item "${libraryItemData.path}"`)
|
||||
|
||||
var libraryItem = new LibraryItem()
|
||||
const libraryItem = new LibraryItem()
|
||||
libraryItem.setData(libraryMediaType, libraryItemData)
|
||||
|
||||
var mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video')
|
||||
const mediaFiles = libraryItemData.libraryFiles.filter(lf => lf.fileType === 'audio' || lf.fileType === 'video')
|
||||
if (mediaFiles.length) {
|
||||
await MediaFileScanner.scanMediaFiles(mediaFiles, libraryItemData, libraryItem, preferAudioMetadata, preferOverdriveMediaMarker, libraryScan)
|
||||
}
|
||||
|
|
@ -414,7 +414,7 @@ class Scanner {
|
|||
|
||||
// Extract embedded cover art if cover is not already in directory
|
||||
if (libraryItem.media.hasEmbeddedCoverArt && !libraryItem.media.coverPath) {
|
||||
var coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
|
||||
const coverPath = await this.coverManager.saveEmbeddedCoverArt(libraryItem)
|
||||
if (coverPath) {
|
||||
if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${coverPath}"`)
|
||||
else Logger.debug(`[Scanner] Saved embedded cover art "${coverPath}"`)
|
||||
|
|
@ -424,7 +424,7 @@ class Scanner {
|
|||
// Scan for cover if enabled and has no cover
|
||||
if (libraryMediaType === 'book') {
|
||||
if (libraryItem && 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -636,19 +636,19 @@ class Scanner {
|
|||
}
|
||||
|
||||
async scanPotentialNewLibraryItem(libraryMediaType, folder, fullPath, isSingleMediaItem = false) {
|
||||
var libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, fullPath, isSingleMediaItem, this.db.serverSettings)
|
||||
const libraryItemData = await getLibraryItemFileData(libraryMediaType, folder, fullPath, isSingleMediaItem, this.db.serverSettings)
|
||||
if (!libraryItemData) return null
|
||||
var serverSettings = this.db.serverSettings
|
||||
const serverSettings = this.db.serverSettings
|
||||
return this.scanNewLibraryItem(libraryItemData, libraryMediaType, serverSettings.scannerPreferAudioMetadata, serverSettings.scannerPreferOpfMetadata, serverSettings.scannerFindCovers, serverSettings.scannerPreferOverdriveMediaMarker)
|
||||
}
|
||||
|
||||
async searchForCover(libraryItem, libraryScan = null) {
|
||||
var options = {
|
||||
const options = {
|
||||
titleDistance: 2,
|
||||
authorDistance: 2
|
||||
}
|
||||
var scannerCoverProvider = this.db.serverSettings.scannerCoverProvider
|
||||
var results = await this.bookFinder.findCovers(scannerCoverProvider, libraryItem.media.metadata.title, libraryItem.media.metadata.authorName, options)
|
||||
const scannerCoverProvider = this.db.serverSettings.scannerCoverProvider
|
||||
const results = await this.bookFinder.findCovers(scannerCoverProvider, libraryItem.media.metadata.title, libraryItem.media.metadata.authorName, options)
|
||||
if (results.length) {
|
||||
if (libraryScan) libraryScan.addLog(LogLevel.DEBUG, `Found best cover for "${libraryItem.media.metadata.title}"`)
|
||||
else Logger.debug(`[Scanner] Found best cover for "${libraryItem.media.metadata.title}"`)
|
||||
|
|
@ -657,7 +657,7 @@ class Scanner {
|
|||
for (let i = 0; i < results.length && i < 2; i++) {
|
||||
|
||||
// Downloads and updates the book cover
|
||||
var result = await this.coverManager.downloadCoverFromUrl(libraryItem, results[i])
|
||||
const result = await this.coverManager.downloadCoverFromUrl(libraryItem, results[i])
|
||||
|
||||
if (result.error) {
|
||||
Logger.error(`[Scanner] Failed to download cover from url "${results[i]}" | Attempt ${i + 1}`, result.error)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue