← back to Retrowalls

scripts/pull-from-shopify.js

86 lines

// Paginate DW Shopify /products.json, filter to retro by tags + keywords
const https = require('https');
const fs = require('fs');
const { classifyAesthetic } = require('../../_shared/microsite-aesthetic');
const SITE_CFG_RAILS = (() => { try { return require('../site.config.json').rails || []; } catch { return []; } })();

const RETRO_TAGS = /^(art deco|deco|midcentury|mid-century|atomic|psychedelic|vintage|retro|paisley|geometric|moroccan|damask|toile|jacquard|art nouveau|nouveau|asian|chinoiserie|mod|bohemian|victorian|baroque|rococo|abstract)$/i;
const RETRO_TITLE = /\b(retro|vintage|midcentury|atomic|deco|paisley|geometric|moroccan|psychedelic|damask|op art|toile|nouveau|chinoiserie)\b/i;
const REJECT_TITLE = /(visual.{0,3}merchandiser|bh.?90210|beverly.?hills.?90210|iconic.{0,4}bh|\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 retrowalls-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(tags, title) {
  const t = (tags || []).map(x => x.toLowerCase()).join(' ');
  const tt = (title || '').toLowerCase();
  if (/atomic|midcentury|mid-century|psychedelic|op art|\b70s\b|\b60s\b/.test(t + ' ' + tt)) return 'midcentury';
  if (/art deco|art nouveau|nouveau/.test(t + ' ' + tt)) return 'deco';
  if (/damask|toile|jacquard|baroque|rococo/.test(t + ' ' + tt)) return 'damask';
  if (/paisley|moroccan|chinoiserie|asian|bohemian|persian|ikat|kilim|suzani/.test(t + ' ' + tt)) return 'global';
  if (/geometric|chevron|herringbone|argyle|trellis|fretwork/.test(t + ' ' + tt)) return 'geometric';
  if (/abstract/.test(t + ' ' + tt)) return 'abstract';
  return 'vintage';
}

function classifyForSite(tags, title) {
  const railsMatch = classifyAesthetic(tags, SITE_CFG_RAILS);
  if (railsMatch && railsMatch !== 'all') return railsMatch;
  return aestheticOf(tags, title);
}

(async () => {
  const all = [];
  for (let page = 1; page <= 30; page++) {
    const products = await fetchPage(page);
    if (!products.length) break;
    all.push(...products);
    process.stdout.write(`page ${page}: ${products.length} (total ${all.length})\n`);
    if (products.length < 250) break;
  }
  console.log(`\ntotal fetched: ${all.length}`);

  const retro = 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 => {
      const hasRetroTag = (p.tags || []).some(t => RETRO_TAGS.test(t));
      const hasRetroTitle = RETRO_TITLE.test(p.title || '');
      return hasRetroTag || hasRetroTitle;
    })
    .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(`retro filtered: ${retro.length}`);

  // breakdown
  const byA = {};
  for (const p of retro) byA[p.aesthetic] = (byA[p.aesthetic] || 0) + 1;
  console.log('aesthetics:', byA);

  fs.writeFileSync('/Users/macstudio3/Projects/retrowalls/data/products.json', JSON.stringify(retro, null, 2));
  console.log('wrote products.json');
})();