Cross-platform Bilibili video/audio downloader built on yt-dlp + ffmpeg.
Project description
bili-dl
Cross-platform Bilibili downloader — a thin, fast wrapper around
yt-dlp+ffmpeg.
bili-dl is a small command-line tool for downloading Bilibili videos and
audio with the best available quality (up to 1080p for non-premium accounts).
It started life as a Windows PowerShell script (bd.ps1) and was rewritten in
pure Python so the same code runs unchanged on Windows, macOS and Linux,
with zero runtime dependencies (standard library only).
It does one thing well: pick the right yt-dlp format, manage your Bilibili
cookie safely, and standardise every audio file into a foobar2000-friendly
container — all without re-encoding.
Why
- Cookie-safe. Drop a full-browser
cookies_all.txtexport next to the tool and it extracts only the.bilibili.comentries into a dedicated file. Cookies for every other site are never parsed, stored, or sent anywhere. - Cookie-verified. Before downloading it pokes the Bilibili
navAPI to confirm your session is actually logged in, falling back to a local check when the network is unavailable. - Audio you can actually play. Both the "audio only" download and the
audio extracted from a video are routed through
ffmpeg -c:a copy -movflags +faststart— a zero-loss remux that produces amoov-first ISOM container. foobar2000 and friends play it instantly without bitrate quirks from Bilibili's raw mux. - No quality downgrade bugs. A scoping bug in the original PowerShell version meant the cookie/referer args were silently dropped inside the download function, quietly capping quality. The rewrite passes all options explicitly, so this class of bug can't recur.
- Zero install footprint beyond the tools you already have. No
pipdependencies, norequests, nocolorama— just the standard library. If you have Python installed,pipx install bili-dlis enough.
Install
bili-dl needs yt-dlp and ffmpeg on your PATH. Both are one-liners:
pip install -U yt-dlp # or: winget install yt-dlp / brew install yt-dlp / pipx install yt-dlp
# ffmpeg:
winget install ffmpeg # Windows
brew install ffmpeg # macOS
sudo apt install ffmpeg # Debian/Ubuntu
Then install bili-dl itself:
pipx install bili-dl # recommended: isolated, exposes the `bili-dl` command
# or, if you must:
pip install bili-dl
Verify:
bili-dl --help
bili-dl -V # show version
Quick start
Cookies (one-time)
Bilibili returns HTTP 412 to anonymous requests, so you need a login cookie.
On Windows yt-dlp --cookies-from-browser can't read Chromium's App-Bound
Encryption, so export manually:
- Install the Get cookies.txt LOCALLY Edge/Chrome extension.
- Log in to bilibili.com.
- Export All Cookies in Netscape format.
- Save as
cookies_all.txtin the cookie directory (see below). - Run
bili-dlonce — it extracts only the.bilibili.comentries intocookies_bilibili.txtand reuses it thereafter.
Cookie directory defaults to:
| OS | Path |
|---|---|
| Windows | %APPDATA%\bili-dl |
| macOS | ~/Library/Application Support/bili-dl |
| Linux | ~/.config/bili-dl |
Override with --cookie-dir.
Download
# interactive REPL — paste URLs, switch modes with all/v/a, quit with q
bili-dl
# one-shot
bili-dl https://www.bilibili.com/video/BVxxxxxxxx
# audio only → standalone, foobar2000-friendly M4A
bili-dl -a https://www.bilibili.com/video/BVxxxxxxxx
# video only (single-file MP4 when available)
bili-dl -v https://www.bilibili.com/video/BVxxxxxxxx
# through a proxy, skipping TLS verification for a self-signed environment
bili-dl --proxy http://127.0.0.1:7890 -k https://www.bilibili.com/video/BVxxxxxxxx
Download destinations default to:
| OS | Videos | Audio |
|---|---|---|
| Windows | ~/Videos/bilibili_videos |
~/Music/bilibili_audio |
| macOS | ~/Movies/bilibili_videos |
~/Music/bilibili_audio |
| Linux | ~/Downloads/bilibili_videos |
~/.local/share/bili-dl/audio |
Override with --output-dir / --audio-dir.
Modes
| Mode | Flag | What it downloads | Container |
|---|---|---|---|
| all | --all (default) |
best video + best audio, merged | MP4 + extracted M4A |
| video | -v |
video (single-file MP4 if a combined stream exists) | MP4 |
| audio | -a |
best audio stream | M4A (faststart ISOM) |
In all mode the merged MP4 is kept in the videos directory and a
zero-loss M4A is extracted to the audio directory. Both audio paths (direct
download and extraction) go through the same ffmpeg remux, so they're
byte-layout-identical.
How audio standardisation works
Bilibili serves DASH audio with moov at the tail and an M4A major brand.
Some players (notably foobar2000) read bitrate metadata incorrectly or show
a noticeable start delay. bili-dl runs:
ffmpeg -i in.m4a -map 0:a -c:a copy -map_metadata 0 -movflags +faststart out.m4a
-c:a copy means no re-encode — the AAC frames are copied verbatim, so
bitrate (e.g. 201 kbps for the 203k stream) is preserved exactly. Only the
container layout changes: moov moves to the front for instant playback, and
the compatible brand set becomes M4A isom iso2. Net effect: same audio,
friendlier file.
Privacy
- The cookie importer reads
cookies_all.txtline by line and keeps only lines containingbilibili. Lines for other domains are discarded in memory; they're never written to disk or sent over the network. - The only network requests
bili-dlmakes go toapi.bilibili.com(the login probe) and the URLs you give it (viayt-dlp). No telemetry, no analytics, no "phone home". cookies_bilibili.txtis created with restrictive handling and a timestamped backup is kept before any overwrite.
Project layout
bili-dl/
├── src/bili_dl/
│ ├── __init__.py # version
│ ├── __main__.py # python -m bili_dl
│ ├── cli.py # argparse + REPL entry point
│ ├── config.py # constants (endpoints, format strings, labels)
│ ├── paths.py # cross-platform path resolution (Win/mac/Linux)
│ ├── cookies.py # Netscape extraction + (online) validity check
│ ├── ffmpeg.py # ffmpeg discovery + zero-loss audio remux/extract
│ ├── downloader.py # yt-dlp two-phase download (predict + fetch)
│ └── ui.py # ANSI-colored output (enables VT on Windows)
├── tests/ # pytest: cookies, paths, package smoke
├── pyproject.toml # hatchling build, ruff, pytest config
└── .github/workflows/ci.yml
Contributing
bili-dl is MIT-licensed and welcomes contributions. The project uses
ruff for lint/format and pytest for tests. Before sending a PR:
pip install -e . pytest ruff
ruff check src tests
ruff format --check src tests
pytest
CI runs the same checks on Windows, macOS and Linux across Python 3.9–3.13.
License
MIT. Note that bili-dl is a wrapper; the actual downloading is
done by yt-dlp (Unlicense) and
ffmpeg (LGPL/GPL). You must install those separately,
and any obligations imposed by their licenses apply to those binaries — not
to this wrapper's MIT license.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bili_dl-0.1.0.tar.gz.
File metadata
- Download URL: bili_dl-0.1.0.tar.gz
- Upload date:
- Size: 25.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68eadda88492ff289f18281ed291b0bb2f08ff1542a68738eee28dd2a83715e5
|
|
| MD5 |
d790b4d422f4e24c89632ad78411f921
|
|
| BLAKE2b-256 |
bb09831346f470604521fd3c122b71e990c102006f6e724611b742b6c1d81a4c
|
File details
Details for the file bili_dl-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bili_dl-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ac7bfef8e150fe039db1f7ef5c82efa1a3d8e1d684c69e996933429a0d24e15
|
|
| MD5 |
9027db5deb811167e43769b4a9ec5ff0
|
|
| BLAKE2b-256 |
886aceea6627cead2ab255cc4e80faf1fb1ddffc471d3f94a072a2f136e6b4a0
|