From 48445020c896723eced61a948bb7a0abf834698f Mon Sep 17 00:00:00 2001
From: Francesco Minnocci
diff --git a/src/scripts/update-semester-data.js b/src/scripts/update-semester-data.js
new file mode 100644
index 0000000..e745b87
--- /dev/null
+++ b/src/scripts/update-semester-data.js
@@ -0,0 +1,186 @@
+#!/usr/bin/env node
+
+// Manual update script for semester timetable data
+// Run this script manually each semester to update timetable IDs and dates
+// Usage: node src/scripts/update-semester-data.js
+
+import https from 'https';
+import fs from 'fs';
+
+// Get current academic year
+function getCurrentAcademicYear() {
+ const now = new Date();
+ const currentYear = now.getFullYear();
+ const currentMonth = now.getMonth(); // 0-based
+
+ // Academic year starts in September, but August belongs to the new year
+ const startYear = currentMonth >= 7 ? currentYear : currentYear - 1;
+ const endYear = startYear + 1;
+
+ return { startYear, endYear };
+}
+
+// Fetch webpage content
+function fetchPage(url) {
+ return new Promise((resolve, reject) => {
+ https.get(url, (res) => {
+ let data = '';
+
+ res.on('data', (chunk) => {
+ data += chunk;
+ });
+
+ res.on('end', () => {
+ resolve(data);
+ });
+ }).on('error', (err) => {
+ reject(err);
+ });
+ });
+}
+
+// Parse timetable IDs from the schedule page
+async function parseTimetableIds() {
+ try {
+ const html = await fetchPage('https://www.dm.unipi.it/didattica/lezioni-esami/orario-delle-lezioni/');
+ const ids = {};
+
+ // Extract links with their text to match correctly
+ const linkPattern = /]*href="[^"]*linkCalendarioId=([a-f0-9]{24})"[^>]*>([^<]+)<\/a>/g;
+ const links = [...html.matchAll(linkPattern)];
+
+ for (const [fullMatch, id, text] of links) {
+ const cleanText = text.trim();
+
+ if (cleanText === 'Triennale I anno') {
+ ids['anno-1'] = id;
+ } else if (cleanText === 'Triennale II anno') {
+ ids['anno-2'] = id;
+ } else if (cleanText === 'Triennale III anno') {
+ ids['anno-3'] = id;
+ } else if (cleanText === 'Magistrale') {
+ ids['magistrale'] = id;
+ }
+ }
+
+ return Object.keys(ids).length > 0 ? ids : null;
+ } catch (error) {
+ console.error('Error parsing timetable IDs:', error.message);
+ return null;
+ }
+}
+
+// Parse semester start date from calendar page
+async function parseSemesterStartDate() {
+ try {
+ const { startYear, endYear } = getCurrentAcademicYear();
+ const currentMonth = new Date().getMonth();
+ const currentSemester = currentMonth >= 1 && currentMonth <= 6 ? 2 : 1;
+
+ const url = `https://www.dm.unipi.it/didattica/lezioni-esami/calendario-delle-attivita-didattiche/calendario-delle-attivita-didattiche-a-a-${startYear}-${endYear.toString().slice(-2)}/`;
+
+ const html = await fetchPage(url);
+
+ // Look for the appropriate semester start date
+ const semesterText = currentSemester === 1 ? 'I semestre' : 'II semestre';
+ const semesterRegex = new RegExp(`Lezioni\\s+${semesterText}.*?(\\d{1,2}\\s+\\w+\\s+\\d{4})`, 'si');
+ const match = html.match(semesterRegex);
+
+ if (match) {
+ return match[1];
+ } else {
+ console.error(`Could not find ${semesterText} start date in calendar`);
+ return null;
+ }
+ } catch (error) {
+ console.error('Error parsing semester start date:', error.message);
+ return null;
+ }
+}
+
+// Find the first Monday after a given date string
+function getFirstMondayAfter(dateStr) {
+ // Parse Italian date format (e.g., "24 settembre 2025")
+ const [day, monthName, year] = dateStr.split(' ');
+
+ const monthMap = {
+ 'gennaio': 0, 'febbraio': 1, 'marzo': 2, 'aprile': 3,
+ 'maggio': 4, 'giugno': 5, 'luglio': 6, 'agosto': 7,
+ 'settembre': 8, 'ottobre': 9, 'novembre': 10, 'dicembre': 11
+ };
+
+ const month = monthMap[monthName.toLowerCase()];
+ if (month === undefined) {
+ throw new Error(`Unknown month: ${monthName}`);
+ }
+
+ const startDate = new Date(parseInt(year), month, parseInt(day));
+ const dayOfWeek = startDate.getDay(); // 0=Sunday, 1=Monday, etc.
+
+ // Calculate days to add to get to the next Monday
+ let daysToAdd;
+ if (dayOfWeek === 0) { // Sunday
+ daysToAdd = 1; // Next day is Monday
+ } else if (dayOfWeek === 1) { // Monday
+ daysToAdd = 7; // Next Monday
+ } else { // Tuesday-Saturday (2-6)
+ daysToAdd = 8 - dayOfWeek; // Days until next Monday
+ }
+
+ const result = new Date(startDate);
+ result.setDate(startDate.getDate() + daysToAdd);
+
+ // Create a new date in UTC to avoid timezone issues with the calendar
+ return new Date(Date.UTC(result.getFullYear(), result.getMonth(), result.getDate()));
+}
+
+// Format date for button text (Italian format)
+function formatDateForButton(date) {
+ const day = date.getUTCDate();
+ const monthNames = [
+ 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno',
+ 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'
+ ];
+ const month = monthNames[date.getUTCMonth()];
+
+ return `${day} ${month}`;
+}
+
+// Main function
+async function updateAcademicData() {
+ const [timetableIds, semesterStartDateStr] = await Promise.all([
+ parseTimetableIds(),
+ parseSemesterStartDate()
+ ]);
+
+ // Fail fast if parsing failed
+ if (!timetableIds) {
+ throw new Error('Failed to parse timetable IDs from the website');
+ }
+
+ if (!semesterStartDateStr) {
+ throw new Error('Failed to parse semester start date from the calendar');
+ }
+
+ const firstMonday = getFirstMondayAfter(semesterStartDateStr);
+
+ const academicData = {
+ timetableIds,
+ semesterStartDateStr,
+ firstMondayDate: firstMonday.toISOString(),
+ buttonText: `Vai al ${formatDateForButton(firstMonday)}! ๐`,
+ lastUpdated: new Date().toISOString(),
+ academicYear: getCurrentAcademicYear()
+ };
+
+ // Save to public/timetable-ids-dates.json
+ fs.writeFileSync('public/timetable-ids-dates.json', JSON.stringify(academicData, null, 2));
+
+ console.log('โ
Academic data updated successfully');
+}
+
+// Run the script
+updateAcademicData().catch(error => {
+ console.error('๐ฅ Script failed:', error);
+ process.exit(1);
+});
From 97e3758bc14dac52b32fe1c9372cb67a0bf2f752 Mon Sep 17 00:00:00 2001
From: Francesco Minnocci
diff --git a/src/scripts/update-semester-data.js b/src/scripts/update-semester-data.js index e745b87..70d2a44 100644 --- a/src/scripts/update-semester-data.js +++ b/src/scripts/update-semester-data.js @@ -164,7 +164,7 @@ async function updateAcademicData() { const firstMonday = getFirstMondayAfter(semesterStartDateStr); - const academicData = { + const semesterData = { timetableIds, semesterStartDateStr, firstMondayDate: firstMonday.toISOString(), @@ -172,11 +172,11 @@ async function updateAcademicData() { lastUpdated: new Date().toISOString(), academicYear: getCurrentAcademicYear() }; - - // Save to public/timetable-ids-dates.json - fs.writeFileSync('public/timetable-ids-dates.json', JSON.stringify(academicData, null, 2)); - - console.log('โ Academic data updated successfully'); + + // Save to src/semester-data.json + fs.writeFileSync('src/semester-data.json', JSON.stringify(semesterData, null, 2)); + + console.log('โ Semester data updated successfully'); } // Run the script diff --git a/public/timetable-ids-dates.json b/src/semester-data.json similarity index 89% rename from public/timetable-ids-dates.json rename to src/semester-data.json index 6c115f6..4e1b93e 100644 --- a/public/timetable-ids-dates.json +++ b/src/semester-data.json @@ -8,7 +8,7 @@ "semesterStartDateStr": "24 settembre 2025", "firstMondayDate": "2025-09-29T00:00:00.000Z", "buttonText": "Vai al 29 settembre! ๐", - "lastUpdated": "2025-08-28T11:47:04.874Z", + "lastUpdated": "2025-08-28T13:15:33.748Z", "academicYear": { "startYear": 2025, "endYear": 2026