Centralize authorization into a policy layer so route, field, and user-permission checks all use the same decision point. The frontend now revalidates /v1/me after 403s or dropped connections, and the users page fetches the real role/permission catalog from the backend instead of hardcoding role descriptions. This also tightens field-level protection for sensitive config/template data and avoids exposing user-management controls when auth is off.
The backend and migrations are updated to handle LF/CRLF checkout differences in SQL migration checksums, with compatibility reconciliation for older databases and safeguards to prevent silent drift of previously shipped migrations.
* 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(web): multi-user accounts with fixed admin/operator/viewer roles
- migration 6 adds web_users and copies the existing single admin with
the same id and password hash, so upgrades need no action and existing
sessions stay logged in
- table-driven permission middleware on every business route (default
deny), 403 for missing permission, 401 when logged out
- hooks/override and secrets redacted for non-admins; operators may only
pick registered bilibili accounts for templates
- /v1/web-users management API, /v1/me and self password change
- login rate limit: 5 consecutive failures lock the username for 30s
- revoked sessions cut long-lived websocket/stream responses
Refs #1717
* feat(cli): add `biliup user list` and `biliup user reset-password`
Refs #1717
* feat(web-ui): user management page, account menu and editable login name
- /users page (super admin only): create users, change role, reset
password, disable, force logout, delete; table on desktop, cards on
mobile, with loading/empty/error states
- sidebar filters menu entries by the permissions from /v1/me and shows
a no-access state for pages the role cannot open
- account menu in the sidebar footer with change password and logout,
hidden when --auth is off
- 403 responses show a warning toast instead of redirecting
- login page username is editable (default biliup)
Refs #1717
* feat(web-ui): hide actions the current role cannot perform
Streamer add/edit/delete/pause, hook and override editing, template and
upload actions, bilibili account management and config saving are only
rendered for roles that have the matching permission. Account and type
tree requests are skipped for roles that would get 403.
Refs #1717
* fix(web-ui): wait for permissions on restricted pages, surface pause errors
- pages that need a permission not every role has render a spinner until
/v1/me returns, so roles without it never fire requests doomed to 403
- user management is hidden when --auth is off, with an explanation if
the page is opened directly
- the pause button goes through the shared response handler, so a 403
shows the permission toast instead of failing silently
- permission errors sent as plain text keep their message
Refs #1717
* fix(web-ui): keep user actions reachable on tablet and narrow desktop
Refs #1717
* fix(py): handle the user subcommand in the stream-gears entry point
Refs #1717
Add an in-process mesio downloader using the rust-srec mesio-engine. Introduces crates/biliup-cli/src/server/core/downloader/mesio.rs implementing FLV/HLS pull, timestamp fixes, keyframe indexing, and size/duration-based segmentation with pipeline_common, flv_fix and hls_fix. Wire Mesio into downloader enum/runtime and add UI options and public config docs. Update crates/biliup-cli/Cargo.toml and workspace Cargo.toml/Cargo.lock to include new dependencies and bump version to 1.2.5. Include tests for protocol selection, pipeline behavior and an e2e FLV download. Small helper changes: config enum docs and segment handling.
Add optional tid_v2 across Studio, config/DB, CLI, Web UI, stream-gears,
and Python uploaders so new Bilibili partition IDs can be set alongside
legacy tid. Fixes#1662; related to #1562.
This change adds a recording policy layer that enforces time-window eligibility and excluded title keywords before probing and before recording. It updates the streamer API to surface reasons like OutOfSchedule and TitleExcluded, clamps ffmpeg/segment durations to the configured window, and exposes the last rejection reason from the worker state for the frontend.
启动 Web 服务时自动登记 CLI 指定的 B 站凭据,并为账号登记、刷新和删除统一补上并发去重、原子写入及引用检查。
同时收紧默认监听、管理员初始化、认证路由、静态文件和日志 WebSocket,恢复 server 的 ds_update.log,并避免凭据及上游响应进入日志。
新增按账号查询远程稿件的 API 与 Web 页面,补齐严格分页和响应校验。
关联 biliup/biliup#1624
关联 biliup/biliup#1658
关联 biliup/biliup#724
Make file_size and segment_time optional and normalize/validate their values so segmentation can be disabled. Frontend: send nulls for empty fields and allow empty segment_time via validation; add showClear to inputs. Downloader: extend SegmentInfo with optional danmaku_file_path and propagate it from various downloaders; DanmakuClient::rolling now returns a bool to signal whether a danmaku file was produced. Uploader: add segment_paths helper to include danmaku files in upload/postprocessing, and preserve processed paths; add unit tests. HookStep: stream child process stdout/stderr as raw bytes to terminal and append to a log file (tee), and simplify run/move logic to use explicit path lists. Cargo.toml: bump reqwest to 0.13.4. Tests and minor adjustments added throughout to support these changes.
Introduces a new `loggers_level` field in the server config to allow dynamic adjustment of log levels via the API and UI. Updates the developer UI to reflect the new log level controls and ensures the backend applies changes to the logging filter at runtime. Also bumps the version to 1.1.27.
Introduces tracing_subscriber::reload to enable dynamic log level changes at runtime. Updates the main server initialization and ServiceRegister to accept and store a log handle. Refactors related code to support this feature and removes disabled state from developer UI log level selectors.
Introduces the struct-patch crate for partial config updates and applies it to configuration models. Refactors config access patterns, adds PartialEq to several types, and updates LiveStreamer to use ConfigPatch for override_cfg. Also updates the CI workflow to use macos-15-intel, improves download task cancellation logic, and upgrades @douyinfe/semi-ui and related dependencies in the frontend.
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.
Refactored worker status management to use async RwLock and updated all related methods to be async. Improved file move logic in hook steps to support cross-filesystem moves by falling back to copy+delete when necessary. Updated API endpoints, download/upload logic, and monitor state transitions to be fully async and more robust. Also added a Debug implementation for Credentials to avoid logging sensitive data, and made minor UI tweaks to disable certain developer options.
Refactored download and upload actor implementations into separate modules for better maintainability. Added upload_status field to LiveStreamerEntity and API responses, and updated the frontend to display upload status. Also added Huya protocol config option and improved Huya stream header handling in stream-gears. Minor bug fixes and code cleanups included.
Merged download and upload logs into a single tab in the log viewer and commented out the separate upload log tab. Removed unused and legacy methods from the Python upload and download engine classes. Improved logging and error handling in Rust server modules, including more informative log messages and better context propagation. Updated plugin interface to pass context instead of just URL, and enhanced dictionary filtering in config state. Bumped workspace version to 1.1.12.
Introduces a pause/resume button for streamers in the UI and backend, including API endpoint and status handling. Refactors streamer status display, updates related TypeScript interfaces, and improves modal forms. Also updates @douyinfe/semi-ui and related dependencies to v2.86.0, and bumps workspace version to 1.1.10. Minor logging and trait changes in Rust backend for improved clarity and error handling.
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.
Removed legacy Python backend modules, database models, and related utilities from the biliup package. Migrated configuration and main loop handling to use stream_gears bindings, simplifying the codebase and shifting backend responsibilities to the Rust implementation. Updated the login page to support registration and login via the new API, and adjusted frontend API base export.
Update Cargo.toml
Update Cargo.lock
* 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.