""" Functions related to this week's schedule. """ from solenlib import networking as nw from solenlib import crypto as cr from bs4 import BeautifulSoup import os not_login = 0 def fetch_locally(password, username) -> list: """ Helper function for extracting data from a local file. """ global not_login if not_login == 1: not_login = 0 schedule = schedule_from_file(password, username) return schedule def sort_schedule(schedule: list[dict]) -> list[dict]: """ Helper function for sorting the schedule correctly. """ sorted_schedule: list[dict] = [{}, {}, {}, {}, {}] for i in range(len(schedule)): if schedule[i]["DAY"] == "Po": sorted_schedule[0] = schedule[i] if schedule[i]["DAY"] == "Út": sorted_schedule[1] = schedule[i] if schedule[i]["DAY"] == "St": sorted_schedule[2] = schedule[i] if schedule[i]["DAY"] == "Čt": sorted_schedule[3] = schedule[i] if schedule[i]["DAY"] == "Pá": sorted_schedule[4] = schedule[i] return sorted_schedule def get_schedule(password, url: str) -> list: """ Filters & extracts the schedule from the HTML soup. """ try: html = nw.get_html_from(url) soup = BeautifulSoup(html.text, "lxml") table = soup.find("table", id="CCADynamicCalendarTable") rows_odd = table.find_all("tr", class_="RowOdd") rows_even = table.find_all("tr", class_="RowEven") rows = rows_odd + rows_even schedule = [] for i in range(len(rows)): if rows[i].find("td", class_="KuvSuplovanaHodina") is not None and rows[i].find("td", class_="KuvSuplujiciHodina") is None and rows[i].find("td", class_="KuvSkolniAkceHodina") is None and rows[i].find("td", class_="DctInnerTableType10DataTD") is None: continue subjects = [] wheres = [] cells = rows[i].find_all("td", attrs={"class": "DctCell"}) header_ = table.find("tr").find_all("td", class_="KuvHeaderNadpis") header = [] for val in header_: header.append(val.text) for j in range(len(cells)): if cells[j].text == "" and header[j] != " - ": new_span = soup.new_tag("span", attrs={'class': 'KuvBunkaRozvrhNadpis'}) new_span.string = "Volno" cells[j].append(new_span) if rows[i].find("td", class_="KuvHeaderNadpis") is not None: day = rows[i].find("td", class_="KuvHeaderNadpis").text date = rows[i].find("td", class_="KuvHeaderText").text subjects_ = rows[i].find_all("span", class_="KuvBunkaRozvrhNadpis") temp = [] for j in range(len(subjects_)): if "KuvSuplovanaHodina" not in subjects_[j].parent["class"]: temp.append(subjects_[j].text) else: temp.append("Volno") subjects = temp F_continue = False try: while subjects[-1] == "Volno": del subjects[-1] if subjects == []: F_continue = True except IndexError: pass if subjects == []: F_continue = True wheres_ = rows[i].find_all("span", class_="KuvBunkaRozvrhText") temp = [] for j in range(len(wheres_)): try: if len(subjects[j]) < 10: if len(wheres_[j].text[4:]) > 10: temp.append(" - ") elif "KuvSuplovanaHodina" not in wheres_[j].parent["class"]: temp.append(wheres_[j].text[4:]) else: temp.append(" - ") except IndexError: pass wheres = temp for j in range(len(cells)): if cells[j].get("colspan") is not None: if int(cells[j].get("colspan")) == 2: try: subjects.insert(j, subjects[j]) wheres.insert(j, wheres[j]) except IndexError: pass for j in range(len(subjects)): if subjects[j] == "Volno": wheres.insert(j, " - ") while True: if len(subjects) > len(wheres): del subjects[-1] elif len(subjects) < len(wheres): del wheres[-1] else: break if F_continue == False: schedule_row = { "DAY": day, "DATE": date, "SUBJECTS": subjects, "WHERES": wheres } schedule.append(schedule_row) sorted_schedule = sort_schedule(schedule) return sorted_schedule except AttributeError: global not_login not_login = 1 schedule = fetch_locally() return schedule def schedule_from_file_to_list(password, username, strdata): """ Extracts the schedule from a local file and returns it in a list, which is better for the get_whitespace() function. """ schedule = [] schedule_ = [] import csv from io import StringIO f = StringIO(strdata) reader = csv.reader(f, delimiter=",") for row in reader: temp = [] for col in row: temp.append(col.strip()) schedule_.append(temp) for i in range(0, len(schedule_), 2): del schedule_[i][0] temp = [] for i in range(1, len(schedule_), 2): temp.append(schedule_[i][0]) del schedule_[i][0] schedule.append(temp) for i in range(10): temp = [] for j in range(10): try: temp.append(schedule_[j][0]) del schedule_[j][0] except IndexError: pass schedule.append(temp) return schedule def get_whitespace(password, username, strdata, key: str, idx=0) -> int: """ Helper function that calculates how much whitespaces are needed in order to display the table grid correctly. """ schedule = schedule_from_file_to_list(password, username, strdata) max_len = 0 if key == "DATE": try: max_len = len(max(schedule[0], key=len)) except ValueError: pass elif key == "WHERES": try: max_len = len(max(schedule[idx], key=len)) except ValueError: pass return max_len def show_schedule(password, username, local=False): """ Shows the schedule on the terminal in a pretty way. """ try: strdata = cr.read_from_file_and_decrypt(password, f"{os.environ['HOME']}/.local/lib/solendata/{nw.get_user_hash(username)}-schedule_week") except: print("Could not read the file") return if local == False: # if there is internet access, load stuff from the web # if not, load the schedule.csv file if nw.is_connected() == True: schedule = get_schedule(password, "/SOL/App/Kalendar/KZK001_KalendarTyden.aspx") schedule_to_file(password, username, schedule) else: schedule = schedule_from_file(password, username) else: schedule = schedule_from_file(password, username) print("") print("----------------") print(" Týdenní rozvrh ") print("----------------\n") if schedule == []: print("N/A\n") return for i in range(len(schedule)): max_len = get_whitespace(password, username, strdata, "DATE") whitespace = " " * (max_len - len(schedule[i]["DAY"])) print(schedule[i]["DAY"] + whitespace, end=" ") for j in range(len(schedule[i]["SUBJECTS"])): max_len = get_whitespace(password, username, strdata, "WHERES", j+1) whitespace = " " * (max_len - len(schedule[i]["SUBJECTS"][j])) print("| " + schedule[i]["SUBJECTS"][j] + whitespace, end=" ") print("") max_len = get_whitespace(password, username, strdata, "DATE") whitespace = " " * (max_len - len(schedule[i]["DATE"])) print(schedule[i]["DATE"] + whitespace, end=" ") for j in range(len(schedule[i]["WHERES"])): max_len = get_whitespace(password, username, strdata, "WHERES", j+1) whitespace = " " * (max_len - len(schedule[i]["WHERES"][j])) print("| " + schedule[i]["WHERES"][j] + whitespace, end=" ") print("") def schedule_to_file(password, username, schedule=None): """ Writes the schedule to a local file for later use. """ if schedule is None: try: schedule = get_schedule(password, "/SOL/App/Kalendar/KZK001_KalendarTyden.aspx") except: print("An error occured, you probably can't access the internet right now") return lstrdata = [] for row in schedule: lstrdata.append(row["DAY"]) lstrdata.append(",") for i in row["SUBJECTS"]: lstrdata.append(i) lstrdata.append(",") del lstrdata[-1] lstrdata.append("\n") lstrdata.append(row["DATE"]) for i in row["WHERES"]: lstrdata.append(i) lstrdata.append(",") del lstrdata[-1] lstrdata.append("\n") strdata = "".join(lstrdata) cr.encrypt_and_write_to_file(password, strdata, f"{os.environ['HOME']}/.local/lib/solendata/{nw.get_user_hash(username)}-schedule_week") def schedule_from_file(password, username) -> list: """ Fetches schedule data from a file. """ import csv from io import StringIO schedule = [] try: strdata = cr.read_from_file_and_decrypt(password, f"{os.environ['HOME']}/.local/lib/solendata/{nw.get_user_hash(username)}-schedule_week") except: print("Could not read the file") return f = StringIO(strdata) reader = csv.reader(f) rows = [] for row in reader: rows.append(row) for row in range(0, len(rows), 2): temp = {} temp["DAY"] = rows[row][0] try: temp["DATE"] = rows[row+1][0] except IndexError: pass subjects = [] for i in range(1, len(rows[row])): subjects.append(rows[row][i]) temp["SUBJECTS"] = subjects wheres = [] try: for i in range(1, len(rows[row+1])): wheres.append(rows[row+1][i]) except IndexError: pass temp["WHERES"] = wheres schedule.append(temp) return schedule