4.0 KiB
Remote asset library (self-hosted)
One team library, many thin Godot checkouts. Artists publish finished assets once; developers browse the catalog from inside the editor and download only what they need — no terabyte clones, no vendor cloud.
Run it
cp .env.example .env # then set a real ASSETMGR_LIBRARY_TOKEN
docker compose up -d --build library
curl localhost:8081/health # -> {"ok": true}
Data lives in the library-data volume (store/ blobs + library.db).
The API is token-authenticated (Authorization: Bearer <token>):
GET /api/v1/assets?q=&tag=&kind=— search the catalogPOST /api/v1/assets?name=&kind=&importer=¶ms={}&tags=(raw body) — publish; replies{"id", "blob_sha256"}(dedupe is by content hash)GET /api/v1/assets/<id>/blob— download bytesGET /api/v1/assets/<id>/thumbnail— 320px PNG preview, or 404{"error": "no thumbnail"}when the asset has none
Thumbnails render server-side at publish time (either ingest path) via
ffmpeg/ImageMagick when a suitable engine is installed — best effort:
unsupported formats, or a server with no engine at all, simply get no
thumbnail and everything else works. Asset listings carry
thumbnail_sha256 (null when absent). Databases from older releases
gain the column automatically on first open; existing rows keep serving
with no thumbnail until re-published.
The same operations exist offline-first on the CLI:
assetmgr library-init|library-push|library-pull|library-thumbnail
(see docs/API.md).
Uploads are capped at 2 GiB (MAX_UPLOAD_BYTES); for anything large use
the session protocol — the CLI switches automatically above 64 MiB
(--chunk-above BYTES), or force it with library-push --chunked [--chunk-size BYTES]. Sessions stream in 8 MiB blocks (the server never
holds a whole file in RAM), each attempt gets a fresh session id, and
abandoned sessions are swept on server start.
Connect Godot
- Copy
godot-plugin/addons/asset_library/into your project'saddons/. - Project → Project Settings → Plugins → enable Asset Library.
- Open the dock (left), enter server URL + token, Search, select, Download.
Files land in
res://<name>and the editor filesystem rescans, so.importsidecars generate on the spot. Selecting a result also shows its server-rendered thumbnail in the preview pane (blank when the asset has none). - The web UI (native binary / Docker) has a Library section that
searches the same catalog over HTTP (the server sends
Access-Control-Allow-Origin: *; auth still required) and shows the thumbnails inline.
Publish the other way with the godot::publish-to-library action
(importer + params travel in the upload), or plain
assetmgr library-push.
Security notes (read before exposing this)
- Token auth: one token per teammate, created locally against the DB file (plaintext shown once, only digests stored).
- Revocation is instant (
library-token-revoke); revoked tokens 401. There are no roles — every live token reads and writes every file. - TLS is built in, off by default. Pass
--tls-cert/--tls-key(orASSETMGR_LIBRARY_TLS_CERT/KEY) with a PEM pair — self-signed is fine on a LAN, use a real certificate (or a reverse proxy that terminates for you) for anything internet-facing. Never serve plain HTTP past your own network: clients fail closed against a TLS port and vice versa. - Tokens live in
.env(git-ignored; see.env.example) only as the bootstrap secret: on first start it seeds thedefaulttoken, and is ignored once any token exists. Prefer per-user tokens after that. - Compose with TLS: mount your PEM pair and override the command, e.g.
volumes
["./certs:/certs:ro"], command["-m", "library", "--host", "0.0.0.0", "--port", "8081", "--tls-cert", "/certs/fullchain.pem", "--tls-key", "/certs/key.pem"]. - Rotate by revoking the name and creating a fresh one.
- The server trusts its operator: anyone with the token can read and write every asset.