fix(harvest): Download is a submenu parent — hover to unfurl 1K flyout, don't click; looser menu finder; reset seen-list (v2 key)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-07 23:04:22 +10:00
parent d3281bc251
commit 2dfa752df3

View File

@ -541,8 +541,14 @@ function findTileMenuButton(tile) {
}
function findMenuItem(re) {
return [...document.querySelectorAll('[role="menu"] [role="menuitem"], [role="menuitem"], [role="menu"] button, [role="dialog"] button')]
const roled = [...document.querySelectorAll('[role="menu"] [role="menuitem"], [role="menuitem"], [role="menu"] button, [role="dialog"] button')]
.filter(visible).find(e => re.test((e.textContent || '').trim()));
if (roled) return roled;
// fallback for menus without ARIA roles: small visible leaf nodes with matching text
const leaf = [...document.querySelectorAll('div, span, li, button')].filter(visible)
.filter(e => re.test((e.textContent || '').trim()) && (e.textContent || '').trim().length < 30 &&
!e.querySelector('div, span, li, button'));
return leaf.length ? (leaf[0].closest('[role="menuitem"], li, button') || leaf[0]) : null;
}
async function executeHarvest(task) {
@ -550,7 +556,7 @@ async function executeHarvest(task) {
let got = 0, missed = 0, skipped = 0;
try {
await waitForAgentReady(30000);
const stored = await new Promise(r => chrome.storage.local.get({ harvested_urls: [] }, d => r(d.harvested_urls)));
const stored = await new Promise(r => chrome.storage.local.get({ harvested_urls_v2: [] }, d => r(d.harvested_urls_v2)));
const seen = new Set(stored);
await bg({ type: 'harvestRouting', on: true });
window.scrollTo(0, 0); await sleep(800);
@ -568,14 +574,20 @@ async function executeHarvest(task) {
const dots = findTileMenuButton(tile);
if (!dots) { missed++; seen.add(href); log('info', `harvest: no ⋮ on a tile — ${gridCensus()}`); continue; }
await bg({ type: 'clickAt', ...center(dots) }); await sleep(800);
const dl = findMenuItem(/^\s*download\s*$/i);
if (!dl) { missed++; seen.add(href); await bg({ type: 'pressEscape' }); await sleep(400); continue; }
await bg({ type: 'clickAt', ...center(dl) }); await sleep(800);
const oneK = findMenuItem(/1k|original/i);
if (!oneK) { missed++; seen.add(href); await bg({ type: 'pressEscape' }); await sleep(400); continue; }
const dl = findMenuItem(/^\s*download\b/i);
if (!dl) { missed++; seen.add(href); log('info', `harvest: menu open but no Download item — ${gridCensus()}`); await bg({ type: 'pressEscape' }); await sleep(400); continue; }
// "Download" is a submenu parent: HOVER unfurls the nested 1K/2K/4K flyout
// (clicking it closes the menu — the bug the first pass hit).
await bg({ type: 'hoverAt', ...center(dl) }); await sleep(800);
let oneK = findMenuItem(/\b1k\b|original/i);
if (!oneK) { // some builds expand on click instead — try once
await bg({ type: 'clickAt', ...center(dl) }); await sleep(800);
oneK = findMenuItem(/\b1k\b|original/i);
}
if (!oneK) { missed++; seen.add(href); log('info', 'harvest: Download hovered but no 1K flyout appeared.'); await bg({ type: 'pressEscape' }); await sleep(400); continue; }
await bg({ type: 'clickAt', ...center(oneK) });
got++; seen.add(href);
chrome.storage.local.set({ harvested_urls: [...seen].slice(-3000) });
chrome.storage.local.set({ harvested_urls_v2: [...seen].slice(-3000) });
if (got % 10 === 0) log('info', `harvest: ${got} downloaded so far…`);
await sleep(1800 + Math.random() * 1500); // pace — don't machine-gun the account
}