← back to Eur Recrawl

probe-dg.mjs

89 lines

// probe-dg.mjs <MFR_CODE> — reuse the authed DG session (.auth/dg) to (1) confirm we're
// logged in and (2) find where a pattern's LOGGED-IN price renders. Read-only recon.
//   node probe-dg.mjs PDG674
import { chromium } from 'playwright';
import path from 'node:path';

const arg = (process.argv[2] || '').trim();
if (!arg) { console.error('usage: node probe-dg.mjs <MFR_CODE | product-URL>'); process.exit(1); }
const isUrl = /^https?:\/\//i.test(arg);
const base = isUrl ? '' : arg.split(/[\/\-]/)[0];

const ctx = await chromium.launchPersistentContext(path.join(process.cwd(), '.auth', 'dg'), {
  headless: false, channel: 'chrome', viewport: { width: 1440, height: 900 },
});
const page = ctx.pages()[0] || await ctx.newPage();

if (isUrl) {
  await page.goto(arg, { waitUntil: 'domcontentloaded', timeout: 60000 }).catch((e) => console.log('nav', e.message));
  await page.waitForTimeout(4000);
  const info = await page.evaluate(() => {
    const t = document.body ? document.body.innerText : '';
    const authed = /log ?out|sign ?out|my account/i.test(t);
    // any element whose class/id/data mentions price -> its trimmed text
    const priceEls = [...document.querySelectorAll('[class*=price i],[id*=price i],[data-price],[class*=cost i]')]
      .map((el) => (el.innerText || el.getAttribute('data-price') || '').trim())
      .filter((x) => x && x.length < 60);
    // any number that looks like money even without a currency symbol
    const nums = [...t.matchAll(/\b\d{2,4}\.\d{2}\b/g)].map((m) => m[0]).slice(0, 20);
    // links mentioning trade (find the separate Trade Site)
    const tradeLinks = [...document.querySelectorAll('a[href]')]
      .filter((a) => /trade/i.test(a.href) || /trade/i.test(a.innerText || ''))
      .map((a) => `${(a.innerText || '').trim().slice(0, 20)} -> ${a.href}`).slice(0, 12);
    return { url: location.href, title: document.title, authed, priceEls: [...new Set(priceEls)].slice(0, 20), nums, tradeLinks: [...new Set(tradeLinks)] };
  });
  console.log(`authed(hasLogout)=${info.authed}`);
  console.log(`landed: ${info.title.slice(0, 80)} @ ${info.url}`);
  console.log(`price ELEMENTS: ${info.priceEls.length ? JSON.stringify(info.priceEls) : '(none)'}`);
  console.log(`money-like nums: ${info.nums.length ? info.nums.join(' | ') : '(none)'}`);
  console.log(`trade links:\n  ${info.tradeLinks.length ? info.tradeLinks.join('\n  ') : '(none)'}`);
  await page.screenshot({ path: 'probe-dg-result.png', fullPage: true }).catch(() => {});
  console.log('screenshot -> probe-dg-result.png');
  await page.waitForTimeout(1200);
  await ctx.close();
  process.exit(0);
}

// 1) auth check on the homepage
await page.goto('https://www.designersguild.com/en-us', { waitUntil: 'domcontentloaded', timeout: 60000 }).catch((e) => console.log('nav', e.message));
await page.waitForTimeout(3000);
const auth = await page.evaluate(() => {
  const t = document.body ? document.body.innerText : '';
  return { loggedOut: /trade login|sign in|log in\b/i.test(t) && !/log ?out|sign ?out|my account/i.test(t), hasLogout: /log ?out|sign ?out|my account/i.test(t) };
});
console.log(`auth: hasLogout=${auth.hasLogout}  looksLoggedOut=${auth.loggedOut}  @ ${page.url()}`);

// 2) search via the real search box
try {
  const box = await page.$('#product-search-input, input[name="search-term"]');
  if (box) {
    await box.click().catch(() => {});
    await box.fill(base).catch(() => {});
    const submit = await page.$('#search-box-submit');
    if (submit) await submit.click().catch(() => {});
    else await page.keyboard.press('Enter').catch(() => {});
    await page.waitForTimeout(4000);
    console.log(`[search "${base}"] -> ${(await page.title().catch(() => '')).slice(0, 60)} @ ${page.url()}`);
    // click first product result
    const link = await page.$('a[href*="/wallpaper"], a[href*="/product"], a[href*="/fabric"], .product-tile a, [class*=product] a[href]');
    if (link) {
      const href = await link.getAttribute('href').catch(() => null);
      if (href) { await page.goto(new URL(href, page.url()).href, { waitUntil: 'domcontentloaded', timeout: 45000 }).catch(() => {}); await page.waitForTimeout(3500); }
    }
  } else { console.log('search box not found'); }
} catch (e) { console.log('search error:', e.message); }

const info = await page.evaluate(() => {
  const t = document.body ? document.body.innerText : '';
  const prices = [...t.matchAll(/(?:£|\$|€|USD|GBP)\s?\d[\d.,]*/g)].map((m) => m[0]).slice(0, 30);
  const labels = [...t.matchAll(/(trade|net|retail|rrp|your price)[^\n]{0,25}/gi)].map((m) => m[0].trim()).slice(0, 12);
  return { url: location.href, title: document.title, prices, labels };
});
console.log(`landed: ${info.title.slice(0, 70)} @ ${info.url}`);
console.log(`price strings: ${info.prices.length ? info.prices.join(' | ') : '(none)'}`);
console.log(`price labels : ${info.labels.length ? info.labels.join(' | ') : '(none)'}`);
await page.screenshot({ path: 'probe-dg-result.png', fullPage: false }).catch(() => {});
console.log('screenshot -> probe-dg-result.png');
await page.waitForTimeout(1500);
await ctx.close();