diff --git a/README.md b/README.md index 1141c04..54929bd 100644 --- a/README.md +++ b/README.md @@ -178,3 +178,43 @@ export interface EncoderConfig { } } ``` + +#### Custom encoder + +The custom encoder enables the use of complex ffmpeg encoding/filter settings. It is assumed you know how to use ffmpeg when using the custom encoder. + +It takes in a string of ffmpeg args and the output file path, name and extension are automatically appended. + +```json +"encoders": [ + { + "postFix": "_custom-text-overlay", + "extension": ".mp4", + "custom": "-vf drawtext=\"fontfile=/Windows/Fonts/arial.ttf: text='Custom text overlay': fontcolor=white: fontsize=120: box=1: boxcolor=black: boxborderw=20: x=(w-text_w)/2: y=(h-text_h)/1.4\"" + } +] +``` + +The custom encoder supports handlebar style string replacement for customising file names. If any handlebars are detected the output filename will not be automatically appended. You will need to handle the output file yourself (e.g. `{{dir}}/{{name}}{{postFix}}_Custom-format{{extension}}`). + +```json +"encoders": [ + { + "postFix": "_Complex-Filter", + "custom": "-an -filter_complex \"[0]pad=iw*2:ih[int];[int][0]overlay=W/2:0[doublewidth];[doublewidth]scale=iw/2:ih/2[scaled];[scaled]split=3[s1][s2][s3];[s1]crop=iw/3:ih:0:0[one];[s2]crop=iw/3:ih:ow:0[two];[s3]crop=iw/3:ih:ow*2:0[three]\" -map \"[one]\" -q:v 1 -sws_flags bicubic \"{{dir}}/{{name}}{{postFix}}_{{date}}_one{{ext}}\" -map \"[two]\" -q:v 1 -sws_flags bicubic \"{{dir}}/{{name}}{{postFix}}_{{date}}_two{{ext}}\" -map \"[three]\" -q:v 1 -sws_flags bicubic \"{{dir}}/{{name}}{{postFix}}_{{date}}_three{{ext}}\"" + } +] +``` + +Available to use: + +```ts +postFix // EncoderConfig postfix +extension? // EncoderConfig extension +root // Input file root name +dir // Input file directory +base // Input file name with original extension +ext // Input file extension +name // Input file name +date // Date in ISO format (YYYY-MM-DD) +``` diff --git a/src/background/api.ts b/src/background/api.ts index 457cef0..21c728c 100644 --- a/src/background/api.ts +++ b/src/background/api.ts @@ -92,9 +92,9 @@ export class API { private _createRenderSteps(file: string, analysis: Analysis) { return this.config!.encoders.map((encoderConfig) => { - const p = path.parse(file) + const p: path.ParsedPath = path.parse(file) const output = `${p.dir}/${p.name}${encoderConfig.postFix}${encoderConfig.extension || p.ext}` - return new RenderWorkstep(file, output, encoderConfig, analysis) + return new RenderWorkstep(file, output, p, encoderConfig, analysis) }) } } diff --git a/src/background/renderer.ts b/src/background/renderer.ts index 4d5111b..c12b1fc 100644 --- a/src/background/renderer.ts +++ b/src/background/renderer.ts @@ -74,8 +74,35 @@ export class Renderer extends EventEmitter { const args = ['-y', '-i', `"${step.input}"`] if (step.encoderConfig.custom) { - args.push(step.encoderConfig.custom) - args.push(`"${step.output}"`) + let stringHasMatchData: boolean = false + // data available for use in handlebars + const customEncoderMatchData: { [key: string]: string } = { + ...step.outputParse, + postFix: step.encoderConfig.postFix, + extension: step.encoderConfig.extension + ? step.encoderConfig.extension + : step.outputParse.ext, + date: new Date().toISOString().slice(0, 10) + } + // replace handlebars with data + const customEncoderString = step.encoderConfig.custom.replace( + /\{\{([^}]+)\}\}/g, + (match: string) => { + match = match.slice(2, -2) + if (!customEncoderMatchData[match]) return '{{' + match + '}}' + stringHasMatchData = true + return customEncoderMatchData[match] + } + ) + + if (stringHasMatchData) { + // handlebars are used. do not append the output file name + args.push(customEncoderString) + } else { + // handlebars are not used. append the output file name + args.push(step.encoderConfig.custom) + args.push(`"${step.output}"`) + } return args } diff --git a/src/background/workStep.ts b/src/background/workStep.ts index 40b83d4..68a47c4 100644 --- a/src/background/workStep.ts +++ b/src/background/workStep.ts @@ -1,6 +1,7 @@ import { EventEmitter } from 'events' import { EncoderConfig } from '@/types/config' import { Analysis } from '@/types/mediaInfo' +import { ParsedPath } from 'path' export class WorkStep extends EventEmitter { input: string @@ -40,13 +41,21 @@ export class WorkStep extends EventEmitter { export class RenderWorkstep extends WorkStep { output: string + outputParse: ParsedPath encoderConfig: EncoderConfig analysis: Analysis - constructor(input: string, output: string, config: EncoderConfig, analysis: Analysis) { + constructor( + input: string, + output: string, + outputParse: ParsedPath, + config: EncoderConfig, + analysis: Analysis + ) { super(input) this.input = input this.output = output + this.outputParse = outputParse this.encoderConfig = config this.analysis = analysis }