mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-10-29 17:40:28 +00:00
Add timezone to exif entity (#1894)
* Add timezone to exif entity * Refactor logging --------- Co-authored-by: Andrea Alemani <andrea.alemani94@gmail.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { ConfigService } from '@nestjs/config';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Job } from 'bull';
|
||||
import { ExifDateTime, exiftool, Tags } from 'exiftool-vendored';
|
||||
import tz_lookup from '@photostructure/tz-lookup';
|
||||
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg';
|
||||
import { getName } from 'i18n-iso-countries';
|
||||
import geocoder, { InitOptions } from 'local-reverse-geocoder';
|
||||
@@ -190,6 +191,17 @@ export class MetadataExtractionProcessor {
|
||||
return exifDate.toDate();
|
||||
};
|
||||
|
||||
const exifTimeZone = (exifDate: string | ExifDateTime | undefined) => {
|
||||
if (!exifDate) return null;
|
||||
|
||||
if (typeof exifDate === 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return exifDate.zone ?? null;
|
||||
};
|
||||
|
||||
const timeZone = exifTimeZone(exifData?.DateTimeOriginal ?? exifData?.CreateDate ?? asset.fileCreatedAt);
|
||||
const fileCreatedAt = exifToDate(exifData?.DateTimeOriginal ?? exifData?.CreateDate ?? asset.fileCreatedAt);
|
||||
const fileModifiedAt = exifToDate(exifData?.ModifyDate ?? asset.fileModifiedAt);
|
||||
const fileStats = fs.statSync(asset.originalPath);
|
||||
@@ -207,6 +219,7 @@ export class MetadataExtractionProcessor {
|
||||
newExif.orientation = exifData?.Orientation?.toString() || null;
|
||||
newExif.dateTimeOriginal = fileCreatedAt;
|
||||
newExif.modifyDate = fileModifiedAt;
|
||||
newExif.timeZone = timeZone;
|
||||
newExif.lensModel = exifData?.LensModel || null;
|
||||
newExif.fNumber = exifData?.FNumber || null;
|
||||
newExif.focalLength = exifData?.FocalLength ? parseFloat(exifData.FocalLength) : null;
|
||||
@@ -308,6 +321,7 @@ export class MetadataExtractionProcessor {
|
||||
newExif.fileSizeInByte = data.format.size || null;
|
||||
newExif.dateTimeOriginal = fileCreatedAt ? new Date(fileCreatedAt) : null;
|
||||
newExif.modifyDate = null;
|
||||
newExif.timeZone = null;
|
||||
newExif.latitude = null;
|
||||
newExif.longitude = null;
|
||||
newExif.city = null;
|
||||
@@ -345,6 +359,14 @@ export class MetadataExtractionProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
if (newExif.longitude && newExif.latitude) {
|
||||
try {
|
||||
newExif.timeZone = tz_lookup(newExif.latitude, newExif.longitude);
|
||||
} catch (error: any) {
|
||||
this.logger.warn(`Error while calculating timezone from gps coordinates: ${error}`, error?.stack);
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse GeoCoding
|
||||
if (this.isGeocodeInitialized && newExif.longitude && newExif.latitude) {
|
||||
const { country, state, city } = await this.reverseGeocodeExif(newExif.latitude, newExif.longitude);
|
||||
|
||||
@@ -3537,6 +3537,11 @@
|
||||
"nullable": true,
|
||||
"default": null
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"default": null
|
||||
},
|
||||
"lensModel": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
|
||||
@@ -13,6 +13,7 @@ export class ExifResponseDto {
|
||||
orientation?: string | null = null;
|
||||
dateTimeOriginal?: Date | null = null;
|
||||
modifyDate?: Date | null = null;
|
||||
timeZone?: string | null = null;
|
||||
lensModel?: string | null = null;
|
||||
fNumber?: number | null = null;
|
||||
focalLength?: number | null = null;
|
||||
@@ -36,6 +37,7 @@ export function mapExif(entity: ExifEntity): ExifResponseDto {
|
||||
orientation: entity.orientation,
|
||||
dateTimeOriginal: entity.dateTimeOriginal,
|
||||
modifyDate: entity.modifyDate,
|
||||
timeZone: entity.timeZone,
|
||||
lensModel: entity.lensModel,
|
||||
fNumber: entity.fNumber,
|
||||
focalLength: entity.focalLength,
|
||||
|
||||
@@ -323,6 +323,7 @@ const assetInfo: ExifResponseDto = {
|
||||
orientation: 'orientation',
|
||||
dateTimeOriginal: today,
|
||||
modifyDate: today,
|
||||
timeZone: 'America/Los_Angeles',
|
||||
lensModel: 'fancy',
|
||||
fNumber: 100,
|
||||
focalLength: 100,
|
||||
@@ -607,6 +608,7 @@ export const sharedLinkStub = {
|
||||
orientation: 'orientation',
|
||||
dateTimeOriginal: today,
|
||||
modifyDate: today,
|
||||
timeZone: 'America/Los_Angeles',
|
||||
latitude: 100,
|
||||
longitude: 100,
|
||||
city: 'city',
|
||||
|
||||
@@ -34,6 +34,9 @@ export class ExifEntity {
|
||||
@Column({ type: 'timestamptz', nullable: true })
|
||||
modifyDate!: Date | null;
|
||||
|
||||
@Column({ type: 'varchar', nullable: true })
|
||||
timeZone!: string | null;
|
||||
|
||||
@Column({ type: 'float', nullable: true })
|
||||
latitude!: number | null;
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddExifTimeZone1677497925328 implements MigrationInterface {
|
||||
name = 'AddExifTimeZone1677497925328'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "exif" ADD "timeZone" character varying`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "timeZone"`);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user