feat: Tdarr Local Flow Plugin Suite v1.0
7 atomic plugins for automated x265 transcoding pipeline: - utility/mediaAnalyzerGOP : GOP calc, FPS detection, film/series/anime routing - utility/setAnimationFlag : manual animation flag override - utility/extractChaptersXml : mkvextract chapters to XML - audio/audioSelectorClamping : codec scoring, clamped Opus bitrates, 2 outputs - audio/backupSourceAudio : lossless DTS/TrueHD ITA backup (-c:a copy) - subtitles/extractSubtitlesAndOcr : SRT extract + SubtitleEdit OCR for PGS - video/transcode2PassX265 : 2-pass x265, Lanczos 1080p bound, Opus mux Test suite: 34 unit tests + 3 integration tests (FFmpeg real files) FlowHelpers mock for local testing included Docs: integration-guide.md with canvas wiring and deploy instructions
This commit is contained in:
commit
c2074be826
19 files changed
+2134
No files matched your search
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
const details = () => ({
|
||||
name: 'Set Animation Flag',
|
||||
description:
|
||||
'Forces isAnimation=true and x265Tune=animation in flow variables. '
|
||||
+ 'Use when a file is animation but was not detected automatically '
|
||||
+ 'by the animeSeries list in mediaAnalyzerGOP. '
|
||||
+ 'Optionally recalculates video bitrate targets.',
|
||||
style: { borderColor: '#FF9800' },
|
||||
tags: 'utility,animation',
|
||||
isStartPlugin: false,
|
||||
pType: '',
|
||||
requiresVersion: '2.11.01',
|
||||
sidebarPosition: -1,
|
||||
icon: 'faMagic',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Anime HD Bitrate (kbps, >=720p)',
|
||||
name: 'animeBitrateHd',
|
||||
type: 'string',
|
||||
defaultValue: '2000',
|
||||
inputUI: { type: 'text' },
|
||||
tooltip: 'Target bitrate for anime >=720p. Leave blank to skip recalculation.',
|
||||
},
|
||||
{
|
||||
label: 'Anime SD Bitrate (kbps, <720p)',
|
||||
name: 'animeBitrateSd',
|
||||
type: 'string',
|
||||
defaultValue: '1000',
|
||||
inputUI: { type: 'text' },
|
||||
tooltip: 'Target bitrate for anime <720p.',
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ number: 1, tooltip: 'Continue with animation flag set' },
|
||||
],
|
||||
});
|
||||
|
||||
const plugin = async (args) => {
|
||||
const { jobLog, inputFileObj, variables } = args;
|
||||
jobLog('[setAnimationFlag] Forcing isAnimation=true\n');
|
||||
|
||||
variables.isAnimation = 'true';
|
||||
variables.x265Tune = 'animation';
|
||||
|
||||
const hdInput = args.inputs.animeBitrateHd;
|
||||
const sdInput = args.inputs.animeBitrateSd;
|
||||
|
||||
if (hdInput && sdInput) {
|
||||
const animeBitrateHd = Math.max(1, parseInt(hdInput, 10));
|
||||
const animeBitrateSd = Math.max(1, parseInt(sdInput, 10));
|
||||
const videoHeight = parseInt(variables.videoHeight || '0', 10);
|
||||
|
||||
if (videoHeight > 0) {
|
||||
const targetKbps = videoHeight >= 720 ? animeBitrateHd : animeBitrateSd;
|
||||
variables.vBitrate = `${targetKbps}k`;
|
||||
variables.vMaxRate = `${targetKbps * 2}k`;
|
||||
variables.vBufSize = `${targetKbps * 4}k`;
|
||||
jobLog(`[setAnimationFlag] Bitrate recalculated: ${variables.vBitrate} (height=${videoHeight}px)\n`);
|
||||
} else {
|
||||
jobLog('[setAnimationFlag] videoHeight not set — skipping bitrate recalculation.\n');
|
||||
}
|
||||
}
|
||||
|
||||
jobLog('[setAnimationFlag] Done.\n');
|
||||
return { outputNumber: 1, outputFileObj: inputFileObj, variables };
|
||||
};
|
||||
|
||||
module.exports.details = details;
|
||||
module.exports.plugin = plugin;
|
||||
Reference in new issue
Block a user