← back to Dw Marketing Reels
Add sync-reels predeploy guard: auto-refresh reels/ from freshest render before deploy (fixes stale-embed desync)
1d80d7377e24b6108dd6e134320c4e2a69289fad · 2026-08-10 12:05:44 -0700 · Steve Abrams
Files touched
Diff
commit 1d80d7377e24b6108dd6e134320c4e2a69289fad
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 10 12:05:44 2026 -0700
Add sync-reels predeploy guard: auto-refresh reels/ from freshest render before deploy (fixes stale-embed desync)
---
scripts/sync-reels.mjs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/scripts/sync-reels.mjs b/scripts/sync-reels.mjs
new file mode 100644
index 0000000..f31cd6d
--- /dev/null
+++ b/scripts/sync-reels.mjs
@@ -0,0 +1,50 @@
+#!/usr/bin/env node
+/**
+ * sync-reels.mjs — single-source-of-truth guard for the flip-book pipeline.
+ *
+ * WHY: the studio serves the public video from `reels/<slug>-flipbook.mp4`, but
+ * `build-page.mjs` only COPIES the render into `reels/` once, at page-build time.
+ * Any RE-RENDER after that writes to `flipbooks/<slug>/renders/<slug>-flipbook.mp4`
+ * and silently leaves `reels/` (the served file) stale — so the live page shows an
+ * old cut while "deploy OK" reports success. (Hit live on Majilite Metallics,
+ * 2026-08-10, TK-10413.)
+ *
+ * FIX: run this as the project's PREDEPLOY_HOOK. Before every deploy it copies each
+ * render into `reels/` whenever the render is newer or differs in size, so the
+ * served file can never lag the freshest render again. It only SYNCS (never gates);
+ * it exits non-zero only on a real IO failure.
+ */
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const PROJ = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
+const flipbooks = path.join(PROJ, 'flipbooks');
+const reelsDir = path.join(PROJ, 'reels');
+fs.mkdirSync(reelsDir, { recursive: true });
+
+let synced = 0, checked = 0;
+try {
+ const slugs = fs.existsSync(flipbooks)
+ ? fs.readdirSync(flipbooks, { withFileTypes: true }).filter(d => d.isDirectory()).map(d => d.name)
+ : [];
+ for (const slug of slugs) {
+ const render = path.join(flipbooks, slug, 'renders', `${slug}-flipbook.mp4`);
+ if (!fs.existsSync(render)) continue; // no render for this slug — skip
+ checked++;
+ const served = path.join(reelsDir, `${slug}-flipbook.mp4`);
+ const src = fs.statSync(render);
+ const cur = fs.existsSync(served) ? fs.statSync(served) : null;
+ const stale = !cur || cur.size !== src.size || cur.mtimeMs < src.mtimeMs;
+ if (stale) {
+ fs.copyFileSync(render, served);
+ console.log(` sync-reels: ${slug} → reels/ (${(src.size / 1e6).toFixed(1)} MB, render was newer)`);
+ synced++;
+ }
+ }
+ console.log(` sync-reels: ${checked} render(s) checked, ${synced} refreshed, ${checked - synced} already current`);
+ process.exit(0);
+} catch (e) {
+ console.error(` sync-reels: IO error — ${e.message}`);
+ process.exit(1); // real failure aborts deploy (safer than shipping unknown state)
+}
← 305a06c Majilite flip book: real Replicate commercial rooms on verso
·
back to Dw Marketing Reels
·
chore: wire sync-reels predeploy hook + version bump (sessio 5e6973b →