Root cause: display-only cloud library filtering was reused by scan jobs, merged cloud mounts could be skipped, and OpenList listing relied on WebDAV/first-page behavior that could cap huge directories around 100 items. Cloud scans also let new items consume probe budget before existing rows with missing track/artwork metadata.\n\nChanges:\n- split display filtering from scannable cloud filtering so merged cloud mounts still scan\n- add OpenList API pagination with WebDAV fallback\n- prioritize existing cloud media missing metadata before new imports\n- restrict automatic cloud sync to one successful 19:00-21:00 daily window and keep manual scan immediate\n- disable startup cloud full-scan by default, with an explicit opt-in setting\n- improve Emby/cloud playback compatibility and cache/search/test coverage from the continued work
Add an admin toggle playback.direct_only that offloads all decoding to the
client. When enabled:
- Emby PlaybackInfo no longer advertises SupportsTranscoding nor a
TranscodingUrl, forcing Emby/Infuse/Yamby clients to direct play.
- HLS endpoints refuse (ErrTranscodeDisabled) so the host never spawns ffmpeg.
- Web player forces direct play, hides the HLS toggle, and surfaces a hint.
Exposed via /system/info (direct_play_only) and the Settings page.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add an admin toggle playback.direct_only that offloads all decoding to the
client. When enabled:
- Emby PlaybackInfo no longer advertises SupportsTranscoding nor a
TranscodingUrl, forcing Emby/Infuse/Yamby clients to direct play.
- HLS endpoints refuse (ErrTranscodeDisabled) so the host never spawns ffmpeg.
- Web player forces direct play, hides the HLS toggle, and surfaces a hint.
Exposed via /system/info (direct_play_only) and the Settings page.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add telegram.registration_enabled setting (default off); admins toggle via
Settings page or /registration on|off bot command.
- Add /register (/reg /signup) bot command: when enabled, regular users can
create a MediaStation account and auto-bind their Telegram. Reuses AuthService
(username-taken / user-limit handling) and keeps new accounts as regular users.
- Regular users still limited to bind / adult-toggle / start / help; all other
commands remain admin-only.
- Update /start and /help text to surface registration when enabled.
- Remove the duplicate 最近入库 module from the 运行状态 (stats) page; the homepage
already shows recently added.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Previously organize only exposed a single 'target dir' that was actually
the destination, conflating 源目录 (where files to organize live) with
目的地目录 (where organized files go). Add an explicit source directory:
- OrganizeOptions gains SourcePath; DestPath replaces the old TargetPath
(destination) for clarity. New organize.source_dir setting + source_path
request override; resolveSourceRoot falls back to library path.
- OrganizeLibraryWithOptions only organizes media located under the source
root, so operators can point at a specific download/staging folder and
organize into a distinct destination.
- Handler accepts source_path/dest_path (target_path kept as a deprecated
alias for the destination, backward compatible).
- Settings page splits into 整理源目录(待整理) + 整理目的地目录; Tools organize
panel exposes 源目录 + 目的地目录 inputs with clear copy.
Defaults are unchanged (source = destination = library path) so existing
setups behave identically. Adds a regression test that organize is scoped
to the source directory.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Organizer: add move/copy/hardlink/symlink transfer modes (default move),
per-request target_path/transfer_mode overrides, and honor organize.target_dir
/ organize.transfer_mode settings.
- keep_seeding (default on): escalate move->hardlink (cross-device->copy) so the
qBittorrent source stays in place and continues seeding after organize.
- qBittorrent SetLocation + POST /downloads/relocate to migrate whole torrents
while keeping them seeding.
- Scanner: FileID (device:inode) hardlink dedup to avoid duplicate recognition
and double-counted storage; extract single-file ingest.
- Watcher: recursive watch + incremental per-file ingest/remove instead of full
re-scan; periodic full library scan now gated behind scan.periodic_enabled
(default off) to reduce disk wear.
- Telegram bot: handle callback_query in polling, declare allowed_updates in
webhook, answer callbacks.
- Frontend: settings for transfer mode / keep_seeding / periodic scan; organize
panel target dir + transfer mode overrides.
- Tests for transfer modes, organizer resolution, SetLocation, inode dedup,
incremental ingest/remove.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Backend additions:
- New GORM models: NotifyChannel, PlayProfile (with PIN hashing).
- NotifyChannelService: multi-channel CRUD + unified dispatcher
supporting Telegram / Bark / WeChat / Webhook with optional
per-channel event filtering.
- PlayProfileService: per-user 'viewing personas' with
content-rating gates, library scoping, PIN protection, and
player defaults (autoplay, skip-intro, audio/subtitle prefs).
- New endpoints:
GET /admin/notify/channels list
POST /admin/notify/channels create
PUT /admin/notify/channels/:id update
DELETE /admin/notify/channels/:id delete
POST /admin/notify/channels/:id/test send test
GET /play-profiles list (admin: ?all=true)
POST /play-profiles create
PUT /play-profiles/:id update
DELETE /play-profiles/:id delete
GET /media/recent home page rail
GET /media/stats library composition
GET /watch-history list
GET /watch-history/stats aggregate
GET /watch-history/continue continue-watching rail
DELETE /watch-history[?media_id=] clear
DELETE /watch-history/:id remove one
GET /discover/sections available rails
GET /discover/feed?sections=a,b multi-section TMDb fetch
GET /system/info name/version/runtime
GET /system/status uptime/cpu/mem/disk
GET /system/scheduler read-only scheduler view
GET /stats/overview counts only
GET /stats/trend daily plays
GET /stats/top-content most played
GET /stats/libraries per-library size
GET /stats/monitor live hardware
Frontend additions:
- New API helpers: notify_channels, play_profiles, history,
stats_extra, media_extra, discover_extra, system.
- ProfileManagementPage (/play-profiles): full CRUD form with
PIN management, library scoping, language preferences.
- NotifyChannelsPage (/notify-channels, admin): typed config
forms per channel type + per-channel test action.
- SettingsPage (/settings, admin): grouped key/value editor
covering General, Organize/Scrape, Adult, qBittorrent.
- Layout sidebar links and App.tsx routes wired for all three.