تفاصيل العمل

Video Downloader & Audio Extractor

A self-hosted web app for downloading video and extracting audio from any public link. Paste a URL, and it reads the available formats from the source, shows you the real options, then downloads video or converts the audio track to MP3, M4A, Opus, FLAC or WAV — with live progress while it runs.

It works with YouTube, Facebook, Instagram, TikTok, Vimeo, SoundCloud, X, Reddit, Twitch, Bilibili, Bandcamp and roughly 1,800 other sites, because it is a safe, injection-proof web interface over yt-dlp (https://github.com/yt-dlp...) and ffmpeg rather than a reimplementation of their extractors.

How it works

Probe → pick → download.

1. Probe. POST /api/probe reads metadata and the format list without downloading anything, returning the title, uploader, duration, thumbnail and a normalised view of every available stream.

2. Pick. The options are built from what the source actually offered, so the quality list is never invented. Two tabs: Video (quality, best-available merging, subtitles) and Audio only (output format, bitrate, source track).

3. Download. The job is queued and progress streams live over SSE, including percentage, speed and ETA, plus a stage indicator for merging and conversion. The finished file is served from a one-time URL.

Audio-only extraction

Six output formats covering the real tradeoffs: MP3 for universal compatibility, M4A and Opus for better quality per megabyte, FLAC for lossless, WAV for uncompressed, and Vorbis. Bitrate is selectable, and cover art plus metadata tags are embedded automatically where the source allows it.

One case needed specific handling: when a link points straight at a media file — a plain .mp4 on a static host — the extractor never probes the container, so it reports no codec and yt-dlp's own audio extraction fails on it. This app detects that situation and drives ffmpeg directly instead, which reads the container properly and succeeds where the normal path cannot.

Command injection is structurally impossible

This is a server-side requester that runs an external binary with a URL the client supplied, which is exactly the shape that produces injection bugs. Every argument is passed as an array to execFile or spawn, and the shell is never invoked — so quoting mistakes and payloads like ; rm -rf / cannot reach a command line, not because they are filtered, but because there is no string to corrupt. The URL is always the final argument, after a -- separator.

Related hardening:

- SSRF guard — only http/https, with private, loopback, link-local, CGNAT, multicast and cloud-metadata ranges refused, including obfuscated encodings (0177.0.0.1, 2130706433, 127.1, 0x7f.0.0.1, [fdff::1]).

- Format IDs are never client-supplied — yt-dlp's -f argument is a small language, so a probe stores its format IDs server-side and returns an opaque token plus integer indexes. The download request sends only token + index, which is bounds-checked; the token expires after 10 minutes.

- Flags locked down — --no-config, --no-exec, --no-playlist, and a scratch HOME so the child process inherits none of the server's environment.

- Resource caps — 2 concurrent downloads, 10-deep queue, 15-minute timeout with SIGTERM→SIGKILL, 4 GB total disk ceiling, and automatic cleanup of finished files.

- Zero innerHTML — every remote-controlled string reaches the DOM through textContent and createElement.

Operational safety

A crash in a request handler cannot take the server down mid-download: uncaughtException and unhandledRejection handlers keep it serving, and stream errors are caught so a client disconnecting doesn't kill in-flight jobs. trust proxy is opt-in via TRUST_PROXY=1, so clients cannot forge X-Forwarded-For to reset their own rate limits.

Interface

Light, dark and hacker (black + lime) themes driven by CSS custom properties, persisted to localStorage and falling back to the system preference, with Shift+T to cycle. Tabs implement the WAI-ARIA pattern with roving tabindex and arrow/Home/End navigation, prefers-reduced-motion is honoured, and recent links are kept locally so a probe can be re-run without re-pasting.

Running it

No build step, no bundler, no database, no Docker. Express plus a single HTML file.

npm install

npm start # http://localhost:4000

node test.js # 136 assertions, 13 groups, fully offline

Requires Node 18+, yt-dlp, and ffmpeg for audio conversion.

Honest limitations

Cloudflare-protected hosts often refuse yt-dlp's default user agent; the error surfaces verbatim with yt-dlp's own suggestion to install the impersonation dependency, which is not bundled here. Private, age-gated and DRM'd content cannot be fetched. A file with no audio track cannot yield audio, and that is reported clearly rather than producing a silent empty file. Jobs live in memory, so restarting the server loses in-flight downloads and queue state. Rate limits are per-instance and reset on restart.

Download only content you own or have permission to download. YouTube, Facebook and Instagram all prohibit downloading in their terms of service; this is appropriate for your own uploads, Creative Commons and public-domain material, backups, accessibility and offline listening — not for redistribution.

بطاقة العمل

اسم المستقل
عدد الإعجابات
0
تاريخ الإضافة
تاريخ الإنجاز
المهارات