mirror of
https://github.com/xuthus83/pigallery2.git
synced 2024-11-03 21:04:03 +08:00
adding thumbnail task
This commit is contained in:
parent
5160e19a35
commit
a80297ce0c
@ -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 \
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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<T> extends Task {
|
||||
export abstract class FileTask<T, S = void> extends Task<S> {
|
||||
public readonly ConfigTemplate: ConfigTemplateEntry[] = null;
|
||||
directoryQueue: string[] = [];
|
||||
fileQueue: T[] = [];
|
||||
|
61
src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts
Normal file
61
src/backend/model/tasks/tasks/ThumbnailGenerationTask.ts
Normal file
@ -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<MediaDTO, { sizes: number[] }> {
|
||||
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<void> {
|
||||
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<MediaDTO[]> {
|
||||
return directory.media;
|
||||
}
|
||||
|
||||
protected async processFile(media: MediaDTO): Promise<void> {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export type fieldType = 'string' | 'number' | 'boolean';
|
||||
export type fieldType = 'string' | 'number' | 'boolean' | 'number-array';
|
||||
|
||||
|
||||
export enum DefaultsTasks {
|
||||
|
@ -1,7 +1,8 @@
|
||||
<form #settingsForm="ngForm" class="form-horizontal">
|
||||
<div class="card mb-4">
|
||||
<h5 class="card-header">
|
||||
{{Name}}<ng-container *ngIf="changed">*</ng-container>
|
||||
{{Name}}
|
||||
<ng-container *ngIf="changed">*</ng-container>
|
||||
</h5>
|
||||
<div class="card-body">
|
||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||
@ -34,7 +35,8 @@
|
||||
<div class="form-group row">
|
||||
<label class="col-md-2 control-label" [for]="'taskName'+i" i18n>Task:</label>
|
||||
<div class="col-md-10">
|
||||
<select class="form-control" [(ngModel)]="schedule.taskName" [name]="'taskName'+i" required>
|
||||
<select class="form-control" (change)="taskTypeChanged(schedule)" [(ngModel)]="schedule.taskName"
|
||||
[name]="'taskName'+i" required>
|
||||
<option *ngFor="let availableTask of _settingsService.availableTasks | async"
|
||||
[ngValue]="availableTask.Name">{{availableTask.Name}}
|
||||
</option>
|
||||
@ -155,6 +157,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'number-array'">
|
||||
<div class="form-group row" [hidden]="simplifiedMode">
|
||||
<label class="col-md-2 control-label"
|
||||
[for]="configEntry.id+'_number-array_'+i">{{configEntry.name}}</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control"
|
||||
[name]="configEntry.id+'_number-array_'+i"
|
||||
[id]="configEntry.id+'_number-array_'+i"
|
||||
(ngModelChange)="setNumberArray(schedule.config,configEntry.id,$event)"
|
||||
[ngModel]="getNumberArray(schedule.config,configEntry.id)" required>
|
||||
<small class="form-text text-muted">
|
||||
<ng-container i18n>';' separated integers.</ng-container>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@ -130,6 +130,13 @@ export class TasksSettingsComponent extends SettingsComponent<ServerConfig.TaskC
|
||||
this.settings.scheduled.splice(index, 1);
|
||||
}
|
||||
|
||||
|
||||
taskTypeChanged(schedule: TaskScheduleDTO) {
|
||||
const task = this._settingsService.availableTasks.value.find(t => 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<ServerConfig.TaskC
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setNumberArray(configElement: any, id: string, value: string) {
|
||||
console.log(value);
|
||||
console.log(configElement[id]);
|
||||
value = value.replace(new RegExp(',', 'g'), ';');
|
||||
value = value.replace(new RegExp(' ', 'g'), ';');
|
||||
configElement[id] = value.split(';')
|
||||
.map((s: string) => parseInt(s, 10))
|
||||
.filter((i: number) => !isNaN(i) && i > 0);
|
||||
console.log(configElement[id]);
|
||||
}
|
||||
|
||||
getNumberArray(configElement: any, id: string) {
|
||||
|
||||
return configElement[id].join('; ');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,6 +48,8 @@ export class ThumbnailSettingsComponent
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user