Turbopack requires native SWC bindings unavailable on o2switch's old
glibc, so force webpack for production builds. NODE_ENV=production on
o2switch's shell also caused npm to skip devDependencies needed at
build time (Tailwind, PostCSS), so deploy now installs with
--include=dev.
yt-dlp's standalone PyInstaller binary self-extracts to noexec /tmp
and fails to mmap its bundled shared libs there, and o2switch's system
python3 (3.6) is too old for the plain zipapp. Revert to the zipapp
and invoke it explicitly through a configurable PYTHON_BIN, set to
o2switch's newer Python 3.11 in .env.prod.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The download endpoint served files under their internal uuid-based
storage name; it now builds the Content-Disposition filename from the
probed video title (persisted on submit) with the original extension,
falling back to the old behavior when no title is available. The
status page also gets an always-visible link back to the homepage.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
yt-dlp needs ffprobe alongside ffmpeg for postprocessing; only ffmpeg was
bundled for the Linux/o2switch prod deploy. Also add Windows builds so
local dev on Windows has a working ffmpeg/ffprobe pair, and gitignore
.env.prod/.env.local so real deployment credentials never get committed.
Options (quality, subtitles) are now derived from a yt-dlp -J probe of
the submitted URL instead of a static list, so users can't pick
combinations the source video doesn't actually support. Submission is
blocked until the probe succeeds.
- New /api/probe endpoint + src/lib/ytdlp-probe.ts, with its own rate
limiter (rate-limit.ts refactored into a createRateLimiter factory).
- New options: subtitle language selection, clip start/end trim, MP3
audio quality.
- Fixed buildYtdlpArgs: format=mp3 never triggered audio extraction
(-x/--audio-format), and quality=best never applied --merge-output-format,
so the chosen container had no real effect.
- Cross-platform yt-dlp invocation: the bundled bin/yt-dlp is a Python
zipapp relying on a shebang, which Windows' spawn() can't run
directly. buildYtdlpCommand() runs it through `python` on Windows and
execs it directly on Linux/o2switch, where the shebang works natively.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Create a dedicated, dynamically-routed page for each of 15 curated
platforms (YouTube, TikTok, Instagram, Facebook, X, Reddit, Pinterest,
Vimeo, SoundCloud, Twitch, Dailymotion, LinkedIn, Tumblr, VK, Snapchat)
under /[locale]/[slug], with a tailored hero, an example URL matched
to the platform, a unique "about" paragraph, and a mix of
platform-specific and shared FAQ items, all translated across
en/fr/es/it. Unknown slugs 404.
Kept the scope to a curated list rather than all 1380 yt-dlp
extractors to avoid thin/duplicate "doorway page" content that search
engines penalize.
The homepage's platform badges and the "+1000 sites" links now point
to these pages, extracted the FAQ accordion markup into a shared
FaqAccordion component reused by both the homepage FAQ and the new
platform pages.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
yt-dlp is an internal implementation detail and should not be exposed
on the public site. Replace direct mentions in the platforms and FAQ
sections with a link to a new /supported-sites page listing every
extractor from yt-dlp's supported-sites doc (searchable, grouped
alphabetically), translated across en/fr/es/it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds precompiled Linux x86_64 binaries for yt-dlp and ffmpeg under bin/.
The processor resolves yt-dlp from bin/ when present, falling back to PATH.
ffmpeg is passed via --ffmpeg-location so yt-dlp uses the bundled binary on o2switch.
BIN_DIR is configurable via env var.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>