← back to George Gmail

trash-redfin-zillow.js

71 lines

const fs=require("fs");const {google}=require("googleapis");
const env={};fs.readFileSync("/root/Projects/Designer-Wallcoverings/DW-MCP/.env","utf8").split("\n").forEach(l=>{const m=l.match(/^([^#=]+)=(.+)/);if(m)env[m[1].trim()]=m[2].trim()});
const accts=[
  {k:"steve-office",l:"steve@designerwallcoverings.com",r:env.GMAIL_REFRESH_TOKEN},
  {k:"info",l:"info@designerwallcoverings.com",r:env.INFO_REFRESH_TOKEN},
  {k:"steve-personal",l:"steveabramsdesigns@gmail.com",r:env.PERSONAL_REFRESH_TOKEN},
];
const QUERY = "redfin OR zillow";

const totals = { collected: 0, trashed: 0, byAccount: {} };
const auditPath = "/root/DW-Agents/logs/george-workspace-audit.log";

(async()=>{
  for(const a of accts){
    const oc=new google.auth.OAuth2(env.GMAIL_CLIENT_ID,env.GMAIL_CLIENT_SECRET,"http://localhost:9850/oauth2callback");
    oc.setCredentials({refresh_token:a.r});
    const gm=google.gmail({version:"v1",auth:oc});
    console.log(`\n=== ${a.l} ===`);

    // 1. Collect all message IDs matching the query
    const ids=[];let pageToken=null,pages=0;
    const t0=Date.now();
    do{
      const r=await gm.users.messages.list({userId:"me",q:QUERY,maxResults:500,pageToken:pageToken||undefined});
      (r.data.messages||[]).forEach(m=>ids.push(m.id));
      pageToken=r.data.nextPageToken||null;
      pages++;
      if(pages%20===0) process.stdout.write(`    collecting... ${ids.length} IDs so far\n`);
    }while(pageToken);
    console.log(`  collected ${ids.length} message IDs in ${((Date.now()-t0)/1000).toFixed(1)}s (${pages} pages)`);
    totals.collected += ids.length;
    totals.byAccount[a.l] = { collected: ids.length, trashed: 0 };

    if(ids.length === 0) continue;

    // 2. Batch-modify: add TRASH label (remove INBOX for cleanliness)
    const BATCH = 1000;
    const t1=Date.now();
    for(let i=0; i<ids.length; i+=BATCH){
      const chunk = ids.slice(i, i+BATCH);
      try {
        await gm.users.messages.batchModify({
          userId:"me",
          requestBody:{
            ids: chunk,
            addLabelIds: ["TRASH"],
            removeLabelIds: ["INBOX"]
          }
        });
        totals.trashed += chunk.length;
        totals.byAccount[a.l].trashed += chunk.length;
        process.stdout.write(`    trashed ${i+chunk.length}/${ids.length}\n`);
      } catch(e) {
        console.log(`    batch ${Math.floor(i/BATCH)+1} failed: ${e.message.slice(0,120)}`);
      }
    }
    const elapsed = ((Date.now()-t1)/1000).toFixed(1);
    console.log(`  trashed ${totals.byAccount[a.l].trashed} in ${elapsed}s`);
    // Audit log
    try {
      fs.appendFileSync(auditPath, `${new Date().toISOString()}\t${a.k}\tgmail.batchTrash\t${JSON.stringify({query:QUERY, count: totals.byAccount[a.l].trashed})}\n`);
    } catch {}
  }

  console.log("\n=== FINAL ===");
  for(const [email,v] of Object.entries(totals.byAccount)){
    console.log(`  ${email}: ${v.trashed}/${v.collected} trashed`);
  }
  console.log(`  TOTAL: ${totals.trashed}/${totals.collected} trashed`);
})();