Bilibili Danmaku Integration for mpv on macOS
Introduction
Bilibili provides Danmaku in an XML format that mpv cannot natively render. Furthermore, Bilibili’s AI subtitles often use non-standard language tags (like ai-zh), which can lead to “null” tracks or rendering errors in older mpv kernels (like the one used in IINA).
Thankfully, yt-dlp allows us to extract and download these Danmaku and AI subtitles; danmaku2ass(deveoped by @m13253) provides a brilliant solution to convert XML files to ASS subtitles.
Steps
1. Pre-requisites
- mpv: Video playback and ASS subtitle rendering.
- yt-dlp: To extact and download video/audio/subtle tracks.
- Python 3: To run the conversion script.
- Danmaku2ASS: A Python script that converts Bilibili XML Danmaku into ASS format.
2. Workflow
The Lua script is to automatically download and convert Bilibili XML Danmaku to ASS format, and then load it into mpv.
[ Start: Bilibili URL ]
|
v
+-------------------------+
| Is it a Bilibili link? |--- No ---> [ Exit ]
+-------------------------+
| Yes
v
+-------------------------+ +--------------------------+
| 1. Download XML/SRT | ---> | 2. Convert XML to ASS |
| (via yt-dlp) | | (via Danmaku2ASS) |
+-------------------------+ +--------------------------+
|
v
+-------------------------+ +--------------------------+
| 4. Finish & Play | <--- | 3. Load Subs into mpv |
+-------------------------+ +--------------------------+
3. Configuration on mpv / IINA
Add this to the bottom of ~/mpv/mpv.conf
[bilibili]
# Only take effects on bilibili
profile-cond=string.match(get("path", ""), "bilibili%.com") ~= nil
# Requied otherwise will fail when access the CDN video streams
http-header-fields="Referer: https://www.bilibili.com/"
# Required when accessing membership only contents
ytdl-raw-options-append=cookies-from-browser=safari
ytdl-raw-options-append=write-subs=
ytdl-raw-options-append=write-auto-subs=
ytdl-raw-options-append=sub-langs=all,-danmaku,-ai-.*,ai-zh # Subtilte filter by languages
4 Install Danmaku2ASS
mkdir -p ~/.config/mpv/tools
git clone https://github.com/m13253/danmaku2ass.git ~/.config/mpv/tools/danmaku2ass
5. Lua Script
The most reliable approach is a Synchronous Hook. By using on_load, we pause the player for a few seconds to prepare the assets. This prevents race conditions where the video starts before the subtitles are ready.
mkdir -p ~/.config/mpv/scripts
vim ~/.config/mpv/scripts/danmaku2ass.lua
And add the following to the lua script.
local utils = require 'mp.utils'
local config = {
python = "/opt/homebrew/bin/python3",
ytdlp = "/opt/homebrew/bin/yt-dlp",
-- Replace <YOUR_USERNAME> with the actual user root directory name
danmaku2ass = "/Users/<YOUR_USERNAME>/.config/mpv/tools/danmaku2ass/danmaku2ass.py",
}
mp.add_hook("on_load", 10, function()
local url = mp.get_property("path")
if string.match(url, "bilibili%.com") then
mp.msg.info("Detected Bilibili, running danmaku2ass.py...")
local danmaku_xml = "/tmp/bili.danmaku.xml"
local danmaku_ass = "/tmp/bili.danmaku.ass"
local ai_zh_sub = "/tmp/bili.ai-zh.srt"
-- Remove old danmaku files
utils.subprocess({args = {"sh", "-c", "rm -f /tmp/bili.danmaku* "}})
-- Download XML danmaku & AI sub
mp.msg.info("Downloading XML danmaku...")
utils.subprocess({
args = {
config.ytdlp,
"--cookies-from-browser", "safari",
"--skip-download",
"--write-auto-subs",
"--write-subs", "--sub-langs", "danmaku,zh-.*,ai-zh",
"-P", "/tmp",
"-o", "bili.%(ext)s",
url}
})
-- Convert danmaku from XML to ASS
mp.msg.info("Converting XML to ASS...")
utils.subprocess({
args = {
config.python,
config.danmaku2ass,
"-o", danmaku_ass,
"-s", "1920x1080",
"-fn", "Sans-serif", "-fs", "42","-a", "0.5",
"-dm", "12", "-ds", "5",
danmaku_xml
}
})
-- Load danmaku & subs
mp.commandv("sub-add", danmaku_ass)
mp.commandv("sub-add", ai_zh_sub, "select", "ai-zh", "ai-zh")
end
end)
Highlights
-
Absolute Paths
Use absolute paths in the config. since mpv’s Lua environment doesn’t run through a full shell, variables like
$HOMEor~will be treated as literal characters. Hardcoding the/Users/[YOUR_USERNAME]/...path is the simplest way to ensure the access todanmaku2ass.py. -
The
/tmpDirectoryUsing
/tmp(or/private/tmpon macOS) is ideal to keep the system clean. These files are cleared by the OS periodically, and the script explicitly deletes them at the start of every Bilibili video anyway.
References
- Gemini 3
- README - Danmaku2ASS: https://github.com/m13253/danmaku2ass