Merge branch 'fix/asset-service-argument-order' of https://github.com/immich-app/immich into feat/sidecar-asset-files

This commit is contained in:
Jonathan Jogenfors
2025-10-31 00:50:15 +01:00
2 changed files with 33 additions and 15 deletions

View File

@@ -262,32 +262,33 @@ export class AssetService extends BaseService {
sourceAsset,
targetAsset,
}: {
sourceAsset: { id: string; files: AssetFile[] | null; originalPath: string };
targetAsset: { files: AssetFile[] | null };
sourceAsset: { files?: AssetFile[] };
targetAsset: { id: string; files?: AssetFile[]; originalPath: string };
}) {
if (!targetAsset.files) {
if (!sourceAsset.files) {
return;
}
const targetSidecarFile = getAssetFiles(targetAsset.files).sidecarFile;
const sourceSidecarPath = getAssetFiles(sourceAsset.files).sidecarFile?.path;
if (!targetSidecarFile) {
if (!sourceSidecarPath) {
return;
}
const sourceSidecarFile = getAssetFiles(sourceAsset.files).sidecarFile;
if (sourceSidecarFile) {
await this.storageRepository.unlink(sourceSidecarFile.path);
if (targetAsset.files) {
const targetSidecar = getAssetFiles(targetAsset.files).sidecarFile;
if (targetSidecar) {
await this.storageRepository.unlink(targetSidecar.path);
}
}
await this.storageRepository.copyFile(targetSidecarFile.path, `${sourceAsset.originalPath}.xmp`);
await this.storageRepository.copyFile(sourceSidecarPath, `${targetAsset.originalPath}.xmp`);
await this.assetRepository.upsertFile({
assetId: sourceAsset.id,
assetId: targetAsset.id,
path: `${targetAsset.originalPath}.xmp`,
type: AssetFileType.Sidecar,
path: `${sourceAsset.originalPath}.xmp`,
});
await this.jobRepository.queue({ name: JobName.AssetExtractMetadata, data: { id: sourceAsset.id } });
await this.jobRepository.queue({ name: JobName.AssetExtractMetadata, data: { id: targetAsset.id } });
}
@OnJob({ name: JobName.AssetDeleteCheck, queue: QueueName.BackgroundTask })

View File

@@ -1,5 +1,5 @@
import { Kysely } from 'kysely';
import { JobName, SharedLinkType } from 'src/enum';
import { AssetFileType, JobName, SharedLinkType } from 'src/enum';
import { AccessRepository } from 'src/repositories/access.repository';
import { AlbumRepository } from 'src/repositories/album.repository';
import { AssetRepository } from 'src/repositories/asset.repository';
@@ -179,12 +179,23 @@ describe(AssetService.name, () => {
const { sut, ctx } = setup();
const storageRepo = ctx.getMock(StorageRepository);
const jobRepo = ctx.getMock(JobRepository);
const assetRepo = ctx.getMock(AssetRepository);
storageRepo.copyFile.mockResolvedValue();
jobRepo.queue.mockResolvedValue();
const { user } = await ctx.newUser();
const { asset: oldAsset } = await ctx.newAsset({ ownerId: user.id, sidecarPath: '/path/to/my/sidecar.xmp' });
const { asset: oldAssetWithoutSidecar } = await ctx.newAsset({ ownerId: user.id });
const sidecarFile = await ctx.newAssetFile({
assetId: oldAssetWithoutSidecar.id,
path: '/path/to/my/sidecar.xmp',
type: AssetFileType.Sidecar,
});
const oldAsset = { ...oldAssetWithoutSidecar, files: [sidecarFile] };
const { asset: newAsset } = await ctx.newAsset({ ownerId: user.id });
await ctx.newExif({ assetId: oldAsset.id, description: 'foo' });
@@ -196,6 +207,12 @@ describe(AssetService.name, () => {
expect(storageRepo.copyFile).toHaveBeenCalledWith('/path/to/my/sidecar.xmp', `${newAsset.originalPath}.xmp`);
expect(assetRepo.upsertFile).toHaveBeenCalledWith({
assetId: newAsset.id,
path: `${newAsset.originalPath}.xmp`,
type: AssetFileType.Sidecar,
});
expect(jobRepo.queue).toHaveBeenCalledWith({
name: JobName.AssetExtractMetadata,
data: { id: newAsset.id },