Add ad-free YouTube player built on zero-native
Desktop YouTube player with no login and no ads. Extracts direct video/audio streams with yt-dlp and plays them in a native window via zero-native (Zig + system WebView) for a tiny footprint vs Electron. - Dual-stream engine: muted video synced with separate audio track for high quality without ffmpeg muxing; progressive fallback - On-device playlists, watch history, audio-only mode - Full custom controls: seek, volume, speed, quality, fullscreen, queue - Zig bridge handlers spawn yt-dlp and return slimmed JSON to the web UI - Cinematic dark UI: Bricolage/Hanken/JetBrains Mono, vermilion accent
This commit is contained in:
89
scripts/setup-ytdlp.js
Normal file
89
scripts/setup-ytdlp.js
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/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();
|
||||
Reference in New Issue
Block a user