summaryrefslogtreecommitdiff
path: root/background.js
diff options
context:
space:
mode:
authorsameerasw <[email protected]>2025-04-10 21:46:01 +0530
committersameerasw <[email protected]>2025-04-10 21:46:01 +0530
commitef561a67101def64da3150067c562d358bb8d802 (patch)
tree9ac9ed10ae814f536c76af4bfea00e935b8bdfd7 /background.js
parent02950d3ba50e3db6ac4c4a3f61cec1117f933cde (diff)
Initial commit for performance improvements
Diffstat (limited to 'background.js')
-rw-r--r--background.js232
1 files changed, 197 insertions, 35 deletions
diff --git a/background.js b/background.js
index 04adfd0..f7b5cb5 100644
--- a/background.js
+++ b/background.js
@@ -1,13 +1,169 @@
let SKIP_FORCE_THEMING_KEY = "skipForceThemingList";
let logging = false;
+// Create a cache for pre-processed CSS to speed up repeated visits
+const cssCache = new Map();
+const activeTabs = new Map();
+
+// Preload styles for faster injection
+async function preloadStyles() {
+ try {
+ const data = await browser.storage.local.get([
+ "styles",
+ "transparentZenSettings",
+ ]);
+ const settings = data.transparentZenSettings || {};
+
+ // No point in preloading if styling is disabled
+ if (settings.enableStyling === false) return;
+
+ // Clear the cache when reloaded to ensure fresh styles
+ cssCache.clear();
+
+ if (data.styles?.website) {
+ for (const [website, features] of Object.entries(data.styles.website)) {
+ // Process and store default CSS for each website (with all features enabled)
+ let combinedCSS = "";
+ for (const [feature, css] of Object.entries(features)) {
+ combinedCSS += css + "\n";
+ }
+ cssCache.set(website.replace(".css", ""), combinedCSS);
+ }
+ if (logging) console.log("Styles preloaded for faster injection");
+ }
+ } catch (error) {
+ console.error("Error preloading styles:", error);
+ }
+}
+
+// Handle web requests - allow injecting CSS before any content is loaded
+browser.webNavigation.onBeforeNavigate.addListener((details) => {
+ if (details.frameId === 0) {
+ // Only for main frame
+ // Track active navigations
+ activeTabs.set(details.tabId, details.url);
+
+ // Pre-fetch any styling needed for this URL
+ prepareStylesForUrl(new URL(details.url).hostname, details.tabId);
+ }
+});
+
+// Listen for content scripts announcing they're ready
+browser.runtime.onMessage.addListener(async (message, sender) => {
+ if (message.action === "contentScriptReady" && message.hostname) {
+ try {
+ // Look for cached styles for this hostname or its domain match
+ const hostname = message.hostname;
+
+ // Get settings to check if styling is enabled
+ const settingsData = await browser.storage.local.get(
+ "transparentZenSettings"
+ );
+ const settings = settingsData.transparentZenSettings || {};
+
+ if (settings.enableStyling === false) return;
+
+ const css = await getStylesForHostname(hostname, settings);
+
+ // If we found matching CSS, send it immediately to the content script
+ if (css) {
+ browser.tabs
+ .sendMessage(sender.tab.id, {
+ action: "applyStyles",
+ css: css,
+ })
+ .catch((err) => {
+ if (logging) console.log("Failed to send immediate CSS:", err);
+ });
+ }
+ } catch (error) {
+ console.error("Error handling content script ready message:", error);
+ }
+ } else if (message.action === "enableAutoUpdate") {
+ startAutoUpdate();
+ return true;
+ } else if (message.action === "disableAutoUpdate") {
+ stopAutoUpdate();
+ return true;
+ }
+
+ return false;
+});
+
+// Get appropriate styles for a hostname based on all rules
+async function getStylesForHostname(hostname, settings) {
+ // Check for exact matches
+ if (cssCache.has(hostname)) {
+ return cssCache.get(hostname);
+ } else if (cssCache.has(`www.${hostname}`)) {
+ return cssCache.get(`www.${hostname}`);
+ } else {
+ // Check for wildcard matches (+domain.com)
+ for (const [cachedSite, cachedCSS] of cssCache.entries()) {
+ if (cachedSite.startsWith("+")) {
+ const baseSite = cachedSite.slice(1);
+ if (hostname.endsWith(baseSite)) {
+ return cachedCSS;
+ }
+ } else if (hostname.endsWith(cachedSite)) {
+ return cachedCSS;
+ }
+ }
+
+ // Check for forced styles
+ if (settings.forceStyling) {
+ const skipListData = await browser.storage.local.get(
+ SKIP_FORCE_THEMING_KEY
+ );
+ const siteList = skipListData[SKIP_FORCE_THEMING_KEY] || [];
+ const isWhitelistMode = settings.whitelistMode || false;
+ const siteInList = siteList.includes(hostname);
+
+ // In whitelist mode: apply only if site is in the list
+ // In blacklist mode: apply only if site is NOT in the list
+ if (
+ (isWhitelistMode && siteInList) ||
+ (!isWhitelistMode && !siteInList)
+ ) {
+ return cssCache.get("example.com");
+ }
+ }
+ }
+
+ return null;
+}
+
+// Prepare styles for a URL that's about to load
+async function prepareStylesForUrl(hostname, tabId) {
+ try {
+ const settingsData = await browser.storage.local.get(
+ "transparentZenSettings"
+ );
+ const settings = settingsData.transparentZenSettings || {};
+
+ if (settings.enableStyling === false) return;
+
+ const css = await getStylesForHostname(hostname, settings);
+
+ if (css && tabId) {
+ // Store the CSS to be ready as soon as the content script connects
+ activeTabs.set(tabId, {
+ hostname: hostname,
+ css: css,
+ });
+ }
+ } catch (error) {
+ console.error("Error preparing styles for URL:", error);
+ }
+}
+
async function applyCSSToTab(tab) {
if (logging) console.log("applyCSSToTab called with", tab);
- // Apply CSS to the specified tab
- const url = new URL(tab.url);
- const hostname = url.hostname;
try {
+ const url = new URL(tab.url);
+ const hostname = url.hostname;
+
const settings = await browser.storage.local.get("transparentZenSettings");
const globalSettings = settings.transparentZenSettings || {};
if (globalSettings.enableStyling === false) return;
@@ -71,7 +227,7 @@ async function applyCSSToTab(tab) {
}
}
} catch (error) {
- console.error(`Error applying CSS to ${hostname}:`, error);
+ console.error(`Error applying CSS:`, error);
}
}
@@ -90,7 +246,19 @@ async function applyCSS(tabId, hostname, features) {
}
if (combinedCSS) {
- await browser.tabs.insertCSS(tabId, { code: combinedCSS });
+ try {
+ // Try to send via messaging (most reliable for instant application)
+ await browser.tabs.sendMessage(tabId, {
+ action: "applyStyles",
+ css: combinedCSS,
+ });
+ } catch (e) {
+ // Fallback to insertCSS if messaging fails
+ await browser.tabs.insertCSS(tabId, {
+ code: combinedCSS,
+ runAt: "document_start",
+ });
+ }
console.log(`Injected custom CSS for ${hostname}`);
}
}
@@ -99,66 +267,60 @@ let autoUpdateInterval;
function startAutoUpdate() {
if (logging) console.log("startAutoUpdate called");
- // Start the auto-update interval
if (autoUpdateInterval) clearInterval(autoUpdateInterval);
autoUpdateInterval = setInterval(refetchCSS, 2 * 60 * 60 * 1000);
}
function stopAutoUpdate() {
if (logging) console.log("stopAutoUpdate called");
- // Stop the auto-update interval
if (autoUpdateInterval) clearInterval(autoUpdateInterval);
}
async function refetchCSS() {
if (logging) console.log("refetchCSS called");
- // Refetch CSS styles from the remote server
try {
const response = await fetch(
"https://sameerasw.github.io/my-internet/styles.json",
- {
- headers: { "Cache-Control": "no-cache" },
- }
+ { headers: { "Cache-Control": "no-cache" } }
);
if (!response.ok) throw new Error("Failed to fetch styles.json");
const styles = await response.json();
await browser.storage.local.set({ styles });
await browser.storage.local.set({ lastFetchedTime: Date.now() });
console.info("All styles refetched and updated from GitHub.");
+
+ // Preload the new styles
+ preloadStyles();
} catch (error) {
console.error("Error refetching styles:", error);
}
}
-browser.runtime.onMessage.addListener((message) => {
- if (logging) console.log("onMessage received", message);
- // Handle messages for enabling/disabling auto-update
- if (message.action === "enableAutoUpdate") {
- startAutoUpdate();
- } else if (message.action === "disableAutoUpdate") {
- stopAutoUpdate();
- }
-});
+// Create a directory to store CSS files
+async function initializeExtension() {
+ // Preload styles immediately
+ await preloadStyles();
-// Initialize auto-update based on stored settings
-browser.storage.local.get("transparentZenSettings").then((settings) => {
- if (logging) console.log("Initial settings loaded", settings);
+ // Initialize auto-update based on stored settings
+ const settings = await browser.storage.local.get("transparentZenSettings");
if (settings.transparentZenSettings?.autoUpdate) {
startAutoUpdate();
}
-});
+}
-browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
- // if (logging) console.log("onUpdated called with", tabId, changeInfo, tab);
- // Apply CSS when a tab is updated
- if (changeInfo.status === "complete" || changeInfo.status === "loading") {
- applyCSSToTab(tab);
+// Listen for specific navigation events to apply CSS as early as possible
+browser.webNavigation.onCommitted.addListener((details) => {
+ if (details.frameId === 0) {
+ browser.tabs
+ .get(details.tabId)
+ .then((tab) => {
+ applyCSSToTab(tab);
+ })
+ .catch((err) => {
+ console.error("Error getting tab info:", err);
+ });
}
});
-browser.tabs.onActivated.addListener(async (activeInfo) => {
- if (logging) console.log("onActivated called with", activeInfo);
- // Apply CSS when a tab is activated
- const tab = await browser.tabs.get(activeInfo.tabId);
- applyCSSToTab(tab);
-});
+// Application start
+initializeExtension();