Adding symmetric up down

This commit is contained in:
2026-07-25 21:43:21 +02:00
parent e7dc402d9e
commit f79a0cb082
+36 -15
View File
@@ -7,16 +7,17 @@ Workflow:
Design: Design:
- commit appends a timestamped entry to commits.log - commit appends a timestamped entry to commits.log
- up checks server commits.log for newer entry (aborts if found), - up checks server commits.log for newer entry (aborts if found), then
then rsyncs a manifest of only the *inputs* needed to render rsyncs the WHOLE project tree, excluding only the large/derived files
(manuscript, slides, narration, audio, videos, keynote). For in _SYNC_EXCLUDES. Everything else — manuscript, slides, narration
narration it pushes the raw raw_mov/ recordings, NOT the processed raw_mov/, per-segment transcripts, events.json, audio, videos, keynote
segments — the rig runs preprocess to produce the large — is carried automatically, so a new kind of input file can never be
processed/*_processed.mov files itself. It also does NOT push the silently left behind.
rendered output (out/*.mp4/.srt) — that is produced on the rig, so - down rsyncs the WHOLE project tree back, with the same _SYNC_EXCLUDES.
pushing a stale local copy would clobber it.
- down rsyncs everything the server has back to local, including the Sync model: move everything, exclude a small denylist. The exclusions are large
freshly rendered out/*.mp4. Rendered output flows one way: rig → local. derived artifacts each side regenerates or ships on its own (rendered output,
preprocessed segments, downscales, chunk scratch), so they never travel over SSH.
""" """
import json import json
@@ -27,16 +28,27 @@ from typing import Optional
_COMMITS_LOG = "commits.log" _COMMITS_LOG = "commits.log"
# Dirs/patterns excluded on down (mirrors what up never pushes). Note: events.json # Files/dirs NEVER transferred in either direction. Everything else syncs, so new
# and scaffold.json are NOT excluded — they must reach the rig so `down` + `render` # artifacts (transcripts, manuscript_transcribed.txt, events.json, scaffold.json, …)
# is all that's needed there. The render never rewrites them, so they stay identical # are carried automatically without touching this list. These are large, derived,
# on both ends (no clobbering). # or machine-local outputs that each side regenerates or ships itself:
_DOWN_EXCLUDES = [ # - out/ rendered video (produced on the rig; `handoff` ships it for review)
# - processed/ heavy preprocessed *_processed.mov segments (rig regenerates)
# - intermediate/ ffmpeg work files
# - low/ proxy/ derived downscales
# - **/chunks/ per-chunk preprocess scratch
# Note: events.json / scaffold.json are deliberately NOT excluded — they must reach
# the rig so `down` + `render` is all that's needed there, and render never rewrites
# them, so they stay identical on both ends.
_SYNC_EXCLUDES = [
"out/",
"media/narration/processed/", "media/narration/processed/",
"media/narration/intermediate/", "media/narration/intermediate/",
"media/videos/intermediate/", "media/videos/intermediate/",
"media/narration/low/", "media/narration/low/",
"media/videos/low/", "media/videos/low/",
"media/narration/proxy/",
"media/videos/proxy/",
"**/chunks/", "**/chunks/",
"*.tmp", "*.tmp",
".*", # rsync in-progress temp files (.filename.XXXXXX) and .DS_Store ".*", # rsync in-progress temp files (.filename.XXXXXX) and .DS_Store
@@ -125,6 +137,15 @@ def _build_manifest(project_path: Path) -> list[str]:
for f in sorted(raw_mov_dir.glob("*.mov")): for f in sorted(raw_mov_dir.glob("*.mov")):
if f.is_file() and not f.name.startswith("."): if f.is_file() and not f.name.startswith("."):
files.add(str(f.relative_to(project_path))) files.add(str(f.relative_to(project_path)))
# Per-segment Whisper transcripts. These are the ONLY non-deterministic input
# to marker alignment (Whisper is not bit-reproducible across platforms), so
# syncing them makes `build` produce identical events.json on any machine — the
# rig can no longer diverge by re-transcribing locally.
transcripts_dir = narration_dir / "transcripts"
if transcripts_dir.is_dir():
for f in sorted(transcripts_dir.glob("*.json")):
if f.is_file() and not f.name.startswith("."):
files.add(str(f.relative_to(project_path)))
# Audio — standard location, non-shared entries only # Audio — standard location, non-shared entries only
audio_json = project_path / "media" / "audio" / "audio.json" audio_json = project_path / "media" / "audio" / "audio.json"