Deploy: - Multi-stage Dockerfile (shadow-cljs release → Python+ffmpeg runtime), fly.toml (one machine, scale-to-zero, SQLite on a volume), .dockerignore, DEPLOY.md - Same-origin release build: api-port defaults "9001" for dev, "" in release (no CORS in prod) - env-driven settings (SECRET_KEY/DEBUG/ALLOWED_HOSTS/DB_PATH/CSRF), WhiteNoise serving static + the SPA, R2 (S3-compatible) media storage when R2_* is set - thumbnails reworked storage-agnostic: download clip, ffmpeg select-pass, upload tiles via default_storage (R2 in prod, disk in dev) - pin channels/daphne; add whitenoise/django-storages/boto3 UI: - frame step buttons flanking play (disabled at timeline bounds) - Add-annotation button moved into the toolbar, made prominent - picker mode pulses a 1-bit glow on clips / frame readout / (while linking) annotation bars; linking an annotation bar inserts a timeline link Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| scenes | ||
| server | ||
| tl | ||
| .dockerignore | ||
| .gitignore | ||
| DEPLOY.md | ||
| Dockerfile | ||
| fly.toml | ||
| manage.py | ||
| README.md | ||
| requirements.txt | ||
scene_analysis
tl/— the lumet frontend (ClojureScript / reagent / re-frame). Seetl/.- Django backend (this folder) — users, admin, and persistence of OTIO + the timeline scene.
Backend
The backend stores one Project per editing session: the uploaded OTIO
source file, the playback fps, and the live scene (the {:tracks :groups} mark-group map the frontend keeps in app-db) as a JSON dump.
Run
python -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python manage.py migrate
DJANGO_SUPERUSER_PASSWORD=admin .venv/bin/python manage.py createsuperuser --noinput --username admin --email admin@example.com
.venv/bin/python manage.py seed_demo # demo project from tl/.../one_two_three.otio
.venv/bin/python manage.py runserver 0.0.0.0:9001 # 0.0.0.0 so it's reachable over Tailscale/LAN
Admin: http://127.0.0.1:9001/admin/ (admin / admin). Upload OTIO and inspect the scene JSON there.
API (session auth; 401 if not logged in)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/projects/ |
the current user's projects |
| GET | /api/projects/<id>/scene/ |
{fps, scene} |
| PUT | /api/projects/<id>/scene/ |
replace scene and/or fps (JSON body) |
| GET | /api/projects/<id>/otio/ |
serve the uploaded OTIO file |
| GET | /api/projects/<id>/revisions/ |
save history (who / when / summary) |
Attribution
Annotations are the authored unit, so that's what's attributed — and the server
is the authority (client-sent stamps are ignored, so authorship can't be
forged). On each scene PUT the server diffs incoming annotation groups against
the stored ones and stamps createdBy/editedBy (+ timestamps) from
request.user; it also writes a Revision (user, time, +N ~N −N summary,
snapshot of the annotation layer). A project is editable by its owner and any
collaborators (managed in the admin), so different users get distinct stamps.
The frontend currently loads /one_two_three.otio and persists annotations to
localStorage; pointing it at /api/projects/<id>/otio/ and the scene endpoints
is the next wiring step (CORS/credentials needed across the dev ports).