1
0
forked from Cutlery/immich

rename to image settings

This commit is contained in:
mertalev 2024-03-24 02:28:40 -04:00
parent a9b90787b2
commit d451abd96c
No known key found for this signature in database
GPG Key ID: 9181CD92C0A1C5E3
9 changed files with 56 additions and 28 deletions

View File

@ -113,7 +113,7 @@ export const defaults = Object.freeze<SystemConfig>({
hashVerificationEnabled: true, hashVerificationEnabled: true,
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
}, },
thumbnail: { image: {
thumbnailFormat: ImageFormat.WEBP, thumbnailFormat: ImageFormat.WEBP,
thumbnailSize: 250, thumbnailSize: 250,
previewFormat: ImageFormat.JPEG, previewFormat: ImageFormat.JPEG,

View File

@ -492,7 +492,7 @@ export class SystemConfigDto implements SystemConfig {
@Type(() => SystemConfigThumbnailDto) @Type(() => SystemConfigThumbnailDto)
@ValidateNested() @ValidateNested()
@IsObject() @IsObject()
thumbnail!: SystemConfigThumbnailDto; image!: SystemConfigThumbnailDto;
@Type(() => SystemConfigTrashDto) @Type(() => SystemConfigTrashDto)
@ValidateNested() @ValidateNested()

View File

@ -254,7 +254,7 @@ export interface SystemConfig {
hashVerificationEnabled: boolean; hashVerificationEnabled: boolean;
template: string; template: string;
}; };
thumbnail: { image: {
thumbnailFormat: ImageFormat; thumbnailFormat: ImageFormat;
thumbnailSize: number; thumbnailSize: number;
previewFormat: ImageFormat; previewFormat: ImageFormat;

View File

@ -6,11 +6,11 @@ export class RenameWebpJpegPaths1711257900274 implements MigrationInterface {
await queryRunner.renameColumn('assets', 'resizePath', 'previewPath'); await queryRunner.renameColumn('assets', 'resizePath', 'previewPath');
await queryRunner.query(` await queryRunner.query(`
UPDATE system_config UPDATE system_config
SET key = 'thumbnail.previewSize' SET key = 'image.previewSize'
WHERE key = 'thumbnail.jpegSize'`); WHERE key = 'thumbnail.jpegSize'`);
await queryRunner.query( await queryRunner.query(
`UPDATE system_config `UPDATE system_config
SET key = 'thumbnail.thumbnailSize' SET key = 'image.thumbnailSize'
WHERE key = 'thumbnail.webpSize'`, WHERE key = 'thumbnail.webpSize'`,
); );
} }
@ -21,11 +21,11 @@ export class RenameWebpJpegPaths1711257900274 implements MigrationInterface {
await queryRunner.query(` await queryRunner.query(`
UPDATE system_config UPDATE system_config
SET key = 'thumbnail.jpegSize' SET key = 'thumbnail.jpegSize'
WHERE key = 'thumbnail.previewSize'`); WHERE key = 'image.previewSize'`);
await queryRunner.query( await queryRunner.query(
`UPDATE system_config `UPDATE system_config
SET key = 'thumbnail.webpSize' SET key = 'thumbnail.webpSize'
WHERE key = 'thumbnail.thumbnailSize'`, WHERE key = 'image.thumbnailSize'`,
); );
} }
} }

View File

