2026-05-13 17:24:10 +02:00
|
|
|
"use strict";
|
|
|
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
|
|
|
};
|
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
|
exports.isYtDlpAvailable = isYtDlpAvailable;
|
|
|
|
|
exports.downloadVideo = downloadVideo;
|
|
|
|
|
const child_process_1 = require("child_process");
|
|
|
|
|
const path_1 = __importDefault(require("path"));
|
|
|
|
|
const fs_1 = __importDefault(require("fs"));
|
|
|
|
|
function isYtDlpAvailable() {
|
|
|
|
|
try {
|
|
|
|
|
(0, child_process_1.execSync)('yt-dlp --version', { stdio: 'pipe' });
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-15 04:10:06 +02:00
|
|
|
const PROGRESS_PREFIX = 'PROG ';
|
|
|
|
|
function downloadVideo(url, outputDir, onProgress) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (!fs_1.default.existsSync(outputDir)) {
|
|
|
|
|
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
|
|
|
}
|
|
|
|
|
const outputTemplate = path_1.default.join(outputDir, '%(title)s.%(ext)s');
|
|
|
|
|
// Pass arguments as an array — no shell, no quoting issues, no truncation
|
|
|
|
|
// on URLs containing & | % ^ etc. (the original execSync bug on Windows).
|
|
|
|
|
const args = [
|
|
|
|
|
'-f', 'best[ext=mp4]/best',
|
|
|
|
|
'-o', outputTemplate,
|
|
|
|
|
'--newline',
|
|
|
|
|
'--progress-template', `${PROGRESS_PREFIX}%(progress._percent_str)s`,
|
|
|
|
|
'--print', 'after_move:filepath',
|
|
|
|
|
'--print', 'title',
|
|
|
|
|
'--no-simulate',
|
|
|
|
|
url,
|
|
|
|
|
];
|
|
|
|
|
const child = (0, child_process_1.spawn)('yt-dlp', args, { shell: false });
|
|
|
|
|
const stderrLines = [];
|
|
|
|
|
const outputLines = [];
|
|
|
|
|
let stdoutBuf = '';
|
|
|
|
|
let stderrBuf = '';
|
|
|
|
|
const handleStdoutLine = (line) => {
|
|
|
|
|
if (!line)
|
|
|
|
|
return;
|
|
|
|
|
if (line.startsWith(PROGRESS_PREFIX)) {
|
|
|
|
|
const m = line.slice(PROGRESS_PREFIX.length).match(/([\d.]+)\s*%/);
|
|
|
|
|
if (m && onProgress) {
|
|
|
|
|
const pct = parseFloat(m[1]);
|
|
|
|
|
if (!isNaN(pct))
|
|
|
|
|
onProgress(pct);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
outputLines.push(line);
|
|
|
|
|
};
|
|
|
|
|
child.stdout.on('data', (chunk) => {
|
|
|
|
|
stdoutBuf += chunk.toString('utf-8');
|
|
|
|
|
let nl;
|
|
|
|
|
while ((nl = stdoutBuf.indexOf('\n')) !== -1) {
|
|
|
|
|
const line = stdoutBuf.slice(0, nl).replace(/\r$/, '');
|
|
|
|
|
stdoutBuf = stdoutBuf.slice(nl + 1);
|
|
|
|
|
handleStdoutLine(line.trim());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
child.stderr.on('data', (chunk) => {
|
|
|
|
|
stderrBuf += chunk.toString('utf-8');
|
|
|
|
|
let nl;
|
|
|
|
|
while ((nl = stderrBuf.indexOf('\n')) !== -1) {
|
|
|
|
|
const line = stderrBuf.slice(0, nl).replace(/\r$/, '').trim();
|
|
|
|
|
stderrBuf = stderrBuf.slice(nl + 1);
|
|
|
|
|
if (line)
|
|
|
|
|
stderrLines.push(line);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
child.on('error', (err) => {
|
|
|
|
|
reject(new Error(`yt-dlp failed to start: ${err.message}`));
|
|
|
|
|
});
|
|
|
|
|
const timeoutMs = 600000;
|
|
|
|
|
const timer = setTimeout(() => {
|
|
|
|
|
child.kill();
|
|
|
|
|
reject(new Error(`yt-dlp timed out after ${timeoutMs / 1000}s`));
|
|
|
|
|
}, timeoutMs);
|
|
|
|
|
child.on('close', (code) => {
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
if (stdoutBuf.trim())
|
|
|
|
|
handleStdoutLine(stdoutBuf.trim());
|
|
|
|
|
if (stderrBuf.trim())
|
|
|
|
|
stderrLines.push(stderrBuf.trim());
|
|
|
|
|
if (code !== 0) {
|
|
|
|
|
const tail = stderrLines.slice(-3).join(' | ') || `exit code ${code}`;
|
|
|
|
|
reject(new Error(tail));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const filePath = outputLines[0];
|
|
|
|
|
const title = outputLines[1] || (filePath ? path_1.default.basename(filePath) : '');
|
|
|
|
|
if (!filePath) {
|
|
|
|
|
reject(new Error('yt-dlp completed but did not report a filename'));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!fs_1.default.existsSync(filePath)) {
|
|
|
|
|
reject(new Error(`yt-dlp reported success but file not found: ${filePath}`));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
resolve({
|
|
|
|
|
filePath: path_1.default.resolve(filePath),
|
|
|
|
|
filename: path_1.default.basename(filePath),
|
|
|
|
|
title,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2026-05-13 17:24:10 +02:00
|
|
|
}
|
|
|
|
|
//# sourceMappingURL=ytDlp.js.map
|