import { REFRESH_TIMEOUT, HOMEPAGE, API_URLS, BADGE_COLORS } from './config.js'; globalThis.browser ??= chrome; browser.runtime.onInstalled.addListener(async (details) => { init(); if (details.reason === 'install') { await browser.tabs.create({ url: HOMEPAGE, }); } }); browser.runtime.onStartup.addListener(() => { init(); }); browser.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'fetchData') { fetchNewData(); } }); /** * @param {number} days * @returns {Promise} */ async function fetchCalendar(days = 28) { const params = new URLSearchParams(); params.set('o', 'json'); if (days) { params.set('r', `${days}`); } const response = await fetch(`${API_URLS.calender}?${params.toString()}`); return response.json(); } /** * @returns {Promise} */ async function fetchSpaceApi() { const response = await fetch(API_URLS.spaceApi); return response.json(); } async function fetchNewData() { if (!globalThis.navigator.onLine) { return; } try { const [resultCalendar, resultSpaceApi] = await Promise.allSettled([fetchCalendar(), fetchSpaceApi()]); const calendarJson = (resultCalendar.status === 'fulfilled') ? resultCalendar.value : undefined; const spaceApiJson = (resultSpaceApi.status === 'fulfilled') ? resultSpaceApi.value : undefined; if (spaceApiJson) { const now = new Date(); const eventActive = calendarJson?.some((event) => ( new Date(event.begin) <= now && now <= new Date(event.end) )) ?? false; await setBadgeStatus(spaceApiJson.state.open, eventActive); /** * @type {import("../types").Storage} */ const { spaceApi } = await browser.storage.session.get('spaceApi'); if (spaceApi && spaceApi.state.open !== spaceApiJson.state.open) { await createStatusChangedNotification(spaceApiJson.state.open); } } await browser.storage.session.set({ calendar: calendarJson, spaceApi: spaceApiJson, }); } catch (error) { console.error(error); } } /** * @param {boolean} open * @param {boolean} eventActive */ async function setBadgeStatus(open, eventActive) { const badgeText = browser.i18n.getMessage(open ? 'badgeOpen' : eventActive ? 'badgeEvent' : 'badgeClosed'); const badgeBgColor = open ? BADGE_COLORS.open : eventActive ? BADGE_COLORS.event : BADGE_COLORS.closed; await browser.action.setBadgeText({ text: badgeText }); await browser.action.setBadgeBackgroundColor({ color: badgeBgColor }); } /** * @param {boolean} open */ async function createStatusChangedNotification(open) { const stateL10n = browser.i18n.getMessage(open ? 'open' : 'closed'); await browser.notifications.create('status-changed', { type: 'basic', title: browser.i18n.getMessage('stateNotificationTitle'), message: browser.i18n.getMessage('stateNotificationMessage', stateL10n), iconUrl: browser.runtime.getURL('icons/favicon.svg'), }); } function init() { fetchNewData(); const now = new Date(); now.setMinutes(Math.ceil((now.getMinutes() + 1) / REFRESH_TIMEOUT) * REFRESH_TIMEOUT, 0, 0); browser.alarms.create('fetchData', { when: now.getTime(), periodInMinutes: REFRESH_TIMEOUT, }); } init();