← back to Dw Yolo Loop
scripts/empty-collections/empty-collections.mjs
39 lines
// empty-collections — READ-ONLY, $0. Officer-recommended (c59). Does the collections
// sitemap advertise LIVE collection URLs that render 0 products? Those are thin /
// soft-404-adjacent pages — and UNLIKE the c59 product case, collection URLs ARE in
// the sitemap, so they ARE actively submitted to Googlebot. VERIFY LIVE via the
// storefront /collections/<h>/products.json (reflects published products a shopper
// sees) — NOT the stale mirror collections_count (proven unreliable, c40).
const WWW='https://www.designerwallcoverings.com';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function get(u){for(let a=0;a<4;a++){try{const r=await fetch(u);if(r.status===429){await sleep(1200*(a+1));continue;}return {status:r.status,text:await r.text()};}catch(e){await sleep(800*(a+1));}}return {status:0,text:''};}
console.log('=== empty-collections (READ-ONLY, $0) ===\n');
const sm=await get(`${WWW}/sitemap_collections_1.xml?from=79864463472&to=301565804595`);
// real collection locs only (exclude nested image:loc .jpg entries)
const handles=[...new Set([...sm.text.matchAll(/<loc>https:\/\/[^<]*\/collections\/([^<\/?]+)<\/loc>/g)].map(m=>m[1]))];
console.log(`collections advertised in sitemap: ${handles.length}\n`);
const empty=[], small=[], errs=[];
let done=0;
for(const h of handles){
// limit=2 so we can distinguish 0 / 1 / 2+ cheaply
const r=await get(`${WWW}/collections/${h}/products.json?limit=2`);
if(r.status!==200){ errs.push({h,status:r.status}); done++; continue; }
let n=0; try{ n=(JSON.parse(r.text).products||[]).length; }catch{ errs.push({h,status:'parse'}); done++; continue; }
if(n===0) empty.push(h);
else if(n===1) small.push(h);
done++;
if(done%100===0) console.log(` ${done}/${handles.length} probed (empty so far: ${empty.length})`);
await sleep(120);
}
console.log(`\nprobed ${done}/${handles.length}`);
console.log(`EMPTY (0 products via products.json): ${empty.length}`);
console.log(`single-product (1): ${small.length}`);
console.log(`fetch/parse errors: ${errs.length}`);
if(empty.length){ console.log('\nsample empty collections:'); empty.slice(0,25).forEach(h=>console.log(' - '+h)); }
import fs from 'fs';
fs.writeFileSync('/tmp/empty-collections.json',JSON.stringify({ts:new Date().toISOString(),advertised:handles.length,empty,small,errs},null,2));
console.log('\nwrote /tmp/empty-collections.json (full list for live verification)');