1
0
forked from Cutlery/immich

update target paths, fix tests

This commit is contained in:
mertalev 2024-03-24 02:16:09 -04:00
parent 35a2aa472a
commit a9b90787b2
No known key found for this signature in database
GPG Key ID: 9181CD92C0A1C5E3
4 changed files with 80 additions and 69 deletions

View File

@ -4,6 +4,7 @@ import { SystemConfigCore } from 'src/cores/system-config.core';
import { AssetEntity } from 'src/entities/asset.entity';
import { AssetPathType, PathType, PersonPathType } from 'src/entities/move.entity';
import { PersonEntity } from 'src/entities/person.entity';
import { ImageFormat } from 'src/entities/system-config.entity';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
@ -95,8 +96,8 @@ export class StorageCore {
return StorageCore.getNestedPath(StorageFolder.THUMBNAILS, person.ownerId, `${person.id}.jpeg`);
}
static getImagePath(asset: AssetEntity, type: GeneratedImageType) {
return StorageCore.getNestedPath(StorageFolder.THUMBNAILS, asset.ownerId, `${asset.id}.${type}`);
static getImagePath(asset: AssetEntity, type: GeneratedImageType, format: ImageFormat) {
return StorageCore.getNestedPath(StorageFolder.THUMBNAILS, asset.ownerId, `${asset.id}-${type}.${format}`);
}
static getEncodedVideoPath(asset: AssetEntity) {
@ -119,34 +120,23 @@ export class StorageCore {
return path.startsWith(THUMBNAIL_DIR) || path.startsWith(ENCODED_VIDEO_DIR);
}
async moveAssetFile(asset: AssetEntity, pathType: GeneratedAssetType) {
const { id: entityId, previewPath, thumbnailPath, encodedVideoPath } = asset;
switch (pathType) {
case AssetPathType.PREVIEW: {
return this.moveFile({
entityId,
pathType,
oldPath: previewPath,
newPath: StorageCore.getImagePath(asset, AssetPathType.PREVIEW),
});
}
case AssetPathType.THUMBNAIL: {
return this.moveFile({
entityId,
pathType,
oldPath: thumbnailPath,
newPath: StorageCore.getImagePath(asset, AssetPathType.THUMBNAIL),
});
}
case AssetPathType.ENCODED_VIDEO: {
return this.moveFile({
entityId,
pathType,
oldPath: encodedVideoPath,
newPath: StorageCore.getEncodedVideoPath(asset),
});
}
}
async moveAssetImage(asset: AssetEntity, pathType: GeneratedAssetType, format: ImageFormat) {
const { id: entityId, previewPath, thumbnailPath } = asset;
return this.moveFile({
entityId,
pathType,
oldPath: pathType === AssetPathType.PREVIEW ? previewPath : thumbnailPath,
newPath: StorageCore.getImagePath(asset, AssetPathType.THUMBNAIL, format),
});
}
async moveAssetVideo(asset: AssetEntity) {
return this.moveFile({
entityId: asset.id,
pathType: AssetPathType.ENCODED_VIDEO,
oldPath: asset.encodedVideoPath,
newPath: StorageCore.getEncodedVideoPath(asset),
});
}
async movePersonFile(person: PersonEntity, pathType: PersonPathType) {

View File

@ -4,6 +4,7 @@ import { ExifEntity } from 'src/entities/exif.entity';
import {
AudioCodec,
Colorspace,
ImageFormat,
SystemConfigKey,
ToneMapping,
TranscodeHWAccel,
@ -214,15 +215,19 @@ describe(MediaService.name, () => {
await sut.handleGeneratePreview({ id: assetStub.image.id });
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
expect(mediaMock.resize).toHaveBeenCalledWith('/original/path.jpg', 'upload/thumbs/user-id/as/se/asset-id.jpeg', {
size: 1440,
format: 'jpeg',
quality: 80,
colorspace: Colorspace.SRGB,
});
expect(mediaMock.resize).toHaveBeenCalledWith(
'/original/path.jpg',
'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
{
size: 1440,
format: ImageFormat.JPEG,
quality: 80,
colorspace: Colorspace.SRGB,
},
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
previewPath: 'upload/thumbs/user-id/as/se/asset-id.jpeg',
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
});
});
@ -233,15 +238,19 @@ describe(MediaService.name, () => {
await sut.handleGeneratePreview({ id: assetStub.image.id });
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
expect(mediaMock.resize).toHaveBeenCalledWith('/original/path.jpg', 'upload/thumbs/user-id/as/se/asset-id.jpeg', {
size: 1440,
format: 'jpeg',
quality: 80,
colorspace: Colorspace.P3,
});
expect(mediaMock.resize).toHaveBeenCalledWith(
'/original/path.jpg',
'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
{
size: 1440,
format: ImageFormat.JPEG,
quality: 80,
colorspace: Colorspace.P3,
},
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
previewPath: 'upload/thumbs/user-id/as/se/asset-id.jpeg',
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
});
});
@ -253,7 +262,7 @@ describe(MediaService.name, () => {
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
expect(mediaMock.transcode).toHaveBeenCalledWith(
'/original/path.ext',
'upload/thumbs/user-id/as/se/asset-id.jpeg',
'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
{
inputOptions: ['-ss 00:00:00', '-sws_flags accurate_rnd+bitexact+full_chroma_int'],
outputOptions: [
@ -266,7 +275,7 @@ describe(MediaService.name, () => {
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
previewPath: 'upload/thumbs/user-id/as/se/asset-id.jpeg',
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
});
});
@ -278,7 +287,7 @@ describe(MediaService.name, () => {
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
expect(mediaMock.transcode).toHaveBeenCalledWith(
'/original/path.ext',
'upload/thumbs/user-id/as/se/asset-id.jpeg',
'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
{
inputOptions: ['-ss 00:00:00', '-sws_flags accurate_rnd+bitexact+full_chroma_int'],
outputOptions: [
@ -291,7 +300,7 @@ describe(MediaService.name, () => {
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
previewPath: 'upload/thumbs/user-id/as/se/asset-id.jpeg',
previewPath: 'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
});
});
@ -306,7 +315,7 @@ describe(MediaService.name, () => {
expect(mediaMock.transcode).toHaveBeenCalledWith(
'/original/path.ext',
'upload/thumbs/user-id/as/se/asset-id.jpeg',
'upload/thumbs/user-id/as/se/asset-id-preview.jpeg',
{
inputOptions: ['-ss 00:00:00', '-sws_flags accurate_rnd+bitexact+full_chroma_int'],
outputOptions: [
@ -337,15 +346,19 @@ describe(MediaService.name, () => {
assetMock.getByIds.mockResolvedValue([assetStub.image]);
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
expect(mediaMock.resize).toHaveBeenCalledWith('/original/path.jpg', 'upload/thumbs/user-id/as/se/asset-id.webp', {
format: 'webp',
size: 250,
quality: 80,
colorspace: Colorspace.SRGB,
});
expect(mediaMock.resize).toHaveBeenCalledWith(
'/original/path.jpg',
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
{
format: ImageFormat.WEBP,
size: 250,
quality: 80,
colorspace: Colorspace.SRGB,
},
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
thumbnailPath: 'upload/thumbs/user-id/as/se/asset-id.webp',
thumbnailPath: 'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
});
});
});
@ -357,15 +370,19 @@ describe(MediaService.name, () => {
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
expect(mediaMock.resize).toHaveBeenCalledWith('/original/path.jpg', 'upload/thumbs/user-id/as/se/asset-id.webp', {
format: 'webp',
size: 250,
quality: 80,
colorspace: Colorspace.P3,
});
expect(mediaMock.resize).toHaveBeenCalledWith(
'/original/path.jpg',
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
{
format: ImageFormat.WEBP,
size: 250,
quality: 80,
colorspace: Colorspace.P3,
},
);
expect(assetMock.update).toHaveBeenCalledWith({
id: 'asset-id',
thumbnailPath: 'upload/thumbs/user-id/as/se/asset-id.webp',
thumbnailPath: 'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
});
});

View File

@ -153,14 +153,15 @@ export class MediaService {
}
async handleAssetMigration({ id }: IEntityJob): Promise<JobStatus> {
const { thumbnail } = await this.configCore.getConfig();
const [asset] = await this.assetRepository.getByIds([id]);
if (!asset) {
return JobStatus.FAILED;
}
await this.storageCore.moveAssetFile(asset, AssetPathType.PREVIEW);
await this.storageCore.moveAssetFile(asset, AssetPathType.THUMBNAIL);
await this.storageCore.moveAssetFile(asset, AssetPathType.ENCODED_VIDEO);
await this.storageCore.moveAssetImage(asset, AssetPathType.PREVIEW, thumbnail.previewFormat);
await this.storageCore.moveAssetImage(asset, AssetPathType.THUMBNAIL, thumbnail.thumbnailFormat);
await this.storageCore.moveAssetVideo(asset);
return JobStatus.SUCCESS;
}
@ -179,7 +180,7 @@ export class MediaService {
private async generateThumbnail(asset: AssetEntity, type: GeneratedImageType, format: ImageFormat) {
const { thumbnail, ffmpeg } = await this.configCore.getConfig();
const size = type === AssetPathType.PREVIEW ? thumbnail.previewSize : thumbnail.thumbnailSize;
const path = StorageCore.getImagePath(asset, type);
const path = StorageCore.getImagePath(asset, type, format);
this.storageCore.ensureFolders(path);
switch (asset.type) {

View File

@ -4,6 +4,7 @@ import {
AudioCodec,
CQMode,
Colorspace,
ImageFormat,
LogLevel,
SystemConfig,
SystemConfigEntity,
@ -120,8 +121,10 @@ const updatedConfig = Object.freeze<SystemConfig>({
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
},
thumbnail: {
webpSize: 250,
jpegSize: 1440,
thumbnailFormat: ImageFormat.WEBP,
thumbnailSize: 250,
previewFormat: ImageFormat.JPEG,
previewSize: 1440,
quality: 80,
colorspace: Colorspace.P3,
},