Add manifest.json, sidepanel components, and scripts. Include project assets and documentation files. Remove placeholder blank file.
118 lines
3.7 KiB
JavaScript
118 lines
3.7 KiB
JavaScript
// Background service worker for Auto Cover Generator
|
|
|
|
// 1. Native Click Behavior
|
|
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
|
|
|
|
const openTabs = new Set();
|
|
|
|
// 2. Click Handler (Native behavior handles opening, we just manage content)
|
|
// Note: chrome.action.onClicked is ignored when openPanelOnActionClick is true.
|
|
|
|
// 3. Tab State Management
|
|
// Monitor all tab changes to ensure correct panel is shown
|
|
chrome.runtime.onInstalled.addListener(() => {
|
|
initializeAllTabs();
|
|
});
|
|
|
|
chrome.runtime.onStartup.addListener(() => {
|
|
initializeAllTabs();
|
|
});
|
|
|
|
async function initializeAllTabs() {
|
|
const tabs = await chrome.tabs.query({});
|
|
for (const tab of tabs) {
|
|
await checkAndSetSidePanel(tab.id);
|
|
}
|
|
}
|
|
|
|
// 4. Tab Activation / Isolation Logic
|
|
chrome.tabs.onActivated.addListener(async (activeInfo) => {
|
|
const tabId = activeInfo.tabId;
|
|
await checkAndSetSidePanel(tabId);
|
|
});
|
|
|
|
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
|
|
if (changeInfo.status === 'complete' || changeInfo.url) {
|
|
await checkAndSetSidePanel(tabId);
|
|
}
|
|
});
|
|
|
|
async function checkAndSetSidePanel(tabId) {
|
|
try {
|
|
const tab = await chrome.tabs.get(tabId);
|
|
if (!tab) return; // Tab doesn't exist
|
|
|
|
// If we don't have permission to see the URL, it's definitely not Gemini (since we have host_permissions for Gemini).
|
|
// So undefined tab.url means "Restricted/Other Site".
|
|
const isGemini = tab.url && tab.url.startsWith('https://gemini.google.com/');
|
|
|
|
if (isGemini) {
|
|
// Enable and set path for Gemini
|
|
await chrome.sidePanel.setOptions({
|
|
tabId: tabId,
|
|
path: 'sidepanel/panel.html',
|
|
enabled: true
|
|
});
|
|
} else {
|
|
// Disable for all other sites - this CLOSES the panel if open
|
|
// and ensures it stays closed when returning to the tab (until clicked manually)
|
|
await chrome.sidePanel.setOptions({
|
|
tabId: tabId,
|
|
enabled: false
|
|
});
|
|
}
|
|
|
|
} catch (e) {
|
|
// Tab might be closed or we heavily failed access
|
|
console.log('Cannot access tab or set panel', e);
|
|
}
|
|
}
|
|
|
|
chrome.runtime.onInstalled.addListener(() => {
|
|
chrome.sidePanel.setOptions({ enabled: false });
|
|
});
|
|
|
|
chrome.tabs.onRemoved.addListener((tabId) => {
|
|
openTabs.delete(tabId);
|
|
});
|
|
|
|
// 4. Message Routing
|
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
// Forward messages to content script
|
|
if (message.action === 'generateCover' || message.action === 'removeObjectFromImage') {
|
|
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
|
if (tabs[0]) {
|
|
chrome.tabs.sendMessage(tabs[0].id, message, (response) => {
|
|
sendResponse(response);
|
|
});
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (message.action === 'downloadImage') {
|
|
const url = message.url;
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
const filename = `gemini_gen_${timestamp}.png`;
|
|
|
|
chrome.downloads.download({
|
|
url: url,
|
|
filename: filename,
|
|
conflictAction: 'uniquify'
|
|
}, (downloadId) => {
|
|
if (chrome.runtime.lastError) {
|
|
console.error('Download failed:', chrome.runtime.lastError);
|
|
} else {
|
|
console.log('Download started, ID:', downloadId);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (message.action === 'generationError') {
|
|
chrome.runtime.sendMessage(message).catch(() => { });
|
|
}
|
|
});
|
|
|
|
console.log('Auto Cover Generator: Background Service Ready');
|