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:
parent
8c86dcbf6f
commit
a6b24aa551
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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 |
@ -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 |
@ -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"
|
||||||
|
]
|
||||||
|
}
|
@ -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];
|
||||||
|
Loading…
Reference in New Issue
Block a user