feat: improve Clipboard Sniffer extension integration and UI fixes
This commit is contained in:
156
extension/background.js
Normal file
156
extension/background.js
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user