1
0
mirror of https://github.com/immich-app/immich.git synced 2024-11-24 08:52:28 +02:00

fix(deps): exiftool-vendored (#11338)

This commit is contained in:
Jason Rasmussen 2024-07-24 17:38:22 -04:00 committed by GitHub
parent 9e60c107ca
commit 9f6ef92f0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 51 additions and 62 deletions

View File

@ -1137,7 +1137,7 @@ describe('/asset', () => {
type: AssetTypeEnum.Image, type: AssetTypeEnum.Image,
originalFileName: '14bit-uncompressed-(3_2).arw', originalFileName: '14bit-uncompressed-(3_2).arw',
resized: true, resized: true,
fileCreatedAt: '2016-01-08T15:08:01.000Z', fileCreatedAt: '2016-01-08T14:08:01.000Z',
exifInfo: { exifInfo: {
make: 'SONY', make: 'SONY',
model: 'ILCE-7M2', model: 'ILCE-7M2',
@ -1149,7 +1149,7 @@ describe('/asset', () => {
iso: 100, iso: 100,
lensModel: 'E 25mm F2', lensModel: 'E 25mm F2',
fileSizeInByte: 49_512_448, fileSizeInByte: 49_512_448,
dateTimeOriginal: '2016-01-08T15:08:01.000Z', dateTimeOriginal: '2016-01-08T14:08:01.000Z',
latitude: null, latitude: null,
longitude: null, longitude: null,
orientation: '1', orientation: '1',

View File

@ -34,7 +34,7 @@
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"exiftool-vendored": "26.0.0", "exiftool-vendored": "^28.1.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"geo-tz": "^8.0.0", "geo-tz": "^8.0.0",
@ -9549,9 +9549,9 @@
} }
}, },
"node_modules/exiftool-vendored": { "node_modules/exiftool-vendored": {
"version": "26.0.0", "version": "28.1.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.0.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.1.0.tgz",
"integrity": "sha512-2TRxx21ovD95VvdSzHb/sTYYcwhiizQIhhVAbrgua9KoL902QRieREGvaUtfBZNjsptdjonuyku2kUBJCPqsgw==", "integrity": "sha512-Anlfl16gv0QuaNbkMuwutCfhzzPn/33Lio2fKCgIHk4m+udz5dsatwv1+tjk4eDMNT1Oj/zwG3hKhSX5zlHzAw==",
"dependencies": { "dependencies": {
"@photostructure/tz-lookup": "^10.0.0", "@photostructure/tz-lookup": "^10.0.0",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
@ -9560,23 +9560,23 @@
"luxon": "^3.4.4" "luxon": "^3.4.4"
}, },
"optionalDependencies": { "optionalDependencies": {
"exiftool-vendored.exe": "12.84.0", "exiftool-vendored.exe": "12.89.0",
"exiftool-vendored.pl": "12.84.0" "exiftool-vendored.pl": "12.89.0"
} }
}, },
"node_modules/exiftool-vendored.exe": { "node_modules/exiftool-vendored.exe": {
"version": "12.84.0", "version": "12.89.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.84.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.89.0.tgz",
"integrity": "sha512-9ocqJb0Pr9k0TownEMd75payF/XOQLF/swr/l0Ep49D+m609uIZsW09CtowhXmk1KrIFobS3+SkdXK04CSyUwQ==", "integrity": "sha512-GyayTRwH6v/3SCV7g80zV5oMw66AQFnPJVfPc/At9PMAe90/9N7GCM1o6U1FGOpa1ZvmSm38RvvBEMr667vnnw==",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
] ]
}, },
"node_modules/exiftool-vendored.pl": { "node_modules/exiftool-vendored.pl": {
"version": "12.84.0", "version": "12.89.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.84.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.89.0.tgz",
"integrity": "sha512-TxvMRaVYtd24Vupn48zy24LOYItIIWEu4dgt/VlqLwxQItTpvJTV9YH04iZRvaNh9ZdPRgVKWMuuUDBBHv+lAg==", "integrity": "sha512-pkkWBRmeylUEAfBOg/e6NO8dZ572yDA6kTsnw1gGiAhJUxgoLGP+ageuOD6Oxywag5/HFcT2syJ+L1/ch5hjfg==",
"optional": true, "optional": true,
"os": [ "os": [
"!win32" "!win32"
@ -23433,29 +23433,29 @@
} }
}, },
"exiftool-vendored": { "exiftool-vendored": {
"version": "26.0.0", "version": "28.1.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.0.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.1.0.tgz",
"integrity": "sha512-2TRxx21ovD95VvdSzHb/sTYYcwhiizQIhhVAbrgua9KoL902QRieREGvaUtfBZNjsptdjonuyku2kUBJCPqsgw==", "integrity": "sha512-Anlfl16gv0QuaNbkMuwutCfhzzPn/33Lio2fKCgIHk4m+udz5dsatwv1+tjk4eDMNT1Oj/zwG3hKhSX5zlHzAw==",
"requires": { "requires": {
"@photostructure/tz-lookup": "^10.0.0", "@photostructure/tz-lookup": "^10.0.0",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
"batch-cluster": "^13.0.0", "batch-cluster": "^13.0.0",
"exiftool-vendored.exe": "12.84.0", "exiftool-vendored.exe": "12.89.0",
"exiftool-vendored.pl": "12.84.0", "exiftool-vendored.pl": "12.89.0",
"he": "^1.2.0", "he": "^1.2.0",
"luxon": "^3.4.4" "luxon": "^3.4.4"
} }
}, },
"exiftool-vendored.exe": { "exiftool-vendored.exe": {
"version": "12.84.0", "version": "12.89.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.84.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.89.0.tgz",
"integrity": "sha512-9ocqJb0Pr9k0TownEMd75payF/XOQLF/swr/l0Ep49D+m609uIZsW09CtowhXmk1KrIFobS3+SkdXK04CSyUwQ==", "integrity": "sha512-GyayTRwH6v/3SCV7g80zV5oMw66AQFnPJVfPc/At9PMAe90/9N7GCM1o6U1FGOpa1ZvmSm38RvvBEMr667vnnw==",
"optional": true "optional": true
}, },
"exiftool-vendored.pl": { "exiftool-vendored.pl": {
"version": "12.84.0", "version": "12.89.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.84.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.89.0.tgz",
"integrity": "sha512-TxvMRaVYtd24Vupn48zy24LOYItIIWEu4dgt/VlqLwxQItTpvJTV9YH04iZRvaNh9ZdPRgVKWMuuUDBBHv+lAg==", "integrity": "sha512-pkkWBRmeylUEAfBOg/e6NO8dZ572yDA6kTsnw1gGiAhJUxgoLGP+ageuOD6Oxywag5/HFcT2syJ+L1/ch5hjfg==",
"optional": true "optional": true
}, },
"express": { "express": {

View File

@ -60,7 +60,7 @@
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"exiftool-vendored": "26.0.0", "exiftool-vendored": "^28.1.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"geo-tz": "^8.0.0", "geo-tz": "^8.0.0",

View File

@ -1,6 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { DefaultReadTaskOptions, Tags, exiftool } from 'exiftool-vendored'; import { DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
import geotz from 'geo-tz'; import geotz from 'geo-tz';
import { DummyValue, GenerateSql } from 'src/decorators'; import { DummyValue, GenerateSql } from 'src/decorators';
import { ExifEntity } from 'src/entities/exif.entity'; import { ExifEntity } from 'src/entities/exif.entity';
@ -12,6 +12,19 @@ import { Repository } from 'typeorm';
@Instrumentation() @Instrumentation()
@Injectable() @Injectable()
export class MetadataRepository implements IMetadataRepository { export class MetadataRepository implements IMetadataRepository {
private exiftool = new ExifTool({
defaultVideosToUTC: true,
backfillTimezones: true,
inferTimezoneFromDatestamps: true,
useMWG: true,
numericTags: [...DefaultReadTaskOptions.numericTags, 'FocalLength'],
/* eslint unicorn/no-array-callback-reference: off, unicorn/no-array-method-this-argument: off */
geoTz: (lat, lon) => geotz.find(lat, lon)[0],
// Enable exiftool LFS to parse metadata for files larger than 2GB.
readArgs: ['-api', 'largefilesupport=1'],
writeArgs: ['-api', 'largefilesupport=1', '-overwrite_original'],
});
constructor( constructor(
@InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>, @InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>,
@Inject(ILoggerRepository) private logger: ILoggerRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository,
@ -20,37 +33,23 @@ export class MetadataRepository implements IMetadataRepository {
} }
async teardown() { async teardown() {
await exiftool.end(); await this.exiftool.end();
} }
readTags(path: string): Promise<ImmichTags | null> { readTags(path: string): Promise<ImmichTags | null> {
return exiftool return this.exiftool.read(path).catch((error) => {
.read(path, undefined, { this.logger.warn(`Error reading exif data (${path}): ${error}`, error?.stack);
...DefaultReadTaskOptions, return null;
}) as Promise<ImmichTags | null>;
// Enable exiftool LFS to parse metadata for files larger than 2GB.
optionalArgs: ['-api', 'largefilesupport=1'],
defaultVideosToUTC: true,
backfillTimezones: true,
inferTimezoneFromDatestamps: true,
useMWG: true,
numericTags: [...DefaultReadTaskOptions.numericTags, 'FocalLength'],
/* eslint unicorn/no-array-callback-reference: off, unicorn/no-array-method-this-argument: off */
geoTz: (lat, lon) => geotz.find(lat, lon)[0],
})
.catch((error) => {
this.logger.warn(`Error reading exif data (${path}): ${error}`, error?.stack);
return null;
}) as Promise<ImmichTags | null>;
} }
extractBinaryTag(path: string, tagName: string): Promise<Buffer> { extractBinaryTag(path: string, tagName: string): Promise<Buffer> {
return exiftool.extractBinaryTagToBuffer(tagName, path); return this.exiftool.extractBinaryTagToBuffer(tagName, path);
} }
async writeTags(path: string, tags: Partial<Tags>): Promise<void> { async writeTags(path: string, tags: Partial<Tags>): Promise<void> {
try { try {
await exiftool.write(path, tags, ['-overwrite_original']); await this.exiftool.write(path, tags);
} catch (error) { } catch (error) {
this.logger.warn(`Error writing exif data (${path}): ${error}`); this.logger.warn(`Error writing exif data (${path}): ${error}`);
} }

View File

@ -1,5 +1,5 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { ExifDateTime, Tags } from 'exiftool-vendored'; import { ContainerDirectoryItem, ExifDateTime, Tags } from 'exiftool-vendored';
import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime'; import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime';
import _ from 'lodash'; import _ from 'lodash';
import { Duration } from 'luxon'; import { Duration } from 'luxon';
@ -48,17 +48,6 @@ const EXIF_DATE_TAGS: Array<keyof Tags> = [
'DateTimeCreated', 'DateTimeCreated',
]; ];
interface DirectoryItem {
Length?: number;
Mime: string;
Padding?: number;
Semantic?: string;
}
interface DirectoryEntry {
Item: DirectoryItem;
}
export enum Orientation { export enum Orientation {
Horizontal = '1', Horizontal = '1',
MirrorHorizontal = '2', MirrorHorizontal = '2',
@ -362,13 +351,14 @@ export class MetadataService implements OnEvents {
return; return;
} }
const rawDirectory = tags.Directory;
const isMotionPhoto = tags.MotionPhoto; const isMotionPhoto = tags.MotionPhoto;
const isMicroVideo = tags.MicroVideo; const isMicroVideo = tags.MicroVideo;
const videoOffset = tags.MicroVideoOffset; const videoOffset = tags.MicroVideoOffset;
const hasMotionPhotoVideo = tags.MotionPhotoVideo; const hasMotionPhotoVideo = tags.MotionPhotoVideo;
const hasEmbeddedVideoFile = tags.EmbeddedVideoType === 'MotionPhoto_Data' && tags.EmbeddedVideoFile; const hasEmbeddedVideoFile = tags.EmbeddedVideoType === 'MotionPhoto_Data' && tags.EmbeddedVideoFile;
const directory = Array.isArray(rawDirectory) ? (rawDirectory as DirectoryEntry[]) : null; const directory = Array.isArray(tags.ContainerDirectory)
? (tags.ContainerDirectory as ContainerDirectoryItem[])
: null;
let length = 0; let length = 0;
let padding = 0; let padding = 0;