/
groupmol
/
s21crx
Обзор
Документация
Войти
/
groupmol
/
s21crx
Код
Запросы
0
Задачи
Пакеты
0
Релизы
2
Аналитика
Безопасность
develop
src/background.js
387 строк
12 KB
groupmol
v2.1
17 фев 2026, 15:25
17 фев 2026, 15:25
1ee4528
Код
Авторство
О чём код?
let currentCount = '0'; let lastKnownCount = '0'; let isConnected = false; let notificationsEnabled = true; let alarmInterval = 5; let activeTabs = new Set(); let keepAliveInterval = null; let activeNotificationId = null; let notificationTimeout = null; // ==================== ФУНКЦИИ ==================== function setupAlarm() { chrome.storage.sync.get(['checkInterval'], (result) => { alarmInterval = result.checkInterval || 3; chrome.alarms.clear('periodicCheck', () => { chrome.alarms.create('periodicCheck', { periodInMinutes: alarmInterval }); console.log('[BG] Будильник:', alarmInterval, 'мин'); }); }); } function checkNotificationsAvailability() { return new Promise((resolve) => { chrome.notifications.create('check-' + Date.now(), { type: 'basic', iconUrl: 'icon.png', title: 'Проверка', message: 'Тест' }, () => { const error = chrome.runtime.lastError; chrome.notifications.clear('check-' + Date.now(), () => {}); resolve(!error); }); }); } function updateBadge() { if (!notificationsEnabled) { chrome.action.setBadgeText({ text: '🔕' }); chrome.action.setBadgeBackgroundColor({ color: '#6c757d' }); return; } if (!isConnected) { chrome.action.setBadgeText({ text: '⚠️' }); chrome.action.setBadgeBackgroundColor({ color: '#ffc107' }); return; } if (currentCount !== '0' && currentCount !== '') { chrome.action.setBadgeText({ text: currentCount }); chrome.action.setBadgeBackgroundColor({ color: '#dc3545' }); } else { chrome.action.setBadgeText({ text: '' }); } } function startKeepAlive() { chrome.alarms.create('keepAlive', { periodInMinutes: 20/60 }); keepAliveInterval = setInterval(() => { if (activeTabs.size > 0) { chrome.tabs.query({ url: 'https://platform.21-school.ru/*' }, (tabs) => { const currentTabIds = new Set(tabs.map(t => t.id)); activeTabs.forEach(id => { if (!currentTabIds.has(id)) activeTabs.delete(id); }); tabs.forEach(tab => { if (!activeTabs.has(tab.id)) activeTabs.add(tab.id); }); const wasConnected = isConnected; isConnected = activeTabs.size > 0; if (wasConnected !== isConnected) updateBadge(); }); } }, 30000); } function sendNotification(message) { return new Promise((resolve) => { // Сначала скрываем предыдущее уведомление если есть if (activeNotificationId) { chrome.notifications.clear(activeNotificationId, () => {}); } if (notificationTimeout) { clearTimeout(notificationTimeout); } chrome.notifications.create({ type: 'basic', iconUrl: 'icon.png', title: '🔔 21-school - Новые уведомления!', message: message, priority: 2, requireInteraction: true, silent: false, buttons: [ { title: 'Открыть сайт' }, { title: 'Позже' } ] }, (id) => { const error = chrome.runtime.lastError; notificationsEnabled = !error; updateBadge(); if (error) { console.warn('[BG] Ошибка уведомления:', error); resolve({ success: !error, error: error }); return; } activeNotificationId = id; console.log('[BG] Уведомление создано:', id); resolve({ success: true, error: null }); }); }); } function requestCountFromTab(tabId) { return new Promise((resolve) => { chrome.tabs.sendMessage(tabId, { type: 'requestCount' }, (response) => { if (chrome.runtime.lastError || !response) resolve(null); else resolve(response.count); }); }); } function handleNewCount(newCount, tabId, suppressNotification = false) { if (newCount === null || newCount === '') return; const oldCount = currentCount; currentCount = newCount; console.log('[BG] Счётчик:', oldCount, '→', newCount, '| Вкладка:', tabId); if (!suppressNotification && newCount !== '0' && parseInt(newCount) > parseInt(oldCount)) { console.log('[BG] 📈 Увеличение, уведомляем'); sendNotification(`У вас ${newCount} непрочитанных уведомлений`); } lastKnownCount = currentCount; updateBadge(); } function injectExistingTabs() { console.log('[BG] Начинаю инжект в существующие вкладки...'); chrome.tabs.query({ url: 'https://platform.21-school.ru/*' }, (tabs) => { console.log('[BG] Найдено вкладок:', tabs.length); if (tabs.length === 0) return; let completedInjections = 0; let maxCount = 0; let maxCountStr = '0'; tabs.forEach((tab, index) => { activeTabs.add(tab.id); chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['content.js'] }, () => { if (chrome.runtime.lastError) { console.warn('[BG] Инжект не удался:', tab.id, chrome.runtime.lastError.message); } else { console.log('[BG] Инжект успешен:', tab.id); } setTimeout(() => { requestCountFromTab(tab.id).then(count => { console.log('[BG] Получен счётчик с вкладки', tab.id, ':', count); if (count !== null && count !== '') { const numCount = parseInt(count); if (numCount > maxCount) { maxCount = numCount; maxCountStr = count; } } completedInjections++; if (completedInjections === tabs.length) { console.log('[BG] Все инжекты завершены. Максимальный счётчик:', maxCountStr); currentCount = maxCountStr; lastKnownCount = maxCountStr; isConnected = true; updateBadge(); if (maxCount > 0) { setTimeout(() => { sendNotification(`У вас ${maxCountStr} непрочитанных уведомлений`); }, 1000); } } }); }, 1000 + (index * 300)); }); }); }); } // ==================== ОБРАБОТЧИКИ ==================== chrome.runtime.onInstalled.addListener((details) => { console.log('[BG] Установлено/Обновлено:', details.reason); if (details.reason === 'install') { injectExistingTabs(); } setupAlarm(); startKeepAlive(); checkNotificationsAvailability().then(enabled => { notificationsEnabled = enabled; updateBadge(); }); }); chrome.runtime.onStartup.addListener(() => { console.log('[BG] Запуск браузера'); injectExistingTabs(); setupAlarm(); startKeepAlive(); }); chrome.tabs.onCreated.addListener((tab) => { if (tab.url && tab.url.includes('platform.21-school.ru')) { activeTabs.add(tab.id); isConnected = true; updateBadge(); setTimeout(() => { requestCountFromTab(tab.id).then(c => handleNewCount(c, tab.id, false)); }, 1000); } }); chrome.tabs.onRemoved.addListener((tabId) => { if (activeTabs.has(tabId)) { activeTabs.delete(tabId); if (activeTabs.size === 0) { isConnected = false; currentCount = '0'; lastKnownCount = '0'; updateBadge(); } } }); chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (!tab.url) return; const isTarget = tab.url.includes('platform.21-school.ru'); if (isTarget && !activeTabs.has(tabId)) { activeTabs.add(tabId); isConnected = true; updateBadge(); setTimeout(() => { requestCountFromTab(tabId).then(c => handleNewCount(c, tabId, false)); }, 1000); } else if (!isTarget && activeTabs.has(tabId)) { activeTabs.delete(tabId); if (activeTabs.size === 0) { isConnected = false; currentCount = '0'; lastKnownCount = '0'; updateBadge(); } } }); chrome.tabs.onActivated.addListener((activeInfo) => { console.log('[BG] Вкладка активирована:', activeInfo.tabId); chrome.tabs.get(activeInfo.tabId, (tab) => { if (tab.url && tab.url.includes('platform.21-school.ru')) { if (!activeTabs.has(tab.id)) { activeTabs.add(tab.id); isConnected = true; updateBadge(); } setTimeout(() => { requestCountFromTab(tab.id).then(count => { if (count !== null && count !== '') { handleNewCount(count, tab.id, false); } }); }, 500); } }); }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'keepAlive') return; if (alarm.name === 'periodicCheck') { if (!isConnected) return; if (currentCount !== '0' && currentCount !== '') { sendNotification(`У вас ${currentCount} непрочитанных уведомлений`); } } }); chrome.notifications.onClicked.addListener((id) => { console.log('[BG] Клик на уведомление:', id); chrome.tabs.query({ url: 'https://platform.21-school.ru/*' }, (tabs) => { if (tabs.length > 0) { chrome.tabs.update(tabs[0].id, { active: true }); chrome.windows.update(tabs[0].windowId, { focused: true }); } else { chrome.tabs.create({ url: 'https://platform.21-school.ru/' }); } }); chrome.notifications.clear(id, () => {}); if (activeNotificationId === id) { activeNotificationId = null; } if (notificationTimeout) { clearTimeout(notificationTimeout); notificationTimeout = null; } }); chrome.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => { console.log('[BG] Клик на кнопку:', buttonIndex); if (buttonIndex === 0) { chrome.tabs.query({ url: 'https://platform.21-school.ru/*' }, (tabs) => { if (tabs.length > 0) { chrome.tabs.update(tabs[0].id, { active: true }); chrome.windows.update(tabs[0].windowId, { focused: true }); } else { chrome.tabs.create({ url: 'https://platform.21-school.ru/' }); } }); } chrome.notifications.clear(notificationId, () => {}); if (activeNotificationId === notificationId) { activeNotificationId = null; } if (notificationTimeout) { clearTimeout(notificationTimeout); notificationTimeout = null; } }); chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === 'notificationChanged') { const newCount = request.count; if (newCount !== null && newCount !== '') { const oldCount = currentCount; currentCount = newCount; lastKnownCount = newCount; if (newCount !== '0' && parseInt(newCount) > parseInt(oldCount)) { sendNotification(`У вас ${newCount} непрочитанных уведомлений`); } updateBadge(); } sendResponse({ success: true }); return true; } if (request.type === 'connectionStatus') { const tabId = sender.tab?.id; if (request.connected) { if (tabId) activeTabs.add(tabId); isConnected = true; } else { if (tabId) activeTabs.delete(tabId); if (activeTabs.size === 0) { isConnected = false; currentCount = '0'; lastKnownCount = '0'; } } updateBadge(); sendResponse({ success: true }); return true; } if (request.type === 'getCurrentCount') { sendResponse({ count: lastKnownCount }); return true; } if (request.type === 'updateAlarm') { setupAlarm(); sendResponse({ success: true }); return true; } if (request.type === 'testNotification') { sendNotification('🔔 Тест').then(r => sendResponse(r)); return true; } if (request.type === 'getStatus') { sendResponse({ connected: isConnected, count: currentCount, notificationsEnabled: notificationsEnabled }); return true; } if (request.type === 'checkNotifications') { checkNotificationsAvailability().then(e => { notificationsEnabled = e; updateBadge(); sendResponse({ enabled: e }); }); return true; } sendResponse({ success: false }); return true; });