tidaldb/applications/forage/extension/content.js
2026-02-23 22:41:16 -07:00

60 lines
1.8 KiB
JavaScript

/**
* Forage Chrome Extension — Content Script
*
* Injected into every page at document_idle. Reads page metadata and sends
* it to the background service worker, which POSTs to the Forage server.
* Also fires a dwell signal after 30 seconds of continuous page presence.
*/
(function () {
const url = location.href;
// Skip internal browser pages and the Forage UI itself to avoid
// self-referential signals and phantom items in the feed.
if (
url.startsWith('chrome://') ||
url.startsWith('chrome-extension://') ||
url.startsWith('moz-extension://') ||
/https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?/.test(url)
) {
return;
}
const canonical_url =
document.querySelector('link[rel="canonical"]')?.href || '';
const title = document.title || url;
const words = (document.body?.innerText || '').trim().split(/\s+/).length;
const reading_time_min = Math.max(1, Math.round(words / 200));
const description =
document.querySelector('meta[name="description"]')?.content ||
document.querySelector('meta[property="og:description"]')?.content ||
'';
const source = (() => {
try {
return new URL(url).hostname.replace(/^www\./, '');
} catch {
return '';
}
})();
let itemId = null;
// Send capture to background worker
chrome.runtime.sendMessage(
{ type: 'capture', url, canonical_url, title, source, description, reading_time_min },
response => {
if (response?.item_id) itemId = response.item_id;
}
);
// 30s dwell timer — cancelled if the user navigates away
const DWELL_MS = 30_000;
let dwellTimer = setTimeout(() => {
if (itemId == null) return;
chrome.runtime.sendMessage({ type: 'dwell', item_id: itemId, duration_ms: DWELL_MS });
}, DWELL_MS);
window.addEventListener('beforeunload', () => {
clearTimeout(dwellTimer);
});
})();