// background.js const runtimeAPI = typeof browser !== 'undefined' ? browser : chrome; const storageAPI = runtimeAPI.storage.local; let currentBgmAudio = null; let bgmEnabledState = false; let logs = []; // In-memory log cache let currentPoints = 0; // In-memory points cache const DEBUG_REDIRECT_SERIAL = "PC156494873"; // Centralized constant // --- Initialization on startup --- async function initializeBackground() { try { const result = await storageAPI.get(['bgmEnabled', 'logs', 'pts']); bgmEnabledState = result.bgmEnabled === true; logs = result.logs || []; currentPoints = result.pts || 0; console.log("Background: Initial states loaded. BGM:", bgmEnabledState, "Logs count:", logs.length, "Points:", currentPoints); } catch (error) { console.error("Background: Error during initialization:", error); } } initializeBackground(); // --- Web Request Listeners --- // 1. Block specific requests (title_manager.js) runtimeAPI.webRequest.onBeforeRequest.addListener( function(details) { if (details.url.includes("title_manager.js")) { console.log("Background: Blocking request for:", details.url); return { cancel: true }; } return {}; }, { urls: [""] }, ["blocking"] ); // 2. Handle all miip:// requests runtimeAPI.webRequest.onBeforeRequest.addListener( function(details) { console.log("Background: Intercepted URL:", details.url); if (details.url.startsWith('miip://')) { const redirectUrl = runtimeAPI.runtime.getURL("images/mii.bmp"); console.log("Background: Redirecting miip:// to:", redirectUrl); return { redirectUrl: redirectUrl }; } return {}; }, { urls: [""] }, // Listen for all URLs to catch miip:// scheme ["blocking"] ); // 3. Redirect debug.jsp if Serial parameter is missing runtimeAPI.webRequest.onBeforeRequest.addListener( function(details) { const url = new URL(details.url); if (url.pathname.includes('/oss/serv/debug.jsp')) { const serialParam = url.searchParams.get('Serial'); if (!serialParam) { console.warn("Background: Intercepted debug.jsp without Serial. Adding static Serial and redirecting."); url.searchParams.set('Serial', DEBUG_REDIRECT_SERIAL); const redirectUrl = url.toString(); console.log("Background: Redirecting to:", redirectUrl); return { redirectUrl: redirectUrl }; } } return {}; }, { urls: ["*://oss-auth.thecheese.io/oss/serv/debug.jsp*"], types: ["main_frame"] }, ["blocking"] ); // --- BGM Playback Functions (managed within background script) --- function playBGM(url) { if (currentBgmAudio) { currentBgmAudio.pause(); currentBgmAudio.currentTime = 0; currentBgmAudio = null; } currentBgmAudio = new Audio(url); currentBgmAudio.loop = true; currentBgmAudio.volume = 0.5; // Default volume currentBgmAudio.play() .then(() => console.log("Background: BGM started playing:", url)) .catch(e => console.error("Background: Error playing BGM:", e)); } function stopBGM() { if (currentBgmAudio) { currentBgmAudio.pause(); currentBgmAudio.currentTime = 0; currentBgmAudio = null; console.log("Background: BGM stopped."); } } async function setBGMEnabled(enabled) { bgmEnabledState = enabled; try { await storageAPI.set({ bgmEnabled: enabled }); console.log("Background: BGM enabled state saved to storage:", enabled); if (!enabled) { stopBGM(); } } catch (error) { console.error("Background: Error saving BGM enabled state:", error); } } async function setFontDisabled(disabled) { try { await storageAPI.set({ fontDisabled: disabled }); console.log("Background: Font disabled state saved to storage:", disabled); } catch (error) { console.error("Background: Error saving font disabled state:", error); } } // --- Main Message Listener (handles communication from popup and content script) --- runtimeAPI.runtime.onMessage.addListener((request, sender, sendResponse) => { // Return true for asynchronous sendResponse or Promise to keep the message channel open. console.log("Background: Received message:", request.action, "from sender:", sender.tab ? "Content Script (Tab ID: " + sender.tab.id + ")" : "Popup/Extension"); switch (request.action) { // --- BGM Control --- case "playBGM": // Only play if BGM is enabled by user preference if (bgmEnabledState) { playBGM(request.url); // Use request.url from the content script } else { console.log("Background: BGM disabled by user preference, not playing."); } sendResponse({ success: true }); return false; // Synchronous acknowledgment case "stopBGM": stopBGM(); sendResponse({ success: true }); return false; case "setBGMEnabled": // This handles toggle state and playback logic setBGMEnabled(request.enabled); sendResponse({ success: true }); return false; case "getBGMEnabled": sendResponse({ enabled: bgmEnabledState }); // Return the current in-memory state return false; case "setBGMVolume": if (currentBgmAudio) { currentBgmAudio.volume = request.volume; console.log("Background: BGM volume set to:", request.volume); } sendResponse({ success: true }); return false; // --- Storage Actions --- case "getStorage": // Handles requests to get data from storage, including 'logs' return (async () => { const result = await storageAPI.get(request.key); let valueToReturn; if (request.key === 'logs') { valueToReturn = logs; // Return in-memory logs } else if (request.key === 'pts') { valueToReturn = currentPoints; // Return in-memory points } else { valueToReturn = result[request.key]; } console.log(`Background: getStorage for ${request.key}, returning:`, valueToReturn); return { value: valueToReturn }; // Send back the result (as a Promise) })(); case "setStorage": // Handles requests to set data in storage, including 'slog' for logs return (async () => { console.log(`Background: setStorage for ${request.key}, value:`, request.value); if (request.key === 'slog') { // Special handling for logs (append) logs.push(`[${new Date().toISOString()}] ${request.value}`); // Optional: Limit log size if necessary (e.g., to last 100 entries) if (logs.length > 100) logs = logs.slice(logs.length - 100); // Keep last 100 await storageAPI.set({ logs: logs }); // Persist logs to local storage } else if (request.key === 'spts') { // Special handling for points (add to existing) const pointsToAdd = parseInt(request.value) || 0; currentPoints += pointsToAdd; await storageAPI.set({ pts: currentPoints }); console.log("Background: Points updated to:", currentPoints); } else { // Generic set for other keys await storageAPI.set({ [request.key]: request.value }); } return { success: true }; // Acknowledge completion })(); case "clearLogs": return (async () => { console.log("Background: Clearing logs."); logs = []; // Clear in-memory logs await storageAPI.set({ logs: [] }); // Clear stored logs return { success: true }; })(); case "clearPoints": return (async () => { console.log("Background: Clearing points."); currentPoints = 0; // Clear in-memory points await storageAPI.set({ pts: 0 }); return { success: true }; })(); // --- Font Control --- case "setFontDisabled": /* ... */ return false; case "getFontDisabled": /* ... */ return false; default: console.warn("Background: Unrecognized message action:", request.action); sendResponse({ success: false, error: "Unrecognized action" }); return false; } });