← back to Fentucci Naturals

scripts/lookbook-verify.js

71 lines

#!/usr/bin/env node
// FIX 3 — verify the 5 zero-yield lookbook COLLECTIONS pages with a REAL
// rendered browser (Playwright chromium). The plain-fetch scraper found 0
// SKU-bearing items on these Wix Pro Gallery pages; gallery items can be
// client-hydrated, so the SSR-only result must be proven, not assumed.
// Counts ALL rendered wixstatic media imgs (empty alts included — an earlier
// version wrongly junk-filtered alt="" and reported 0 rendered imgs), checks
// alts AND rendered page text for SKU-shaped tokens, and writes evidence to
// data/lookbook-verification.json.
const fs = require('fs');
const path = require('path');
const { chromium } = require('/Users/macstudio3/Projects/Designer-Wallcoverings/node_modules/playwright');

const BASE = 'https://www.tokiwausa.com';
const PAGES = ['reflectionvol1', 'reflectionsvol2', 'greenbookcollection', 'glassbeadscollection', 'textilecollection'];
// site-chrome imgs (logo strip, social icons) — identified by size/uri, not alt
const SKUISH = /^([A-Z]{1,4}-?\d{3,5}[A-D]?|005-\d{3}-003(-\d+)?|[A-Z -]{2,20}NO\.\s?\d+|[A-Za-z ]+#\d+|[A-Z]{2,6}-[A-Z0-9]{0,8}\d)$/i;
const TEXT_SKU = /\b([A-Z]{1,4}-\d{3,5}[A-D]?|005-\d{3}-003-\d+|[A-Z]{2,10}\s?NO\.\s?\d+|KP\d{4}|GB-\d{4}|PD-\d{4})\b/g;

(async () => {
  const browser = await chromium.launch();
  const out = { checked_at: new Date().toISOString(), method: 'playwright chromium, waitUntil load + wix-media img-count stabilization (Wix long-polls; networkidle never fires) + full scroll (lazy-load) + settle; rendered DOM imgs incl. empty alts + rendered innerText scanned for SKU-shaped tokens', pages: {} };
  for (const slug of PAGES) {
    const page = await browser.newPage({ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36' });
    const url = `${BASE}/${slug}`;
    await page.goto(url, { waitUntil: 'load', timeout: 60000 });
    let prev = -1;
    for (let i = 0; i < 20; i++) {
      await page.waitForTimeout(1500);
      const n = await page.$$eval('img', els => els.filter(e => (e.currentSrc || e.src || '').includes('static.wixstatic.com/media')).length);
      if (n === prev && n > 0 && i >= 3) break;
      prev = n;
    }
    await page.evaluate(async () => {
      for (let y = 0; y < document.body.scrollHeight; y += 600) { window.scrollTo(0, y); await new Promise(r => setTimeout(r, 150)); }
      window.scrollTo(0, document.body.scrollHeight);
    });
    await page.waitForTimeout(6000);
    const imgs = await page.$$eval('img', els => els.map(e => ({
      src: e.currentSrc || e.src || '', alt: (e.alt || '').trim(),
      w: e.naturalWidth, h: e.naturalHeight, visible: !!(e.offsetWidth || e.offsetHeight),
    })));
    const text = await page.evaluate(() => document.body.innerText);
    const media = imgs.filter(i => i.src.includes('static.wixstatic.com/media'));
    // gallery items = visible, substantial renders (logo strip ~152x40, icons 20x20 excluded by size)
    const gallery = media.filter(i => i.visible && i.w >= 100 && i.h >= 100);
    const altBases = gallery.map(i => i.alt.replace(/\.(jpe?g|png|webp)$/i, '')).filter(Boolean);
    const skuAlts = [...new Set(altBases.filter(b => SKUISH.test(b)))];
    const skuText = [...new Set([...text.matchAll(TEXT_SKU)].map(m => m[1]))];
    out.pages[slug] = {
      url,
      page_title: await page.title(),
      rendered_wix_media_imgs: media.length,
      rendered_gallery_items: gallery.length,
      gallery_items_with_alt: altBases.length,
      sku_bearing_alts: skuAlts,
      sku_tokens_in_rendered_text: skuText,
      sample_alts: [...new Set(altBases)].slice(0, 15),
      sample_gallery_srcs: gallery.slice(0, 5).map(i => i.src.slice(0, 120)),
      verdict: (skuAlts.length || skuText.length)
        ? 'SKU-BEARING — scrape into pipeline'
        : 'lookbook-only: gallery renders room-scene/editorial spreads with no per-SKU alts or SKU text',
    };
    console.log(slug, JSON.stringify(out.pages[slug], null, 1));
    await page.close();
  }
  await browser.close();
  fs.writeFileSync(path.join(__dirname, '..', 'data', 'lookbook-verification.json'), JSON.stringify(out, null, 2));
  console.log('wrote data/lookbook-verification.json');
})();