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[];
}