1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

improving video transcoding task:

- better progress
- transcoding interruption handling by creating .part file during transcoding
This commit is contained in:
Patrik J. Braun 2019-12-10 21:11:15 +01:00
parent cd9200fb6a
commit 17086bcb9e
2 changed files with 46 additions and 19 deletions

View File

@ -6,50 +6,66 @@ import {ProjectPath} from '../../../ProjectPath';
import {MediaDTO} from '../../../../common/entities/MediaDTO'; import {MediaDTO} from '../../../../common/entities/MediaDTO';
import {Logger} from '../../../Logger'; import {Logger} from '../../../Logger';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs';
import * as util from 'util';
import {DiskManager} from '../../DiskManger'; import {DiskManager} from '../../DiskManger';
import {VideoConverterMWs} from '../../../middlewares/VideoConverterMWs'; import {VideoConverterMWs} from '../../../middlewares/VideoConverterMWs';
import {VideoDTO} from '../../../../common/entities/VideoDTO';
const LOG_TAG = '[VideoConvertingTask]'; const LOG_TAG = '[VideoConvertingTask]';
const existsPr = util.promisify(fs.exists);
export class VideoConvertingTask extends Task { export class VideoConvertingTask extends Task {
public readonly Name = DefaultsTasks[DefaultsTasks['Video Converting']]; public readonly Name = DefaultsTasks[DefaultsTasks['Video Converting']];
public readonly ConfigTemplate: ConfigTemplateEntry[] = null; public readonly ConfigTemplate: ConfigTemplateEntry[] = null;
queue: (string | VideoDTO)[] = []; directoryQueue: string[] = [];
videoQueue: string[] = [];
public get Supported(): boolean { public get Supported(): boolean {
return Config.Client.Video.enabled === true; return Config.Client.Video.enabled === true;
} }
protected async init() { protected async init() {
this.queue.push('/'); this.directoryQueue = [];
this.videoQueue = [];
this.directoryQueue.push('/');
} }
protected async step(): Promise<TaskProgressDTO> { protected async step(): Promise<TaskProgressDTO> {
if (this.queue.length === 0) { if ((this.directoryQueue.length === 0 && this.videoQueue.length === 0)
|| this.running === false) {
if (global.gc) { if (global.gc) {
global.gc(); global.gc();
} }
return null; return null;
} }
if (this.running === false) {
return null; this.progress.left = this.videoQueue.length;
}
const entry = this.queue.shift();
this.progress.left = this.queue.length;
this.progress.progress++;
this.progress.time.current = Date.now(); this.progress.time.current = Date.now();
if (typeof entry === 'string') { if (this.directoryQueue.length > 0) {
const directory = entry; const directory = this.directoryQueue.shift();
this.progress.comment = 'scanning directory: ' + entry; this.progress.comment = 'scanning directory: ' + directory;
const scanned = await DiskManager.scanDirectory(directory, {noPhoto: true, noMetaFile: true}); const scanned = await DiskManager.scanDirectory(directory, {noPhoto: true, noMetaFile: true});
for (let i = 0; i < scanned.directories.length; i++) { for (let i = 0; i < scanned.directories.length; i++) {
this.queue.push(path.join(scanned.directories[i].path, scanned.directories[i].name)); this.directoryQueue.push(path.join(scanned.directories[i].path, scanned.directories[i].name));
} }
this.queue = this.queue.concat(<VideoDTO[]>scanned.media.filter(m => MediaDTO.isVideo(m)));
} else { for (let i = 0; i < scanned.media.length; ++i) {
const video: VideoDTO = entry; if (!MediaDTO.isVideo(scanned.media[i])) {
const videoPath = path.join(ProjectPath.ImageFolder, video.directory.path, video.directory.name, video.name); continue;
}
const videoPath = path.join(ProjectPath.ImageFolder,
scanned.media[i].directory.path,
scanned.media[i].directory.name,
scanned.media[i].name);
if (await existsPr(VideoConverterMWs.generateConvertedFileName(videoPath)) === false) {
this.videoQueue.push(videoPath);
}
}
} else if (this.videoQueue.length > 0) {
const videoPath = this.videoQueue.shift();
this.progress.progress++;
this.progress.comment = 'transcoding: ' + videoPath; this.progress.comment = 'transcoding: ' + videoPath;
try { try {
await VideoConverterMWs.convertVideo(videoPath); await VideoConverterMWs.convertVideo(videoPath);

View File

@ -1,8 +1,11 @@
import {Logger} from '../../Logger'; import {Logger} from '../../Logger';
import * as fs from 'fs';
import * as util from 'util';
import {FfmpegCommand} from 'fluent-ffmpeg'; import {FfmpegCommand} from 'fluent-ffmpeg';
import {FFmpegFactory} from '../FFmpegFactory'; import {FFmpegFactory} from '../FFmpegFactory';
import {ServerConfig} from '../../../common/config/private/IPrivateConfig'; import {ServerConfig} from '../../../common/config/private/IPrivateConfig';
const renamePr = util.promisify(fs.rename);
export interface VideoConverterInput { export interface VideoConverterInput {
videoPath: string; videoPath: string;
@ -20,7 +23,15 @@ export class VideoConverterWorker {
private static ffmpeg = FFmpegFactory.get(); private static ffmpeg = FFmpegFactory.get();
public static convert(input: VideoConverterInput): Promise<void> { public static async convert(input: VideoConverterInput): Promise<void> {
const origPath = input.output.path;
input.output.path = origPath + '.part';
await this._convert(input);
await renamePr(input.output.path, origPath);
}
private static _convert(input: VideoConverterInput): Promise<void> {
if (this.ffmpeg == null) { if (this.ffmpeg == null) {
this.ffmpeg = FFmpegFactory.get(); this.ffmpeg = FFmpegFactory.get();