* fix(build): restore editable installs after stream_gears packaging change
Editable installs only put python-source (crates/stream-gears) on sys.path and skip include, so the root biliup/ package was unimportable after maturin develop / pip install -e . Add crates/stream-gears/biliup/__init__.py, which loads the root package under the same name. Wheels are unchanged: maturin only walks stream_gears/ and the include globs, which match the root biliup/ first.
* test(stream-gears): cover editable installs
test_wheel_ships_stubs only checks RECORD for regular installs, since an editable install's RECORD lists the .pth. A new test puts only python-source on PYTHONPATH and checks that biliup and biliup.__main__ resolve to the root package.
* build: move biliup/ and pyproject.toml into crates/stream-gears
Editable installs (`maturin develop`, `pip install -e`) only put
`python-source` on sys.path and skip `include`, so with `biliup/` at the
repository root they could not import it. With `pyproject.toml`,
`biliup/` and `stream_gears/` in the same directory, `biliup` goes in
through `python-packages`, which editable installs honour.
- `biliup/` is moved unchanged; the loader added earlier in this PR is
removed because that path is now the real package.
- `readme` and `license` point at the repository root, so the wheel's
METADATA and `licenses/LICENSE` stay the same.
- CI, Termux and the Dockerfile build with
`-m crates/stream-gears/Cargo.toml`.
Ref #1732
* docs: point source install commands at crates/stream-gears
* 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.
* fix(stream-gears): write the cached GOP on disconnect, flush before the segment hook
The httpflv loop kept the current GOP in `flv_tags_cache` and only wrote it
when the next keyframe arrived. On EOF, a 30 s read timeout or a parse error
the function returned and the cache was dropped, so every disconnect,
reconnect and stream end lost the last 1-10 s. The loop now runs in an inner
function; whatever way it exits, the complete tags in the cache are written
before the original result (including the error) is returned.
`FlvFile` / `TsFile` renamed the `.part` file and ran the segment hook before
the old `BufWriter` was flushed, so the hook (FileValidator, upload) could see
a truncated file, and a failed final flush (disk full) was swallowed. Both now
go through `finish()`: flush and check the error, then rename, then run the
hook. `create_new` returns the flush error; `Drop` logs it with `error!`.
Tests: the rolling-segment test now expects 120 keyframes on disk (was 119)
and checks the size seen by the hook equals the final size; new cases for a
stream that ends cleanly, a read that times out and a parse error; a TS hook
size test; a failed-flush test.
Ref #1726
* feat(recorder): default to mesio when no downloader is configured
Rooms without a `downloader` setting followed the plugin hint, which is
stream-gears for almost every platform. They now use mesio: its FLV output
carries `onMetaData.keyframes` and every segment starts at timestamp 0, so
players can seek; it also records HEVC / Enhanced-FLV and HLS fMP4, which
stream-gears cannot. Only the hint mapping in `core/live.rs` changes; an
explicit `stream-gears` keeps using stream-gears, and plugins that hint
streamlink / yt-dlp are unaffected.
`DownloaderRuntime::from_type` no longer has a catch-all arm. `ffmpeg-external`
and `ffmpeg-internal` used to fall into it and silently run stream-gears; both
now run ffmpeg (external segmenting, same as `ffmpeg`). The arm for
streamlink / yt-dlp / ytarchive, which need the live stream and are built in
`downloader_runtime`, is listed explicitly and logs a warning.
WebUI, README, sample configs and CHANGELOG now say mesio is the default and
list the behaviour differences: the container follows the source (HLS fMP4 is
saved as .mp4), files are written under their final name without `.part`, and
Douyu Wangsu reconnects leave a 2.6-5.8 s overlap between segments.
Ref #1726
* feat(mesio): pass segment duration and size to the segment callback
mesio's segment-complete callback reports the duration and byte size of each
closed file, but biliup only logged them and built `SegmentInfo` with the path
and index. `SegmentInfo` gains `duration_secs` / `size_bytes` (None for the
other downloaders) and mesio fills them in. The end-to-end mesio test checks
the reported size equals the file size on disk.
Ref #1726
* fix(recorder): parse segment_time the same way in every downloader
`segment_time` was read three different ways. stream-gears indexed
`parts[1]` / `parts[2]` directly, so "3600" or "01:00" panicked the download
task (and an unparsable hour silently became 1); mesio returned 0 for anything
that was not HH:MM:SS and silently recorded without time splits; ffmpeg got
the raw string and accepted both forms.
`parse_segment_time` follows ffmpeg's duration syntax (`[HH:]MM:SS[.frac]`
or plain seconds; minutes and seconds below 60 when colons are used), so all
three downloaders now agree. stream-gears and mesio share
`DownloadConfig::segment_time_limit`: 0 means no time split for both (mesio
already did this; stream-gears used to split at every keyframe), and a value
that still cannot be parsed logs a warning and records without time splits
instead of panicking or being ignored silently. The time-range clamp uses the
same parser, so "3600" is shortened near the window end like "01:00:00".
Ref #1726
* feat(webui): enter file_size as a number with an MB/GB unit
The config still stores bytes. The control converts with 1024 (the same
sizes Windows Explorer shows), keeps an untouched value byte-exact even
when it is not a round MB/GB, and re-picks the unit when the form value
is replaced from outside.
In the streamer override, clearing a value that was already set now
saves null (no size split for that streamer); before, Semi dropped the
emptied key and the old value stayed. Clearing something typed in the
same session still falls back to inheriting the global setting.
* fix(webui): keep the file_size unit beside the number in narrow modals
* feat(uploader): public season API handle and BV lookup for archive view
- `SeasonApi` becomes public: `BiliBili::season_api()` returns it, and a
`#[doc(hidden)]` `SeasonApi::with_hosts` points it at other hosts so
callers outside the crate (the CLI tests) can use a local fake server.
The `BiliBili` struct itself is unchanged.
- `archive_view_by_vid(&Vid)` queries the public view endpoint with either
`aid` or `bvid`, so a BV number does not need a separate lookup.
Ref #1721
* feat(cli): biliup season subcommands
`biliup season list | sections <season_id> | add <section_id> --vid … |
remove <episode_id> | sort <section_id> [episode_id…] [--reverse]`, all with
`--json`. `add` fetches cid and title through the public view endpoint.
`sort` puts the listed episodes first and keeps the rest in their current
order, since B站 requires every episode of the section in the request.
The logic lives in `season_cli.rs`; dispatch only gains one match arm in
`main.rs` and in the copy in `stream-gears/src/server.rs`.
Ref #1721
* docs: list season and user subcommands in README and SKILL.md
Ref #1721
Update workspace package version from 1.2.5 to 1.2.6 in Cargo.toml and synchronize package versions in Cargo.lock (biliup, biliup-cli, danmaku, stream-gears). Also add a README bullet noting streaming-upload without local save (边录边传 0 落盘).
This change updates the server default bind to 127.0.0.1 for safer local-only access while documenting how to expose the Web UI via --bind 0.0.0.0 --auth for remote or Docker use. It also removes the previous restriction that blocked first-time admin bootstrap on non-loopback addresses, allowing authenticated remote initialization and bumping the workspace version to 1.2.4.
The star history chart in the README is no longer loading because the upstream API it depended on stopped working. Point the chart and its link to the star-history service hosted at star-history.dera.page, which uses a different data source and requires no API key, so the chart renders again for everyone.
This keeps the same query and hash parameters as before, so only the domain in the two URLs changes.
Remove legacy engine and many plugin modules, refactor upload plugins to standalone classes, and simplify package entry points. __init__.py now provides a safe __version__ fallback; __main__.py directly invokes stream_gears.main_loop. BiliWeb/BiliWebAsync plugins were adapted to use a FileInfo NamedTuple and no longer depend on engine.UploadBase/Plugin decorator. Documentation updated (README expanded with new commands and CLI/SKILL integration) and a new SKILL.md added. Workspace version bumped to 1.2.1 in Cargo.toml (lock updated accordingly).
Introduced a new cover_downloader module in the downloader core. Updated several dependencies in Cargo.toml and Cargo.lock, including major upgrades to image processing, HTTP, and async libraries. Adjusted related code in util, download, plugin, and uploader modules to support new features and dependency changes.
Updated the GitHub Actions release workflow to include Node.js setup and frontend build steps. Also updated the README to clarify the Windows release download link and removed extra blank lines in the disclaimer section.
Removed biliup/config.py and refactored all plugin and downloader classes to accept a config parameter, passing configuration explicitly instead of relying on a global import. Updated Rust backend to pass config objects to Python plugins and added a OnceConfig Python class for config access. Introduced a GitHub Actions release workflow. Updated version to 1.1.26 and added a disclaimer to the README. Minor bug fixes and improvements in Rust uploader and config handling.
Refactored the DownloadTask::execute method to return DownloadStatus and adjusted its visibility. Enhanced DActor message handling to update stream info after download execution. Updated README and introduction guide with improved instructions for background running and systemd service configuration.
Introduces a new API endpoint `/v1/streamer-info/files/{id}` to fetch file lists for a specific streamer, and updates the frontend to fetch file lists dynamically per row. Also updates serialization for streamer date fields, improves comments and error handling, and changes the default downloader type for plugins. Minor documentation and code cleanup included.
Migrates the YY plugin from Python to Rust, implementing it under crates/biliup-cli/src/server/core/plugin/yy.rs and registering it in the service register. Removes the old Python plugin. Refactors downloader instantiation logic into DownloadPlugin, and updates header construction utility. Updates CLI and README to clarify the --auth option. Cleans up duplicate code in stream-gears and synchronizes workspace version numbers.
Refactored tracing initialization from lib.rs to server.rs, ensuring logging setup occurs only when the server starts. Updated README and docker-compose.yml to reflect new server startup command and options for authentication.
Moved and refactored server-related modules from stream-gears to biliup-cli, including API endpoints, configuration, core logic, and infrastructure. Replaced usage of anyhow with error-stack and custom AppError/AppResult types throughout the codebase. Updated dependencies in Cargo.toml and Cargo.lock, and adjusted code to use new error handling and module paths. Removed obsolete modules and files from stream-gears, and updated README and workspace version.
Introduces a new put_configuration handler to allow updating configuration via the /v1/configuration endpoint. Updates the router to support PUT requests, modifies the README to improve image rendering, and bumps the workspace version to 1.1.3.
Introduces endpoints for QR code-based login and user management in the stream-gears server. Adds support for creating, deleting, and listing users, as well as endpoints for QR code generation and login via QR code. Refactors configuration management to use a global LazyLock, updates model serialization for streamer hooks, and improves context and service registration to support stateless clients. Also updates the frontend to handle new user and QR code flows, and adds an image resource for donation display in the README.
Updated stream-gears crate version to 1.0.7 in Cargo.toml and Cargo.lock. Revised README to use 'uv' for installation and updated backend dependency installation instructions to use 'maturin dev'.
Updated stream-gears crate version from 1.0.5 to 1.0.6 in Cargo.toml and Cargo.lock. Also changed the image URL in README.md from docs.biliup.me to docs.biliup.rs.
Added a forum link to the README for user reference. Removed the 'quickjs' package from the dependencies in pyproject.toml, likely because it is no longer required.
* feat: 新增重试上传次数限制
* feat: 新增上传后WebHook设置选项
* feat: 新增上传webhook逻辑
* mod: 将功能配置移至直播配置中的更多设置
* mod: 修改webhook传输的信息
* mod: 修正错误的数据类型
Refactor webhook upload logic and update build configs
Replaces the 'uploaded_webhook' field with a 'webhook' postprocessor in the upload workflow, updating both backend and frontend to support this change. Updates the Tauri app to use the correct resource path for the sidecar binary, adjusts process management, and modifies build and workflow scripts for improved compatibility. Also bumps the 'stream-gears' crate version to 1.0.1 and adds '_internal' to .gitignore.
Update pyinstaller-publish.yml
Fix pyinstaller copy metadata (#1357)
* Update tauri.conf.json
* Update biliup.spec
Update pyinstaller-publish.yml
feat: 新增上传重试次数限制和上传结果webhook通知 (#1355)
* feat: 新增重试上传次数限制
* feat: 新增上传后WebHook设置选项
* feat: 新增上传webhook逻辑
* mod: 将功能配置移至直播配置中的更多设置
* mod: 修改webhook传输的信息
* mod: 修正错误的数据类型
Refactor webhook upload logic and update build configs
Replaces the 'uploaded_webhook' field with a 'webhook' postprocessor in the upload workflow, updating both backend and frontend to support this change. Updates the Tauri app to use the correct resource path for the sidecar binary, adjusts process management, and modifies build and workflow scripts for improved compatibility. Also bumps the 'stream-gears' crate version to 1.0.1 and adds '_internal' to .gitignore.