Noah 6c06b85b1c feat(desktop): run biliup server in-process, drop PyInstaller sidecar (#1731)
* 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.
2026-09-24 07:28:02 +00:00
2025-07-16 03:43:05 +08:00
2023-12-08 23:37:40 +08:00
2023-12-31 23:56:40 +08:00
2024-01-17 22:15:17 +08:00
2026-09-23 15:41:52 +00:00
2024-01-27 07:46:15 +00:00
2019-07-28 17:54:29 +08:00

biliup

Python PyPI PyPI - Downloads License Telegram

GitHub Issues GitHub Stars GitHub Forks

🛠️ 功能

  • 提供 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

Linux 或 macOS

  1. 安装 uv
  2. 安装:uv tool install biliup
  3. 启动:biliup server --auth
  4. 访问 WebUI:http://127.0.0.1:19159(默认只监听本机,远程访问见下方说明)

Termux

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

  1. 确保 Node.js 版本 ≥ 18.17(Next.js 14 要求)
  2. 安装依赖:npm i
  3. 启动开发服务器:npm run dev
  4. 访问:http://localhost:3000

Python

  1. 安装依赖 maturin dev
  2. npm run build
  3. 启动 Biliup:python3 -m biliup

Rust-cli

  1. npm run build
  2. 构建 cargo build --release --bin biliup
  3. 开发启动 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, streamlink provides downloader.
  • Thanks THMonster/danmaku.

💴捐赠

爱发电 »

⭐Stars

Star History Chart

S
Description
自动直播录制、投稿、twitch、ytb频道搬运工具。命令行投稿(B站)和视频下载工具,提供多种登录方式,支持多p。边录边传0落盘
https://biliup.github.io/biliup/
Readme MIT
6.7 MiB
0 Stars 1 Watchers 0 Forks
Languages
Rust 75.6%
TypeScript 16.6%
Python 4.8%
SCSS 2%
JavaScript 0.4%
Other 0.5%