← back to Beverlyhillsvideos
auto-save: 2026-08-06T05:48:58 (1 files) — build.mjs
519176b55d10f87819e484e59ab151f566faf156 · 2026-08-06 05:49:01 -0700 · Steve Abrams
Files touched
Diff
commit 519176b55d10f87819e484e59ab151f566faf156
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Aug 6 05:49:01 2026 -0700
auto-save: 2026-08-06T05:48:58 (1 files) — build.mjs
---
build.mjs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/build.mjs b/build.mjs
index 481c2d5..1cfe72e 100644
--- a/build.mjs
+++ b/build.mjs
@@ -397,6 +397,63 @@ writeFileSync('public/map.html', page({
canonical: '/map.html', body: mapBody,
}));
+// ---- per-restaurant film pages (SEO surface: film + cuisine + contact + menu) ----
+mkdirSync('public/restaurants', { recursive: true });
+let R_CUISINE = {}, R_SCRIPTS = {};
+try { (JSON.parse(readFileSync('data/restaurants.json','utf8')).restaurants||[]).forEach(r => R_CUISINE[r.name]=r.cuisine); } catch {}
+try { R_SCRIPTS = JSON.parse(readFileSync('data/film-scripts.json','utf8')); } catch {}
+const rnorm = s => (s||'').toLowerCase().replace(/beverly hills|estiatorio|the /g,'').replace(/[^a-z0-9]+/g,'').trim();
+const findBy = (obj, name) => { const n = rnorm(name); for (const k of Object.keys(obj)) { const kn = rnorm(k); if (kn && (kn===n || kn.includes(n) || n.includes(kn))) return obj[k]; } return null; };
+const contactFor = name => MAP_LOCS.filter(l=>l.type==='restaurant').find(l => { const a=rnorm(l.name), b=rnorm(name); return a===b || a.includes(b) || b.includes(a); });
+const restFilms = FILMS.map(f => {
+ const c = contactFor(f.name);
+ return { ...f,
+ cuisine: R_CUISINE[f.name] || findBy(R_CUISINE, f.name) || (c && c.category) || 'Beverly Hills',
+ narration: R_SCRIPTS[f.name] || findBy(R_SCRIPTS, f.name) || f.blurb,
+ address: c && c.address, phone: c && c.phone, menu_url: c && c.menu_url };
+});
+for (const f of restFilms) {
+ const tel = f.phone ? f.phone.replace(/[^+0-9]/g,'') : '';
+ const contact = (f.address || f.phone || f.menu_url) ? `
+ <div class="rest-contact">
+ ${f.address ? `<a class="paddr" href="https://maps.google.com/?q=${encodeURIComponent(f.name+' '+f.address)}" target="_blank" rel="noopener">${f.address}</a>` : ''}
+ ${f.phone ? `<a class="pcall" href="tel:${tel}">Call ${f.phone}</a>` : ''}
+ ${f.menu_url ? `<a class="pmenu" href="${f.menu_url}" target="_blank" rel="noopener">View current menu →</a>` : ''}
+ </div>` : '';
+ const body = `
+ <article class="rest"><div class="wrap">
+ <p class="crumb"><a href="/">Home</a> · <a href="/restaurants.html">Restaurants</a> · ${f.cuisine}</p>
+ <p class="eyebrow">${f.cuisine} · Beverly Hills</p>
+ <h1>${f.name.replace(/ Beverly Hills$/,'')}</h1>
+ <figure class="film rest-film"><video controls preload="metadata" playsinline poster="${f.poster}"><source src="${f.src}" type="video/mp4"></video></figure>
+ <p class="rest-narr">${f.narration}</p>
+ ${contact}
+ ${adSlot()}
+ <p class="rest-more"><a href="/map.html">See it on the map →</a> · <a href="/videos.html">All restaurant films →</a></p>
+ </div></article>`;
+ writeFileSync(`public/restaurants/${f.slug}.html`, page({
+ title: `${f.name.replace(/ Beverly Hills$/,'')} — Beverly Hills ${f.cuisine} | ${BRAND}`,
+ desc: f.narration.slice(0,155),
+ canonical: `/restaurants/${f.slug}.html`, body,
+ }));
+}
+// index
+const restIndex = `
+ <section class="hero home-hero vids-hero"><div class="wrap">
+ <p class="eyebrow">The Restaurants</p><h1>Every great table in Beverly Hills.</h1>
+ <p class="sub">Original short films on ${restFilms.length} of the city's finest restaurants — with menus, maps, and click-to-call.</p>
+ </div></section>
+ <section class="rest-grid-sec"><div class="wrap"><div class="rest-grid">
+ ${restFilms.map(f => `<a class="rest-card" href="/restaurants/${f.slug}.html">
+ <div class="rc-thumb"><img src="${f.poster}" alt="${f.name}" loading="lazy"></div>
+ <div class="rc-meta"><strong>${f.name.replace(/ Beverly Hills$/,'')}</strong><span>${f.cuisine}</span></div></a>`).join('')}
+ </div></div></section>`;
+writeFileSync('public/restaurants.html', page({
+ title: `Beverly Hills Restaurants — ${restFilms.length} Original Films, Menus & Map | ${BRAND}`,
+ desc: `Original short films on ${restFilms.length} of the finest restaurants in Beverly Hills, each with its current menu, address, and click-to-call.`,
+ canonical: '/restaurants.html', body: restIndex,
+}));
+
// ---- privacy (AdSense-compliant) ----
const privacyBody = `
<article class="post">
← 80e43a0 films: fix CUT + Mastro's integration (had undefined slug ->
·
back to Beverlyhillsvideos
·
restaurants: 50 per-restaurant SEO film pages (embed film + bcb2964 →