这篇记录如何在已经运行 Synapse、Element Call、LiveKit 和 Matrix LiveKit JWT Service 的 Docker 主机上,额外安装一个可以进入 Element Call 播放音乐、电台或 Podcast 的机器人。
上游项目是 SultanAlburaq/matrix-element-call-musicbot。本文使用的是我整理后的 Docker 部署包 hanigege/matrix-element-call-musicbot-docker-pro,它保留上游镜像,通过只读挂载增强版 patches/bot.py,补上电台短命令、Podcast RSS 别名、房间白名单和管理员控制边界。
本文使用的实际环境如下:
Matrix server_name: 666666.xyz
Synapse client API: https://matrix.666666.xyz:12335
Docker 数据目录: /root/data/docker_data
MusicBot 账号: @musicbot:666666.xyz
MusicBot 目录: /root/data/docker_data/matrix-musicbot
Docker 网络: matrix这个机器人适合在 Matrix 房间里用命令点歌、播放 URL 或网络电台,然后把声音推入 Element Call。它不是普通聊天窗口里的音频播放器:要听到声音,用户自己的 Element 客户端也必须点击右上角“加入”进入通话。
如果只是想复刻本文的生产方案,推荐直接使用 Docker 部署包:
git clone https://github.com/hanigege/matrix-element-call-musicbot-docker-pro.git
cd matrix-element-call-musicbot-docker-pro
cp .env.example .env
vi .env
chmod +x scripts/*.sh
./scripts/install.sh这会渲染 config/config.toml、准备 data/radio_aliases.json 和 data/podcast_aliases.json,再启动 matrix-musicbot。后面的手工步骤保留下来,是为了说明每个文件为什么这样写,以及生产排障时该看哪里。
一、重要限制
先说限制,避免后面踩坑。
这个项目目前不支持加密通话媒体。如果房间或通话强制端到端加密,机器人可能无法正常播放。普通 Element Call 房间更适合测试。
!load 对普通歌曲和有限长度音频可以用,但对直播电台容易卡住。直播电台没有自然结束点,如果机器人按“下载完整音频”的方式处理,就会一直停在 Loading...。后文会通过配置和补丁把单条直播 URL 的保存队列转为流式播放。
!join 的含义是让 机器人 加入 Element Call,不是让你自己的客户端加入通话。你本人仍然要点击 Element 右上角的“加入”。
生产环境还要注意单实例模型:一个 matrix-musicbot 容器只有一个全局播放器。多个房间共用同一个 bot 时,任何有权限的人都能切台、停止、跳过或清队列,所以建议同时设置房间白名单和管理员白名单。示例配置只允许指定房间里的 @admin:666666.xyz、@owner:666666.xyz 控制播放。
二、创建目录
在 Docker 主机上创建独立服务目录:
mkdir -p /root/data/docker_data/matrix-musicbot/config
mkdir -p /root/data/docker_data/matrix-musicbot/logs
mkdir -p /root/data/docker_data/matrix-musicbot/data
mkdir -p /root/data/docker_data/matrix-musicbot/cache
mkdir -p /root/data/docker_data/matrix-musicbot/patches镜像内进程固定使用 UID 10001 运行,所以可写目录要交给这个 UID:
chown -R 10001:10001 \
/root/data/docker_data/matrix-musicbot/logs \
/root/data/docker_data/matrix-musicbot/data \
/root/data/docker_data/matrix-musicbot/cache配置目录只读挂载即可:
chmod 755 /root/data/docker_data/matrix-musicbot/config三、创建 Matrix 机器人账号
如果 Synapse 配置里有 registration_shared_secret,可以直接在 Synapse 容器里创建普通用户:
docker exec matrix-synapse register_new_matrix_user \
-u musicbot \
-p '替换成一个强密码' \
--no-admin \
--exists-ok \
-c /data/homeserver.yaml \
http://localhost:8008然后登录获取 access token:
curl -sS -X POST http://127.0.0.1:8008/_matrix/client/v3/login \
-H 'Content-Type: application/json' \
-d '{
"type": "m.login.password",
"identifier": {"type": "m.id.user", "user": "musicbot"},
"password": "替换成上面的密码",
"initial_device_display_name": "matrix-musicbot-docker"
}'返回 JSON 里的 access_token 要保存到下一节的 config.toml。不要把真实 token 提交到公开仓库。
可以用 whoami 验证 token:
curl -sS \
-H "Authorization: Bearer 这里填机器人token" \
http://127.0.0.1:8008/_matrix/client/v3/account/whoami期望返回:
{"user_id":"@musicbot:666666.xyz","is_guest":false}四、写入 config.toml
创建配置文件:
vi /root/data/docker_data/matrix-musicbot/config/config.toml写入:
[matrix]
homeserver = "https://matrix.666666.xyz:12335"
user_id = "@musicbot:666666.xyz"
access_token = "替换成真实 access_token"
[bot]
name = "Music Bot"
history_limit = 10
auto_accept_invites = true
[access]
# 单实例 musicbot 只有一个全局播放器;只允许这些房间控制,避免陌生房间或私聊抢占播放。
allowed_rooms = [
"!roomid1:666666.xyz",
"!roomid2:666666.xyz",
]
# 播放器是单实例全局资源;只有这些 Matrix 账号可以查看节目列表、点播或控制播放,不能随便留空开放。
admin_users = [
"@admin:666666.xyz",
"@owner:666666.xyz",
]
[paths]
audio_dir = "/tmp/musicbot_audio"
saved_queues_file = "data/saved_queues.json"
[audio]
cache_mode = "size_lru"
cache_max_bytes = 1073741824
cache_delete_after_playback = false
cache_delete_on_shutdown = true
search_mode = "fast"
search_timeout_seconds = 8.0
extractor_retries = 1
download_format = "wav"
audio_quality = "best"
stream_first_idle = true
# 直播电台没有自然结束点,后台预取和失败转下载会让 ffmpeg / yt-dlp 挂住。
stream_prefetch_current = false
stream_retry_to_file_on_fail = false
auto_advance_buffer = 2.0
preroll_silence = 1.0
normalize_audio = false
fade_in_ms = 120
volume_percent = 100
[worker]
max_restart_attempts = 3
heartbeat_interval_seconds = 10.0
skip_cooldown_seconds = 1.0
stop_timeout_restart_threshold = 2
membership_mode = "legacy"
log_max_bytes = 2000000
log_backups = 5
[playlist]
max_tracks_per_request = 50
background_load_concurrency = 4
[logging]
file = "logs/musicbot.log"
clean_enabled = true
clean_file = "logs/musicbot.clean.log"
clean_filter_matrixrtc_noise = true
max_bytes = 2000000
backups = 5
[ui]
show_progress_messages = false
rich_formatting = false
quiet_mode = true关键点:
auto_accept_invites = true:否则机器人收到邀请后不会自动加入房间,房间里发!help也没有反应。[access].allowed_rooms:生产环境建议填写允许控制播放的房间 ID,避免机器人被私聊或陌生房间抢占。[access].admin_users:生产环境必须填写管理员账号;留空时增强补丁会拒绝所有播放控制命令,避免误开放。stream_first_idle = true:空闲时直接用流式播放,适合电台。stream_prefetch_current = false:不要后台预取直播流。stream_retry_to_file_on_fail = false:流式失败后不要改成下载完整文件。membership_mode = "legacy":兼容当前 Synapse / Element Call 栈。cache_mode = "size_lru"+cache_max_bytes = 1073741824:普通歌曲和 Podcast 下载后最多保留 1GB 缓存,超过后删最旧文件;同一集下次再听通常不用重新下载。cache_delete_after_playback = false:配合 1GB LRU 缓存,不在播完立刻删除下载文件。
设置权限:
chmod 644 /root/data/docker_data/matrix-musicbot/config/config.toml五、创建 docker-compose.yaml
创建 Compose 文件:
vi /root/data/docker_data/matrix-musicbot/docker-compose.yaml写入:
services:
matrix-musicbot:
image: ghcr.io/sultanalburaq/matrix-element-call-musicbot:latest
container_name: matrix-musicbot
restart: unless-stopped
environment:
- CONFIG_FILE=/app/config/config.toml
volumes:
- ./config:/app/config:ro
- ./patches/bot.py:/app/bot.py:ro
- ./logs:/app/logs
- ./data:/app/data
- ./cache:/tmp/musicbot_audio
networks:
- matrix
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
networks:
matrix:
external: true
name: matrix这里接入现有 matrix Docker 网络,不需要开放宿主机端口。日志使用 Docker 自带轮转,避免容器日志无限增长。
如果 Docker 主机本身可以直连外网,但 Docker daemon 配了失效代理,拉取 GHCR 镜像时可能看到类似错误:
proxyconnect tcp: dial tcp 10.20.20.6:9666: connect: connection refused这时检查 Docker daemon 的代理环境。例如 Alpine / OpenRC 常见位置:
grep -n 'HTTP_PROXY\|HTTPS_PROXY\|proxy' /etc/conf.d/docker如果旧代理已不可用,可以注释掉后重启 Docker:
rc-service docker restart重启 Docker daemon 会让现有容器短暂重启,操作前应确认业务可接受。
六、为直播电台增加别名文件
原项目支持 !play URL,但每次输入长电台地址很麻烦。推荐把电台保存到独立 JSON 文件里,让 tw1、tw2、jp1 这类名字变成可维护的电台别名。
创建别名文件:
vi /root/data/docker_data/matrix-musicbot/data/radio_aliases.json示例:
{
"dinner1": "http://stream.srg-ssr.ch/m/rsj/mp3_128",
"dinner2": "https://west-mp3-128.streamthejazzgroove.com/stream",
"jazz1": "http://jazzblues.ice.infomaniak.ch/jazzblues-high.mp3",
"jp1": "https://listen.moe/stream",
"relax1": "http://stream.srg-ssr.ch/m/rsc_de/mp3_128",
"study1": "http://stream.zeno.fm/0r0xa792kwzuv",
"tw1": "http://59.120.88.155:8000/live.mp3",
"tw2": "https://stream.pbs.gov.tw/live/TPS/playlist.m3u8",
"tw3": "https://mangoradio.stream.laut.fm/mangoradio",
"tw4": "https://azuracast.conceptradio.fr/radio/8030/stream.mp3",
"tw5": "https://n10.rcs.revma.com/h4ta80hbqwuvv",
"us1": "http://stream-uk1.radioparadise.com/aac-320",
"us2": "https://icecast.walmradio.com:8443/classic"
}设置权限:
chown 10001:10001 /root/data/docker_data/matrix-musicbot/data/radio_aliases.json
chmod 644 /root/data/docker_data/matrix-musicbot/data/radio_aliases.json
python3 -m json.tool /root/data/docker_data/matrix-musicbot/data/radio_aliases.json >/dev/null以后新增或删除电台,只改这个 JSON 文件,不需要再改 bot.py。JSON 的 key 不需要带 !,房间里输入 tw1 或 !tw1 都能触发。
先从镜像里复制原始文件:
docker cp matrix-musicbot:/app/bot.py \
/root/data/docker_data/matrix-musicbot/patches/bot.py如果容器还没启动过,也可以先临时启动一次,复制后再重建。
编辑:
vi /root/data/docker_data/matrix-musicbot/patches/bot.py补丁的目标不是把短命令简单转成 !play,而是让别名统一进入安全换台逻辑:先停止旧直播流、清空队列,再启动新电台。否则正在播放直播流时再次点台,容易回到下载或排队路径。
在 bot.py 顶部补充:
import json并在 logger = logging.getLogger(__name__) 后加入:
RADIO_ALIASES_FILE = Path("data/radio_aliases.json")在 handle_command 前添加读取别名的方法:
def _load_radio_aliases(self) -> dict[str, str]:
try:
raw_aliases = json.loads(RADIO_ALIASES_FILE.read_text(encoding="utf-8"))
except FileNotFoundError:
return {}
except Exception as exc:
logger.warning("Failed to read radio aliases from %s: %s", RADIO_ALIASES_FILE, exc)
return {}
if not isinstance(raw_aliases, dict):
logger.warning("Radio aliases file %s must contain a JSON object", RADIO_ALIASES_FILE)
return {}
aliases: dict[str, str] = {}
for raw_name, raw_url in raw_aliases.items():
if not isinstance(raw_name, str) or not isinstance(raw_url, str):
continue
name = raw_name.strip().lower()
url = raw_url.strip()
if not name or not url:
continue
aliases[name[1:] if name.startswith("!") else name] = url
return aliases找到 handle_command 里的:
command = aliases.get(command, command)
handler = self._command_handlers.get(command)在它前面加入:
alias_name = command[1:] if command.startswith("!") else command
radio_aliases = self._load_radio_aliases()
if alias_name in radio_aliases:
# 电台别名来自 data/radio_aliases.json;新增 jp1/tw3 时不改代码,且换台必须走安全切流逻辑。
await self._switch_radio_stream(room, radio_aliases[alias_name])
return再改 !load 的处理逻辑。找到:
if not tracks:
await self.send_message(room.room_id, f"❌ Saved queue `{name}` is empty")
return
if not await self._join_call_for_room(room.room_id):在中间加入:
saved_sources = [
track.get("source_url")
for track in tracks
if isinstance(track, dict) and track.get("source_url")
]
if len(saved_sources) == 1 and self.audio_queue.looks_like_url(saved_sources[0]):
# 直播电台没有自然结束点;单条 URL 保存队列直接走 !play 的流式路径,避免卡在下载完整音频。
await self._handle_command_internal(room, "!play", saved_sources[0])
return检查语法:
python3 -m py_compile /root/data/docker_data/matrix-musicbot/patches/bot.py这个补丁做了两件事:
tw1、!tw1、jp1、!jp1这类别名都从data/radio_aliases.json读取,不用每次输入长链接。- 单条 URL 保存队列执行
!load时,自动走!play的流式播放路径,避免直播流卡在Loading...。
七、为 Podcast 增加最新一集别名
Podcast 和直播电台不是一类音源。直播电台是持续不断的流,适合放在 radio_aliases.json;Podcast 是有限长度单集音频,适合放在单独的 podcast_aliases.json。
创建:
vi /root/data/docker_data/matrix-musicbot/data/podcast_aliases.json示例:
{
"blg": "https://feed.firstory.me/rss/user/cmjaz594i0000hdvpdpnd4fw8",
"twpo1": "https://feed.firstory.me/rss/user/ckga7ibs77fgl0875bxwgl0y0",
"twpo2": "https://feed.firstory.me/rss/user/cknb77ey7f2ob0853hehms3e9",
"dateline": "https://podcastfeeds.nbcnews.com/dateline-true-crime-weekly"
}这里的 blg 是百靈果 News 的 Podcast 别名,twpo1、twpo2 是另外两个台湾 Podcast RSS,dateline 是 Dateline True Crime Weekly。机器人收到 blg 或 !blg 后,会读取 RSS,取最新一集的 enclosure 音频地址,然后停止当前播放、清空队列,再立即播放这一集。
新增 Podcast 前,先在服务器上测试 RSS 能否访问、能否解析出音频 enclosure。如果某个 RSS 在服务器上出现 TLS、geofence、403 或没有音频 enclosure,就不要写入别名文件,避免房间里输入后报错。
设置权限并检查 JSON:
chown 10001:10001 /root/data/docker_data/matrix-musicbot/data/podcast_aliases.json
chmod 644 /root/data/docker_data/matrix-musicbot/data/podcast_aliases.json
python3 -m json.tool /root/data/docker_data/matrix-musicbot/data/podcast_aliases.json >/dev/null用法:
blg 播放百靈果 News 最新一集
!blg 同上
blg 3 播放第 3 新的一集
twpo1 播放 twpo1 最新一集
twpo2 3 播放 twpo2 第 3 新的一集
dateline 播放 Dateline 最新一集Podcast 别名和电台别名一样按“输入即切换”处理,不会排在当前长节目后面慢慢等。已经下载过的单集仍受 1GB LRU 缓存管理,下次播放同一集时尽量复用本地缓存。
继续添加新的 Podcast 主播时,只要给 podcast_aliases.json 增加一组短名和 RSS 地址:
{
"blg": "https://feed.firstory.me/rss/user/cmjaz594i0000hdvpdpnd4fw8",
"twpo1": "https://feed.firstory.me/rss/user/ckga7ibs77fgl0875bxwgl0y0",
"twpo2": "https://feed.firstory.me/rss/user/cknb77ey7f2ob0853hehms3e9",
"dateline": "https://podcastfeeds.nbcnews.com/dateline-true-crime-weekly",
"newpod": "https://example.com/new-podcast/rss"
}检查 JSON 后重启机器人:
python3 -m json.tool /root/data/docker_data/matrix-musicbot/data/podcast_aliases.json >/dev/null
cd /root/data/docker_data/matrix-musicbot
docker compose restart matrix-musicbot之后在房间里输入:
newpod 播放新 Podcast 最新一集
!newpod 同上
newpod 3 播放第 3 新的一集注意这里要填 Podcast RSS/feed 地址,不是 Apple Podcasts、Spotify、YouTube 或 Firstory 的普通页面地址。RSS 常见形式类似:
https://feed.firstory.me/rss/user/xxxx
https://feeds.buzzsprout.com/xxxx.rss
https://anchor.fm/s/xxxx/podcast/rss如果 RSS 里没有音频 enclosure,机器人会提示 Podcast 解析失败;这通常表示该平台没有在 RSS 中公开 MP3,或 feed 临时不可访问。
实际测试中,百靈果 News 的 RSS 大约 9MB。补丁里的 RSS 读取上限建议至少保留 16MB,并在超过上限时明确报错;不要只读前几 MB,否则 XML 会被截断,可能出现 unclosed CDATA section 这类解析错误。
八、启动和验证
如果使用 Docker 部署包,先在项目目录里跑一次本地校验:
./scripts/validate.sh它会检查增强补丁语法、JSON 示例文件,以及 docker-compose.yaml 是否能被 Compose 正常解析。手工部署时也建议至少执行:
cd /root/data/docker_data/matrix-musicbot
python3 -m py_compile patches/bot.py
python3 -m json.tool data/radio_aliases.json >/dev/null
python3 -m json.tool data/podcast_aliases.json >/dev/null
docker compose config >/dev/null启动:
cd /root/data/docker_data/matrix-musicbot
docker compose up -d检查容器:
docker compose ps
docker logs --tail=100 matrix-musicbot正常日志类似:
Music Bot Core Starting
Startup checks passed
Bot ready如果看到:
PermissionError: [Errno 13] Permission denied: '/app/config/config.toml'说明配置文件或目录权限不对。确认:
chmod 755 /root/data/docker_data/matrix-musicbot/config
chmod 644 /root/data/docker_data/matrix-musicbot/config/config.toml如果看到:
PermissionError: [Errno 13] Permission denied: '/app/logs/musicbot.log'说明日志目录没有给 UID 10001 写入权限:
chown -R 10001:10001 \
/root/data/docker_data/matrix-musicbot/logs \
/root/data/docker_data/matrix-musicbot/data \
/root/data/docker_data/matrix-musicbot/cache生产机当前容器正常时,docker compose ps 应看到 matrix-musicbot 处于 Up / healthy 状态。日志里如果已经在通话中播放,可能会持续出现 MatrixRTC membership 心跳,这不等于启动失败。
九、日常使用
先把机器人邀请进房间:
@musicbot:666666.xyz如果 auto_accept_invites = true,它会自动接受邀请。测试命令:
!help播放电台最简单,带不带 ! 都可以:
tw1或:
!tw2你自己的 Element 客户端必须点击右上角“加入”进入通话,才能听到声音。机器人回:
Joined Element Call
Now playing: live表示机器人已经进通话并开始推音频。
!join 只表示让机器人加入通话,不会让你的客户端加入通话。通常听电台不需要手动发 !join,因为 !tw1 / !tw2 会自动触发机器人加入。
完整命令速查:
基础播放
!help / !h 查看帮助
!join / !j 让机器人加入当前房间的 Element Call
!leave / !lv 让机器人离开 Element Call
!play URL 播放一个音频 URL
!play 搜索词 让 yt-dlp 搜索并播放
!queue / !q 查看当前队列和预计时间
!nowplaying / !np 查看当前播放
!skip / !s 跳过当前曲目
!stop / !x 停止播放并清空队列
!loop / !lp 切换循环模式
!history / !hist 查看最近播放历史
电台别名
!stations / !radios 查看可用电台别名
tw1 / !tw1 播放 tw1 电台
tw2 / !tw2 播放 tw2 电台
jp1 / !jp1 播放 jp1 电台
study1 / !study1 播放 study1 电台
relax1 / !relax1 播放 relax1 电台
us1 / !us1 播放 us1 电台
Podcast 别名
!podcasts / !pods 查看可用 Podcast 别名
blg / !blg 播放百靈果 News 最新一集
blg 3 / !blg 3 播放百靈果 News 第 3 新的一集
twpo1 / !twpo1 播放 twpo1 最新一集
dateline / !dateline 播放 Dateline 最新一集
保存队列
!save 名字 保存当前播放和后续队列
!save 名字 --force 覆盖同名保存队列
!load 名字 加载保存队列并自动加入通话
!queues / !qs 列出当前房间保存过的队列名
!deletequeue 名字 / !dq 名字 删除保存队列
!renamequeue 旧名 新名 / !rq 旧名 新名 重命名保存队列
音频和诊断
!audio / !a 查看当前音频设置
!normalize on|off 开关音量归一化
!fadein 300 设置淡入毫秒数,范围 0-5000
!volume 80 / !v 80 设置音量百分比,范围 0-200
!status / !st 查看机器人状态
!diag / !d 查看诊断信息
!config / !cfg 查看当前配置摘要
!defaults / !df 查看默认配置值保存一组临时歌单
data/saved_queues.json 就是给 !save / !load 用的运行状态文件。它不是电台配置,也不是 Podcast 配置;它只记录某个房间里用户保存过的队列。
举个例子,先排一组晚饭歌单:
!play https://example.com/song-a.mp3
!play https://example.com/song-b.mp3
!play https://example.com/song-c.mp3
!queue
!save dinner这时机器人会把当前正在播的曲目和后续队列保存成 dinner。以后想重新播放这组临时歌单:
!load dinner查看保存过哪些队列:
!queues覆盖同名队列:
!save dinner --force改名:
!renamequeue dinner dinner-jazz删除:
!deletequeue dinner-jazz短写也可以:
!sv dinner --force
!ld dinner
!qs
!rq dinner dinner-jazz
!dq dinner-jazz这个文件按房间分组保存。A 房间里的 dinner 和 B 房间里的 dinner 不是同一个队列。它会包含真实房间 ID 和历史播放 URL,所以属于运行状态文件,不适合写进恢复仓库,也不适合作为公开教程里的固定模板。
这里要分清三个名字来源:
data/radio_aliases.json里的jp2是电台别名。房间里直接输入jp2或!jp2,会安全换台或播放。data/podcast_aliases.json里的blg是 Podcast 别名。房间里直接输入blg或blg 3,会解析 RSS 最新或第 3 新的一集。!save jp2保存的是 MusicBot 的 saved queue。房间里直接输入jp2不会加载这个队列,必须用!load jp2。
所以如果新增的是直播电台,推荐写进 data/radio_aliases.json:
{
"tw1": "http://59.120.88.155:8000/live.mp3",
"tw2": "https://stream.pbs.gov.tw/live/TPS/playlist.m3u8",
"jp2": "https://example.com/jp2/live.mp3"
}这样后续直接输入:
jp2就会按直播电台的安全换台逻辑处理。!save 更适合普通歌曲或有限长度音频队列,不建议把它当作电台别名管理方式。
注意:删除 saved queue 里的 tw1 不会删除电台别名。要取消电台别名,需要从 data/radio_aliases.json 删除对应项,然后重启或重建 matrix-musicbot。
十、推荐操作顺序
听第一个电台:
tw1听第二个电台:
!tw2换台:
!stop
tw2退出:
!leave如果机器人卡在直播流加载或命令无响应,可以在服务器上重启它:
cd /root/data/docker_data/matrix-musicbot
docker compose restart matrix-musicbot这只影响 matrix-musicbot 容器,不影响 Synapse、Postgres、LiveKit、coturn、Element Call、Nginx Proxy Manager 等其它容器。
十一、恢复仓库模板
如果把它纳入 /root/data/docker_data 恢复蓝图,建议至少保存这些文件:
docker_data/matrix-musicbot/docker-compose.yaml
docker_data/matrix-musicbot/config/config.toml
docker_data/matrix-musicbot/data/radio_aliases.json
docker_data/matrix-musicbot/data/podcast_aliases.json
docker_data/matrix-musicbot/patches/bot.py不要保存这些运行产物:
docker_data/matrix-musicbot/config/config.toml 里的真实 access_token
docker_data/matrix-musicbot/logs/
docker_data/matrix-musicbot/cache/
docker_data/matrix-musicbot/data/saved_queues.json
docker_data/matrix-musicbot/data/*.state.json
docker_data/matrix-musicbot/patches/__pycache__/
*.pycconfig.toml 里不要提交真实 token,可以用环境变量占位:
access_token = "${MATRIX_MUSICBOT_ACCESS_TOKEN}"恢复脚本应创建运行目录并修正 UID:
mkdir -p \
/root/data/docker_data/matrix-musicbot/logs \
/root/data/docker_data/matrix-musicbot/data \
/root/data/docker_data/matrix-musicbot/cache
chown -R 10001:10001 \
/root/data/docker_data/matrix-musicbot/logs \
/root/data/docker_data/matrix-musicbot/data \
/root/data/docker_data/matrix-musicbot/cache启动顺序上,先启动 Synapse、LiveKit、Matrix LiveKit JWT Service,再启动 matrix-musicbot。它不需要独立开放端口,只需要能访问 Matrix client API 和 MatrixRTC / LiveKit 配置。
我的恢复仓库里对应模板目前应保持这几类文件:docker-compose.yaml、带 ${MATRIX_MUSICBOT_ACCESS_TOKEN} 占位的 config/config.toml、data/radio_aliases.json、data/podcast_aliases.json、patches/bot.py。恢复脚本要创建 logs、data、cache 并把可写目录交给 UID 10001,否则容器会启动但写日志或缓存时报权限错误。