Compare commits

..

2 Commits

Author SHA1 Message Date
renovate[bot]
0e84f91751 chore(deps): update dependency terragrunt to v0.93.12 2025-12-06 20:47:39 +00:00
Sergey Katsubo
42136f9091 fix(server): update exiftool-vendored to v34 for more robust metadata extraction (#24424) 2025-12-06 14:45:59 -06:00
10 changed files with 40 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
[tools]
terragrunt = "0.93.10"
terragrunt = "0.93.12"
opentofu = "1.10.7"
[tasks."tg:fmt"]

View File

@@ -36,7 +36,7 @@
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^62.0.0",
"exiftool-vendored": "^33.0.0",
"exiftool-vendored": "^34.0.0",
"globals": "^16.0.0",
"jose": "^5.6.3",
"luxon": "^3.4.4",

View File

@@ -4,7 +4,7 @@ experimental_monorepo_root = true
node = "24.11.1"
flutter = "3.35.7"
pnpm = "10.24.0"
terragrunt = "0.93.10"
terragrunt = "0.93.12"
opentofu = "1.10.7"
java = "25.0.1"

39
pnpm-lock.yaml generated
View File

@@ -244,8 +244,8 @@ importers:
specifier: ^62.0.0
version: 62.0.0(eslint@9.39.1(jiti@2.6.1))
exiftool-vendored:
specifier: ^33.0.0
version: 33.5.0
specifier: ^34.0.0
version: 34.0.0
globals:
specifier: ^16.0.0
version: 16.5.0
@@ -428,8 +428,8 @@ importers:
specifier: 4.3.3
version: 4.3.3
exiftool-vendored:
specifier: ^33.0.0
version: 33.5.0
specifier: ^34.0.0
version: 34.0.0
express:
specifier: ^5.1.0
version: 5.2.0
@@ -3236,6 +3236,7 @@ packages:
'@koa/router@14.0.0':
resolution: {integrity: sha512-LBSu5K0qAaaQcXX/0WIB9PGDevyCxxpnc1uq13vV/CgObaVxuis5hKl3Eboq/8gcb6ebnkAStW9NB/Em2eYyFA==}
engines: {node: '>= 20'}
deprecated: Please upgrade to v15 or higher. All reported bugs in this version are fixed in newer releases, dependencies have been updated, and security has been improved.
'@koddsson/eslint-plugin-tscompat@0.2.0':
resolution: {integrity: sha512-Oqd4kWSX0LiO9wWHjcmDfXZNC7TotFV/tLRhwCFU3XUeb//KYvJ75c9OmeSJ+vBv5lkCeB+xYsqyNrBc5j18XA==}
@@ -5503,8 +5504,8 @@ packages:
resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==}
hasBin: true
batch-cluster@15.0.1:
resolution: {integrity: sha512-eUmh0ld1AUPKTEmdzwGF9QTSexXAyt9rA1F5zDfW1wUi3okA3Tal4NLdCeFI6aiKpBenQhR6NmK9bW9tBHTGPQ==}
batch-cluster@16.0.0:
resolution: {integrity: sha512-+T7Ho09ikx/kP4P8M+GEnpuePzRQa4gTUhtPIu6ApFC8+0GY0sri1y1PuB+yfXlQWl5DkHC/e58z3U6g0qCz/A==}
engines: {node: '>=20'}
batch@0.6.1:
@@ -6848,17 +6849,17 @@ packages:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
exiftool-vendored.exe@13.42.0:
resolution: {integrity: sha512-6AFybe5IakduMWleuQBfep9OWGSVZSedt2uKL+LzufRsATp+beOF7tZyKtMztjb6VRH1GF/4F9EvBVam6zm70w==}
exiftool-vendored.exe@13.43.0:
resolution: {integrity: sha512-EENHNz86tYY5yHGPtGB2mto3FIGstQvEhrcU34f7fm4RMxBKNfTWYOGkhU1jzvjOi+V4575LQX/FUES1TwgUbQ==}
os: [win32]
exiftool-vendored.pl@13.42.0:
resolution: {integrity: sha512-EF5IdxQNIJIvZjHf4bG4jnwAHVVSLkYZToo2q+Mm89kSuppKfRvHz/lngIxN0JALE8rFdC4zt6NWY/PKqRdCcg==}
exiftool-vendored.pl@13.43.0:
resolution: {integrity: sha512-0ApWaQ/pxaliPK7HzTxVA0sg/wZ8vl7UtFVhCyWhGQg01WfZkFrKwKmELB0Bnn01WTfgIuMadba8ccmFvpmJag==}
os: ['!win32']
hasBin: true
exiftool-vendored@33.5.0:
resolution: {integrity: sha512-7cCh6izwdmC5ZaCxpHFehnExIr2Yp7CJuxHg4WFiGcm81yyxXLtvSE+85ep9VsNwhlOtSpk+XxiqrlddjY5lAw==}
exiftool-vendored@34.0.0:
resolution: {integrity: sha512-rhIe4XGE7kh76nwytwHtq6qK/pc1mpOBHRV++gudFeG2PfAp3XIVQbFWCLK3S4l9I4AWYOe4mxk8mW8l1oHRTw==}
engines: {node: '>=20.0.0'}
expect-type@1.2.1:
@@ -17580,7 +17581,7 @@ snapshots:
baseline-browser-mapping@2.8.31: {}
batch-cluster@15.0.1: {}
batch-cluster@16.0.0: {}
batch@0.6.1: {}
@@ -19128,21 +19129,21 @@ snapshots:
signal-exit: 3.0.7
strip-final-newline: 2.0.0
exiftool-vendored.exe@13.42.0:
exiftool-vendored.exe@13.43.0:
optional: true
exiftool-vendored.pl@13.42.0: {}
exiftool-vendored.pl@13.43.0: {}
exiftool-vendored@33.5.0:
exiftool-vendored@34.0.0:
dependencies:
'@photostructure/tz-lookup': 11.3.0
'@types/luxon': 3.7.1
batch-cluster: 15.0.1
exiftool-vendored.pl: 13.42.0
batch-cluster: 16.0.0
exiftool-vendored.pl: 13.43.0
he: 1.2.0
luxon: 3.7.2
optionalDependencies:
exiftool-vendored.exe: 13.42.0
exiftool-vendored.exe: 13.43.0
expect-type@1.2.1: {}

View File

@@ -70,7 +70,7 @@
"cookie": "^1.0.2",
"cookie-parser": "^1.4.7",
"cron": "4.3.3",
"exiftool-vendored": "^33.0.0",
"exiftool-vendored": "^34.0.0",
"express": "^5.1.0",
"fast-glob": "^3.3.2",
"fluent-ffmpeg": "^2.1.2",

View File

@@ -188,7 +188,7 @@
// the performance benefits of deferred layouts while still supporting deep linking
// to assets at the end of the timeline.
timelineManager.isScrollingOnLoad = true;
const monthGroup = await timelineManager.findMonthGroupForAsset({ id: assetId });
const monthGroup = await timelineManager.findMonthGroupForAsset(assetId);
if (!monthGroup) {
return false;
}

View File

@@ -1,5 +1,5 @@
import { plainDateTimeCompare, type TimelineYearMonth } from '$lib/utils/timeline-util';
import { AssetOrder, type AssetResponseDto } from '@immich/sdk';
import { AssetOrder } from '@immich/sdk';
import { DateTime } from 'luxon';
import type { MonthGroup } from '../month-group.svelte';
import { TimelineManager } from '../timeline-manager.svelte';
@@ -7,16 +7,12 @@ import type { AssetDescriptor, Direction, TimelineAsset } from '../types';
export async function getAssetWithOffset(
timelineManager: TimelineManager,
assetDescriptor: AssetDescriptor | AssetResponseDto,
assetDescriptor: AssetDescriptor,
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
direction: Direction,
): Promise<TimelineAsset | undefined> {
const monthGroup = await timelineManager.findMonthGroupForAsset(assetDescriptor);
if (!monthGroup) {
return;
}
const asset = monthGroup.findAssetById(assetDescriptor);
if (!asset) {
const { asset, monthGroup } = findMonthGroupForAsset(timelineManager, assetDescriptor.id) ?? {};
if (!monthGroup || !asset) {
return;
}

View File

@@ -524,7 +524,6 @@ describe('TimelineManager', () => {
{ count: 3, timeBucket: '2024-01-01T00:00:00.000Z' },
]);
sdkMock.getTimeBucket.mockImplementation(({ timeBucket }) => Promise.resolve(bucketAssetsResponse[timeBucket]));
sdkMock.getAssetInfo.mockRejectedValue(new Error('Asset not found'));
await timelineManager.updateViewport({ width: 1588, height: 1000 });
});

View File

@@ -16,13 +16,12 @@ import { WebsocketSupport } from '$lib/managers/timeline-manager/internal/websoc
import { CancellableTask } from '$lib/utils/cancellable-task';
import { PersistedLocalStorage } from '$lib/utils/persisted';
import {
isAssetResponseDto,
setDifference,
toTimelineAsset,
type TimelineDateTime,
type TimelineYearMonth,
} from '$lib/utils/timeline-util';
import { AssetOrder, getAssetInfo, getTimeBuckets, type AssetResponseDto } from '@immich/sdk';
import { AssetOrder, getAssetInfo, getTimeBuckets } from '@immich/sdk';
import { clamp, isEqual } from 'lodash-es';
import { SvelteDate, SvelteSet } from 'svelte/reactivity';
import { DayGroup } from './day-group.svelte';
@@ -344,30 +343,27 @@ export class TimelineManager extends VirtualScrollManager {
this.addAssetsUpsertSegments([...notExcluded]);
}
async findMonthGroupForAsset(asset: AssetDescriptor | AssetResponseDto) {
async findMonthGroupForAsset(id: string) {
if (!this.isInitialized) {
await this.initTask.waitUntilCompletion();
}
const { id } = asset;
let { monthGroup } = findMonthGroupForAssetUtil(this, id) ?? {};
if (monthGroup) {
return monthGroup;
}
const response = isAssetResponseDto(asset)
? asset
: await getAssetInfo({ ...authManager.params, id }).catch(() => null);
const response = await getAssetInfo({ ...authManager.params, id }).catch(() => null);
if (!response) {
return;
}
const timelineAsset = toTimelineAsset(response);
if (this.isExcluded(timelineAsset)) {
const asset = toTimelineAsset(response);
if (!asset || this.isExcluded(asset)) {
return;
}
monthGroup = await this.#loadMonthGroupAtTime(timelineAsset.localDateTime, { cancelable: false });
monthGroup = await this.#loadMonthGroupAtTime(asset.localDateTime, { cancelable: false });
if (monthGroup?.findAssetById({ id })) {
return monthGroup;
}
@@ -536,14 +532,14 @@ export class TimelineManager extends VirtualScrollManager {
}
async getLaterAsset(
assetDescriptor: AssetDescriptor | AssetResponseDto,
assetDescriptor: AssetDescriptor,
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
): Promise<TimelineAsset | undefined> {
return await getAssetWithOffset(this, assetDescriptor, interval, 'later');
}
async getEarlierAsset(
assetDescriptor: AssetDescriptor | AssetResponseDto,
assetDescriptor: AssetDescriptor,
interval: 'asset' | 'day' | 'month' | 'year' = 'asset',
): Promise<TimelineAsset | undefined> {
return await getAssetWithOffset(this, assetDescriptor, interval, 'earlier');

View File

@@ -1,4 +1,4 @@
import type { AssetDescriptor, TimelineAsset, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
import type { TimelineAsset, ViewportTopMonth } from '$lib/managers/timeline-manager/types';
import { locale } from '$lib/stores/preferences.store';
import { getAssetRatio } from '$lib/utils/asset-utils';
import { AssetTypeEnum, type AssetResponseDto } from '@immich/sdk';
@@ -192,13 +192,8 @@ export const toTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset):
};
};
export const isTimelineAsset = (
unknownAsset: AssetDescriptor | AssetResponseDto | TimelineAsset,
): unknownAsset is TimelineAsset => (unknownAsset as TimelineAsset).ratio !== undefined;
export const isAssetResponseDto = (
unknownAsset: AssetDescriptor | AssetResponseDto | TimelineAsset,
): unknownAsset is AssetResponseDto => (unknownAsset as AssetResponseDto).type !== undefined;
export const isTimelineAsset = (unknownAsset: AssetResponseDto | TimelineAsset): unknownAsset is TimelineAsset =>
(unknownAsset as TimelineAsset).ratio !== undefined;
export const isTimelineAssets = (assets: AssetResponseDto[] | TimelineAsset[]): assets is TimelineAsset[] =>
assets.length === 0 || 'ratio' in assets[0];