← back to 1960swallpaper
scripts/pull-from-shopify.js
110 lines
// 1960s wallpaper pull from live DW Shopify catalog.
// Era tags don't exist in catalog. TITLE-PATTERN allowlist of known 60s/mod/
// op-art/psychedelic patterns already in inventory.
const https = require('https');
const fs = require('fs');
const path = require('path');
const { classifyAesthetic } = require('../../_shared/microsite-aesthetic');
const SITE_CFG_RAILS = (() => { try { return require('../site.config.json').rails || []; } catch { return []; } })();
const PATTERN_REGEX = new RegExp([
// Rebel Walls
'tie\\s*dye\\s*kaleidoscope',
'paper\\s*kaleidoscope',
'kaleidoscope',
// Jeffrey Stevens
'siliano\\s*stone\\s*kaleidoscope',
// Cole & Son
'circus',
'punchinello',
'luxor\\s*linen',
'riviera\\s*linen',
'deco\\s*palm',
// Coordonné
'juko\\s*japanese\\s*waves',
'waves\\s*of\\s*the\\s*east',
'paseo\\s*pastel\\s*geometric',
'amore\\s*mondrian',
// DW Bespoke Studio
'balogna\\s*balloon',
"birmingham\\s*1940'?s\\s*butterfly\\s*retro",
// Kravet
'metromod',
'modern\\s*swirl',
'niko\\s*mod',
// PR Faux Leather
"wanda'?s\\s*wavy\\s*stripe",
].join('|'), 'i');
const REJECT_TITLE = /(visual.{0,3}merchandiser|bh.?90210|\bimage[ _-]?4\b|lamp|rug|pillow|throw|tripod|frame|mirror|vase|candle|sculpture|figurine)/i;
function fetchPage(page) {
return new Promise((resolve, reject) => {
https.get(`https://designerwallcoverings.com/products.json?limit=250&page=${page}`, {
headers: { 'User-Agent': 'Mozilla/5.0 1960swallpaper-builder' }
}, (res) => {
let data = '';
res.on('data', c => data += c);
res.on('end', () => { try { resolve(JSON.parse(data).products || []); } catch(e) { reject(e); } });
}).on('error', reject);
});
}
function aestheticOf(title) {
const t = (title || '').toLowerCase();
if (/kaleidoscope|tie\s*dye/.test(t)) return 'psychedelic';
if (/swirl|wavy|waves/.test(t)) return 'op-art';
if (/mod|metromod|niko|mondrian|geometric/.test(t)) return 'mod';
if (/circus|punchinello|balloon|butterfly/.test(t)) return 'whimsy';
if (/linen|palm/.test(t)) return 'mid-century';
return '1960s';
}
function classifyForSite(tags, title) {
const railsMatch = classifyAesthetic(tags, SITE_CFG_RAILS);
if (railsMatch && railsMatch !== 'all') return railsMatch;
return aestheticOf(title);
}
(async () => {
const all = [];
for (let page = 1; page <= 30; page++) {
const products = await fetchPage(page);
if (!products.length) break;
all.push(...products);
if (products.length < 250) break;
}
console.log(`fetched: ${all.length}`);
const niche = all
.filter(p => p.product_type && /wallcovering/i.test(p.product_type))
.filter(p => !REJECT_TITLE.test(p.title || ''))
.filter(p => p.images && p.images.length > 0 && p.images[0].src)
.filter(p => PATTERN_REGEX.test(p.title || ''))
.map(p => ({
sku: p.handle,
handle: p.handle,
title: p.title,
vendor: (p.vendor || '').trim(),
product_type: p.product_type,
image_url: p.images[0].src,
tags: p.tags || [],
aesthetic: classifyForSite(p.tags, p.title),
product_url: `https://designerwallcoverings.com/products/${p.handle}`,
}));
console.log(`niche-filtered: ${niche.length}`);
const byA = {};
for (const p of niche) byA[p.aesthetic] = (byA[p.aesthetic] || 0) + 1;
console.log('aesthetics:', byA);
const byV = {};
for (const p of niche) byV[p.vendor] = (byV[p.vendor] || 0) + 1;
console.log('vendors:', Object.entries(byV).sort((a,b)=>b[1]-a[1]));
const tmp = path.join(__dirname, '..', 'data', 'products.json.tmp');
const final = path.join(__dirname, '..', 'data', 'products.json');
fs.writeFileSync(tmp, JSON.stringify(niche, null, 2));
fs.renameSync(tmp, final);
console.log('wrote data/products.json');
})();