Usage › Web UI¶
The Web UI is a React SPA served by FastAPI. It covers the full Unit3D pre-flight workflow from the browser: library scan, guided upload, torrent queue, history, configuration, real-time logs. Available in Italian and English (language switcher in the TopBar, v0.6.0).
Start:
Open the resulting URL (http://<U3DP_HOST>:<U3DP_PORT><U3DP_ROOT_PATH>, default http://127.0.0.1:8765).
Login¶
First screen: password field. Credentials are validated against U3DP_PASSWORD_HASH (bcrypt). The session is signed with U3DP_SECRET (itsdangerous) and lasts as long as the browser keeps the cookie.
Middleware order
Behind the scenes: SessionMiddleware must be added after the auth middleware (LIFO = last added is outermost). If auth tries to read request.session before SessionMiddleware is installed, it crashes with AssertionError: SessionMiddleware must be installed.
Media Library¶

Lists categories (subfolders of U3DP_MEDIA_ROOT) and items inside them.
Features:
- Category dropdown — categories are auto-discovered (
GET /api/library/categories). Not hardcoded. - Item list — each row shows title, year (if from TMDB), total size, detected audio languages.
- Sorting — name, year, size.
- Search — live filter on name.
- Hide uploaded — toggle controlled by
W_HIDE_UPLOADED. - Detail panel — clicking an item opens a side panel (mobile: full-screen overlay) with file list, TMDB match, actions.
- Rescan audio languages — button that streams the
pymediainfoscan via SSE, updating the cache. - Manual TMDB match — field to enter an ID, search button with result previews.
- Multi-select — checkbox on each item; action bar with "Select all", "Deselect", "Mark as uploaded" for bulk operations. (v0.6.1)
- Type filter — toggle to show only movies (
kind === 'movie'), hiding series and seasons. (v0.6.1)
Relevant endpoints: GET /api/library/categories, GET /api/library/{category}, GET /api/library/{category}/{item}, POST /api/library/{category}/{item}/langs, POST /api/tmdb/search, POST /api/tmdb/fetch.
Upload Wizard¶

Step-by-step flow. Alternative to the CLI with more options and persistent history.
Typical steps:
- Select source — file or folder under
U3DP_MEDIA_ROOT. - Audio check — if
W_AUDIO_CHECK, scans the tracks. - TMDB — search or ID entry. If
W_AUTO_TMDB, auto-fetch from an existing ID. - Name preview — editable; if
W_CONFIRM_NAMESis OFF, skips the confirmation. - Hardlink — into
U3DP_SEEDINGS_DIR. IfW_HARDLINK_ONLY, it stops here and records exit code0. - Upload — launches
unit3dupinside a PTY and streams the output live via SSE (GET /wizard/{token}/stream). - History write —
update_exit_code(seeding_path, code)persists intoU3DP_DB_PATH.
Quick upload¶
POST /upload/quick skips most of the wizard for power users: you get a job ID directly and consume GET /upload/{job}/stream. Use it when you already have renamed files in ~/seedings/.
Upload Queue¶

Shows active torrents in the configured client (TORRENT_CLIENT in Unit3Dbot.json: qbittorrent, transmission, rtorrent).
- Filter by name and state (downloading, seeding, paused, error).
- Auto-refresh.
- Links to local files.
Endpoint: GET /api/queue. Client credentials read from QBIT_* / TRASM_* / RTORR_*.
Uploaded (history)¶
Table of completed uploads (GET /api/uploaded). Fields:
- Local path in
~/seedings/. unit3dupexit code (0 = ok, ≠0 = error,pending= never finished).- Destination tracker.
- Timestamp.
- Size.
- Search and filter.
On mobile the table uses overflow-x:auto with min-width:820px to stay readable on narrow screens.
Stuck pending records
A record stuck as pending after a successful upload means the endpoint never called update_exit_code. This is a known regression trigger on changes to quickupload.py or wizard.py — see Troubleshooting.
Search Tracker¶

Searches for a torrent on ITT (always) and on PTT/SIS (if configured in Unit3Dbot.json with valid URL + API key).
- Tab per tracker.
- Shows link, size, seeders, freeleech, upload date.
- Handy for duplicate checks before uploading.
Endpoint: GET /api/trackers (status) + GET /api/search?q=....
Tracker status
A tracker shows as "Online" only if URL and API key are both set and the API key is not the "no_key" placeholder. All trackers appear in the sidebar even unconfigured ones (grey "Not set" badge).
Settings¶

Full Unit3Dbot.json editor right in the browser.
Sections:
- Trackers — URL, API key, PID for ITT / PTT / SIS;
MULTI_TRACKERlist. - Metadata — TMDB, TVDB, IGDB, YouTube.
- Torrent client — type + credentials (qBit / Transmission / rTorrent).
- Image host — preference order + API keys for PTSCREENS, PASSIMA, IMGBB, etc.
- Upload options —
DUPLICATE_ON,ANON,NUMBER_OF_SCREENSHOTS,COMPRESS_SCSHOT, ... - Seeding Flow —
U3DP_*with effective values (env vs config) viaenv_runtime().UNIT3DUP_CONFIGis read-only. - App Auto-Update —
U3DP_SYSTEMD_UNIT, systemd user unit name used by the "Update app" button for the post-update restart. Defaultunit3dprep.service; on Ultra.cc typicallyunit3dprep-web.service. - Wizard Defaults — all
W_*. - Interface — language selector (IT / EN); preference saved to
localStorageand synced toU3DP_LANGviaPUT /api/settings. (v0.6.0)
Secrets masked as __SET__ — the field still appears populated. Editing other keys does not wipe secrets.
Endpoints: GET /api/settings, PUT /api/settings, GET /api/settings/fs-check.
Mobile: the left nav becomes a horizontally scrollable row; 2-col grids collapse to 1-col.
In-app auto-update¶
At the bottom-left of the Sidebar, above the trackers list, a banner appears when a newer release of the installed app or unit3dup is available.
- App → GitHub Releases (
api.github.com/repos/.../releases/latest). The flow auto-picksgit pull + pip install -e .if the source is a git checkout, otherwisepip install --upgrade --force-reinstall git+URL@vX. - unit3dup → PyPI (
pypi.org/pypi/unit3dup/json).pip install --upgrade unit3dup.
On click:
- Modal with
pip/gitoutput live-streamed via SSE (/api/version/update/{app|unit3dup}/stream). - When done, a "Refresh in 5…1" countdown + automatic browser reload.
- Post-reload popup with the new release changelog (GitHub release body).
The "Update app" button stays disabled (can_update_app: false) if the systemd user unit is not reachable. See Configuration › In-app auto-update for details (including the U3DP_SYSTEMD_UNIT key).
Endpoints: GET /api/version/info, GET /api/version/changelog?v=X, GET /api/version/update/{app|unit3dup}/stream (SSE), POST /api/version/refresh.
Logs¶
Real-time log stream via SSE. Anything uvicorn / the app writes to logbuf (unit3dprep/web/logbuf.py) shows up here.
Useful for debugging without opening a shell on the VPS.
Mobile notes (≤768px)¶
The UI is responsive:
- Sidebar — closed via
translateX(-100%), scrim overlay when open. - Modal — full-bleed with 14px padding.
- Library detail —
position:fixed; inset:0overlay instead of the 360px side panel. - Settings nav — horizontal scrollable row.
- Tables —
overflow-x:auto.
Breakpoint handled by isMobile (App.tsx → Sidebar / TopBar / Library / Settings via props).
Programmatic access?¶
Every UI view consumes the JSON API under {U3DP_ROOT_PATH}/api/*. You can call it directly with a valid session cookie. See unit3dprep/web/api/*.py for the full list of routers.