From 3ea0dc914743859e567b54b93d8690fd892ad6e9 Mon Sep 17 00:00:00 2001 From: Graham Alderson Date: Mon, 4 Dec 2023 12:13:38 +1200 Subject: [PATCH] Sidecar load refactor Resolves error when sidecar metadata not complete, migrates from any to SideCar type, moves sidecar loading to after file loading, finishes async/await transition. --- .../model/fileaccess/MetadataLoader.ts | 117 +++++++++++------- src/common/entities/MediaDTO.ts | 13 ++ 2 files changed, 86 insertions(+), 44 deletions(-) diff --git a/src/backend/model/fileaccess/MetadataLoader.ts b/src/backend/model/fileaccess/MetadataLoader.ts index 8a6187fa..80df3587 100644 --- a/src/backend/model/fileaccess/MetadataLoader.ts +++ b/src/backend/model/fileaccess/MetadataLoader.ts @@ -1,5 +1,6 @@ import {VideoMetadata} from '../../../common/entities/VideoDTO'; import {FaceRegion, PhotoMetadata} from '../../../common/entities/PhotoDTO'; +import {SideCar} from '../../../common/entities/MediaDTO'; import {Config} from '../../../common/config/private/Config'; import {Logger} from '../../Logger'; import * as fs from 'fs'; @@ -37,28 +38,6 @@ export class MetadataLoader { fps: 0, }; - try { - // search for sidecar and merge metadata - const fullPathWithoutExt = path.parse(fullPath).name; - const sidecarPaths = [ - fullPath + '.xmp', - fullPath + '.XMP', - fullPathWithoutExt + '.xmp', - fullPathWithoutExt + '.XMP', - ]; - - for (const sidecarPath of sidecarPaths) { - if (fs.existsSync(sidecarPath)) { - const sidecarData = await exifr.sidecar(sidecarPath); - metadata.keywords = [(sidecarData as any).dc.subject].flat(); - metadata.rating = (sidecarData as any).xmp.Rating; - } - } - } catch (err) { - Logger.silly(LOG_TAG, 'Error loading sidecar metadata for : ' + fullPath); - Logger.silly(err); - } - try { const stat = fs.statSync(fullPath); metadata.fileSize = stat.size; @@ -147,6 +126,41 @@ export class MetadataLoader { Logger.silly(err); } metadata.creationDate = metadata.creationDate || 0; + + try { + // search for sidecar and merge metadata + const fullPathWithoutExt = path.parse(fullPath).name; + const sidecarPaths = [ + fullPath + '.xmp', + fullPath + '.XMP', + fullPathWithoutExt + '.xmp', + fullPathWithoutExt + '.XMP', + ]; + + for (const sidecarPath of sidecarPaths) { + if (fs.existsSync(sidecarPath)) { + const sidecarData = await exifr.sidecar(sidecarPath); + if (sidecarData !== undefined) { + if ((sidecarData as SideCar).dc.subject !== undefined) { + if (metadata.keywords === undefined) { + metadata.keywords = []; + } + for (const kw of (sidecarData as SideCar).dc.subject) { + if (metadata.keywords.indexOf(kw) === -1) { + metadata.keywords.push(kw); + } + } } + if ((sidecarData as SideCar).xmp.Rating !== undefined) { + metadata.rating = (sidecarData as SideCar).xmp.Rating; + } + } + } + } + } catch (err) { + Logger.silly(LOG_TAG, 'Error loading sidecar metadata for : ' + fullPath); + Logger.silly(err); + } + } catch (err) { Logger.silly(LOG_TAG, 'Error loading metadata for : ' + fullPath); Logger.silly(err); @@ -190,27 +204,6 @@ export class MetadataLoader { // ignoring errors } - try { - // search for sidecar and merge metadata - const fullPathWithoutExt = path.parse(fullPath).name; - const sidecarPaths = [ - fullPath + '.xmp', - fullPath + '.XMP', - fullPathWithoutExt + '.xmp', - fullPathWithoutExt + '.XMP', - ]; - - for (const sidecarPath of sidecarPaths) { - if (fs.existsSync(sidecarPath)) { - const sidecarData = await exifr.sidecar(sidecarPath); - metadata.keywords = [(sidecarData as any).dc.subject].flat(); - metadata.rating = (sidecarData as any).xmp.Rating; - } - } - } catch (err) { - // ignoring errors - } - try { const exif = ExifParserFactory.create(data).parse(); if ( @@ -313,7 +306,7 @@ export class MetadataLoader { } } catch (err) { Logger.debug(LOG_TAG, 'Error parsing exif', fullPath, err); - try { + try { const info = imageSize(fullPath); metadata.size = {width: info.width, height: info.height}; } catch (e) { @@ -508,6 +501,42 @@ export class MetadataLoader { // ignoring errors } + try { + // search for sidecar and merge metadata + const fullPathWithoutExt = path.parse(fullPath).name; + const sidecarPaths = [ + fullPath + '.xmp', + fullPath + '.XMP', + fullPathWithoutExt + '.xmp', + fullPathWithoutExt + '.XMP', + ]; + + for (const sidecarPath of sidecarPaths) { + if (fs.existsSync(sidecarPath)) { + const sidecarData = await exifr.sidecar(sidecarPath); + + if (sidecarData !== undefined) { + if ((sidecarData as SideCar).dc.subject !== undefined) { + if (metadata.keywords === undefined) { + metadata.keywords = []; + } + for (const kw of (sidecarData as SideCar).dc.subject) { + if (metadata.keywords.indexOf(kw) === -1) { + metadata.keywords.push(kw); + } + } + } + if ((sidecarData as SideCar).xmp.Rating !== undefined) { + metadata.rating = (sidecarData as SideCar).xmp.Rating; + } + } + } + } + } catch (err) { + Logger.silly(LOG_TAG, 'Error loading sidecar metadata for : ' + fullPath); + Logger.silly(err); + } + } catch (err) { Logger.error(LOG_TAG, 'Error during reading photo: ' + fullPath); console.error(err); diff --git a/src/common/entities/MediaDTO.ts b/src/common/entities/MediaDTO.ts index b56136ca..b53fc46e 100644 --- a/src/common/entities/MediaDTO.ts +++ b/src/common/entities/MediaDTO.ts @@ -26,6 +26,19 @@ export interface MediaDimension { height: number; } +export interface SideCar { + dc?: SideCarDc; + xmp?: SideCarXmp; +} + +export interface SideCarDc { + subject?: string[]; +} + +export interface SideCarXmp { + Rating?: RatingTypes; +} + export const MediaDTOUtils = { hasPositionData: (media: MediaDTO): boolean => { return (