feat: tile-link diffing + grid census — video harvest stops flying blind
- snapshotAssets also keys on /project/…/edit/<uuid> tile anchors: stable https, survive reloads (video blob srcs don't) — the reliable new-asset signal - harvestFresh splits diff into direct media (downloaded) vs tile links (reported as assets when no media url — credits not lost, recoverable from the library) - gridCensus appended to every miss so failures describe the actual harvest surface Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
39d133ddfb
commit
78b3ac85b0
53
content.js
53
content.js
@ -199,6 +199,9 @@ function snapshotAssets() {
|
||||
scope.querySelectorAll('a[href]').forEach(a => {
|
||||
if (a.hasAttribute('download') || /googleusercontent|media\.getMediaUrl|\/media\//i.test(a.href)) push(a.href);
|
||||
});
|
||||
// grid tiles are anchors to /project/<id>/edit/<uuid> — stable https keys that
|
||||
// survive reloads (video blob: srcs don't). The most reliable "new asset" signal.
|
||||
scope.querySelectorAll('a[href*="/edit/"]').forEach(a => push(a.href));
|
||||
// images: match media hosts + the redirect API + blobs (diffed before/after, so only NEW ones count)
|
||||
scope.querySelectorAll('img[src]').forEach(i => {
|
||||
if (/googleusercontent|lh3|ggpht|storage|media\.getMediaUrl|^blob:/i.test(i.src)) push(i.src);
|
||||
@ -277,6 +280,28 @@ async function waitForResultOrError(baseCount, maxMs, maxRetries = 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Split a fresh-URL diff into direct media vs tile links, download the media.
|
||||
async function harvestFresh(id, kind, category, fresh) {
|
||||
const tiles = fresh.filter(u => /\/edit\//.test(u));
|
||||
const media = fresh.filter(u => !/\/edit\//.test(u));
|
||||
const ext = kind === 'video' ? 'mp4' : 'png';
|
||||
const cat = (category || 'misc').replace(/[^a-z0-9_\-]/gi, '_');
|
||||
let saved = 0;
|
||||
for (let i = 0; i < media.length; i++) {
|
||||
const r = await bg({ type: 'download', url: media[i], filename: `flowrinse/${cat}/${id}_${i}.${ext}` });
|
||||
if (r && r.ok) saved++;
|
||||
}
|
||||
return { saved, media, tiles };
|
||||
}
|
||||
|
||||
// One line describing the harvest surface — appended to failures so a miss tells
|
||||
// us what the grid actually looked like instead of leaving us guessing.
|
||||
function gridCensus() {
|
||||
const q = s => document.querySelectorAll(s).length;
|
||||
return `census: video=${q('video')} videoSrc=${q('video[src]')} poster=${q('video[poster]')} ` +
|
||||
`img=${q('img[src]')} editTiles=${q('a[href*="/edit/"]')} dl=${q('a[download]')}`;
|
||||
}
|
||||
|
||||
// ---- queue loop ----------------------------------------------------------
|
||||
|
||||
// Entry point (Start / reload). Kicks the first poll soon; the rest is paced.
|
||||
@ -428,17 +453,9 @@ async function executeTask(task) {
|
||||
|
||||
const after = snapshotAssets();
|
||||
const fresh = [...after].filter(u => !before.has(u));
|
||||
log('success', `Harvested ${fresh.length} asset(s).`);
|
||||
|
||||
// Browser download — uses your session, no CSP/CORS. Lands in Downloads/flowrinse/<category>/.
|
||||
const ext = task.kind === 'video' ? 'mp4' : 'png';
|
||||
const cat = (task.category || 'misc').replace(/[^a-z0-9_\-]/gi, '_');
|
||||
let saved = 0;
|
||||
for (let i = 0; i < fresh.length; i++) {
|
||||
const r = await bg({ type: 'download', url: fresh[i], filename: `flowrinse/${cat}/${task.id}_${i}.${ext}` });
|
||||
if (r && r.ok) saved++;
|
||||
}
|
||||
if (fresh.length) log(saved === fresh.length ? 'success' : 'info', `Downloaded ${saved}/${fresh.length} → Downloads/flowrinse/${cat}/`);
|
||||
const { saved, media, tiles } = await harvestFresh(task.id, task.kind, task.category, fresh);
|
||||
if (media.length) log('success', `Downloaded ${saved}/${media.length} asset(s) → Downloads/flowrinse/.`);
|
||||
else if (tiles.length) log('info', `New tile detected but no direct media URL — reporting the tile link (recover later). ${gridCensus()}`);
|
||||
await reportCompletion(task.id, 'success', null, fresh);
|
||||
chrome.storage.local.remove('requeue_' + task.id);
|
||||
successCount++; consecutiveRateLimits = 0;
|
||||
@ -475,23 +492,19 @@ async function runPostReloadHarvest(ph) {
|
||||
if ((ph.tries || 0) < 2) {
|
||||
ph.tries = (ph.tries || 0) + 1;
|
||||
await new Promise(r => chrome.storage.local.set({ pendingHarvest: ph }, r));
|
||||
log('info', `Post-refresh grid shows nothing new yet — refresh ${ph.tries}/2 and re-check.`);
|
||||
log('info', `Post-refresh grid shows nothing new yet — refresh ${ph.tries}/2 and re-check. ${gridCensus()}`);
|
||||
await sleep(10000);
|
||||
const r = await bg({ type: 'hardReload' });
|
||||
if (!r || !r.ok) location.reload();
|
||||
return;
|
||||
}
|
||||
chrome.storage.local.remove('pendingHarvest');
|
||||
await reportCompletion(ph.id, 'failed', 'video generated but never surfaced in the grid after 3 loads', []);
|
||||
await reportCompletion(ph.id, 'failed', `video generated but never surfaced in the grid after 3 loads — ${gridCensus()}`, []);
|
||||
return;
|
||||
}
|
||||
const cat = (ph.category || 'misc').replace(/[^a-z0-9_\-]/gi, '_');
|
||||
let saved = 0;
|
||||
for (let i = 0; i < fresh.length; i++) {
|
||||
const r = await bg({ type: 'download', url: fresh[i], filename: `flowrinse/${cat}/${ph.id}_${i}.${ph.kind === 'video' ? 'mp4' : 'png'}` });
|
||||
if (r && r.ok) saved++;
|
||||
}
|
||||
log('success', `Post-refresh harvest: ${fresh.length} asset(s), downloaded ${saved} → Downloads/flowrinse/${cat}/.`);
|
||||
const { saved, media, tiles } = await harvestFresh(ph.id, ph.kind, ph.category, fresh);
|
||||
if (media.length) log('success', `Post-refresh harvest: downloaded ${saved}/${media.length} → Downloads/flowrinse/.`);
|
||||
else if (tiles.length) log('info', `Post-refresh: new tile found, no direct media URL — reporting tile link (recover later). ${gridCensus()}`);
|
||||
chrome.storage.local.remove('pendingHarvest');
|
||||
chrome.storage.local.remove('requeue_' + ph.id);
|
||||
await reportCompletion(ph.id, 'success', null, fresh);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user