2023-09-28 00:00:46 +02:00
|
|
|
use chrono::{DateTime, Duration, Utc};
|
2022-08-15 17:25:36 +02:00
|
|
|
use regex::{Captures, Regex};
|
2023-09-28 00:00:46 +02:00
|
|
|
use scraper::Selector;
|
2024-01-01 14:14:13 +01:00
|
|
|
use std::{collections::HashMap, sync::Arc};
|
2022-08-15 12:20:16 +02:00
|
|
|
|
2024-01-22 21:46:25 +01:00
|
|
|
use crate::utils::{
|
|
|
|
get_semester, get_webpage, get_year,
|
|
|
|
models::{Info, InfoList, InfoType},
|
|
|
|
};
|
2022-08-15 17:50:16 +02:00
|
|
|
|
2024-09-13 19:00:18 +02:00
|
|
|
pub async fn get_start_date(
|
2023-09-28 00:00:46 +02:00
|
|
|
level: i8,
|
|
|
|
semester_opt: Option<i8>,
|
|
|
|
year_opt: Option<i32>,
|
|
|
|
user_agent: &str,
|
2024-09-13 19:00:18 +02:00
|
|
|
) -> String {
|
2023-09-28 00:00:46 +02:00
|
|
|
let semester = get_semester(semester_opt);
|
|
|
|
let year = get_year(year_opt, semester);
|
2022-08-15 20:12:22 +02:00
|
|
|
|
2023-09-28 00:23:51 +02:00
|
|
|
// Fetch the timetable of the FIRST semester
|
|
|
|
let document = get_webpage(level, 1, &year, user_agent)
|
2023-09-28 00:00:46 +02:00
|
|
|
.await
|
|
|
|
.expect("Can't reach info website.");
|
2022-08-15 12:20:16 +02:00
|
|
|
|
2023-09-28 00:00:46 +02:00
|
|
|
// Selectors
|
|
|
|
let sel_b = Selector::parse("b").unwrap();
|
|
|
|
let sel_font = Selector::parse("font").unwrap();
|
|
|
|
|
|
|
|
// Find when is the back-to-school date
|
|
|
|
let raw_data = document
|
|
|
|
.select(&sel_b)
|
|
|
|
.find(|element| element.select(&sel_font).next().is_some())
|
|
|
|
.unwrap()
|
|
|
|
.inner_html();
|
|
|
|
|
|
|
|
let re = Regex::new(r"\d{1,2} (septembre|octobre)").unwrap();
|
2024-09-13 19:00:18 +02:00
|
|
|
|
|
|
|
re.captures(&raw_data)
|
|
|
|
.and_then(|caps| caps.get(0))
|
|
|
|
.map_or("1 septembre".to_owned(), |m| m.as_str().to_owned())
|
|
|
|
}
|
|
|
|
|
2024-09-13 19:07:18 +02:00
|
|
|
pub fn info(semester_opt: Option<i8>, year_opt: Option<i32>, date: &str, skip_week: bool) -> Info {
|
2024-09-13 19:00:18 +02:00
|
|
|
let semester = get_semester(semester_opt);
|
|
|
|
let year = get_year(year_opt, semester);
|
2023-09-28 00:00:46 +02:00
|
|
|
|
2024-01-22 18:27:18 +01:00
|
|
|
// 1st semester
|
|
|
|
let weeks_s1_1 = 6; // Weeks before break
|
|
|
|
let weeks_s1_2 = 7; // Weeks after break
|
|
|
|
let date_s1_1 = get_date(&format!("{} {}", date, year.split_once('-').unwrap().0)); // Get first week of school
|
|
|
|
let date_s1_2 = date_s1_1 + Duration::weeks(weeks_s1_1 + 1); // Back-to-school week - add week of holidays
|
2023-09-28 00:00:46 +02:00
|
|
|
|
2024-01-22 18:27:18 +01:00
|
|
|
// 2nd semester
|
|
|
|
let weeks_s2_1 = 11; // Weeks before break
|
|
|
|
let weeks_s2_2 = 1; // Weeks after break
|
|
|
|
let date_s2_1 = date_s1_2 + Duration::weeks(weeks_s1_2 + 4); // Get first week - add week of 'christmas/new year holidays'
|
|
|
|
let date_s2_2 = date_s2_1 + Duration::weeks(weeks_s2_1 + 2); // Back-to-school week - add week of holidays
|
2023-09-28 00:00:46 +02:00
|
|
|
|
2024-01-22 21:46:25 +01:00
|
|
|
// Group courses values and derive it for TD/TP
|
|
|
|
let cours_s1 = vec![(date_s1_1, weeks_s1_1), (date_s1_2, weeks_s1_2)];
|
|
|
|
let cours_s2 = vec![(date_s2_1, weeks_s2_1), (date_s2_2, weeks_s2_2)];
|
|
|
|
|
2024-09-13 19:07:18 +02:00
|
|
|
let delta = i64::from(skip_week);
|
|
|
|
|
|
|
|
let tdtp_s1 = derive_from_cours(&cours_s1, delta);
|
|
|
|
let tdtp_s2 = derive_from_cours(&cours_s2, delta);
|
2024-01-22 21:46:25 +01:00
|
|
|
|
2023-09-28 00:00:46 +02:00
|
|
|
HashMap::from([
|
|
|
|
(
|
|
|
|
1_usize,
|
2024-01-22 21:46:25 +01:00
|
|
|
InfoType {
|
|
|
|
course: cours_s1,
|
|
|
|
td_tp: tdtp_s1,
|
|
|
|
},
|
2023-09-28 00:00:46 +02:00
|
|
|
),
|
|
|
|
(
|
|
|
|
2_usize,
|
2024-01-22 21:46:25 +01:00
|
|
|
InfoType {
|
|
|
|
course: cours_s2,
|
|
|
|
td_tp: tdtp_s2,
|
|
|
|
},
|
2023-09-28 00:00:46 +02:00
|
|
|
),
|
|
|
|
])
|
2022-08-15 12:20:16 +02:00
|
|
|
}
|
2022-08-15 17:25:36 +02:00
|
|
|
|
2024-01-22 21:46:25 +01:00
|
|
|
/// Find TD/TP dates, based on the ones from courses
|
2024-09-13 19:07:18 +02:00
|
|
|
fn derive_from_cours(courses: &InfoList, delta: i64) -> Vec<(DateTime<Utc>, i64)> {
|
2024-01-22 21:46:25 +01:00
|
|
|
// TD/TP start one week after courses
|
|
|
|
let before_break = courses.first().unwrap();
|
|
|
|
let after_break = courses.last().unwrap();
|
|
|
|
vec![
|
2024-09-13 19:07:18 +02:00
|
|
|
(
|
|
|
|
before_break.0 + Duration::weeks(delta),
|
|
|
|
before_break.1 - delta,
|
|
|
|
),
|
|
|
|
(after_break.0, after_break.1 + delta),
|
2024-01-22 21:46:25 +01:00
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2022-08-15 17:25:36 +02:00
|
|
|
/// Turn a french date to an english one
|
|
|
|
fn anglophonization(date: &str) -> String {
|
|
|
|
let dico = HashMap::from([
|
|
|
|
("janvier", "january"),
|
2023-09-07 18:20:51 +02:00
|
|
|
("février", "february"),
|
2022-08-15 17:25:36 +02:00
|
|
|
("mars", "march"),
|
2023-09-07 18:20:51 +02:00
|
|
|
("avril", "april"),
|
|
|
|
("mai", "may"),
|
|
|
|
("juin", "june"),
|
|
|
|
("juillet", "july"),
|
|
|
|
("août", "august"),
|
2022-08-15 17:25:36 +02:00
|
|
|
("septembre", "september"),
|
2023-09-07 18:20:51 +02:00
|
|
|
("octobre", "october"),
|
2022-08-15 17:25:36 +02:00
|
|
|
("novembre", "november"),
|
2023-09-07 18:20:51 +02:00
|
|
|
("décembre", "december"),
|
2022-08-15 17:25:36 +02:00
|
|
|
]);
|
|
|
|
|
|
|
|
// New regex of all the french month
|
|
|
|
let re = Regex::new(&format!(
|
|
|
|
"({})",
|
2024-05-28 21:19:19 +02:00
|
|
|
dico.keys().copied().collect::<Arc<[_]>>().join("|")
|
2022-08-15 17:25:36 +02:00
|
|
|
))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
format!(
|
2023-09-07 18:29:09 +02:00
|
|
|
// Use 12:00 and UTC TZ for chrono parser
|
|
|
|
"{} 12:00 +0000",
|
2022-08-15 17:25:36 +02:00
|
|
|
// Replace french by english month
|
2024-09-13 19:00:18 +02:00
|
|
|
re.replace_all(&date.to_lowercase(), |cap: &Captures| match &cap[0] {
|
2023-09-07 18:19:29 +02:00
|
|
|
month if dico.contains_key(month) => dico.get(month).unwrap(),
|
|
|
|
month => {
|
2024-05-28 21:19:19 +02:00
|
|
|
panic!("Unknown month: {month}")
|
2022-08-15 17:25:36 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
2022-08-15 17:50:16 +02:00
|
|
|
|
2024-05-28 21:19:19 +02:00
|
|
|
/// Turn a string to a `DateTime`
|
2022-08-15 19:06:36 +02:00
|
|
|
fn get_date(date: &str) -> DateTime<Utc> {
|
2022-08-15 17:50:16 +02:00
|
|
|
// Use and keep UTC time, we have the hour set to 12h and
|
2023-09-18 18:46:50 +02:00
|
|
|
// Paris 7 is in France so there is no problems
|
2023-09-07 18:29:09 +02:00
|
|
|
DateTime::parse_from_str(&anglophonization(date), "%e %B %Y %H:%M %z")
|
2022-08-15 17:50:16 +02:00
|
|
|
.unwrap()
|
2023-09-07 18:29:09 +02:00
|
|
|
.into()
|
2022-08-15 17:50:16 +02:00
|
|
|
}
|