[object Object]

← back to Beverlyhillsvideos

films: pipeline trims leading gap + caps to 29s (guarantees short, gap-free films); fix Mr.Chow/E.Baldi captions; keep Spago flagship full-length

4cd852ab33eb02a930bfe50a1b3012889c755bd4 · 2026-08-05 16:02:51 -0700 · Steve Abrams

Files touched

Diff

commit 4cd852ab33eb02a930bfe50a1b3012889c755bd4
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Aug 5 16:02:51 2026 -0700

    films: pipeline trims leading gap + caps to 29s (guarantees short, gap-free films); fix Mr.Chow/E.Baldi captions; keep Spago flagship full-length
---
 data/films.json              |   4 ++--
 filmgen/heygen_batch.mjs     |  32 +++++++++++++++++++++++++++-----
 filmgen/trim_existing.sh     |  32 ++++++++++++++++++++++++++++++++
 public/video/nate-n-al-s.jpg | Bin 148298 -> 146334 bytes
 public/video/spago.jpg       | Bin 74463 -> 73485 bytes
 public/video/spago.mp4       | Bin 7782958 -> 7396040 bytes
 public/videos.html           |   4 ++--
 7 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/data/films.json b/data/films.json
index cb242d1..2b3a316 100644
--- a/data/films.json
+++ b/data/films.json
@@ -16,7 +16,7 @@
  {
   "name": "Mr. Chow",
   "slug": "mr-chow",
-  "blurb": "On North Camden Drive, Mr.",
+  "blurb": "On North Camden Drive, Mr. Chow has been Beverly Hills' theater of Beijing cuisine since 1974.",
   "src": "/video/mr-chow.mp4",
   "poster": "/video/mr-chow.jpg"
  },
@@ -58,7 +58,7 @@
  {
   "name": "E. Baldi",
   "slug": "e-baldi",
-  "blurb": "On Canon Drive, E.",
+  "blurb": "On Canon Drive, E. Baldi is Beverly Hills' insider Italian, run by Giorgio Baldi's son Edoardo.",
   "src": "/video/e-baldi.mp4",
   "poster": "/video/e-baldi.jpg"
  },
