lib_vtop 1.0.0

A minimal libre package for VTOP
Documentation
use scraper::{Html, Selector};
use serde;
use serde::Deserialize;
use std::collections::HashMap;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use super::super::types::*;

pub fn parse_timetable(html: String) -> Vec<TimetableSlot> {
    #[derive(serde::Serialize, Deserialize)]
    struct Timeing {
        serial: String,
        start_time: String,
        end_time: String,
    }
    let mut classname_code: HashMap<String, String> = HashMap::new();
    let document = Html::parse_document(&html);
    let rows_selector = Selector::parse("tr").unwrap();
    let mut timetables: Vec<TimetableSlot> = Vec::new();
    let mut timeings_temp: Vec<Timeing> = Vec::new();
    let mut count_for_offset = 0;
    let tabel_selector = Selector::parse("tbody").unwrap();
    let mut table = document.select(&tabel_selector);
    let mut day = "".to_string();

    if let Some(document) = table.next() {
        for row in document.select(&rows_selector) {
            let cells: Vec<_> = row.select(&Selector::parse("td").unwrap()).collect();
            if cells.len() > 8 {
                let cname = cells[2]
                    .text()
                    .collect::<Vec<_>>()
                    .join("")
                    .trim()
                    .replace("\t", "")
                    .replace("\n", "");
                let tep = cname
                    .split("-")
                    .filter(|k| !k.is_empty())
                    .collect::<Vec<_>>();
                if tep.len() > 1 {
                    let code = tep[0].trim().to_string();
                    let name = tep[1]
                        .to_string()
                        .split_once("(")
                        .unwrap_or(("", ""))
                        .0
                        .trim()
                        .to_string();
                    if !classname_code.contains_key(&code) {
                        classname_code.insert(code, name);
                    }
                }
            }
        }
    }

    if let Some(document) = table.next() {
        for row in document.select(&rows_selector) {
            let mut cells: Vec<_> = row.select(&Selector::parse("td").unwrap()).collect();
            if cells.len() > 6 {
                if count_for_offset % 2 == 0 {
                    day = cells[0]
                        .text()
                        .collect::<Vec<_>>()
                        .join("")
                        .trim()
                        .replace("\t", "")
                        .replace("\n", "");
                    cells.remove(0);
                }

                for (index, val) in cells.iter().enumerate() {
                    if count_for_offset < 2 {
                        if count_for_offset == 0 {
                            let timeing = Timeing {
                                serial: index.to_string(),
                                start_time: val
                                    .text()
                                    .collect::<Vec<_>>()
                                    .join("")
                                    .trim()
                                    .replace("\t", "")
                                    .replace("\n", ""),
                                end_time: "".to_string(),
                            };
                            timeings_temp.push(timeing);
                        } else if count_for_offset == 1 {
                            if let Some(timeing) = timeings_temp.get_mut(index) {
                                timeing.end_time = val
                                    .text()
                                    .collect::<Vec<_>>()
                                    .join("")
                                    .trim()
                                    .replace("\t", "")
                                    .replace("\n", "");
                            }
                        }
                    } else if count_for_offset > 3 {
                        let class_name = val
                            .text()
                            .collect::<Vec<_>>()
                            .join("")
                            .trim()
                            .replace("\t", "")
                            .replace("\n", "");
                        if class_name.len() > 5 && index != 0 {
                            let cle = class_name
                                .split("-")
                                .filter(|k| !k.is_empty())
                                .collect::<Vec<_>>();
                            if cle.len() > 2 {
                                let mut cl = class_name.split("-");
                                let code = class_name
                                    .split("-")
                                    .nth(1)
                                    .unwrap_or("")
                                    .trim()
                                    .to_string();
                                let class = TimetableSlot {
                                    serial: index.to_string(),
                                    day: day.clone(),
                                    slot: cl.next().unwrap_or("").trim().to_string(),
                                    course_code: cl.next().unwrap_or("").trim().to_string(),
                                    course_type: cl.next().unwrap_or("").trim().to_string(),
                                    room_no: cl.next().unwrap_or("").trim().to_string(),
                                    block: cl.take(2).collect::<Vec<_>>().join(" "),
                                    start_time: "".to_string(),
                                    end_time: "".to_string(),
                                    name: classname_code
                                        .get(&code)
                                        .unwrap_or(&"".to_string())
                                        .to_string(),
                                };
                                timetables.push(class);
                            }
                        }
                    }
                }
                count_for_offset += 1;
            }
        }
    } else {
        return timetables;
    }
    for timetable in &mut timetables {
        if let Some(times) = timeings_temp.iter().find(|t| t.serial == timetable.serial) {
            timetable.start_time = times.start_time.clone();
            timetable.end_time = times.end_time.clone();
        }
    }

    timetables
}
pub fn parse_semid_timetable(html: String) -> SemesterData {
    let mut sem_names_ids = vec![];
    let document = Html::parse_document(&html);
    let selector = Selector::parse(r#"select[name="semesterSubId"] option"#).unwrap();
    for element in document.select(&selector).skip(1) {
        if let Some(value) = element.value().attr("value") {
            if let Some(name) = element.text().next() {
                sem_names_ids.push(SemesterInfo {
                    id: value.trim().to_string(),
                    name: name.trim().replace("- AMR", "").to_string(),
                });
            }
        }
    }
    SemesterData {
        semesters: sem_names_ids,
        update_time: SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or(Duration::new(1, 0))
            .as_secs(),
    }
}