From 5160e19a35c2bd3d8e270ae8f74e653b2017930e Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Sun, 15 Dec 2019 14:40:31 +0100 Subject: [PATCH] improve settings --- src/backend/middlewares/admin/SettingsMWs.ts | 2 +- src/backend/model/DiskManger.ts | 4 +- .../model/diagnostics/ConfigDiagnostics.ts | 23 ++-- .../model/fileprocessing/PhotoProcessing.ts | 8 +- src/backend/model/tasks/TaskRepository.ts | 2 + src/backend/model/tasks/tasks/FileTask.ts | 11 +- src/backend/model/tasks/tasks/IndexingTask.ts | 41 +----- .../model/tasks/tasks/PhotoConvertingTask.ts | 6 +- src/backend/model/threading/ThreadPool.ts | 2 +- .../model/threading/ThumbnailWorker.ts | 14 +- src/backend/model/threading/Worker.ts | 2 +- src/common/config/private/IPrivateConfig.ts | 6 +- .../private/PrivateConfigDefaultsClass.ts | 4 +- src/common/entities/task/TaskDTO.ts | 2 +- src/frontend/app/app.module.ts | 2 + .../app/ui/admin/admin.component.html | 41 +++--- .../settings/_abstract/ISettingsComponent.ts | 3 +- .../_abstract/abstract.settings.component.ts | 8 ++ .../faces/faces.settings.component.ts | 12 +- .../indexing/indexing.settings.component.html | 58 ++++---- .../indexing/indexing.settings.component.ts | 6 +- .../ui/settings/map/map.settings.component.ts | 2 +- .../metafiles/metafile.settings.component.ts | 2 +- .../other/other.settings.component.html | 4 +- .../photo/photo.settings.component.css | 4 + .../photo/photo.settings.component.html | 129 ++++++++++++++++++ .../photo/photo.settings.component.ts | 105 ++++++++++++++ .../settings/photo/photo.settings.service.ts | 21 +++ .../random-photo.settings.component.html | 6 +- .../tasks/tasks.settings.component.ts | 2 +- .../thumbnail.settings.component.html | 28 ---- .../thumbnail/thumbnail.settings.component.ts | 19 +-- .../usermanager.settings.component.ts | 3 +- .../video/video.settings.component.html | 46 ++++--- .../video/video.settings.component.ts | 7 +- .../settings/video/video.settings.service.ts | 5 +- 36 files changed, 428 insertions(+), 212 deletions(-) create mode 100644 src/frontend/app/ui/settings/photo/photo.settings.component.css create mode 100644 src/frontend/app/ui/settings/photo/photo.settings.component.html create mode 100644 src/frontend/app/ui/settings/photo/photo.settings.component.ts create mode 100644 src/frontend/app/ui/settings/photo/photo.settings.service.ts diff --git a/src/backend/middlewares/admin/SettingsMWs.ts b/src/backend/middlewares/admin/SettingsMWs.ts index 7bd9daf..7f6cad6 100644 --- a/src/backend/middlewares/admin/SettingsMWs.ts +++ b/src/backend/middlewares/admin/SettingsMWs.ts @@ -359,7 +359,7 @@ export class SettingsMWs { original.Client.Other.enableOnScrollThumbnailPrioritising = settings.Client.enableOnScrollThumbnailPrioritising; original.Client.Other.defaultPhotoSortingMethod = settings.Client.defaultPhotoSortingMethod; original.Client.Other.NavBar.showItemCount = settings.Client.NavBar.showItemCount; - original.Server.Threading.enable = settings.Server.enable; + original.Server.Threading.enabled = settings.Server.enabled; original.Server.Threading.thumbnailThreads = settings.Server.thumbnailThreads; original.save(); await ConfigDiagnostics.runDiagnostics(); diff --git a/src/backend/model/DiskManger.ts b/src/backend/model/DiskManger.ts index dbc0fc4..749b71e 100644 --- a/src/backend/model/DiskManger.ts +++ b/src/backend/model/DiskManger.ts @@ -11,7 +11,7 @@ export class DiskManager { static threadPool: DiskManagerTH = null; public static init() { - if (Config.Server.Threading.enable === true) { + if (Config.Server.Threading.enabled === true) { DiskManager.threadPool = new DiskManagerTH(1); } } @@ -23,7 +23,7 @@ export class DiskManager { let directory: DirectoryDTO; - if (Config.Server.Threading.enable === true) { + if (Config.Server.Threading.enabled === true) { directory = await DiskManager.threadPool.execute(relativeDirectoryName, settings); } else { directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName, settings); diff --git a/src/backend/model/diagnostics/ConfigDiagnostics.ts b/src/backend/model/diagnostics/ConfigDiagnostics.ts index 5986308..dcdbf8b 100644 --- a/src/backend/model/diagnostics/ConfigDiagnostics.ts +++ b/src/backend/model/diagnostics/ConfigDiagnostics.ts @@ -81,13 +81,13 @@ export class ConfigDiagnostics { } } - static async testThumbnailLib(processingLibrary: ServerConfig.ThumbnailProcessingLib) { + static async testThumbnailLib(processingLibrary: ServerConfig.PhotoProcessingLib) { switch (processingLibrary) { - case ServerConfig.ThumbnailProcessingLib.sharp: + case ServerConfig.PhotoProcessingLib.sharp: const sharp = require('sharp'); sharp(); break; - case ServerConfig.ThumbnailProcessingLib.gm: + case ServerConfig.PhotoProcessingLib.gm: const gm = require('gm'); await new Promise((resolve, reject) => { gm(ProjectPath.FrontendFolder + '/assets/icon.png').size((err: Error) => { @@ -120,8 +120,10 @@ export class ConfigDiagnostics { } - static async testServerThumbnailConfig(thumbnailConfig: ServerConfig.ThumbnailConfig) { - await ConfigDiagnostics.testThumbnailLib(thumbnailConfig.processingLibrary); + public static async testServerThumbnailConfig(server: ServerConfig.ThumbnailConfig) { + if (server.personFaceMargin < 0 || server.personFaceMargin > 1) { + throw new Error('personFaceMargin should be between 0 and 1'); + } } static async testClientThumbnailConfig(thumbnailConfig: ClientConfig.ThumbnailConfig) { @@ -218,19 +220,19 @@ export class ConfigDiagnostics { } } - if (Config.Server.Media.Thumbnail.processingLibrary !== ServerConfig.ThumbnailProcessingLib.Jimp) { + if (Config.Server.Media.photoProcessingLibrary !== ServerConfig.PhotoProcessingLib.Jimp) { try { - await ConfigDiagnostics.testThumbnailLib(Config.Server.Media.Thumbnail.processingLibrary); + await ConfigDiagnostics.testThumbnailLib(Config.Server.Media.photoProcessingLibrary); } catch (ex) { const err: Error = ex; NotificationManager.warning('Thumbnail hardware acceleration is not possible.' + - ' \'' + ServerConfig.ThumbnailProcessingLib[Config.Server.Media.Thumbnail.processingLibrary] + '\' node module is not found.' + + ' \'' + ServerConfig.PhotoProcessingLib[Config.Server.Media.photoProcessingLibrary] + '\' node module is not found.' + ' Falling back temporally to JS based thumbnail generation', err.toString()); Logger.warn(LOG_TAG, '[Thumbnail hardware acceleration] module error: ', err.toString()); Logger.warn(LOG_TAG, 'Thumbnail hardware acceleration is not possible.' + - ' \'' + ServerConfig.ThumbnailProcessingLib[Config.Server.Media.Thumbnail.processingLibrary] + '\' node module is not found.' + + ' \'' + ServerConfig.PhotoProcessingLib[Config.Server.Media.photoProcessingLibrary] + '\' node module is not found.' + ' Falling back temporally to JS based thumbnail generation'); - Config.Server.Media.Thumbnail.processingLibrary = ServerConfig.ThumbnailProcessingLib.Jimp; + Config.Server.Media.photoProcessingLibrary = ServerConfig.PhotoProcessingLib.Jimp; } } @@ -343,4 +345,5 @@ export class ConfigDiagnostics { } } + } diff --git a/src/backend/model/fileprocessing/PhotoProcessing.ts b/src/backend/model/fileprocessing/PhotoProcessing.ts index 11ec2af..a09f789 100644 --- a/src/backend/model/fileprocessing/PhotoProcessing.ts +++ b/src/backend/model/fileprocessing/PhotoProcessing.ts @@ -22,7 +22,7 @@ export class PhotoProcessing { } - if (Config.Server.Threading.enable === true) { + if (Config.Server.Threading.enabled === true) { if (Config.Server.Threading.thumbnailThreads > 0) { Config.Client.Media.Thumbnail.concurrentThumbnailGenerations = Config.Server.Threading.thumbnailThreads; } else { @@ -32,12 +32,12 @@ export class PhotoProcessing { Config.Client.Media.Thumbnail.concurrentThumbnailGenerations = 1; } - if (Config.Server.Threading.enable === true && - Config.Server.Media.Thumbnail.processingLibrary === ServerConfig.ThumbnailProcessingLib.Jimp) { + if (Config.Server.Threading.enabled === true && + Config.Server.Media.photoProcessingLibrary === ServerConfig.PhotoProcessingLib.Jimp) { this.taskQue = new ThumbnailTH(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations); } else { this.taskQue = new TaskExecuter(Config.Client.Media.Thumbnail.concurrentThumbnailGenerations, - (input => ThumbnailWorker.render(input, Config.Server.Media.Thumbnail.processingLibrary))); + (input => ThumbnailWorker.render(input, Config.Server.Media.photoProcessingLibrary))); } this.initDone = true; diff --git a/src/backend/model/tasks/TaskRepository.ts b/src/backend/model/tasks/TaskRepository.ts index 93e9a62..eb5d12e 100644 --- a/src/backend/model/tasks/TaskRepository.ts +++ b/src/backend/model/tasks/TaskRepository.ts @@ -2,6 +2,7 @@ import {ITask} from './tasks/ITask'; import {IndexingTask} from './tasks/IndexingTask'; import {DBRestTask} from './tasks/DBResetTask'; import {VideoConvertingTask} from './tasks/VideoConvertingTask'; +import {PhotoConvertingTask} from './tasks/PhotoConvertingTask'; export class TaskRepository { @@ -28,3 +29,4 @@ export class TaskRepository { TaskRepository.Instance.register(new IndexingTask()); TaskRepository.Instance.register(new DBRestTask()); TaskRepository.Instance.register(new VideoConvertingTask()); +TaskRepository.Instance.register(new PhotoConvertingTask()); diff --git a/src/backend/model/tasks/tasks/FileTask.ts b/src/backend/model/tasks/tasks/FileTask.ts index 8796ada..d3462e3 100644 --- a/src/backend/model/tasks/tasks/FileTask.ts +++ b/src/backend/model/tasks/tasks/FileTask.ts @@ -2,17 +2,15 @@ import {TaskProgressDTO, TaskState} from '../../../../common/entities/settings/T import {ConfigTemplateEntry} from '../../../../common/entities/task/TaskDTO'; import {Task} from './Task'; import * as path from 'path'; -import * as fs from 'fs'; -import * as util from 'util'; import {DiskManager} from '../../DiskManger'; import {DiskMangerWorker} from '../../threading/DiskMangerWorker'; import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO'; +import {Logger} from '../../../Logger'; declare var global: NodeJS.Global; const LOG_TAG = '[FileTask]'; -const existsPr = util.promisify(fs.exists); export abstract class FileTask extends Task { @@ -58,7 +56,12 @@ export abstract class FileTask extends Task { this.progress.left = this.fileQueue.length; this.progress.progress++; this.progress.comment = 'processing: ' + file; - await this.processFile(file); + try { + await this.processFile(file); + } catch (e) { + console.error(e); + Logger.error(LOG_TAG, 'Error during processing file: ' + e.toString()); + } } return this.progress; } diff --git a/src/backend/model/tasks/tasks/IndexingTask.ts b/src/backend/model/tasks/tasks/IndexingTask.ts index 2ac2fb5..75dca01 100644 --- a/src/backend/model/tasks/tasks/IndexingTask.ts +++ b/src/backend/model/tasks/tasks/IndexingTask.ts @@ -1,30 +1,18 @@ import {TaskProgressDTO, TaskState} from '../../../../common/entities/settings/TaskProgressDTO'; import {ObjectManagers} from '../../ObjectManagers'; import * as path from 'path'; -import * as fs from 'fs'; -import {Logger} from '../../../Logger'; -import {RendererInput, ThumbnailSourceType, ThumbnailWorker} from '../../threading/ThumbnailWorker'; import {Config} from '../../../../common/config/private/Config'; -import {MediaDTO} from '../../../../common/entities/MediaDTO'; -import {ProjectPath} from '../../../ProjectPath'; -import {ThumbnailGeneratorMWs} from '../../../middlewares/thumbnail/ThumbnailGeneratorMWs'; import {Task} from './Task'; import {ConfigTemplateEntry, DefaultsTasks} from '../../../../common/entities/task/TaskDTO'; import {ServerConfig} from '../../../../common/config/private/IPrivateConfig'; -import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing'; declare var global: NodeJS.Global; const LOG_TAG = '[IndexingTask]'; -export class IndexingTask extends Task<{ createThumbnails: boolean }> { +export class IndexingTask extends Task { public readonly Name = DefaultsTasks[DefaultsTasks.Indexing]; directoriesToIndex: string[] = []; - public readonly ConfigTemplate: ConfigTemplateEntry[] = [{ - id: 'createThumbnails', - type: 'boolean', - name: 'With thumbnails', - defaultValue: false - }]; + public readonly ConfigTemplate: ConfigTemplateEntry[] = null; public get Supported(): boolean { return Config.Server.Database.type !== ServerConfig.DatabaseType.memory; @@ -54,31 +42,6 @@ export class IndexingTask extends Task<{ createThumbnails: boolean }> { for (let i = 0; i < scanned.directories.length; i++) { this.directoriesToIndex.push(path.join(scanned.directories[i].path, scanned.directories[i].name)); } - if (this.config.createThumbnails) { - for (let i = 0; i < scanned.media.length; i++) { - try { - const media = scanned.media[i]; - const mPath = path.join(ProjectPath.ImageFolder, media.directory.path, media.directory.name, media.name); - const thPath = path.join(ProjectPath.ThumbnailFolder, - PhotoProcessing.generateThumbnailName(mPath, Config.Client.Media.Thumbnail.thumbnailSizes[0])); - if (fs.existsSync(thPath)) { // skip existing thumbnails - continue; - } - await ThumbnailWorker.render({ - type: MediaDTO.isVideo(media) ? ThumbnailSourceType.Video : ThumbnailSourceType.Photo, - mediaPath: mPath, - size: Config.Client.Media.Thumbnail.thumbnailSizes[0], - outPath: thPath, - makeSquare: false, - qualityPriority: Config.Server.Media.Thumbnail.qualityPriority - }, Config.Server.Media.Thumbnail.processingLibrary); - } catch (e) { - console.error(e); - Logger.error(LOG_TAG, 'Error during indexing job: ' + e.toString()); - } - } - - } return this.progress; } diff --git a/src/backend/model/tasks/tasks/PhotoConvertingTask.ts b/src/backend/model/tasks/tasks/PhotoConvertingTask.ts index 1c5afe6..ad88058 100644 --- a/src/backend/model/tasks/tasks/PhotoConvertingTask.ts +++ b/src/backend/model/tasks/tasks/PhotoConvertingTask.ts @@ -14,14 +14,14 @@ const existsPr = util.promisify(fs.exists); export class PhotoConvertingTask extends FileTask { - public readonly Name = DefaultsTasks[DefaultsTasks['Video Converting']]; + public readonly Name = DefaultsTasks[DefaultsTasks['Photo Converting']]; constructor() { super({noVideo: true, noMetaFile: true}); } public get Supported(): boolean { - return Config.Server.Media.Photo.Converting.enabled === true; + return Config.Client.Media.Photo.Converting.enabled === true; } protected async processDirectory(directory: DirectoryDTO): Promise { @@ -40,7 +40,7 @@ export class PhotoConvertingTask extends FileTask { } protected async processFile(file: string): Promise { - await PhotoProcessing.generateThumbnail(file, Config.Server.Media.Photo.Converting.resolution, ThumbnailSourceType.Photo, false); + await PhotoProcessing.convertPhoto(file, Config.Server.Media.Photo.Converting.resolution); } diff --git a/src/backend/model/threading/ThreadPool.ts b/src/backend/model/threading/ThreadPool.ts index bae1b9b..9ac7774 100644 --- a/src/backend/model/threading/ThreadPool.ts +++ b/src/backend/model/threading/ThreadPool.ts @@ -103,7 +103,7 @@ export class ThumbnailTH extends ThreadPool implements ITaskExecuter{ type: WorkerTaskTypes.thumbnail, input: input, - renderer: Config.Server.Media.Thumbnail.processingLibrary + renderer: Config.Server.Media.photoProcessingLibrary }); } } diff --git a/src/backend/model/threading/ThumbnailWorker.ts b/src/backend/model/threading/ThumbnailWorker.ts index 7135d26..350aef8 100644 --- a/src/backend/model/threading/ThumbnailWorker.ts +++ b/src/backend/model/threading/ThumbnailWorker.ts @@ -9,16 +9,16 @@ export class ThumbnailWorker { private static imageRenderer: (input: RendererInput) => Promise = null; private static videoRenderer: (input: RendererInput) => Promise = null; - private static rendererType: ServerConfig.ThumbnailProcessingLib = null; + private static rendererType: ServerConfig.PhotoProcessingLib = null; - public static render(input: RendererInput, renderer: ServerConfig.ThumbnailProcessingLib): Promise { + public static render(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise { if (input.type === ThumbnailSourceType.Photo) { return this.renderFromImage(input, renderer); } return this.renderFromVideo(input); } - public static renderFromImage(input: RendererInput, renderer: ServerConfig.ThumbnailProcessingLib): Promise { + public static renderFromImage(input: RendererInput, renderer: ServerConfig.PhotoProcessingLib): Promise { if (ThumbnailWorker.rendererType !== renderer) { ThumbnailWorker.imageRenderer = ImageRendererFactory.build(renderer); ThumbnailWorker.rendererType = renderer; @@ -117,13 +117,13 @@ export class VideoRendererFactory { export class ImageRendererFactory { - public static build(renderer: ServerConfig.ThumbnailProcessingLib): (input: RendererInput) => Promise { + public static build(renderer: ServerConfig.PhotoProcessingLib): (input: RendererInput) => Promise { switch (renderer) { - case ServerConfig.ThumbnailProcessingLib.Jimp: + case ServerConfig.PhotoProcessingLib.Jimp: return ImageRendererFactory.Jimp(); - case ServerConfig.ThumbnailProcessingLib.gm: + case ServerConfig.PhotoProcessingLib.gm: return ImageRendererFactory.Gm(); - case ServerConfig.ThumbnailProcessingLib.sharp: + case ServerConfig.PhotoProcessingLib.sharp: return ImageRendererFactory.Sharp(); } throw new Error('unknown renderer'); diff --git a/src/backend/model/threading/Worker.ts b/src/backend/model/threading/Worker.ts index 6c01fa7..ba60a85 100644 --- a/src/backend/model/threading/Worker.ts +++ b/src/backend/model/threading/Worker.ts @@ -54,7 +54,7 @@ export interface DiskManagerTask extends WorkerTask { export interface ThumbnailTask extends WorkerTask { input: RendererInput; - renderer: ServerConfig.ThumbnailProcessingLib; + renderer: ServerConfig.PhotoProcessingLib; } export module WorkerTask { diff --git a/src/common/config/private/IPrivateConfig.ts b/src/common/config/private/IPrivateConfig.ts index 22a0961..7d32e6a 100644 --- a/src/common/config/private/IPrivateConfig.ts +++ b/src/common/config/private/IPrivateConfig.ts @@ -14,7 +14,7 @@ export module ServerConfig { none = 1, error = 2, all = 3 } - export enum ThumbnailProcessingLib { + export enum PhotoProcessingLib { sharp = 3, Jimp = 1, gm = 2, @@ -43,7 +43,6 @@ export module ServerConfig { } export interface ThumbnailConfig { - processingLibrary: ThumbnailProcessingLib; qualityPriority: boolean; personFaceMargin: number; // in ration [0-1] } @@ -65,7 +64,7 @@ export module ServerConfig { } export interface ThreadingConfig { - enable: boolean; + enabled: boolean; thumbnailThreads: number; } @@ -107,6 +106,7 @@ export module ServerConfig { export interface MediaConfig { folder: string; tempFolder: string; + photoProcessingLibrary: PhotoProcessingLib; Video: VideoConfig; Photo: PhotoConfig; Thumbnail: ThumbnailConfig; diff --git a/src/common/config/private/PrivateConfigDefaultsClass.ts b/src/common/config/private/PrivateConfigDefaultsClass.ts index 080888f..a2d0b0d 100644 --- a/src/common/config/private/PrivateConfigDefaultsClass.ts +++ b/src/common/config/private/PrivateConfigDefaultsClass.ts @@ -14,8 +14,8 @@ export class PrivateConfigDefaultsClass extends PublicConfigClass implements IPr Media: { folder: 'demo/images', tempFolder: 'demo/tmp', + photoProcessingLibrary: ServerConfig.PhotoProcessingLib.sharp, Thumbnail: { - processingLibrary: ServerConfig.ThumbnailProcessingLib.sharp, qualityPriority: true, personFaceMargin: 0.6 }, @@ -61,7 +61,7 @@ export class PrivateConfigDefaultsClass extends PublicConfigClass implements IPr updateTimeout: 1000 * 60 * 5 }, Threading: { - enable: true, + enabled: true, thumbnailThreads: 0 }, Indexing: { diff --git a/src/common/entities/task/TaskDTO.ts b/src/common/entities/task/TaskDTO.ts index 6b75e75..36812d0 100644 --- a/src/common/entities/task/TaskDTO.ts +++ b/src/common/entities/task/TaskDTO.ts @@ -2,7 +2,7 @@ export type fieldType = 'string' | 'number' | 'boolean'; export enum DefaultsTasks { - Indexing = 1, 'Database Reset' = 2, 'Video Converting' = 3 + Indexing = 1, 'Database Reset' = 2, 'Video Converting' = 3, 'Photo Converting' = 4, 'Thumbnail Generation' = 5 } export interface ConfigTemplateEntry { diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts index 0c42148..e4f562c 100644 --- a/src/frontend/app/app.module.ts +++ b/src/frontend/app/app.module.ts @@ -87,6 +87,7 @@ import {TimepickerModule} from 'ngx-bootstrap/timepicker'; import {TimeStampDatePickerComponent} from './ui/utils/timestamp-datepicker/datepicker.component'; import {TimeStampTimePickerComponent} from './ui/utils/timestamp-timepicker/timepicker.component'; import {TasksProgressComponent} from './ui/settings/tasks/progress/progress.tasks.settings.component'; +import {PhotoSettingsComponent} from './ui/settings/photo/photo.settings.component'; @@ -188,6 +189,7 @@ export function translationsFactory(locale: string) { MapSettingsComponent, ThumbnailSettingsComponent, VideoSettingsComponent, + PhotoSettingsComponent, MetaFileSettingsComponent, SearchSettingsComponent, ShareSettingsComponent, diff --git a/src/frontend/app/ui/admin/admin.component.html b/src/frontend/app/ui/admin/admin.component.html index afb3aa7..4d675d9 100644 --- a/src/frontend/app/ui/admin/admin.component.html +++ b/src/frontend/app/ui/admin/admin.component.html @@ -53,8 +53,10 @@ + [hidden]="!s.HasAvailableSettings"> + {{s.Name}}* + @@ -63,44 +65,47 @@
+ [hidden]="!basic.HasAvailableSettings"> + [hidden]="!userManager.HasAvailableSettings"> - + [hidden]="!database.HasAvailableSettings"> + +
diff --git a/src/frontend/app/ui/settings/_abstract/ISettingsComponent.ts b/src/frontend/app/ui/settings/_abstract/ISettingsComponent.ts index fc9810f..2d3814b 100644 --- a/src/frontend/app/ui/settings/_abstract/ISettingsComponent.ts +++ b/src/frontend/app/ui/settings/_abstract/ISettingsComponent.ts @@ -1,5 +1,6 @@ export interface ISettingsComponent { - hasAvailableSettings: boolean; + HasAvailableSettings: boolean; Name: string; + Changed: boolean; } diff --git a/src/frontend/app/ui/settings/_abstract/abstract.settings.component.ts b/src/frontend/app/ui/settings/_abstract/abstract.settings.component.ts index 5aabe49..15f431c 100644 --- a/src/frontend/app/ui/settings/_abstract/abstract.settings.component.ts +++ b/src/frontend/app/ui/settings/_abstract/abstract.settings.component.ts @@ -60,6 +60,14 @@ export abstract class SettingsComponent { this.settings = Utils.clone(this.sliceFN(s)); this.original = Utils.clone(this.settings); diff --git a/src/frontend/app/ui/settings/faces/faces.settings.component.ts b/src/frontend/app/ui/settings/faces/faces.settings.component.ts index a407017..e312af1 100644 --- a/src/frontend/app/ui/settings/faces/faces.settings.component.ts +++ b/src/frontend/app/ui/settings/faces/faces.settings.component.ts @@ -18,7 +18,12 @@ import {UserRoles} from '../../../../../common/entities/UserDTO'; }) export class FacesSettingsComponent extends SettingsComponent { - public userRoles: Array = []; + public readonly userRoles = Utils + .enumToArray(UserRoles) + .filter(r => r.key !== UserRoles.LimitedGuest) + .filter(r => r.key <= this._authService.user.value.role) + .sort((a, b) => a.key - b.key); + constructor(_authService: AuthenticationService, _navigation: NavigationService, _settingsService: FacesSettingsService, @@ -26,11 +31,6 @@ export class FacesSettingsComponent extends SettingsComponent s.Client.Faces); - this.userRoles = Utils - .enumToArray(UserRoles) - .filter(r => r.key !== UserRoles.LimitedGuest) - .filter(r => r.key <= this._authService.user.value.role) - .sort((a, b) => a.key - b.key); } diff --git a/src/frontend/app/ui/settings/indexing/indexing.settings.component.html b/src/frontend/app/ui/settings/indexing/indexing.settings.component.html index fa50cbb..ef4f75e 100644 --- a/src/frontend/app/ui/settings/indexing/indexing.settings.component.html +++ b/src/frontend/app/ui/settings/indexing/indexing.settings.component.html @@ -99,43 +99,39 @@
- If you add a new folder to your gallery, the site indexes it automatically.  - If you would like to trigger indexing manually, click index button. -
- ( - Note: search only works among the indexed directories - )
+
-
- - - - -
+ + + + + +
diff --git a/src/frontend/app/ui/settings/indexing/indexing.settings.component.ts b/src/frontend/app/ui/settings/indexing/indexing.settings.component.ts index c11ece5..80b64e6 100644 --- a/src/frontend/app/ui/settings/indexing/indexing.settings.component.ts +++ b/src/frontend/app/ui/settings/indexing/indexing.settings.component.ts @@ -36,7 +36,7 @@ export class IndexingSettingsComponent extends SettingsComponent_settingsService, + _settingsService, notification, i18n, s => s.Server.Indexing); @@ -89,11 +89,11 @@ export class IndexingSettingsComponent extends SettingsComponent_settingsService, notification, i18n, s => s.Client.Map); + super(i18n('Map'), _authService, _navigation, _settingsService, notification, i18n, s => s.Client.Map); this.mapProviders = Utils.enumToArray(ClientConfig.MapProviders); } diff --git a/src/frontend/app/ui/settings/metafiles/metafile.settings.component.ts b/src/frontend/app/ui/settings/metafiles/metafile.settings.component.ts index eefeede..774e9c0 100644 --- a/src/frontend/app/ui/settings/metafiles/metafile.settings.component.ts +++ b/src/frontend/app/ui/settings/metafiles/metafile.settings.component.ts @@ -22,7 +22,7 @@ export class MetaFileSettingsComponent extends SettingsComponent_settingsService, notification, i18n, s => s.Client.MetaFile); + super(i18n('Meta file'), _authService, _navigation, _settingsService, notification, i18n, s => s.Client.MetaFile); } diff --git a/src/frontend/app/ui/settings/other/other.settings.component.html b/src/frontend/app/ui/settings/other/other.settings.component.html index c455078..8e980d5 100644 --- a/src/frontend/app/ui/settings/other/other.settings.component.html +++ b/src/frontend/app/ui/settings/other/other.settings.component.html @@ -21,7 +21,7 @@ [switch-on-text]="text.Enabled" [switch-handle-width]="100" [switch-label-width]="20" - [(ngModel)]="settings.Server.enable"> + [(ngModel)]="settings.Server.enabled"> Runs directory scanning and thumbnail generation (only for Jimp) in a different thread @@ -29,7 +29,7 @@
-
+
+ + + Make sure that sharp node module is installed (npm install sharp). + + + Make sure that gm node module and + GraphicsMagick + are installed (npm install sharp). + + +
+
+ +
+
+

Photo converting:

+ +
+ +
+ + + Downsizes photos for faster preview loading. (Zooming in to the photo + loads the original) +
+
+ +
+ +
+ + + Converts photos on the fly, when they are requested. +
+
+ +
+ +
+ + The shorter edge of the converted photo will be scaled down to this, + while + keeping the aspect ratio. +
+
+ + + + + +
+ + + + + +
+
+ +
+ +
+ + + + diff --git a/src/frontend/app/ui/settings/photo/photo.settings.component.ts b/src/frontend/app/ui/settings/photo/photo.settings.component.ts new file mode 100644 index 0000000..8ae9df1 --- /dev/null +++ b/src/frontend/app/ui/settings/photo/photo.settings.component.ts @@ -0,0 +1,105 @@ +import {Component} from '@angular/core'; +import {PhotoSettingsService} from './photo.settings.service'; +import {SettingsComponent} from '../_abstract/abstract.settings.component'; +import {AuthenticationService} from '../../../model/network/authentication.service'; +import {NavigationService} from '../../../model/navigation.service'; +import {NotificationService} from '../../../model/notification.service'; +import {ClientConfig} from '../../../../../common/config/public/ConfigClass'; +import {I18n} from '@ngx-translate/i18n-polyfill'; +import {ScheduledTasksService} from '../scheduled-tasks.service'; +import {ServerConfig} from '../../../../../common/config/private/IPrivateConfig'; +import {Utils} from '../../../../../common/Utils'; +import {DefaultsTasks} from '../../../../../common/entities/task/TaskDTO'; +import {ErrorDTO} from '../../../../../common/entities/Error'; +import {TaskState} from '../../../../../common/entities/settings/TaskProgressDTO'; + + +@Component({ + selector: 'app-settings-photo', + templateUrl: './photo.settings.component.html', + styleUrls: ['./photo.settings.component.css', + '../_abstract/abstract.settings.component.css'], + providers: [PhotoSettingsService], +}) +export class PhotoSettingsComponent extends SettingsComponent<{ + photoProcessingLibrary: ServerConfig.PhotoProcessingLib, + server: ServerConfig.PhotoConfig, + client: ClientConfig.PhotoConfig +}> { + resolutions = [720, 1080, 1440, 2160, 4320]; + PhotoProcessingLib = ServerConfig.PhotoProcessingLib; + TaskState = TaskState; + + libTypes = Utils + .enumToArray(ServerConfig.PhotoProcessingLib).map((v) => { + if (v.value.toLowerCase() === 'sharp') { + v.value += ' ' + this.i18n('(recommended)'); + } else { + v.value += ' ' + this.i18n('(deprecated, will be removed)'); + } + return v; + }); + + constructor(_authService: AuthenticationService, + _navigation: NavigationService, + _settingsService: PhotoSettingsService, + public tasksService: ScheduledTasksService, + notification: NotificationService, + i18n: I18n) { + super(i18n('Photo'), _authService, _navigation, _settingsService, notification, i18n, s => ({ + photoProcessingLibrary: s.Server.Media.photoProcessingLibrary, + client: s.Client.Media.Photo, + server: s.Server.Media.Photo + })); + const currentRes = _settingsService.Settings.value.Server.Media.Photo.Converting.resolution; + if (this.resolutions.indexOf(currentRes) === -1) { + this.resolutions.push(currentRes); + } + } + + + get Progress() { + return this.tasksService.progress.value[DefaultsTasks[DefaultsTasks['Photo Converting']]]; + } + + async convertPhoto() { + this.inProgress = true; + this.error = ''; + try { + await this.tasksService.start(DefaultsTasks[DefaultsTasks['Photo Converting']]); + this.notification.info(this.i18n('Photo converting started')); + this.inProgress = false; + return true; + } catch (err) { + console.log(err); + if (err.message) { + this.error = (err).message; + } + } + + this.inProgress = false; + return false; + } + + async cancelPhotoConverting() { + this.inProgress = true; + this.error = ''; + try { + await this.tasksService.stop(DefaultsTasks[DefaultsTasks['Photo Converting']]); + this.notification.info(this.i18n('Photo converting interrupted')); + this.inProgress = false; + return true; + } catch (err) { + console.log(err); + if (err.message) { + this.error = (err).message; + } + } + + this.inProgress = false; + return false; + } +} + + + diff --git a/src/frontend/app/ui/settings/photo/photo.settings.service.ts b/src/frontend/app/ui/settings/photo/photo.settings.service.ts new file mode 100644 index 0000000..89b80ad --- /dev/null +++ b/src/frontend/app/ui/settings/photo/photo.settings.service.ts @@ -0,0 +1,21 @@ +import {Injectable} from '@angular/core'; +import {NetworkService} from '../../../model/network/network.service'; +import {ClientConfig} from '../../../../../common/config/public/ConfigClass'; +import {SettingsService} from '../settings.service'; +import {AbstractSettingsService} from '../_abstract/abstract.settings.service'; +import {ServerConfig} from '../../../../../common/config/private/IPrivateConfig'; + +@Injectable() +export class PhotoSettingsService extends AbstractSettingsService<{ server: ServerConfig.PhotoConfig, client: ClientConfig.PhotoConfig }> { + constructor(private _networkService: NetworkService, + _settingsService: SettingsService) { + super(_settingsService); + } + + + public updateSettings(settings: { server: ServerConfig.PhotoConfig, client: ClientConfig.PhotoConfig }): Promise { + return this._networkService.putJson('/settings/photo', {settings: settings}); + } + + +} diff --git a/src/frontend/app/ui/settings/random-photo/random-photo.settings.component.html b/src/frontend/app/ui/settings/random-photo/random-photo.settings.component.html index 76aef24..3a14d14 100644 --- a/src/frontend/app/ui/settings/random-photo/random-photo.settings.component.html +++ b/src/frontend/app/ui/settings/random-photo/random-photo.settings.component.html @@ -2,7 +2,8 @@
- {{Name}}* + {{Name}} + *
Error: {{error}}
-
+ +
- -
-
- -
- - Make sure that sharp node module is installed (npm install sharp). - - - Make sure that gm node module and - GraphicsMagick - are installed (npm install sharp). - - -
-
@@ -84,7 +57,6 @@
- -
-
- To ensure smooth video playback, video transcoding is recommended to a lower bit rate than the - server's upload rate. -   - The transcoded videos will be save to the thumbnail folder.  - You can trigger the transcoding manually, but you can also create an automatic encoding task in - advanced settings mode. -   - -
- - - -