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
71 lines
3.1 KiB
JavaScript
71 lines
3.1 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* run-tests.js
|
|
* Orchestrates all 4 test cases.
|
|
* Usage: node tests/run-tests.js [--skip-transcode]
|
|
*
|
|
* Options:
|
|
* --skip-transcode Skip test3 (which runs actual FFmpeg x265 encode)
|
|
*/
|
|
|
|
const args = process.argv.slice(2);
|
|
const skipTranscode = args.includes('--skip-transcode');
|
|
|
|
const tests = [
|
|
{ name: 'Test 1 — Film 23.976fps (AC3 ITA + EAC3 ENG)', file: './test-cases/test1-movie-23976fps', heavy: false },
|
|
{ name: 'Test 2 — Anime 25fps DTS ITA (Naruto)', file: './test-cases/test2-anime-25fps', heavy: false },
|
|
{ name: 'Test 3 — Ultrawide 3840x1600 Scale', file: './test-cases/test3-ultrawide', heavy: true },
|
|
{ name: 'Test 4 — Subtitle Extraction (forced + SDH)', file: './test-cases/test4-subtitles', heavy: false },
|
|
];
|
|
|
|
async function main() {
|
|
console.log('╔══════════════════════════════════════════════════════════╗');
|
|
console.log('║ Tdarr Plugin Suite — Test Runner ║');
|
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
|
|
const results = [];
|
|
|
|
for (const test of tests) {
|
|
if (test.heavy && skipTranscode) {
|
|
console.log(`[SKIP] ${test.name} (--skip-transcode)\n`);
|
|
results.push({ name: test.name, status: 'SKIPPED' });
|
|
continue;
|
|
}
|
|
|
|
console.log(`[RUN] ${test.name}`);
|
|
try {
|
|
const fn = require(test.file);
|
|
await fn();
|
|
results.push({ name: test.name, status: 'PASSED' });
|
|
} catch (err) {
|
|
console.error(`\n[FAIL] ${test.name}\n ${err.message}\n`);
|
|
results.push({ name: test.name, status: 'FAILED', error: err.message });
|
|
}
|
|
}
|
|
|
|
// ── Summary ───────────────────────────────────────────────────────────────
|
|
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
console.log('║ SUMMARY ║');
|
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
|
|
let passed = 0, failed = 0, skipped = 0;
|
|
for (const r of results) {
|
|
const icon = r.status === 'PASSED' ? '[OK]' : r.status === 'SKIPPED' ? '[--]' : '[!!]';
|
|
console.log(` ${icon} ${r.name}`);
|
|
if (r.error) console.log(` Error: ${r.error}`);
|
|
if (r.status === 'PASSED') passed++;
|
|
if (r.status === 'FAILED') failed++;
|
|
if (r.status === 'SKIPPED') skipped++;
|
|
}
|
|
|
|
console.log(`\n Results: ${passed} passed, ${failed} failed, ${skipped} skipped\n`);
|
|
|
|
if (failed > 0) process.exit(1);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('Fatal error:', err);
|
|
process.exit(1);
|
|
});
|