1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2024-11-03 21:04:03 +08:00

update from master and fix merge comment

This commit is contained in:
gras 2024-04-13 18:16:18 +02:00
parent 8c86dcbf6f
commit a6b24aa551
10 changed files with 104 additions and 11 deletions

View File

@ -380,27 +380,27 @@ export class MetadataLoader {
if (!offset) { //Find offset among other options if possible if (!offset) { //Find offset among other options if possible
offset = exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.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 = Utils.timestampToMS(exif.exif.DateTimeOriginal, offset); metadata.creationDate = Utils.timestampToMS(exif.exif.DateTimeOriginal, offset) || metadata.creationDate;
} else if (exif.exif.CreateDate) { //using else if here, because DateTimeOriginal has preceedence } 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) //Create is when the camera wrote the file (typically within the same ms as shutter close)
offset = exif.exif.OffsetTimeDigitized; //OffsetTimeDigitized is the corresponding offset offset = exif.exif.OffsetTimeDigitized; //OffsetTimeDigitized is the corresponding offset
if (!offset) { //Find offset among other options if possible if (!offset) { //Find offset among other options if possible
offset = exif.exif.OffsetTimeOriginal || exif.exif.OffsetTime || Utils.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 = Utils.timestampToMS(exif.exif.CreateDate, offset); metadata.creationDate = Utils.timestampToMS(exif.exif.CreateDate, offset) || metadata.creationDate;
} else if (exif.ifd0?.ModifyDate) { //using else if here, because DateTimeOriginal and CreatDate have preceedence } else if (exif.ifd0?.ModifyDate) { //using else if here, because DateTimeOriginal and CreatDate have preceedence
offset = exif.exif.OffsetTime; //exif.Offsettime is the offset corresponding to ifd0.ModifyDate offset = exif.exif.OffsetTime; //exif.Offsettime is the offset corresponding to ifd0.ModifyDate
if (!offset) { //Find offset among other options if possible if (!offset) { //Find offset among other options if possible
offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || Utils.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 = Utils.timestampToMS(exif.ifd0.ModifyDate, offset); metadata.creationDate = Utils.timestampToMS(exif.ifd0.ModifyDate, offset) || metadata.creationDate;
} else if (exif.ihdr && exif.ihdr["Creation Time"]) {// again else if (another fallback date if the good ones aren't there) { } 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 || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps); 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.creationDate = Utils.timestampToMS(exif.ihdr["Creation Time"], any_offset);
offset = any_offset; offset = 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) { } 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 || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps); 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.creationDate = Utils.timestampToMS(exif.xmp.MetadataDate, any_offset) || metadata.creationDate;
offset = any_offset; offset = any_offset;
} }
metadata.creationDateOffset = offset || metadata.creationDateOffset; metadata.creationDateOffset = offset || metadata.creationDateOffset;

View File

