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:
parent
b7ebf3152f
commit
1bebc7368c
2 changed files with 16 additions and 8 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue