diff --git a/src/main.rs b/src/main.rs index 0cd853d..cab88fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,176 +1,21 @@ -use scraper::{Html, Selector}; +use scraper::Html; -mod models; +mod timetable; #[tokio::main] async fn main() { - let document = get_webpage(3, 1, None).await.expect("Can't reach website."); - // Selectors - let sel_table = Selector::parse("table").unwrap(); - let sel_tr = Selector::parse("tr").unwrap(); - let sel_tbody = Selector::parse("tbody").unwrap(); - let sel_th = Selector::parse("th").unwrap(); - let sel_td = Selector::parse("td").unwrap(); - let sel_em = Selector::parse("em").unwrap(); - let sel_small = Selector::parse("small").unwrap(); - let sel_strong = Selector::parse("strong").unwrap(); + let _timetable = timetable::timetable(3, 1, None).await; - // Find the timetable - let raw_timetable = document.select(&sel_table).next().unwrap(); - - // Find the slots available for the timetable - let raw_schedules = raw_timetable.select(&sel_tr).next().unwrap(); - - // Find availables schedules - let mut schedules = Vec::new(); - for time in raw_schedules.select(&sel_th) { - schedules.push(time.inner_html()); - } - - // Find the timetable values - let raw_timetable_values = raw_timetable.select(&sel_tbody).next().unwrap(); - - // For each days - let mut timetable = Vec::new(); - for day in raw_timetable_values.select(&sel_tr) { - let mut courses_vec = Vec::new(); - let mut location_tracker = 0; - for course in day.select(&sel_td) { - if course.inner_html() == "—" { - courses_vec.push(None); - location_tracker += 1; - } else { - courses_vec.push(Some(models::Course { - name: course.select(&sel_em).next().unwrap().inner_html(), - professor: match course - .select(&sel_small) - .next() - .unwrap() - .inner_html() - .split("
") - .next() - { - Some(data) => { - if data.contains("") { - // This is the room, so there is no professor assigned - // to this courses yet - None - } else { - Some(data.to_string()) - } - } - None => None, - }, - room: course.select(&sel_strong).next().unwrap().inner_html(), - start: location_tracker, - size: match course.value().attr("colspan") { - Some(i) => i.parse().unwrap(), - None => 1, - }, - })); - - match &courses_vec[courses_vec.len() - 1] { - Some(course) => location_tracker += course.size, - None => location_tracker += 1, - } - } - } - - timetable.push(models::Day { - name: day.select(&sel_th).next().unwrap().inner_html(), - courses: courses_vec, - }) - } - - if !check_timetable_consistency(&schedules, &timetable) { - panic!("Error when building the timetable."); - } + let _document_info = get_webpage_info().await.expect("Can't reach info website."); + // println!("{:#?}", document_info); } -/// Check if the timetable is well built -fn check_timetable_consistency(schedules: &Vec, timetable: &Vec) -> bool { - let mut checker = true; - for day in timetable { - let mut i = 0; - for course in &day.courses { - match course { - Some(course_it) => { - // Checks the consistency of course start times - if i != course_it.start { - checker = false; - break; - } - // Keep the track of how many courses are in the day - i += course_it.size - } - None => i += 1, - } - } - // The counter should be the same as the amount of possible hours of the day - if i != schedules.len() { - checker = false; - break; - } - } +async fn get_webpage_info() -> Result> { + /* let html = reqwest::get("https://informatique.up8.edu/licence-iv/edt").await?.text().await?; - checker -} - -async fn get_webpage( - _year: i8, - _semester: i8, - _letter: Option, -) -> Result> { - /* let url = { - let panic_semester_message = "Unknown semester."; - let panic_letter_message = "Unknown letter."; - - let base_url = "https://informatique.up8.edu/licence-iv/edt"; - match year { - 1 => { - let allow_letters = match semester { - 1 => ['a', 'b', 'c'], - 2 => ['x', 'y', 'z'], - _ => panic!("{}", panic_semester_message), - }; - let c = letter.expect(panic_letter_message); - if allow_letters.contains(&c) { - format!("{}/l1-{}.html", base_url, c) - } else { - panic!("{}", panic_letter_message) - } - } - 2 => { - let allow_letters = match semester { - 1 => ['a', 'b'], - 2 => ['x', 'y'], - _ => panic!("{}", panic_semester_message), - }; - let c = letter.expect(panic_letter_message); - if allow_letters.contains(&c) { - format!("{}/l2-{}.html", base_url, c) - } else { - panic!("{}", panic_letter_message) - } - } - 3 => match semester { - 1 => format!("{}/l3.html", base_url), - 2 => format!("{}/l3_2.html", base_url), - _ => panic!("{}", panic_semester_message), - }, - _ => panic!("Unknown year."), - } - }; - - // Get raw html - let html = reqwest::get(url).await?.text().await?; - - // Parse document - let document = Html::parse_document(&html); */ - - let html = include_str!("../target/debug.html"); - let document = Html::parse_document(html); - - Ok(document) + Ok(Html::parse_document(&html)) */ + + let html = include_str!("../target/debug2.html"); + Ok(Html::parse_document(html)) } diff --git a/src/timetable.rs b/src/timetable.rs new file mode 100644 index 0000000..40d6961 --- /dev/null +++ b/src/timetable.rs @@ -0,0 +1,183 @@ +use scraper::{Selector, Html}; + +mod models; + +pub async fn timetable(year: i8, semester: i8, letter: Option) -> Vec { + let document_timetable = get_webpage(year, semester, letter).await.expect("Can't reach timetable website."); + + // Selectors + let sel_table = Selector::parse("table").unwrap(); + let sel_tr = Selector::parse("tr").unwrap(); + let sel_tbody = Selector::parse("tbody").unwrap(); + let sel_th = Selector::parse("th").unwrap(); + let sel_td = Selector::parse("td").unwrap(); + let sel_em = Selector::parse("em").unwrap(); + let sel_small = Selector::parse("small").unwrap(); + let sel_strong = Selector::parse("strong").unwrap(); + + // Find the timetable + let raw_timetable = document_timetable.select(&sel_table).next().unwrap(); + + // Find the slots available for the timetable + let raw_schedules = raw_timetable.select(&sel_tr).next().unwrap(); + + // Find availables schedules + let mut schedules = Vec::new(); + for time in raw_schedules.select(&sel_th) { + schedules.push(time.inner_html()); + } + + // Find the timetable values + let raw_timetable_values = raw_timetable.select(&sel_tbody).next().unwrap(); + + // For each days + let mut timetable = Vec::new(); + for day in raw_timetable_values.select(&sel_tr) { + let mut courses_vec = Vec::new(); + let mut location_tracker = 0; + for course in day.select(&sel_td) { + if course.inner_html() == "—" { + courses_vec.push(None); + location_tracker += 1; + } else { + courses_vec.push(Some(models::Course { + name: course.select(&sel_em).next().unwrap().inner_html(), + professor: match course + .select(&sel_small) + .next() + .unwrap() + .inner_html() + .split("
") + .next() + { + Some(data) => { + if data.contains("") { + // This is the room, so there is no professor assigned + // to this courses yet + None + } else { + Some(data.to_string()) + } + } + None => None, + }, + room: course + .select(&sel_strong) + .next() + .unwrap() + .inner_html() + .replace("
", ""), + start: location_tracker, + size: match course.value().attr("colspan") { + Some(i) => i.parse().unwrap(), + None => 1, + }, + })); + + match &courses_vec[courses_vec.len() - 1] { + Some(course) => location_tracker += course.size, + None => location_tracker += 1, + } + } + } + + timetable.push(models::Day { + name: day.select(&sel_th).next().unwrap().inner_html(), + courses: courses_vec, + }) + } + + if !check_consistency(&schedules, &timetable) { + panic!("Error when building the timetable."); + } + + timetable +} + +async fn get_webpage( + year: i8, + semester: i8, + letter: Option, +) -> Result> { + /* let url = { + let panic_semester_message = "Unknown semester."; + let panic_letter_message = "Unknown letter."; + + let base_url = "https://informatique.up8.edu/licence-iv/edt"; + match year { + 1 => { + let allow_letters = match semester { + 1 => ['a', 'b', 'c'], + 2 => ['x', 'y', 'z'], + _ => panic!("{}", panic_semester_message), + }; + let c = letter.expect(panic_letter_message); + if allow_letters.contains(&c) { + format!("{}/l1-{}.html", base_url, c) + } else { + panic!("{}", panic_letter_message) + } + } + 2 => { + let allow_letters = match semester { + 1 => ['a', 'b'], + 2 => ['x', 'y'], + _ => panic!("{}", panic_semester_message), + }; + let c = letter.expect(panic_letter_message); + if allow_letters.contains(&c) { + format!("{}/l2-{}.html", base_url, c) + } else { + panic!("{}", panic_letter_message) + } + } + 3 => match semester { + 1 => format!("{}/l3.html", base_url), + 2 => format!("{}/l3_2.html", base_url), + _ => panic!("{}", panic_semester_message), + }, + _ => panic!("Unknown year."), + } + }; + + // Get raw html + let html = reqwest::get(url).await?.text().await?; + + // Parse document + let document = Html::parse_document(&html); */ + + println!("Fetch 'L{}{} (s{})'", year, letter.unwrap_or(' '), semester); + let html = include_str!("../target/debug.html"); + let document = Html::parse_document(html); + + Ok(document) +} + +/// Check if the timetable is well built +fn check_consistency(schedules: &Vec, timetable: &Vec) -> bool { + let mut checker = true; + for day in timetable { + let mut i = 0; + for course in &day.courses { + match course { + Some(course_it) => { + // Checks the consistency of course start times + if i != course_it.start { + checker = false; + break; + } + // Keep the track of how many courses are in the day + i += course_it.size + } + None => i += 1, + } + } + // The counter should be the same as the amount of possible hours of the day + if i != schedules.len() { + checker = false; + break; + } + } + + checker +} diff --git a/src/models.rs b/src/timetable/models.rs similarity index 100% rename from src/models.rs rename to src/timetable/models.rs