diff --git a/filmgen/heygen_batch.mjs b/filmgen/heygen_batch.mjs
index 36a0dc0..3f9c804 100644
--- a/filmgen/heygen_batch.mjs
+++ b/filmgen/heygen_batch.mjs
@@ -44,8 +44,13 @@ function updateFilms(rows, scripts) {
   const bySlug = Object.fromEntries(films.map(f=>[f.slug,f]));
   for (const r of Object.values(rows)) {
     if (r.status === 'completed' && r.downloaded && !bySlug[r.slug]) {
-      const first = (scripts[r.name]||'').split('. ')[0];
-      const blurb = first ? (first.endsWith('.')?first:first+'.') : catFor(r.name);
+      // first sentence, but abbreviation-safe: truncate at a word boundary near ~100 chars
+      const s = (scripts[r.name]||'').trim();
+      let blurb = catFor(r.name);
+      if (s) {
+        if (s.length <= 100) blurb = s;
+        else { const cut = s.slice(0,100); blurb = cut.slice(0, cut.lastIndexOf(' ')) + '…'; }
+      }
       films.push({ name: r.name, slug: r.slug, blurb, src: `/video/${r.slug}.mp4`, poster: `/video/${r.slug}.jpg` });
     }
   }
@@ -53,11 +58,28 @@ function updateFilms(rows, scripts) {
   return films.length;
 }
 
+// Detect leading silence so the film starts talking at t=0 (no initial gap).
+function leadStart(raw) {
+  try {
+    const sd = sh(`ffmpeg -i ${raw} -af silencedetect=noise=-35dB:d=0.2 -f null - 2>&1 || true`);
+    const firstStart = (sd.match(/silence_start:\s*(-?[0-9.]+)/) || [])[1];
+    const firstEnd = (sd.match(/silence_end:\s*([0-9.]+)/) || [])[1];
+    if (firstStart !== undefined && parseFloat(firstStart) <= 0.3 && firstEnd !== undefined) {
+      return Math.min(2.5, Math.max(0, parseFloat(firstEnd) - 0.05)); // trim the lead-in, cap at 2.5s
+    }
+  } catch {}
+  return 0;
+}
 function download(r) {
+  const raw = `${VIDEO_DIR}/${r.slug}-raw.mp4`;
   const mp4 = `${VIDEO_DIR}/${r.slug}.mp4`;
-  sh(`heygen video download ${r.video_id} --output-path ${mp4} --force`);
-  try { sh(`ffmpeg -y -ss 2 -i ${mp4} -vframes 1 -q:v 3 ${VIDEO_DIR}/${r.slug}.jpg 2>/dev/null`); } catch {}
-  // 9:16 vertical for Instagram Reels / TikTok (blurred-fill, whole frame preserved)
+  sh(`heygen video download ${r.video_id} --output-path ${raw} --force`);
+  const start = leadStart(raw);
+  // trim leading gap + hard-cap to 29s (guarantees the delivered film is <=29s, talk at t=0)
+  sh(`ffmpeg -y -ss ${start} -i ${raw} -t 29 -c:v libx264 -preset medium -crf 20 -c:a aac -b:a 128k -movflags +faststart ${mp4} 2>/dev/null`);
+  try { sh(`rm -f ${raw}`); } catch {}
+  try { sh(`ffmpeg -y -ss 1 -i ${mp4} -vframes 1 -q:v 3 ${VIDEO_DIR}/${r.slug}.jpg 2>/dev/null`); } catch {}
+  // 9:16 vertical for Instagram Reels / TikTok, built from the trimmed film
   try {
     const v = `${VIDEO_DIR}/vertical/${r.slug}.mp4`;
     sh(`ffmpeg -y -i ${mp4} -filter_complex "[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,gblur=sigma=26,eq=brightness=-0.10[bg];[0:v]scale=1080:-1[fg];[bg][fg]overlay=(W-w)/2:(H-h)/2,format=yuv420p[v]" -map "[v]" -map 0:a -c:v libx264 -preset medium -crf 21 -c:a aac -b:a 128k ${v} 2>/dev/null`);
diff --git a/filmgen/trim_existing.sh b/filmgen/trim_existing.sh
new file mode 100644
index 0000000..a0f8cbf
--- /dev/null
+++ b/filmgen/trim_existing.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# One-time reprocess of already-downloaded restaurant films:
+# remove any leading silence (talk starts at t=0) and hard-cap to 29s.
+# Rebuilds poster + 9:16 vertical from the trimmed file. Idempotent.
+cd /Users/macstudio3/Projects/beverlyhillsvideos || exit 1
+VD=public/video
+for f in "$VD"/*.mp4; do
+  [ -f "$f" ] || continue
+  base=$(basename "$f" .mp4)
+  # detect leading-silence end
+  sd=$(ffmpeg -i "$f" -af silencedetect=noise=-35dB:d=0.2 -f null - 2>&1)
+  fs=$(echo "$sd" | grep -o 'silence_start: [-0-9.]*' | head -1 | awk '{print $2}')
+  fe=$(echo "$sd" | grep -o 'silence_end: [0-9.]*' | head -1 | awk '{print $2}')
+  start=0
+  if [ -n "$fs" ] && [ -n "$fe" ]; then
+    awk "BEGIN{exit !($fs<=0.3)}" && start=$(awk "BEGIN{s=$fe-0.05; if(s<0)s=0; if(s>2.5)s=2.5; print s}")
+  fi
+  dur=$(ffprobe -v error -show_entries format=duration -of default=nk=1:nw=1 "$f")
+  # skip if already <=29s AND no leading gap to trim
+  if awk "BEGIN{exit !($dur<=29.05 && $start<0.15)}"; then
+    echo "  = $base ${dur}s (already clean, skip)"
+    continue
+  fi
+  tmp="$VD/$base-trim.mp4"
+  ffmpeg -y -ss "$start" -i "$f" -t 29 -c:v libx264 -preset medium -crf 20 -c:a aac -b:a 128k -movflags +faststart "$tmp" 2>/dev/null \
+    && mv -f "$tmp" "$f" \
+    && echo "  ✓ $base trimmed (start=${start}s -> <=29s)"
+  # rebuild poster + vertical from trimmed
+  ffmpeg -y -ss 1 -i "$f" -vframes 1 -q:v 3 "$VD/$base.jpg" 2>/dev/null
+  ffmpeg -y -i "$f" -filter_complex "[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,gblur=sigma=26,eq=brightness=-0.10[bg];[0:v]scale=1080:-1[fg];[bg][fg]overlay=(W-w)/2:(H-h)/2,format=yuv420p[v]" -map "[v]" -map 0:a -c:v libx264 -preset medium -crf 21 -c:a aac -b:a 128k "$VD/vertical/$base.mp4" 2>/dev/null
+done
+echo "done."
diff --git a/public/video/nate-n-al-s.jpg b/public/video/nate-n-al-s.jpg
index a7b862d..940d470 100644
Binary files a/public/video/nate-n-al-s.jpg and b/public/video/nate-n-al-s.jpg differ
diff --git a/public/video/spago.jpg b/public/video/spago.jpg
index 51327eb..e82236f 100644
Binary files a/public/video/spago.jpg and b/public/video/spago.jpg differ
diff --git a/public/video/spago.mp4 b/public/video/spago.mp4
index 6a8e83b..77b2884 100644
Binary files a/public/video/spago.mp4 and b/public/video/spago.mp4 differ
diff --git a/public/videos.html b/public/videos.html
index f7af6cd..2f315ef 100644
--- a/public/videos.html
+++ b/public/videos.html
@@ -77,7 +77,7 @@
         <video controls preload="metadata" playsinline poster="/video/mr-chow.jpg">
           <source src="/video/mr-chow.mp4" type="video/mp4">
         </video>
-        <figcaption><strong>Mr. Chow</strong><span>On North Camden Drive, Mr.</span></figcaption>
+        <figcaption><strong>Mr. Chow</strong><span>On North Camden Drive, Mr. Chow has been Beverly Hills' theater of Beijing cuisine since 1974.</span></figcaption>
       </figure>
       <figure class="film">
         <video controls preload="metadata" playsinline poster="/video/il-pastaio.jpg">
@@ -113,7 +113,7 @@
         <video controls preload="metadata" playsinline poster="/video/e-baldi.jpg">
           <source src="/video/e-baldi.mp4" type="video/mp4">
         </video>
-        <figcaption><strong>E. Baldi</strong><span>On Canon Drive, E.</span></figcaption>
+        <figcaption><strong>E. Baldi</strong><span>On Canon Drive, E. Baldi is Beverly Hills' insider Italian, run by Giorgio Baldi's son Edoardo.</span></figcaption>
       </figure>
       <figure class="film">
         <video controls preload="metadata" playsinline poster="/video/la-scala.jpg">

← 2a4f891 films: integrate completed restaurant film(s) [auto]  ·  back to Beverlyhillsvideos  ·  films: integrate completed restaurant film(s) [auto] e061461 →