PronounsPage/server/miastamaszerujace.ts
2025-06-19 18:03:32 -04:00

111 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import './setup.ts';
import fs from 'fs';
import * as Sentry from '@sentry/node';
import { createEvents } from 'ics';
import { JSDOM } from 'jsdom';
import { Day } from '../src/calendar/helpers.ts';
import type { MiastamaszerujaceEvent } from '../src/calendar/helpers.ts';
import mailer from './mailer.ts';
import { loadTranslator } from '~/server/data.ts';
const __dirname = new URL('.', import.meta.url).pathname;
const year = Day.today().year;
const fetchEvents = async (): Promise<MiastamaszerujaceEvent[]> => {
const events: MiastamaszerujaceEvent[] = [];
// issue with third-party cert: Verification error: unable to verify the first certificate
// browser and curl accepts the certificate, but node seems more picky
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
const html = await (await fetch('https://miastamaszerujace.pl/')).text();
const dom = new JSDOM(html
// manual fixes for irregular HTML
.replace(new RegExp('ref=newsfeed</a><br /><b>', 'g'), '</a></p><p><b>')
.replace(new RegExp('<span style="font-weight: 400;">(.*?)</span>', 'g'), '$1'));
const eventNodes = dom.window.document.querySelectorAll('[data-id="d4c3075"] p, [data-id="9cc25f4"] p');
for (const p of eventNodes) {
if (p.textContent!.includes('Daty kolejnych') ||
p.textContent!.includes('Marsz organizowany przez grupę współpracującą') ||
p.textContent!.includes('Opublikowane do tej pory')
) {
continue;
}
const [day, month] = p.querySelector('b,strong')!.textContent!.trim().split('/');
const date = new Day(year, parseInt(month), parseInt(day));
const name = [...p.childNodes]
.filter((c) => c.nodeType === 3 /* text node */ || c.nodeName === 'A')
.map((c) => c.textContent!.trim())
.filter((t) => !!t)
.join(' ')
.replace(/^ /, '')
;
let link = null;
try {
link = new URL(p.querySelector('a')!.getAttribute('href')!);
link.hash = '';
link.search = '';
} catch (e) { void 0; }
events.push({
name,
date,
link: link ? link.toString() : null,
});
}
return events;
};
(async (): Promise<void> => {
const events = await fetchEvents();
console.log(events);
const dir = `${__dirname}/../calendar/pl`;
const path = `${dir}/miastamaszerujace-${year}.json`;
const previous = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path).toString('utf-8')) : [];
if (JSON.stringify(events) !== JSON.stringify(previous)) {
console.log('wykryto zmiany, wysyłam maila');
await mailer('kontakt@zaimki.pl', 'miastamaszerujace', await loadTranslator('_'), {
before: JSON.stringify(previous, null, 4),
after: JSON.stringify(events, null, 4),
maxwidth: '100%',
});
}
if (previous.length > events.length) {
console.error('stopping execution, number of events decreased');
return;
}
console.log(`Saving to ${path}`);
fs.writeFileSync(path, JSON.stringify(events, null, 4));
createEvents(
events.map((e, i) => {
return {
title: e.name,
start: [e.date.year, e.date.month, e.date.day],
end: [e.date.year, e.date.month, e.date.day],
calName: `Marsze Równości ${year}`,
sequence: i,
};
}),
(error, value) => {
if (error) {
Sentry.captureException(error);
return;
}
console.log(`Saving to ${dir}/miastamaszerujace.ics`);
fs.writeFileSync(`${dir}/miastamaszerujace.ics`, value);
},
);
})();