/* * Copyright (C) 2025 Jakub Žitník * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ import fs from "fs/promises"; import { setup } from "./call.js"; const PREVIOUS = "db/v3/_previous.json"; const FINAL = "db/v3/v3.json"; const EXCLUDE_CLASSES = new Set(["ABSENCE"]); async function checkFileExists(filePath) { try { await fs.access(filePath); return true; } catch (err) { return false; } } function arraysAreEqual(arr1, arr2) { if (arr1.length !== arr2.length) return false; for (let i = 0; i < arr1.length; i++) { if (arr1[i] !== arr2[i]) return false; } return true; } function getTime() { const currentDate = new Date(); return currentDate.getHours().toString().padStart(2, "0") + ":" + currentDate.getMinutes().toString().padStart(2, "0"); } function setupFinal() { return { schedule: [], status: { lastUpdated: getTime(), } } } export default async function parseV3(fileV2Path) { const call = await setup(); let clearRun = false; let previousStr = "{}"; if (await checkFileExists(PREVIOUS)) { previousStr = await fs.readFile(PREVIOUS, "utf8"); } else { clearRun = true; } const now = JSON.parse(await fs.readFile(fileV2Path, "utf8")); const previous = JSON.parse(previousStr); const previousDays = previous.props?.map(p => p.date) || []; let final; if (await checkFileExists(FINAL)) { final = JSON.parse(await fs.readFile(FINAL, "utf8")); } else { final = setupFinal(); clearRun = true; } let i = 0; for (const prop of now.props) { const date = new Date(prop.date); const dayIndex = (date.getDay() + 6) % 7; if (!final.schedule[i]) { final.schedule[i] = {}; } const day = now.schedule[i]; const batch = {}; for (const cls of Object.keys(day)) { if (EXCLUDE_CLASSES.has(cls)) continue; const newClass = day[cls]; if (clearRun || !previousDays.includes(prop.date)) { batch[cls] = newClass; continue; } const oldPropIndex = previous.props.findIndex( p => p.date === prop.date ); const oldClass = previous.schedule[oldPropIndex]?.[cls] || []; if (!arraysAreEqual(oldClass, newClass)) { batch[cls] = newClass; } } if (Object.keys(batch).length > 0) { const results = await call(batch, dayIndex); for (const cls of Object.keys(results)) { final.schedule[i][cls] = results[cls]; } } i++; } if (!clearRun) { final.status.lastUpdated = getTime(); } final.props = now.props; await fs.writeFile(FINAL, JSON.stringify(final), "utf8"); await fs.copyFile(fileV2Path, PREVIOUS); } parseV3("db/v2.json");