Compare commits

...

2 commits

Author SHA1 Message Date
5588c999a7 finding dynamiclly the date and time from the headers 2023-08-15 15:01:11 +03:00
fd7e2377e1 testing 2023-08-13 11:44:41 +03:00
7 changed files with 97 additions and 77 deletions

50
dist/GameSource.js vendored
View file

@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
require('dotenv').config(); require("dotenv").config();
const axios_1 = __importDefault(require("axios")); const axios_1 = __importDefault(require("axios"));
const node_html_parser_1 = require("node-html-parser"); const node_html_parser_1 = require("node-html-parser");
const moment_1 = __importDefault(require("moment")); // require const moment_1 = __importDefault(require("moment")); // require
@ -17,34 +17,62 @@ class GameSource {
const gameBoxs = parsedResult.querySelectorAll(".game-box"); const gameBoxs = parsedResult.querySelectorAll(".game-box");
const games = []; const games = [];
for (let gameBox of gameBoxs) { for (let gameBox of gameBoxs) {
const teamsPlaying = gameBox.querySelectorAll(".team-name").map((team) => team.text); const teamsPlaying = gameBox
.querySelectorAll(".team-name")
.map((team) => team.text);
const regex = /[\r\n\s]+/g; const regex = /[\r\n\s]+/g;
const gameHeader = gameBox.querySelector(".game-header").text.replace(regex, " ").trim(); const gameHeader = gameBox
.querySelector(".game-header")
.text.replace(regex, " ")
.trim();
const headerSplit = gameHeader.split(","); const headerSplit = gameHeader.split(",");
// In data, if there is no time, it means it's the last game for the calender // In data, if there is no time, it means it's the last game for the calender
const lastGameForCalender = headerSplit.length < 4; const lastGameForCalender = headerSplit.length < 4;
if (lastGameForCalender) if (lastGameForCalender)
break; break;
const gameDate = headerSplit[2].trim(); const gameDate = this.findDate(headerSplit);
const gameTime = headerSplit[3].trim(); const gameTime = this.findTime(headerSplit);
const start = (0, moment_1.default)(gameDate + gameTime, "DD/MM/YYYYHH:mm").toISOString(); const start = (0, moment_1.default)(gameDate + gameTime, "DD/MM/YYYYHH:mm").toISOString();
const end = (0, moment_1.default)(gameDate + gameTime, "DD/MM/YYYYHH:mm").add(2, "hours").toISOString(); const end = (0, moment_1.default)(gameDate + gameTime, "DD/MM/YYYYHH:mm")
.add(2, "hours")
.toISOString();
games.push({ games.push({
summary: 'Maccabi Haifa F.C.', summary: "Maccabi Haifa F.C.",
location: headerSplit[4].trim(), location: headerSplit[headerSplit.length - 1].trim(),
description: `${teamsPlaying[0]} vs. ${teamsPlaying[1]}`, description: `${teamsPlaying[0]} vs. ${teamsPlaying[1]}`,
start: { start: {
dateTime: start, dateTime: start,
timeZone: 'Asia/Jerusalem' timeZone: "Asia/Jerusalem",
}, },
end: { end: {
dateTime: end, dateTime: end,
timeZone: 'Asia/Jerusalem' timeZone: "Asia/Jerusalem",
} },
}); });
} }
return games; return games;
} }
findTime(headerSplit) {
let time = '';
headerSplit.forEach((item) => {
if (/\d{2}:\d{2}/.test(item)) {
time = item;
return;
}
});
return time.trim();
}
findDate(headerSplit) {
// if it's a date format, return it like: 19/08/2023
let date = '';
headerSplit.forEach((item) => {
if (/\d{2}\/\d{2}\/\d{4}/.test(item)) {
date = item;
return;
}
});
return date.trim();
}
getOpponentIndexByStadium(stadium) { getOpponentIndexByStadium(stadium) {
if (stadium === "Sammy Ofer Stadium") { if (stadium === "Sammy Ofer Stadium") {
return 1; return 1;

2
dist/index.js vendored
View file

@ -28,6 +28,8 @@ class App {
} }
else { else {
console.log("Event already exists"); console.log("Event already exists");
console.log("Event:");
console.log("Happening at:");
} }
} }
if (newGamesAdded.length > 0) { if (newGamesAdded.length > 0) {

37
package-lock.json generated
View file

@ -6,12 +6,10 @@
"": { "": {
"dependencies": { "dependencies": {
"axios": "^1.3.4", "axios": "^1.3.4",
"cron": "^2.3.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"googleapis": "^122.0.0", "googleapis": "^122.0.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.43", "moment-timezone": "^0.5.43",
"node-cron": "^3.0.2",
"node-html-parser": "^6.1.5", "node-html-parser": "^6.1.5",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
@ -191,14 +189,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/cron": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/cron/-/cron-2.3.0.tgz",
"integrity": "sha512-ZN5HP8zDY41sJolMsbc+GksRATcbvkPKF5wR/qc8FrV4NBVi9ORQa1HmYa5GydaysUB80X9XpRlRkooa5uEtTA==",
"dependencies": {
"luxon": "^3.2.1"
}
},
"node_modules/css-select": { "node_modules/css-select": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
@ -578,14 +568,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/luxon": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
"integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
"engines": {
"node": ">=12"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -629,25 +611,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}, },
"node_modules/node-cron": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
"dependencies": {
"uuid": "8.3.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/node-cron/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.6.12", "version": "2.6.12",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",

View file

@ -1,12 +1,10 @@
{ {
"dependencies": { "dependencies": {
"axios": "^1.3.4", "axios": "^1.3.4",
"cron": "^2.3.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"googleapis": "^122.0.0", "googleapis": "^122.0.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.43", "moment-timezone": "^0.5.43",
"node-cron": "^3.0.2",
"node-html-parser": "^6.1.5", "node-html-parser": "^6.1.5",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },

View file

@ -1,57 +1,87 @@
require('dotenv').config(); require("dotenv").config();
import axios from "axios"; import axios from "axios";
import { GoogleCalendarEvent } from "./types"; import { GoogleCalendarEvent } from "./types";
import { parse } from 'node-html-parser'; import { parse } from "node-html-parser";
import moment from 'moment'; // require import moment from "moment"; // require
// This calss will be the game source. // This calss will be the game source.
// search for upcomming games // search for upcomming games
export default class GameSource { export default class GameSource {
async getGamesFromHaifa(): Promise<GoogleCalendarEvent[]> { async getGamesFromHaifa(): Promise<GoogleCalendarEvent[]> {
const sourceUrl = `https://mhaifafc.com/games?lang=en`; const sourceUrl = `https://mhaifafc.com/games?lang=en`;
const result = await axios.get(sourceUrl); const result = await axios.get(sourceUrl);
const parsedResult = parse(result.data.toString()) const parsedResult = parse(result.data.toString());
const gameBoxs = parsedResult.querySelectorAll(".game-box"); const gameBoxs = parsedResult.querySelectorAll(".game-box");
const games: GoogleCalendarEvent[] = []; const games: GoogleCalendarEvent[] = [];
for (let gameBox of gameBoxs) { for (let gameBox of gameBoxs) {
const teamsPlaying = gameBox
const teamsPlaying = gameBox.querySelectorAll(".team-name").map((team: any) => team.text); .querySelectorAll(".team-name")
.map((team: any) => team.text);
const regex = /[\r\n\s]+/g; const regex = /[\r\n\s]+/g;
const gameHeader = gameBox.querySelector(".game-header").text.replace(regex, " ").trim(); const gameHeader = gameBox
.querySelector(".game-header")
.text.replace(regex, " ")
.trim();
const headerSplit = gameHeader.split(","); const headerSplit = gameHeader.split(",");
// In data, if there is no time, it means it's the last game for the calender // In data, if there is no time, it means it's the last game for the calender
const lastGameForCalender = headerSplit.length < 4; const lastGameForCalender = headerSplit.length < 4;
if (lastGameForCalender) break; if (lastGameForCalender) break;
const gameDate = headerSplit[2].trim();
const gameTime = headerSplit[3].trim();
const start = moment(gameDate + gameTime, "DD/MM/YYYYHH:mm").toISOString();
const end = moment(gameDate + gameTime, "DD/MM/YYYYHH:mm").add(2, "hours").toISOString();
const gameDate = this.findDate(headerSplit);
const gameTime = this.findTime(headerSplit);
const start = moment(
games.push({ gameDate + gameTime,
summary: 'Maccabi Haifa F.C.', "DD/MM/YYYYHH:mm"
location: headerSplit[4].trim(), ).toISOString();
const end = moment(gameDate + gameTime, "DD/MM/YYYYHH:mm")
.add(2, "hours")
.toISOString();
games.push({
summary: "Maccabi Haifa F.C.",
location: headerSplit[headerSplit.length - 1].trim(),
description: `${teamsPlaying[0]} vs. ${teamsPlaying[1]}`, description: `${teamsPlaying[0]} vs. ${teamsPlaying[1]}`,
start: { start: {
dateTime: start, dateTime: start,
timeZone: 'Asia/Jerusalem' timeZone: "Asia/Jerusalem",
}, },
end: { end: {
dateTime: end, dateTime: end,
timeZone: 'Asia/Jerusalem' timeZone: "Asia/Jerusalem",
} },
}) });
} }
return games; return games;
} }
private findTime(headerSplit: string[]) {
let time = '';
headerSplit.forEach((item) => {
if (/\d{2}:\d{2}/.test(item)) {
time = item;
return
}
});
return time.trim();
}
private findDate(headerSplit: string[]) {
// if it's a date format, return it like: 19/08/2023
let date = '';
headerSplit.forEach((item) => {
if(/\d{2}\/\d{2}\/\d{4}/.test(item)) {
date = item;
return;
}
})
return date.trim();
}
getOpponentIndexByStadium(stadium: string) { getOpponentIndexByStadium(stadium: string) {
if (stadium === "Sammy Ofer Stadium") { if (stadium === "Sammy Ofer Stadium") {
return 1; return 1;
@ -59,4 +89,4 @@ export default class GameSource {
return 0; return 0;
} }
} }
} }

View file

@ -1,7 +1,6 @@
import GameSource from "./GameSource"; import GameSource from "./GameSource";
import GoogleCalendar from "./GoogleCalendar"; import GoogleCalendar from "./GoogleCalendar";
import env from "dotenv"; import env from "dotenv";
import cron from "node-cron";
env.config(); env.config();
@ -19,7 +18,6 @@ class App {
console.log("START CRON JOB"); console.log("START CRON JOB");
const newGamesAdded = []; const newGamesAdded = [];
await this.googleCalendar.init(); await this.googleCalendar.init();
// Schedule the job to run daily at a specific time (e.g., 1:00 AM) // Schedule the job to run daily at a specific time (e.g., 1:00 AM)
try { try {
const games = await app.gameSource.getGamesFromHaifa(); const games = await app.gameSource.getGamesFromHaifa();

View file

@ -1,2 +1,3 @@
#!/bin/bash #!/bin/bash
docker run -p 3000:3000 -d --restart=unless-stopped --name haifareminder docker.io/kfda89/haifareminder docker run -p 3000:3000 -d --restart=unless-stopped --name haifareminder docker.io/kfda89/haifareminder