* feat(cli): let serve run on a host-bound listener with a host-owned shutdown ServeOptions gains two optional fields for embedding hosts: - listener: serve on an already-bound socket, so the host knows the actual port (e.g. after falling back to port 0); - shutdown: stop when the given future completes instead of installing Ctrl+C / SIGTERM handlers, which would otherwise take those signals away from the host process. The CLI path is unchanged apart from binding the port before opening the database, so a busy port now fails before data/ is touched. Ref #1721 * feat(desktop): run biliup server in-process, drop PyInstaller sidecar The Tauri app now depends on biliup-cli as a library and runs entry::serve on its own tokio runtime instead of spawning binaries/biliup.exe: - listens on 127.0.0.1:19159, or a free port when that one is taken; the window shows a bundled startup page and switches to the Web UI once GET / answers 200 (startup failures are shown on that page); - data/, ds_update.log, cookies.json and recordings live in app_data_dir(); on first start, data/ left in the install directory by the old sidecar is copied over and the original is kept; - closing the window stops the server and waits for it (up to 10 s); no expect() on exit; - a second launch focuses the running window instead of starting a second server on the same data. Removed: the greet command, the Vite + React scaffold under tauri-app/src, the shell:allow-execute capability, tauri-plugin-shell, tauri-plugin-opener, GBK decoding of sidecar stdout and the bundled binaries/ resource. The Web UI itself is unchanged. Ref #1721 * ci(desktop): build the Tauri app directly, remove biliup.spec The Windows desktop workflow no longer builds a wheel, installs it and runs PyInstaller: it builds the Web UI (embedded into biliup-cli by rust-embed) and then the Tauri app with tauri-action. Renamed pyinstaller-publish.yml to desktop-publish.yml. On release it uploads to the release as before; a manual workflow_dispatch run only builds and uploads the installers as an artifact, without touching any release. The Dockerfile used biliup.spec to tell whether it was built from a checkout (otherwise it clones master); it now checks pyproject.toml. Ref #1721 * ci(desktop): smoke-test the installer on manual runs Only on workflow_dispatch: pretend an old install left data/ in the install directory, install the NSIS package silently, start the app and require GET http://127.0.0.1:19159/ to return 200, the database to be created in the app data directory, the old data/ to be copied there and kept in place, and the server to stop when the window is closed. Ref #1721 * feat(desktop): keep data next to the exe unless it is on the system drive On Windows the data directory is the install directory again, as with the old sidecar, when the executable is not on %SystemDrive%. When it is, the first start asks the user (tauri-plugin-dialog): the app data directory (default), the install directory, or another folder. The choice is saved as {"data_dir": ...} in desktop.json under the app config directory and not asked again; a saved directory that cannot be used is reported on the startup page instead of silently creating a new one. Closing the dialog quits. Other platforms have no drive letters and install into read-only locations, so they keep using the app data directory (or data_dir from desktop.json) without asking. When the chosen directory has no data/ yet, data/ left by an older version is copied there and kept in place. Besides the install directory, Windows also looks where the old bbup-app installers put the app (their registry keys and %LOCALAPPDATA%\bbup-app), since a new product name installs into a new directory. The data directory is resolved on a separate thread because the dialog blocks. The migration helpers move to data_dir.rs unchanged. Ref #1721 * chore(desktop): replace the template names with biliup - productName bbup-app -> biliup (installers biliup_<version>_x64-setup.exe and biliup_<version>_x64_en-US.msi, NSIS default install directory %LOCALAPPDATA%\biliup, Start menu entry biliup) - identifier com.tauri-app.app -> com.biliup.desktop (app data directory %APPDATA%\com.biliup.desktop, which is the default data directory offered on the system drive) - Cargo package tauri-app -> biliup-desktop (executable biliup-desktop.exe, so it is not confused with the biliup CLI), lib tauri_app_lib -> biliup_desktop_lib, drop the template authors - npm package name, workflow artifact name and the README download link Tauri derives the NSIS uninstall/registry keys and the MSI upgrade code from the product name, so the new installers do not replace an installed bbup-app; both show up in Apps & features. The app copies data/ from the old bbup-app install directory on first start (see the previous commit), after which bbup-app can be uninstalled; its uninstaller does not delete data/. Ref #1721 * ci(desktop): bump the workflow actions to their latest majors actions/checkout v4 -> v7, actions/setup-node v4 -> v7, actions/upload-artifact v4 -> v7 (Node 24 runtimes; the other breaking changes are about fork checkouts in pull_request_target, caching driven by a packageManager field and single-file uploads, none of which this workflow uses). Swatinem/rust-cache@v2 and dtolnay/rust-toolchain@stable already track the latest release. tauri-apps/tauri-action v0 -> v1. v1 updates the name and body of an existing published release it finds by tagName with releaseName and releaseBody, which are empty here and would wipe the release notes, so the release job now passes releaseId from the release event instead; with releaseId the action uploads to that release without looking it up. Ref #1721 * ci(desktop): smoke-test the new data directory rules on manual runs Replaces the manual-run smoke step from the earlier smoke-test commit and can be dropped together with it. On the Windows runner: - install the v1.2.8 bbup-app NSIS package into C:\old-bbup-app and leave a data/ there; - install biliup into its default directory on the system drive (with an old data/ in it); both products stay installed side by side; - first start shows the data directory dialog and does not start the server; UI Automation clicks the default button (the dialog text and a screenshot are kept as evidence), then GET / must return 200, the database and the copied data/ must be in %APPDATA%\com.biliup.desktop, the original kept and the choice saved in desktop.json; - a second start must not ask again; a preset desktop.json pointing at another directory stands in for "choose another folder"; - reinstall on D: (or a subst drive when the runner has none): no dialog, database and log in the install directory, data/ copied from the old bbup-app directory found through its registry key; - uninstalling bbup-app keeps its data/. Ref #1721 * Revert "ci(desktop): smoke-test the new data directory rules on manual runs" This reverts commit 860c45e89f8e5dab11468c83db7c623b7304e4dd. * Revert "ci(desktop): smoke-test the installer on manual runs" This reverts commit b3831f014a2b37f81b71c96e8229a6254bee1b9c.
🛠️ 功能
- 提供 skill,让你的 Agent 成为 up 主:
npx skills add biliup/biliup - 开箱即用,多种安装方式,提供可视化 WebUi 界面
- 多主播录制/上传,24X7 无人值守运行,高自定义元信息
- 录制同时抓取弹幕,输出 XML 弹幕文件
- 正在录制的直播间可在 WebUI 内直接预览:复用正在写盘的那一路流(不另外拉流),带封面、实时弹幕与写盘码率曲线,支持多路同屏监视
- 作为自动化流程中的命令行工具封装使用
- 边录边传 0 落盘
论坛:BBS
📺 支持平台
内置 19 个直播平台解析,未匹配的地址会交给通用适配器(依赖本机的 yt-dlp / Streamlink)尝试处理。
| 平台 | 站点 | 弹幕 |
|---|---|---|
| 哔哩哔哩 | live.bilibili.com、b23.tv |
✅ |
| 抖音 | douyin.com |
✅ |
| 斗鱼 | douyu.com |
✅ |
| 虎牙 | huya.com |
✅ |
| 快手 | kuaishou.com、chenzhongtech.com |
|
| AcFun | acfun.cn |
|
| 网易 CC | cc.163.com |
|
| 映客 | inke.cn |
|
| 猫耳 FM | missevan.com |
|
| KilaKila / 红豆 FM | live.kilakila.cn、hongdoufm.com |
|
| YY | yy.com |
|
| TTingLive | ttinglive.com |
|
| Twitch | twitch.tv(直播与录像) |
✅ |
| YouTube | youtube.com、youtu.be |
✅ |
| TwitCasting | twitcasting.tv |
✅ |
| niconico | nicovideo.jp |
|
| AfreecaTV | afreecatv.com |
|
| Bigo Live | bigo.tv |
|
| Picarto | picarto.tv |
|
| 通用适配器 | 其他 http(s) 地址 |
📜 更新日志
Important
Disclaimer / 免责声明
- 本项目仅供个人学习研究,不保证稳定性,不提供技术支持
- 使用本项目产生的一切后果由用户自行承担
- 禁止商业用途,请遵守版权及平台规定
- This project is for personal learning and research purposes only
- No stability guarantee or technical support provided
- Users are solely responsible for any consequences of using this project
- Commercial use is strictly prohibited
- Please respect copyright and platform ToS
📜 使用文档
B 站命令行投稿工具,支持短信登录、账号密码登录、扫码登录、浏览器登录以及网页Cookie登录,并将登录后返回的 cookie 和 token 保存在 cookies.json 中,可用于其他项目。
- 下载 Release: biliupR
- 获取命令帮助
biliup --help - 登录信息文件可用
-u/--user-cookie指定,便于多账号切换
文档地址:https://biliup.github.io/biliup-rs
Upload video to bilibili.
Usage: biliup [OPTIONS] <COMMAND>
Commands:
login 登录B站并保存登录信息
renew 手动验证并刷新登录信息
upload 上传视频
append 是否要对某稿件追加视频
show 打印视频详情
comments 查看视频评论
reply 回复视频评论,默认只打印将要回复的内容
dump-flv 输出flv元数据
download 下载视频
server 启动web服务,默认端口19159
season 管理自己的合集:列合集、查小节、加入 / 移出稿件、排序
user 管理 Web 界面的登录用户(在 biliup 服务的工作目录下执行,直接读写 data/data.sqlite3)
list 列出所有已上传的视频
help Print this message or the help of the given subcommand(s)
Options:
-p, --proxy <PROXY> 配置代理
-u, --user-cookie <USER_COOKIE> 登录信息文件 [default: cookies.json]
--rust-log <RUST_LOG> [default: tower_http=debug,info]
-h, --help Print help
-V, --version Print version
启动录制服务
启动web服务,默认端口19159
Usage: biliup server [OPTIONS]
Options:
-b, --bind <BIND> Specify bind address [default: 127.0.0.1]
-p, --port <PORT> Port to use [default: 19159]
--auth 开启登录密码认证
--secure-session-cookie 为会话 Cookie 附加 Secure 属性。仅当通过 HTTPS 反向代理访问 Web UI 时开启; 直接通过 HTTP 远程访问时开启会导致浏览器丢弃登录态
-c, --config <FILE> 使用 biliup 1.0.7 风格配置文件启动录制
-h, --help Print help
Important
自 #1660 起,
--bind的默认值由0.0.0.0改为127.0.0.1,即默认只监听本机,局域网/公网无法直接访问。 如需从其他设备访问,请加上--bind 0.0.0.0 --auth,详见下方「🔓 远程访问」一节。Docker 镜像已内置该参数,不受影响。
单独下载一场直播/视频,无需启动服务:
biliup download <URL> -o "./video/%Y-%m-%dT%H_%M_%S{title}" --split-time 1h
管理自己的合集(需要先 biliup login,所有子命令都支持 --json):
biliup season list # 列出合集和小节 ID
biliup season sections <合集ID> # 查看各小节里的稿件及其 episode ID
biliup season add <小节ID> --vid BV1xx411c7mD # 加入稿件,cid 和标题自动获取;--vid 可重复
biliup season remove <episode ID> # 移出稿件
biliup season sort <小节ID> <episode ID>... # 列出的稿件按顺序排到最前,其余保持原顺序;或用 --reverse 整体倒序
--split-size 与 --split-time 可按体积或时长自动分段,-o 支持 {title} 占位符与 strftime 时间格式。
🚀 快速开始
Windows
- 下载 Release 中的桌面版安装包 biliup_*_x64-setup.exe
Linux 或 macOS
- 安装 uv
- 安装:
uv tool install biliup - 启动:
biliup server --auth - 访问 WebUI:
http://127.0.0.1:19159(默认只监听本机,远程访问见下方说明)
- 后台运行
nohup biliup server --auth &- 请查看参考
Termux
- 详见Wiki
Note
默认下载器
mesio(rust-srec 引擎)和可选的stream-gears都由 Rust 实现、编进 biliup,无需外部依赖。若配置ffmpeg下载器或使用后处理,需要本机安装ffmpeg;YouTube、niconico 等平台与通用适配器则依赖yt-dlp或streamlink。Docker 镜像已内置ffmpeg。
🔓 远程访问(监听 0.0.0.0)
默认的 127.0.0.1 只允许本机访问。需要从其他设备访问时,显式指定 --bind 0.0.0.0 并开启 --auth:
biliup server --bind 0.0.0.0 --auth
首次打开 http://your-ip:19159 会引导设置管理员密码(用户名固定为 biliup),之后即可正常登录使用。
Note
绑定非回环地址时必须同时开启
--auth,否则会拒绝启动,避免无认证的 Web API 被暴露:refusing to expose the unauthenticated Web API on 0.0.0.0:19159; use a loopback bind address or enable --auth
Warning
将 Web UI 暴露到公网存在风险,建议仅在可信局域网内使用,或置于反向代理之后。 首次访问即可设置管理员密码,请在启动后立即完成初始化,避免被他人抢先占用。 若通过 HTTPS 反向代理访问,请加上
--secure-session-cookie;直接以 HTTP 远程访问时不要加,否则浏览器会丢弃登录态(见 #1669)。
Docker
镜像已内置 --bind 0.0.0.0 --auth,开箱即用,无需额外配置:
docker compose up -d
打开 http://your-ip:19159 设置管理员密码即可。录播与配置默认持久化在容器的 /opt 卷中。
Important
若要自定义
command,必须带上--bind 0.0.0.0。容器内若监听127.0.0.1,宿主机的端口映射无法转发进容器,Web UI 将完全无法访问。
📤 边录边传(sync-downloader)
把 downloader 设为 sync-downloader 后,ffmpeg 会把直播流 remux 成 Matroska 写到 stdout,按 UPOS 分片一边录一边上传,每录满 file_size(默认 2.5 GB,向上对齐到 10 MiB)就作为一 P 追加到同一稿件。前提:
- 本机
PATH中有ffmpeg;HLS 流(B 站bili_protocol = "hls_fmp4")若装有streamlink会用它拉流再交给 ffmpeg,没有则由 ffmpeg 直拉。 - 主播必须绑定上传模板,且模板对应的 cookies 文件可用;
uploader = "Noop"或没有模板时不会录制,日志会给出边录边传需要先为主播设定上传模板。 - 上传并发固定 3 线程,不受
threads、segment_time控制。
downloader = "sync-downloader"
uploader = "bili_web"
file_size = 2621440000 # 每 P 大小,可按上传带宽调小
# sync_save_dir = "/data/sync" # 可选:额外保留每 P 的本地副本
[streamers."某主播"]
url = ["https://live.bilibili.com/1234"]
title = "{streamer}%Y-%m-%d 直播录像"
tid = 171
user_cookie = "cookies.json"
行为说明:
- 录制期间每 P 会同时写入系统临时目录(
$TMPDIR/biliup-sync/worker-<id>/)作为兜底;预传完整且校验一致时直接 complete,否则(直播提前结束、上传落后)按实际长度从临时文件重传。投稿确认后临时文件删除,设置了sync_save_dir的副本保留并交给postprocessor。 - 停止/暂停/编辑主播只会结束当前分段,已录内容仍会上传并投稿;上传或投稿失败时保留有内容的分段文件并在日志中打印路径,可手动补传。
- B 站直链约 1 小时过期。分段结束后拉不到数据时会立刻交回监控循环重新解析直链,并在同一稿件上继续追加分 P。
- 排查问题时留意
ERROR ... 下载流程出错日志:会带上具体原因(cookies 文件路径、preupload 拒绝等),而不是静默退回落盘录制。
🧑💻开发
架构概览
Rust后端 + 精简 Python 包 + Next.js前端的混合架构。
graph TB
subgraph "🌐 前端层"
UI[Next.js Web界面<br/>React + TypeScript<br/>Semi UI组件库]
end
subgraph "⚡ Rust后端服务"
CLI[命令行与 Web API<br/>biliup-cli<br/>REST API / WebUI / 配置导入]
CORE[核心库<br/>biliup<br/>直播解析 / 下载 / 上传]
DANMAKU[弹幕库<br/>danmaku<br/>多平台协议 / XML输出]
GEARS[Python绑定<br/>stream-gears<br/>python -m biliup 入口]
end
subgraph "🐍 Python包"
PYENTRY[最小入口<br/>biliup.__main__<br/>调用 stream_gears.main_loop]
PYUPLOAD[投稿库<br/>bili_webup / bili_webup_sync<br/>供外部项目调用]
end
subgraph "🗄️ 数据层"
DB[(SQLite数据库<br/>配置存储<br/>任务状态 & 日志)]
FILES[文件系统<br/>视频分段 / 弹幕XML<br/>缓存与临时文件]
end
subgraph "🌍 外部服务"
BILI[Bilibili API<br/>视频上传服务]
STREAMS[直播平台<br/>B站/斗鱼/虎牙/抖音/Twitch等]
end
UI --> CLI
CLI --> CORE
CLI --> DANMAKU
CLI --> DB
CLI --> FILES
CORE --> STREAMS
CORE --> BILI
DANMAKU --> STREAMS
DANMAKU --> FILES
GEARS --> CLI
PYENTRY --> GEARS
PYUPLOAD --> BILI
style UI fill:#e1f5fe
style CLI fill:#f3e5f5
style CORE fill:#f3e5f5
style DANMAKU fill:#f3e5f5
style GEARS fill:#f3e5f5
style PYENTRY fill:#e8f5e8
style PYUPLOAD fill:#e8f5e8
style DB fill:#fff3e0
style FILES fill:#fff3e0
style BILI fill:#ffebee
style STREAMS fill:#ffebee
目录结构
| 路径 | 说明 |
|---|---|
crates/biliup |
核心库:直播解析、下载器、B 站投稿与凭据管理 |
crates/biliup-cli |
命令行与 Web 服务:REST API、WebUI 托管、录制调度 |
crates/danmaku |
弹幕客户端:多平台协议解析与 XML 输出 |
crates/stream-gears |
PyO3 绑定,暴露给 python -m biliup |
app、public |
Next.js WebUI 源码;npm run build 产物输出到 out/ 并由后端内嵌 |
biliup |
精简 Python 包:最小入口与可供外部调用的投稿库 |
tauri-app |
桌面端外壳(实验性) |
frontend
- 确保 Node.js 版本 ≥ 18.17(Next.js 14 要求)
- 安装依赖:
npm i - 启动开发服务器:
npm run dev - 访问:
http://localhost:3000
Python
- 安装依赖
maturin dev npm run build- 启动 Biliup:
python3 -m biliup
Rust-cli
npm run build- 构建
cargo build --release --bin biliup - 开发启动 BiliupR:
cargo run
Note
biliup-cli通过rust-embed内嵌前端产物目录out/,因此在cargo build/cargo test之前必须先执行npm run build,否则编译会因out/不存在而失败。
测试
cargo test -p biliup -p biliup-cli -p danmaku
🤝Credits
- Thanks
ykdl, youtube-dl, streamlinkprovides downloader. - Thanks
THMonster/danmaku.
💴捐赠
