Skip to content

Configuration

unit3dprep reads configuration from three layers, in order of priority:

  1. Environment variables — always win.
  2. Unit3Dbot.json — shared with the unit3dup CLI, editable from the Web UI.
  3. Built-in defaults — used when neither env nor file sets a value.

U3DP_* and W_* keys are re-read on every access via config.runtime_setting(): changing them from the Web UI takes effect immediately, no restart needed. Exceptions are U3DP_HOST, U3DP_PORT, U3DP_ROOT_PATH, and U3DP_HTTPS_ONLY, which are read once at server startup.


Environment variables

Required by the Web UI

Variable Description
U3DP_PASSWORD_HASH Bcrypt hash of the web password. Generated by generate_hash.py.
U3DP_SECRET Hex secret that signs session cookies. Generated by generate_hash.py.

TMDB

Variable Default Description
TMDB_API_KEY TMDB v3 API key. Needed for automatic TMDB search and metadata fetch. The CLI prompts the user if missing.

Runtime (re-read on every access)

Variable Default Description
U3DP_HOST 127.0.0.1 uvicorn bind address. Use 0.0.0.0 on a public VPS with firewall, 127.0.0.1 behind an nginx reverse proxy.
U3DP_PORT 8765 Listening port. On Ultra.cc pick a reserved port (app-ports free).
U3DP_ROOT_PATH "" Nginx prefix (e.g. /unit3dprep). See ROOT_PATH notes.
U3DP_HTTPS_ONLY 0 1 sets the https_only flag on the session cookie (required behind HTTPS).
U3DP_MEDIA_ROOT ~/media Base media folder. Subfolders become categories.
U3DP_SEEDINGS_DIR ~/seedings Hardlink destination. Must live on the same FS as U3DP_MEDIA_ROOT.
U3DP_TMDB_LANG it-IT TMDB response language. Examples: en-US, es-ES.
U3DP_DB_PATH ~/.unit3dprep_db.json Upload history (JSON).
U3DP_TMDB_CACHE_PATH ~/.unit3dprep_tmdb_cache.json TMDB query cache.
U3DP_LANG_CACHE_PATH ~/.unit3dprep_lang_cache.json Audio language detection cache.
U3DP_SYSTEMD_UNIT unit3dprep.service Systemd user unit name used by the "Update app" button for systemctl --user cat/restart. On Ultra.cc set to unit3dprep-web.service.
U3DP_GITHUB_REPO davidesidoti/unit3dprep owner/repo slug used to poll GitHub releases (env-only, read at import).

Install / path

Variable Default Description
UNIT3DUP_CONFIG ~/Unit3Dup_config/Unit3Dbot.json Override path to Unit3Dbot.json. Read only at startup.

Web UI wizard (W_*)

Control the default state of the upload wizard toggles. Stored in Unit3Dbot.json, editable from Settings.

Key Default Description
W_AUDIO_CHECK true Enable Italian audio check inside the wizard.
W_AUTO_TMDB true Auto-fetch TMDB metadata if an ID is already present.
W_HIDE_UPLOADED true Hide already-uploaded items from the Library.
W_HARDLINK_ONLY false End the wizard after the hardlink, without calling unit3dup.
W_CONFIRM_NAMES true Require confirmation of the final name before hardlinking.

Unit3Dbot.json file

Unit3Dbot.json is the same file unit3dup consumes. Default path: ~/Unit3Dup_config/Unit3Dbot.json, override via UNIT3DUP_CONFIG.

It contains ~100 keys, grouped by purpose:

Group Key examples
Trackers ITT_URL, ITT_APIKEY, ITT_PID, PTT_URL, PTT_APIKEY, PTT_PID, SIS_URL, SIS_APIKEY, SIS_PID, MULTI_TRACKER
Metadata TMDB_APIKEY, TVDB_APIKEY, YOUTUBE_KEY, IGDB_*
Torrent client TORRENT_CLIENT (qbittorrent / transmission / rtorrent), QBIT_*, TRASM_*, RTORR_*
Image host PTSCREENS_KEY, PASSIMA_KEY, IMGBB_KEY, IMGFI_KEY, IMAGE_HOST_ORDER, …
Behavior DUPLICATE_ON, SKIP_DUPLICATE, ANON, PERSONAL_RELEASE, NUMBER_OF_SCREENSHOTS, …
Seeding Flow all U3DP_* (overrides defaults)
Wizard defaults all W_*

Secret masking

Secrets (API keys, passwords, PIDs) are masked as "__SET__" in responses to GET /api/settings. On PUT, if the client sends back "__SET__" the server preserves the original value on disk. This avoids leaks in browser logs while letting you edit other keys without reentering secrets.

