Add AI button reactivation countdown

This commit is contained in:
2026-04-07 16:20:51 +02:00
parent 9144bdea21
commit a265160624
2 changed files with 89 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
// Facebook Post Tracker Extension
// Uses API_BASE_URL from config.js
const EXTENSION_VERSION = '1.2.1';
const EXTENSION_VERSION = '1.2.2';
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"]';
@@ -1019,6 +1019,7 @@ const aiCredentialCache = {
const AI_SETTINGS_CACHE_TTL = 30 * 1000;
const AI_SETTINGS_SYNC_KEY = 'fb_tracker_ai_settings_sync';
const AI_AVAILABILITY_AUTO_REFRESH_INTERVAL_MS = 30 * 1000;
const AI_REACTIVATION_COUNTDOWN_THRESHOLD_MS = 5 * 60 * 1000;
const aiSettingsCache = {
data: null,
timestamp: 0,
@@ -6852,6 +6853,7 @@ async function addAICommentButton(container, postElement) {
let notePreviewElement = null;
let noteClearButton = null;
let rateLimitRefreshPromise = null;
let blockedCountdownIntervalId = null;
const truncateNoteForPreview = (note) => {
if (!note) {
@@ -6887,6 +6889,81 @@ async function addAICommentButton(container, postElement) {
showToast(`${status.profile_name || 'Profil'}: ${formatAIAutoCommentRateLimitReason(status)}.${untilText}`.trim(), 'info');
};
const clearBlockedCountdown = () => {
if (blockedCountdownIntervalId) {
window.clearInterval(blockedCountdownIntervalId);
blockedCountdownIntervalId = null;
}
};
const getBlockedCountdownRemainingMs = (status) => {
if (!status || !status.blocked_until) {
return null;
}
const blockedUntilMs = new Date(status.blocked_until).getTime();
if (!Number.isFinite(blockedUntilMs)) {
return null;
}
return blockedUntilMs - Date.now();
};
const formatBlockedCountdown = (remainingMs) => {
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
if (hours > 0) {
return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
return `${minutes}:${String(seconds).padStart(2, '0')}`;
};
const renderBlockedCountdownText = (status) => {
const remainingMs = getBlockedCountdownRemainingMs(status);
if (remainingMs === null || remainingMs <= 0 || remainingMs > AI_REACTIVATION_COUNTDOWN_THRESHOLD_MS) {
return false;
}
button.textContent = `${button.dataset.aiOriginalText || baseButtonText} 🔒 ${formatBlockedCountdown(remainingMs)}`;
return true;
};
const scheduleBlockedCountdown = (status) => {
clearBlockedCountdown();
if (!status || !status.blocked) {
return;
}
if ((button.dataset.aiState || 'idle') !== 'idle' || button._aiContext) {
return;
}
const updateCountdown = () => {
if (!wrapper.isConnected) {
clearBlockedCountdown();
return;
}
if ((button.dataset.aiState || 'idle') !== 'idle' || button._aiContext) {
clearBlockedCountdown();
return;
}
const remainingMs = getBlockedCountdownRemainingMs(status);
if (remainingMs !== null && remainingMs <= 0) {
clearBlockedCountdown();
void refreshAvailabilityState(true);
return;
}
if (!renderBlockedCountdownText(status)) {
clearBlockedCountdown();
}
};
if (!renderBlockedCountdownText(status)) {
return;
}
blockedCountdownIntervalId = window.setInterval(updateCountdown, 1000);
};
const applyAvailabilityState = (status = null, options = {}) => {
const { preserveText = false } = options;
const blocked = Boolean(status && status.blocked);
@@ -6894,6 +6971,7 @@ async function addAICommentButton(container, postElement) {
button.dataset.aiAvailability = blocked ? 'blocked' : 'available';
if (blocked) {
clearBlockedCountdown();
wrapper.style.opacity = '0.72';
wrapper.style.boxShadow = baseWrapperShadow;
wrapper.style.transform = 'translateY(0)';
@@ -6904,10 +6982,15 @@ async function addAICommentButton(container, postElement) {
button.title = buildBlockedButtonTitle(status);
dropdownButton.title = buildBlockedButtonTitle(status);
dropdownButton.setAttribute('aria-label', buildBlockedButtonTitle(status));
if (!preserveText && (button.dataset.aiState || 'idle') === 'idle' && !button._aiContext) {
button.textContent = `${button.dataset.aiOriginalText || baseButtonText} 🔒`;
if ((button.dataset.aiState || 'idle') === 'idle' && !button._aiContext) {
const countdownVisible = renderBlockedCountdownText(status);
if (!countdownVisible && !preserveText) {
button.textContent = `${button.dataset.aiOriginalText || baseButtonText} 🔒`;
}
scheduleBlockedCountdown(status);
}
} else {
clearBlockedCountdown();
wrapper.style.opacity = '1';
wrapper.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
button.style.cursor = 'pointer';
@@ -6959,6 +7042,7 @@ async function addAICommentButton(container, postElement) {
const handleSharedAISettingsUpdate = async (settings) => {
if (!wrapper.isConnected) {
clearBlockedCountdown();
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
return;
}
@@ -6980,6 +7064,7 @@ async function addAICommentButton(container, postElement) {
const handleAutoRefreshAvailability = ({ forceRefresh = false } = {}) => {
if (!wrapper.isConnected) {
clearBlockedCountdown();
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
aiAvailabilityRefreshSubscribers.delete(handleAutoRefreshAvailability);
return;