Merge remote-tracking branch 'origin/master'
# Conflicts: # src/backend/model/extension/ExtensionConfigWrapper.ts
@ -82,9 +82,14 @@ export class MetadataLoader {
|
||||
if (Utils.isInt32(parseInt(stream.avg_frame_rate, 10))) {
|
||||
metadata.fps = parseInt(stream.avg_frame_rate, 10) || null;
|
||||
}
|
||||
metadata.creationDate =
|
||||
Date.parse(stream.tags.creation_time) ||
|
||||
metadata.creationDate;
|
||||
if (
|
||||
stream.tags !== undefined &&
|
||||
typeof stream.tags.creation_time === 'string'
|
||||
) {
|
||||
metadata.creationDate =
|
||||
Date.parse(stream.tags.creation_time) ||
|
||||
metadata.creationDate;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -127,7 +132,7 @@ export class MetadataLoader {
|
||||
|
||||
try {
|
||||
// search for sidecar and merge metadata
|
||||
const fullPathWithoutExt = path.parse(fullPath).name;
|
||||
const fullPathWithoutExt = path.join(path.parse(fullPath).dir, path.parse(fullPath).name);
|
||||
const sidecarPaths = [
|
||||
fullPath + '.xmp',
|
||||
fullPath + '.XMP',
|
||||
@ -139,18 +144,54 @@ export class MetadataLoader {
|
||||
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).dc !== undefined) {
|
||||
if ((sidecarData as SideCar).dc.subject !== undefined) {
|
||||
if (metadata.keywords === undefined) {
|
||||
metadata.keywords = [];
|
||||
}
|
||||
let keywords = (sidecarData as SideCar).dc.subject || [];
|
||||
if (typeof keywords === 'string') {
|
||||
keywords = [keywords];
|
||||
}
|
||||
for (const kw of keywords) {
|
||||
if (metadata.keywords.indexOf(kw) === -1) {
|
||||
metadata.keywords.push(kw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((sidecarData as SideCar).xmp.Rating !== undefined) {
|
||||
metadata.rating = (sidecarData as SideCar).xmp.Rating;
|
||||
let hasPhotoshopDate = false;
|
||||
if ((sidecarData as SideCar).photoshop !== undefined) {
|
||||
if ((sidecarData as SideCar).photoshop.DateCreated !== undefined) {
|
||||
const date = Utils.timestampToMS((sidecarData as SideCar).photoshop.DateCreated, null);
|
||||
if (date) {
|
||||
metadata.creationDate = date;
|
||||
hasPhotoshopDate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.hasOwn(sidecarData, 'xap')) {
|
||||
(sidecarData as any)['xmp'] = (sidecarData as any)['xap'];
|
||||
delete (sidecarData as any)['xap'];
|
||||
}
|
||||
if ((sidecarData as SideCar).xmp !== undefined) {
|
||||
if (
|
||||
(sidecarData as SideCar).xmp.Rating !== undefined &&
|
||||
(sidecarData as SideCar).xmp.Rating > 0
|
||||
) {
|
||||
metadata.rating = (sidecarData as SideCar).xmp.Rating;
|
||||
}
|
||||
if (
|
||||
!hasPhotoshopDate && (
|
||||
(sidecarData as SideCar).xmp.CreateDate !== undefined ||
|
||||
(sidecarData as SideCar).xmp.ModifyDate !== undefined
|
||||
)
|
||||
) {
|
||||
metadata.creationDate =
|
||||
Utils.timestampToMS((sidecarData as SideCar).xmp.CreateDate, null) ||
|
||||
Utils.timestampToMS((sidecarData as SideCar).xmp.ModifyDate, null) ||
|
||||
metadata.creationDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,43 +235,6 @@ export class MetadataLoader {
|
||||
translateValues: false, //don't translate orientation from numbers to strings etc.
|
||||
mergeOutput: false //don't merge output, because things like Microsoft Rating (percent) and xmp.rating will be merged
|
||||
};
|
||||
|
||||
//function to convert timestamp into milliseconds taking offset into account
|
||||
const timestampToMS = (timestamp: string, offset: string) => {
|
||||
if (!timestamp) {
|
||||
return undefined;
|
||||
}
|
||||
//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.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00');
|
||||
} else if (formattedTimestamp.indexOf("+") > 0) { //don't do anything
|
||||
} else { //add offset
|
||||
formattedTimestamp = formattedTimestamp + (offset ? offset : '+00:00');
|
||||
}
|
||||
//parse into MS and return
|
||||
return Date.parse(formattedTimestamp);
|
||||
}
|
||||
|
||||
//function to calculate offset from exif.exif.gpsTimeStamp or exif.gps.GPSDateStamp + exif.gps.GPSTimestamp
|
||||
const getTimeOffsetByGPSStamp = (timestamp: string, gpsTimeStamp: string, gps: any) => {
|
||||
let UTCTimestamp = gpsTimeStamp;
|
||||
if (!UTCTimestamp &&
|
||||
gps &&
|
||||
gps.GPSDateStamp &&
|
||||
gps.GPSTimeStamp) { //else use exif.gps.GPS*Stamp if available
|
||||
//GPS timestamp is always UTC (+00:00)
|
||||
UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + gps.GPSTimeStamp.join(':');
|
||||
}
|
||||
if (UTCTimestamp && timestamp) {
|
||||
//offset in minutes is the difference between gps timestamp and given timestamp
|
||||
//to calculate this correctly, we have to work with the same offset
|
||||
const offsetMinutes = (timestampToMS(timestamp, '+00:00')- timestampToMS(UTCTimestamp, '+00:00')) / 1000 / 60;
|
||||
return Utils.getOffsetString(offsetMinutes);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
//Function to convert html code for special characters into their corresponding character (used in exif.photoshop-section)
|
||||
const unescape = (tag: string) => {
|
||||
@ -364,32 +368,32 @@ export class MetadataLoader {
|
||||
//DateTimeOriginal is when the camera shutter closed
|
||||
let offset = exif.exif.OffsetTimeOriginal; //OffsetTimeOriginal is the corresponding offset
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
offset = exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = timestampToMS(exif.exif.DateTimeOriginal, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.DateTimeOriginal, offset);
|
||||
metadata.creationDateOffset = offset;
|
||||
} else if (exif.exif.CreateDate) { //using else if here, because DateTimeOriginal has preceedence
|
||||
//Create is when the camera wrote the file (typically within the same ms as shutter close)
|
||||
let offset = exif.exif.OffsetTimeDigitized; //OffsetTimeDigitized is the corresponding offset
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.OffsetTimeOriginal || exif.exif.OffsetTime || getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
offset = exif.exif.OffsetTimeOriginal || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = timestampToMS(exif.exif.CreateDate, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.CreateDate, offset);
|
||||
metadata.creationDateOffset = offset;
|
||||
} else if (exif.ifd0?.ModifyDate) { //using else if here, because DateTimeOriginal and CreatDate have preceedence
|
||||
let offset = exif.exif.OffsetTime; //exif.Offsettime is the offset corresponding to ifd0.ModifyDate
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = timestampToMS(exif.ifd0.ModifyDate, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.ifd0.ModifyDate, offset);
|
||||
metadata.creationDateOffset = offset
|
||||
} else if (exif.ihdr && exif.ihdr["Creation Time"]) {// again else if (another fallback date if the good ones aren't there) {
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = timestampToMS(exif.ihdr["Creation Time"], any_offset);
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.ihdr["Creation Time"], any_offset);
|
||||
metadata.creationDateOffset = any_offset;
|
||||
} else if (exif.xmp?.MetadataDate) {// again else if (another fallback date if the good ones aren't there - metadata date is probably later than actual creation date, but much better than file time) {
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = timestampToMS(exif.xmp.MetadataDate, any_offset);
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.xmp.MetadataDate, any_offset);
|
||||
metadata.creationDateOffset = any_offset;
|
||||
}
|
||||
if (exif.exif.LensModel && exif.exif.LensModel !== '') {
|
||||
@ -606,7 +610,7 @@ export class MetadataLoader {
|
||||
|
||||
try {
|
||||
// search for sidecar and merge metadata
|
||||
const fullPathWithoutExt = path.parse(fullPath).name;
|
||||
const fullPathWithoutExt = path.join(path.parse(fullPath).dir, path.parse(fullPath).name);
|
||||
const sidecarPaths = [
|
||||
fullPath + '.xmp',
|
||||
fullPath + '.XMP',
|
||||
@ -619,18 +623,70 @@ export class MetadataLoader {
|
||||
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).dc !== undefined) {
|
||||
if ((sidecarData as SideCar).dc.subject !== undefined) {
|
||||
if (metadata.keywords === undefined) {
|
||||
metadata.keywords = [];
|
||||
}
|
||||
let keywords = (sidecarData as SideCar).dc.subject || [];
|
||||
if (typeof keywords === 'string') {
|
||||
keywords = [keywords];
|
||||
}
|
||||
for (const kw of keywords) {
|
||||
if (metadata.keywords.indexOf(kw) === -1) {
|
||||
metadata.keywords.push(kw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((sidecarData as SideCar).xmp.Rating !== undefined) {
|
||||
metadata.rating = (sidecarData as SideCar).xmp.Rating;
|
||||
let hasPhotoshopDate = false;
|
||||
if ((sidecarData as SideCar).photoshop !== undefined) {
|
||||
if ((sidecarData as SideCar).photoshop.DateCreated !== undefined) {
|
||||
const date = Utils.timestampToMS((sidecarData as SideCar).photoshop.DateCreated, null);
|
||||
if (date) {
|
||||
metadata.creationDate = date;
|
||||
hasPhotoshopDate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.hasOwn(sidecarData, 'xap')) {
|
||||
(sidecarData as any)['xmp'] = (sidecarData as any)['xap'];
|
||||
delete (sidecarData as any)['xap'];
|
||||
}
|
||||
if ((sidecarData as SideCar).xmp !== undefined) {
|
||||
if (
|
||||
(sidecarData as SideCar).xmp.Rating !== undefined &&
|
||||
(sidecarData as SideCar).xmp.Rating > 0
|
||||
) {
|
||||
metadata.rating = (sidecarData as SideCar).xmp.Rating;
|
||||
}
|
||||
if (
|
||||
!hasPhotoshopDate && (
|
||||
(sidecarData as SideCar).xmp.CreateDate !== undefined ||
|
||||
(sidecarData as SideCar).xmp.ModifyDate !== undefined
|
||||
)
|
||||
) {
|
||||
metadata.creationDate =
|
||||
Utils.timestampToMS((sidecarData as SideCar).xmp.CreateDate, null) ||
|
||||
Utils.timestampToMS((sidecarData as SideCar).xmp.ModifyDate, null) ||
|
||||
metadata.creationDate;
|
||||
}
|
||||
}
|
||||
if ((sidecarData as SideCar).exif !== undefined) {
|
||||
if (
|
||||
(sidecarData as SideCar).exif.GPSLatitude !== undefined &&
|
||||
(sidecarData as SideCar).exif.GPSLongitude !== undefined
|
||||
) {
|
||||
metadata.positionData = metadata.positionData || {};
|
||||
metadata.positionData.GPSData = {};
|
||||
|
||||
metadata.positionData.GPSData.longitude = Utils.xmpExifGpsCoordinateToDecimalDegrees(
|
||||
(sidecarData as SideCar).exif.GPSLongitude
|
||||
);
|
||||
metadata.positionData.GPSData.latitude = Utils.xmpExifGpsCoordinateToDecimalDegrees(
|
||||
(sidecarData as SideCar).exif.GPSLatitude
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,43 @@ export class Utils {
|
||||
return new Date(new Date(d).toISOString().substring(0,19) + (offset ? offset : '')).getFullYear();
|
||||
}
|
||||
|
||||
//function to convert timestamp into milliseconds taking offset into account
|
||||
static timestampToMS(timestamp: string, offset: string) {
|
||||
if (!timestamp) {
|
||||
return undefined;
|
||||
}
|
||||
//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.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00');
|
||||
} else if (formattedTimestamp.indexOf("+") > 0) { //don't do anything
|
||||
} else { //add offset
|
||||
formattedTimestamp = formattedTimestamp + (offset ? offset : '+00:00');
|
||||
}
|
||||
//parse into MS and return
|
||||
return Date.parse(formattedTimestamp);
|
||||
}
|
||||
|
||||
//function to calculate offset from exif.exif.gpsTimeStamp or exif.gps.GPSDateStamp + exif.gps.GPSTimestamp
|
||||
static getTimeOffsetByGPSStamp(timestamp: string, gpsTimeStamp: string, gps: any) {
|
||||
let UTCTimestamp = gpsTimeStamp;
|
||||
if (!UTCTimestamp &&
|
||||
gps &&
|
||||
gps.GPSDateStamp &&
|
||||
gps.GPSTimeStamp) { //else use exif.gps.GPS*Stamp if available
|
||||
//GPS timestamp is always UTC (+00:00)
|
||||
UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + gps.GPSTimeStamp.join(':');
|
||||
}
|
||||
if (UTCTimestamp && timestamp) {
|
||||
//offset in minutes is the difference between gps timestamp and given timestamp
|
||||
//to calculate this correctly, we have to work with the same offset
|
||||
const offsetMinutes = (Utils.timestampToMS(timestamp, '+00:00')- Utils.timestampToMS(UTCTimestamp, '+00:00')) / 1000 / 60;
|
||||
return Utils.getOffsetString(offsetMinutes);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static getOffsetString(offsetMinutes: number) {
|
||||
if (-720 <= offsetMinutes && offsetMinutes <= 840) {
|
||||
//valid offset is within -12 and +14 hrs (https://en.wikipedia.org/wiki/List_of_UTC_offsets)
|
||||
@ -344,6 +381,14 @@ export class Utils {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static xmpExifGpsCoordinateToDecimalDegrees(text: string): number {
|
||||
const parts = text.match(/^([0-9]+),([0-9.]+)([EWNS])$/);
|
||||
const degrees: number = parseInt(parts[1], 10);
|
||||
const minutes: number = parseFloat(parts[2]);
|
||||
const sign = (parts[3] === "N" || parts[3] === "E") ? 1 : -1;
|
||||
return sign * (degrees + (minutes / 60.0))
|
||||
}
|
||||
}
|
||||
|
||||
export class LRU<V> {
|
||||
|
@ -30,8 +30,15 @@ export interface MediaDimension {
|
||||
}
|
||||
|
||||
export interface SideCar {
|
||||
exif?: SideCarExif;
|
||||
dc?: SideCarDc;
|
||||
xmp?: SideCarXmp;
|
||||
photoshop?: SideCarPhotoshop;
|
||||
}
|
||||
|
||||
export interface SideCarExif {
|
||||
GPSLatitude?: string;
|
||||
GPSLongitude?: string;
|
||||
}
|
||||
|
||||
export interface SideCarDc {
|
||||
@ -40,6 +47,14 @@ export interface SideCarDc {
|
||||
|
||||
export interface SideCarXmp {
|
||||
Rating?: RatingTypes;
|
||||
CreateDate?: string;
|
||||
ModifyDate?: string;
|
||||
}
|
||||
|
||||
export interface SideCarPhotoshop {
|
||||
// Corresponds to Exif.Photo.DateTimeOriginal. No corresponding key exists in
|
||||
// the xmp namespace!
|
||||
DateCreated?: string;
|
||||
}
|
||||
|
||||
export const MediaDTOUtils = {
|
||||
|
BIN
test/backend/assets/sidecar/20240107_110258.jpg
Normal file
After Width: | Height: | Size: 15 KiB |
73
test/backend/assets/sidecar/20240107_110258.jpg.xmp
Normal file
@ -0,0 +1,73 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:xap="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
||||
xmlns:digiKam="http://www.digikam.org/ns/1.0/"
|
||||
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xap:Rating="3"
|
||||
xap:CreatorTool="digiKam-8.2.0"
|
||||
xap:ModifyDate="2024-01-07T11:02:59.177"
|
||||
xap:CreateDate="2024-01-07T11:02:59.177"
|
||||
exif:GPSVersionID="2.0.0.0"
|
||||
exif:GPSLatitude="50,5.3752490N"
|
||||
exif:GPSLongitude="14,23.8445710E"
|
||||
exif:GPSMapDatum="WGS-84"
|
||||
exif:ExifVersion="0220"
|
||||
exif:PixelXDimension="10"
|
||||
exif:PixelYDimension="13"
|
||||
exif:ExposureTime="1/105"
|
||||
exif:FNumber="220/100"
|
||||
exif:ExposureProgram="2"
|
||||
exif:ShutterSpeedValue="1/105"
|
||||
exif:ApertureValue="227/100"
|
||||
exif:BrightnessValue="0/100"
|
||||
exif:ExposureBiasValue="0/100"
|
||||
exif:MaxApertureValue="227/100"
|
||||
exif:MeteringMode="2"
|
||||
exif:FocalLength="375/100"
|
||||
exif:ExposureMode="0"
|
||||
exif:WhiteBalance="0"
|
||||
exif:DigitalZoomRatio="100/100"
|
||||
exif:FocalLengthIn35mmFilm="25"
|
||||
exif:SceneCaptureType="0"
|
||||
exif:ImageUniqueID="A64QLMD00YM"
|
||||
tiff:ImageWidth="10"
|
||||
tiff:ImageLength="13"
|
||||
tiff:Orientation="1"
|
||||
tiff:YCbCrPositioning="1"
|
||||
tiff:XResolution="72/1"
|
||||
tiff:YResolution="72/1"
|
||||
tiff:ResolutionUnit="2"
|
||||
tiff:Make="samsung"
|
||||
tiff:Model="SM-A715F"
|
||||
tiff:Software="digiKam-8.2.0"
|
||||
photoshop:DateCreated="2024-01-07T11:02:59.177">
|
||||
<exif:Flash
|
||||
exif:Fired="False"
|
||||
exif:Return="0"
|
||||
exif:Mode="0"
|
||||
exif:Function="False"
|
||||
exif:RedEyeMode="False"/>
|
||||
<exif:ISOSpeedRatings>
|
||||
<rdf:Seq>
|
||||
<rdf:li>40</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ISOSpeedRatings>
|
||||
<digiKam:TagsList>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Seq>
|
||||
</digiKam:TagsList>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
28
test/backend/assets/sidecar/20240107_110258.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"cameraData": {
|
||||
"ISO": 40,
|
||||
"exposure": 0.009524,
|
||||
"fStop": 2.2,
|
||||
"focalLength": 3.75,
|
||||
"make": "samsung",
|
||||
"model": "SM-A715F"
|
||||
},
|
||||
"creationDate": 1704625379177,
|
||||
"creationDateOffset": "+01:00",
|
||||
"fileSize": 15126,
|
||||
"size": {
|
||||
"height": 13,
|
||||
"width": 10
|
||||
},
|
||||
"keywords": [
|
||||
"Výlet",
|
||||
"Travel"
|
||||
],
|
||||
"positionData": {
|
||||
"GPSData": {
|
||||
"latitude": 50.08958748333333,
|
||||
"longitude": 14.397409516666666
|
||||
}
|
||||
},
|
||||
"rating": 3
|
||||
}
|
BIN
test/backend/assets/sidecar/20240121_102400.JPG
Executable file
After Width: | Height: | Size: 25 KiB |
91
test/backend/assets/sidecar/20240121_102400.JPG.xmp
Normal file
@ -0,0 +1,91 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
||||
xmlns:digiKam="http://www.digikam.org/ns/1.0/"
|
||||
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
||||
xmp:CreatorTool="NIKON Z 30 Ver.01.00 "
|
||||
xmp:Rating="3"
|
||||
xmp:ModifyDate="2024-03-04T12:03:45.65"
|
||||
xmp:CreateDate="2024-03-04T12:03:45.65"
|
||||
exif:GPSLatitude="50,5.3752490N"
|
||||
exif:GPSLongitude="14,23.8445710E"
|
||||
exif:GPSMapDatum="WGS-84"
|
||||
exif:ExifVersion="0231"
|
||||
exif:FlashpixVersion="0100"
|
||||
exif:CompressedBitsPerPixel="4/1"
|
||||
exif:PixelXDimension="15"
|
||||
exif:PixelYDimension="10"
|
||||
exif:ExposureTime="10/3200"
|
||||
exif:FNumber="630/100"
|
||||
exif:ExposureProgram="0"
|
||||
exif:ExposureBiasValue="4/6"
|
||||
exif:MeteringMode="5"
|
||||
exif:LightSource="11"
|
||||
exif:FocalLength="160/10"
|
||||
exif:SensingMethod="2"
|
||||
exif:FileSource="3"
|
||||
exif:SceneType="1"
|
||||
exif:CFAPattern="2 0 2 0 0 1 1 2"
|
||||
exif:CustomRendered="1"
|
||||
exif:ExposureMode="0"
|
||||
exif:WhiteBalance="1"
|
||||
exif:FocalLengthIn35mmFilm="24"
|
||||
exif:SceneCaptureType="0"
|
||||
exif:GainControl="0"
|
||||
exif:Contrast="0"
|
||||
exif:Saturation="0"
|
||||
exif:Sharpness="0"
|
||||
exif:SubjectDistanceRange="0"
|
||||
exif:GPSVersionID="2.3.0.0"
|
||||
tiff:ImageWidth="15"
|
||||
tiff:ImageLength="10"
|
||||
tiff:Orientation="1"
|
||||
tiff:YCbCrPositioning="2"
|
||||
tiff:XResolution="300/1"
|
||||
tiff:YResolution="300/1"
|
||||
tiff:ResolutionUnit="2"
|
||||
tiff:Make="NIKON CORPORATION"
|
||||
tiff:Model="NIKON Z 30"
|
||||
tiff:Software="digiKam-8.2.0"
|
||||
photoshop:DateCreated="2024-01-21T10:24:00.93">
|
||||
<exif:Flash
|
||||
exif:Fired="False"
|
||||
exif:Return="0"
|
||||
exif:Mode="0"
|
||||
exif:Function="False"
|
||||
exif:RedEyeMode="False"/>
|
||||
<exif:ComponentsConfiguration>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1</rdf:li>
|
||||
<rdf:li>2</rdf:li>
|
||||
<rdf:li>3</rdf:li>
|
||||
<rdf:li>0</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ComponentsConfiguration>
|
||||
<exif:ISOSpeedRatings>
|
||||
<rdf:Seq>
|
||||
<rdf:li>100</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ISOSpeedRatings>
|
||||
<digiKam:TagsList>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Seq>
|
||||
</digiKam:TagsList>
|
||||
<dc:creator>
|
||||
<rdf:Seq/>
|
||||
</dc:creator>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
29
test/backend/assets/sidecar/20240121_102400.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"cameraData": {
|
||||
"ISO": 100,
|
||||
"exposure": 0.003125,
|
||||
"fStop": 6.3,
|
||||
"focalLength": 16,
|
||||
"lens": "NIKKOR Z DX 16-50mm f/3.5-6.3 VR",
|
||||
"make": "NIKON CORPORATION",
|
||||
"model": "NIKON Z 30"
|
||||
},
|
||||
"creationDate": 1705832640930,
|
||||
"creationDateOffset": "+01:00",
|
||||
"fileSize": 25556,
|
||||
"size": {
|
||||
"height": 10,
|
||||
"width": 15
|
||||
},
|
||||
"keywords": [
|
||||
"Výlet",
|
||||
"Travel"
|
||||
],
|
||||
"positionData": {
|
||||
"GPSData": {
|
||||
"latitude": 50.08958748333333,
|
||||
"longitude": 14.397409516666666
|
||||
}
|
||||
},
|
||||
"rating": 3
|
||||
}
|
15
test/backend/assets/sidecar/20240128_105420.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"bitRate": 184871,
|
||||
"creationDate": 1706435660000,
|
||||
"duration": 1000,
|
||||
"fileSize": 23132,
|
||||
"size": {
|
||||
"height": 46,
|
||||
"width": 80
|
||||
},
|
||||
"fps": 60000,
|
||||
"keywords": [
|
||||
"Travel"
|
||||
],
|
||||
"rating": 3
|
||||
}
|
BIN
test/backend/assets/sidecar/20240128_105420.mp4
Normal file
115
test/backend/assets/sidecar/20240128_105420.mp4.xmp
Normal file
@ -0,0 +1,115 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:video="http://www.video/"
|
||||
xmlns:xmpDM="http://ns.adobe.com/xmp/1.0/DynamicMedia/"
|
||||
xmlns:audio="http://www.audio/"
|
||||
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
||||
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
||||
xmlns:xap="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/"
|
||||
xmlns:LImage="http://ns.leiainc.com/photos/1.0/image/"
|
||||
xmlns:digiKam="http://www.digikam.org/ns/1.0/"
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
video:duration="1001"
|
||||
video:MaxBitRate="184871"
|
||||
video:StreamCount="3"
|
||||
video:Codec="h264"
|
||||
video:CodecDescription="H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"
|
||||
video:Format="yuv420p"
|
||||
video:ColorMode="bt709"
|
||||
video:ColorSpace="CCIR-709"
|
||||
video:Width="80"
|
||||
video:FrameWidth="80"
|
||||
video:SourceImageWidth="80"
|
||||
video:Height="46"
|
||||
video:FrameHeight="46"
|
||||
video:SourceImageHeight="46"
|
||||
video:FrameSize="w:80, h:46, unit:pixels"
|
||||
video:AspectRatio="80/46"
|
||||
video:FrameRate="59.9401"
|
||||
video:BitDepth="24"
|
||||
video:Language="eng"
|
||||
video:TrackCreateDate="3789284060"
|
||||
video:HandlerDescription="VideoHandler"
|
||||
video:MajorBrand="qt "
|
||||
video:CompatibleBrands="qt niko"
|
||||
video:MinorVersion="538315008"
|
||||
video:Encoder="Lavf60.16.100"
|
||||
video:DateTimeOriginal="2024-01-28T09:54:20"
|
||||
video:DateUTC="2024-01-28T09:54:20"
|
||||
video:ModificationDate="2024-01-28T09:54:20"
|
||||
video:DateTimeDigitized="2024-01-28T09:54:20"
|
||||
video:FileName="DSC_1928_20240128_105420_80p.mp4"
|
||||
video:FileSize="0"
|
||||
video:FileType="mp4"
|
||||
video:MimeType="video/mp4"
|
||||
xmpDM:duration="1001"
|
||||
xmpDM:videoColorSpace="CCIR-709"
|
||||
xmpDM:FieldOrder="Progressive"
|
||||
xmpDM:videoFrameSize="w:80, h:46, unit:pixels"
|
||||
xmpDM:videoPixelAspectRatio="80/46"
|
||||
xmpDM:videoFrameRate="59.94"
|
||||
xmpDM:videoPixelDepth="8Int"
|
||||
xmpDM:shotDate="ne led 28 10:54:20 2024"
|
||||
xmpDM:audioSampleRate="48000"
|
||||
xmpDM:audioChannelType="Stereo"
|
||||
xmpDM:audioSampleType="32Float"
|
||||
audio:Codec="aac"
|
||||
audio:CodecDescription="AAC (Advanced Audio Coding)"
|
||||
audio:SampleRate="48000"
|
||||
audio:ChannelType="Stereo"
|
||||
audio:Format="fltp"
|
||||
audio:SampleType="32Float"
|
||||
audio:TrackLang="eng"
|
||||
audio:TrackCreateDate="3789284060"
|
||||
audio:HandlerDescription="SoundHandler"
|
||||
exif:DateTimeOriginal="2024-01-28T09:54:20"
|
||||
exif:DateTimeDigitized="2024-01-28T09:54:20"
|
||||
exif:ExifVersion="0232"
|
||||
exif:FlashpixVersion="0100"
|
||||
exif:ColorSpace="65535"
|
||||
exif:PixelXDimension="80"
|
||||
exif:PixelYDimension="46"
|
||||
exif:GPSVersionID="2.0.0.0"
|
||||
exif:GPSLatitude="50,5.3752490N"
|
||||
exif:GPSLongitude="14,23.8445710E"
|
||||
exif:GPSMapDatum="WGS-84"
|
||||
tiff:DateTime="2024-01-28T09:54:20"
|
||||
tiff:ImageWidth="80"
|
||||
tiff:ImageLength="46"
|
||||
tiff:YCbCrPositioning="1"
|
||||
tiff:XResolution="72/1"
|
||||
tiff:YResolution="72/1"
|
||||
tiff:ResolutionUnit="2"
|
||||
xap:MetadataDate="2024-01-28T09:54:20"
|
||||
xap:Rating="3"
|
||||
xap:ModifyDate="2024-01-28T09:54:20"
|
||||
xap:CreateDate="2024-01-28T09:54:20"
|
||||
Iptc4xmpExt:audioBitsPerSample="16"
|
||||
LImage:MinorVersion="538315008"
|
||||
photoshop:DateCreated="2024-01-28T09:54:20">
|
||||
<exif:ComponentsConfiguration>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1</rdf:li>
|
||||
<rdf:li>2</rdf:li>
|
||||
<rdf:li>3</rdf:li>
|
||||
<rdf:li>0</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ComponentsConfiguration>
|
||||
<digiKam:TagsList>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Seq>
|
||||
</digiKam:TagsList>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
15
test/backend/assets/sidecar/20240128_120909.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"bitRate": 183168,
|
||||
"creationDate": 1706440145000,
|
||||
"duration": 1000,
|
||||
"fileSize": 22896,
|
||||
"size": {
|
||||
"height": 80,
|
||||
"width": 46
|
||||
},
|
||||
"fps": 30,
|
||||
"keywords": [
|
||||
"Travel"
|
||||
],
|
||||
"rating": 3
|
||||
}
|
BIN
test/backend/assets/sidecar/20240128_120909.mp4
Normal file
117
test/backend/assets/sidecar/20240128_120909.mp4.xmp
Normal file
@ -0,0 +1,117 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:video="http://www.video/"
|
||||
xmlns:xmpDM="http://ns.adobe.com/xmp/1.0/DynamicMedia/"
|
||||
xmlns:audio="http://www.audio/"
|
||||
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
||||
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
||||
xmlns:xap="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/"
|
||||
xmlns:LImage="http://ns.leiainc.com/photos/1.0/image/"
|
||||
xmlns:digiKam="http://www.digikam.org/ns/1.0/"
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
video:duration="1000"
|
||||
video:MaxBitRate="183168"
|
||||
video:StreamCount="2"
|
||||
video:Codec="h264"
|
||||
video:CodecDescription="H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"
|
||||
video:Format="yuv420p"
|
||||
video:ColorMode="bt709"
|
||||
video:ColorSpace="CCIR-709"
|
||||
video:Width="80"
|
||||
video:FrameWidth="80"
|
||||
video:SourceImageWidth="80"
|
||||
video:Height="46"
|
||||
video:FrameHeight="46"
|
||||
video:SourceImageHeight="46"
|
||||
video:FrameSize="w:80, h:46, unit:pixels"
|
||||
video:AspectRatio="16/9"
|
||||
video:FrameRate="30"
|
||||
video:BitDepth="24"
|
||||
video:Orientation="6"
|
||||
video:Language="und"
|
||||
video:TrackCreateDate="3789288545"
|
||||
video:HandlerDescription="VideoHandler"
|
||||
video:MajorBrand="mp42"
|
||||
video:CompatibleBrands="mp42mp41isomiso2"
|
||||
video:MinorVersion="0"
|
||||
video:Encoder="Lavf60.16.100"
|
||||
video:DateTimeOriginal="2024-01-28T11:09:05"
|
||||
video:DateUTC="2024-01-28T11:09:05"
|
||||
video:ModificationDate="2024-01-28T11:09:05"
|
||||
video:DateTimeDigitized="2024-01-28T11:09:05"
|
||||
video:FileName="20240128_120909_80p.mp4"
|
||||
video:FileSize="0"
|
||||
video:FileType="mp4"
|
||||
video:MimeType="video/mp4"
|
||||
xmpDM:duration="1000"
|
||||
xmpDM:videoColorSpace="CCIR-709"
|
||||
xmpDM:FieldOrder="Progressive"
|
||||
xmpDM:videoFrameSize="w:80, h:46, unit:pixels"
|
||||
xmpDM:videoPixelAspectRatio="16/9"
|
||||
xmpDM:videoFrameRate="30"
|
||||
xmpDM:videoPixelDepth="8Int"
|
||||
xmpDM:shotDate="ne led 28 12:09:05 2024"
|
||||
xmpDM:audioSampleRate="48000"
|
||||
xmpDM:audioChannelType="Stereo"
|
||||
xmpDM:audioSampleType="32Float"
|
||||
audio:Codec="aac"
|
||||
audio:CodecDescription="AAC (Advanced Audio Coding)"
|
||||
audio:SampleRate="48000"
|
||||
audio:ChannelType="Stereo"
|
||||
audio:Format="fltp"
|
||||
audio:SampleType="32Float"
|
||||
audio:TrackLang="und"
|
||||
audio:TrackCreateDate="3789288545"
|
||||
audio:HandlerDescription="SoundHandler"
|
||||
exif:DateTimeOriginal="2024-01-28T11:09:05"
|
||||
exif:DateTimeDigitized="2024-01-28T11:09:05"
|
||||
exif:ExifVersion="0232"
|
||||
exif:FlashpixVersion="0100"
|
||||
exif:ColorSpace="65535"
|
||||
exif:PixelXDimension="80"
|
||||
exif:PixelYDimension="46"
|
||||
exif:GPSVersionID="2.0.0.0"
|
||||
exif:GPSLatitude="50,5.3752490N"
|
||||
exif:GPSLongitude="14,23.8445710E"
|
||||
exif:GPSMapDatum="WGS-84"
|
||||
tiff:DateTime="2024-01-28T11:09:05"
|
||||
tiff:ImageWidth="81"
|
||||
tiff:ImageLength="46"
|
||||
tiff:Orientation="6"
|
||||
tiff:YCbCrPositioning="1"
|
||||
tiff:XResolution="72/1"
|
||||
tiff:YResolution="72/1"
|
||||
tiff:ResolutionUnit="2"
|
||||
xap:MetadataDate="2024-01-28T11:09:05"
|
||||
xap:Rating="3"
|
||||
xap:ModifyDate="2024-01-28T11:09:05"
|
||||
xap:CreateDate="2024-01-28T11:09:05"
|
||||
Iptc4xmpExt:audioBitsPerSample="16"
|
||||
LImage:MinorVersion="0"
|
||||
photoshop:DateCreated="2024-01-28T11:09:05">
|
||||
<exif:ComponentsConfiguration>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1</rdf:li>
|
||||
<rdf:li>2</rdf:li>
|
||||
<rdf:li>3</rdf:li>
|
||||
<rdf:li>0</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ComponentsConfiguration>
|
||||
<digiKam:TagsList>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Seq>
|
||||
</digiKam:TagsList>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
BIN
test/backend/assets/sidecar/20240128_185808.JPG
Normal file
After Width: | Height: | Size: 46 KiB |
114
test/backend/assets/sidecar/20240128_185808.JPG.xmp
Normal file
@ -0,0 +1,114 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:exif="http://ns.adobe.com/exif/1.0/"
|
||||
xmlns:acdsee="http://ns.acdsee.com/iptc/1.0/"
|
||||
xmlns:MicrosoftPhoto="http://ns.microsoft.com/photo/1.0/"
|
||||
xmlns:digiKam="http://www.digikam.org/ns/1.0/"
|
||||
xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
|
||||
xmlns:mediapro="http://ns.iview-multimedia.com/mediapro/1.0/"
|
||||
xmlns:tiff="http://ns.adobe.com/tiff/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
|
||||
xmp:CreatorTool="NIKON Z 30 Ver.01.00 "
|
||||
xmp:Rating="3"
|
||||
xmp:ModifyDate="2024-01-28T18:58:08.66"
|
||||
xmp:CreateDate="2024-01-28T18:58:08.66"
|
||||
exif:GPSLatitude="50,5.3752490N"
|
||||
exif:GPSLongitude="14,23.8445710E"
|
||||
exif:GPSMapDatum="WGS-84"
|
||||
exif:ExifVersion="0231"
|
||||
exif:FlashpixVersion="0100"
|
||||
exif:CompressedBitsPerPixel="4/1"
|
||||
exif:PixelXDimension="15"
|
||||
exif:PixelYDimension="10"
|
||||
exif:ExposureTime="10/250"
|
||||
exif:FNumber="420/100"
|
||||
exif:ExposureProgram="2"
|
||||
exif:ExposureBiasValue="0/6"
|
||||
exif:MeteringMode="5"
|
||||
exif:LightSource="0"
|
||||
exif:FocalLength="250/10"
|
||||
exif:SensingMethod="2"
|
||||
exif:FileSource="3"
|
||||
exif:SceneType="1"
|
||||
exif:CFAPattern="2 0 2 0 0 1 1 2"
|
||||
exif:CustomRendered="1"
|
||||
exif:ExposureMode="0"
|
||||
exif:WhiteBalance="0"
|
||||
exif:FocalLengthIn35mmFilm="37"
|
||||
exif:SceneCaptureType="0"
|
||||
exif:GainControl="2"
|
||||
exif:Contrast="0"
|
||||
exif:Saturation="0"
|
||||
exif:Sharpness="0"
|
||||
exif:SubjectDistanceRange="0"
|
||||
exif:GPSVersionID="2.3.0.0"
|
||||
acdsee:categories="<Categories><Category Assigned="1">Travel</Category></Categories>"
|
||||
acdsee:rating="3"
|
||||
MicrosoftPhoto:Rating="50"
|
||||
tiff:ImageWidth="15"
|
||||
tiff:ImageLength="10"
|
||||
tiff:Orientation="1"
|
||||
tiff:YCbCrPositioning="2"
|
||||
tiff:XResolution="300/1"
|
||||
tiff:YResolution="300/1"
|
||||
tiff:ResolutionUnit="2"
|
||||
tiff:Make="NIKON CORPORATION"
|
||||
tiff:Model="NIKON Z 30"
|
||||
tiff:Software="digiKam-8.2.0"
|
||||
photoshop:DateCreated="2024-01-28T18:58:08.66"
|
||||
photoshop:Urgency="4">
|
||||
<exif:Flash
|
||||
exif:Fired="False"
|
||||
exif:Return="0"
|
||||
exif:Mode="0"
|
||||
exif:Function="False"
|
||||
exif:RedEyeMode="False"/>
|
||||
<exif:ComponentsConfiguration>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1</rdf:li>
|
||||
<rdf:li>2</rdf:li>
|
||||
<rdf:li>3</rdf:li>
|
||||
<rdf:li>0</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ComponentsConfiguration>
|
||||
<exif:ISOSpeedRatings>
|
||||
<rdf:Seq>
|
||||
<rdf:li>25600</rdf:li>
|
||||
</rdf:Seq>
|
||||
</exif:ISOSpeedRatings>
|
||||
<MicrosoftPhoto:LastKeywordXMP>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</MicrosoftPhoto:LastKeywordXMP>
|
||||
<digiKam:TagsList>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Seq>
|
||||
</digiKam:TagsList>
|
||||
<lr:hierarchicalSubject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</lr:hierarchicalSubject>
|
||||
<mediapro:CatalogSets>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</mediapro:CatalogSets>
|
||||
<dc:creator>
|
||||
<rdf:Seq/>
|
||||
</dc:creator>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>Travel</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
29
test/backend/assets/sidecar/20240128_185808.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"cameraData": {
|
||||
"ISO": 25600,
|
||||
"exposure": 0.04,
|
||||
"fStop": 4.2,
|
||||
"focalLength": 25,
|
||||
"lens": "NIKKOR Z DX 16-50mm f/3.5-6.3 VR",
|
||||
"make": "NIKON CORPORATION",
|
||||
"model": "NIKON Z 30"
|
||||
},
|
||||
"creationDate": 1706468288660,
|
||||
"creationDateOffset": "+01:00",
|
||||
"fileSize": 47059,
|
||||
"size": {
|
||||
"height": 10,
|
||||
"width": 15
|
||||
},
|
||||
"keywords": [
|
||||
"Výlet",
|
||||
"Travel"
|
||||
],
|
||||
"positionData": {
|
||||
"GPSData": {
|
||||
"latitude": 50.08958748333333,
|
||||
"longitude": 14.397409516666666
|
||||
}
|
||||
},
|
||||
"rating": 3
|
||||
}
|
16
test/backend/assets/sidecar/bunny_1sec.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
},
|
||||
"bitRate": 1794127,
|
||||
"duration": 290,
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 65073,
|
||||
"fps": 40000,
|
||||
"keywords": [
|
||||
"rabbit",
|
||||
"test"
|
||||
],
|
||||
"rating": 4
|
||||
}
|
BIN
test/backend/assets/sidecar/bunny_1sec.mp4
Normal file
119
test/backend/assets/sidecar/bunny_1sec.mp4.xmp
Normal file
@ -0,0 +1,119 @@
|
||||
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
||||
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 12.69'>
|
||||
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
|
||||
<Iptc4xmpExt:audioBitsPerSample>16</Iptc4xmpExt:audioBitsPerSample>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:LImage='http://ns.leiainc.com/photos/1.0/image/'>
|
||||
<LImage:MinorVersion>0.0.0</LImage:MinorVersion>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:dc='http://purl.org/dc/elements/1.1/'>
|
||||
<dc:format>H.264</dc:format>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>rabbit</rdf:li>
|
||||
<rdf:li>test</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:tiff='http://ns.adobe.com/tiff/1.0/'>
|
||||
<tiff:ImageLength>480</tiff:ImageLength>
|
||||
<tiff:ImageWidth>852</tiff:ImageWidth>
|
||||
<tiff:XResolution>72/1</tiff:XResolution>
|
||||
<tiff:YResolution>72/1</tiff:YResolution>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
<xmp:Rating>4</xmp:Rating>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stDim='http://ns.adobe.com/xap/1.0/sType/Dimensions#'
|
||||
xmlns:xmpDM='http://ns.adobe.com/xmp/1.0/DynamicMedia/'>
|
||||
<xmpDM:altTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:altTimecode>
|
||||
<xmpDM:audioChannelType>Stereo</xmpDM:audioChannelType>
|
||||
<xmpDM:audioSampleRate>48000</xmpDM:audioSampleRate>
|
||||
<xmpDM:audioSampleType>16Int</xmpDM:audioSampleType>
|
||||
<xmpDM:duration rdf:parseType='Resource'>
|
||||
<xmpDM:scale>1/90000</xmpDM:scale>
|
||||
<xmpDM:value>2928000</xmpDM:value>
|
||||
</xmpDM:duration>
|
||||
<xmpDM:startTimeSampleSize>1</xmpDM:startTimeSampleSize>
|
||||
<xmpDM:startTimeScale>25</xmpDM:startTimeScale>
|
||||
<xmpDM:startTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:startTimecode>
|
||||
<xmpDM:videoFieldOrder>Progressive</xmpDM:videoFieldOrder>
|
||||
<xmpDM:videoFrameRate>25.000000</xmpDM:videoFrameRate>
|
||||
<xmpDM:videoFrameSize rdf:parseType='Resource'>
|
||||
<stDim:h>480</stDim:h>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
<stDim:w>852</stDim:w>
|
||||
</xmpDM:videoFrameSize>
|
||||
<xmpDM:videoPixelAspectRatio>1/1</xmpDM:videoPixelAspectRatio>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stEvt='http://ns.adobe.com/xap/1.0/sType/ResourceEvent#'
|
||||
xmlns:stRef='http://ns.adobe.com/xap/1.0/sType/ResourceRef#'
|
||||
xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/'>
|
||||
<xmpMM:DerivedFrom rdf:parseType='Resource'>
|
||||
<stRef:documentID>d47681ee-e57e-2256-f455-43c40000004b</stRef:documentID>
|
||||
<stRef:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stRef:instanceID>
|
||||
<stRef:originalDocumentID>xmp.did:5af8e6dd-2af0-e94e-8f3c-767794b3efa1</stRef:originalDocumentID>
|
||||
</xmpMM:DerivedFrom>
|
||||
<xmpMM:DocumentID>b2c5763f-bfb9-7ee1-6893-05220000004b</xmpMM:DocumentID>
|
||||
<xmpMM:History>
|
||||
<rdf:Seq>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>63c4c09c-9648-ee43-720e-644600000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:26:54+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:6e43712c-17f5-cc4c-b90d-766dca2590dc</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/metadata</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</xmpMM:History>
|
||||
<xmpMM:InstanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</xmpMM:InstanceID>
|
||||
<xmpMM:OriginalDocumentID>xmp.did:1aa2d671-bf82-2043-9053-ec864079866c</xmpMM:OriginalDocumentID>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end='w'?>
|
16
test/backend/assets/sidecar/bunny_1sec_v2.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
},
|
||||
"bitRate": 1794127,
|
||||
"duration": 290,
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 65073,
|
||||
"fps": 40000,
|
||||
"keywords": [
|
||||
"rabbit",
|
||||
"test"
|
||||
],
|
||||
"rating": 4
|
||||
}
|
BIN
test/backend/assets/sidecar/bunny_1sec_v2.mp4
Normal file
119
test/backend/assets/sidecar/bunny_1sec_v2.xmp
Normal file
@ -0,0 +1,119 @@
|
||||
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
||||
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 12.69'>
|
||||
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
|
||||
<Iptc4xmpExt:audioBitsPerSample>16</Iptc4xmpExt:audioBitsPerSample>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:LImage='http://ns.leiainc.com/photos/1.0/image/'>
|
||||
<LImage:MinorVersion>0.0.0</LImage:MinorVersion>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:dc='http://purl.org/dc/elements/1.1/'>
|
||||
<dc:format>H.264</dc:format>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>rabbit</rdf:li>
|
||||
<rdf:li>test</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:tiff='http://ns.adobe.com/tiff/1.0/'>
|
||||
<tiff:ImageLength>480</tiff:ImageLength>
|
||||
<tiff:ImageWidth>852</tiff:ImageWidth>
|
||||
<tiff:XResolution>72/1</tiff:XResolution>
|
||||
<tiff:YResolution>72/1</tiff:YResolution>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
<xmp:Rating>4</xmp:Rating>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stDim='http://ns.adobe.com/xap/1.0/sType/Dimensions#'
|
||||
xmlns:xmpDM='http://ns.adobe.com/xmp/1.0/DynamicMedia/'>
|
||||
<xmpDM:altTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:altTimecode>
|
||||
<xmpDM:audioChannelType>Stereo</xmpDM:audioChannelType>
|
||||
<xmpDM:audioSampleRate>48000</xmpDM:audioSampleRate>
|
||||
<xmpDM:audioSampleType>16Int</xmpDM:audioSampleType>
|
||||
<xmpDM:duration rdf:parseType='Resource'>
|
||||
<xmpDM:scale>1/90000</xmpDM:scale>
|
||||
<xmpDM:value>2928000</xmpDM:value>
|
||||
</xmpDM:duration>
|
||||
<xmpDM:startTimeSampleSize>1</xmpDM:startTimeSampleSize>
|
||||
<xmpDM:startTimeScale>25</xmpDM:startTimeScale>
|
||||
<xmpDM:startTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:startTimecode>
|
||||
<xmpDM:videoFieldOrder>Progressive</xmpDM:videoFieldOrder>
|
||||
<xmpDM:videoFrameRate>25.000000</xmpDM:videoFrameRate>
|
||||
<xmpDM:videoFrameSize rdf:parseType='Resource'>
|
||||
<stDim:h>480</stDim:h>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
<stDim:w>852</stDim:w>
|
||||
</xmpDM:videoFrameSize>
|
||||
<xmpDM:videoPixelAspectRatio>1/1</xmpDM:videoPixelAspectRatio>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stEvt='http://ns.adobe.com/xap/1.0/sType/ResourceEvent#'
|
||||
xmlns:stRef='http://ns.adobe.com/xap/1.0/sType/ResourceRef#'
|
||||
xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/'>
|
||||
<xmpMM:DerivedFrom rdf:parseType='Resource'>
|
||||
<stRef:documentID>d47681ee-e57e-2256-f455-43c40000004b</stRef:documentID>
|
||||
<stRef:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stRef:instanceID>
|
||||
<stRef:originalDocumentID>xmp.did:5af8e6dd-2af0-e94e-8f3c-767794b3efa1</stRef:originalDocumentID>
|
||||
</xmpMM:DerivedFrom>
|
||||
<xmpMM:DocumentID>b2c5763f-bfb9-7ee1-6893-05220000004b</xmpMM:DocumentID>
|
||||
<xmpMM:History>
|
||||
<rdf:Seq>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>63c4c09c-9648-ee43-720e-644600000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:26:54+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:6e43712c-17f5-cc4c-b90d-766dca2590dc</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/metadata</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</xmpMM:History>
|
||||
<xmpMM:InstanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</xmpMM:InstanceID>
|
||||
<xmpMM:OriginalDocumentID>xmp.did:1aa2d671-bf82-2043-9053-ec864079866c</xmpMM:OriginalDocumentID>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end='w'?>
|
15
test/backend/assets/sidecar/bunny_1sec_v3.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 640,
|
||||
"height": 360
|
||||
},
|
||||
"bitRate": 1794127,
|
||||
"duration": 290,
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 65073,
|
||||
"fps": 40000,
|
||||
"keywords": [
|
||||
"rabbit"
|
||||
],
|
||||
"rating": 4
|
||||
}
|
BIN
test/backend/assets/sidecar/bunny_1sec_v3.mp4
Normal file
118
test/backend/assets/sidecar/bunny_1sec_v3.xmp
Normal file
@ -0,0 +1,118 @@
|
||||
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
|
||||
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 12.69'>
|
||||
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
|
||||
<Iptc4xmpExt:audioBitsPerSample>16</Iptc4xmpExt:audioBitsPerSample>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:LImage='http://ns.leiainc.com/photos/1.0/image/'>
|
||||
<LImage:MinorVersion>0.0.0</LImage:MinorVersion>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:dc='http://purl.org/dc/elements/1.1/'>
|
||||
<dc:format>H.264</dc:format>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>rabbit</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:tiff='http://ns.adobe.com/tiff/1.0/'>
|
||||
<tiff:ImageLength>480</tiff:ImageLength>
|
||||
<tiff:ImageWidth>852</tiff:ImageWidth>
|
||||
<tiff:XResolution>72/1</tiff:XResolution>
|
||||
<tiff:YResolution>72/1</tiff:YResolution>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
<xmp:Rating>4</xmp:Rating>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stDim='http://ns.adobe.com/xap/1.0/sType/Dimensions#'
|
||||
xmlns:xmpDM='http://ns.adobe.com/xmp/1.0/DynamicMedia/'>
|
||||
<xmpDM:altTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:altTimecode>
|
||||
<xmpDM:audioChannelType>Stereo</xmpDM:audioChannelType>
|
||||
<xmpDM:audioSampleRate>48000</xmpDM:audioSampleRate>
|
||||
<xmpDM:audioSampleType>16Int</xmpDM:audioSampleType>
|
||||
<xmpDM:duration rdf:parseType='Resource'>
|
||||
<xmpDM:scale>1/90000</xmpDM:scale>
|
||||
<xmpDM:value>2928000</xmpDM:value>
|
||||
</xmpDM:duration>
|
||||
<xmpDM:startTimeSampleSize>1</xmpDM:startTimeSampleSize>
|
||||
<xmpDM:startTimeScale>25</xmpDM:startTimeScale>
|
||||
<xmpDM:startTimecode rdf:parseType='Resource'>
|
||||
<xmpDM:timeFormat>25Timecode</xmpDM:timeFormat>
|
||||
<xmpDM:timeValue>00:00:00:00</xmpDM:timeValue>
|
||||
</xmpDM:startTimecode>
|
||||
<xmpDM:videoFieldOrder>Progressive</xmpDM:videoFieldOrder>
|
||||
<xmpDM:videoFrameRate>25.000000</xmpDM:videoFrameRate>
|
||||
<xmpDM:videoFrameSize rdf:parseType='Resource'>
|
||||
<stDim:h>480</stDim:h>
|
||||
<stDim:unit>pixel</stDim:unit>
|
||||
<stDim:w>852</stDim:w>
|
||||
</xmpDM:videoFrameSize>
|
||||
<xmpDM:videoPixelAspectRatio>1/1</xmpDM:videoPixelAspectRatio>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:stEvt='http://ns.adobe.com/xap/1.0/sType/ResourceEvent#'
|
||||
xmlns:stRef='http://ns.adobe.com/xap/1.0/sType/ResourceRef#'
|
||||
xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/'>
|
||||
<xmpMM:DerivedFrom rdf:parseType='Resource'>
|
||||
<stRef:documentID>d47681ee-e57e-2256-f455-43c40000004b</stRef:documentID>
|
||||
<stRef:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stRef:instanceID>
|
||||
<stRef:originalDocumentID>xmp.did:5af8e6dd-2af0-e94e-8f3c-767794b3efa1</stRef:originalDocumentID>
|
||||
</xmpMM:DerivedFrom>
|
||||
<xmpMM:DocumentID>b2c5763f-bfb9-7ee1-6893-05220000004b</xmpMM:DocumentID>
|
||||
<xmpMM:History>
|
||||
<rdf:Seq>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>63c4c09c-9648-ee43-720e-644600000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>2a5a623f-09cc-ea32-5014-869400000078</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:26:54+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:6e43712c-17f5-cc4c-b90d-766dca2590dc</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
<rdf:li rdf:parseType='Resource'>
|
||||
<stEvt:action>saved</stEvt:action>
|
||||
<stEvt:changed>/metadata</stEvt:changed>
|
||||
<stEvt:instanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</stEvt:instanceID>
|
||||
<stEvt:softwareAgent>Adobe Adobe Media Encoder CC 2017.1 (Windows)</stEvt:softwareAgent>
|
||||
<stEvt:when>2018-11-17T20:27:31+01:00</stEvt:when>
|
||||
</rdf:li>
|
||||
</rdf:Seq>
|
||||
</xmpMM:History>
|
||||
<xmpMM:InstanceID>xmp.iid:4d4376d3-c650-354b-b4eb-0fc2d21bcaa4</xmpMM:InstanceID>
|
||||
<xmpMM:OriginalDocumentID>xmp.did:1aa2d671-bf82-2043-9053-ec864079866c</xmpMM:OriginalDocumentID>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end='w'?>
|
BIN
test/backend/assets/sidecar/metadata.jpg
Normal file
After Width: | Height: | Size: 5.0 KiB |
12
test/backend/assets/sidecar/metadata.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 10,
|
||||
"height": 5
|
||||
},
|
||||
"creationDate": 1710188754000,
|
||||
"fileSize": 5095,
|
||||
"keywords": [
|
||||
"floor",
|
||||
"book"
|
||||
]
|
||||
}
|
BIN
test/backend/assets/sidecar/metadata_v2.jpg
Normal file
After Width: | Height: | Size: 5.0 KiB |
14
test/backend/assets/sidecar/metadata_v2.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 10,
|
||||
"height": 5
|
||||
},
|
||||
"creationDate": 1710188754000,
|
||||
"fileSize": 5095,
|
||||
"keywords": [
|
||||
"floor",
|
||||
"book",
|
||||
"first",
|
||||
"second"
|
||||
]
|
||||
}
|
18
test/backend/assets/sidecar/metadata_v2.xmp
Normal file
@ -0,0 +1,18 @@
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 6.0.0">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
|
||||
xmlns:MicrosoftPhoto="http://ns.microsoft.com/photo/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:lr="http://ns.adobe.com/lightroom/1.0/">
|
||||
<xmp:Rating>0</xmp:Rating>
|
||||
<MicrosoftPhoto:Rating>0</MicrosoftPhoto:Rating>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>first</rdf:li>
|
||||
<rdf:li>second</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
BIN
test/backend/assets/sidecar/no_metadata.jpg
Normal file
After Width: | Height: | Size: 1.4 KiB |
24
test/backend/assets/sidecar/no_metadata.jpg.xmp
Normal file
@ -0,0 +1,24 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:fstop="http://www.fstopapp.com/xmp/"
|
||||
fstop:favorite="0">
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>first</rdf:li>
|
||||
<rdf:li>second</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
12
test/backend/assets/sidecar/no_metadata.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 10,
|
||||
"height": 5
|
||||
},
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 1430,
|
||||
"keywords": [
|
||||
"first",
|
||||
"second"
|
||||
]
|
||||
}
|
BIN
test/backend/assets/sidecar/no_metadata_v2.jpg
Normal file
After Width: | Height: | Size: 1.4 KiB |
12
test/backend/assets/sidecar/no_metadata_v2.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 10,
|
||||
"height": 5
|
||||
},
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 1430,
|
||||
"keywords": [
|
||||
"first",
|
||||
"second"
|
||||
]
|
||||
}
|
23
test/backend/assets/sidecar/no_metadata_v2.xmp
Normal file
@ -0,0 +1,23 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:fstop="http://www.fstopapp.com/xmp/"
|
||||
fstop:favorite="0">
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>first</rdf:li>
|
||||
<rdf:li>second</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
BIN
test/backend/assets/sidecar/no_metadata_v3.jpg
Normal file
After Width: | Height: | Size: 1.4 KiB |
11
test/backend/assets/sidecar/no_metadata_v3.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 10,
|
||||
"height": 5
|
||||
},
|
||||
"creationDate": 1542482851000,
|
||||
"fileSize": 1430,
|
||||
"keywords": [
|
||||
"first"
|
||||
]
|
||||
}
|
22
test/backend/assets/sidecar/no_metadata_v3.xmp
Normal file
@ -0,0 +1,22 @@
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2">
|
||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<rdf:Description rdf:about=""
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:fstop="http://www.fstopapp.com/xmp/"
|
||||
fstop:favorite="0">
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>first</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about=''
|
||||
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
|
||||
<xmp:CreateDate>2018-11-17T20:27:31+01:00</xmp:CreateDate>
|
||||
<xmp:MetadataDate>2018-11-17T20:27:31+01:00</xmp:MetadataDate>
|
||||
<xmp:ModifyDate>2018-11-17T20:27:31+01:00</xmp:ModifyDate>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</x:xmpmeta>
|
||||
<?xpacket end="w"?>
|
@ -5,6 +5,7 @@ import {Utils} from '../../../../../src/common/Utils';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import {PhotoProcessing} from '../../../../../src/backend/model/fileaccess/fileprocessing/PhotoProcessing';
|
||||
import {VideoProcessing} from '../../../../../src/backend/model/fileaccess/fileprocessing/VideoProcessing';
|
||||
import {Config} from '../../../../../src/common/config/private/Config';
|
||||
import {DatabaseType} from '../../../../../src/common/config/private/PrivateConfig';
|
||||
|
||||
@ -99,6 +100,67 @@ describe('MetadataLoader', () => {
|
||||
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
it('should load sidecar file with file extension for video', async () => {
|
||||
const data = await MetadataLoader.loadVideoMetadata(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec.mp4'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should load sidecar file without file extension for video', async () => {
|
||||
const data = await MetadataLoader.loadVideoMetadata(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec_v2.mp4'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec.json'));//sidecar "bunny_1sec_v2.xmp" is identical to "bunny_1sec.mp4.xmp" so we expect the same result
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should retrieve both keywords from sidecar file for video', async () => {
|
||||
const data = await MetadataLoader.loadVideoMetadata(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec.mp4'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should retrieve one keyword from sidecar file for video', async () => {
|
||||
const data = await MetadataLoader.loadVideoMetadata(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec_v3.mp4'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/bunny_1sec_v3.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should load sidecar file with file extension for photo', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/no_metadata.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/no_metadata.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should load sidecar file without file extension for photo', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/no_metadata_v2.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/no_metadata_v2.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should retrieve both keywords from sidecar file for photo', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/no_metadata.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/no_metadata.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should retrieve one keyword from sidecar file for photo', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/no_metadata_v3.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/no_metadata_v3.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should read keywords from photo without sidecar file', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/metadata.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/metadata.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('should merge keywords from photo with keywords from sidecar', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/sidecar/metadata_v2.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/sidecar/metadata_v2.json')); //"metadata_v2.jpg" is identical to "metadata.jpg" and "metadata_v2.xmp" contains 2 different keywords
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
|
||||
describe('should load jpg with proper height and orientation', () => {
|
||||
it('jpg 1', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/orientation/broken_orientation_exif.jpg'));
|
||||
@ -196,4 +258,24 @@ describe('MetadataLoader', () => {
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
|
||||
describe('should load metadata from sidecar files', () => {
|
||||
const root = path.join(__dirname, '/../../../assets/sidecar');
|
||||
const files = fs.readdirSync(root);
|
||||
for (const item of files) {
|
||||
const fullFilePath = path.join(root, item);
|
||||
if (PhotoProcessing.isPhoto(fullFilePath)) {
|
||||
it(item, async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(fullFilePath);
|
||||
const expected = require(fullFilePath.split('.').slice(0, -1).join('.') + '.json');
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
} else if (VideoProcessing.isVideo(fullFilePath)) {
|
||||
it(item, async () => {
|
||||
const data = await MetadataLoader.loadVideoMetadata(fullFilePath);
|
||||
const expected = require(fullFilePath.split('.').slice(0, -1).join('.') + '.json');
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|