Masked keys are defined in unit3dprep/web/config.py (constant MASKED_KEYS): ITT_APIKEY, ITT_PID, PTT_APIKEY, PTT_PID, SIS_APIKEY, SIS_PID, TMDB_APIKEY, TVDB_APIKEY, YOUTUBE_KEY, IGDB_CLIENT_ID, IGDB_ID_SECRET, QBIT_PASS, TRASM_PASS, RTORR_PASS, FTPX_PASS, PTSCREENS_KEY, PASSIMA_KEY, IMGBB_KEY, IMGFI_KEY, FREE_IMAGE_KEY, LENSDUMP_KEY, IMARIDE_KEY.

Atomic writes

Writes to Unit3Dbot.json go through tempfile.mkstemp + os.replace → the unit3dup CLI never sees a half-written file.


U3DP_ROOT_PATH and nginx

When you serve the Web UI behind a reverse proxy at a subpath (e.g. /unit3dprep), set:

export U3DP_ROOT_PATH="/unit3dprep"

Important — on Ultra.cc the nginx user-proxy does not strip the prefix: requests arrive at uvicorn with /unit3dprep still in place. That is why the app mounts routes under the prefix with app.include_router(r, prefix=ROOT_PATH) instead of FastAPI(root_path=...) (the latter is only for proxies that do strip).

The SPA reads window.__ROOT_PATH__ injected at serve-time into index.html, so assets and API calls automatically hit the right prefix with no rebuild.

On a generic VPS where nginx strips the prefix (proxy_pass http://127.0.0.1:8765/; with trailing slash), set U3DP_ROOT_PATH="" instead and handle the path from the server block.


In-app auto-update

The Web UI ships an integrated update system (badge at the bottom-left of the Sidebar, above the trackers list):

  • App: compares the installed version (importlib.metadata.version("unit3dprep")) against the latest GitHub release. If newer == true the "Update app" button appears.
  • unit3dup: compares against PyPI (https://pypi.org/pypi/unit3dup/json).

Clicking triggers the SSE endpoint /api/version/update/{app|unit3dup}/stream: live-streamed pip install in the modal, systemd service restart, browser auto-reload with a changelog popup.

App prerequisites

The "Update app" button stays disabled (can_update_app: false) when:

  • systemctl is not in PATH, or
  • the configured unit does not exist (systemctl --user cat <unit> fails).

On Ultra.cc the user unit is typically unit3dprep-web.service, not the default unit3dprep.service. Set it via:

# ~/.config/systemd/user/unit3dprep-web.service
[Service]
Environment=U3DP_SYSTEMD_UNIT=unit3dprep-web.service

or save the key through Settings › App Auto-Update. The key is read at runtime, so a Save takes effect immediately. daemon-reload + restart are only needed when you add a fresh Environment= entry.

Install mode

_install_mode() picks the flow based on the install layout:

  • git — source has a reachable .git (typical for pip install -e . from a checkout). Runs git pull --ff-only origin main + pip install -e ..
  • pip — installed via pip install git+https://...@vX (no .git). Runs pip install --upgrade --force-reinstall git+URL@vX.

Editable install + service WorkingDirectory

If the systemd [Service] has WorkingDirectory=<repo> and that folder contains .git, Python imports unit3dprep from the local source (editable) even when you installed via pip install git+.... The flow becomes "git" as a consequence. To force the pip flow, use WorkingDirectory=%h and remove/rename the checkout.

GitHub token (optional)

The api.github.com anonymous rate limit is 60 requests/hour per IP. This should be enough (polling every 15 min), but in case of saturation a token-via-env path is tracked as a follow-up — not yet implemented.


Complete examples

Local deploy (just you, on a trusted machine)

export U3DP_PASSWORD_HASH="$2b$12$..."
export U3DP_SECRET="..."
export TMDB_API_KEY="..."
export U3DP_HOST="127.0.0.1"
export U3DP_PORT="8765"
unit3dprep-web

Behind nginx with HTTPS and a subpath

export U3DP_PASSWORD_HASH="..."
export U3DP_SECRET="..."
export TMDB_API_KEY="..."
export U3DP_HOST="127.0.0.1"
export U3DP_PORT="45678"                 # backend port, not exposed
export U3DP_ROOT_PATH="/unit3dprep"     # public subpath
export U3DP_HTTPS_ONLY="1"
unit3dprep-web

Media on a separate disk

export U3DP_MEDIA_ROOT="/mnt/storage/media"
export U3DP_SEEDINGS_DIR="/mnt/storage/seedings"

Same filesystem

U3DP_SEEDINGS_DIR must live on the same device as U3DP_MEDIA_ROOT, otherwise hardlink creation fails with OSError: [Errno 18] Invalid cross-device link. Check with df <media> <seedings>.