diff --git a/pc_linux/.config/launch.sh b/pc_linux/.config/launch.sh deleted file mode 100755 index 48543b5..0000000 --- a/pc_linux/.config/launch.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if command -v solen > /dev/null -then - solen -else - python3 "./src/main.py" -fi diff --git a/pc_linux/.config/mkdirs.sh b/pc_linux/.config/mkdirs.sh deleted file mode 100755 index ad5dbd4..0000000 --- a/pc_linux/.config/mkdirs.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -if [ ! -d "$HOME/.local/lib/python3.11/site-packages/solenlib" ]; then - sudo mkdir --parents "$HOME/.local/lib/python3.11/site-packages/solenlib" -fi - -if [ ! -d "$HOME/.local/lib/solendata" ]; then - sudo mkdir --parents "$HOME/.local/lib/solendata" -fi diff --git a/pc_linux/Makefile b/pc_linux/Makefile deleted file mode 100755 index 33bb75a..0000000 --- a/pc_linux/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -SHELL=/bin/bash - -install: - python -m pip install -r requirements.txt - - ./.config/mkdirs.sh - - sudo cp ./src/main.py /bin/solen - sudo chown $(USER) /bin/solen - - sudo cp ./src/lib/*.py $(HOME)/.local/lib/python3.10/site-packages/solenlib - -run: - ./.config/launch.sh diff --git a/pc_linux/requirements.txt b/pc_linux/requirements.txt deleted file mode 100755 index ccff3a7..0000000 --- a/pc_linux/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -lxml -bs4 -requests -cryptography diff --git a/pc_linux/src/lib/__init__.py b/pc_linux/src/lib/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/pc_linux/src/lib/crypto.py b/pc_linux/src/lib/crypto.py deleted file mode 100755 index d157718..0000000 --- a/pc_linux/src/lib/crypto.py +++ /dev/null @@ -1,85 +0,0 @@ -""" - Cryptography related stuff - mostly - encrypting and decrypting user data. -""" - -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -from cryptography.fernet import Fernet -import base64 -import os - -def get_key(password: str) -> bytes: - """ - Derives a bytes key - from a given password. - - Useful when you want - to generate the same - key over and over again. - E.g. to encrypt/decrypt - locally stored user data. - """ - - password = password.encode() - - salt = b'?\x0f\xa1\x97otT\xe48\xc9O\xb4\x1f\xef\xf5\xea' - - kdf = PBKDF2HMAC( - algorithm=hashes.SHA256, - length=32, - salt=salt, - iterations=100000, - backend=default_backend() - ) - - key = base64.urlsafe_b64encode(kdf.derive(password)) - return key - -def encrypt_and_write_to_file(password: str, strdata: str, file_path: str) -> bool: - """ - Encrypts the given string data - and stores them in a file. - """ - - try: - key = get_key(password) - - f = Fernet(key) - - encrypted = f.encrypt(strdata.encode()) - if os.path.exists(file_path): - with open(file_path, "wb") as ef: - ef.write(encrypted) - else: - os.system(f"touch {file_path}") - with open(file_path, "wb") as ef: - ef.write(encrypted) - - return 0 - except: - return 1 - -def read_from_file_and_decrypt(password: str, file_path: str) -> str: - """ - Reads contents of an encrypted file - and decrypts them. - """ - - try: - key = get_key(password) - - f = Fernet(key) - - if os.path.exists(file_path): - with open(file_path, "rb") as ef: - decrypted = f.decrypt(ef.read()) - else: - os.system(f"touch {file_path}") - with open(file_path, "rb") as ef: - decrypted = f.decrypt(ef.read()) - - return decrypted.decode() - except: - return "" diff --git a/pc_linux/src/lib/grades.py b/pc_linux/src/lib/grades.py deleted file mode 100755 index b634a7e..0000000 --- a/pc_linux/src/lib/grades.py +++ /dev/null @@ -1,203 +0,0 @@ -""" - Functions for grades related stuff. - Like 1, 2, 3, 4 and 5, in what subject, - what is the average of a subject, ... -""" - -from solenlib import networking as nw -from solenlib import crypto as cr -from cryptography.fernet import Fernet -from bs4 import BeautifulSoup -import os - -not_login = 0 - -def fetch_locally(password, username) -> list: - """ - Helper function for exctracting - data from local files. - """ - - global not_login - - if not_login == 1: - not_login = 0 - #print("Could not sign in (you may have entered invalid login credentials)") - #print("Fetching grades locally\n") - grades = grades_from_file(password, username) - return grades - -def get_grades(password, url: str) -> list: - """ - Extracts the grades from the HTML soup - and returns them in a list of dictionaries. - """ - - try: - html = nw.get_html_from(url) - - soup = BeautifulSoup(html.text, "lxml") - - rows = soup.find("table", id="G_ctl00xmainxCCADynamicUWGrid").find_all("tr") - for i in range(3): - r = soup.find("table", id="G_ctl00xmainxCCADynamicUWGrid").find("tr") - r.decompose() - - grades = [] - - for i in range(1, len(rows)): - if rows[i].find("td") is not None: - subject = rows[i].find("td").text - temp_dict = {} - temp_dict["SUBJECT"] = subject - cells = rows[i].find_all("span", class_="VHVysl") - temp = [] - for j in range(len(cells)): - if cells[j].parent.has_attr("class"): - if "VHUzaverka" not in cells[j].parent["class"]: - temp.append(cells[j].text) - else: - temp.append(cells[j].text) - temp_dict["FINAL"] = rows[i].find("td", class_="VHUzaverka CCATooltip").text.replace(" ", "") - - avg = rows[i].find("td", class_="VHCelkPrumer").text.replace(",", ".") - temp_dict["AVG"] = avg - - temp_dict["GRADES"] = temp - - grades.append(temp_dict) - - return grades - except AttributeError: - global not_login - - not_login = 1 - grades = fetch_locally(password, username) - return grades - -def show_grades(password, username, local=False): - """ - Shows the grades in the terminal - in a pretty way. - """ - - if local == False: - if nw.is_connected() == True: - grades = get_grades(password, "/SOL/App/Hodnoceni/KZH001_HodnVypisStud.aspx") - grades_to_file(password, username, grades) - else: - grades = grades_from_file(password, username) - else: - grades = grades_from_file(password, username) - - whitespace = "" - max_len_of_subject = 0 - subjects = [grades[j]["SUBJECT"] for j in range(len(grades))] - for i in subjects: - if len(i) > max_len_of_subject: - max_len_of_subject = len(i) - max_len_of_subject += 1 - - print("") - - print("--------") - print(" Známky ") - print("--------\n") - - if grades == []: - print("N/A\n") - - return - - for i in range(len(grades)): - if grades[i]["GRADES"] != []: - whitespace = " " * (max_len_of_subject - len(grades[i]["SUBJECT"])) - print(grades[i]["SUBJECT"] + whitespace + "|", end=" ") - print(grades[i]["FINAL"], "|", end=" ") - print(grades[i]["AVG"], "|", end=" ") - print("".join([grades[i]["GRADES"][j]+" " for j in range(len(grades[i]["GRADES"]))])) - else: - if grades[i]["FINAL"] is not None: - whitespace = " " * (max_len_of_subject - len(grades[i]["SUBJECT"])) - print(grades[i]["SUBJECT"] + whitespace + "|", end=" ") - print(grades[i]["FINAL"], "|") - -def grades_to_file(password, username, grades=None): - """ - Writes the grades to a local file - for later use and extraction. - """ - - if grades is None: - try: - grades = get_grades(password, username, "/SOL/App/Hodnoceni/KZH001_HodnVypisStud.aspx") - except Exception: - print("An error occured, you probably can't access the internet right now") - return - - data = [] - lstrdata = [] - - for i in range(len(grades)): - temp = {} - temp["SUBJECT"] = grades[i]["SUBJECT"] - temp["FINAL"] = grades[i]["FINAL"] - temp["AVG"] = grades[i]["AVG"] - temp_grades = [] - for j in range(len(grades[i]["GRADES"])): - temp_grades.append(grades[i]["GRADES"][j]) - temp["GRADES"] = temp_grades - data.append(temp) - - for row in data: - lstrdata.append(row["SUBJECT"]) - lstrdata.append(",") - lstrdata.append(row["FINAL"]) - lstrdata.append(",") - lstrdata.append(row["AVG"]) - lstrdata.append(",") - for i in row["GRADES"]: - 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)}-grades") - -def grades_from_file(password, username) -> list: - """ - Extracts the grades from the local - file and returns them in a better - format. - """ - import csv - from io import StringIO - try: - strdata = cr.read_from_file_and_decrypt(password, f"{os.environ['HOME']}/.local/lib/solendata/{nw.get_user_hash(username)}-grades") - except: - print("Could not read the file") - return - f = StringIO(strdata) - reader = csv.reader(f, delimiter=",") - grades = [] - rows = [] - for row in reader: - rows.append(row) - - for row in range(len(rows)): - temp = {} - - temp["SUBJECT"] = rows[row][0] - temp["FINAL"] = rows[row][1] - temp["AVG"] = rows[row][2] - - temp_lst = [] - for i in range(3, len(rows[row])): - temp_lst.append(rows[row][i]) - temp["GRADES"] = temp_lst - - grades.append(temp) - - return grades diff --git a/pc_linux/src/lib/networking.py b/pc_linux/src/lib/networking.py deleted file mode 100755 index 92042b4..0000000 --- a/pc_linux/src/lib/networking.py +++ /dev/null @@ -1,146 +0,0 @@ -""" - Functions for network related stuff. -""" - -import requests -import hashlib -from bs4 import BeautifulSoup -import os - -not_login = 0 -F_not_anymore = 0 -session = requests.Session() - -def _read_shadow() -> str: - """ - Reads the shadow file and returns it in - a suitable format for other functions. - """ - - result = "" - try: - with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "r") as f: - for row in f: - result += row+";" - except FileNotFoundError: - os.system(f"touch {os.environ['HOME']}/.local/lib/solendata/shadow") - with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "r") as f: - for row in f: - result += row+";" - - return result - -def _save_creds(user: str, pwd: str): - """ - Saves credentials into the shadow file - by appending them. - """ - - creds = ";" + _get_creds_hash(user, pwd) - - try: - with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "a+") as f: - if not creds in _read_shadow(): - f.write(creds) - except FileNotFoundError: - os.system(f"touch {os.environ['HOME']}/.local/lib/solendata/shadow") - with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "a+") as f: - if not creds in _read_shadow(): - f.write(creds) - -def _eval_creds(creds: str) -> bool: - """ - Evaluates the credentials for if - they are in the shadow file or not. - """ - - shadow = _read_shadow() - - if creds in shadow: - return True - else: - return False - -def _get_creds_hash(user: str, pwd: str) -> str: - """ - Creates a sha512 hash from the username - and password. - """ - - user_hash = hashlib.sha512(bytes(user, 'utf-8')).hexdigest() - pwd_hash = hashlib.sha512(bytes(pwd, 'utf-8')).hexdigest() - creds = user_hash+":"+pwd_hash - - return creds - -def get_user_hash(user: str) -> str: - return str(hashlib.sha512(bytes(user, 'utf-8')).hexdigest()) - -def login(user: str, pwd: str) -> bool: - """ - Tries to send a request to the SOL - servers in order to log in. - """ - - if is_connected(): - url: str = "https://aplikace.skolaonline.cz/SOL/Prihlaseni.aspx" - data = { - "__EVENTTARGET": "dnn$ctr994$SOLLogin$btnODeslat", - "__EVENTARGUMENT": "", - "__VIEWSTATE": "", - "__VIEWSTATEGENERATOR": "", - "__VIEWSTATEENCRYPTED": "", - "__PREVIOUSPAGE": "", - "__EVENTVALIDATION": "", - "dnn$dnnSearch$txtSearch": "", - "JmenoUzivatele": user, # username - "HesloUzivatele": pwd, # password - "ScrollTop": "", - "__dnnVariable": "", - "__RequestVerificationToken": "" - } - - post_login = session.post(url, data=data) - if post_login.status_code != 200: - return False - else: - return True - else: - if _eval_creds(_get_creds_hash(user, pwd)): - return True - else: - return False - -def is_connected() -> bool: - """ - Checks whether there is internet - access present. - """ - - import socket - - try: - host = socket.gethostbyname("one.one.one.one") - s = socket.create_connection((host, 80), 2) - s.close() - return True - except: - pass - return False - -def get_html_from(params=None) -> str: - """ - Fetches the HTML markup of - a specified subsite of SOL. - """ - - base = "https://aplikace.skolaonline.cz" - - if params is not None: - base += params - - response = session.get(base) - if response.status_code == 200: - return response - else: - return "" diff --git a/pc_linux/src/lib/schedule_tdy_tmr.py b/pc_linux/src/lib/schedule_tdy_tmr.py deleted file mode 100755 index e99163c..0000000 --- a/pc_linux/src/lib/schedule_tdy_tmr.py +++ /dev/null @@ -1,345 +0,0 @@ -""" - Functions related to today's - and tomorrow'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 exctracting - data from a local file. - """ - - global not_login - - if not_login == 1: - not_login = 0 - - schedule = schedule_from_file(password, username) - return 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="ctl00_main_boxKalendar_ctl00_ctl04") - - 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_)): - 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(" - ") - 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) - - return schedule - except AttributeError: - global not_login - - not_login = 1 - return fetch_locally(password, username) - -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_tdy_tmr") - 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/Spolecne/KZZ010_RychlyPrehled.aspx") - schedule_to_file(password, username, schedule) - else: - schedule = schedule_from_file(password, username) - else: - schedule = schedule_from_file(password, username) - - print("") - - print("--------------------------") - print(" Dnešní a zítřejší 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/Spolecne/KZZ010_RychlyPrehled.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_tdy_tmr") - -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_tdy_tmr") - except: - print("Could not read the file") - return - f = StringIO(strdata) - reader = csv.reader(f, delimiter=",") - 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 diff --git a/pc_linux/src/lib/schedule_week.py b/pc_linux/src/lib/schedule_week.py deleted file mode 100755 index 1aee963..0000000 --- a/pc_linux/src/lib/schedule_week.py +++ /dev/null @@ -1,376 +0,0 @@ -""" - 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 - - print(max_len) - 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"]) - lstrdata.append(",") - 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) - print(schedule) - return schedule diff --git a/pc_linux/src/main.py b/pc_linux/src/main.py deleted file mode 100755 index f2361ad..0000000 --- a/pc_linux/src/main.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/python3 - -from solenlib import grades as gr -from solenlib import networking as nw -from solenlib import schedule_week as sw -from solenlib import schedule_tdy_tmr as st -import sys -import getpass -import argparse -import os -from datetime import datetime - -if __name__ == "__main__": - parser = argparse.ArgumentParser(prog="solen", description="solen, an enhanced version of the ŠkolaOnLine online school system") - - parser.add_argument("-t", "--today-tomorrow", action="store_true", help="show the schedule for today and tomorrow") - parser.add_argument("-w", "--week", action="store_true", help="show the schedule for this week") - parser.add_argument("-g", "--grades", action="store_true", help="show the grades") - parser.add_argument("-u", "--username", action="store", default="", help="provide the username for login") - parser.add_argument("-p", "--password", action="store", default="", help="provide the password for login") - parser.add_argument("-l", "--local", action="store_true", help="only fetch local files, don't connect to the internet") - parser.add_argument("-d", "--delete-local-files", action="store_true", help="delete all local user data, including schedules, grades and user credentials") - - parser.add_argument("-b", "--backup", action="store_true", help="back up all user data and store them in a .tar.gz archive") - parser.add_argument("-R", "--backup-restore", action="store", nargs=1, metavar="PATH", help="specify the path to a .tar.gz archive that was previously created with Solen") - - args = parser.parse_args() - - if args.delete_local_files: - try: - print("Removing all schedules and grades ...", end=" ") - os.system(f"rm -rf {os.environ['HOME']}/.local/lib/solendata/*") - print("done") - print("Removing all user credentials ...", end=" ") - os.system(f"rm -rf {os.environ['HOME']}/.local/lib/solendata/shadow") - print("done") - print("All user data removed successfully") - except: - print("Could not remove user data") - - elif args.backup: - try: - nowtime = str(datetime.now().strftime("%Y-%m-%d_%H-%M-%S")) - try: - print("Creating the backup archive ...", end=" ") - os.system(f"tar cf solen-backup-{nowtime}.tar {os.getcwd()}") - print("done") - print("Compressing the archive ...", end=" ") - os.system(f"gzip {os.getcwd()}/solen-backup-{nowtime}.tar") - print("done") - print("Backup archive created successfully") - except: - print("The 'tar' utility or the 'gzip' utility is not installed") - except: - print("Could not backup user data") - elif args.backup_restore: - try: - backup_path = args.backup_restore - print("Preparing ...", end=" ") - os.system(f"mkdir {os.getcwd()}/.solentmp") - print("done") - print("Uncompressing the archive ...", end=" ") - os.system(f"gunzip {backup_path}") - print("done") - print("Unpacking the archive ...", end=" ") - os.system(f"tar xzjf {backup_path} {os.getcwd()}/.solentmp") - print("done") - print("Moving the files ...", end=" ") - os.system(f"mv {os.getcwd()}/.solentmp/* {os.environ['HOME']}/.local/lib/solendata") - print("done") - print("Cleaning up ...", end=" ") - os.system(f"rm -rf {os.getcwd()}/.solentmp") - print("done") - print("Backup restored successfully") - except: - print("Could not restore the backup") - else: - if args.username: - user = str(args.username) - else: - user = str(input("Zadejte přihlašovací jméno: ")) - - if args.password: - pwd = str(args.password) - else: - try: - pwd = str(getpass.getpass("Zadejte heslo: ")) - except: - pwd = str(input("Zadejte heslo: ")) - - if not nw.login(user, pwd): - print("Login unsuccessful") - sys.exit(1) - else: - try: - if args.week: - if args.local: - sw.show_schedule(pwd, user, local=True) - else: - sw.show_schedule(pwd, user) - if args.today_tomorrow: - if args.local: - st.show_schedule(pwd, user, local=True) - else: - st.show_schedule(pwd, user) - if args.grades: - if args.local: - gr.show_grades(pwd, user, local=True) - else: - gr.show_grades(pwd, user) - - if not args.grades and not args.today_tomorrow and not args.week: - if args.local: - sw.show_schedule(pwd, user, local=True) - st.show_schedule(pwd, user, local=True) - gr.show_grades(pwd, user, local=True) - else: - sw.show_schedule(pwd, user) - st.show_schedule(pwd, user) - gr.show_grades(pwd, user) - except: - print("Could not execute")