1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-01 08:31:59 +00:00

fix(server): regenerate (extract) motion videos (#9438)

This commit is contained in:
Jason Rasmussen 2024-05-13 16:38:11 -04:00 committed by GitHub
parent b7ebf3152f
commit 1bebc7368c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 16 additions and 8 deletions

View file

@ -459,10 +459,14 @@ describe(MetadataService.name, () => {
storageMock.readFile.mockResolvedValue(video); storageMock.readFile.mockResolvedValue(video);
await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id });
expect(jobMock.queue).toHaveBeenNthCalledWith(2, { expect(jobMock.queue).toHaveBeenNthCalledWith(1, {
name: JobName.ASSET_DELETION, name: JobName.ASSET_DELETION,
data: { id: assetStub.livePhotoStillAsset.livePhotoVideoId }, data: { id: assetStub.livePhotoStillAsset.livePhotoVideoId },
}); });
expect(jobMock.queue).toHaveBeenNthCalledWith(2, {
name: JobName.METADATA_EXTRACTION,
data: { id: 'random-uuid' },
});
}); });
it('should not create a new motion photo video asset if the hash of the extracted video matches an existing asset', async () => { it('should not create a new motion photo video asset if the hash of the extracted video matches an existing asset', async () => {
@ -477,6 +481,7 @@ describe(MetadataService.name, () => {
assetMock.getByChecksum.mockResolvedValue(assetStub.livePhotoMotionAsset); assetMock.getByChecksum.mockResolvedValue(assetStub.livePhotoMotionAsset);
const video = randomBytes(512); const video = randomBytes(512);
storageMock.readFile.mockResolvedValue(video); storageMock.readFile.mockResolvedValue(video);
storageMock.checkFileExists.mockResolvedValue(true);
await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id });
expect(assetMock.create).toHaveBeenCalledTimes(0); expect(assetMock.create).toHaveBeenCalledTimes(0);

View file

@ -423,10 +423,7 @@ export class MetadataService {
this.logger.log(`Hid unlinked motion photo video asset (${motionAsset.id})`); this.logger.log(`Hid unlinked motion photo video asset (${motionAsset.id})`);
} }
} else { } else {
// We create a UUID in advance so that each extracted video can have a unique filename
// (allowing us to delete old ones if necessary)
const motionAssetId = this.cryptoRepository.randomUUID(); const motionAssetId = this.cryptoRepository.randomUUID();
const motionPath = StorageCore.getAndroidMotionPath(asset, motionAssetId);
const createdAt = asset.fileCreatedAt ?? asset.createdAt; const createdAt = asset.fileCreatedAt ?? asset.createdAt;
motionAsset = await this.assetRepository.create({ motionAsset = await this.assetRepository.create({
id: motionAssetId, id: motionAssetId,
@ -437,16 +434,13 @@ export class MetadataService {
localDateTime: createdAt, localDateTime: createdAt,
checksum, checksum,
ownerId: asset.ownerId, ownerId: asset.ownerId,
originalPath: motionPath, originalPath: StorageCore.getAndroidMotionPath(asset, motionAssetId),
originalFileName: asset.originalFileName, originalFileName: asset.originalFileName,
isVisible: false, isVisible: false,
deviceAssetId: 'NONE', deviceAssetId: 'NONE',
deviceId: 'NONE', deviceId: 'NONE',
}); });
this.storageCore.ensureFolders(motionPath);
await this.storageRepository.writeFile(motionAsset.originalPath, video);
await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: motionAsset.id } });
if (!asset.isExternal) { if (!asset.isExternal) {
await this.userRepository.updateUsage(asset.ownerId, video.byteLength); await this.userRepository.updateUsage(asset.ownerId, video.byteLength);
} }
@ -465,6 +459,15 @@ export class MetadataService {
} }
} }
// write extracted motion video to disk, especially if the encoded-video folder has been deleted
const existsOnDisk = await this.storageRepository.checkFileExists(motionAsset.originalPath);
if (!existsOnDisk) {
this.storageCore.ensureFolders(motionAsset.originalPath);
await this.storageRepository.writeFile(motionAsset.originalPath, video);
this.logger.log(`Wrote motion photo video to ${motionAsset.originalPath}`);
await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: motionAsset.id } });
}
this.logger.debug(`Finished motion photo video extraction (${asset.id})`); this.logger.debug(`Finished motion photo video extraction (${asset.id})`);
} catch (error: Error | any) { } catch (error: Error | any) {
this.logger.error(`Failed to extract live photo ${asset.originalPath}: ${error}`, error?.stack); this.logger.error(`Failed to extract live photo ${asset.originalPath}: ${error}`, error?.stack);