From 98cabfde96c80e2a309317479243c92792ffb2ef Mon Sep 17 00:00:00 2001 From: YohanColla Date: Fri, 20 Oct 2023 14:12:54 -0500 Subject: [PATCH 1/3] Ajuste comando notas y promedio. Ahora crea un calendario del horario --- botTelegram/calendar.ics | 150 ++++++++++++++++++++++++++ botTelegram/package-lock.json | 87 +++++++++++++++ botTelegram/package.json | 3 +- botTelegram/src/botTelegram.js | 77 +++++++++++--- botTelegram/src/util/scraper.js | 181 +++++++++++++++++++++++++++++--- 5 files changed, 468 insertions(+), 30 deletions(-) create mode 100644 botTelegram/calendar.ics diff --git a/botTelegram/calendar.ics b/botTelegram/calendar.ics new file mode 100644 index 0000000..21a6545 --- /dev/null +++ b/botTelegram/calendar.ics @@ -0,0 +1,150 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Universidad Tecnológica de Pereira//Horario asignado//ES +NAME:Horario de clases +X-WR-CALNAME:Horario de clases +BEGIN:VEVENT +UID:627f6dce-d85f-4192-afad-a1b678245df0 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231010T210000Z +DTEND:20231010T220000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Matematicas Iii Gr. 103 +LOCATION:Edificio 6-125 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:d74b9875-1369-44e8-ab43-fb02d6070374 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231011T210000Z +DTEND:20231011T230000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Matematicas Iii Gr. 103 +LOCATION:Edificio 1A-208 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:01d80519-4d82-4650-97e0-c2ad1e02ffcf +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231013T210000Z +DTEND:20231013T230000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Matematicas Iii Gr. 103 +LOCATION:Edificio 1A-209 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:e80002ee-77d4-44da-a2b8-d6205b0d0217 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231010T170000Z +DTEND:20231010T190000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Fisica Ii Gr. 103 +LOCATION:Edificio 4B-305 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:c9d54fc8-093c-4d96-ae2d-cb60364d04e6 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231011T180000Z +DTEND:20231011T190000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Fisica Ii Gr. 103 +LOCATION:Edificio 16B-110 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:6041c097-e7cc-4d3f-a97f-e698c559118c +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231012T170000Z +DTEND:20231012T190000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Fisica Ii Gr. 103 +LOCATION:Edificio 10-307 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:ceb72040-84f9-4484-aa6d-815d41e43f8b +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231010T230000Z +DTEND:20231011T004000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Laboratorio De Fisica Ii Gr. 106 +LOCATION:Edificio 1A-119 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:379b3322-2b8c-4024-a941-e2abe1f43074 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231013T000000Z +DTEND:20231013T020000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Laboratorio De Circuito I Gr. 103 +LOCATION:Edificio 1B-019 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:553d712f-86a6-4d47-95c8-e88ed6144b91 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231011T190000Z +DTEND:20231011T210000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Programacion I Gr. 102 +LOCATION:Edificio 1A-209 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:55af1034-71bb-4db5-9ec5-9f60e93860b1 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231013T150000Z +DTEND:20231013T180000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Programacion I Gr. 102 +LOCATION:Edificio 3-211 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:d165a488-194b-4602-abae-e045decd02fe +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231016T190000Z +DTEND:20231016T210000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Circuitos I Gr. 101 +LOCATION:Edificio 1A-207 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +BEGIN:VEVENT +UID:0b81622a-7f80-4702-a716-a2273a695111 +SEQUENCE:0 +DTSTAMP:20231010T152654Z +DTSTART:20231012T190000Z +DTEND:20231012T210000Z +RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z +SUMMARY:Circuitos I Gr. 101 +LOCATION:Edificio 1A-207 +DESCRIPTION:Advice: You would should go to the classroom 10min before +URL;VALUE=URI:http://github.com/ +END:VEVENT +END:VCALENDAR \ No newline at end of file diff --git a/botTelegram/package-lock.json b/botTelegram/package-lock.json index 2d42730..f517ebd 100644 --- a/botTelegram/package-lock.json +++ b/botTelegram/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "dotenv": "^16.3.1", + "ical-generator": "^5.0.1", "puppeteer": "^19.8.5", "random-useragent": "^0.5.0", "telegraf": "^4.12.2" @@ -79,6 +80,16 @@ } } }, + "node_modules/@touch4it/ical-timezones": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@touch4it/ical-timezones/-/ical-timezones-1.9.0.tgz", + "integrity": "sha512-UAiZMrFlgMdOIaJDPsKu5S7OecyMLr3GGALJTYkRgHmsHAA/8Ixm1qD09ELP2X7U1lqgrctEgvKj9GzMbczC+g==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", @@ -585,6 +596,57 @@ "node": ">= 6" } }, + "node_modules/ical-generator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-5.0.1.tgz", + "integrity": "sha512-ln2cbzi+Z+f9WrWseU4B75Ccwb2hMpgjTYkriSPmqODmOCWNYknTSWiLSrCkl0cHiWcwaTWstMPLDyiFbELmoA==", + "dependencies": { + "uuid-random": "^1.3.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "@touch4it/ical-timezones": ">=1.6.0", + "@types/luxon": ">= 1.26.0", + "@types/mocha": ">= 8.2.1", + "@types/node": ">= 15.0.0", + "dayjs": ">= 1.10.0", + "luxon": ">= 1.26.0", + "moment": ">= 2.29.0", + "moment-timezone": ">= 0.5.33", + "rrule": ">= 2.6.8" + }, + "peerDependenciesMeta": { + "@touch4it/ical-timezones": { + "optional": true + }, + "@types/luxon": { + "optional": true + }, + "@types/mocha": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-timezone": { + "optional": true + }, + "rrule": { + "optional": true + } + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -1264,6 +1326,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid-random": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", + "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -1431,6 +1498,13 @@ "yargs": "17.7.1" } }, + "@touch4it/ical-timezones": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@touch4it/ical-timezones/-/ical-timezones-1.9.0.tgz", + "integrity": "sha512-UAiZMrFlgMdOIaJDPsKu5S7OecyMLr3GGALJTYkRgHmsHAA/8Ixm1qD09ELP2X7U1lqgrctEgvKj9GzMbczC+g==", + "optional": true, + "peer": true + }, "@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", @@ -1797,6 +1871,14 @@ "debug": "4" } }, + "ical-generator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-5.0.1.tgz", + "integrity": "sha512-ln2cbzi+Z+f9WrWseU4B75Ccwb2hMpgjTYkriSPmqODmOCWNYknTSWiLSrCkl0cHiWcwaTWstMPLDyiFbELmoA==", + "requires": { + "uuid-random": "^1.3.2" + } + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2296,6 +2378,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "uuid-random": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", + "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/botTelegram/package.json b/botTelegram/package.json index 49bf4e3..23a402f 100644 --- a/botTelegram/package.json +++ b/botTelegram/package.json @@ -18,6 +18,7 @@ "homepage": "https://github.com/JGaviria0/BotNotasUTP#readme", "type": "module", "dependencies": { + "ical-generator": "^5.0.1", "dotenv": "^16.3.1", "puppeteer": "^19.8.5", "random-useragent": "^0.5.0", @@ -26,4 +27,4 @@ "devDependencies": { "nodemon": "^2.0.22" } -} +} \ No newline at end of file diff --git a/botTelegram/src/botTelegram.js b/botTelegram/src/botTelegram.js index d48edf8..fc786a5 100644 --- a/botTelegram/src/botTelegram.js +++ b/botTelegram/src/botTelegram.js @@ -1,13 +1,14 @@ import { Telegraf } from "telegraf"; -import 'dotenv/config'; -import {historicGradesScraping, logInScraping } from "./util/scraper.js" +import * as dotenv from 'dotenv'; +import {historicGradesScraping, logInScraping, getGrades, getSchedule } from "./util/scraper.js" import { validateInputLogIn } from "./util/validations.js"; import { readHTML } from "./util/extractValues.js"; const GRADES_PAGE_URL = "https://app4.utp.edu.co/reportes/ryc/ReporteDetalladoNotasxEstudiante.php"; const HISTORIC_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/historial-web/programas.php"; +const SCHEDULE_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/horario.php"; const USERS_ID_DEFAULT_LENGTH = 10; // Amount of numbers of the citizen's id -const URL_BOT = process.env.URL_BOT; +const URL_BOT = "1622421418:AAFkFveWj569pzZ9V3nT2gMVCf-ZMlCVvX0"; const bot = new Telegraf(URL_BOT); @@ -17,10 +18,11 @@ bot.use((ctx, next) => { }) bot.start((ctx) => { - ctx.reply('Welcome'); + ctx.reply(`Welcome ${ctx.from.first_name}`); ctx.reply(`Para usar el bot alguno de los siguientes comando\n - /notas cedula contraseña\n - /promedio cedula contraseña\n + /notas código contraseña\n + /promedio código contraseña\n + /horario código contraseña\n Los datos del portal estudiantil`) }) @@ -57,11 +59,11 @@ bot.command([/notas.*/], async (ctx) => { const password = userInput[2]; validateInputLogIn(id, userInput) - const page = await logInScraping(id, password); + const {page} = await logInScraping(id, password); await page.goto(GRADES_PAGE_URL); const values = await readHTML(page); - console.log(values); + // console.log(values); for (const ms of values) { ctx.reply(ms) @@ -86,7 +88,7 @@ bot.command([/promedio.*/], async (ctx) => { const password = userInput[2]; validateInputLogIn(id, userInput) - const page = await logInScraping(id, password); + const {page, browser} = await logInScraping(id, password); await page.goto(HISTORIC_PAGE_URL); const userPrograms = await historicGradesScraping(page); @@ -97,12 +99,31 @@ bot.command([/promedio.*/], async (ctx) => { const programsIds = [] userPrograms.forEach(program => programsIds.push(program.id)); - console.log(programsIds); - bot.command(programsIds, () => { - console.log("Ha seleccionado una carrera"); + // console.log(programsIds); + + bot.command(programsIds, async (ctx) => { + const page = await browser.newPage(); + await page.goto(HISTORIC_PAGE_URL); + const programId = ctx.update.message.text.slice(1); + // console.log(page.isClosed()); + const { grades } = await getGrades(page, programId); + + let sumGrades = 0.0, sumCredits = 0.0; + for (let i = 0; i < grades.length; i++) { + const grade = grades[i].grade; + const credit = grades[i].cred; + + sumGrades += grade * credit; + sumCredits += credit; + } + + const result = sumGrades / sumCredits; + + ctx.reply(`Tu promedio acumulado es de: ${result.toFixed(2)}`) }); - page.close(); + await page.close(); + // await browser.close(); } catch (error) { //ERRORS_HANDLING[error.name](error.message, ctx) console.log(error); @@ -111,4 +132,34 @@ bot.command([/promedio.*/], async (ctx) => { } }) +// Command to export schedule +bot.command([/horario.*/], async (ctx) => { + showInfoMessage(ctx, 'Vamos a procesar su peticion, esto puede tardar algunos minutos.'); + + try { + const userInput = ctx.update.message.text.split(" "); + const id = userInput[1]; + const password = userInput[2]; + + validateInputLogIn(id, userInput) + const {page, browser} = await logInScraping(id, password); + await page.goto(SCHEDULE_PAGE_URL); + // await page.waitForNavigation(); + const schedule = await getSchedule(page); + + console.log(schedule.length()); + ctx.reply('Tu horario se ha creado'); + ctx.replyWithDocument('../calendar.ics').catch((error) => { + console.log(error); + }) + + await page.close(); + await browser.close(); + } catch (error) { + console.log(error); + } finally { + ctx.deleteMessage(ctx.update.message.message_id); + } +}); + bot.launch() \ No newline at end of file diff --git a/botTelegram/src/util/scraper.js b/botTelegram/src/util/scraper.js index 47fa56a..fbeca62 100644 --- a/botTelegram/src/util/scraper.js +++ b/botTelegram/src/util/scraper.js @@ -1,4 +1,5 @@ -import puppeteer from "puppeteer"; +import puppeteer, { Page } from "puppeteer"; +import {ICalCalendar} from 'ical-generator'; import * as randomUseragent from "random-useragent"; import { IncorrectData } from "./errors.js"; @@ -6,15 +7,17 @@ import { IncorrectData } from "./errors.js"; const logInScraping = async (user, password) => { - const header = randomUseragent.getRandom((ua) => { - return ua.browserName == 'Firefox'; - }); - const browser = await puppeteer.launch({ headless: false, ignoreHTTPSErrors: true, }); + //console.log(`La dirección WebSocket es: ${browserWSEndpoint}`); + + const header = randomUseragent.getRandom((ua) => { + return ua.browserName == 'Firefox'; + }); + const page = await browser.newPage(); await page.setUserAgent(header); @@ -36,24 +39,21 @@ const logInScraping = async (user, password) => { if (page.url() != 'https://app4.utp.edu.co/pe/utp.php') throw new IncorrectData("Usuario y/o contrasela incorrectos"); - return page; // returns portal home page (After log in) + return {page, browser}; // returns portal home page (After log in) //await page.goto("https://app4.utp.edu.co/reportes/ryc/ReporteDetalladoNotasxEstudiante.php", {timeout: 0}) } -const goToPage = async (homePage, pageUrl) => { - return await homePage.goto(pageUrl); -} - -const historicGradesScraping = async (programsPage) => { - await programsPage.waitForSelector('#cmbprogramas'); - const userPrograms = await programsPage.evaluate(() => { - var options = Array.from(document.querySelectorAll('html body div#utp-contenedor div#utp-contenido div fieldset.form1line select#cmbprogramas option')); +const historicGradesScraping = async (page) => { + await page.waitForSelector('#cmbprogramas'); + await new Promise(r => setTimeout(r, 600)); + const userPrograms = await page.evaluate(() => { + var options = Array.from(document.querySelectorAll('select#cmbprogramas option')); var finalOptions = []; for(var op of options) { var subjectId = op.textContent.substring(0,2); var subjectName = op.textContent.substring(3); - if(subjectId.match(/^[0-9]+$/) != null){ // Id only has numbers + if(subjectId != "Pr"){ // Id diferent of Programa finalOptions.push({id: subjectId, name: subjectName}); } } @@ -62,4 +62,153 @@ const historicGradesScraping = async (programsPage) => { return userPrograms; } -export { logInScraping, goToPage, historicGradesScraping }; +/** + * getGrades + * @param {Page} page + * @param {String} programId + */ +const getGrades = async (page, programId) => { + // await page.goto("https://app4.utp.edu.co/MatAcad/verificacion/historial-web/programas.php"); + // await page.waitForNavigation(); + const selector = await page.waitForSelector('#cmbprogramas'); + await selector.select(programId); + await new Promise(r => setTimeout(r, 600)); + + + const getGrades = await page.evaluate( () => { + var subjects = Array.from(document.querySelectorAll('fieldset#infoHistorial table.tblNotas table.tblDetalle tr td:nth-child(2)')); + var creds = Array.from(document.querySelectorAll('fieldset#infoHistorial table.tblNotas table.tblDetalle tr td:nth-child(3)')); + var allGrades = Array.from(document.querySelectorAll('fieldset#infoHistorial table.tblNotas table.tblDetalle tr td:nth-child(5)')); + var state = Array.from(document.querySelectorAll('fieldset#infoHistorial table.tblNotas table.tblDetalle tr td:nth-child(7)')); + + var gradesForSubject = {} + var grades = [] + for (var i = 0; i < allGrades.length; i++) { + if (state[i].innerText !== "Cursando") { + var grade = allGrades[i].innerText.replace(/\s/g, '').replace(/,/g, '.').toLowerCase(); + var data = {} + if (grade.includes("aprobado")) grade = 5; + + data.grade = parseFloat(grade, 10); + data.cred = parseInt(creds[i].innerText, 10); + + // It save in an object with grades and credits for subject + gradesForSubject[subjects[i].innerText] = data; + // It save in an array with grades and credits + grades.push(data); + } + } + return {grades, gradesForSubject} + }); + + //console.log("GRADES:", getGrades.grades); + // browser.close().then(setTimeout(() => console.log("Closing browser"), 600)); + return getGrades +} + +const getSchedule = async (page) => { + await new Promise(r => setTimeout(r, 600)); + const {info, subjects} = await page.evaluate( () => { + var scheduleData = Array.from(document.querySelector('div>fieldset.form1line').childNodes); + var info = [] + var subjects = [] + + for (var elemento of scheduleData){ + if (elemento.nodeName == '#text' && !elemento.textContent.includes('\n')){ + info.push(elemento.textContent.replace(/,\s$/, '').replace(/\sde\s/g,' ').replace(/\sa\s/g,' ')); + } + if (elemento.nodeName == 'STRONG'){ + subjects.push(elemento.innerText.slice(6)); + } + } + + for (var i = 0; i < info.length; i++){ + info[i] = info[i].replace(/,\s/g, ' ').split(' ') + } + + return {info, subjects} + }); + + // Creating the schedule + const calendar = new ICalCalendar({ + name: 'Horario de clases', + prodId: { + company: 'Universidad Tecnológica de Pereira', + product: 'Horario asignado', + language: 'ES' + } + }); + + for (let i = 0; i < info.length; i++) { + for (let j = 0; j < info[i].length; j+=4) { + const {startDate, endDate} = getSubjectDate(info[i][j+1] ,info[i][j+2], info[i][j+3]) + // console.log("TIME:", startDate.getHours()); + // console.log("TIME END:", endDate.getHours()); + calendar.createEvent({ + start: startDate, + end: endDate, + summary: subjects[i], + description: 'Advice: You would should go to the classroom 10min before', + location: `Edificio ${info[i][j]}`, + repeating: { + freq: 'WEEKLY', + until: new Date(2023, 10, 19, 0, 0, 0, 0), + wkst: 'SU' + } + }); + } + } + try { + calendar.save('./calendar.ics'); + } catch (error) { + console.log(error); + } + return calendar; +} + +const getSubjectDate = (day, timeInitial, timeEnd) => { + const days = ["Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"] + + let dayOfWeek = ""; + + // Convierte el dia de la semana dado a un número entre 1 y 7 + for (let i = 0; i < 7; i++) { + if (day === days[i]) { + dayOfWeek = i+1; + } + } + + // Crea una fecha inicial + const startDate = new Date(); + + // Encuentra el día de la semana actual + const startDayOfWeek = startDate.getDay(); + + // Calcula la diferencia entre el día de la semana deseado y el día actual. + const dayDifference = dayOfWeek - startDayOfWeek; + + // Calcula el número de días para agregar a la fecha inicial. + const daysToAdd = dayDifference >= 0 ? dayDifference : dayDifference + 7; + + // Agrega los días necesarios para llegar al día de la semana deseado. + startDate.setDate(startDate.getDate() + daysToAdd); + + // It saves hours and minutes like an array + const timeI = timeInitial.split(':'); + const timeE = timeEnd.split(':'); + // Set time + startDate.setHours(parseInt(timeI[0])); + startDate.setMinutes(parseInt(timeI[1])); + startDate.setSeconds(0); + startDate.setMilliseconds(0); + + // console.log(`HORA ${timeI[0]}:`, startDate.getHours()); + + const endDate = new Date(startDate); + endDate.setHours(parseInt(timeE[0])); + endDate.setMinutes(parseInt(timeE[1])); + + return {startDate, endDate} +} + +export { logInScraping, historicGradesScraping, getGrades, getSchedule }; From 244a762b9e4a36efaf2cb7463b301fde2d53a19f Mon Sep 17 00:00:00 2001 From: YohanColla Date: Sat, 21 Oct 2023 13:57:54 -0500 Subject: [PATCH 2/3] Update botTelegram.js --- botTelegram/src/botTelegram.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/botTelegram/src/botTelegram.js b/botTelegram/src/botTelegram.js index fc786a5..1bc45b3 100644 --- a/botTelegram/src/botTelegram.js +++ b/botTelegram/src/botTelegram.js @@ -8,7 +8,7 @@ const GRADES_PAGE_URL = "https://app4.utp.edu.co/reportes/ryc/ReporteDetalladoNo const HISTORIC_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/historial-web/programas.php"; const SCHEDULE_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/horario.php"; const USERS_ID_DEFAULT_LENGTH = 10; // Amount of numbers of the citizen's id -const URL_BOT = "1622421418:AAFkFveWj569pzZ9V3nT2gMVCf-ZMlCVvX0"; +const URL_BOT = process.env.URL_BOT; const bot = new Telegraf(URL_BOT); @@ -162,4 +162,4 @@ bot.command([/horario.*/], async (ctx) => { } }); -bot.launch() \ No newline at end of file +bot.launch() From 3d84b5283fc28c7c16de373d50916e1cbd940e3c Mon Sep 17 00:00:00 2001 From: YohanColla Date: Mon, 26 Feb 2024 16:10:04 -0500 Subject: [PATCH 3/3] Creacion del archivo .ics y envio a telegram --- botTelegram/calendar.ics | 150 -------------------------------- botTelegram/package-lock.json | 59 ++++++------- botTelegram/package.json | 4 +- botTelegram/src/botTelegram.js | 30 ++++--- botTelegram/src/util/scraper.js | 38 +++++--- 5 files changed, 75 insertions(+), 206 deletions(-) delete mode 100644 botTelegram/calendar.ics diff --git a/botTelegram/calendar.ics b/botTelegram/calendar.ics deleted file mode 100644 index 21a6545..0000000 --- a/botTelegram/calendar.ics +++ /dev/null @@ -1,150 +0,0 @@ -BEGIN:VCALENDAR -VERSION:2.0 -PRODID:-//Universidad Tecnológica de Pereira//Horario asignado//ES -NAME:Horario de clases -X-WR-CALNAME:Horario de clases -BEGIN:VEVENT -UID:627f6dce-d85f-4192-afad-a1b678245df0 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231010T210000Z -DTEND:20231010T220000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Matematicas Iii Gr. 103 -LOCATION:Edificio 6-125 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:d74b9875-1369-44e8-ab43-fb02d6070374 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231011T210000Z -DTEND:20231011T230000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Matematicas Iii Gr. 103 -LOCATION:Edificio 1A-208 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:01d80519-4d82-4650-97e0-c2ad1e02ffcf -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231013T210000Z -DTEND:20231013T230000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Matematicas Iii Gr. 103 -LOCATION:Edificio 1A-209 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:e80002ee-77d4-44da-a2b8-d6205b0d0217 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231010T170000Z -DTEND:20231010T190000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Fisica Ii Gr. 103 -LOCATION:Edificio 4B-305 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:c9d54fc8-093c-4d96-ae2d-cb60364d04e6 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231011T180000Z -DTEND:20231011T190000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Fisica Ii Gr. 103 -LOCATION:Edificio 16B-110 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:6041c097-e7cc-4d3f-a97f-e698c559118c -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231012T170000Z -DTEND:20231012T190000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Fisica Ii Gr. 103 -LOCATION:Edificio 10-307 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:ceb72040-84f9-4484-aa6d-815d41e43f8b -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231010T230000Z -DTEND:20231011T004000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Laboratorio De Fisica Ii Gr. 106 -LOCATION:Edificio 1A-119 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:379b3322-2b8c-4024-a941-e2abe1f43074 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231013T000000Z -DTEND:20231013T020000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Laboratorio De Circuito I Gr. 103 -LOCATION:Edificio 1B-019 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:553d712f-86a6-4d47-95c8-e88ed6144b91 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231011T190000Z -DTEND:20231011T210000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Programacion I Gr. 102 -LOCATION:Edificio 1A-209 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:55af1034-71bb-4db5-9ec5-9f60e93860b1 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231013T150000Z -DTEND:20231013T180000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Programacion I Gr. 102 -LOCATION:Edificio 3-211 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:d165a488-194b-4602-abae-e045decd02fe -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231016T190000Z -DTEND:20231016T210000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Circuitos I Gr. 101 -LOCATION:Edificio 1A-207 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -BEGIN:VEVENT -UID:0b81622a-7f80-4702-a716-a2273a695111 -SEQUENCE:0 -DTSTAMP:20231010T152654Z -DTSTART:20231012T190000Z -DTEND:20231012T210000Z -RRULE:FREQ=WEEKLY;UNTIL=20231119T050000Z -SUMMARY:Circuitos I Gr. 101 -LOCATION:Edificio 1A-207 -DESCRIPTION:Advice: You would should go to the classroom 10min before -URL;VALUE=URI:http://github.com/ -END:VEVENT -END:VCALENDAR \ No newline at end of file diff --git a/botTelegram/package-lock.json b/botTelegram/package-lock.json index f517ebd..61f4635 100644 --- a/botTelegram/package-lock.json +++ b/botTelegram/package-lock.json @@ -10,10 +10,10 @@ "license": "ISC", "dependencies": { "dotenv": "^16.3.1", - "ical-generator": "^5.0.1", + "ical-generator": "^6.0.1", "puppeteer": "^19.8.5", "random-useragent": "^0.5.0", - "telegraf": "^4.12.2" + "telegraf": "^4.15.3" }, "devDependencies": { "nodemon": "^2.0.22" @@ -80,6 +80,11 @@ } } }, + "node_modules/@telegraf/types": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@telegraf/types/-/types-6.9.1.tgz", + "integrity": "sha512-bzqwhicZq401T0e09tu8b1KvGfJObPmzKU/iKCT5V466AsAZZWQrBYQ5edbmD1VZuHLEwopoOVY5wPP4HaLtug==" + }, "node_modules/@touch4it/ical-timezones": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@touch4it/ical-timezones/-/ical-timezones-1.9.0.tgz", @@ -597,20 +602,19 @@ } }, "node_modules/ical-generator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-5.0.1.tgz", - "integrity": "sha512-ln2cbzi+Z+f9WrWseU4B75Ccwb2hMpgjTYkriSPmqODmOCWNYknTSWiLSrCkl0cHiWcwaTWstMPLDyiFbELmoA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-6.0.1.tgz", + "integrity": "sha512-m0Li239l4xddH+MveodfAWFFrHrT8F3rGmgR0zyWUe0Mg7Q/XxiPssN+cKer3+WSpfFNyhjdAsqalTUivKl/vQ==", "dependencies": { "uuid-random": "^1.3.2" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "@touch4it/ical-timezones": ">=1.6.0", "@types/luxon": ">= 1.26.0", "@types/mocha": ">= 8.2.1", - "@types/node": ">= 15.0.0", "dayjs": ">= 1.10.0", "luxon": ">= 1.26.0", "moment": ">= 2.29.0", @@ -1228,18 +1232,18 @@ } }, "node_modules/telegraf": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.12.2.tgz", - "integrity": "sha512-PgwqI4wD86cMqVfFtEM9JkGGnMHgvgLJbReZMmwW4z35QeOi4DvbdItONld4bPnYn3A1jcO0SRKs0BXmR+x+Ew==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.15.3.tgz", + "integrity": "sha512-pm2ZQAisd0YlUvnq6xdymDfoQR++8wTalw0nfw7Tjy0va+V/0HaBLzM8kMNid8pbbt7GHTU29lEyA5CAAr8AqA==", "dependencies": { + "@telegraf/types": "^6.9.1", "abort-controller": "^3.0.0", "debug": "^4.3.4", "mri": "^1.2.0", "node-fetch": "^2.6.8", "p-timeout": "^4.1.0", "safe-compare": "^1.1.4", - "sandwich-stream": "^2.0.2", - "typegram": "^4.3.0" + "sandwich-stream": "^2.0.2" }, "bin": { "telegraf": "lib/cli.mjs" @@ -1301,11 +1305,6 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/typegram": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/typegram/-/typegram-4.3.0.tgz", - "integrity": "sha512-pS4STyOZoJ++Mwa9GPMTNjOwEzMkxFfFt1By6IbMOJfheP0utMP/H1ga6J9R4DTjAYBr0UDn4eQg++LpWBvcAg==" - }, "node_modules/unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", @@ -1498,6 +1497,11 @@ "yargs": "17.7.1" } }, + "@telegraf/types": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@telegraf/types/-/types-6.9.1.tgz", + "integrity": "sha512-bzqwhicZq401T0e09tu8b1KvGfJObPmzKU/iKCT5V466AsAZZWQrBYQ5edbmD1VZuHLEwopoOVY5wPP4HaLtug==" + }, "@touch4it/ical-timezones": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@touch4it/ical-timezones/-/ical-timezones-1.9.0.tgz", @@ -1872,9 +1876,9 @@ } }, "ical-generator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-5.0.1.tgz", - "integrity": "sha512-ln2cbzi+Z+f9WrWseU4B75Ccwb2hMpgjTYkriSPmqODmOCWNYknTSWiLSrCkl0cHiWcwaTWstMPLDyiFbELmoA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-6.0.1.tgz", + "integrity": "sha512-m0Li239l4xddH+MveodfAWFFrHrT8F3rGmgR0zyWUe0Mg7Q/XxiPssN+cKer3+WSpfFNyhjdAsqalTUivKl/vQ==", "requires": { "uuid-random": "^1.3.2" } @@ -2301,18 +2305,18 @@ } }, "telegraf": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.12.2.tgz", - "integrity": "sha512-PgwqI4wD86cMqVfFtEM9JkGGnMHgvgLJbReZMmwW4z35QeOi4DvbdItONld4bPnYn3A1jcO0SRKs0BXmR+x+Ew==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.15.3.tgz", + "integrity": "sha512-pm2ZQAisd0YlUvnq6xdymDfoQR++8wTalw0nfw7Tjy0va+V/0HaBLzM8kMNid8pbbt7GHTU29lEyA5CAAr8AqA==", "requires": { + "@telegraf/types": "^6.9.1", "abort-controller": "^3.0.0", "debug": "^4.3.4", "mri": "^1.2.0", "node-fetch": "^2.6.8", "p-timeout": "^4.1.0", "safe-compare": "^1.1.4", - "sandwich-stream": "^2.0.2", - "typegram": "^4.3.0" + "sandwich-stream": "^2.0.2" }, "dependencies": { "node-fetch": { @@ -2353,11 +2357,6 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "typegram": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/typegram/-/typegram-4.3.0.tgz", - "integrity": "sha512-pS4STyOZoJ++Mwa9GPMTNjOwEzMkxFfFt1By6IbMOJfheP0utMP/H1ga6J9R4DTjAYBr0UDn4eQg++LpWBvcAg==" - }, "unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", diff --git a/botTelegram/package.json b/botTelegram/package.json index 23a402f..7a772de 100644 --- a/botTelegram/package.json +++ b/botTelegram/package.json @@ -18,11 +18,11 @@ "homepage": "https://github.com/JGaviria0/BotNotasUTP#readme", "type": "module", "dependencies": { - "ical-generator": "^5.0.1", + "ical-generator": "^6.0.1", "dotenv": "^16.3.1", "puppeteer": "^19.8.5", "random-useragent": "^0.5.0", - "telegraf": "^4.12.2" + "telegraf": "^4.15.3" }, "devDependencies": { "nodemon": "^2.0.22" diff --git a/botTelegram/src/botTelegram.js b/botTelegram/src/botTelegram.js index fc786a5..7277c28 100644 --- a/botTelegram/src/botTelegram.js +++ b/botTelegram/src/botTelegram.js @@ -1,14 +1,15 @@ -import { Telegraf } from "telegraf"; -import * as dotenv from 'dotenv'; -import {historicGradesScraping, logInScraping, getGrades, getSchedule } from "./util/scraper.js" +import { Telegraf, Input } from "telegraf"; +import 'dotenv/config'; +import fs from 'fs'; import { validateInputLogIn } from "./util/validations.js"; import { readHTML } from "./util/extractValues.js"; +import {historicGradesScraping, logInScraping, getGrades, getSchedule } from "./util/scraper.js" const GRADES_PAGE_URL = "https://app4.utp.edu.co/reportes/ryc/ReporteDetalladoNotasxEstudiante.php"; const HISTORIC_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/historial-web/programas.php"; const SCHEDULE_PAGE_URL = "https://app4.utp.edu.co/MatAcad/verificacion/horario.php"; const USERS_ID_DEFAULT_LENGTH = 10; // Amount of numbers of the citizen's id -const URL_BOT = "1622421418:AAFkFveWj569pzZ9V3nT2gMVCf-ZMlCVvX0"; +const URL_BOT = process.env.URL_BOT; const bot = new Telegraf(URL_BOT); @@ -145,13 +146,22 @@ bot.command([/horario.*/], async (ctx) => { const {page, browser} = await logInScraping(id, password); await page.goto(SCHEDULE_PAGE_URL); // await page.waitForNavigation(); - const schedule = await getSchedule(page); + try { + await getSchedule(page) + } catch (error) { + console.log("Failed to get schedule") + } + - console.log(schedule.length()); - ctx.reply('Tu horario se ha creado'); - ctx.replyWithDocument('../calendar.ics').catch((error) => { - console.log(error); - }) + if (fs.existsSync('./calendar.ics')){ + ctx.reply('Tu horario se ha creado'); + ctx.replyWithDocument(Input.fromLocalFile('./calendar.ics', 'calendar.ics')).catch((error) => { + console.log(error); + }) + } else { + ctx.reply("Ocurrió un error durante el envío del calendario") + } + await page.close(); await browser.close(); diff --git a/botTelegram/src/util/scraper.js b/botTelegram/src/util/scraper.js index fbeca62..065b1a3 100644 --- a/botTelegram/src/util/scraper.js +++ b/botTelegram/src/util/scraper.js @@ -1,5 +1,6 @@ import puppeteer, { Page } from "puppeteer"; -import {ICalCalendar} from 'ical-generator'; +import {ICalCalendar, ICalAlarmType} from 'ical-generator'; +import { writeFile } from 'node:fs/promises'; import * as randomUseragent from "random-useragent"; import { IncorrectData } from "./errors.js"; @@ -100,33 +101,36 @@ const getGrades = async (page, programId) => { } return {grades, gradesForSubject} }); - - //console.log("GRADES:", getGrades.grades); + // browser.close().then(setTimeout(() => console.log("Closing browser"), 600)); return getGrades } const getSchedule = async (page) => { await new Promise(r => setTimeout(r, 600)); - const {info, subjects} = await page.evaluate( () => { + + const {info, subjects, teachers} = await page.evaluate( () => { var scheduleData = Array.from(document.querySelector('div>fieldset.form1line').childNodes); - var info = [] - var subjects = [] + var info = [], subjects = [], teachers = []; for (var elemento of scheduleData){ if (elemento.nodeName == '#text' && !elemento.textContent.includes('\n')){ info.push(elemento.textContent.replace(/,\s$/, '').replace(/\sde\s/g,' ').replace(/\sa\s/g,' ')); } - if (elemento.nodeName == 'STRONG'){ + if (elemento.nodeName == 'STRONG' && !elemento.textContent.includes('@')){ subjects.push(elemento.innerText.slice(6)); } + + if (elemento.nodeName == 'STRONG' && elemento.textContent.includes('@')){ + teachers.push(elemento.innerText.slice(3)); + } } for (var i = 0; i < info.length; i++){ info[i] = info[i].replace(/,\s/g, ' ').split(' ') } - return {info, subjects} + return {info, subjects, teachers} }); // Creating the schedule @@ -139,27 +143,33 @@ const getSchedule = async (page) => { } }); + for (let i = 0; i < info.length; i++) { for (let j = 0; j < info[i].length; j+=4) { const {startDate, endDate} = getSubjectDate(info[i][j+1] ,info[i][j+2], info[i][j+3]) - // console.log("TIME:", startDate.getHours()); - // console.log("TIME END:", endDate.getHours()); calendar.createEvent({ start: startDate, end: endDate, summary: subjects[i], - description: 'Advice: You would should go to the classroom 10min before', + description: teachers[i] + '\n\nAdvice: You would should go to the classroom 10min before', location: `Edificio ${info[i][j]}`, repeating: { freq: 'WEEKLY', - until: new Date(2023, 10, 19, 0, 0, 0, 0), + until: new Date(2024, 5, 26, 0, 0, 0, 0), wkst: 'SU' - } + }, + alarms: [ + {type: ICalAlarmType.display, trigger: 1200}, + ] }); } } + + + + try { - calendar.save('./calendar.ics'); + await writeFile('./calendar.ics', calendar.toString()); } catch (error) { console.log(error); }