60 lines
1.8 KiB
JavaScript
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);
|
|
});
|
|
})();
|