Add AI button reactivation countdown
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// Facebook Post Tracker Extension
|
// Facebook Post Tracker Extension
|
||||||
// Uses API_BASE_URL from config.js
|
// 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 PROCESSED_ATTR = 'data-fb-tracker-processed';
|
||||||
const PENDING_ATTR = 'data-fb-tracker-pending';
|
const PENDING_ATTR = 'data-fb-tracker-pending';
|
||||||
const DIALOG_ROOT_SELECTOR = '[role="dialog"], [data-pagelet*="Modal"], [data-pagelet="StoriesRecentStoriesFeedSection"]';
|
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_CACHE_TTL = 30 * 1000;
|
||||||
const AI_SETTINGS_SYNC_KEY = 'fb_tracker_ai_settings_sync';
|
const AI_SETTINGS_SYNC_KEY = 'fb_tracker_ai_settings_sync';
|
||||||
const AI_AVAILABILITY_AUTO_REFRESH_INTERVAL_MS = 30 * 1000;
|
const AI_AVAILABILITY_AUTO_REFRESH_INTERVAL_MS = 30 * 1000;
|
||||||
|
const AI_REACTIVATION_COUNTDOWN_THRESHOLD_MS = 5 * 60 * 1000;
|
||||||
const aiSettingsCache = {
|
const aiSettingsCache = {
|
||||||
data: null,
|
data: null,
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
@@ -6852,6 +6853,7 @@ async function addAICommentButton(container, postElement) {
|
|||||||
let notePreviewElement = null;
|
let notePreviewElement = null;
|
||||||
let noteClearButton = null;
|
let noteClearButton = null;
|
||||||
let rateLimitRefreshPromise = null;
|
let rateLimitRefreshPromise = null;
|
||||||
|
let blockedCountdownIntervalId = null;
|
||||||
|
|
||||||
const truncateNoteForPreview = (note) => {
|
const truncateNoteForPreview = (note) => {
|
||||||
if (!note) {
|
if (!note) {
|
||||||
@@ -6887,6 +6889,81 @@ async function addAICommentButton(container, postElement) {
|
|||||||
showToast(`⏳ ${status.profile_name || 'Profil'}: ${formatAIAutoCommentRateLimitReason(status)}.${untilText}`.trim(), 'info');
|
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 applyAvailabilityState = (status = null, options = {}) => {
|
||||||
const { preserveText = false } = options;
|
const { preserveText = false } = options;
|
||||||
const blocked = Boolean(status && status.blocked);
|
const blocked = Boolean(status && status.blocked);
|
||||||
@@ -6894,6 +6971,7 @@ async function addAICommentButton(container, postElement) {
|
|||||||
button.dataset.aiAvailability = blocked ? 'blocked' : 'available';
|
button.dataset.aiAvailability = blocked ? 'blocked' : 'available';
|
||||||
|
|
||||||
if (blocked) {
|
if (blocked) {
|
||||||
|
clearBlockedCountdown();
|
||||||
wrapper.style.opacity = '0.72';
|
wrapper.style.opacity = '0.72';
|
||||||
wrapper.style.boxShadow = baseWrapperShadow;
|
wrapper.style.boxShadow = baseWrapperShadow;
|
||||||
wrapper.style.transform = 'translateY(0)';
|
wrapper.style.transform = 'translateY(0)';
|
||||||
@@ -6904,10 +6982,15 @@ async function addAICommentButton(container, postElement) {
|
|||||||
button.title = buildBlockedButtonTitle(status);
|
button.title = buildBlockedButtonTitle(status);
|
||||||
dropdownButton.title = buildBlockedButtonTitle(status);
|
dropdownButton.title = buildBlockedButtonTitle(status);
|
||||||
dropdownButton.setAttribute('aria-label', buildBlockedButtonTitle(status));
|
dropdownButton.setAttribute('aria-label', buildBlockedButtonTitle(status));
|
||||||
if (!preserveText && (button.dataset.aiState || 'idle') === 'idle' && !button._aiContext) {
|
if ((button.dataset.aiState || 'idle') === 'idle' && !button._aiContext) {
|
||||||
button.textContent = `${button.dataset.aiOriginalText || baseButtonText} 🔒`;
|
const countdownVisible = renderBlockedCountdownText(status);
|
||||||
|
if (!countdownVisible && !preserveText) {
|
||||||
|
button.textContent = `${button.dataset.aiOriginalText || baseButtonText} 🔒`;
|
||||||
|
}
|
||||||
|
scheduleBlockedCountdown(status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
clearBlockedCountdown();
|
||||||
wrapper.style.opacity = '1';
|
wrapper.style.opacity = '1';
|
||||||
wrapper.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
|
wrapper.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
|
||||||
button.style.cursor = 'pointer';
|
button.style.cursor = 'pointer';
|
||||||
@@ -6959,6 +7042,7 @@ async function addAICommentButton(container, postElement) {
|
|||||||
|
|
||||||
const handleSharedAISettingsUpdate = async (settings) => {
|
const handleSharedAISettingsUpdate = async (settings) => {
|
||||||
if (!wrapper.isConnected) {
|
if (!wrapper.isConnected) {
|
||||||
|
clearBlockedCountdown();
|
||||||
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
|
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -6980,6 +7064,7 @@ async function addAICommentButton(container, postElement) {
|
|||||||
|
|
||||||
const handleAutoRefreshAvailability = ({ forceRefresh = false } = {}) => {
|
const handleAutoRefreshAvailability = ({ forceRefresh = false } = {}) => {
|
||||||
if (!wrapper.isConnected) {
|
if (!wrapper.isConnected) {
|
||||||
|
clearBlockedCountdown();
|
||||||
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
|
aiAvailabilitySubscribers.delete(handleSharedAISettingsUpdate);
|
||||||
aiAvailabilityRefreshSubscribers.delete(handleAutoRefreshAvailability);
|
aiAvailabilityRefreshSubscribers.delete(handleAutoRefreshAvailability);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Facebook Post Tracker",
|
"name": "Facebook Post Tracker",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Track Facebook posts across multiple profiles",
|
"description": "Track Facebook posts across multiple profiles",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage",
|
"storage",
|
||||||
|
|||||||
Reference in New Issue
Block a user