From a80297ce0ce6621fc08eb34f62a741b4245e081d Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Sun, 15 Dec 2019 15:36:05 +0100 Subject: [PATCH] adding thumbnail task --- docker/arm32v6/alpine/Dockerfile | 12 +++- src/backend/middlewares/admin/AdminMWs.ts | 4 +- src/backend/model/tasks/TaskRepository.ts | 2 + src/backend/model/tasks/tasks/FileTask.ts | 3 +- .../tasks/tasks/ThumbnailGenerationTask.ts | 61 +++++++++++++++++++ src/common/entities/task/TaskDTO.ts | 2 +- .../tasks/tasks.settings.component.html | 22 ++++++- .../tasks/tasks.settings.component.ts | 24 ++++++++ .../thumbnail/thumbnail.settings.component.ts | 2 + 9 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts diff --git a/docker/arm32v6/alpine/Dockerfile b/docker/arm32v6/alpine/Dockerfile index 741963eb..d1246469 100644 --- a/docker/arm32v6/alpine/Dockerfile +++ b/docker/arm32v6/alpine/Dockerfile @@ -3,8 +3,8 @@ RUN apk add --no-cache wget && \ wget https://github.com/multiarch/qemu-user-static/releases/download/v4.1.1-1/x86_64_qemu-arm-static.tar.gz && \ tar -xvf x86_64_qemu-arm-static.tar.gz -FROM arm32v6/node:12-alpine AS builder -COPY --from=qemu-builder /qemu-arm-static /usr/bin +# separate release builder for faster build on docker hub +FROM node:12-alpine AS node-builder RUN apk add python build-base # copying only package{-lock}.json to make node_modules cachable COPY package*.json /build/ @@ -12,6 +12,12 @@ WORKDIR /build RUN set -x && npm install --unsafe-perm # build app COPY . /build +RUN npm run create-release + +FROM arm32v6/node:12-alpine AS builder +COPY --from=qemu-builder /qemu-arm-static /usr/bin +RUN apk add python build-base +COPY --from=node-builder /build/release /build/release RUN mkdir -p /build/release/data/config && \ mkdir -p /build/release/data/db && \ mkdir -p /build/release/data/images && \ @@ -32,7 +38,7 @@ WORKDIR /app ENTRYPOINT ["npm", "start"] EXPOSE 80 ENV NODE_ENV=production -COPY --from=builder /build/release /app +COPY --from=qemu-builder /build/release /app RUN ln -s /app/data/config/config.json config.json VOLUME ["/app/data/config", "/app/data/db", "/app/data/images", "/app/data/TEMP"] HEALTHCHECK --interval=30s --timeout=10s --retries=4 --start-period=60s \ diff --git a/src/backend/middlewares/admin/AdminMWs.ts b/src/backend/middlewares/admin/AdminMWs.ts index 700987d5..d2ba8c56 100644 --- a/src/backend/middlewares/admin/AdminMWs.ts +++ b/src/backend/middlewares/admin/AdminMWs.ts @@ -50,11 +50,11 @@ export class AdminMWs { } } - public static startTask(req: Request, res: Response, next: NextFunction) { + public static async startTask(req: Request, res: Response, next: NextFunction) { try { const id = req.params.id; const taskConfig: any = req.body.config; - ObjectManagers.getInstance().TaskManager.run(id, taskConfig); + await ObjectManagers.getInstance().TaskManager.run(id, taskConfig); req.resultPipe = 'ok'; return next(); } catch (err) { diff --git a/src/backend/model/tasks/TaskRepository.ts b/src/backend/model/tasks/TaskRepository.ts index eb5d12e8..3528b4ce 100644 --- a/src/backend/model/tasks/TaskRepository.ts +++ b/src/backend/model/tasks/TaskRepository.ts @@ -3,6 +3,7 @@ import {IndexingTask} from './tasks/IndexingTask'; import {DBRestTask} from './tasks/DBResetTask'; import {VideoConvertingTask} from './tasks/VideoConvertingTask'; import {PhotoConvertingTask} from './tasks/PhotoConvertingTask'; +import {ThumbnailGenerationTask} from './tasks/ThumbnailGenerationTask'; export class TaskRepository { @@ -30,3 +31,4 @@ TaskRepository.Instance.register(new IndexingTask()); TaskRepository.Instance.register(new DBRestTask()); TaskRepository.Instance.register(new VideoConvertingTask()); TaskRepository.Instance.register(new PhotoConvertingTask()); +TaskRepository.Instance.register(new ThumbnailGenerationTask()); diff --git a/src/backend/model/tasks/tasks/FileTask.ts b/src/backend/model/tasks/tasks/FileTask.ts index d3462e35..8b30ca08 100644 --- a/src/backend/model/tasks/tasks/FileTask.ts +++ b/src/backend/model/tasks/tasks/FileTask.ts @@ -6,6 +6,7 @@ import {DiskManager} from '../../DiskManger'; import {DiskMangerWorker} from '../../threading/DiskMangerWorker'; import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO'; import {Logger} from '../../../Logger'; +import {MediaDTO} from '../../../../common/entities/MediaDTO'; declare var global: NodeJS.Global; @@ -13,7 +14,7 @@ declare var global: NodeJS.Global; const LOG_TAG = '[FileTask]'; -export abstract class FileTask extends Task { +export abstract class FileTask extends Task { public readonly ConfigTemplate: ConfigTemplateEntry[] = null; directoryQueue: string[] = []; fileQueue: T[] = []; diff --git a/src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts b/src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts new file mode 100644 index 00000000..0c2873ca --- /dev/null +++ b/src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts @@ -0,0 +1,61 @@ +import {Config} from '../../../../common/config/private/Config'; +import {ConfigTemplateEntry, DefaultsTasks} from '../../../../common/entities/task/TaskDTO'; +import {ProjectPath} from '../../../ProjectPath'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as util from 'util'; +import {FileTask} from './FileTask'; +import {DirectoryDTO} from '../../../../common/entities/DirectoryDTO'; +import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing'; +import {ThumbnailSourceType} from '../../threading/ThumbnailWorker'; +import {MediaDTO} from '../../../../common/entities/MediaDTO'; + +const LOG_TAG = '[ThumbnailGenerationTask]'; +const existsPr = util.promisify(fs.exists); + + +export class ThumbnailGenerationTask extends FileTask { + public readonly Name = DefaultsTasks[DefaultsTasks['Thumbnail Generation']]; + public readonly ConfigTemplate: ConfigTemplateEntry[] = [{ + id: 'sizes', + type: 'number-array', + name: 'Sizes to generate', + defaultValue: [Config.Client.Media.Thumbnail.thumbnailSizes[0]] + }]; + + constructor() { + super({noMetaFile: true}); + } + + public get Supported(): boolean { + return true; + } + + start(config: { sizes: number[] }): Promise { + for (let i = 0; i < config.sizes.length; ++i) { + if (Config.Client.Media.Thumbnail.thumbnailSizes.indexOf(config.sizes[i]) === -1) { + throw new Error('unknown thumbnails size: ' + config.sizes[i] + '. Add it to the possible thumbnail sizes.'); + } + } + + return super.start(config); + } + + protected async processDirectory(directory: DirectoryDTO): Promise { + return directory.media; + } + + protected async processFile(media: MediaDTO): Promise { + + const mPath = path.join(ProjectPath.ImageFolder, media.directory.path, media.directory.name, media.name); + for (let i = 0; i < this.config.sizes.length; ++i) { + await PhotoProcessing.generateThumbnail(mPath, + this.config.sizes[i], + MediaDTO.isVideo(media) ? ThumbnailSourceType.Video : ThumbnailSourceType.Photo, + false); + + } + } + + +} diff --git a/src/common/entities/task/TaskDTO.ts b/src/common/entities/task/TaskDTO.ts index 36812d0f..6a58e1de 100644 --- a/src/common/entities/task/TaskDTO.ts +++ b/src/common/entities/task/TaskDTO.ts @@ -1,4 +1,4 @@ -export type fieldType = 'string' | 'number' | 'boolean'; +export type fieldType = 'string' | 'number' | 'boolean' | 'number-array'; export enum DefaultsTasks { diff --git a/src/frontend/app/ui/settings/tasks/tasks.settings.component.html b/src/frontend/app/ui/settings/tasks/tasks.settings.component.html index afa93977..9a8503a7 100644 --- a/src/frontend/app/ui/settings/tasks/tasks.settings.component.html +++ b/src/frontend/app/ui/settings/tasks/tasks.settings.component.html @@ -1,7 +1,8 @@
- {{Name}}* + {{Name}} + *
@@ -34,7 +35,8 @@
- @@ -155,6 +157,22 @@
+ +
+ +
+ + + ';' separated integers. + +
+
+
diff --git a/src/frontend/app/ui/settings/tasks/tasks.settings.component.ts b/src/frontend/app/ui/settings/tasks/tasks.settings.component.ts index 2f619015..c3b51b96 100644 --- a/src/frontend/app/ui/settings/tasks/tasks.settings.component.ts +++ b/src/frontend/app/ui/settings/tasks/tasks.settings.component.ts @@ -130,6 +130,13 @@ export class TasksSettingsComponent extends SettingsComponent t.Name === schedule.taskName); + schedule.config = schedule.config || {}; + task.ConfigTemplate.forEach(ct => schedule.config[ct.id] = ct.defaultValue); + } + addNewTask() { const taskName = this._settingsService.availableTasks.value[0].Name; const newSchedule: TaskScheduleDTO = { @@ -159,6 +166,23 @@ export class TasksSettingsComponent extends SettingsComponent parseInt(s, 10)) + .filter((i: number) => !isNaN(i) && i > 0); + console.log(configElement[id]); + } + + getNumberArray(configElement: any, id: string) { + + return configElement[id].join('; '); + } + } diff --git a/src/frontend/app/ui/settings/thumbnail/thumbnail.settings.component.ts b/src/frontend/app/ui/settings/thumbnail/thumbnail.settings.component.ts index bbc71916..268f322f 100644 --- a/src/frontend/app/ui/settings/thumbnail/thumbnail.settings.component.ts +++ b/src/frontend/app/ui/settings/thumbnail/thumbnail.settings.component.ts @@ -48,6 +48,8 @@ export class ThumbnailSettingsComponent super.ngOnInit(); } + + }