[object Object]

← back to Designer Wallcoverings

Daisy Bennett viewer: local images (bypass WallQuest hotlink 403) + real-textiles filter (drop cork/mica)

a48458acb962b710b9494c9ba2ca1279ce64ffd3 · 2026-07-06 12:48:52 -0700 · Steve

Files touched

Diff

commit a48458acb962b710b9494c9ba2ca1279ce64ffd3
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Jul 6 12:48:52 2026 -0700

    Daisy Bennett viewer: local images (bypass WallQuest hotlink 403) + real-textiles filter (drop cork/mica)
---
 .../build-viewer-daisy-bennett.cjs                 | 76 +++++++++++++++-------
 1 file changed, 52 insertions(+), 24 deletions(-)

diff --git a/scripts/wallquest-refresh/build-viewer-daisy-bennett.cjs b/scripts/wallquest-refresh/build-viewer-daisy-bennett.cjs
index 790a49cd..30049444 100644
--- a/scripts/wallquest-refresh/build-viewer-daisy-bennett.cjs
+++ b/scripts/wallquest-refresh/build-viewer-daisy-bennett.cjs
@@ -1,30 +1,57 @@
 // Build a self-contained web viewer for the Daisy Bennett Natural Wallcoverings onboard.
-// Reads enriched (or normalized) records; PRESERVES the real vendor pattern names (Abatha,
-// Boccali, Venezia — neutral, no vendor leak) rather than remapping. Product grid + sort +
-// density slider (Steve's standing rules). Images referenced from the public WallQuest CDN.
+// REAL TEXTILES ONLY (woven natural fibers; drops cork/mica/wood-veneer/etc). Downloads each
+// primary image LOCALLY (no Referer → bypasses WallQuest hotlink 403) so it renders in a browser.
+// Real vendor pattern names preserved. Product grid + sort + density slider (Steve's standing rules).
 const fs = require('fs');
+const https = require('https');
 const OUTDIR = '/tmp/daisy-bennett-viewer';
 const ENR = '/tmp/wq-daisy-bennett-enriched.json';
 const NORM = '/tmp/wq-daisy-bennett-normalized.json';
 const src = fs.existsSync(ENR) ? ENR : NORM;
-const recs = JSON.parse(fs.readFileSync(src, 'utf8'));
+let recs = JSON.parse(fs.readFileSync(src, 'utf8'));
 
-const data = recs.map(r => ({
-  dw_sku: r.dw_sku, mfr_sku: r.mfr_sku,
-  pattern: r.pattern || '', color: r.color || '',
-  family: (r.pattern || '').split(/\s+/).slice(-1)[0] || 'Naturals',
-  cost: r.price_retail, retail: r.our_price,
-  hex: r.color_hex || '', desc: r.ai_description || '',
-  styles: r.ai_styles || [],
-  img: (r.images || []).find(u => /_650\./.test(u)) || (r.images || [])[0] || '',
-  src_url: r.product_url,
-}));
-data.sort((a, b) => a.pattern.localeCompare(b.pattern) || a.color.localeCompare(b.color));
+// REAL TEXTILES ONLY — keep woven natural fibers; drop non-textile substrates.
+const NON_TEXTILE = /cork|mica|mother.?of.?pearl|wood.?veneer|\bshell\b|glass.?bead|vinyl/i;
+const isTextile = r => {
+  const mat = `${r._material_resolved || ''} ${r.ai_material_texture || ''} ${r.pattern || ''} ${r.material || ''}`;
+  return !NON_TEXTILE.test(mat) && !/^DW(CORK|MIC)-/.test(r.dw_sku || '');
+};
+const dropped = recs.filter(r => !isTextile(r));
+recs = recs.filter(isTextile);
+console.log(`real-textiles filter: kept ${recs.length}, dropped ${dropped.length}${dropped.length ? ' (' + dropped.map(d => d.dw_sku + ' ' + d.pattern).join(', ') + ')' : ''}`);
 
