1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00
pigallery2/src/common/config/private/PrivateConfig.ts

491 lines
14 KiB
TypeScript
Raw Normal View History

2022-04-04 19:37:31 +02:00
/* eslint-disable @typescript-eslint/no-inferrable-types */
2020-01-28 18:36:52 +01:00
import 'reflect-metadata';
2022-04-04 19:37:31 +02:00
import {
JobScheduleDTO,
JobTrigger,
JobTriggerType,
} from '../../entities/job/JobScheduleDTO';
import { ClientConfig } from '../public/ClientConfig';
import { SubConfigClass } from 'typeconfig/src/decorators/class/SubConfigClass';
import { ConfigProperty } from 'typeconfig/src/decorators/property/ConfigPropoerty';
import { DefaultsJobs } from '../../entities/job/JobDTO';
import {
SearchQueryDTO,
SearchQueryTypes,
TextSearch,
} from '../../entities/SearchQueryDTO';
import { SortingMethods } from '../../entities/SortingMethods';
import { UserRoles } from '../../entities/UserDTO';
2020-01-28 18:36:52 +01:00
export enum DatabaseType {
2022-04-04 19:37:31 +02:00
memory = 1,
mysql = 2,
sqlite = 3,
}
2020-01-28 18:36:52 +01:00
export enum LogLevel {
2022-04-04 19:37:31 +02:00
error = 1,
warn = 2,
info = 3,
verbose = 4,
debug = 5,
silly = 6,
}
2020-01-28 18:36:52 +01:00
export enum SQLLogLevel {
2022-04-04 19:37:31 +02:00
none = 1,
error = 2,
all = 3,
}
2020-01-28 18:36:52 +01:00
export enum ReIndexingSensitivity {
2022-04-04 19:37:31 +02:00
low = 1,
medium = 2,
high = 3,
}
2020-01-28 18:36:52 +01:00
export enum FFmpegPresets {
2022-04-04 19:37:31 +02:00
ultrafast = 1,
superfast = 2,
veryfast = 3,
faster = 4,
fast = 5,
medium = 6,
slow = 7,
slower = 8,
veryslow = 9,
placebo = 10,
}
export type videoCodecType = 'libvpx-vp9' | 'libx264' | 'libvpx' | 'libx265';
2022-04-04 19:37:31 +02:00
export type videoResolutionType =
| 240
| 360
| 480
| 720
| 1080
| 1440
| 2160
| 4320;
export type videoFormatType = 'mp4' | 'webm';
@SubConfigClass()
export class MySQLConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ envAlias: 'MYSQL_HOST' })
host: string = 'localhost';
2022-04-04 19:37:31 +02:00
@ConfigProperty({ envAlias: 'MYSQL_PORT', min: 0, max: 65535 })
port: number = 3306;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ envAlias: 'MYSQL_DATABASE' })
database: string = 'pigallery2';
2022-04-04 19:37:31 +02:00
@ConfigProperty({ envAlias: 'MYSQL_USERNAME' })
username: string = '';
2022-04-04 19:37:31 +02:00
@ConfigProperty({ envAlias: 'MYSQL_PASSWORD', type: 'password' })
password: string = '';
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class SQLiteConfig {
@ConfigProperty()
DBFileName: string = 'sqlite.db';
}
2020-12-28 22:08:57 +01:00
@SubConfigClass()
export class UserConfig {
@ConfigProperty()
name: string;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: UserRoles })
role: UserRoles;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ description: 'Unencrypted, temporary password' })
password: string;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ description: 'Encrypted password' })
encryptedPassword: string | undefined;
constructor(name: string, password: string, role: UserRoles) {
this.name = name;
this.role = role;
this.password = password;
}
}
2020-12-28 22:08:57 +01:00
@SubConfigClass()
export class ServerDataBaseConfig {
@ConfigProperty<DatabaseType, IPrivateConfig>({
type: DatabaseType,
onNewValue: (value, config) => {
2022-04-04 19:37:31 +02:00
if (config && value === DatabaseType.memory) {
config.Client.Search.enabled = false;
config.Client.Sharing.enabled = false;
2020-01-28 18:36:52 +01:00
}
2022-04-04 19:37:31 +02:00
},
})
type: DatabaseType = DatabaseType.sqlite;
2020-01-28 18:36:52 +01:00
@ConfigProperty()
dbFolder: string = 'db';
2020-01-28 18:36:52 +01:00
@ConfigProperty()
sqlite?: SQLiteConfig = new SQLiteConfig();
2020-12-28 22:08:57 +01:00
@ConfigProperty()
mysql?: MySQLConfig = new MySQLConfig();
2022-01-14 11:12:53 +01:00
@ConfigProperty({
arrayType: UserConfig,
2022-04-04 19:37:31 +02:00
description:
'Creates these users in the DB if they do not exist. If a user with this name exist, it wont be overwritten, even if the role is different.',
2022-01-14 11:12:53 +01:00
})
enforcedUsers: UserConfig[] = [];
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerThumbnailConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ description: 'if true, photos will have better quality.' })
qualityPriority: boolean = true;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'ratio' })
personFaceMargin: number = 0.6; // in ration [0-1]
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerSharingConfig {
@ConfigProperty()
updateTimeout: number = 1000 * 60 * 5;
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerIndexingConfig {
@ConfigProperty()
cachedFolderTimeout: number = 1000 * 60 * 60; // Do not rescans the folder if seems ok
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: ReIndexingSensitivity })
reIndexingSensitivity: ReIndexingSensitivity = ReIndexingSensitivity.low;
@ConfigProperty({
arrayType: 'string',
2022-04-04 19:37:31 +02:00
description:
"If an entry starts with '/' it is treated as an absolute path." +
" If it doesn't start with '/' but contains a '/', the path is relative to the image directory." +
" If it doesn't contain a '/', any folder with this name will be excluded.",
})
excludeFolderList: string[] = ['.Trash-1000', '.dtrash', '$RECYCLE.BIN'];
2022-04-04 19:37:31 +02:00
@ConfigProperty({
arrayType: 'string',
description:
'Any folder that contains a file with this name will be excluded from indexing.',
})
excludeFileList: string[] = [];
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerThreadingConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ description: 'App can run on multiple thread' })
enabled: boolean = true;
2022-04-04 19:37:31 +02:00
@ConfigProperty({
description:
"Number of threads that are used to generate thumbnails. If 0, number of 'CPU cores -1' threads will be used.",
})
thumbnailThreads: number = 0; // if zero-> CPU count -1
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerDuplicatesConfig {
@ConfigProperty()
listingLimit: number = 1000; // maximum number of duplicates to list
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerLogConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: LogLevel })
level: LogLevel = LogLevel.info;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: SQLLogLevel })
sqlLevel: SQLLogLevel = SQLLogLevel.error;
@ConfigProperty()
logServerTiming: boolean = false;
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class NeverJobTrigger implements JobTrigger {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: JobTriggerType })
readonly type = JobTriggerType.never;
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ScheduledJobTrigger implements JobTrigger {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: JobTriggerType })
readonly type = JobTriggerType.scheduled;
2020-01-28 18:36:52 +01:00
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt' })
time: number; // data time
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class PeriodicJobTrigger implements JobTrigger {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: JobTriggerType })
readonly type = JobTriggerType.periodic;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt', max: 7 })
periodicity: number | undefined; // 0-6: week days 7 every day
@ConfigProperty({ type: 'unsignedInt', max: 23 * 60 + 59 })
atTime: number | undefined; // day time
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class AfterJobTrigger implements JobTrigger {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: JobTriggerType })
readonly type = JobTriggerType.after;
@ConfigProperty()
2022-04-04 19:37:31 +02:00
afterScheduleName: string | undefined; // runs after schedule
2020-01-28 18:36:52 +01:00
constructor(afterScheduleName?: string) {
this.afterScheduleName = afterScheduleName;
2020-01-28 18:36:52 +01:00
}
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class JobScheduleConfig implements JobScheduleDTO {
@ConfigProperty()
name: string;
@ConfigProperty()
jobName: string;
@ConfigProperty()
config: any = {};
@ConfigProperty()
allowParallelRun: boolean;
@ConfigProperty({
type: NeverJobTrigger,
typeBuilder: (v: JobTrigger) => {
const type = typeof v.type === 'number' ? v.type : JobTriggerType[v.type];
switch (type) {
case JobTriggerType.after:
return AfterJobTrigger;
case JobTriggerType.never:
return NeverJobTrigger;
case JobTriggerType.scheduled:
return ScheduledJobTrigger;
case JobTriggerType.periodic:
return PeriodicJobTrigger;
2020-01-28 18:36:52 +01:00
}
return null;
2022-04-04 19:37:31 +02:00
},
})
2022-04-04 19:37:31 +02:00
trigger:
| AfterJobTrigger
| NeverJobTrigger
| PeriodicJobTrigger
| ScheduledJobTrigger;
constructor(
name: string,
jobName: string,
allowParallelRun: boolean,
trigger:
| AfterJobTrigger
| NeverJobTrigger
| PeriodicJobTrigger
| ScheduledJobTrigger,
config: any
) {
this.name = name;
this.jobName = jobName;
this.config = config;
this.allowParallelRun = allowParallelRun;
this.trigger = trigger;
2020-01-28 18:36:52 +01:00
}
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerJobConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'integer', description: 'Job history size' })
maxSavedProgress: number = 10;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ arrayType: JobScheduleConfig })
scheduled: JobScheduleConfig[] = [
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs.Indexing],
DefaultsJobs[DefaultsJobs.Indexing],
false,
2022-04-04 19:37:31 +02:00
new NeverJobTrigger(),
{ indexChangesOnly: true }
),
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs['Preview Filling']],
DefaultsJobs[DefaultsJobs['Preview Filling']],
false,
2022-04-04 19:37:31 +02:00
new NeverJobTrigger(),
{}
),
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs['Thumbnail Generation']],
DefaultsJobs[DefaultsJobs['Thumbnail Generation']],
false,
2022-04-04 19:37:31 +02:00
new AfterJobTrigger(DefaultsJobs[DefaultsJobs['Preview Filling']]),
{ sizes: [240], indexedOnly: true }
),
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs['Photo Converting']],
DefaultsJobs[DefaultsJobs['Photo Converting']],
false,
2022-04-04 19:37:31 +02:00
new AfterJobTrigger(DefaultsJobs[DefaultsJobs['Thumbnail Generation']]),
{ indexedOnly: true }
),
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs['Video Converting']],
DefaultsJobs[DefaultsJobs['Video Converting']],
false,
2022-04-04 19:37:31 +02:00
new AfterJobTrigger(DefaultsJobs[DefaultsJobs['Photo Converting']]),
{ indexedOnly: true }
),
2022-04-04 19:37:31 +02:00
new JobScheduleConfig(
DefaultsJobs[DefaultsJobs['Temp Folder Cleaning']],
DefaultsJobs[DefaultsJobs['Temp Folder Cleaning']],
false,
2022-04-04 19:37:31 +02:00
new AfterJobTrigger(DefaultsJobs[DefaultsJobs['Video Converting']]),
{ indexedOnly: true }
),
];
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class VideoTranscodingConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt' })
bitRate: number = 5 * 1024 * 1024;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt' })
resolution: videoResolutionType = 720;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'positiveFloat' })
fps: number = 25;
@ConfigProperty()
codec: videoCodecType = 'libx264';
@ConfigProperty()
format: videoFormatType = 'mp4';
@ConfigProperty({
type: 'unsignedInt',
2022-04-04 19:37:31 +02:00
description:
'Constant Rate Factor. The range of the CRF scale is 051, where 0 is lossless, 23 is the default, and 51 is worst quality possible.',
max: 51,
})
crf: number = 23;
@ConfigProperty({
type: FFmpegPresets,
2022-04-04 19:37:31 +02:00
description:
'A preset is a collection of options that will provide a certain encoding speed to compression ratio',
})
preset: FFmpegPresets = FFmpegPresets.medium;
2022-04-04 19:37:31 +02:00
@ConfigProperty({
arrayType: 'string',
description: 'It will be sent to ffmpeg as it is, as custom options.',
})
customOptions: string[] = [];
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerVideoConfig {
@ConfigProperty()
transcoding: VideoTranscodingConfig = new VideoTranscodingConfig();
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class PhotoConvertingConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({
description: 'Converts photos on the fly, when they are requested.',
})
onTheFly: boolean = true;
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt' })
resolution: videoResolutionType = 1080;
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerPhotoConfig {
@ConfigProperty()
Converting: PhotoConvertingConfig = new PhotoConvertingConfig();
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerPreviewConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'object' })
SearchQuery: SearchQueryDTO = {
type: SearchQueryTypes.any_text,
text: '',
} as TextSearch;
@ConfigProperty({ arrayType: SortingMethods })
Sorting: SortingMethods[] = [
SortingMethods.descRating,
2022-04-04 19:37:31 +02:00
SortingMethods.descDate,
];
}
@SubConfigClass()
export class ServerMediaConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({
description:
'Images are loaded from this folder (read permission required)',
})
folder: string = 'demo/images';
2022-04-04 19:37:31 +02:00
@ConfigProperty({
description:
'Thumbnails, converted photos, videos will be stored here (write permission required)',
})
tempFolder: string = 'demo/tmp';
@ConfigProperty()
Video: ServerVideoConfig = new ServerVideoConfig();
@ConfigProperty()
Photo: ServerPhotoConfig = new ServerPhotoConfig();
@ConfigProperty()
Thumbnail: ServerThumbnailConfig = new ServerThumbnailConfig();
}
2020-01-28 18:36:52 +01:00
@SubConfigClass()
export class ServerEnvironmentConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ volatile: true })
upTime: string | undefined;
@ConfigProperty({ volatile: true })
appVersion: string | undefined;
@ConfigProperty({ volatile: true })
buildTime: string | undefined;
@ConfigProperty({ volatile: true })
buildCommitHash: string | undefined;
@ConfigProperty({ volatile: true })
isDocker: boolean | undefined;
}
2020-02-07 23:32:41 +01:00
@SubConfigClass()
export class ServerConfig {
2022-04-04 19:37:31 +02:00
@ConfigProperty({ volatile: true })
Environment: ServerEnvironmentConfig = new ServerEnvironmentConfig();
2022-04-04 19:37:31 +02:00
@ConfigProperty({ arrayType: 'string' })
sessionSecret: string[] = [];
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt', envAlias: 'PORT', min: 0, max: 65535 })
port: number = 80;
@ConfigProperty()
host: string = '0.0.0.0';
@ConfigProperty()
Media: ServerMediaConfig = new ServerMediaConfig();
@ConfigProperty()
Preview: ServerPreviewConfig = new ServerPreviewConfig();
@ConfigProperty()
Threading: ServerThreadingConfig = new ServerThreadingConfig();
@ConfigProperty()
Database: ServerDataBaseConfig = new ServerDataBaseConfig();
@ConfigProperty()
Sharing: ServerSharingConfig = new ServerSharingConfig();
2022-04-04 19:37:31 +02:00
@ConfigProperty({ type: 'unsignedInt', description: 'unit: ms' })
sessionTimeout: number = 1000 * 60 * 60 * 24 * 7; // in ms
@ConfigProperty()
Indexing: ServerIndexingConfig = new ServerIndexingConfig();
2022-04-04 19:37:31 +02:00
@ConfigProperty({
type: 'unsignedInt',
description:
'only this many bites will be loaded when scanning photo for metadata',
})
photoMetadataSize: number = 512 * 1024; // only this many bites will be loaded when scanning photo for metadata
@ConfigProperty()
Duplicates: ServerDuplicatesConfig = new ServerDuplicatesConfig();
@ConfigProperty()
Log: ServerLogConfig = new ServerLogConfig();
@ConfigProperty()
Jobs: ServerJobConfig = new ServerJobConfig();
2020-01-28 18:36:52 +01:00
}
export interface IPrivateConfig {
Server: ServerConfig;
Client: ClientConfig;
2020-01-28 18:36:52 +01:00
}