@ -153,14 +153,14 @@ export class MediaService {
} }
async handleAssetMigration({ id }: IEntityJob): Promise<JobStatus> { async handleAssetMigration({ id }: IEntityJob): Promise<JobStatus> {
const { thumbnail } = await this.configCore.getConfig(); const { image } = await this.configCore.getConfig();
const [asset] = await this.assetRepository.getByIds([id]); const [asset] = await this.assetRepository.getByIds([id]);
if (!asset) { if (!asset) {
return JobStatus.FAILED; return JobStatus.FAILED;
} }
await this.storageCore.moveAssetImage(asset, AssetPathType.PREVIEW, thumbnail.previewFormat); await this.storageCore.moveAssetImage(asset, AssetPathType.PREVIEW, image.previewFormat);
await this.storageCore.moveAssetImage(asset, AssetPathType.THUMBNAIL, thumbnail.thumbnailFormat); await this.storageCore.moveAssetImage(asset, AssetPathType.THUMBNAIL, image.thumbnailFormat);
await this.storageCore.moveAssetVideo(asset); await this.storageCore.moveAssetVideo(asset);
return JobStatus.SUCCESS; return JobStatus.SUCCESS;
@ -178,16 +178,16 @@ export class MediaService {
} }
private async generateThumbnail(asset: AssetEntity, type: GeneratedImageType, format: ImageFormat) { private async generateThumbnail(asset: AssetEntity, type: GeneratedImageType, format: ImageFormat) {
const { thumbnail, ffmpeg } = await this.configCore.getConfig(); const { image, ffmpeg } = await this.configCore.getConfig();
const size = type === AssetPathType.PREVIEW ? thumbnail.previewSize : thumbnail.thumbnailSize; const size = type === AssetPathType.PREVIEW ? image.previewSize : image.thumbnailSize;
const path = StorageCore.getImagePath(asset, type, format); const path = StorageCore.getImagePath(asset, type, format);
this.storageCore.ensureFolders(path); this.storageCore.ensureFolders(path);
switch (asset.type) { switch (asset.type) {
case AssetType.IMAGE: { case AssetType.IMAGE: {
const colorspace = this.isSRGB(asset) ? Colorspace.SRGB : thumbnail.colorspace; const colorspace = this.isSRGB(asset) ? Colorspace.SRGB : image.colorspace;
const thumbnailOptions = { format, size, colorspace, quality: thumbnail.quality }; const imageOptions = { format, size, colorspace, quality: image.quality };
await this.mediaRepository.resize(asset.originalPath, path, thumbnailOptions); await this.mediaRepository.resize(asset.originalPath, path, imageOptions);
break; break;
} }

View File

@ -471,7 +471,7 @@ export class PersonService {
} }
async handleGeneratePersonThumbnail(data: IEntityJob): Promise<JobStatus> { async handleGeneratePersonThumbnail(data: IEntityJob): Promise<JobStatus> {
const { machineLearning, thumbnail } = await this.configCore.getConfig(); const { machineLearning, image } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) {
return JobStatus.SKIPPED; return JobStatus.SKIPPED;
} }
@ -532,8 +532,8 @@ export class PersonService {
const thumbnailOptions = { const thumbnailOptions = {
format: ImageFormat.JPEG, format: ImageFormat.JPEG,
size: FACE_THUMBNAIL_SIZE, size: FACE_THUMBNAIL_SIZE,
colorspace: thumbnail.colorspace, colorspace: image.colorspace,
quality: thumbnail.quality, quality: image.quality,
} as const; } as const;
await this.mediaRepository.resize(croppedOutput, thumbnailPath, thumbnailOptions); await this.mediaRepository.resize(croppedOutput, thumbnailPath, thumbnailOptions);

View File

@ -120,7 +120,7 @@ const updatedConfig = Object.freeze<SystemConfig>({
hashVerificationEnabled: true, hashVerificationEnabled: true,
template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}',
}, },
thumbnail: { image: {
thumbnailFormat: ImageFormat.WEBP, thumbnailFormat: ImageFormat.WEBP,
thumbnailSize: 250, thumbnailSize: 250,
previewFormat: ImageFormat.JPEG, previewFormat: ImageFormat.JPEG,

View File

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { Colorspace, type SystemConfigDto } from '@immich/sdk'; import { Colorspace, ImageFormat, type SystemConfigDto } from '@immich/sdk';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
@ -24,6 +24,20 @@
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" on:submit|preventDefault> <form autocomplete="off" on:submit|preventDefault>
<div class="ml-4 mt-4 flex flex-col gap-4"> <div class="ml-4 mt-4 flex flex-col gap-4">
<SettingSelect
label="THUMBNAIL FORMAT"
desc="Format used for generated thumbnail images. WebP produces smaller files at the same quality."
number
bind:value={config.thumbnail.thumbnailFormat}
options={[
{ value: ImageFormat.Jpeg, text: 'JPEG' },
{ value: ImageFormat.Webp, text: 'WEBP' },
]}
name="resolution"
isEdited={config.thumbnail.thumbnailFormat !== savedConfig.thumbnail.thumbnailFormat}
{disabled}
/>
<SettingSelect <SettingSelect
label="THUMBNAIL RESOLUTION" label="THUMBNAIL RESOLUTION"
desc="Used when viewing groups of photos (main timeline, album view, etc.). Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness." desc="Used when viewing groups of photos (main timeline, album view, etc.). Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."
@ -41,6 +55,20 @@
{disabled} {disabled}
/> />
<SettingSelect
label="PREVIEW FORMAT"
desc="Format used for generated preview images. WebP produces smaller files at the same quality."
number
bind:value={config.thumbnail.thumbnailFormat}
options={[
{ value: ImageFormat.Jpeg, text: 'JPEG' },
{ value: ImageFormat.Webp, text: 'WEBP' },
]}
name="resolution"
isEdited={config.thumbnail.thumbnailFormat !== savedConfig.thumbnail.thumbnailFormat}
{disabled}
/>
<SettingSelect <SettingSelect
label="PREVIEW RESOLUTION" label="PREVIEW RESOLUTION"
desc="Used when viewing a single photo and for machine learning. Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness." desc="Used when viewing a single photo and for machine learning. Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."

View File

@ -13,7 +13,7 @@
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte'; import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte'; import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte'; import ThemeSettings from '$lib/components/admin-page/settings/theme/theme-settings.svelte';
import ThumbnailSettings from '$lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte'; import ImageSettings from '$lib/components/admin-page/settings/image/image-settings.svelte';
import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte'; import TrashSettings from '$lib/components/admin-page/settings/trash-settings/trash-settings.svelte';
import UserSettings from '$lib/components/admin-page/settings/user-settings/user-settings.svelte'; import UserSettings from '$lib/components/admin-page/settings/user-settings/user-settings.svelte';
import LinkButton from '$lib/components/elements/buttons/link-button.svelte'; import LinkButton from '$lib/components/elements/buttons/link-button.svelte';
@ -43,7 +43,7 @@
| typeof ServerSettings | typeof ServerSettings
| typeof StorageTemplateSettings | typeof StorageTemplateSettings
| typeof ThemeSettings | typeof ThemeSettings
| typeof ThumbnailSettings | typeof ImageSettings
| typeof TrashSettings | typeof TrashSettings
| typeof NewVersionCheckSettings | typeof NewVersionCheckSettings
| typeof FFmpegSettings | typeof FFmpegSettings
@ -64,6 +64,12 @@
subtitle: string; subtitle: string;
key: string; key: string;
}> = [ }> = [
{
item: ImageSettings,
title: 'Image Settings',
subtitle: 'Manage the format, quality and resolution of generated images',
key: 'image',
},
{ {
item: JobSettings, item: JobSettings,
title: 'Job Settings', title: 'Job Settings',
@ -124,12 +130,6 @@
subtitle: 'Manage customization of the Immich web interface', subtitle: 'Manage customization of the Immich web interface',
key: 'theme', key: 'theme',
}, },
{
item: ThumbnailSettings,
title: 'Thumbnail Settings',
subtitle: 'Manage the resolution of thumbnail sizes',
key: 'thumbnail',
},
{ {
item: TrashSettings, item: TrashSettings,
title: 'Trash Settings', title: 'Trash Settings',