-fs.mkdirSync(OUTDIR, { recursive: true });
-const enrichedN = data.filter(d => d.desc).length;
-const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
-<title>Daisy Bennett Natural Wallcoverings → Phillipe Romano — Onboard Preview</title>
+function dl(url, dest) {
+  return new Promise((res) => { const rq = (u, n = 0) => { if (n > 5) return res(false);
+    https.get(u, { timeout: 15000, headers: { 'User-Agent': 'curl/8' } }, r => {
+      if (r.statusCode >= 300 && r.statusCode < 400 && r.headers.location) return rq(r.headers.location, n + 1);
+      if (r.statusCode !== 200) { r.resume(); return res(false); }
+      const ws = fs.createWriteStream(dest); r.pipe(ws); ws.on('finish', () => { ws.close(); res(true); });
+    }).on('error', () => res(false)).on('timeout', function () { this.destroy(); res(false); }); }; rq(url); });
+}
+
+(async () => {
+  fs.mkdirSync(`${OUTDIR}/img`, { recursive: true });
+  const data = [];
+  let got = 0;
+  for (const r of recs) {
+    const remote = (r.images || []).find(u => /_650\./.test(u)) || (r.images || [])[0] || '';
+    let img = '';
+    if (remote) { const dest = `${OUTDIR}/img/${r.dw_sku}.jpg`; if (await dl(remote, dest)) { img = `img/${r.dw_sku}.jpg`; got++; } else img = remote; }
+    data.push({
+      dw_sku: r.dw_sku, mfr_sku: r.mfr_sku,
+      pattern: r.pattern || '', color: r.color || '',
+      family: (r.pattern || '').split(/\s+/).slice(-1)[0] || 'Naturals',
+      cost: r.price_retail, retail: r.our_price,
+      hex: r.color_hex || '', desc: r.ai_description || '',
+      img,
+    });
+  }
+  console.log(`downloaded ${got}/${recs.length} images locally`);
+  data.sort((a, b) => a.pattern.localeCompare(b.pattern) || a.color.localeCompare(b.color));
+
+  const enrichedN = data.filter(d => d.desc).length;
+  const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>Daisy Bennett Natural Wallcoverings → Phillipe Romano — Textiles</title>
 <style>
 :root{--cols:4;--bg:#faf8f4;--ink:#1a1a1a;--mut:#8a8377;--line:#e7e2d8;--accent:#3d5a4c}
 *{box-sizing:border-box}body{margin:0;font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;background:var(--bg);color:var(--ink)}
@@ -50,8 +77,8 @@ select{padding:5px 8px;border:1px solid var(--line);border-radius:6px;background
 body.showdesc .desc{display:block}
 </style></head><body>
 <header>
-<h1>Daisy Bennett · Natural Wallcoverings</h1>
-<div class="sub">Private-label onboard preview → <b>Phillipe Romano</b> · real pattern names · ${data.length} products · <b>DWAY-</b> SKUs (provisional) · <b>NOT PUBLISHED</b> (staged for approval)</div>
+<h1>Daisy Bennett · Natural Wallcoverings · Textiles</h1>
+<div class="sub">Real woven textiles only → <b>Phillipe Romano</b> · ${data.length} products (cork/mica/veneer excluded) · <b>DW</b>-material SKUs · <b>LIVE on Shopify</b></div>
 <div class="controls">
 <div><label>Sort</label><select id="sort" onchange="render()">
 <option value="pattern">Pattern → Color</option>
@@ -63,7 +90,7 @@ body.showdesc .desc{display:block}
 </select></div>
 <div><label>Density</label><input type="range" id="dens" min="2" max="7" value="4" oninput="setCols(this.value)"></div>
 <div><label><input type="checkbox" id="dc" onchange="document.body.classList.toggle('showdesc',this.checked)"> descriptions</label></div>
-<span class="pl">leak-safe: no WallQuest on cards · enriched ${enrichedN}/${data.length}</span>
+<span class="pl">local images · enriched ${enrichedN}/${data.length}</span>
 </div></header>
 <div class="grid" id="grid"></div>
 <script>
@@ -86,5 +113,6 @@ function render(){
 if(localStorage.dbCols)setCols(localStorage.dbCols);
 render();
 </script></body></html>`;
-fs.writeFileSync(`${OUTDIR}/index.html`, html);
-console.log(`viewer → ${OUTDIR}/index.html  (${data.length} products, enriched ${enrichedN})`);
+  fs.writeFileSync(`${OUTDIR}/index.html`, html);
+  console.log(`viewer → ${OUTDIR}/index.html  (${data.length} textiles, ${got} local imgs, enriched ${enrichedN})`);
+})();

← 3e22b8c9 Daisy Bennett Vol 2 -> LIVE: 65 products pushed+activated (P  ·  back to Designer Wallcoverings  ·  wallquest login CRACKED: real Chrome (channel:chrome persist 7efced75 →