A cross-platform multimedia downloader & format converter built on top of
yt-dlp and ffmpeg, with an AI assistant
for batch automation. Ships as a native desktop app (Windows / Linux / macOS)
built with Tauri, and as a deployable web app.
This document is in English. For 繁體中文 / 简体中文 documentation, see the Wiki — the app's own UI stays available in all three languages regardless.
- AI Assistant — describe what you want in plain language ("convert every .mkv in this folder to mp4"); the assistant drafts a batch plan and only runs it after you confirm — nothing executes without your approval.
- 500+ sites — YouTube, Facebook, Instagram, TikTok, BiliBili, Twitter, SoundCloud, Twitch, Vimeo, and every other site yt-dlp supports.
- Audio extraction — convert to MP3, FLAC, AAC, WAV, OGG, M4A, Opus, WMA.
- Format conversion — transcode any input to any output via ffmpeg (bundled — no separate ffmpeg install needed).
- Tri-language UI — English (default), Traditional Chinese, Simplified Chinese; switchable at runtime.
- Cookie support — read from an installed browser, or supply a
cookies.txtfor Douyin / Instagram / login-gated platforms. - Batch queue — download or convert many items in one go, with live per-item progress and a run log.
- Built-in User Manual — a quick reference panel right in the app (header book icon), available in all three languages.
Note
Primarily a desktop app; V4.1 adds a real, network-deployable web version (see Run as a web app below). Native mobile apps are planned for V5.0.
- Download the installer for your platform from the Releases page (Windows:
.exeor.msi). - Run it and follow the prompts.
- Launch Multimedia Downloader from the Start Menu / Applications.
No separate Python or ffmpeg install is required — both are bundled inside the app.
Note
The AI Assistant runtime error in the 4.0.0 build — caused by OpenRouter retiring the free models it was pinned to — was patched in v4.1 by swapping in replacements, and those were retired in turn. Since v4.3.10 the assistant checks its models against OpenRouter's live catalogue on first use and substitutes an available free model automatically, so a retired model no longer breaks it.
- Click the ✨ AI Assistant button (or press
Ctrl/Cmd+K). - First time only: open Settings and paste your own OpenRouter API key (stored locally on your device only — never bundled, never sent anywhere but OpenRouter).
- Describe your task, e.g. "Download https://youtube.com/watch?v=... as mp4" or "Convert D:\videos\a.mov and b.avi to mp4".
- Review the generated plan — nothing runs yet.
- Click Confirm to execute, or Cancel / Regenerate.
| Component | Notes |
|---|---|
| Windows 10/11, Linux, or macOS | Desktop app; all three platforms built and published automatically by CI. |
| WebView2 | Pre-installed on modern Windows; the installer will prompt if missing. |
| OpenRouter API key | Optional — only needed to use the AI Assistant. Get one free at openrouter.ai. |
git clone https://github.com/SpaceSquare640/Multimedia_Downloader.git
cd Multimedia_Downloader
npm install # installs the Tauri CLI at the project root
npm run tauri dev # compile + run in dev mode (needs Python 3.8+, Rust, Node)
npm run tauri build # build an installer locally, if you want one without waiting for CIThe frontend's TypeScript major version is kept within the range supported by
svelte-check; Dependabot updates to TypeScript 7 are paused until that peer
dependency supports it.
Only pull requests merged into Source_Code with the release:patch label
automatically increment the patch version, create and push the matching
vX.Y.Z tag, and start the three-platform release build. Merged pull requests
without that label do not create a release. The automatic release workflow can
also be run manually for a merged pull request. If another pull request
advances Source_Code while a release commit is being pushed, the workflow
rebases that commit onto the new branch tip and retries. Dependabot groups
minor and patch updates by ecosystem; its pull requests are merged
automatically after the full CI workflow passes, but do not trigger a release
unless they carry the release:patch label. Major updates remain separate
pull requests and also require CI to pass before automatic merging. PRs that
change files under
.github/workflows/ are left for manual merging because GitHub requires a
separate Workflows permission to merge them. Put release notes under
Unreleased in CHANGELOG.md; the release workflow promotes them to the new
version entry.
Official installers are built and published automatically by GitHub Actions
(see .github/workflows/auto-patch-release.yml and
.github/workflows/release.yml) — no local release build or manual tag is
needed after a labeled pull request is merged.
The CI workflow runs the existing source checks on pushes and pull requests.
Every Monday at 00:17 UTC (08:17 Hong Kong time), it also runs those checks on
Source_Code, builds the Multimedia_Downloader_Web_Preview branch, and checks
that the published GitHub Pages URL returns HTTP 200 with the expected page
title. Schedule events run from the repository's default branch.
Run the Python test suite:
pip install -r requirements-dev.txt # what CI installs, in one file
python -m unittest discover -s tests # 161 testsInstall that file first — the suite does not skip tests whose dependencies are
missing, it fails and tells you what to install. A skipped test reports as
success, so a partial run would otherwise print OK and mean nothing. To run
only part of the suite, name the module: python -m unittest tests.test_engine.
The same UI can run as a standalone, deployable web app — no desktop shell — with a real Flask + SSE backend that drives the same engine (real yt-dlp / ffmpeg, not the browser mock):
cd Multimedia_Downloader
pip install -r requirements-web.txt # yt-dlp + Flask (ffmpeg on PATH)
npm run build:frontend:web # build the frontend in web mode
npm run web # serve on http://127.0.0.1:5000
# LAN / server:
HOST=0.0.0.0 PORT=8000 python web_app.pyBecause it's a browser app, downloaded/converted files land in a server-side
folder (MMDL_DOWNLOADS, default ./downloads) retrievable at /files/<name>
— leave the Save-Location field blank to use it. It's a single-user model (one
operation at a time, like V3.0's web_app.py); for production put it behind a
streaming-friendly WSGI worker, e.g. gunicorn -k gthread -w 1 --threads 8 web_app:app, and add your own auth if exposing it beyond localhost.
Paths sent by the browser are confined to that downloads folder, and a request
pointing outside it is rejected with HTTP 400 — otherwise anyone who can reach
the server could read and write files anywhere on it. The format, quality and
browser fields are checked against the engine's own catalogues for the same
reason: the requested format ends up in the output filename, so an unchecked
one steers the path straight back out of the folder. Set
MMDL_ALLOW_ABSOLUTE_PATHS=1 to lift the restriction when you are running it
locally for yourself and want to save elsewhere on the machine.
The desktop app can't run on Android, but the Python engine can — via Termux. Use it from the terminal (CLI) or as the web UI in your phone's browser:
pkg install -y git && git clone https://github.com/SpaceSquare640/Multimedia_Downloader.git
cd Multimedia_Downloader
bash termux/run-cli.sh download "https://youtu.be/XXXX" -o ~/storage/downloads -f mp4 # CLI
bash termux/run-web.sh # web UIFull walkthrough: termux/README.md. The CLI (cli.py)
also runs on any desktop/server with Python + ffmpeg.
Prefer a keyboard-driven interface over the desktop GUI — or you're on a
headless server / SSH session? The desktop, Termux, and web installs all
already had a terminal-friendly path via cli.py; V4.3 adds a
full interactive terminal UI (built with Textual)
with the same Download / Convert / Log tabs as the desktop app, driving the
same engine:
pip install -r requirements-tui.txt # yt-dlp + textual (ffmpeg on PATH)
python -m tui # or: python -m tui --lang zh_twKeyboard shortcuts: d toggles light/dark, q quits. The language is fixed
at launch via --lang (like cli.py) rather than switchable mid-session.
Source_Code/
├── src-tauri/ Tauri shell (Rust): window, sidecar management
├── frontend/ Web UI (Svelte + Vite + TS + Tailwind)
├── engine/ Python engine: Downloader / Converter (yt-dlp + ffmpeg)
├── engine_sidecar.py stdio IPC entrypoint spawned by the Rust shell
├── web_app.py Flask + SSE backend for the standalone web app (V4.1)
├── cli.py terminal CLI over the engine (great for Termux / headless)
├── tui/ interactive terminal UI (Textual) over the same engine
├── termux/ Android (Termux) launchers + guide
├── ai/ OpenRouter client + multi-model planning pipeline
├── locales/ en.json / zh_tw.json / zh_cn.json
├── packaging/ PyInstaller spec (used by CI to build the sidecar)
└── tests/ Unit tests
Some platforms (Douyin, private TikTok, private Instagram) refuse to serve media without an authenticated cookie:
- Browser-direct (easiest) — select the browser you are logged into in the download tab. yt-dlp reads its cookies for you.
- Manual file — export
cookies.txtwith a browser extension (e.g. Get cookies.txt LOCALLY for Chrome/Edge/Brave, cookies.txt for Firefox).
This software is for personal, lawful use only. Respect each platform's terms of service and the copyright of content owners.