Update flows

This commit is contained in:
HaveAGitGat 2023-08-26 17:53:07 +01:00
parent 658857fdf4
commit 25c4fab8d9
73 changed files with 4295 additions and 839 deletions

View file

@ -0,0 +1,115 @@
import { getContainer } from '../../../../FlowHelpers/1.0.0/fileUtils';
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Run Classic Filter Plugin',
description: 'Run one of Tdarr\'s classic plugins that has Operation: Filter',
style: {
borderColor: 'orange',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [
{
name: 'pluginSourceId',
type: 'string',
defaultValue: 'Community:Tdarr_Plugin_00td_filter_by_codec',
inputUI: {
type: 'dropdown',
options: [],
},
tooltip: 'Specify the classic plugin ID',
},
],
outputs: [
{
number: 1,
tooltip: 'File met conditions, would traditionally continue to next plugin in plugin stack',
},
{
number: 2,
tooltip: 'File did not meet conditions, would traditionally break out of plugin stack',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
const path = require('path');
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const pluginSourceId = String(args.inputs.pluginSourceId);
const parts = pluginSourceId.split(':');
const pluginSource = parts[0];
const pluginId = parts[1];
const relativePluginPath = `../../../../../${pluginSource}/${pluginId}.js`;
const absolutePath = path.resolve(__dirname, relativePluginPath);
let classicPlugin;
if (pluginSource === 'Community') {
classicPlugin = args.deps.importFresh(relativePluginPath);
} else {
// eslint-disable-next-line no-await-in-loop
const res = await args.deps.axiosMiddleware('api/v2/read-plugin', {
plugin: {
id: pluginId,
source: pluginSource,
},
});
classicPlugin = args.deps.requireFromString(res.pluginRaw, absolutePath);
}
if (classicPlugin.details().Operation !== 'Filter') {
throw new Error(
`${'This plugin is meant for classic plugins that have '
+ 'Operation: Filter. This classic plugin has Operation: '}${classicPlugin.details().Operation}`
+ 'Please use the Run Classic Transcode Flow Plugin plugin instead.'
,
);
}
const container = getContainer(args.inputFileObj._id);
const cacheFilePath = `${args.workDir}/tempFile_${new Date().getTime()}.${container}`;
const otherArguments = {
handbrakePath: args.handbrakePath,
ffmpegPath: args.ffmpegPath,
mkvpropeditPath: args.mkvpropeditPath,
originalLibraryFile: args.originalLibraryFile,
nodeHardwareType: args.nodeHardwareType,
pluginCycle: 0,
workerType: args.workerType,
version: args.config.version,
platform_arch_isdocker: args.platform_arch_isdocker,
cacheFilePath,
job: args.job,
};
const result = await classicPlugin.plugin(args.inputFileObj, args.librarySettings, args.inputs, otherArguments);
args.jobLog(JSON.stringify(result, null, 2));
const outputNumber = result.processFile ? 1 : 2;
return {
outputFileObj: args.inputFileObj,
outputNumber,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,237 @@
import { CLI } from '../../../../FlowHelpers/1.0.0/cliUtils';
import { getContainer } from '../../../../FlowHelpers/1.0.0/fileUtils';
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Run Classic Transcode Plugin',
description: 'Run one of Tdarr\'s classic plugins that has Operation: Transcode',
style: {
borderColor: 'green',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [
{
name: 'pluginSourceId',
type: 'string',
defaultValue: 'Community:Tdarr_Plugin_MC93_Migz1FFMPEG',
inputUI: {
type: 'dropdown',
options: [],
},
tooltip: 'Specify the classic plugin ID',
},
],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
const replaceContainer = (filePath:string, container:string): string => {
const parts = filePath.split('.');
parts[parts.length - 1] = container.split('.').join('');
return parts.join('.');
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
const path = require('path');
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const pluginSourceId = String(args.inputs.pluginSourceId);
const parts = pluginSourceId.split(':');
const pluginSource = parts[0];
const pluginId = parts[1];
const relativePluginPath = `../../../../../${pluginSource}/${pluginId}.js`;
const absolutePath = path.resolve(__dirname, relativePluginPath);
let classicPlugin;
if (pluginSource === 'Community') {
classicPlugin = args.deps.importFresh(relativePluginPath);
} else {
// eslint-disable-next-line no-await-in-loop
const res = await args.deps.axiosMiddleware('api/v2/read-plugin', {
plugin: {
id: pluginId,
source: pluginSource,
},
});
classicPlugin = args.deps.requireFromString(res.pluginRaw, absolutePath);
}
if (classicPlugin.details().Operation === 'Filter') {
throw new Error(
`${'This plugin is meant for classic plugins that have '
+ 'Operation: Transcode. This classic plugin has Operation: '}${classicPlugin.details().Operation}`
+ 'Please use the Run Classic Filter Flow Plugin plugin instead.'
,
);
}
const container = getContainer(args.inputFileObj._id);
let cacheFilePath = `${args.workDir}/tempFile_${new Date().getTime()}.${container}`;
const otherArguments = {
handbrakePath: args.handbrakePath,
ffmpegPath: args.ffmpegPath,
mkvpropeditPath: args.mkvpropeditPath,
originalLibraryFile: args.originalLibraryFile,
nodeHardwareType: args.nodeHardwareType,
pluginCycle: 0,
workerType: args.workerType,
version: args.config.version,
platform_arch_isdocker: args.platform_arch_isdocker,
cacheFilePath,
job: args.job,
};
const result = await classicPlugin.plugin(args.inputFileObj, args.librarySettings, args.inputs, otherArguments);
args.jobLog(JSON.stringify(result, null, 2));
// --- Backwards compatibility------------
if (result.handBrakeMode) {
result.handbrakeMode = result.handBrakeMode;
}
if (result.FFmpegMode) {
result.ffmpegMode = result.FFmpegMode;
}
//----------------------------------------
if (result.ffmpegMode) {
result.cliToUse = 'ffmpeg';
} else if (result.handbrakeMode) {
result.cliToUse = 'handbrake';
} else if (typeof result?.custom?.cliPath === 'string') {
const { cliPath } = result.custom;
if (cliPath.toLowerCase().includes('ffmpeg')) {
result.cliToUse = 'ffmpeg';
} else if (cliPath.toLowerCase().includes('handbrake')) {
result.cliToUse = 'handbrake';
} else if (cliPath.toLowerCase().includes('editready')) {
result.cliToUse = 'editready';
} else if (cliPath.toLowerCase().includes('av1an')) {
result.cliToUse = 'av1an';
}
}
result.workerLog = result.transcodeSettingsLog;
args.jobLog(JSON.stringify(result, null, 2));
if (result.error) {
throw new Error(`Plugin ${absolutePath} failed: ${result.error}`);
} if (result.processFile !== true) {
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};
}
const customArgs = result?.custom?.args;
const isCustomConfig = (Array.isArray(customArgs) && customArgs.length > 0)
|| (typeof customArgs === 'string' && customArgs.length > 0);
if (!isCustomConfig) {
cacheFilePath = replaceContainer(cacheFilePath, result.container);
} else {
cacheFilePath = result.custom.outputPath;
}
let presetSplit;
if (result.preset.includes('<io>')) {
presetSplit = result.preset.split('<io>');
} else {
presetSplit = result.preset.split(',');
}
let workerCommand: string[] = [];
let cliPath = '';
if (isCustomConfig) {
cliPath = result?.custom?.cliPath;
if (Array.isArray(customArgs)) {
workerCommand = customArgs;
} else {
workerCommand = [
...args.deps.parseArgsStringToArgv(customArgs, '', ''),
];
}
} else {
// working on windows with '` and spaces
// working on unix with '
switch (true) {
case result.cliToUse === 'handbrake':
workerCommand = [
'-i',
`${args.inputFileObj._id}`,
'-o',
`${cacheFilePath}`,
...args.deps.parseArgsStringToArgv(result.preset, '', ''),
];
cliPath = `${args.handbrakePath}`;
break;
case result.cliToUse === 'ffmpeg':
workerCommand = [
...args.deps.parseArgsStringToArgv(presetSplit[0], '', ''),
'-i',
`${args.inputFileObj._id}`,
...args.deps.parseArgsStringToArgv(presetSplit[1], '', ''),
`${cacheFilePath}`,
];
cliPath = `${args.ffmpegPath}`;
break;
default:
}
}
const cli = new CLI({
cli: cliPath,
spawnArgs: workerCommand,
spawnOpts: {},
jobLog: args.jobLog,
outputFilePath: cacheFilePath,
inputFileObj: args.inputFileObj,
logFullCliOutput: args.logFullCliOutput,
updateWorker: args.updateWorker,
});
const res = await cli.runCli();
if (res.cliExitCode !== 0) {
args.jobLog(`Running ${cliPath} failed`);
throw new Error(`Running ${cliPath} failed`);
}
args.logOutcome('tSuc');
return {
outputFileObj: {
_id: cacheFilePath,
},
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -10,7 +10,6 @@ const details = () :IpluginDetails => ({
description: 'Set 10 Bit Video',
style: {
borderColor: '#6efefc',
opacity: 0.5,
},
tags: 'video',
isStartPlugin: false,
@ -31,6 +30,13 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
for (let i = 0; i < args.variables.ffmpegCommand.streams.length; i += 1) {
const stream = args.variables.ffmpegCommand.streams[i];
if (stream.codec_type === 'video') {
stream.outputArgs.push('-pix_fmt:v:{outputTypeIndex}', 'p010le', '-profile:v:{outputTypeIndex}', 'main10');
}
}
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,

View file

@ -1,9 +1,11 @@
import {
IffmpegCommandStream,
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
import { CLI } from '../../../../FlowHelpers/1.0.0/utils';
import { CLI } from '../../../../FlowHelpers/1.0.0/cliUtils';
import { getContainer } from '../../../../FlowHelpers/1.0.0/fileUtils';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
@ -21,24 +23,41 @@ const details = (): IpluginDetails => ({
outputs: [
{
number: 1,
tooltip: 'File is 480p',
},
{
number: 2,
tooltip: 'File is 576p',
tooltip: 'Continue to next plugin',
},
],
});
const getEncoder = (codec: string) => {
switch (codec) {
case 'h264':
return 'libx264';
case 'hevc':
return 'libx265';
default:
return codec;
const getOuputStreamIndex = (streams: IffmpegCommandStream[], stream: IffmpegCommandStream): number => {
let index = -1;
for (let idx = 0; idx < streams.length; idx += 1) {
if (!stream.removed) {
index += 1;
}
if (streams[idx].index === stream.index) {
break;
}
}
return index;
};
const getOuputStreamTypeIndex = (streams: IffmpegCommandStream[], stream: IffmpegCommandStream): number => {
let index = -1;
for (let idx = 0; idx < streams.length; idx += 1) {
if (!stream.removed && streams[idx].codec_type === stream.codec_type) {
index += 1;
}
if (streams[idx].index === stream.index) {
break;
}
}
return index;
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -53,25 +72,48 @@ const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
cliArgs.push('-i');
cliArgs.push(args.inputFileObj._id);
let shouldProcess = false;
const inputArgs: string[] = [];
let { shouldProcess, streams } = args.variables.ffmpegCommand;
// @ts-expect-error type
args.variables.ffmpegCommand.streams.forEach((stream) => {
if (!stream.removed) {
cliArgs.push('-map');
cliArgs.push(`0:${stream.index}`);
cliArgs.push(`-c:${stream.index}`);
args.jobLog(JSON.stringify({ stream }));
if (args.inputs.forceProcess || stream.codec_name !== stream.targetCodec) {
shouldProcess = true;
cliArgs.push(getEncoder(stream.targetCodec));
} else {
cliArgs.push('copy');
}
streams = streams.filter((stream) => {
if (stream.removed) {
shouldProcess = true;
}
return !stream.removed;
});
if (getContainer(args.inputFileObj._id) !== args.variables.ffmpegCommand.container) {
shouldProcess = true;
}
for (let i = 0; i < streams.length; i += 1) {
const stream = streams[i];
stream.outputArgs = stream.outputArgs.map((arg) => {
if (arg.includes('{outputIndex}')) {
// eslint-disable-next-line no-param-reassign
arg = arg.replace('{outputIndex}', String(getOuputStreamIndex(streams, stream)));
}
if (arg.includes('{outputTypeIndex}')) {
// eslint-disable-next-line no-param-reassign
arg = arg.replace('{outputTypeIndex}', String(getOuputStreamTypeIndex(streams, stream)));
}
return arg;
});
cliArgs.push(...stream.mapArgs);
if (stream.outputArgs.length === 0) {
cliArgs.push(`-c:${getOuputStreamIndex(streams, stream)}`, 'copy');
} else {
cliArgs.push(...stream.outputArgs);
}
inputArgs.push(...stream.inputArgs);
}
if (!shouldProcess) {
args.jobLog('No need to process file, already as required');
return {
@ -81,12 +123,11 @@ const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
};
}
// @ts-expect-error type
const outputFilePath = `${args.workDir}/tempFile.${args.variables.ffmpegCommand.container}`;
cliArgs.push(outputFilePath);
const idx = cliArgs.indexOf('-i');
cliArgs.splice(idx, 0, ...inputArgs);
// @ts-expect-error type
args.deps.fsextra.ensureDirSync(args.workDir);
const outputFilePath = `${args.workDir}/tempFile_${new Date().getTime()}.${args.variables.ffmpegCommand.container}`;
cliArgs.push(outputFilePath);
args.jobLog('Processing file');
args.jobLog(JSON.stringify({
@ -94,6 +135,11 @@ const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
outputFilePath,
}));
args.updateWorker({
CLIType: args.ffmpegPath,
preset: cliArgs.join(' '),
});
const cli = new CLI({
cli: args.ffmpegPath,
spawnArgs: cliArgs,
@ -107,10 +153,6 @@ const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
const res = await cli.runCli();
if (!args.logFullCliOutput) {
args.jobLog(res.errorLogFull.slice(-1000).join(''));
}
if (res.cliExitCode !== 0) {
args.jobLog('Running FFmpeg failed');
throw new Error('FFmpeg failed');

View file

@ -33,7 +33,6 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
// @ts-expect-error type
args.variables.ffmpegCommand.streams.forEach((stream) => {
if (stream.codec_type === 'data') {
stream.removed = true;

View file

@ -32,7 +32,6 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
// @ts-expect-error type
args.variables.ffmpegCommand.streams.forEach((stream) => {
if (stream.codec_type === 'subtitle') {
stream.removed = true;

View file

@ -1,22 +1,93 @@
import {
IffmpegCommandStream,
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
import { Istreams } from '../../../../FlowHelpers/1.0.0/interfaces/synced/IFileObject';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = () :IpluginDetails => ({
name: 'Set Video Bitrate',
description: 'Set Video Bitrate',
const details = (): IpluginDetails => ({
name: 'Reorder Streams',
description: 'Reorder Streams',
style: {
borderColor: '#6efefc',
opacity: 0.5,
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [],
inputs: [
{
name: 'processOrder',
type: 'string',
defaultValue: 'codecs,channels,languages,streamTypes',
inputUI: {
type: 'text',
},
tooltip:
`Specify the process order.
For example, if 'languages' is first, the streams will be ordered based on that first.
So put the most important properties last.
The default order is suitable for most people.
\\nExample:\\n
codecs,channels,languages,streamTypes
`,
},
{
name: 'languages',
type: 'string',
defaultValue: '',
inputUI: {
type: 'text',
},
tooltip:
`Specify the language tags order, separated by commas. Leave blank to disable.
\\nExample:\\n
eng,fre
`,
},
{
name: 'channels',
type: 'string',
defaultValue: '7.1,5.1,2,1',
inputUI: {
type: 'text',
},
tooltip:
`Specify the channels order, separated by commas. Leave blank to disable.
\\nExample:\\n
7.1,5.1,2,1`,
},
{
name: 'codecs',
type: 'string',
defaultValue: '',
inputUI: {
type: 'text',
},
tooltip:
`Specify the codec order, separated by commas. Leave blank to disable.
\\nExample:\\n
aac,ac3`,
},
{
name: 'streamTypes',
type: 'string',
defaultValue: 'video,audio,subtitle',
inputUI: {
type: 'text',
},
tooltip:
`Specify the streamTypes order, separated by commas. Leave blank to disable.
\\nExample:\\n
video,audio,subtitle
`,
},
],
outputs: [
{
number: 1,
@ -26,11 +97,125 @@ const details = () :IpluginDetails => ({
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
let streams: IffmpegCommandStream[] = JSON.parse(JSON.stringify(args.variables.ffmpegCommand.streams));
const originalStreams = JSON.stringify(streams);
streams.forEach((stream, index) => {
// eslint-disable-next-line no-param-reassign
stream.typeIndex = index;
});
const sortStreams = (sortType: {
inputs: string,
getValue: (stream: Istreams) => string,
}) => {
const items = sortType.inputs.split(',');
items.reverse();
for (let i = 0; i < items.length; i += 1) {
const matchedStreams = [];
for (let j = 0; j < streams.length; j += 1) {
if (String(sortType.getValue(streams[j])) === String(items[i])) {
if (
streams[j].codec_long_name
&& (
streams[j].codec_long_name.includes('image')
|| streams[j].codec_name.includes('png')
)
) {
// do nothing, ffmpeg bug, doesn't move image streams
} else {
matchedStreams.push(streams[j]);
streams.splice(j, 1);
j -= 1;
}
}
}
streams = matchedStreams.concat(streams);
}
};
const processOrder = String(args.inputs.processOrder);
const {
languages, codecs, channels, streamTypes,
} = args.inputs;
const sortTypes:{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any,
} = {
languages: {
getValue: (stream: Istreams) => {
if (stream?.tags?.language) {
return stream.tags.language;
}
return '';
},
inputs: languages,
},
codecs: {
getValue: (stream: Istreams) => {
try {
return stream.codec_name;
} catch (err) {
// err
}
return '';
},
inputs: codecs,
},
channels: {
getValue: (stream: Istreams) => {
const chanMap:{
[key: number]: string
} = {
8: '7.1',
6: '5.1',
2: '2',
1: '1',
};
if (stream?.channels && chanMap[stream.channels]) {
return chanMap[stream.channels];
}
return '';
},
inputs: channels,
},
streamTypes: {
getValue: (stream:Istreams) => {
if (stream.codec_type) {
return stream.codec_type;
}
return '';
},
inputs: streamTypes,
},
};
const processOrderArr = processOrder.split(',');
for (let k = 0; k < processOrderArr.length; k += 1) {
if (sortTypes[processOrderArr[k]] && sortTypes[processOrderArr[k]].inputs) {
sortStreams(sortTypes[processOrderArr[k]]);
}
}
if (JSON.stringify(streams) !== originalStreams) {
// eslint-disable-next-line no-param-reassign
args.variables.ffmpegCommand.shouldProcess = true;
// eslint-disable-next-line no-param-reassign
args.variables.ffmpegCommand.streams = streams;
}
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,

View file

@ -46,8 +46,7 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
// @ts-expect-error type
args.variables.ffmpegCommand.container = args.inputs.container;
args.variables.ffmpegCommand.container = String(args.inputs.container);
return {
outputFileObj: args.inputFileObj,

View file

@ -0,0 +1,103 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = () :IpluginDetails => ({
name: 'Set Video Resolution',
description: 'Change video resolution',
style: {
borderColor: '#6efefc',
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [
{
name: 'targetResolution',
type: 'string',
defaultValue: '1080p',
inputUI: {
type: 'dropdown',
options: [
'480p',
'720p',
'1080p',
'1440p',
'4KUHD',
],
},
tooltip: 'Specify the codec to use',
},
],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
const getVfScale = (
targetResolution: string,
):string[] => {
switch (targetResolution) {
case '480p':
return ['-vf', 'scale=720:-2'];
case '576p':
return ['-vf', 'scale=720:-2'];
case '720p':
return ['-vf', 'scale=1280:-2'];
case '1080p':
return ['-vf', 'scale=1920:-2'];
case '1440p':
return ['-vf', 'scale=2560:-2'];
case '4KUHD':
return ['-vf', 'scale=3840:-2'];
default:
return ['-vf', 'scale=1920:-2'];
}
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
for (let i = 0; i < args.variables.ffmpegCommand.streams.length; i += 1) {
const stream = args.variables.ffmpegCommand.streams[i];
if (stream.codec_type === 'video') {
const targetResolution = String(args.inputs.targetResolution);
if (
targetResolution !== args.inputFileObj.video_resolution
) {
// eslint-disable-next-line no-param-reassign
args.variables.ffmpegCommand.shouldProcess = true;
const scaleArgs = getVfScale(targetResolution);
stream.outputArgs.push(...scaleArgs);
}
}
}
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -3,20 +3,30 @@ import {
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
import { getFfType } from '../../../../FlowHelpers/1.0.0/fileUtils';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = () :IpluginDetails => ({
name: 'Reorder Streams',
description: 'Reorder Streams',
name: 'Set Video Bitrate',
description: 'Set Video Bitrate',
style: {
borderColor: '#6efefc',
opacity: 0.5,
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [],
inputs: [
{
name: 'bitrate',
type: 'string',
defaultValue: '5000',
inputUI: {
type: 'text',
},
tooltip: 'Specify bitrate in kbps',
},
],
outputs: [
{
number: 1,
@ -31,6 +41,13 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
args.variables.ffmpegCommand.streams.forEach((stream) => {
if (stream.codec_type === 'video') {
const ffType = getFfType(stream.codec_type);
stream.outputArgs.push(`-b:${ffType}:{outputTypeIndex}`, `${String(args.inputs.bitrate)}k`);
}
});
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,

View file

@ -1,5 +1,6 @@
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
import { getEncoder } from '../../../../FlowHelpers/1.0.0/hardwareUtils';
import {
IpluginDetails,
IpluginInputArgs,
@ -7,7 +8,7 @@ import {
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint-disable no-param-reassign */
const details = () :IpluginDetails => ({
const details = (): IpluginDetails => ({
name: 'Set Video Encoder',
description: 'Set the video encoder for all streams',
style: {
@ -19,7 +20,7 @@ const details = () :IpluginDetails => ({
icon: '',
inputs: [
{
name: 'targetCodec',
name: 'outputCodec',
type: 'string',
defaultValue: 'hevc',
inputUI: {
@ -33,6 +34,61 @@ const details = () :IpluginDetails => ({
},
tooltip: 'Specify the codec to use',
},
{
name: 'ffmpegPreset',
type: 'string',
defaultValue: 'fast',
inputUI: {
type: 'dropdown',
options: [
'veryslow',
'slower',
'slow',
'medium',
'fast',
'faster',
'veryfast',
'superfast',
'ultrafast',
],
},
tooltip: 'Specify the codec to use',
},
{
name: 'ffmpegQuality',
type: 'number',
defaultValue: '25',
inputUI: {
type: 'text',
},
tooltip: 'Specify the codec to use',
},
{
name: 'hardwareEncoding',
type: 'boolean',
defaultValue: 'true',
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: 'Specify whether to use hardware encoding if available',
},
{
name: 'hardwareDecoding',
type: 'boolean',
defaultValue: 'true',
inputUI: {
type: 'dropdown',
options: [
'false',
'true',
],
},
tooltip: 'Specify whether to use hardware decoding if available',
},
{
name: 'forceEncoding',
type: 'boolean',
@ -56,19 +112,59 @@ const details = () :IpluginDetails => ({
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
// @ts-expect-error type
args.variables.ffmpegCommand.streams.forEach((stream) => {
const hardwareDecoding = args.inputs.hardwareDecoding === true;
args.variables.ffmpegCommand.hardwareDecoding = hardwareDecoding;
for (let i = 0; i < args.variables.ffmpegCommand.streams.length; i += 1) {
const stream = args.variables.ffmpegCommand.streams[i];
if (stream.codec_type === 'video') {
// @ts-expect-error type
stream.targetCodec = args.inputs.targetCodec;
stream.forceEncoding = args.inputs.forceEncoding;
const targetCodec = String(args.inputs.outputCodec);
const ffmpegPreset = String(args.inputs.ffmpegPreset);
const ffmpegQuality = String(args.inputs.ffmpegQuality);
const forceEncoding = args.inputs.forceEncoding === true;
const hardwarEncoding = args.inputs.hardwareEncoding === true;
if (
forceEncoding
|| stream.codec_name !== targetCodec
) {
args.variables.ffmpegCommand.shouldProcess = true;
// eslint-disable-next-line no-await-in-loop
const encoderProperties = await getEncoder({
targetCodec,
hardwareEncoding: hardwarEncoding,
args,
});
stream.outputArgs.push('-c:{outputIndex}', encoderProperties.encoder);
if (encoderProperties.isGpu) {
stream.outputArgs.push('-qp', ffmpegQuality);
} else {
stream.outputArgs.push('-crf', ffmpegQuality);
}
if (ffmpegPreset) {
stream.outputArgs.push('-preset', ffmpegPreset);
}
if (hardwareDecoding) {
stream.inputArgs.push(...encoderProperties.inputArgs);
}
if (encoderProperties.outputArgs) {
stream.outputArgs.push(...encoderProperties.outputArgs);
}
}
}
});
}
return {
outputFileObj: args.inputFileObj,

View file

@ -42,10 +42,18 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
streams: JSON.parse(JSON.stringify(args.inputFileObj.ffProbeData.streams)).map((stream:Istreams) => ({
...stream,
removed: false,
targetCodec: stream.codec_name,
args: [],
mapArgs: [
'-map',
`0:${stream.index}`,
],
inputArgs: [],
outputArgs: [],
})),
container,
hardwareDecoding: false,
shouldProcess: false,
overallInputArguments: [],
overallOuputArguments: [],
};
args.variables.ffmpegCommand = ffmpegCommand;

View file

@ -0,0 +1,68 @@
import { getContainer } from '../../../../FlowHelpers/1.0.0/fileUtils';
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Check File Extension',
description: 'Check file extension',
style: {
borderColor: 'orange',
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [
{
name: 'extensions',
type: 'string',
defaultValue: 'mkv,mp4',
inputUI: {
type: 'text',
},
tooltip: 'A comma separated list of extensions to check',
},
],
outputs: [
{
number: 1,
tooltip: 'File is one of extensions',
},
{
number: 2,
tooltip: 'File is not one of extensions',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const extensions = String(args.inputs.extensions);
const extensionArray = extensions.trim().split(',');
const extension = getContainer(args.inputFileObj._id);
let extensionMatch = false;
if (extensionArray.includes(extension)) {
extensionMatch = true;
}
return {
outputFileObj: args.inputFileObj,
outputNumber: extensionMatch ? 1 : 2,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,100 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Check File Size',
description: 'Check size of working file',
style: {
borderColor: 'orange',
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [
{
name: 'unit',
type: 'string',
defaultValue: 'GB',
inputUI: {
type: 'dropdown',
options: [
'B',
'KB',
'MB',
'GB',
],
},
tooltip: 'Specify the unit to use',
},
{
name: 'greaterThan',
type: 'number',
defaultValue: '0',
inputUI: {
type: 'text',
},
tooltip: 'Specify lower bound',
},
{
name: 'lessThan',
type: 'number',
defaultValue: '10000',
inputUI: {
type: 'text',
},
tooltip: 'Specify upper bound',
},
],
outputs: [
{
number: 1,
tooltip: 'File within range',
},
{
number: 2,
tooltip: 'File not within range',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
let isWithinRange = false;
let greaterThanBytes = Number(args.inputs.greaterThan);
let lessThanBytes = Number(args.inputs.lessThan);
const fileSizeBytes = args.inputFileObj.file_size * 1000 * 1000;
if (args.inputs.unit === 'KB') {
greaterThanBytes *= 1000;
lessThanBytes *= 1000;
} else if (args.inputs.unit === 'MB') {
greaterThanBytes *= 1000000;
lessThanBytes *= 1000000;
} else if (args.inputs.unit === 'GB') {
greaterThanBytes *= 1000000000;
lessThanBytes *= 1000000000;
}
if (fileSizeBytes >= greaterThanBytes && fileSizeBytes <= lessThanBytes) {
isWithinRange = true;
}
return {
outputFileObj: args.inputFileObj,
outputNumber: isWithinRange ? 1 : 2,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,62 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Compare File Size',
description: 'Compare file size of working file compared to original file',
style: {
borderColor: 'orange',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [],
outputs: [
{
number: 1,
tooltip: 'Working file is smaller than original file',
},
{
number: 2,
tooltip: 'Working file is same size as original file',
},
{
number: 3,
tooltip: 'Working file is larger than original file',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
let outputNumber = 1;
if (args.inputFileObj.file_size < args.originalLibraryFile.file_size) {
outputNumber = 1;
} else if (args.inputFileObj.file_size === args.originalLibraryFile.file_size) {
outputNumber = 2;
} else if (args.inputFileObj.file_size > args.originalLibraryFile.file_size) {
outputNumber = 3;
}
return {
outputFileObj: args.inputFileObj,
outputNumber,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -1,3 +1,5 @@
import { promises as fs } from 'fs';
import { getContainer, getFileName } from '../../../../FlowHelpers/1.0.0/fileUtils';
import {
IpluginDetails,
IpluginInputArgs,
@ -5,12 +7,11 @@ import {
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
const details = (): IpluginDetails => ({
name: 'Copy to Directory',
description: 'Copy the working file to a directory',
style: {
borderColor: 'green',
opacity: 0.5,
},
tags: '',
@ -19,19 +20,26 @@ const details = ():IpluginDetails => ({
icon: 'faArrowRight',
inputs: [
{
name: 'target_codec',
name: 'outputDirectory',
type: 'string',
defaultValue: 'hevc',
defaultValue: '',
inputUI: {
type: 'dropdown',
type: 'text',
},
tooltip: 'Specify ouput directory',
},
{
name: 'makeWorkingFile',
type: 'boolean',
defaultValue: 'false',
inputUI: {
type: 'text',
options: [
'hevc',
// 'vp9',
'h264',
// 'vp8',
'false',
'true',
],
},
tooltip: 'Specify the codec to use',
tooltip: 'Make the copied file the working file',
},
],
outputs: [
@ -43,13 +51,28 @@ const details = ():IpluginDetails => ({
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const plugin = async (args: IpluginInputArgs): Promise<IpluginOutputArgs> => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const originalFileName = getFileName(args.originalLibraryFile._id);
const newContainer = getContainer(args.inputFileObj._id);
const outputPath = `${args.inputs.outputDirectory}/${originalFileName}.${newContainer}`;
await fs.copyFile(args.inputFileObj._id, outputPath);
let workingFile = args.inputFileObj._id;
if (args.inputs.makeWorkingFile) {
workingFile = outputPath;
}
return {
outputFileObj: args.inputFileObj,
outputFileObj: {
_id: workingFile,
},
outputNumber: 1,
variables: args.variables,
};

View file

@ -10,6 +10,7 @@ const details = ():IpluginDetails => ({
description: 'Move working file to directory.',
style: {
borderColor: 'green',
opacity: 0.5,
},
tags: '',
isStartPlugin: false,

View file

@ -1,3 +1,5 @@
import { promises as fs } from 'fs';
import { getContainer, getFileName } from '../../../../FlowHelpers/1.0.0/fileUtils';
import {
IpluginDetails,
IpluginInputArgs,
@ -10,14 +12,23 @@ const details = ():IpluginDetails => ({
description: 'Move working file to directory.',
style: {
borderColor: 'green',
opacity: 0.5,
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faArrowRight',
inputs: [],
inputs: [
{
name: 'outputDirectory',
type: 'string',
defaultValue: '',
inputUI: {
type: 'text',
},
tooltip: 'Specify ouput directory',
},
],
outputs: [
{
number: 1,
@ -27,13 +38,22 @@ const details = ():IpluginDetails => ({
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const plugin = async (args:IpluginInputArgs):Promise<IpluginOutputArgs> => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const originalFileName = getFileName(args.originalLibraryFile._id);
const newContainer = getContainer(args.inputFileObj._id);
const outputPath = `${args.inputs.outputDirectory}/${originalFileName}.${newContainer}`;
await fs.rename(args.inputFileObj._id, outputPath);
return {
outputFileObj: args.inputFileObj,
outputFileObj: {
_id: outputPath,
},
outputNumber: 1,
variables: args.variables,
};

View file

@ -7,7 +7,7 @@ import {
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Replace Original File',
description: 'Replace the origial file',
description: 'Replace the original file',
style: {
borderColor: 'green',
},
@ -15,23 +15,7 @@ const details = ():IpluginDetails => ({
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faArrowRight',
inputs: [
{
name: 'target_codec',
type: 'string',
defaultValue: 'hevc',
inputUI: {
type: 'dropdown',
options: [
'hevc',
// 'vp9',
'h264',
// 'vp8',
],
},
tooltip: 'Specify the codec to use',
},
],
inputs: [],
outputs: [
{
number: 1,

View file

@ -0,0 +1,44 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Set Original File',
description: 'Set the working file to the original file',
style: {
borderColor: 'green',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
return {
outputFileObj: {
_id: args.originalLibraryFile._id,
},
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -5,17 +5,17 @@ import {
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = () :IpluginDetails => ({
name: 'Set Video Scale',
description: 'Change video scale',
const details = ():IpluginDetails => ({
name: 'Unpack File',
description: 'Unpack a file',
style: {
borderColor: '#6efefc',
borderColor: 'green',
opacity: 0.5,
},
tags: 'video',
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
icon: 'faArrowRight',
inputs: [],
outputs: [
{

View file

@ -0,0 +1,135 @@
import { promises as fs } from 'fs';
import { CLI } from '../../../../FlowHelpers/1.0.0/cliUtils';
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'HandBrake Custom Arguments',
description: 'HandBrake Custom Arguments',
style: {
borderColor: 'green',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [
{
name: 'customArguments',
type: 'string',
defaultValue: '-Z "Fast 1080p30" --all-subtitles',
inputUI: {
type: 'text',
},
tooltip: 'Specify HandBrake arguments',
},
{
name: 'jsonPreset',
type: 'string',
defaultValue: '',
inputUI: {
type: 'text',
},
tooltip: 'Paste a HandBrake JSON preset here. Leave blank to disable.',
},
{
name: 'container',
type: 'string',
defaultValue: 'mkv',
inputUI: {
type: 'dropdown',
options: [
'mkv',
'mp4',
'm4v',
'avi',
'mov',
'mpg',
'mpeg',
],
},
tooltip: 'Specify HandBrake arguments',
},
],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args:IpluginInputArgs):Promise<IpluginOutputArgs> => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const customArguments = String(args.inputs.customArguments);
const container = String(args.inputs.container);
const outputFilePath = `${args.workDir}/tempFile_${new Date().getTime()}.${container}`;
const presetString = String(args.inputs.jsonPreset);
const cliArgs = [
'-i',
`${args.inputFileObj._id}`,
'-o',
`${outputFilePath}`,
];
const presetPath = `${args.workDir}/preset.json`;
if (presetString.trim() !== '') {
const preset = JSON.parse(presetString);
await fs.writeFile(presetPath, JSON.stringify(preset, null, 2));
cliArgs.push('--preset-import-file');
cliArgs.push(presetPath);
cliArgs.push('-Z');
cliArgs.push(preset.PresetList[0].PresetName);
} else {
cliArgs.push(...args.deps.parseArgsStringToArgv(customArguments, '', ''));
}
args.updateWorker({
CLIType: args.handbrakePath,
preset: cliArgs.join(' '),
});
const cli = new CLI({
cli: args.handbrakePath,
spawnArgs: cliArgs,
spawnOpts: {},
jobLog: args.jobLog,
outputFilePath,
inputFileObj: args.inputFileObj,
logFullCliOutput: args.logFullCliOutput,
updateWorker: args.updateWorker,
});
const res = await cli.runCli();
if (res.cliExitCode !== 0) {
args.jobLog('Running HandBrake failed');
throw new Error('Running HandBrake failed');
}
args.logOutcome('tSuc');
return {
outputFileObj: {
_id: outputFilePath,
},
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -7,7 +7,7 @@ import {
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Input File',
description: 'Transcode a video file using ffmpeg. GPU transcoding will be used if possible.',
description: 'Start the flow with an input file',
style: {
borderColor: 'pink',
},

View file

@ -0,0 +1,39 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Fail Flow',
description: 'Force the flow to fail and be move to the error table',
style: {
borderColor: 'red',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faExclamationTriangle',
inputs: [],
outputs: [],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
throw new Error('Forcing flow to fail!');
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,38 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Go To Flow',
description: 'Go to a different flow',
style: {
borderColor: 'red',
opacity: 0.5,
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faArrowRight',
inputs: [],
outputs: [],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,67 @@
import { CLI } from '../../../../FlowHelpers/1.0.0/cliUtils';
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Run MKVPropEdit',
description: 'Run MKVPropEdit on a file to update metadata which'
+ ' FFmpeg doesn\'t typically update such as stream bitrate.',
style: {
borderColor: 'green',
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: '',
inputs: [],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args:IpluginInputArgs):Promise<IpluginOutputArgs> => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const cliArgs = [
'--add-track-statistics-tags',
args.inputFileObj._id,
];
const cli = new CLI({
cli: args.mkvpropeditPath,
spawnArgs: cliArgs,
spawnOpts: {},
jobLog: args.jobLog,
outputFilePath: '',
inputFileObj: args.inputFileObj,
logFullCliOutput: args.logFullCliOutput,
updateWorker: args.updateWorker,
});
const res = await cli.runCli();
if (res.cliExitCode !== 0) {
args.jobLog('Running MKVPropEdit failed');
throw new Error('Running MKVPropEdit failed');
}
return {
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -1,94 +0,0 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = ():IpluginDetails => ({
name: 'Unpack File',
description: 'Unpack a file',
style: {
borderColor: 'green',
opacity: 0.5,
},
tags: '',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faArrowRight',
inputs: [
{
name: 'target_codec',
type: 'string',
defaultValue: 'hevc',
inputUI: {
type: 'dropdown',
options: [
'hevc',
// 'vp9',
'h264',
// 'vp8',
],
},
tooltip: 'Specify the codec to use',
},
],
outputs: [
{
number: 1,
tooltip: 'Continue to next plugin',
},
],
});
const getNewPath = (originalPath:string, tempPath:string) => {
const tempPathParts = tempPath.split('.');
const container = tempPathParts[tempPathParts.length - 1];
const originalPathParts = originalPath.split('.');
originalPathParts[originalPathParts.length - 1] = container;
return originalPathParts.join('.');
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args:IpluginInputArgs):Promise<IpluginOutputArgs> => {
const fs = require('fs');
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const currentPath = args.inputFileObj._id;
const newPath = getNewPath(args.originalLibraryFile._id, currentPath);
const newPathTmp = `${newPath}.tmp`;
args.jobLog(JSON.stringify({
currentPath,
newPath,
newPathTmp,
}));
await new Promise((resolve) => setTimeout(resolve, 2000));
fs.renameSync(currentPath, newPathTmp);
if (fs.existsSync(newPath)) {
fs.unlinkSync(newPath);
}
await new Promise((resolve) => setTimeout(resolve, 2000));
fs.renameSync(newPathTmp, newPath);
return {
outputFileObj: {
_id: newPath,
},
outputNumber: 1,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -16,23 +16,7 @@ const details = ():IpluginDetails => ({
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faArrowRight',
inputs: [
{
name: 'target_codec',
type: 'string',
defaultValue: 'hevc',
inputUI: {
type: 'dropdown',
options: [
'hevc',
// 'vp9',
'h264',
// 'vp8',
],
},
tooltip: 'Specify the codec to use',
},
],
inputs: [],
outputs: [
{
number: 1,
@ -41,49 +25,14 @@ const details = ():IpluginDetails => ({
],
});
const getNewPath = (originalPath:string, tempPath:string) => {
const tempPathParts = tempPath.split('.');
const container = tempPathParts[tempPathParts.length - 1];
const originalPathParts = originalPath.split('.');
originalPathParts[originalPathParts.length - 1] = container;
return originalPathParts.join('.');
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = async (args:IpluginInputArgs):Promise<IpluginOutputArgs> => {
const fs = require('fs');
const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
const currentPath = args.inputFileObj._id;
const newPath = getNewPath(args.originalLibraryFile._id, currentPath);
const newPathTmp = `${newPath}.tmp`;
args.jobLog(JSON.stringify({
currentPath,
newPath,
newPathTmp,
}));
await new Promise((resolve) => setTimeout(resolve, 2000));
fs.renameSync(currentPath, newPathTmp);
if (fs.existsSync(newPath)) {
fs.unlinkSync(newPath);
}
await new Promise((resolve) => setTimeout(resolve, 2000));
fs.renameSync(newPathTmp, newPath);
return {
outputFileObj: {
_id: newPath,
},
outputFileObj: args.inputFileObj,
outputNumber: 1,
variables: args.variables,
};

View file

@ -0,0 +1,55 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Check 10 Bit Video',
description: 'Check if a file is 10 bit video',
style: {
borderColor: 'orange',
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [],
outputs: [
{
number: 1,
tooltip: 'File is 10 bit video',
},
{
number: 2,
tooltip: 'File is not 10 bit video',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
let is10Bit = false;
for (let i = 0; i < args.variables.ffmpegCommand.streams.length; i += 1) {
const stream = args.variables.ffmpegCommand.streams[i];
if (stream.codec_type === 'video' && stream.bits_per_raw_sample === 10) {
is10Bit = true;
}
}
return {
outputFileObj: args.inputFileObj,
outputNumber: is10Bit ? 1 : 2,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -0,0 +1,102 @@
import {
IpluginDetails,
IpluginInputArgs,
IpluginOutputArgs,
} from '../../../../FlowHelpers/1.0.0/interfaces/interfaces';
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
const details = (): IpluginDetails => ({
name: 'Check Video Bitrate',
description: 'Check if video bitrate is within a specific range',
style: {
borderColor: 'orange',
},
tags: 'video',
isStartPlugin: false,
sidebarPosition: -1,
icon: 'faQuestion',
inputs: [
{
name: 'unit',
type: 'string',
defaultValue: 'kbps',
inputUI: {
type: 'dropdown',
options: [
'bps',
'kbps',
'mbps',
],
},
tooltip: 'Specify the unit to use',
},
{
name: 'greaterThan',
type: 'number',
defaultValue: '0',
inputUI: {
type: 'text',
},
tooltip: 'Specify lower bound',
},
{
name: 'lessThan',
type: 'number',
defaultValue: '10000',
inputUI: {
type: 'text',
},
tooltip: 'Specify upper bound',
},
],
outputs: [
{
number: 1,
tooltip: 'File within range',
},
{
number: 2,
tooltip: 'File not within range',
},
],
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const plugin = (args: IpluginInputArgs): IpluginOutputArgs => {
const lib = require('../../../../../methods/lib')();
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign
args.inputs = lib.loadDefaultValues(args.inputs, details);
let isWithinRange = false;
let greaterThanBits = Number(args.inputs.greaterThan);
let lessThanBits = Number(args.inputs.lessThan);
if (args.inputs.unit === 'kbps') {
greaterThanBits *= 1000;
lessThanBits *= 1000;
} else if (args.inputs.unit === 'mbps') {
greaterThanBits *= 1000000;
lessThanBits *= 1000000;
}
if (args.inputFileObj?.mediaInfo?.track) {
args.inputFileObj.mediaInfo.track.forEach((stream) => {
if (stream['@type'] === 'video') {
if (stream.BitRate >= greaterThanBits && stream.BitRate <= lessThanBits) {
isWithinRange = true;
}
}
});
}
return {
outputFileObj: args.inputFileObj,
outputNumber: isWithinRange ? 1 : 2,
variables: args.variables,
};
};
export {
details,
plugin,
};

View file

@ -52,12 +52,13 @@ const plugin = (args:IpluginInputArgs):IpluginOutputArgs => {
let hasCodec = false;
// @ts-expect-error type
args.inputFileObj.ffProbeData.streams.forEach((stream) => {
if (stream.codec_type === 'video' && stream.codec_name === args.inputs.codec) {
hasCodec = true;
}
});
if (args.inputFileObj.ffProbeData.streams) {
args.inputFileObj.ffProbeData.streams.forEach((stream) => {
if (stream.codec_type === 'video' && stream.codec_name === args.inputs.codec) {
hasCodec = true;
}
});
}
return {
outputFileObj: args.inputFileObj,