diff --git a/demo/images/IMG_5910.jpg.xmp b/demo/images/IMG_5910.jpg.xmp new file mode 100644 index 00000000..8ca2fac0 --- /dev/null +++ b/demo/images/IMG_5910.jpg.xmp @@ -0,0 +1,406 @@ + + + + + + US + + + + 50 + + + + 213/100 + 1.0.2 + 0/1 + 0 + EF-S15-85mm f/3.5-5.6 IS USM + 488 + + + + True + 0 + 134348800 + -10 + 0 + 0 + Camera Standard + +26 + 25 + 50 + 50 + +12 + False + 0 + 1 + 0 + 0 + 0.768224 + 0.231776 + 0 + 60 + 40 + 0 + 70 + 30 + 0 + +0.12 + 0 + 0 + 0 + True + True + -83 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + LensDefaults + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 50 + 21 + 0 + 75 + 0 + 0 + 50 + 25 + 0 + 0 + 0 + 0.0 + 100 + 0 + 0 + 0 + 6.7 + IMG_5910.jpg + 0 + 0 + 0 + 0 + -20 + 0 + +27 + 0 + +24 + +27 + 0 + +64 + 25 + 0 + +1.0 + 0 + 0 + 0 + 0 + 0 + 4300 + +20 + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + Linear + Linear + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + + + 0, 0 + 255, 255 + + + 0 + 9.1 + +19 + 0 + +1 + + + + + + Patrik + + + + + Squirrel at berkely + + + image/jpeg + + + Alvin the Squirrel + Berkley + USA + test + + + + + Squirrel at berkely + + + + + + 40761/8200 + 1 + 0 + 2015-06-12T10: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 + 2 + 0 + 2 + 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 + + + + + + Alvin the Squirrel + Berkley + USA + + + + + Alvin the Squirrel + Berkley + USA + + + + + + + + 930 + pixel + 1394 + + + + + + 0.28108 + 0.21731 + 0.57214 + 0.42297 + + Alvin the Squirrel + 0.00000 + Face + + + + + + + + Alvin the Squirrel, Berkley, USA + + + + Berkeley + United States + 2015-06-12 + California + + + + Patrik + + + 8 + + + 6 + + + Squirrel at berkely + + + 930 + 1394 + Canon + Canon EOS 600D + 1 + 3 + Adobe Photoshop Lightroom 6.1 (Windows) + 94/1 + + + 2 + 2 + + + 94/1 + + + + 2015-06-11T10:29:26 + Adobe Photoshop Lightroom 6.1 (Windows) + 2023-09-02T16:18:48+02:00 + 2015-07-24T22:45:50 + 3 + + + + + B6C3AD6C2A4882C8DBC687A5511B328D + B6C3AD6C2A4882C8DBC687A5511B328D + + xmp.did:bbbfe6e4-c352-5441-a4c0-d1a95da2ac63 + + + + derived + converted from image/x-canon-cr2 to image/jpeg, saved to new location + + + saved + / + xmp.iid:bbbfe6e4-c352-5441-a4c0-d1a95da2ac63 + Adobe Photoshop Lightroom 6.1 (Windows) + 2015-07-24T22:45:50+02:00 + + + saved + /metadata + xmp.iid:2ae29592-26ec-d344-ac38-bdbca6a40891 + Adobe Photoshop Lightroom 6.1 (Windows) + 2015-07-24T22:45:51+02:00 + + + saved + /metadata + xmp.iid:bcb273dc-155b-d546-80b8-63148cc30f8b + Adobe Photoshop Lightroom Classic 11.2 (Windows) + 2023-09-02T16:18:48+02:00 + + + + xmp.iid:bcb273dc-155b-d546-80b8-63148cc30f8b + B6C3AD6C2A4882C8DBC687A5511B328D + IMG_5910.jpg + + + + \ No newline at end of file diff --git a/demo/images/bunny.mp4.xmp b/demo/images/bunny.mp4.xmp new file mode 100644 index 00000000..639324df --- /dev/null +++ b/demo/images/bunny.mp4.xmp @@ -0,0 +1,118 @@ + + + + + + 16 + + + + 0.0.0 + + + + H.264 + + + rabbit + test + + + + + + 480 + 852 + 72/1 + 72/1 + + + + 2018-11-17T20:27:31+01:00 + 2018-11-17T20:27:31+01:00 + 2018-11-17T20:27:31+01:00 + + + + + 25Timecode + 00:00:00:00 + + Stereo + 48000 + 16Int + + 1/90000 + 2928000 + + 1 + 25 + + 25Timecode + 00:00:00:00 + + Progressive + 25.000000 + + 480 + pixel + 852 + + 1/1 + + + + + d47681ee-e57e-2256-f455-43c40000004b + 2a5a623f-09cc-ea32-5014-869400000078 + xmp.did:5af8e6dd-2af0-e94e-8f3c-767794b3efa1 + + b2c5763f-bfb9-7ee1-6893-05220000004b + + + + saved + / + 63c4c09c-9648-ee43-720e-644600000078 + Adobe Adobe Media Encoder CC 2017.1 (Windows) + 2018-11-17T20:27:31+01:00 + + + saved + / + 2a5a623f-09cc-ea32-5014-869400000078 + Adobe Adobe Media Encoder CC 2017.1 (Windows) + 2018-11-17T20:26:54+01:00 + + + saved + / + xmp.iid:6e43712c-17f5-cc4c-b90d-766dca2590dc + Adobe Adobe Media Encoder CC 2017.1 (Windows) + 2018-11-17T20:27:31+01:00 + + + saved + /metadata + xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4 + Adobe Adobe Media Encoder CC 2017.1 (Windows) + 2018-11-17T20:27:31+01:00 + + + + xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4 + xmp.did:1aa2d671-bf82-2043-9053-ec864079866c + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 912d4dac..fe5711e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pigallery2", - "version": "2.0.0-rc", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pigallery2", - "version": "2.0.0-rc", + "version": "2.0.0", "license": "MIT", "dependencies": { "archiver": "5.3.1", @@ -16,6 +16,7 @@ "cookie-session": "2.0.0", "csurf": "1.11.0", "ejs": "3.1.8", + "exifr": "7.1.3", "exifreader": "4.10.0", "express": "4.18.2", "express-unless": "2.1.3", @@ -10846,6 +10847,11 @@ "node": ">=4" } }, + "node_modules/exifr": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz", + "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==" + }, "node_modules/exifreader": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.10.0.tgz", @@ -32249,6 +32255,11 @@ "pify": "^2.2.0" } }, + "exifr": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz", + "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==" + }, "exifreader": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.10.0.tgz", diff --git a/package.json b/package.json index 54158f12..db95cf66 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "cookie-session": "2.0.0", "csurf": "1.11.0", "ejs": "3.1.8", + "exifr": "7.1.3", "exifreader": "4.10.0", "express": "4.18.2", "express-unless": "2.1.3", diff --git a/src/backend/model/fileaccess/MetadataLoader.ts b/src/backend/model/fileaccess/MetadataLoader.ts index 0e4915f7..88be5394 100644 --- a/src/backend/model/fileaccess/MetadataLoader.ts +++ b/src/backend/model/fileaccess/MetadataLoader.ts @@ -12,6 +12,8 @@ import {IptcParser} from 'ts-node-iptc'; import {FFmpegFactory} from '../FFmpegFactory'; import {FfprobeData} from 'fluent-ffmpeg'; import {Utils} from '../../../common/Utils'; +import * as exifr from 'exifr'; +import * as path from 'path'; const LOG_TAG = '[MetadataLoader]'; const ffmpeg = FFmpegFactory.get(); @@ -30,6 +32,29 @@ export class MetadataLoader { fileSize: 0, 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 = exifr.sidecar(sidecarPath); + sidecarData.then((response) => { + metadata.keywords = [(response as any).dc.subject].flat(); + }); + } + } + } catch (err) { + // ignoring errors + } + try { const stat = fs.statSync(fullPath); metadata.fileSize = stat.size; @@ -155,6 +180,28 @@ 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 = exifr.sidecar(sidecarPath); + sidecarData.then((response) => { + metadata.keywords = [(response as any).dc.subject].flat(); + }); + } + } + } catch (err) { + // ignoring errors + } + try { const exif = ExifParserFactory.create(data).parse(); if ( diff --git a/src/common/entities/ConentWrapper.ts b/src/common/entities/ConentWrapper.ts index bc3435e3..5bd6e3e2 100644 --- a/src/common/entities/ConentWrapper.ts +++ b/src/common/entities/ConentWrapper.ts @@ -241,7 +241,6 @@ export class ContentWrapper { delete (m as PhotoDTO).metadata.rating; delete (m as PhotoDTO).metadata.caption; delete (m as PhotoDTO).metadata.cameraData; - delete (m as PhotoDTO).metadata.keywords; delete (m as PhotoDTO).metadata.faces; delete (m as PhotoDTO).metadata.positionData; ContentWrapper.mapify(cw, m, isSearchResult); diff --git a/src/common/entities/VideoDTO.ts b/src/common/entities/VideoDTO.ts index d9cefefc..e726c625 100644 --- a/src/common/entities/VideoDTO.ts +++ b/src/common/entities/VideoDTO.ts @@ -15,4 +15,5 @@ export interface VideoMetadata extends MediaMetadata { duration: number; // in milliseconds fileSize: number; fps: number; + keywords?: string[]; }