mirror of
https://github.com/immich-app/immich.git
synced 2025-01-21 00:52:43 -05:00
feat(server): delete unnecessary encoded videos (#6027)
* delete unnecessary transcodes * added test
This commit is contained in:
parent
fd3a1a4da8
commit
a1e1f11399
3 changed files with 67 additions and 6 deletions
|
@ -658,6 +658,21 @@ describe(MediaService.name, () => {
|
||||||
expect(mediaMock.transcode).not.toHaveBeenCalled();
|
expect(mediaMock.transcode).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should delete existing transcode if current policy does not require transcoding', async () => {
|
||||||
|
const asset = assetStub.hasEncodedVideo;
|
||||||
|
mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p);
|
||||||
|
configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.DISABLED }]);
|
||||||
|
assetMock.getByIds.mockResolvedValue([asset]);
|
||||||
|
|
||||||
|
await sut.handleVideoConversion({ id: asset.id });
|
||||||
|
|
||||||
|
expect(mediaMock.transcode).not.toHaveBeenCalled();
|
||||||
|
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||||
|
name: JobName.DELETE_FILES,
|
||||||
|
data: { files: [asset.encodedVideoPath] },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should set max bitrate if above 0', async () => {
|
it('should set max bitrate if above 0', async () => {
|
||||||
mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
||||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }]);
|
configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }]);
|
||||||
|
|
|
@ -241,11 +241,22 @@ export class MediaService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mainVideoStream.height || !mainVideoStream.width) {
|
||||||
|
this.logger.warn(`Skipped transcoding for asset ${asset.id}: no video streams found`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const { ffmpeg: config } = await this.configCore.getConfig();
|
const { ffmpeg: config } = await this.configCore.getConfig();
|
||||||
|
|
||||||
const required = this.isTranscodeRequired(asset, mainVideoStream, mainAudioStream, containerExtension, config);
|
const required = this.isTranscodeRequired(asset, mainVideoStream, mainAudioStream, containerExtension, config);
|
||||||
if (!required) {
|
if (!required) {
|
||||||
return false;
|
if (asset.encodedVideoPath) {
|
||||||
|
this.logger.log(`Transcoded video exists for asset ${asset.id}, but is no longer required. Deleting...`);
|
||||||
|
await this.jobRepository.queue({ name: JobName.DELETE_FILES, data: { files: [asset.encodedVideoPath] } });
|
||||||
|
await this.assetRepository.save({ id: asset.id, encodedVideoPath: null });
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let transcodeOptions;
|
let transcodeOptions;
|
||||||
|
@ -289,11 +300,6 @@ export class MediaService {
|
||||||
containerExtension: string,
|
containerExtension: string,
|
||||||
ffmpegConfig: SystemConfigFFmpegDto,
|
ffmpegConfig: SystemConfigFFmpegDto,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!videoStream.height || !videoStream.width) {
|
|
||||||
this.logger.error('Skipping transcode, height or width undefined for video stream');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isTargetVideoCodec = videoStream.codecName === ffmpegConfig.targetVideoCodec;
|
const isTargetVideoCodec = videoStream.codecName === ffmpegConfig.targetVideoCodec;
|
||||||
const isTargetContainer = ['mov,mp4,m4a,3gp,3g2,mj2', 'mp4', 'mov'].includes(containerExtension);
|
const isTargetContainer = ['mov,mp4,m4a,3gp,3g2,mj2', 'mp4', 'mov'].includes(containerExtension);
|
||||||
const isTargetAudioCodec = audioStream == null || audioStream.codecName === ffmpegConfig.targetAudioCodec;
|
const isTargetAudioCodec = audioStream == null || audioStream.codecName === ffmpegConfig.targetAudioCodec;
|
||||||
|
|
40
server/test/fixtures/asset.stub.ts
vendored
40
server/test/fixtures/asset.stub.ts
vendored
|
@ -545,4 +545,44 @@ export const assetStub = {
|
||||||
sidecarPath: '/original/path.ext.xmp',
|
sidecarPath: '/original/path.ext.xmp',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
hasEncodedVideo: Object.freeze<AssetEntity>({
|
||||||
|
id: 'asset-id',
|
||||||
|
originalFileName: 'asset-id.ext',
|
||||||
|
deviceAssetId: 'device-asset-id',
|
||||||
|
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
owner: userStub.user1,
|
||||||
|
ownerId: 'user-id',
|
||||||
|
deviceId: 'device-id',
|
||||||
|
originalPath: '/original/path.ext',
|
||||||
|
resizePath: '/uploads/user-id/thumbs/path.ext',
|
||||||
|
checksum: Buffer.from('file hash', 'utf8'),
|
||||||
|
type: AssetType.VIDEO,
|
||||||
|
webpPath: null,
|
||||||
|
thumbhash: null,
|
||||||
|
encodedVideoPath: '/encoded/video/path.mp4',
|
||||||
|
createdAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
localDateTime: new Date('2023-02-23T05:06:29.716Z'),
|
||||||
|
isFavorite: true,
|
||||||
|
isArchived: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
isExternal: false,
|
||||||
|
isOffline: false,
|
||||||
|
libraryId: 'library-id',
|
||||||
|
library: libraryStub.uploadLibrary1,
|
||||||
|
duration: null,
|
||||||
|
isVisible: true,
|
||||||
|
livePhotoVideo: null,
|
||||||
|
livePhotoVideoId: null,
|
||||||
|
tags: [],
|
||||||
|
sharedLinks: [],
|
||||||
|
faces: [],
|
||||||
|
sidecarPath: null,
|
||||||
|
exifInfo: {
|
||||||
|
fileSizeInByte: 100_000,
|
||||||
|
} as ExifEntity,
|
||||||
|
deletedAt: null,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue