From 64911ba35121510629f455a97b422d7e47684d90 Mon Sep 17 00:00:00 2001 From: Mylloon Date: Fri, 3 Jan 2025 11:17:28 +0100 Subject: [PATCH] Many improvement to support many type of cases - ask for first period day of the current one instead of the first one - holidays are not mandatory anymore - also add an option to force the weeks number --- src/info.rs | 45 ++++++++++++++++++++++++++++++++------------- src/main.rs | 26 +++++++++++++++++++++----- src/utils.rs | 15 +++++++++++++++ 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/info.rs b/src/info.rs index cd2a35c..3b7cd58 100644 --- a/src/info.rs +++ b/src/info.rs @@ -4,7 +4,7 @@ use scraper::Selector; use std::{collections::HashMap, sync::Arc}; use crate::utils::{ - get_semester, get_webpage, get_year, + get_period_weeks, get_semester, get_webpage, get_year, models::{Info, InfoList, InfoType}, }; @@ -33,28 +33,47 @@ pub async fn get_start_date( .unwrap() .inner_html(); - let re = Regex::new(r"\d{1,2} (septembre|octobre)").unwrap(); + let first_semester = semester == 1; - re.captures(&raw_data) - .and_then(|caps| caps.get(0)) - .map_or("1 septembre".to_owned(), |m| m.as_str().to_owned()) + let re = Regex::new(if first_semester { + r"\d{1,2} (septembre|octobre)" + } else { + r"\d{1,2} (janvier|février)" + }) + .unwrap(); + + re.captures(&raw_data).and_then(|caps| caps.get(0)).map_or( + if first_semester { + "1 septembre" + } else { + "1 janvier" + } + .to_owned(), + |m| m.as_str().to_owned(), + ) } -pub fn info(semester_opt: Option, year_opt: Option, date: &str, skip_week: bool) -> Info { +#[allow(clippy::bool_to_int_with_if)] +pub fn info( + semester_opt: Option, + year_opt: Option, + date: &str, + skip_week: bool, + holidays: bool, + weeks: Option, +) -> Info { let semester = get_semester(semester_opt); let year = get_year(year_opt, semester); // 1st semester - let weeks_s1_1 = 6; // Weeks before break - let weeks_s1_2 = 7; // Weeks after break + let (weeks_s1_1, weeks_s1_2) = get_period_weeks(1, weeks); // Weeks before and 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 + let date_s1_2 = date_s1_1 + Duration::weeks(weeks_s1_1 + if holidays { 1 } else { 0 }); // Back-to-school week // 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 + let (weeks_s2_1, weeks_s2_2) = get_period_weeks(2, weeks); // Weeks before and after break + let date_s2_1 = get_date(&format!("{} {}", date, year.split_once('-').unwrap().1)); // Get first week + let date_s2_2 = date_s2_1 + Duration::weeks(weeks_s2_1 + if holidays { 2 } else { 0 }); // Back-to-school week // 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)]; diff --git a/src/main.rs b/src/main.rs index f4e6515..392ac85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod info; mod timetable; mod utils; +#[allow(clippy::struct_excessive_bools)] #[derive(Parser)] #[clap(version, about, long_about = None)] struct Args { @@ -31,17 +32,25 @@ struct Args { #[clap(short, long)] td_are_tp: bool, + /// Number of weeks for the period + #[clap(short, long, value_parser)] + weeks: Option, + /// First day of your year - #[clap(short, long)] + #[clap(long)] first_day: Option, /// If TD/TP start a week after courses - #[clap(short, long)] + #[clap(long)] week_skip: bool, /// If the exported ICS file should not use the timezone - #[clap(short, long)] + #[clap(long)] no_tz: bool, + + /// Guess the holidays and apply it to the generated calendar + #[clap(long)] + holidays: bool, } #[tokio::main] @@ -69,7 +78,7 @@ async fn main() { let date = match args.first_day { None => Input::new() - .with_prompt("Début des cours de l'année (première période)") + .with_prompt("Début des cours de la période") .default(info::get_start_date(level, args.semester, args.year, &user_agent).await) .interact_text() .unwrap(), @@ -77,7 +86,14 @@ async fn main() { }; println!("Récupération des informations par rapport à l'année..."); - let info = info::info(args.semester, args.year, &date, args.week_skip); + let info = info::info( + args.semester, + args.year, + &date, + args.week_skip, + args.holidays, + args.weeks, + ); if let Some(mut filename) = args.export { // Export the calendar diff --git a/src/utils.rs b/src/utils.rs index 7f9d607..4df3e25 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -176,3 +176,18 @@ pub fn format_time_slot(start: usize, size: usize) -> String { format!("{start_hour:02}h{start_minute:02}-{end_hour:02}h{end_minute:02}") } + +/// Based on the user input and some default values, find the correct repartition of weeks between the break +pub fn get_period_weeks(semester: i32, user_input: Option) -> (i64, i64) { + if let Some(nb_weeks) = user_input { + // When weeks are forced by the user, we simply cut the period in half + let half = nb_weeks / 2; + return (half.into(), (nb_weeks - half).into()); + } + + match semester { + 1 => (6, 7), + 2 => (11, 1), + _ => panic!("Weird semester"), + } +}