'use strict'; /** * Local fallback/mock of Tdarr FlowHelpers/1.0.0/cliUtils.js * Used for local testing and as safe fallback. * * Matches the real Tdarr CLI constructor signature: * new CLI({ cli, spawnArgs, spawnOpts, WorkDir, jobLog, inputFileObj, updateWorker, logFullCliOutput }) */ const { spawn } = require('child_process'); class CLI { constructor(config) { this.config = config || {}; } runCli() { return new Promise((resolve) => { const { cli, spawnArgs = [], spawnOpts = {}, WorkDir, jobLog, updateWorker, logFullCliOutput = false, } = this.config; const opts = { cwd: spawnOpts.cwd || WorkDir || process.cwd(), stdio: ['ignore', 'pipe', 'pipe'], shell: false, ...spawnOpts, }; if (jobLog) jobLog(`Running ${cli} ${spawnArgs.join(' ')}\n`); const proc = spawn(cli, spawnArgs, opts); const errorLogFull = []; const handleData = (data) => { const str = data.toString(); errorLogFull.push(str); if (logFullCliOutput && jobLog) { jobLog(str); } if (typeof updateWorker === 'function') { // ffmpeg progress matching: time=HH:MM:SS const fpsMatch = str.match(/fps=\s*(\d+(?:\.\d+)?)/); if (fpsMatch) { updateWorker({ fps: parseFloat(fpsMatch[1]) }); } const timeMatch = str.match(/time=(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)/); if (timeMatch) { const curSec = parseInt(timeMatch[1], 10) * 3600 + parseInt(timeMatch[2], 10) * 60 + parseFloat(timeMatch[3]); const duration = this.config.inputFileObj?.meta?.Duration || parseFloat(this.config.inputFileObj?.ffProbeData?.format?.duration) || 0; if (duration > 0) { const perc = Math.min(100, Math.max(0, +((curSec / duration) * 100).toFixed(1))); updateWorker({ percentage: perc }); } } else if (str.includes('%')) { // mkvextract progress matching (e.g. "Progress: 45%" or "Progresso: 45%") const pMatch = str.match(/(?:Progress|Progresso):\s*(\d+)%/i); if (pMatch) { updateWorker({ percentage: parseInt(pMatch[1], 10) }); } } } }; proc.stdout.on('data', handleData); proc.stderr.on('data', handleData); proc.on('close', (code) => { if (!logFullCliOutput && jobLog) { jobLog(errorLogFull.slice(-1000).join('')); } resolve({ cliExitCode: code || 0, errorLogFull }); }); proc.on('error', (err) => { if (jobLog) jobLog(`Error executing binary: ${cli}: ${err.message}\n`); resolve({ cliExitCode: 1, errorLogFull }); }); }); } } const getFFmpegVar = () => {}; module.exports = { CLI, getFFmpegVar };