mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-04-15 11:56:50 +02:00
improving jobs
This commit is contained in:
parent
34267e8ed8
commit
c716ff4ca7
@ -14,7 +14,7 @@
|
|||||||
"pretest": "tsc",
|
"pretest": "tsc",
|
||||||
"test": "ng test && mocha --recursive test/backend/unit && mocha --recursive test/backend/integration && mocha --recursive test/common/unit ",
|
"test": "ng test && mocha --recursive test/backend/unit && mocha --recursive test/backend/integration && mocha --recursive test/common/unit ",
|
||||||
"start": "node ./src/backend/index",
|
"start": "node ./src/backend/index",
|
||||||
"run-dev": "ng build --aot --watch --output-path=./dist --i18n-locale hu --i18n-file src/frontend/translate/messages.hu.xlf --i18n-missing-translation warning",
|
"run-dev": "ng build --aot --watch --output-path=./dist --i18n-locale en --i18n-file src/frontend/translate/messages.en.xlf --i18n-missing-translation warning",
|
||||||
"build-stats": "ng build --aot --prod --stats-json --output-path=./dist --i18n-locale en --i18n-file src/frontend/translate/messages.en.xlf --i18n-missing-translation warning",
|
"build-stats": "ng build --aot --prod --stats-json --output-path=./dist --i18n-locale en --i18n-file src/frontend/translate/messages.en.xlf --i18n-missing-translation warning",
|
||||||
"merge-new-translation": "gulp merge-new-translation",
|
"merge-new-translation": "gulp merge-new-translation",
|
||||||
"add-translation": "gulp add-translation"
|
"add-translation": "gulp add-translation"
|
||||||
|
@ -12,7 +12,7 @@ import {MediaEntity} from '../../database/sql/enitites/MediaEntity';
|
|||||||
import {PhotoEntity} from '../../database/sql/enitites/PhotoEntity';
|
import {PhotoEntity} from '../../database/sql/enitites/PhotoEntity';
|
||||||
import {VideoEntity} from '../../database/sql/enitites/VideoEntity';
|
import {VideoEntity} from '../../database/sql/enitites/VideoEntity';
|
||||||
import {backendTexts} from '../../../../common/BackendTexts';
|
import {backendTexts} from '../../../../common/BackendTexts';
|
||||||
import DatabaseType = ServerConfig.DatabaseType;
|
import {ProjectPath} from '../../../ProjectPath';
|
||||||
|
|
||||||
declare var global: NodeJS.Global;
|
declare var global: NodeJS.Global;
|
||||||
|
|
||||||
@ -23,12 +23,12 @@ const LOG_TAG = '[FileJob]';
|
|||||||
export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly: boolean }> extends Job<S> {
|
export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly: boolean }> extends Job<S> {
|
||||||
public readonly ConfigTemplate: ConfigTemplateEntry[] = [];
|
public readonly ConfigTemplate: ConfigTemplateEntry[] = [];
|
||||||
directoryQueue: string[] = [];
|
directoryQueue: string[] = [];
|
||||||
fileQueue: FileDTO[] = [];
|
fileQueue: string[] = [];
|
||||||
|
|
||||||
|
|
||||||
protected constructor(private scanFilter: DiskMangerWorker.DirectoryScanSettings) {
|
protected constructor(private scanFilter: DiskMangerWorker.DirectoryScanSettings) {
|
||||||
super();
|
super();
|
||||||
if (Config.Server.Database.type !== DatabaseType.memory) {
|
if (Config.Server.Database.type !== ServerConfig.DatabaseType.memory) {
|
||||||
this.ConfigTemplate.push({
|
this.ConfigTemplate.push({
|
||||||
id: 'indexedOnly',
|
id: 'indexedOnly',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@ -54,9 +54,9 @@ export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract async shouldProcess(file: FileDTO): Promise<boolean>;
|
protected abstract async shouldProcess(filePath: string): Promise<boolean>;
|
||||||
|
|
||||||
protected abstract async processFile(file: FileDTO): Promise<void>;
|
protected abstract async processFile(filePath: string): Promise<void>;
|
||||||
|
|
||||||
protected async step(): Promise<boolean> {
|
protected async step(): Promise<boolean> {
|
||||||
if (this.directoryQueue.length === 0 && this.fileQueue.length === 0) {
|
if (this.directoryQueue.length === 0 && this.fileQueue.length === 0) {
|
||||||
@ -66,7 +66,7 @@ export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly
|
|||||||
if (this.directoryQueue.length > 0) {
|
if (this.directoryQueue.length > 0) {
|
||||||
|
|
||||||
if (this.config.indexedOnly === true &&
|
if (this.config.indexedOnly === true &&
|
||||||
Config.Server.Database.type !== DatabaseType.memory) {
|
Config.Server.Database.type !== ServerConfig.DatabaseType.memory) {
|
||||||
await this.loadAllMediaFilesFromDB();
|
await this.loadAllMediaFilesFromDB();
|
||||||
this.directoryQueue = [];
|
this.directoryQueue = [];
|
||||||
} else {
|
} else {
|
||||||
@ -74,13 +74,12 @@ export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly
|
|||||||
}
|
}
|
||||||
} else if (this.fileQueue.length > 0) {
|
} else if (this.fileQueue.length > 0) {
|
||||||
this.Progress.Left = this.fileQueue.length;
|
this.Progress.Left = this.fileQueue.length;
|
||||||
const file = this.fileQueue.shift();
|
const filePath = this.fileQueue.shift();
|
||||||
const filePath = path.join(file.directory.path, file.directory.name, file.name);
|
|
||||||
try {
|
try {
|
||||||
if ((await this.shouldProcess(file)) === true) {
|
if ((await this.shouldProcess(filePath)) === true) {
|
||||||
this.Progress.Processed++;
|
this.Progress.Processed++;
|
||||||
this.Progress.log('processing: ' + filePath);
|
this.Progress.log('processing: ' + filePath);
|
||||||
await this.processFile(file);
|
await this.processFile(filePath);
|
||||||
} else {
|
} else {
|
||||||
this.Progress.log('skipping: ' + filePath);
|
this.Progress.log('skipping: ' + filePath);
|
||||||
this.Progress.Skipped++;
|
this.Progress.Skipped++;
|
||||||
@ -102,10 +101,12 @@ export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly
|
|||||||
this.directoryQueue.push(path.join(scanned.directories[i].path, scanned.directories[i].name));
|
this.directoryQueue.push(path.join(scanned.directories[i].path, scanned.directories[i].name));
|
||||||
}
|
}
|
||||||
if (this.scanFilter.noVideo !== true || this.scanFilter.noVideo !== true) {
|
if (this.scanFilter.noVideo !== true || this.scanFilter.noVideo !== true) {
|
||||||
this.fileQueue.push(...await this.filterMediaFiles(scanned.media));
|
this.fileQueue.push(...(await this.filterMediaFiles(scanned.media))
|
||||||
|
.map(f => path.join(ProjectPath.ImageFolder, f.directory.path, f.directory.name, f.name)));
|
||||||
}
|
}
|
||||||
if (this.scanFilter.noMetaFile !== true) {
|
if (this.scanFilter.noMetaFile !== true) {
|
||||||
this.fileQueue.push(...await this.filterMetaFiles(scanned.metaFile));
|
this.fileQueue.push(...(await this.filterMetaFiles(scanned.metaFile))
|
||||||
|
.map(f => path.join(ProjectPath.ImageFolder, f.directory.path, f.directory.name, f.name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +135,7 @@ export abstract class FileJob<S extends { indexedOnly: boolean } = { indexedOnly
|
|||||||
.leftJoinAndSelect('media.directory', 'directory')
|
.leftJoinAndSelect('media.directory', 'directory')
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
this.fileQueue.push(...await this.filterMediaFiles(result));
|
this.fileQueue.push(...(result
|
||||||
|
.map(f => path.join(ProjectPath.ImageFolder, f.directory.path, f.directory.name, f.name))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,14 +21,12 @@ export class PhotoConvertingJob extends FileJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected async shouldProcess(file: FileDTO): Promise<boolean> {
|
protected async shouldProcess(mPath: string): Promise<boolean> {
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
return !(await PhotoProcessing.convertedPhotoExist(mPath, Config.Server.Media.Photo.Converting.resolution));
|
return !(await PhotoProcessing.convertedPhotoExist(mPath, Config.Server.Media.Photo.Converting.resolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected async processFile(file: FileDTO): Promise<void> {
|
protected async processFile(mPath: string): Promise<void> {
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
await PhotoProcessing.convertPhoto(mPath);
|
await PhotoProcessing.convertPhoto(mPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import {Config} from '../../../../common/config/private/Config';
|
import {Config} from '../../../../common/config/private/Config';
|
||||||
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
|
||||||
import * as path from 'path';
|
|
||||||
import {FileJob} from './FileJob';
|
import {FileJob} from './FileJob';
|
||||||
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing';
|
||||||
import {ThumbnailSourceType} from '../../threading/PhotoWorker';
|
import {ThumbnailSourceType} from '../../threading/PhotoWorker';
|
||||||
@ -49,8 +47,7 @@ export class ThumbnailGenerationJob extends FileJob<{ sizes: number[], indexedOn
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async shouldProcess(file: FileDTO): Promise<boolean> {
|
protected async shouldProcess(mPath: string): Promise<boolean> {
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
for (let i = 0; i < this.config.sizes.length; ++i) {
|
for (let i = 0; i < this.config.sizes.length; ++i) {
|
||||||
if (!(await PhotoProcessing.convertedPhotoExist(mPath, this.config.sizes[i]))) {
|
if (!(await PhotoProcessing.convertedPhotoExist(mPath, this.config.sizes[i]))) {
|
||||||
return true;
|
return true;
|
||||||
@ -58,13 +55,11 @@ export class ThumbnailGenerationJob extends FileJob<{ sizes: number[], indexedOn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processFile(file: FileDTO): Promise<void> {
|
protected async processFile(mPath: string): Promise<void> {
|
||||||
|
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
for (let i = 0; i < this.config.sizes.length; ++i) {
|
for (let i = 0; i < this.config.sizes.length; ++i) {
|
||||||
await PhotoProcessing.generateThumbnail(mPath,
|
await PhotoProcessing.generateThumbnail(mPath,
|
||||||
this.config.sizes[i],
|
this.config.sizes[i],
|
||||||
MediaDTO.isVideo(file) ? ThumbnailSourceType.Video : ThumbnailSourceType.Photo,
|
MediaDTO.isVideoPath(mPath) ? ThumbnailSourceType.Video : ThumbnailSourceType.Photo,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import {Config} from '../../../../common/config/private/Config';
|
import {Config} from '../../../../common/config/private/Config';
|
||||||
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
|
||||||
import {ProjectPath} from '../../../ProjectPath';
|
|
||||||
import * as path from 'path';
|
|
||||||
import {FileJob} from './FileJob';
|
import {FileJob} from './FileJob';
|
||||||
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
import {VideoProcessing} from '../../fileprocessing/VideoProcessing';
|
||||||
import {FileDTO} from '../../../../common/entities/FileDTO';
|
|
||||||
|
|
||||||
const LOG_TAG = '[VideoConvertingJob]';
|
const LOG_TAG = '[VideoConvertingJob]';
|
||||||
|
declare const global: any;
|
||||||
|
|
||||||
|
|
||||||
export class VideoConvertingJob extends FileJob {
|
export class VideoConvertingJob extends FileJob {
|
||||||
@ -20,14 +18,15 @@ export class VideoConvertingJob extends FileJob {
|
|||||||
return Config.Client.Media.Video.enabled === true;
|
return Config.Client.Media.Video.enabled === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async shouldProcess(file: FileDTO): Promise<boolean> {
|
protected async shouldProcess(mPath: string): Promise<boolean> {
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
return !(await VideoProcessing.convertedVideoExist(mPath));
|
return !(await VideoProcessing.convertedVideoExist(mPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async processFile(file: FileDTO): Promise<void> {
|
protected async processFile(mPath: string): Promise<void> {
|
||||||
const mPath = path.join(ProjectPath.ImageFolder, file.directory.path, file.directory.name, file.name);
|
|
||||||
await VideoProcessing.convertVideo(mPath);
|
await VideoProcessing.convertVideo(mPath);
|
||||||
|
if (global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,6 +65,16 @@ export module MediaDTO {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isVideoPath = (path: string): boolean => {
|
||||||
|
const lower = path.toLowerCase();
|
||||||
|
for (const ext of SupportedFormats.WithDots.Videos) {
|
||||||
|
if (lower.endsWith(ext)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export const isVideoTranscodingNeeded = (media: FileDTO): boolean => {
|
export const isVideoTranscodingNeeded = (media: FileDTO): boolean => {
|
||||||
const lower = media.name.toLowerCase();
|
const lower = media.name.toLowerCase();
|
||||||
for (const ext of SupportedFormats.WithDots.TranscodeNeed.Videos) {
|
for (const ext of SupportedFormats.WithDots.TranscodeNeed.Videos) {
|
||||||
|
@ -41,7 +41,7 @@ export class JobButtonComponent {
|
|||||||
this.error.emit('');
|
this.error.emit('');
|
||||||
try {
|
try {
|
||||||
await this.jobsService.start(this.jobName, this.config, this.soloRun);
|
await this.jobsService.start(this.jobName, this.config, this.soloRun);
|
||||||
this.notification.info(this.i18n('Job started') + ': ' + this.jobName);
|
this.notification.success(this.i18n('Job started') + ': ' + this.backendTextService.getJobName(this.jobName));
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -57,7 +57,7 @@ export class JobButtonComponent {
|
|||||||
this.error.emit('');
|
this.error.emit('');
|
||||||
try {
|
try {
|
||||||
await this.jobsService.stop(this.jobName);
|
await this.jobsService.stop(this.jobName);
|
||||||
this.notification.info(this.i18n('Job stopped') + ': ' + this.jobName);
|
this.notification.info(this.i18n('Job stopped') + ': ' + this.backendTextService.getJobName(this.jobName));
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<div class="input-group form-group">
|
<div class="input-group form-group">
|
||||||
<input
|
<input
|
||||||
*ngIf="progress.state === JobProgressStates.running" type="text" class="form-control" disabled
|
*ngIf="progress.state === JobProgressStates.running && progress.logs.length > 0" type="text" class="form-control" disabled
|
||||||
[ngModel]="progress.logs[progress.logs.length-1].comment" name="details">
|
[ngModel]="progress.logs[progress.logs.length-1].comment" name="details">
|
||||||
<input
|
<input
|
||||||
*ngIf="progress.state === JobProgressStates.cancelling" type="text" class="form-control" disabled
|
*ngIf="progress.state === JobProgressStates.cancelling" type="text" class="form-control" disabled
|
||||||
@ -112,7 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body text-secondary">
|
<div class="card-body text-secondary">
|
||||||
<ng-container *ngFor="let log of progress.logs; let i = index;">
|
<ng-container *ngFor="let log of progress.logs; let i = index;">
|
||||||
<p class="card-text" *ngIf="(i==0 && log.id > 0) || ( i> 0 && progress.logs[i-1].id+1!=log.id)">
|
<p class="card-text" *ngIf="(i==0 && log.id > 0) || ( i> 0 && progress.logs[i-1].id+1!=log.id)">
|
||||||
...
|
...
|
||||||
</p>
|
</p>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div [hidden]="!settings.client.Converting.enabled">
|
<div [hidden]="!settings.client.Converting.enabled">
|
||||||
<app-settings-job-button class="mt-2 mt-md-2 float-left"
|
<app-settings-job-button class="mt-2 mt-md-0 float-left"
|
||||||
[soloRun]="true"
|
[soloRun]="true"
|
||||||
(error)="error=$event"
|
(error)="error=$event"
|
||||||
[jobName]="jobName"></app-settings-job-button>
|
[jobName]="jobName"></app-settings-job-button>
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import {EventEmitter, Injectable} from '@angular/core';
|
import {EventEmitter, Injectable} from '@angular/core';
|
||||||
import {BehaviorSubject} from 'rxjs';
|
import {BehaviorSubject} from 'rxjs';
|
||||||
import {JobProgressDTO} from '../../../../common/entities/job/JobProgressDTO';
|
import {JobProgressDTO, JobProgressStates} from '../../../../common/entities/job/JobProgressDTO';
|
||||||
import {NetworkService} from '../../model/network/network.service';
|
import {NetworkService} from '../../model/network/network.service';
|
||||||
import {JobScheduleDTO} from '../../../../common/entities/job/JobScheduleDTO';
|
import {JobScheduleDTO} from '../../../../common/entities/job/JobScheduleDTO';
|
||||||
import {JobDTO} from '../../../../common/entities/job/JobDTO';
|
import {JobDTO} from '../../../../common/entities/job/JobDTO';
|
||||||
|
import {BackendtextService} from '../../model/backendtext.service';
|
||||||
|
import {NotificationService} from '../../model/notification.service';
|
||||||
|
import {I18n} from '@ngx-translate/i18n-polyfill';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ScheduledJobsService {
|
export class ScheduledJobsService {
|
||||||
@ -15,7 +18,10 @@ export class ScheduledJobsService {
|
|||||||
public jobStartingStopping: { [key: string]: boolean } = {};
|
public jobStartingStopping: { [key: string]: boolean } = {};
|
||||||
private subscribers = 0;
|
private subscribers = 0;
|
||||||
|
|
||||||
constructor(private _networkService: NetworkService) {
|
constructor(private _networkService: NetworkService,
|
||||||
|
private notification: NotificationService,
|
||||||
|
private backendTextService: BackendtextService,
|
||||||
|
private i18n: I18n) {
|
||||||
this.progress = new BehaviorSubject({});
|
this.progress = new BehaviorSubject({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +45,8 @@ export class ScheduledJobsService {
|
|||||||
this.jobStartingStopping[jobName] = true;
|
this.jobStartingStopping[jobName] = true;
|
||||||
await this._networkService.postJson('/admin/jobs/scheduled/' + jobName + '/' + (soloStart === true ? 'soloStart' : 'start'),
|
await this._networkService.postJson('/admin/jobs/scheduled/' + jobName + '/' + (soloStart === true ? 'soloStart' : 'start'),
|
||||||
{config: config});
|
{config: config});
|
||||||
|
// placeholder to force showing running job
|
||||||
|
this.addDummyProgress(jobName, config);
|
||||||
delete this.jobStartingStopping[jobName];
|
delete this.jobStartingStopping[jobName];
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
@ -53,14 +61,20 @@ export class ScheduledJobsService {
|
|||||||
protected async loadProgress(): Promise<void> {
|
protected async loadProgress(): Promise<void> {
|
||||||
const prevPrg = this.progress.value;
|
const prevPrg = this.progress.value;
|
||||||
this.progress.next(await this._networkService.getJson<{ [key: string]: JobProgressDTO }>('/admin/jobs/scheduled/progress'));
|
this.progress.next(await this._networkService.getJson<{ [key: string]: JobProgressDTO }>('/admin/jobs/scheduled/progress'));
|
||||||
for (const prg in prevPrg) {
|
for (const prg of Object.keys(prevPrg)) {
|
||||||
if (!this.progress.value.hasOwnProperty(prg)) {
|
if (!this.progress.value.hasOwnProperty(prg) ||
|
||||||
|
// state changed from running to finished
|
||||||
|
((prevPrg[prg].state === JobProgressStates.running ||
|
||||||
|
prevPrg[prg].state === JobProgressStates.cancelling) &&
|
||||||
|
!(this.progress.value[prg].state === JobProgressStates.running ||
|
||||||
|
this.progress.value[prg].state === JobProgressStates.cancelling)
|
||||||
|
)) {
|
||||||
this.onJobFinish.emit(prg);
|
this.onJobFinish.emit(prg);
|
||||||
|
this.notification.info(this.i18n('Job finished') + ': ' + this.backendTextService.getJobName(prevPrg[prg].jobName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected getProgressPeriodically() {
|
protected getProgressPeriodically() {
|
||||||
if (this.timer != null || this.subscribers === 0) {
|
if (this.timer != null || this.subscribers === 0) {
|
||||||
return;
|
return;
|
||||||
@ -76,6 +90,25 @@ export class ScheduledJobsService {
|
|||||||
this.loadProgress().catch(console.error);
|
this.loadProgress().catch(console.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addDummyProgress(jobName: string, config: any) {
|
||||||
|
const prgs = this.progress.value;
|
||||||
|
prgs[JobDTO.getHashName(jobName, config)] = {
|
||||||
|
jobName: jobName,
|
||||||
|
state: JobProgressStates.running,
|
||||||
|
HashName: JobDTO.getHashName(jobName, config),
|
||||||
|
logs: [], steps: {
|
||||||
|
skipped: 0,
|
||||||
|
processed: 0,
|
||||||
|
all: 0
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
start: Date.now(),
|
||||||
|
end: Date.now()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.progress.next(prgs);
|
||||||
|
}
|
||||||
|
|
||||||
private incSubscribers() {
|
private incSubscribers() {
|
||||||
this.subscribers++;
|
this.subscribers++;
|
||||||
this.getProgressPeriodically();
|
this.getProgressPeriodically();
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
<app-settings-job-button class="mt-2 mt-md-2 float-left"
|
<app-settings-job-button class="mt-2 mt-md-0 float-left"
|
||||||
[soloRun]="true"
|
[soloRun]="true"
|
||||||
(error)="error=$event"
|
(error)="error=$event"
|
||||||
[jobName]="jobName"
|
[jobName]="jobName"
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
(click)="reset()" i18n>Reset
|
(click)="reset()" i18n>Reset
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<app-settings-job-button class="mt-2 mt-md-2 float-left"
|
<app-settings-job-button class="mt-2 mt-md-0 float-left"
|
||||||
[soloRun]="true"
|
[soloRun]="true"
|
||||||
(error)="error=$event"
|
(error)="error=$event"
|
||||||
[jobName]="jobName"></app-settings-job-button>
|
[jobName]="jobName"></app-settings-job-button>
|
||||||
|
@ -904,9 +904,7 @@
|
|||||||
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">59</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160
|
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160 pixels.</target>
|
||||||
pixels.
|
|
||||||
</target>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
||||||
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
||||||
@ -2592,6 +2590,14 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Random Photo</target>
|
<target>Random Photo</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="bf5ce15a43de0abbce2193b3061a208eb35f7195" datatype="html">
|
||||||
|
<source>Job finished</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/frontend/app/ui/settings/scheduled-jobs.service.ts</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Job finished</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
||||||
<source>Thumbnail</source>
|
<source>Thumbnail</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
@ -904,9 +904,7 @@
|
|||||||
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">59</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160
|
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160 pixels.</target>
|
||||||
pixels.
|
|
||||||
</target>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
||||||
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
||||||
@ -2592,6 +2590,14 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Random Photo</target>
|
<target>Random Photo</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="bf5ce15a43de0abbce2193b3061a208eb35f7195" datatype="html">
|
||||||
|
<source>Job finished</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/frontend/app/ui/settings/scheduled-jobs.service.ts</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Job finished</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
||||||
<source>Thumbnail</source>
|
<source>Thumbnail</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
@ -2590,6 +2590,14 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Véletleg Fotó</target>
|
<target>Véletleg Fotó</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="bf5ce15a43de0abbce2193b3061a208eb35f7195" datatype="html">
|
||||||
|
<source>Job finished</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/frontend/app/ui/settings/scheduled-jobs.service.ts</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Feladat végzett</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
||||||
<source>Thumbnail</source>
|
<source>Thumbnail</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
@ -904,9 +904,7 @@
|
|||||||
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">59</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160
|
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160 pixels.</target>
|
||||||
pixels.
|
|
||||||
</target>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
||||||
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
||||||
@ -2592,6 +2590,14 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Random Photo</target>
|
<target>Random Photo</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="bf5ce15a43de0abbce2193b3061a208eb35f7195" datatype="html">
|
||||||
|
<source>Job finished</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/frontend/app/ui/settings/scheduled-jobs.service.ts</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Job finished</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
||||||
<source>Thumbnail</source>
|
<source>Thumbnail</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
@ -904,9 +904,7 @@
|
|||||||
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
<context context-type="sourcefile">app/ui/settings/thumbnail/thumbnail.settings.component.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">59</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160
|
<target>';' separated integers. If size is 240, that shorter side of the thumbnail will have 160 pixels.</target>
|
||||||
pixels.
|
|
||||||
</target>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
<trans-unit id="69149fe434cf1b0d9bafe5ead5d126101bb5162e" datatype="html">
|
||||||
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
<source>Video support uses ffmpeg. ffmpeg and ffprobe binaries need to be available in the PATH or
|
||||||
@ -2592,6 +2590,14 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<target>Random Photo</target>
|
<target>Random Photo</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="bf5ce15a43de0abbce2193b3061a208eb35f7195" datatype="html">
|
||||||
|
<source>Job finished</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">src/frontend/app/ui/settings/scheduled-jobs.service.ts</context>
|
||||||
|
<context context-type="linenumber">1</context>
|
||||||
|
</context-group>
|
||||||
|
<target>Job finished</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
<trans-unit id="45dda89cf029b7d7b457a8dff01dc4b9a6485816" datatype="html">
|
||||||
<source>Thumbnail</source>
|
<source>Thumbnail</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user