@ -186,12 +186,12 @@ export class Utils {
gps.GPSDateStamp && gps.GPSDateStamp &&
gps.GPSTimeStamp) { //else use exif.gps.GPS*Stamp if available gps.GPSTimeStamp) { //else use exif.gps.GPS*Stamp if available
//GPS timestamp is always UTC (+00:00) //GPS timestamp is always UTC (+00:00)
UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + gps.GPSTimeStamp.join(':'); UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + " " + gps.GPSTimeStamp.map((num: any) => Utils.zeroPad(num ,2)).join(':');
} }
if (UTCTimestamp && timestamp) { if (UTCTimestamp && timestamp) {
//offset in minutes is the difference between gps timestamp and given 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 //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; const offsetMinutes: number = Math.round((Utils.timestampToMS(timestamp, '+00:00')- Utils.timestampToMS(UTCTimestamp, '+00:00')) / 1000 / 60);
return Utils.getOffsetString(offsetMinutes); return Utils.getOffsetString(offsetMinutes);
} else { } else {
return undefined; return undefined;
@ -202,13 +202,22 @@ export class Utils {
if (-720 <= offsetMinutes && offsetMinutes <= 840) { if (-720 <= offsetMinutes && offsetMinutes <= 840) {
//valid offset is within -12 and +14 hrs (https://en.wikipedia.org/wiki/List_of_UTC_offsets) //valid offset is within -12 and +14 hrs (https://en.wikipedia.org/wiki/List_of_UTC_offsets)
return (offsetMinutes < 0 ? "-" : "+") + //leading +/- return (offsetMinutes < 0 ? "-" : "+") + //leading +/-
("0" + Math.trunc(Math.abs(offsetMinutes) / 60)).slice(-2) + ":" + //zeropadded hours and ':' Utils.zeroPad(Math.trunc(Math.abs(offsetMinutes) / 60), 2) + ":" + //zeropadded hours and ':'
("0" + Math.abs(offsetMinutes) % 60).slice(-2); //zeropadded minutes Utils.zeroPad((Math.abs(offsetMinutes) % 60), 2); //zeropadded minutes
} else { } else {
return undefined; return undefined;
} }
} }
static zeroPad(number: any, length: number): string {
if (!isNaN(number)) {
const zerosToAdd = Math.max(length - String(number).length, 0);
return '0'.repeat(zerosToAdd) + number;
} else {
return '0'.repeat(number);
}
}
static getOffsetMinutes(offsetString: string) { //Convert offset string (+HH:MM or -HH:MM) into a minute value static getOffsetMinutes(offsetString: string) { //Convert offset string (+HH:MM or -HH:MM) into a minute value
const regex = /^([+-](0[0-9]|1[0-4]):[0-5][0-9])$/; //checks if offset is between -14:00 and +14:00. const regex = /^([+-](0[0-9]|1[0-4]):[0-5][0-9])$/; //checks if offset is between -14:00 and +14:00.
//-12:00 is the lowest valid UTC-offset, but we allow down to -14 for efficiency //-12:00 is the lowest valid UTC-offset, but we allow down to -14 for efficiency

View File

@ -7,7 +7,8 @@
"make": "HUAWEI", "make": "HUAWEI",
"model": "HUAWEI G6-L11" "model": "HUAWEI G6-L11"
}, },
"creationDate": 1460826466000, "creationDate": 1460819266000,
"creationDateOffset": "+02:00",
"fileSize": 1980, "fileSize": 1980,
"size": { "size": {
"height": 1, "height": 1,

View File

@ -7,7 +7,7 @@
"make": "NIKON", "make": "NIKON",
"model": "E880" "model": "E880"
}, },
"creationDate": 0, "creationDate": "fileModificationTime",
"fileSize": 72850, "fileSize": 72850,
"size": { "size": {
"height": 768, "height": 768,

View File

@ -3,7 +3,8 @@
"width": 3024, "width": 3024,
"height": 4032 "height": 4032
}, },
"creationDate": 1518964712000, "creationDate": 1518982712000,
"creationDateOffset": "-05:00",
"fileSize": 256001, "fileSize": 256001,
"cameraData": { "cameraData": {
"model": "Pixel 2", "model": "Pixel 2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,25 @@
{
"size": {
"width": 200,
"height": 300
},
"creationDate": 1686141955000,
"creationDateOffset": "+01:00",
"fileSize": 18663,
"cameraData": {
"model": "Canon EOS R5",
"make": "Canon"
},
"positionData": {
"GPSData": {
"longitude": -0.124575,
"latitude": 51.500694
},
"country": "Storbritannien",
"state": "England",
"city": "St James's"
},
"keywords": [
"Big Ben"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,25 @@
{
"size": {
"width": 200,
"height": 300
},
"creationDate": 1686141955000,
"creationDateOffset": "+01:00",
"fileSize": 18601,
"cameraData": {
"model": "Canon EOS R5",
"make": "Canon"
},
"positionData": {
"GPSData": {
"longitude": -0.124575,
"latitude": 51.500694
},
"country": "Storbritannien",
"state": "England",
"city": "St James's"
},
"keywords": [
"Big Ben"
]
}

View File

@ -11,6 +11,18 @@ import {DatabaseType} from '../../../../../src/common/config/private/PrivateConf
declare const before: any; declare const before: any;
function getFileModificationTime(filename: string): Promise<Date | null> {
return new Promise((resolve, reject) => {
fs.stat(filename, (err, stats) => {
if (err) {
reject(err);
} else {
resolve(stats.mtime);
}
});
});
}
describe('MetadataLoader', () => { describe('MetadataLoader', () => {
// loading default settings (this might have been changed by other tests) // loading default settings (this might have been changed by other tests)
@ -114,6 +126,16 @@ describe('MetadataLoader', () => {
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc.json')); const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc.json'));
expect(Utils.clone(data)).to.be.deep.equal(expected); expect(Utils.clone(data)).to.be.deep.equal(expected);
}); });
it('should load jpg with timestamps and gps (UTC) and calculate offset +1, but GPS is off by 1 min', async () => {
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min.jpg'));
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min.json'));
expect(Utils.clone(data)).to.be.deep.equal(expected);
});
it('should load jpg with timestamps and gps (UTC) and calculate offset +1, but GPS is off by 1 min - no XMP GPS', async () => {
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min_no_xmpgps.jpg'));
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min_no_xmpgps.json'));
expect(Utils.clone(data)).to.be.deep.equal(expected);
});
it('should load jpg with timestamps but no offset and no GPS to calculate it from', async () => { it('should load jpg with timestamps but no offset and no GPS to calculate it from', async () => {
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.jpg')); const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.jpg'));
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.json')); const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.json'));
@ -213,6 +235,16 @@ describe('MetadataLoader', () => {
it(item, async () => { it(item, async () => {
const data = await MetadataLoader.loadPhotoMetadata(fullFilePath); const data = await MetadataLoader.loadPhotoMetadata(fullFilePath);
const expected = require(fullFilePath.split('.').slice(0, -1).join('.') + '.json'); const expected = require(fullFilePath.split('.').slice(0, -1).join('.') + '.json');
if (expected.creationDate == "fileModificationTime") {
await getFileModificationTime(fullFilePath).then((modificationTime: any) => {
if (modificationTime) {
expected.creationDate = new Date(modificationTime).getTime();
} else {
expected.creationDate = 0;
}
})
}
if (expected.skip) { if (expected.skip) {
expected.skip.forEach((s: string) => { expected.skip.forEach((s: string) => {
delete (data as any)[s]; delete (data as any)[s];