90 lines
3.1 KiB
JavaScript
Executable File
90 lines
3.1 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* Downloads the standalone yt-dlp binary into ./bin so the app never depends on
|
|
* a system-wide install. The Linux/macOS builds are self-contained (no Python
|
|
* required). Run automatically on `npm install`, or manually with `npm run setup`.
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const https = require('https');
|
|
|
|
const BIN_DIR = path.join(__dirname, '..', 'bin');
|
|
const force = process.argv.includes('--force');
|
|
|
|
function assetForPlatform() {
|
|
switch (process.platform) {
|
|
case 'win32':
|
|
return { asset: 'yt-dlp.exe', out: 'yt-dlp.exe' };
|
|
case 'darwin':
|
|
return { asset: 'yt-dlp_macos', out: 'yt-dlp' };
|
|
default:
|
|
// Linux (incl. WSL). yt-dlp_linux is a self-contained build.
|
|
return { asset: 'yt-dlp_linux', out: 'yt-dlp' };
|
|
}
|
|
}
|
|
|
|
function download(url, dest) {
|
|
return new Promise((resolve, reject) => {
|
|
const file = fs.createWriteStream(dest);
|
|
const get = (u, redirects = 0) => {
|
|
if (redirects > 10) return reject(new Error('Too many redirects'));
|
|
https
|
|
.get(u, { headers: { 'User-Agent': 'ytplayer-setup' } }, (res) => {
|
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
res.resume();
|
|
return get(res.headers.location, redirects + 1);
|
|
}
|
|
if (res.statusCode !== 200) {
|
|
res.resume();
|
|
return reject(new Error(`HTTP ${res.statusCode} for ${u}`));
|
|
}
|
|
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
let received = 0;
|
|
res.on('data', (chunk) => {
|
|
received += chunk.length;
|
|
if (total) {
|
|
const pct = ((received / total) * 100).toFixed(0);
|
|
process.stdout.write(`\r downloading yt-dlp… ${pct}%`);
|
|
}
|
|
});
|
|
res.pipe(file);
|
|
file.on('finish', () => file.close(() => {
|
|
process.stdout.write('\r downloading yt-dlp… done \n');
|
|
resolve();
|
|
}));
|
|
})
|
|
.on('error', (err) => {
|
|
fs.unlink(dest, () => reject(err));
|
|
});
|
|
};
|
|
get(url);
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
const { asset, out } = assetForPlatform();
|
|
const dest = path.join(BIN_DIR, out);
|
|
|
|
if (!fs.existsSync(BIN_DIR)) fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
|
|
if (fs.existsSync(dest) && !force) {
|
|
console.log(`yt-dlp already present at ${dest} (use "npm run update-ytdlp" to refresh).`);
|
|
return;
|
|
}
|
|
|
|
const url = `https://github.com/yt-dlp/yt-dlp/releases/latest/download/${asset}`;
|
|
console.log(`Fetching ${asset} from latest yt-dlp release…`);
|
|
try {
|
|
await download(url, dest);
|
|
if (process.platform !== 'win32') fs.chmodSync(dest, 0o755);
|
|
console.log(`yt-dlp installed at ${dest}`);
|
|
} catch (err) {
|
|
console.error('\nFailed to download yt-dlp automatically:', err.message);
|
|
console.error('You can place a yt-dlp binary manually in the ./bin folder, or ensure');
|
|
console.error('yt-dlp is on your PATH — the app will fall back to PATH if ./bin is empty.');
|
|
process.exitCode = 1;
|
|
}
|
|
}
|
|
|
|
main();
|