Format PodcastScanner (Pretteier-only changes)

This commit is contained in:
mikiher 2025-02-16 12:41:47 +02:00
parent 0169bf5518
commit bacefb5f6f

View File

@ -1,4 +1,4 @@
const uuidv4 = require("uuid").v4 const uuidv4 = require('uuid').v4
const Path = require('path') const Path = require('path')
const { LogLevel } = require('../utils/constants') const { LogLevel } = require('../utils/constants')
const { getTitleIgnorePrefix } = require('../utils/index') const { getTitleIgnorePrefix } = require('../utils/index')
@ -8,9 +8,9 @@ const { filePathToPOSIX, getFileTimestampsWithIno } = require('../utils/fileUtil
const AudioFile = require('../objects/files/AudioFile') const AudioFile = require('../objects/files/AudioFile')
const CoverManager = require('../managers/CoverManager') const CoverManager = require('../managers/CoverManager')
const LibraryFile = require('../objects/files/LibraryFile') const LibraryFile = require('../objects/files/LibraryFile')
const fsExtra = require("../libs/fsExtra") const fsExtra = require('../libs/fsExtra')
const PodcastEpisode = require("../models/PodcastEpisode") const PodcastEpisode = require('../models/PodcastEpisode')
const AbsMetadataFileScanner = require("./AbsMetadataFileScanner") const AbsMetadataFileScanner = require('./AbsMetadataFileScanner')
/** /**
* Metadata for podcasts pulled from files * Metadata for podcasts pulled from files
@ -32,7 +32,7 @@ const AbsMetadataFileScanner = require("./AbsMetadataFileScanner")
*/ */
class PodcastScanner { class PodcastScanner {
constructor() { } constructor() {}
/** /**
* @param {import('../models/LibraryItem')} existingLibraryItem * @param {import('../models/LibraryItem')} existingLibraryItem
@ -59,7 +59,8 @@ class PodcastScanner {
if (libraryItemData.hasAudioFileChanges || libraryItemData.audioLibraryFiles.length !== existingPodcastEpisodes.length) { if (libraryItemData.hasAudioFileChanges || libraryItemData.audioLibraryFiles.length !== existingPodcastEpisodes.length) {
// Filter out and destroy episodes that were removed // Filter out and destroy episodes that were removed
existingPodcastEpisodes = await Promise.all(existingPodcastEpisodes.filter(async ep => { existingPodcastEpisodes = await Promise.all(
existingPodcastEpisodes.filter(async (ep) => {
if (libraryItemData.checkAudioFileRemoved(ep.audioFile)) { if (libraryItemData.checkAudioFileRemoved(ep.audioFile)) {
libraryScan.addLog(LogLevel.INFO, `Podcast episode "${ep.title}" audio file was removed`) libraryScan.addLog(LogLevel.INFO, `Podcast episode "${ep.title}" audio file was removed`)
// TODO: Should clean up other data linked to this episode // TODO: Should clean up other data linked to this episode
@ -67,20 +68,25 @@ class PodcastScanner {
return false return false
} }
return true return true
})) })
)
// Update audio files that were modified // Update audio files that were modified
if (libraryItemData.audioLibraryFilesModified.length) { if (libraryItemData.audioLibraryFilesModified.length) {
let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(existingLibraryItem.mediaType, libraryItemData, libraryItemData.audioLibraryFilesModified.map(lf => lf.new)) let scannedAudioFiles = await AudioFileScanner.executeMediaFileScans(
existingLibraryItem.mediaType,
libraryItemData,
libraryItemData.audioLibraryFilesModified.map((lf) => lf.new)
)
for (const podcastEpisode of existingPodcastEpisodes) { for (const podcastEpisode of existingPodcastEpisodes) {
let matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.metadata.path === podcastEpisode.audioFile.metadata.path) let matchedScannedAudioFile = scannedAudioFiles.find((saf) => saf.metadata.path === podcastEpisode.audioFile.metadata.path)
if (!matchedScannedAudioFile) { if (!matchedScannedAudioFile) {
matchedScannedAudioFile = scannedAudioFiles.find(saf => saf.ino === podcastEpisode.audioFile.ino) matchedScannedAudioFile = scannedAudioFiles.find((saf) => saf.ino === podcastEpisode.audioFile.ino)
} }
if (matchedScannedAudioFile) { if (matchedScannedAudioFile) {
scannedAudioFiles = scannedAudioFiles.filter(saf => saf !== matchedScannedAudioFile) scannedAudioFiles = scannedAudioFiles.filter((saf) => saf !== matchedScannedAudioFile)
const audioFile = new AudioFile(podcastEpisode.audioFile) const audioFile = new AudioFile(podcastEpisode.audioFile)
audioFile.updateFromScan(matchedScannedAudioFile) audioFile.updateFromScan(matchedScannedAudioFile)
podcastEpisode.audioFile = audioFile.toJSON() podcastEpisode.audioFile = audioFile.toJSON()
@ -137,14 +143,14 @@ class PodcastScanner {
} }
// Check if cover was removed // Check if cover was removed
if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some(lf => lf.metadata.path === media.coverPath)) { if (media.coverPath && libraryItemData.imageLibraryFilesRemoved.some((lf) => lf.metadata.path === media.coverPath)) {
media.coverPath = null media.coverPath = null
hasMediaChanges = true hasMediaChanges = true
} }
// Update cover if it was modified // Update cover if it was modified
if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) { if (media.coverPath && libraryItemData.imageLibraryFilesModified.length) {
let coverMatch = libraryItemData.imageLibraryFilesModified.find(iFile => iFile.old.metadata.path === media.coverPath) let coverMatch = libraryItemData.imageLibraryFilesModified.find((iFile) => iFile.old.metadata.path === media.coverPath)
if (coverMatch) { if (coverMatch) {
const coverPath = coverMatch.new.metadata.path const coverPath = coverMatch.new.metadata.path
if (coverPath !== media.coverPath) { if (coverPath !== media.coverPath) {
@ -159,7 +165,7 @@ class PodcastScanner {
// Check if cover is not set and image files were found // Check if cover is not set and image files were found
if (!media.coverPath && libraryItemData.imageLibraryFiles.length) { if (!media.coverPath && libraryItemData.imageLibraryFiles.length) {
// Prefer using a cover image with the name "cover" otherwise use the first image // Prefer using a cover image with the name "cover" otherwise use the first image
const coverMatch = libraryItemData.imageLibraryFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path)) const coverMatch = libraryItemData.imageLibraryFiles.find((iFile) => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
media.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path media.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
hasMediaChanges = true hasMediaChanges = true
} }
@ -172,7 +178,7 @@ class PodcastScanner {
if (key === 'genres') { if (key === 'genres') {
const existingGenres = media.genres || [] const existingGenres = media.genres || []
if (podcastMetadata.genres.some(g => !existingGenres.includes(g)) || existingGenres.some(g => !podcastMetadata.genres.includes(g))) { if (podcastMetadata.genres.some((g) => !existingGenres.includes(g)) || existingGenres.some((g) => !podcastMetadata.genres.includes(g))) {
libraryScan.addLog(LogLevel.DEBUG, `Updating podcast genres "${existingGenres.join(',')}" => "${podcastMetadata.genres.join(',')}" for podcast "${podcastMetadata.title}"`) libraryScan.addLog(LogLevel.DEBUG, `Updating podcast genres "${existingGenres.join(',')}" => "${podcastMetadata.genres.join(',')}" for podcast "${podcastMetadata.title}"`)
media.genres = podcastMetadata.genres media.genres = podcastMetadata.genres
media.changed('genres', true) media.changed('genres', true)
@ -180,7 +186,7 @@ class PodcastScanner {
} }
} else if (key === 'tags') { } else if (key === 'tags') {
const existingTags = media.tags || [] const existingTags = media.tags || []
if (podcastMetadata.tags.some(t => !existingTags.includes(t)) || existingTags.some(t => !podcastMetadata.tags.includes(t))) { if (podcastMetadata.tags.some((t) => !existingTags.includes(t)) || existingTags.some((t) => !podcastMetadata.tags.includes(t))) {
libraryScan.addLog(LogLevel.DEBUG, `Updating podcast tags "${existingTags.join(',')}" => "${podcastMetadata.tags.join(',')}" for podcast "${podcastMetadata.title}"`) libraryScan.addLog(LogLevel.DEBUG, `Updating podcast tags "${existingTags.join(',')}" => "${podcastMetadata.tags.join(',')}" for podcast "${podcastMetadata.title}"`)
media.tags = podcastMetadata.tags media.tags = podcastMetadata.tags
media.changed('tags', true) media.changed('tags', true)
@ -195,7 +201,7 @@ class PodcastScanner {
// If no cover then extract cover from audio file if available // If no cover then extract cover from audio file if available
if (!media.coverPath && existingPodcastEpisodes.length) { if (!media.coverPath && existingPodcastEpisodes.length) {
const audioFiles = existingPodcastEpisodes.map(ep => ep.audioFile) const audioFiles = existingPodcastEpisodes.map((ep) => ep.audioFile)
const extractedCoverPath = await CoverManager.saveEmbeddedCoverArt(audioFiles, existingLibraryItem.id, existingLibraryItem.path) const extractedCoverPath = await CoverManager.saveEmbeddedCoverArt(audioFiles, existingLibraryItem.id, existingLibraryItem.path)
if (extractedCoverPath) { if (extractedCoverPath) {
libraryScan.addLog(LogLevel.DEBUG, `Updating podcast "${podcastMetadata.title}" extracted embedded cover art from audio file to path "${extractedCoverPath}"`) libraryScan.addLog(LogLevel.DEBUG, `Updating podcast "${podcastMetadata.title}" extracted embedded cover art from audio file to path "${extractedCoverPath}"`)
@ -272,7 +278,7 @@ class PodcastScanner {
// Set cover image from library file // Set cover image from library file
if (libraryItemData.imageLibraryFiles.length) { if (libraryItemData.imageLibraryFiles.length) {
// Prefer using a cover image with the name "cover" otherwise use the first image // Prefer using a cover image with the name "cover" otherwise use the first image
const coverMatch = libraryItemData.imageLibraryFiles.find(iFile => /\/cover\.[^.\/]*$/.test(iFile.metadata.path)) const coverMatch = libraryItemData.imageLibraryFiles.find((iFile) => /\/cover\.[^.\/]*$/.test(iFile.metadata.path))
podcastMetadata.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path podcastMetadata.coverPath = coverMatch?.metadata.path || libraryItemData.imageLibraryFiles[0].metadata.path
} }
@ -405,9 +411,11 @@ class PodcastScanner {
explicit: !!libraryItem.media.explicit, explicit: !!libraryItem.media.explicit,
podcastType: libraryItem.media.podcastType podcastType: libraryItem.media.podcastType
} }
return fsExtra.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2)).then(async () => { return fsExtra
.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2))
.then(async () => {
// Add metadata.json to libraryFiles array if it is new // Add metadata.json to libraryFiles array if it is new
let metadataLibraryFile = libraryItem.libraryFiles.find(lf => lf.metadata.path === filePathToPOSIX(metadataFilePath)) let metadataLibraryFile = libraryItem.libraryFiles.find((lf) => lf.metadata.path === filePathToPOSIX(metadataFilePath))
if (storeMetadataWithItem) { if (storeMetadataWithItem) {
if (!metadataLibraryFile) { if (!metadataLibraryFile) {
const newLibraryFile = new LibraryFile() const newLibraryFile = new LibraryFile()
@ -428,7 +436,7 @@ class PodcastScanner {
libraryItem.mtime = libraryItemDirTimestamps.mtimeMs libraryItem.mtime = libraryItemDirTimestamps.mtimeMs
libraryItem.ctime = libraryItemDirTimestamps.ctimeMs libraryItem.ctime = libraryItemDirTimestamps.ctimeMs
let size = 0 let size = 0
libraryItem.libraryFiles.forEach((lf) => size += (!isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0)) libraryItem.libraryFiles.forEach((lf) => (size += !isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0))
libraryItem.size = size libraryItem.size = size
} }
} }
@ -436,7 +444,8 @@ class PodcastScanner {
libraryScan.addLog(LogLevel.DEBUG, `Success saving abmetadata to "${metadataFilePath}"`) libraryScan.addLog(LogLevel.DEBUG, `Success saving abmetadata to "${metadataFilePath}"`)
return metadataLibraryFile return metadataLibraryFile
}).catch((error) => { })
.catch((error) => {
libraryScan.addLog(LogLevel.ERROR, `Failed to save json file at "${metadataFilePath}"`, error) libraryScan.addLog(LogLevel.ERROR, `Failed to save json file at "${metadataFilePath}"`, error)
return null return null
}) })