diff --git a/background.js b/background.js index 137a4cd..8344c1e 100644 --- a/background.js +++ b/background.js @@ -1,8 +1,10 @@ -const SCROBBLE_ENDPOINT = "https://life.lab.unbl.ink/?scrobble_url="; -const STOP_ENDPOINT = "https://life.lab.unbl.ink/?action=stop&scrobble_url="; +// ======== Life Scrobbler Extension ======== +// Fully self-contained version with base64 icons +// Stop scrobble code is commented out for now +// ====== Default Settings ====== const DEFAULT_SETTINGS = { - delay: 7, + delay: 8, blacklist: [ "*.unbl.ink", "moz-extension://", @@ -21,9 +23,23 @@ const DEFAULT_SETTINGS = { "*.todoist.com", ], paused: false, - siteDelays: { "readscomisconline.ru": 1 }, + siteDelays: { "readcomicsonline.ru": 1 }, + scrobbleBaseUrl: "https://life.lab.unbl.ink", }; +// ====== Base64 icons ====== +const ICONS = { + wait: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...", + scrobbled: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...", + stopped: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...", + pause: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...", +}; + +// ====== State ====== +let activeTabs = new Map(); // tabId -> timeout +let pausedTabs = new Set(); // tabIds that are paused + +// ====== Utility Functions ====== function matchPattern(url, pattern) { if (pattern.startsWith("*.")) { const domain = pattern.slice(2); @@ -36,11 +52,56 @@ function isBlacklisted(url, blacklist) { return blacklist.some((p) => matchPattern(url, p)); } +async function getSettings() { + return new Promise((resolve) => { + browser.storage.local.get(DEFAULT_SETTINGS, resolve); + }); +} + +async function setPaused(tabId, paused) { + if (paused) pausedTabs.add(tabId); + else pausedTabs.delete(tabId); + + updateIcon(tabId, paused ? "pause" : "wait"); + // persist globally + await browser.storage.local.set({ paused }); +} + +function updateIcon(tabId, state) { + browser.browserAction.setIcon({ path: ICONS[state], tabId }); +} + +// ====== Scrobble Start ====== +async function scrobbleStart(url, baseUrl) { + const endpoint = `${baseUrl}/?scrobble_url=${encodeURIComponent(url)}`; + try { + await fetch(endpoint, { method: "GET" }); + console.log("LifeScrobbler: scrobbled", url); + } catch (err) { + console.error("LifeScrobbler: failed scrobble", url, err); + } +} + +// ====== Scrobble Stop ====== +async function scrobbleStop(url, baseUrl) { + const endpoint = `${baseUrl}/?action=stop&scrobble_url=${encodeURIComponent(url)}`; + try { + await fetch(endpoint, { method: "GET" }); + console.log("LifeScrobbler: stopped", url); + } catch (err) { + console.error("LifeScrobbler: stop failed", url, err); + } +} + +// ====== Delay for given URL ====== function getDelayForUrl(url, settings) { try { const u = new URL(url); + console.log(u); for (const [domain, customDelay] of Object.entries(settings.siteDelays)) { + console.log(domain, customDelay, u.hostname, domain == u.hostname); if (u.hostname.includes(domain)) { + console.log("Found custom delay of ", customDelay); return customDelay; } } @@ -48,44 +109,28 @@ function getDelayForUrl(url, settings) { return settings.delay; } -let activeTabs = new Map(); - -// Load settings -async function getSettings() { - return new Promise((resolve) => { - browser.storage.local.get(DEFAULT_SETTINGS, (items) => resolve(items)); - }); -} - -// Save pause state -async function setPaused(paused) { - await browser.storage.local.set({ paused }); - updateIcon(paused ? "pause" : "wait"); -} - -function updateIcon(state) { - const icons = { - wait: "icons/wait.png", - scrobbled: "icons/check.png", - stopped: "icons/stop.png", - pause: "icons/pause.png", - }; - browser.browserAction.setIcon({ path: icons[state] }); -} - -// Handle tab updates +// ====== Tab Updates ====== browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { if (changeInfo.status !== "complete" || !tab.url) return; - const settings = await getSettings(); - const { delay, blacklist, paused } = await getSettings(); - if (paused || isBlacklisted(tab.url, blacklist)) return; - if (tab.url.startsWith("moz-extension://")) return; + const { delay, blacklist, scrobbleBaseUrl, paused } = await getSettings(); + const url = tab.url; - const url = encodeURIComponent(tab.url); - updateIcon("wait"); + // Skip if globally paused or blacklisted + console.log( + "Globally paused? ", + paused, + " - Is this tab paused? ", + pausedTabs.has(tabId), + " - Is site blacklisted? ", + isBlacklisted(url, blacklist), + ); + + if (paused || pausedTabs.has(tabId) || isBlacklisted(url, blacklist)) return; + updateIcon(tabId, "wait"); const siteDelay = getDelayForUrl(url, await getSettings()); + console.log("Waiting " + siteDelay + " seconds before scrobbling ..."); if (activeTabs.has(tabId)) clearTimeout(activeTabs.get(tabId)); const timeout = setTimeout(() => { @@ -97,27 +142,22 @@ browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { activeTabs.set(tabId, timeout); }); -// Stop scrobble when navigating away or closing -function stopScrobble(tabId, url) { - getSettings().then(({ blacklist }) => { - if (!url || isBlacklisted(url, blacklist)) return; - if (url.startsWith("moz-extension://")) return; - fetch(`${STOP_ENDPOINT}${encodeURIComponent(url)}`).then(() => - updateIcon("stopped"), - ); - }); -} +// ====== Pause Toggle via Toolbar Icon ====== +browser.browserAction.onClicked.addListener(async (tab) => { + const { paused } = await getSettings(); + const tabPaused = pausedTabs.has(tab.id) || paused; + setPaused(tab.id, !tabPaused); +}); +// ====== Clean up on Tab Close ====== browser.tabs.onRemoved.addListener((tabId) => { if (activeTabs.has(tabId)) clearTimeout(activeTabs.get(tabId)); + pausedTabs.delete(tabId); }); -//browser.webNavigation.onBeforeNavigate.addListener((details) => { -// stopScrobble(details.tabId, details.url); -//}); - -// Toggle pause on icon click -browser.browserAction.onClicked.addListener(async () => { - const { paused } = await getSettings(); - setPaused(!paused); +// ====== Web Navigation stop code is commented ====== +browser.webNavigation.onBeforeNavigate.addListener((details) => { + const { scrobbleBaseUrl } = DEFAULT_SETTINGS; + // scrobbleStop(details.url, scrobbleBaseUrl); + // TODO need to fix this in Scrobbler to check if a running scrobble exists and stop if it does });