← 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
M scripts/wallquest-refresh/build-viewer-daisy-bennett.cjs
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 →