157 lines
4.8 KiB
JavaScript
157 lines
4.8 KiB
JavaScript
// background.js
|
|
// Listen for messages from content scripts or offscreen document
|
|
|
|
let isSniffing = false;
|
|
let lastClipboardContent = '';
|
|
let creatingOffscreenDocument;
|
|
|
|
// Hot-reconnect: Inject content script into existing tabs upon installation/update/restart
|
|
const injectContentScriptIfNeeded = async () => {
|
|
const tabs = await chrome.tabs.query({ url: ['http://localhost/*', 'http://localhost:*/*', 'https://tools.7u.pl/*'] });
|
|
for (const tab of tabs) {
|
|
try {
|
|
// Try to ping the tab first
|
|
try {
|
|
await chrome.tabs.sendMessage(tab.id, { action: 'ping' });
|
|
// console.log('Content script already active in tab:', tab.id);
|
|
} catch (e) {
|
|
// If ping fails (no listener), inject script
|
|
await chrome.scripting.executeScript({
|
|
target: { tabId: tab.id },
|
|
files: ['content.js']
|
|
});
|
|
// console.log('Injected content script into existing tab:', tab.id);
|
|
}
|
|
} catch (err) {
|
|
// console.error('Failed to handle tab:', tab.id, err);
|
|
}
|
|
}
|
|
};
|
|
|
|
chrome.runtime.onInstalled.addListener(injectContentScriptIfNeeded);
|
|
// Also run on startup (when extension is enabled/reloaded)
|
|
injectContentScriptIfNeeded();
|
|
|
|
// Listen for alarms
|
|
try {
|
|
if (chrome.alarms) {
|
|
chrome.alarms.onAlarm.addListener((alarm) => {
|
|
if (alarm.name === 'keepAlive') {
|
|
refreshOffscreenDocument();
|
|
}
|
|
});
|
|
} else {
|
|
// console.warn('chrome.alarms API is not available.');
|
|
}
|
|
} catch (e) {
|
|
// console.error('Error initializing alarms:', e);
|
|
}
|
|
|
|
// Setup offscreen document
|
|
async function setupOffscreenDocument(path) {
|
|
// Check if an offscreen document already exists
|
|
const existingContexts = await chrome.runtime.getContexts({
|
|
contextTypes: ['OFFSCREEN_DOCUMENT'],
|
|
});
|
|
|
|
if (existingContexts.length > 0) {
|
|
return;
|
|
}
|
|
|
|
// Create an offscreen document
|
|
if (creatingOffscreenDocument) {
|
|
await creatingOffscreenDocument;
|
|
} else {
|
|
creatingOffscreenDocument = chrome.offscreen.createDocument({
|
|
url: path,
|
|
reasons: ['CLIPBOARD', 'AUDIO_PLAYBACK'],
|
|
justification: 'To read clipboard content in the background and play notification sounds',
|
|
});
|
|
await creatingOffscreenDocument;
|
|
creatingOffscreenDocument = null;
|
|
}
|
|
}
|
|
|
|
// Lifecycle management: Refresh offscreen document every 25s to avoid 30s timeout
|
|
async function refreshOffscreenDocument() {
|
|
if (isSniffing) {
|
|
await chrome.offscreen.closeDocument();
|
|
await setupOffscreenDocument('offscreen.html');
|
|
}
|
|
}
|
|
|
|
// Start sniffing when requested
|
|
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
|
|
if (request.action === 'startSniffing') {
|
|
if (isSniffing) {
|
|
sendResponse({ status: 'already_started' });
|
|
return true;
|
|
}
|
|
|
|
isSniffing = true;
|
|
// console.log('Starting sniffing process...');
|
|
await setupOffscreenDocument('offscreen.html');
|
|
|
|
// Setup interval to keep offscreen alive - more aggressive
|
|
chrome.alarms.create('keepAlive', { periodInMinutes: 0.1 }); // every 6 seconds
|
|
|
|
sendResponse({ status: 'started' });
|
|
return true;
|
|
}
|
|
|
|
if (request.action === 'stopSniffing') {
|
|
if (!isSniffing) {
|
|
sendResponse({ status: 'not_running' });
|
|
return true;
|
|
}
|
|
|
|
isSniffing = false;
|
|
// console.log('Stopping sniffing process...');
|
|
|
|
// Stop alarm
|
|
chrome.alarms.clear('keepAlive');
|
|
|
|
// Close offscreen document
|
|
if (creatingOffscreenDocument) {
|
|
await creatingOffscreenDocument;
|
|
}
|
|
await chrome.offscreen.closeDocument().catch(() => {});
|
|
creatingOffscreenDocument = null;
|
|
|
|
sendResponse({ status: 'stopped' });
|
|
return true;
|
|
}
|
|
|
|
if (request.type === 'clipboard-data' && request.target === 'background') {
|
|
// Received data from offscreen document
|
|
if (isSniffing && request.data && request.data !== lastClipboardContent) {
|
|
lastClipboardContent = request.data;
|
|
// console.log('Clipboard changed:', request.data.substring(0, 20) + '...');
|
|
|
|
// Check if sound should be played
|
|
chrome.storage.local.get(['playSound'], (result) => {
|
|
if (result.playSound !== false) {
|
|
// Send message to offscreen document to play sound
|
|
chrome.runtime.sendMessage({
|
|
target: 'offscreen',
|
|
type: 'play-sound'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Broadcast to all active tabs (content scripts)
|
|
// We could filter by sender.tab.id if we knew which tab started sniffing,
|
|
// but broadcasting is simpler for now and covers multiple open tabs of the app.
|
|
const tabs = await chrome.tabs.query({ url: ['http://localhost/*', 'http://localhost:*/*', 'https://tools.7u.pl/*'] });
|
|
for (const tab of tabs) {
|
|
chrome.tabs.sendMessage(tab.id, {
|
|
action: 'clipboardUpdate',
|
|
content: request.data
|
|
}).catch(() => {
|
|
// Tab might be closed or content script not injected yet
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|