feat(web/server): webp thumbnail size configurable (#3598)

* feat(server/web): webp thumbnail size configurable

* update api

* add ui and fix test

* lint

* setting for jpeg size

* feat: coerce to number

* api

* jpeg resolution

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
Alex
2023-08-08 09:39:51 -05:00
committed by GitHub
parent 1812e8811b
commit ddd4ec2d9e
26 changed files with 429 additions and 18 deletions

View File

@@ -1,3 +1 @@
export const JPEG_THUMBNAIL_SIZE = 1440;
export const WEBP_THUMBNAIL_SIZE = 250;
export const FACE_THUMBNAIL_SIZE = 250;

View File

@@ -7,7 +7,6 @@ import { IBaseJob, IEntityJob, IJobRepository, JobName, JOBS_ASSET_PAGINATION_SI
import { IStorageRepository, StorageCore, StorageFolder } from '../storage';
import { ISystemConfigRepository, SystemConfigFFmpegDto } from '../system-config';
import { SystemConfigCore } from '../system-config/system-config.core';
import { JPEG_THUMBNAIL_SIZE, WEBP_THUMBNAIL_SIZE } from './media.constant';
import { AudioStreamInfo, IMediaRepository, VideoCodecHWConfig, VideoStreamInfo } from './media.repository';
import { H264Config, HEVCConfig, NVENCConfig, QSVConfig, ThumbnailConfig, VAAPIConfig, VP9Config } from './media.util';
@@ -63,11 +62,12 @@ export class MediaService {
const resizePath = this.storageCore.getFolderLocation(StorageFolder.THUMBNAILS, asset.ownerId);
this.storageRepository.mkdirSync(resizePath);
const jpegThumbnailPath = join(resizePath, `${asset.id}.jpeg`);
const { thumbnail } = await this.configCore.getConfig();
switch (asset.type) {
case AssetType.IMAGE:
await this.mediaRepository.resize(asset.originalPath, jpegThumbnailPath, {
size: JPEG_THUMBNAIL_SIZE,
size: thumbnail.jpegSize,
format: 'jpeg',
});
this.logger.log(`Successfully generated image thumbnail ${asset.id}`);
@@ -80,7 +80,7 @@ export class MediaService {
return false;
}
const { ffmpeg } = await this.configCore.getConfig();
const config = { ...ffmpeg, targetResolution: JPEG_THUMBNAIL_SIZE.toString(), twoPass: false };
const config = { ...ffmpeg, targetResolution: thumbnail.jpegSize.toString(), twoPass: false };
const options = new ThumbnailConfig(config).getOptions(mainVideoStream);
await this.mediaRepository.transcode(asset.originalPath, jpegThumbnailPath, options);
this.logger.log(`Successfully generated video thumbnail ${asset.id}`);
@@ -100,7 +100,8 @@ export class MediaService {
const webpPath = asset.resizePath.replace('jpeg', 'webp').replace('jpg', 'webp');
await this.mediaRepository.resize(asset.resizePath, webpPath, { size: WEBP_THUMBNAIL_SIZE, format: 'webp' });
const { thumbnail } = await this.configCore.getConfig();
await this.mediaRepository.resize(asset.resizePath, webpPath, { size: thumbnail.webpSize, format: 'webp' });
await this.assetRepository.save({ id: asset.id, webpPath });
return true;

View File

@@ -2,4 +2,5 @@ export * from './system-config-ffmpeg.dto';
export * from './system-config-oauth.dto';
export * from './system-config-password-login.dto';
export * from './system-config-storage-template.dto';
export * from './system-config-thumbnail.dto';
export * from './system-config.dto';

View File

@@ -0,0 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsInt } from 'class-validator';
export class SystemConfigThumbnailDto {
@IsInt()
@Type(() => Number)
@ApiProperty({ type: 'integer' })
webpSize!: number;
@IsInt()
@Type(() => Number)
@ApiProperty({ type: 'integer' })
jpegSize!: number;
}

View File

@@ -1,3 +1,4 @@
import { SystemConfigThumbnailDto } from '@app/domain/system-config';
import { SystemConfig } from '@app/infra/entities';
import { Type } from 'class-transformer';
import { IsObject, ValidateNested } from 'class-validator';
@@ -32,6 +33,11 @@ export class SystemConfigDto {
@ValidateNested()
@IsObject()
job!: SystemConfigJobDto;
@Type(() => SystemConfigThumbnailDto)
@ValidateNested()
@IsObject()
thumbnail!: SystemConfigThumbnailDto;
}
export function mapConfig(config: SystemConfig): SystemConfigDto {

View File

@@ -64,6 +64,11 @@ export const defaults = Object.freeze<SystemConfig>({
storageTemplate: {
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
},
thumbnail: {
webpSize: 250,
jpegSize: 1440,
},
});
const singleton = new Subject<SystemConfig>();

View File

@@ -65,6 +65,10 @@ const updatedConfig = Object.freeze<SystemConfig>({
storageTemplate: {
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
},
thumbnail: {
webpSize: 250,
jpegSize: 1440,
},
});
describe(SystemConfigService.name, () => {