1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00:00

fix: downgrade exiftool-vendored to fix motion photo extraction (#11145)

* Revert "chore(server): update exiftool and migrate off deprecated method signatures (#10367)"

This reverts commit 1b67ea2d

* fix: downgrade exiftool-vendored to 26.0.0

* chore: change motionphoto filenames to be kebab-case

* test: add pixel 6 pro motionphoto e2e test case

* test: add pixel 8a motion photo

* chore: update test-assets submodule pointer
This commit is contained in:
Zack Pollard 2024-07-16 20:55:51 +01:00 committed by GitHub
parent 87e8c16a90
commit fb8d9d8c40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 62 additions and 54 deletions

View file

@ -1170,17 +1170,25 @@ describe('/asset', () => {
// into the test here. // into the test here.
it.each([ it.each([
{ {
filepath: 'formats/motionphoto/Samsung One UI 5.jpg', filepath: 'formats/motionphoto/samsung-one-ui-5.jpg',
checksum: 'fr14niqCq6N20HB8rJYEvpsUVtI=', checksum: 'fr14niqCq6N20HB8rJYEvpsUVtI=',
}, },
{ {
filepath: 'formats/motionphoto/Samsung One UI 6.jpg', filepath: 'formats/motionphoto/samsung-one-ui-6.jpg',
checksum: 'lT9Uviw/FFJYCjfIxAGPTjzAmmw=', checksum: 'lT9Uviw/FFJYCjfIxAGPTjzAmmw=',
}, },
{ {
filepath: 'formats/motionphoto/Samsung One UI 6.heic', filepath: 'formats/motionphoto/samsung-one-ui-6.heic',
checksum: '/ejgzywvgvzvVhUYVfvkLzFBAF0=', checksum: '/ejgzywvgvzvVhUYVfvkLzFBAF0=',
}, },
{
filepath: 'formats/motionphoto/pixel-6-pro.jpg',
checksum: 'bFhLGbdK058PSk4FTfrSnoKWykc=',
},
{
filepath: 'formats/motionphoto/pixel-8a.jpg',
checksum: '7YdY+WF0h+CXHbiXpi0HiCMTTjs=',
},
])(`should extract motionphoto video from $filepath`, async ({ filepath, checksum }) => { ])(`should extract motionphoto video from $filepath`, async ({ filepath, checksum }) => {
const response = await utils.createAsset(admin.accessToken, { const response = await utils.createAsset(admin.accessToken, {
assetData: { assetData: {

View file

@ -49,9 +49,9 @@ describe('/search', () => {
{ filename: '/albums/nature/silver_fir.jpg' }, { filename: '/albums/nature/silver_fir.jpg' },
{ filename: '/formats/heic/IMG_2682.heic' }, { filename: '/formats/heic/IMG_2682.heic' },
{ filename: '/formats/jpg/el_torcal_rocks.jpg' }, { filename: '/formats/jpg/el_torcal_rocks.jpg' },
{ filename: '/formats/motionphoto/Samsung One UI 6.jpg' }, { filename: '/formats/motionphoto/samsung-one-ui-6.jpg' },
{ filename: '/formats/motionphoto/Samsung One UI 6.heic' }, { filename: '/formats/motionphoto/samsung-one-ui-6.heic' },
{ filename: '/formats/motionphoto/Samsung One UI 5.jpg' }, { filename: '/formats/motionphoto/samsung-one-ui-5.jpg' },
{ filename: '/metadata/gps-position/thompson-springs.jpg', dto: { isArchived: true } }, { filename: '/metadata/gps-position/thompson-springs.jpg', dto: { isArchived: true } },
@ -315,7 +315,7 @@ describe('/search', () => {
{ {
should: 'should search by originalFilename with spaces', should: 'should search by originalFilename with spaces',
deferred: () => ({ deferred: () => ({
dto: { originalFileName: 'Samsung One', type: 'IMAGE' }, dto: { originalFileName: 'samsung-one', type: 'IMAGE' },
assets: [assetOneJpg5, assetOneJpg6, assetOneHeic6], assets: [assetOneJpg5, assetOneJpg6, assetOneHeic6],
}), }),
}, },

@ -1 +1 @@
Subproject commit 625ec3a5e9aa9b087ad986e0c2e6a24edb4ea81e Subproject commit 898069e47f8e3283bf3bbd40b58b56d8fd57dc65

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": "~27.0.0", "exiftool-vendored": "26.0.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,10 +9549,9 @@
} }
}, },
"node_modules/exiftool-vendored": { "node_modules/exiftool-vendored": {
"version": "27.0.0", "version": "26.0.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-27.0.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.0.0.tgz",
"integrity": "sha512-/jHX8Jjadj0YJzpqnuBo1Yy2ln2hnRbBIc+3jcVOLQ6qhHEKsLRlfJ145Ghn7k/EcnfpDzVX3V8AUCTC8juTow==", "integrity": "sha512-2TRxx21ovD95VvdSzHb/sTYYcwhiizQIhhVAbrgua9KoL902QRieREGvaUtfBZNjsptdjonuyku2kUBJCPqsgw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@photostructure/tz-lookup": "^10.0.0", "@photostructure/tz-lookup": "^10.0.0",
"@types/luxon": "^3.4.2", "@types/luxon": "^3.4.2",
@ -9561,23 +9560,23 @@
"luxon": "^3.4.4" "luxon": "^3.4.4"
}, },
"optionalDependencies": { "optionalDependencies": {
"exiftool-vendored.exe": "12.85.0", "exiftool-vendored.exe": "12.84.0",
"exiftool-vendored.pl": "12.85.0" "exiftool-vendored.pl": "12.84.0"
} }
}, },
"node_modules/exiftool-vendored.exe": { "node_modules/exiftool-vendored.exe": {
"version": "12.85.0", "version": "12.84.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.85.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.84.0.tgz",
"integrity": "sha512-rWsKVp9oXsS79S3bfCNXKeEo4av0xcd7slk/TfPpCa5pojg8ZVXSVfPZMAAlhOuK63YXrKN/e3jRNReeGP+2Gw==", "integrity": "sha512-9ocqJb0Pr9k0TownEMd75payF/XOQLF/swr/l0Ep49D+m609uIZsW09CtowhXmk1KrIFobS3+SkdXK04CSyUwQ==",
"optional": true, "optional": true,
"os": [ "os": [
"win32" "win32"
] ]
}, },
"node_modules/exiftool-vendored.pl": { "node_modules/exiftool-vendored.pl": {
"version": "12.85.0", "version": "12.84.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.85.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.84.0.tgz",
"integrity": "sha512-AelZQCCfl0a0g7PYx90TqbNGlSu2zDbRfCTjGw6bBBYnJF0NUfUWVhTpa8XGe2lHx1KYikH8AkJaey3esAxMAg==", "integrity": "sha512-TxvMRaVYtd24Vupn48zy24LOYItIIWEu4dgt/VlqLwxQItTpvJTV9YH04iZRvaNh9ZdPRgVKWMuuUDBBHv+lAg==",
"optional": true, "optional": true,
"os": [ "os": [
"!win32" "!win32"
@ -23434,29 +23433,29 @@
} }
}, },
"exiftool-vendored": { "exiftool-vendored": {
"version": "27.0.0", "version": "26.0.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-27.0.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-26.0.0.tgz",
"integrity": "sha512-/jHX8Jjadj0YJzpqnuBo1Yy2ln2hnRbBIc+3jcVOLQ6qhHEKsLRlfJ145Ghn7k/EcnfpDzVX3V8AUCTC8juTow==", "integrity": "sha512-2TRxx21ovD95VvdSzHb/sTYYcwhiizQIhhVAbrgua9KoL902QRieREGvaUtfBZNjsptdjonuyku2kUBJCPqsgw==",
"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.85.0", "exiftool-vendored.exe": "12.84.0",
"exiftool-vendored.pl": "12.85.0", "exiftool-vendored.pl": "12.84.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.85.0", "version": "12.84.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.85.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.84.0.tgz",
"integrity": "sha512-rWsKVp9oXsS79S3bfCNXKeEo4av0xcd7slk/TfPpCa5pojg8ZVXSVfPZMAAlhOuK63YXrKN/e3jRNReeGP+2Gw==", "integrity": "sha512-9ocqJb0Pr9k0TownEMd75payF/XOQLF/swr/l0Ep49D+m609uIZsW09CtowhXmk1KrIFobS3+SkdXK04CSyUwQ==",
"optional": true "optional": true
}, },
"exiftool-vendored.pl": { "exiftool-vendored.pl": {
"version": "12.85.0", "version": "12.84.0",
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.85.0.tgz", "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.84.0.tgz",
"integrity": "sha512-AelZQCCfl0a0g7PYx90TqbNGlSu2zDbRfCTjGw6bBBYnJF0NUfUWVhTpa8XGe2lHx1KYikH8AkJaey3esAxMAg==", "integrity": "sha512-TxvMRaVYtd24Vupn48zy24LOYItIIWEu4dgt/VlqLwxQItTpvJTV9YH04iZRvaNh9ZdPRgVKWMuuUDBBHv+lAg==",
"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": "~27.0.0", "exiftool-vendored": "26.0.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, ExifTool, Tags } from 'exiftool-vendored'; import { DefaultReadTaskOptions, Tags, exiftool } 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';
@ -17,39 +17,40 @@ export class MetadataRepository implements IMetadataRepository {
@Inject(ILoggerRepository) private logger: ILoggerRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository,
) { ) {
this.logger.setContext(MetadataRepository.name); this.logger.setContext(MetadataRepository.name);
this.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'],
});
} }
private exiftool: ExifTool;
async teardown() { async teardown() {
await this.exiftool.end(); await exiftool.end();
} }
readTags(path: string): Promise<ImmichTags | null> { readTags(path: string): Promise<ImmichTags | null> {
return this.exiftool.read(path).catch((error) => { return exiftool
this.logger.warn(`Error reading exif data (${path}): ${error}`, error?.stack); .read(path, undefined, {
return null; ...DefaultReadTaskOptions,
}) 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 this.exiftool.extractBinaryTagToBuffer(tagName, path); return 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 this.exiftool.write(path, tags); await exiftool.write(path, tags, ['-overwrite_original']);
} catch (error) { } catch (error) {
this.logger.warn(`Error writing exif data (${path}): ${error}`); this.logger.warn(`Error writing exif data (${path}): ${error}`);
} }