diff --git a/extension/content.js b/extension/content.js index 6e268bf..0e4ac41 100644 --- a/extension/content.js +++ b/extension/content.js @@ -1,7 +1,7 @@ // Facebook Post Tracker Extension // Uses API_BASE_URL from config.js -const EXTENSION_VERSION = '1.2.3'; +const EXTENSION_VERSION = '1.2.4'; const PROCESSED_ATTR = 'data-fb-tracker-processed'; const PENDING_ATTR = 'data-fb-tracker-pending'; const DIALOG_ROOT_SELECTOR = '[role="dialog"], [data-pagelet*="Modal"], [data-pagelet="StoriesRecentStoriesFeedSection"]'; @@ -18,6 +18,7 @@ const FEED_HOME_PATHS = ['/', '/home.php']; const sessionSearchRecordedUrls = new Set(); const sessionSearchInfoCache = new Map(); let profileSelectionNoticeShown = false; +let extensionPaused = false; function isOnSearchResultsPage() { try { @@ -132,16 +133,57 @@ function applyDebugLoggingPreference(value) { } } -chrome.storage.sync.get(['debugLoggingEnabled'], (result) => { +function resetTrackerUiState() { + document.querySelectorAll('.fb-tracker-ui').forEach((element) => { + const host = getTrackerHostElement(element); + if (host) { + host.removeAttribute(PROCESSED_ATTR); + host.removeAttribute(PENDING_ATTR); + clearTrackerElementForPost(host, element); + } + element.remove(); + }); + + document.querySelectorAll(`[${PROCESSED_ATTR}], [${PENDING_ATTR}]`).forEach((element) => { + element.removeAttribute(PROCESSED_ATTR); + element.removeAttribute(PENDING_ATTR); + }); + + processedPostUrls.clear(); +} + +function applyExtensionPausedPreference(value) { + extensionPaused = Boolean(value); + if (extensionPaused) { + hideSelectionAIButton(); + resetTrackerUiState(); + originalConsoleLog('[FB Tracker] Extension paused'); + return; + } + + originalConsoleLog('[FB Tracker] Extension resumed'); + scheduleScan(); +} + +chrome.storage.sync.get(['debugLoggingEnabled', 'extensionPaused'], (result) => { applyDebugLoggingPreference(result && typeof result.debugLoggingEnabled !== 'undefined' ? result.debugLoggingEnabled : false); + applyExtensionPausedPreference(result && typeof result.extensionPaused !== 'undefined' + ? result.extensionPaused + : false); }); chrome.storage.onChanged.addListener((changes, area) => { - if (area === 'sync' && changes && Object.prototype.hasOwnProperty.call(changes, 'debugLoggingEnabled')) { + if (area !== 'sync' || !changes) { + return; + } + if (Object.prototype.hasOwnProperty.call(changes, 'debugLoggingEnabled')) { applyDebugLoggingPreference(changes.debugLoggingEnabled.newValue); } + if (Object.prototype.hasOwnProperty.call(changes, 'extensionPaused')) { + applyExtensionPausedPreference(changes.extensionPaused.newValue); + } }); function getTrackerElementForPost(postElement) { @@ -4119,6 +4161,10 @@ async function renderTrackedStatus({ // Create the tracking UI async function createTrackerUI(postElement, buttonBar, postNum = '?', options = {}) { + if (extensionPaused) { + return; + } + // Normalize to top-level post container if nested element passed postElement = ensurePrimaryPostElement(postElement); @@ -4972,6 +5018,10 @@ let globalPostCounter = 0; // Find all Facebook posts on the page function findPosts() { + if (extensionPaused) { + return; + } + if (maybeRedirectPageReelsToMain()) { return; } @@ -5100,6 +5150,9 @@ setTimeout(findPosts, 6000); // Debounced scan function let scanTimeout = null; function scheduleScan() { + if (extensionPaused) { + return; + } if (scanTimeout) { clearTimeout(scanTimeout); } @@ -5405,6 +5458,11 @@ const positionSelectionAIButton = (rect) => { const updateSelectionAIButton = async () => { clearSelectionAIHideTimeout(); + if (extensionPaused) { + hideSelectionAIButton(); + return; + } + if (selectionAIEnabledCached === null) { try { selectionAIEnabledCached = await isAIEnabled(); @@ -5498,6 +5556,11 @@ initSelectionAIFloatingButton(); // Listen for manual reparse command chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (extensionPaused && message && (message.type === 'generateSelectionAI' || message.type === 'reparsePost')) { + sendResponse({ success: false, paused: true }); + return true; + } + if (message && message.type === 'generateSelectionAI') { handleSelectionAIRequest(message.selectionText || '', sendResponse); return true; diff --git a/extension/manifest.json b/extension/manifest.json index 4b292d6..8f95efa 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Facebook Post Tracker", - "version": "1.2.3", + "version": "1.2.4", "description": "Track Facebook posts across multiple profiles", "permissions": [ "storage", diff --git a/extension/popup.html b/extension/popup.html index 687ea6c..5bc5532 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -137,6 +137,10 @@ +
+ +
+ diff --git a/extension/popup.js b/extension/popup.js index 50bb376..c22ac95 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -1,6 +1,8 @@ const profileSelect = document.getElementById('profileSelect'); const statusEl = document.getElementById('status'); const debugToggle = document.getElementById('debugLoggingToggle'); +const pauseBtn = document.getElementById('pauseBtn'); +let extensionPaused = false; function isValidProfileNumber(value) { return Number.isInteger(value) && value >= 1 && value <= 5; @@ -63,6 +65,13 @@ function updateStatus(message, saved = false) { statusEl.className = saved ? 'status saved' : 'status'; } +function updatePauseButton() { + if (!pauseBtn) { + return; + } + pauseBtn.textContent = extensionPaused ? 'Extension fortsetzen' : 'Extension pausieren'; +} + async function initProfileSelect() { const backendProfile = await fetchProfileState(); if (isValidProfileNumber(backendProfile)) { @@ -100,6 +109,11 @@ if (debugToggle) { }); } +chrome.storage.sync.get(['extensionPaused'], (result) => { + extensionPaused = Boolean(result && result.extensionPaused); + updatePauseButton(); +}); + function reloadFacebookTabs() { chrome.tabs.query({ url: ['https://www.facebook.com/*', 'https://facebook.com/*'] }, (tabs) => { tabs.forEach(tab => { @@ -125,3 +139,14 @@ document.getElementById('saveBtn').addEventListener('click', async () => { document.getElementById('webInterfaceBtn').addEventListener('click', () => { chrome.tabs.create({ url: API_BASE_URL }); }); + +if (pauseBtn) { + pauseBtn.addEventListener('click', () => { + const nextPaused = !extensionPaused; + chrome.storage.sync.set({ extensionPaused: nextPaused }, () => { + extensionPaused = nextPaused; + updatePauseButton(); + updateStatus(`Extension ${nextPaused ? 'pausiert' : 'fortgesetzt'} (wirksam ohne Reload)`, true); + }); + }); +}