[object Object]

← back to Dw Marketing Reels

Build-gate for read-only public deploy + nightly push to Kamatera

a1ba7d4edafa5b5f331b4bb8fe9254238b8df844 · 2026-07-12 10:31:09 -0700 · Steve Abrams

Files touched

Diff

commit a1ba7d4edafa5b5f331b4bb8fe9254238b8df844
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 12 10:31:09 2026 -0700

    Build-gate for read-only public deploy + nightly push to Kamatera
---
 public/index.html   | 12 ++++++++++++
 scripts/cron-run.sh | 12 +++++++++++-
 server.js           |  7 +++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/public/index.html b/public/index.html
index c5733f7..c7bd454 100644
--- a/public/index.html
+++ b/public/index.html
@@ -138,6 +138,18 @@ async function job(path, label) {
 $('#btnRefresh').addEventListener('click', ()=>job('api/refresh','↻ refreshing feed…'));
 $('#btnBuild').addEventListener('click', ()=>job('api/build','▶ generating reel (≈30s)…'));
 
+// read-only public deploy hides the generation controls
+(async () => {
+  try {
+    const cfg = await (await fetch('api/config')).json();
+    if (!cfg.allowBuild) {
+      $('#btnBuild').style.display = 'none';
+      $('#btnRefresh').style.display = 'none';
+      $('#status').textContent = 'Reels are rendered on the studio host and published here automatically.';
+    }
+  } catch {}
+})();
+
 loadReels(); loadNA();
 </script>
 </body>
diff --git a/scripts/cron-run.sh b/scripts/cron-run.sh
index 5b77b0a..f7868e3 100755
--- a/scripts/cron-run.sh
+++ b/scripts/cron-run.sh
@@ -1,5 +1,15 @@
 #!/bin/zsh
+# Nightly: refresh the New Arrivals feed, render a fresh reel locally ($0), then
+# push the rendered reels + data up to the Kamatera console so the live gallery updates.
 export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
 export HYPERFRAMES_SKIP_SKILLS=1
 cd "$(dirname "$0")/.."
-node scripts/fetch-new-arrivals.mjs && node scripts/build-reel.mjs
+node scripts/fetch-new-arrivals.mjs && node scripts/build-reel.mjs || exit 1
+
+PUSH_HOST="${PUSH_HOST:-root@45.61.58.125}"
+PUSH_PATH="${PUSH_PATH:-/root/public-projects/dw-marketing-reels}"
+if ssh -o BatchMode=yes -o ConnectTimeout=6 "$PUSH_HOST" "test -d $PUSH_PATH" 2>/dev/null; then
+  rsync -az reels/ "$PUSH_HOST:$PUSH_PATH/reels/"
+  rsync -az data/ "$PUSH_HOST:$PUSH_PATH/data/"
+  echo "pushed reels+data -> $PUSH_HOST:$PUSH_PATH"
+fi
diff --git a/server.js b/server.js
index c58c701..e41ab2e 100644
--- a/server.js
+++ b/server.js
@@ -14,6 +14,9 @@ const ROOT = dirname(fileURLToPath(import.meta.url));
 const PORT = Number(process.env.PORT || 9846);
 const USER = process.env.MKT_USER || 'admin';
 const PASS = process.env.MKT_PASS || 'DW2024!';
+// Generation needs the local render toolchain (Chrome/ffmpeg). On the public
+// Kamatera deploy set ALLOW_BUILD=0 — it serves reels only; Mac3 renders + pushes.
+const ALLOW_BUILD = process.env.ALLOW_BUILD !== '0';
 const MIME = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript', '.css': 'text/css',
   '.json': 'application/json', '.mp4': 'video/mp4', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' };
 
@@ -28,6 +31,8 @@ function authed(req) {
 }
 
 function run(script, res) {
+  if (!ALLOW_BUILD) { res.writeHead(400, { 'content-type': 'application/json' })
+    .end(JSON.stringify({ error: 'Generation runs on the render host (Mac3). This deploy serves reels only.' })); return; }
   if (building) { res.writeHead(409).end(JSON.stringify({ error: 'a job is already running' })); return; }
   building = true; lastLog = '';
   const env = { ...process.env, PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env.PATH || ''}`, HYPERFRAMES_SKIP_SKILLS: '1' };
@@ -71,6 +76,8 @@ const server = http.createServer(async (req, res) => {
       const fp = join(ROOT, 'data', 'new-arrivals.json');
       return res.writeHead(200, { 'content-type': 'application/json' }).end(existsSync(fp) ? await readFile(fp) : '{"items":[]}');
     }
+    if (p === '/api/config') return res.writeHead(200, { 'content-type': 'application/json' })
+      .end(JSON.stringify({ allowBuild: ALLOW_BUILD }));
     if (p === '/api/status') return res.writeHead(200, { 'content-type': 'application/json' })
       .end(JSON.stringify({ building, log: lastLog.slice(-4000) }));
     if (p === '/api/refresh' && req.method === 'POST') return run('fetch-new-arrivals.mjs', res);

← 7630cbd Add nightly runner (gated plist), README, deploy config  ·  back to Dw Marketing Reels  ·  Auto-post to IG/TikTok (fail-safe pending-creds) + captions 20c8b48 →