mirror of
https://github.com/immich-app/immich.git
synced 2024-12-28 22:51:59 +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:
parent
87e8c16a90
commit
fb8d9d8c40
6 changed files with 62 additions and 54 deletions
|
@ -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: {
|
||||||
|
|
|
@ -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
|
47
server/package-lock.json
generated
47
server/package-lock.json
generated
|
@ -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": {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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}`);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue