Script pane, realtime peer sync, and logout button

- Script pane: PDF tab beside annotations; "Add script annotation" arms
  highlight mode on the draft, ✓/✕ to confirm/cancel, auto-scrolls to the
  active annotation's highlights during playback. Adds Project.script.
- Realtime: Django Channels websocket per project broadcasts attributed
  scene deltas after each save; peers merge them in (keeping local drafts).
- Logout link in the editor project-bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-06-29 10:52:46 -04:00
parent 595ac5ba72
commit d3c8dcbdf2
13 changed files with 307 additions and 11 deletions

View file

@ -1,5 +1,7 @@
import json
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.contrib.auth import authenticate, login as dj_login, logout as dj_logout
from django.db import transaction
from django.db.models import Q
@ -53,6 +55,7 @@ def _meta(request, project):
"owner": project.owner.get_username(),
"otio": request.build_absolute_uri(project.otio.url) if project.otio else None,
"clip": request.build_absolute_uri(project.clip.url) if project.clip else None,
"script": request.build_absolute_uri(project.script.url) if project.script else None,
"thumbnail_status": project.thumbnail_status,
"thumbnail_error": project.thumbnail_error,
"thumbnails": thumbnails or None,
@ -150,6 +153,15 @@ def scene(request, pk):
if any(counts.values()): # don't log a no-op save
Revision.objects.create(project=p, user=request.user, summary=summary,
annotations=annotation_layer(p.scene))
# push the attributed delta to peers viewing this project
scene_groups = (p.scene or {}).get("groups", {})
async_to_sync(get_channel_layer().group_send)(
f"project_{p.pk}",
{"type": "scene.delta",
"delta": {"changed": {gid: scene_groups[gid]
for gid in changed if gid in scene_groups},
"deleted": list(deleted),
"by": request.user.get_username()}})
if "fps" in data:
p.fps = data["fps"]
p.save(update_fields=["scene", "fps", "updated"])