diff --git a/src/backend/model/fileaccess/MetadataLoader.ts b/src/backend/model/fileaccess/MetadataLoader.ts index 8feb8427..5a61af21 100644 --- a/src/backend/model/fileaccess/MetadataLoader.ts +++ b/src/backend/model/fileaccess/MetadataLoader.ts @@ -139,13 +139,13 @@ export class MetadataLoader { fullPathWithoutExt + '.xmp', fullPathWithoutExt + '.XMP', ]; + for (const sidecarPath of sidecarPaths) { if (fs.existsSync(sidecarPath)) { const sidecarData: any = await exifr.sidecar(sidecarPath); if (sidecarData !== undefined) { MetadataLoader.mapMetadata(metadata, sidecarData); } - break; //Break the loop as soon as a sidecar is found, no need to check the extra sidecar paths } } } catch (err) { @@ -316,8 +316,6 @@ export class MetadataLoader { const orientation = MetadataLoader.getOrientation(exif); MetadataLoader.mapImageDimensions(metadata, exif, orientation); MetadataLoader.mapKeywords(metadata, exif); - MetadataLoader.mapTitle(metadata, exif); - MetadataLoader.mapCaption(metadata, exif); MetadataLoader.mapTimestampAndOffset(metadata, exif); MetadataLoader.mapCameraData(metadata, exif); MetadataLoader.mapGPS(metadata, exif); @@ -372,15 +370,6 @@ export class MetadataLoader { } } - private static mapTitle(metadata: PhotoMetadata, exif: any) { - metadata.title = exif.dc?.title?.value || metadata.title || exif.photoshop?.Headline || exif.acdsee?.caption; //acdsee caption holds the title when data is saved by digikam. Used as last resort if iptc and dc do not contain the data - } - - private static mapCaption(metadata: PhotoMetadata, exif: any) { - metadata.caption = exif.dc?.description?.value || metadata.caption || exif.ifd0?.ImageDescription || exif.exif?.UserComment?.value || exif.Iptc4xmpCore?.ExtDescrAccessibility?.value ||exif.acdsee?.notes; - } - - private static mapTimestampAndOffset(metadata: PhotoMetadata, exif: any) { metadata.creationDate = Utils.timestampToMS(exif?.photoshop?.DateCreated, null) || Utils.timestampToMS(exif?.xmp?.CreateDate, null) || diff --git a/src/common/Utils.ts b/src/common/Utils.ts index a9a7a862..49a89307 100644 --- a/src/common/Utils.ts +++ b/src/common/Utils.ts @@ -132,8 +132,8 @@ export class Utils { //replace : with - in the yyyy-mm-dd part of the timestamp. let formattedTimestamp = timestamp.substring(0,9).replaceAll(':', '-') + timestamp.substring(9,timestamp.length); if (formattedTimestamp.indexOf("Z") > 0) { //replace Z (and what comes after the Z) with offset - formattedTimestamp = formattedTimestamp.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00'); - } else if (formattedTimestamp.indexOf("+") > 0) { //don't do anything + formattedTimestamp.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00'); + } else if (formattedTimestamp.indexOf("+") > 0 || timestamp.substring(9,timestamp.length).indexOf("-") > 0) { //don't do anything } else { //add offset formattedTimestamp = formattedTimestamp + (offset ? offset : '+00:00'); } @@ -144,11 +144,11 @@ export class Utils { //function to extract offset string from timestamp string, returns undefined if timestamp does not contain offset static timestampToOffsetString(timestamp: string) { try { - const idx = timestamp.indexOf("+"); - if (idx > 0) { - return timestamp.substring(idx, timestamp.length); - } - if (timestamp.indexOf("Z") > 0) { + const offsetRegex = /[+-]\d{2}:\d{2}$/; + const match = timestamp.match(offsetRegex); + if (match) { + return match[0]; + } else if (timestamp.indexOf("Z") > 0) { return '+00:00'; } return undefined; diff --git a/test/backend/assets/sidecar/flatxmp.jpg b/test/backend/assets/sidecar/flatxmp.jpg deleted file mode 100644 index c119808d..00000000 Binary files a/test/backend/assets/sidecar/flatxmp.jpg and /dev/null differ diff --git a/test/backend/assets/sidecar/flatxmp.json b/test/backend/assets/sidecar/flatxmp.json deleted file mode 100644 index 008108db..00000000 --- a/test/backend/assets/sidecar/flatxmp.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "size": { - "width": 10, - "height": 5 - }, - "caption": "Description of image", - "creationDate": 328817998000, - "faces": [ - { - "box": { - "height": 1, - "left": 6, - "top": 2, - "width": 2 - }, - "name": "Person1" - }, - { - "box": { - "height": 2, - "left": 2, - "top": 1, - "width": 2 - }, - "name": "Person2" - } - ], - "fileSize": 1430, - "keywords": [ - "Thing3" - ], - "title": "The title" -} \ No newline at end of file diff --git a/test/backend/assets/sidecar/flatxmp.xmp b/test/backend/assets/sidecar/flatxmp.xmp deleted file mode 100644 index 74506a10..00000000 --- a/test/backend/assets/sidecar/flatxmp.xmp +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - 0, 0 - 32, 22 - 64, 56 - 128, 128 - 192, 196 - 255, 255 - - - - - - - - - - - - - - - - - - - Digitized By Testmaster - - - - - The title - - - - - © Testmaster 2024 - - - - - Person1 - Person2 - Thing3 - - - - - Description of image - - - - - All Rights Reserved - - - - - User comment - - - - - 400 - - - - - - - alt text - - - - - extended description - - - - - Person1 - Person2 - - - - - Person1 - Person2 - - - - - Person1 - Person2 - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/backend/assets/sidecar/headline.jpg b/test/backend/assets/sidecar/headline.jpg deleted file mode 100644 index c119808d..00000000 Binary files a/test/backend/assets/sidecar/headline.jpg and /dev/null differ diff --git a/test/backend/assets/sidecar/headline.json b/test/backend/assets/sidecar/headline.json deleted file mode 100644 index 7d6cb058..00000000 --- a/test/backend/assets/sidecar/headline.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "size": { - "width": 10, - "height": 5 - }, - "creationDate": 1185683698000, - "creationDateOffset": "+13:45", - "fileSize": 1430, - "keywords": ["Person 1", "Person 2"], - "caption": "XMP description", - "title": "Photoshop Headline" -} \ No newline at end of file diff --git a/test/backend/assets/sidecar/headline.xmp b/test/backend/assets/sidecar/headline.xmp deleted file mode 100644 index db1f80cf..00000000 --- a/test/backend/assets/sidecar/headline.xmp +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - alt text - - - - Testville - Testica - Testroad 2 - 7357 - Testas - test@example.com - - - - extended description - - - - - - 4244 - 28.0-80.0 mm f/2.8 - 28/1 80/1 14/5 14/5 - - - - True - 0 - 0 - +50 - ACR 3.3 - 0 - 0 - 25 - +58 - False - -0.35 - 0 - 0 - 0 - False - True - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 75 - 0 - 0 - 50 - 25 - 0 - family-220.png - 0 - 0 - -24 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 32 - 25 - 0 - 0 - 0 - 0 - 0 - 4150 - +32 - - - 0, 0 - 32, 22 - 64, 56 - 128, 128 - 192, 196 - 255, 255 - - - Medium Contrast - 3.7 - 0 - 0 - Custom - - - - - - XMP Creator - - - - - XMP description - - - image/png - - - XMP Creator - - - - - Person 1 - Person 2 - - - - - - 24361/8200 - 1 - 0 - 0 - 2007-07-29T18:19:58+13:45 - 1/1 - 0221 - 1/1 - 0 - 2 - 1/8 - 14/5 - 3 - - False - False - 0 - False - 0 - - 28/1 - 42 - 1 - - - 400 - - - 0 - 24361/8200 - 3 - 0 - 0 - 1 - 2 - 0 - 3/1 - 0 - 0 - - - - - Archivalist - 1980-06-02T18:19:58 - Photoshop Headline - - - - CamMake - CamModel - 1 - - - - 2007-07-29T18:19:58+13:45 - Adobe Photoshop Lightroom 13.2 Classic (Windows) - 2014-03-23T01:17:49-05:00 - 2014-03-22T19:09:41-05:00 - - - - - \ No newline at end of file diff --git a/test/backend/assets/sidecar/testimagedesc1.jpg b/test/backend/assets/sidecar/testimagedesc1.jpg deleted file mode 100644 index f0fa299a..00000000 Binary files a/test/backend/assets/sidecar/testimagedesc1.jpg and /dev/null differ diff --git a/test/backend/assets/sidecar/testimagedesc1.json b/test/backend/assets/sidecar/testimagedesc1.json deleted file mode 100644 index bc0aac3b..00000000 --- a/test/backend/assets/sidecar/testimagedesc1.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "cameraData": { - "ISO": 3200, - "exposure": 0.00125, - "fStop": 5.6, - "focalLength": 85, - "lens": "EF-S15-85mm f/3.5-5.6 IS USM", - "make": "Canon", - "model": "óüöúőűáé ÓÜÖÚŐŰÁÉ" - }, - "caption": "Test caption", - "creationDate": 1434018566690, - "faces": [ - { - "box": { - "height": 2, - "width": 2, - "left": 7, - "top": 3 - }, - "name": "squirrel" - }, - { - "box": { - "height": 3, - "width": 2, - "left": 4, - "top": 4 - }, - "name": "special_chars űáéúőóüío?._:" - } - ], - "fileSize": 39424, - "keywords": [ - "Berkley", - "USA", - "űáéúőóüö ŰÁÉÚŐÓÜÖ" - ], - "positionData": { - "GPSData": { - "latitude": 37.871093, - "longitude": -122.25678 - }, - "city": "test city őúéáűóöí-.,)(=", - "country": "test country őúéáűóöí-.,)(=/%!+\"'", - "state": "test state őúéáűóöí-.,)(" - }, - "rating": 3, - "size": { - "height": 10, - "width": 14 - }, - "title": "Test caption" -} diff --git a/test/backend/assets/sidecar/testimagedesc1.xmp b/test/backend/assets/sidecar/testimagedesc1.xmp deleted file mode 100644 index f27c3386..00000000 --- a/test/backend/assets/sidecar/testimagedesc1.xmp +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - Patrik - - - - - Test caption - - - - - - Copyright test - - - - - Berkley - USA - special_chars űáéúőóüío?._: - squirrel - űáéúőóüö ŰÁÉÚŐÓÜÖ - - - - - Test caption - - - - - - - - - - - - - - Berkley - USA - űáéúőóüö ŰÁÉÚŐÓÜÖ - - - - - Berkley - USA - űáéúőóüö ŰÁÉÚŐÓÜÖ - - - - - - - - - - - - - - - - - - - - - - Berkley - USA - special_chars űáéúőóüío?._: - squirrel - űáéúőóüö ŰÁÉÚŐÓÜÖ - - - - - \ No newline at end of file diff --git a/test/backend/assets/sidecar/testimagedesc2.jpg b/test/backend/assets/sidecar/testimagedesc2.jpg deleted file mode 100644 index f0fa299a..00000000 Binary files a/test/backend/assets/sidecar/testimagedesc2.jpg and /dev/null differ diff --git a/test/backend/assets/sidecar/testimagedesc2.json b/test/backend/assets/sidecar/testimagedesc2.json deleted file mode 100644 index 803e2afd..00000000 --- a/test/backend/assets/sidecar/testimagedesc2.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "cameraData": { - "ISO": 3200, - "exposure": 0.00125, - "fStop": 5.6, - "focalLength": 85, - "lens": "EF-S15-85mm f/3.5-5.6 IS USM", - "make": "Canon", - "model": "óüöúőűáé ÓÜÖÚŐŰÁÉ" - }, - "caption": "Test caption", - "creationDate": 1434018566000, - "faces": [ - { - "box": { - "height": 2, - "width": 2, - "left": 7, - "top": 3 - }, - "name": "squirrel" - }, - { - "box": { - "height": 3, - "width": 2, - "left": 4, - "top": 4 - }, - "name": "special_chars űáéúőóüío?._:" - } - ], - "fileSize": 39424, - "keywords": [ - "Berkley", - "USA", - "űáéúőóüö ŰÁÉÚŐÓÜÖ", - "special_chars űáéúőóüío?._:", - "squirrel" - ], - "positionData": { - "GPSData": { - "latitude": 37.871093, - "longitude": -122.25678 - }, - "city": "test city őúéáűóöí-.,)(=", - "country": "test country őúéáűóöí-.,)(=/%!+\"'", - "state": "test state őúéáűóöí-.,)(" - }, - "rating": 3, - "size": { - "height": 10, - "width": 14 - }, - "title": "Test caption" -} diff --git a/test/backend/assets/sidecar/testimagedesc2.xmp b/test/backend/assets/sidecar/testimagedesc2.xmp deleted file mode 100644 index ca499497..00000000 --- a/test/backend/assets/sidecar/testimagedesc2.xmp +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - US - Sublocation test - - - - - - Patrik - - - - - Test caption - - - - - Copyright test - - - - - Berkley - USA - special_chars űáéúőóüío?._: - squirrel - űáéúőóüö ŰÁÉÚŐÓÜÖ - - - - - Test caption - - - - - - 40761/8200 - 1 - 0 - 2015-06-11T10:29:26 - 0230 - 0/1 - 0 - 6 - 1/800 - 28/5 - - False - False - 2 - False - 0 - - 85/1 - 2 - 1036800/181 - 691200/119 - 90/1 - 37,52.2656N - 122,15.4068W - 2.2.0.0 - - - 3200 - - - 18325/3649 - 5 - 0 - 19307/2002 - 0 - - - - 123063022888 - EF-S15-85mm f/3.5-5.6 IS USM - 0000129324 - - - 15/1 - 85/1 - 0/0 - 0/0 - - - 3200 - 2 - - - - test city őúéáűóöí-.,)(= - test country őúéáűóöí-.,)(=/%!+"' - 2015-06-11T10:29:26 - test state őúéáűóöí-.,)( - - - - Patrik - 6 - - - Copyright test - - - - - Test caption - - - Canon - óüöúőűáé ÓÜÖÚŐŰÁÉ - 1 - 3 - Adobe Photoshop Lightroom 6.1 (Windows) - 94/1 - 94/1 - - - - 2015-06-11T10:29:26 - Adobe Photoshop Lightroom 6.1 (Windows) - 2015-07-24T22:45:50 - - - - \ No newline at end of file diff --git a/test/backend/assets/title_caption/description.json b/test/backend/assets/title_caption/description.json deleted file mode 100644 index 677f3940..00000000 --- a/test/backend/assets/title_caption/description.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "size": { - "width": 3144, - "height": 2288 - }, - "creationDate": -2195790002000, - "fileSize": 8909621, - "keywords": [], - "faces": [ - { - "name": "Hulda Stein", - "box": { - "width": 645, - "height": 645, - "left": 1919, - "top": 547 - } - }, - { - "name": "John Amschler", - "box": { - "width": 709, - "height": 709, - "left": 544, - "top": 394 - } - } - ], - "cameraData": { - "make": "NIKON CORPORATION", - "model": "NIKON D200" - }, - "caption": "Hulda and John's Wedding", - "title": "The Wedding" -} \ No newline at end of file diff --git a/test/backend/assets/title_caption/description.png b/test/backend/assets/title_caption/description.png deleted file mode 100644 index 6f906d67..00000000 Binary files a/test/backend/assets/title_caption/description.png and /dev/null differ diff --git a/test/backend/assets/title_caption/digikam.jpg b/test/backend/assets/title_caption/digikam.jpg deleted file mode 100644 index 534135e4..00000000 Binary files a/test/backend/assets/title_caption/digikam.jpg and /dev/null differ diff --git a/test/backend/assets/title_caption/digikam.json b/test/backend/assets/title_caption/digikam.json deleted file mode 100644 index 87a627a1..00000000 --- a/test/backend/assets/title_caption/digikam.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "cameraData": { - "ISO": 200, - "exposure": 0.008, - "fStop": 2.8, - "focalLength": 9.4, - "make": "FUJIFILM", - "model": "FinePix F601 ZOOM" - }, - "creationDate": 1126423382000, - "creationDateOffset": "+09:00", - "fileSize": 14134, - "size": { - "height": 5, - "width": 7 - }, - "title": "Digikam Title field", - "caption": "Digikam Caption field", - "faces": [ - { - "box": { - "height": 2, - "left": 3, - "top": 2, - "width": 2 - }, - "name": "Æske Øllegård" - } - ], - "keywords": [ - "æÆøØåÅéÉüÜäÄöÖïÏñÑ" - ], - "positionData": { - "GPSData": { - "latitude": 35.9524, - "longitude": 139.863355 - }, - "city": "Shimizu", - "country": "Japan", - "state": "Chiba Ken" - }, - "rating": 4 -} \ No newline at end of file diff --git a/test/backend/assets/wild-2-small.jpg b/test/backend/assets/wild-2-small.jpg new file mode 100644 index 00000000..10ec42a6 Binary files /dev/null and b/test/backend/assets/wild-2-small.jpg differ diff --git a/test/backend/assets/wild-2-small.jpg_original b/test/backend/assets/wild-2-small.jpg_original new file mode 100644 index 00000000..10ec42a6 Binary files /dev/null and b/test/backend/assets/wild-2-small.jpg_original differ diff --git a/test/backend/assets/wild-2-small.json b/test/backend/assets/wild-2-small.json new file mode 100644 index 00000000..6dee39a6 --- /dev/null +++ b/test/backend/assets/wild-2-small.json @@ -0,0 +1,20 @@ +{ + "size": { + "width": 306, + "height": 204 + }, + "creationDate": 1435943085000, + "fileSize": 62306, + "positionData": { + "country": "United States", + "state": "Arizona", + "city": "Williams" + }, + "keywords": ["Akela the wolf", "Balu the bear", "Bearizona", "Hugin the raven", "USA", "USA Road trip"], + "cameraData": { + "make": "Canon", + "model": "Canon EOS 600D", + "lens": "EF-S15-85mm f/3.5-5.6 IS USM" + }, + "creationDateOffset": "-07:00" +} \ No newline at end of file diff --git a/test/backend/unit/model/threading/DiskManagerWorker.spec.ts b/test/backend/unit/model/threading/DiskManagerWorker.spec.ts index a04ee32f..6f901c8d 100644 --- a/test/backend/unit/model/threading/DiskManagerWorker.spec.ts +++ b/test/backend/unit/model/threading/DiskManagerWorker.spec.ts @@ -24,7 +24,7 @@ describe('DiskMangerWorker', () => { ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets'); const dir = await DiskManager.scanDirectory('/'); // should match the number of media (photo/video) files in the assets folder - expect(dir.media.length).to.be.equals(15); + expect(dir.media.length).to.be.equals(16); // eslint-disable-next-line @typescript-eslint/no-var-requires const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json')); const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg'); diff --git a/test/backend/unit/model/threading/MetaDataLoader.spec.ts b/test/backend/unit/model/threading/MetaDataLoader.spec.ts index d52ccd1d..17bc5a44 100644 --- a/test/backend/unit/model/threading/MetaDataLoader.spec.ts +++ b/test/backend/unit/model/threading/MetaDataLoader.spec.ts @@ -35,12 +35,6 @@ describe('MetadataLoader', () => { expect(Utils.clone(data)).to.be.deep.equal(expected); }); - it('should load png with description', async () => { - const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/title_caption/description.png')); - const expected = require(path.join(__dirname, '/../../../assets/title_caption/description.json')); - expect(Utils.clone(data)).to.be.deep.equal(expected); - }); - it('should load jpg', async () => { const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.jpg')); const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json')); @@ -185,9 +179,9 @@ describe('MetadataLoader', () => { const expected = require(path.join(__dirname, '/../../../assets/wild-1-small.json')); expect(Utils.clone(data)).to.be.deep.equal(expected); }); - it('should load image with metadata saved by digikam', async () => { - const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/title_caption/digikam.jpg')); - const expected = require(path.join(__dirname, '/../../../assets/title_caption/digikam.json')); + it('should load wild-2-small image with xmp-CreateDate from 2015 and negative offset', async () => { + const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/wild-2-small.jpg')); + const expected = require(path.join(__dirname, '/../../../assets/wild-2-small.json')); expect(Utils.clone(data)).to.be.deep.equal(expected); });