Mon Jun 12 10:35:01 CEST 2023

This commit is contained in:
mnjx
2023-06-12 11:01:43 +02:00
parent f7c2b541b5
commit 66297ecc0c
11 changed files with 211 additions and 150 deletions
+4
View File
@@ -1 +1,5 @@
*.pyc *.pyc
src/lib/data/*.csv
src/lib/shadow
TODO.md
Regular → Executable
View File
Regular → Executable
+13 -2
View File
@@ -1,5 +1,16 @@
SHELL=/bin/bash
install: install:
pip install -r requirements.txt python3 -m pip install -r requirements.txt
./.config/mkdirs.sh
cp ./src/main.py /bin/solen
chmod 774 /bin/solen
cp ./src/lib/*.py $(HOME)/.local/lib/python3.11/site-packages/solenlib
cp ./src/lib/shadow $(HOME)/.local/lib/solendata
cp ./src/lib/data/*.csv $(HOME)/.local/lib/solendata
run: run:
python3 "src/main.py" ./.config/launch.sh
Regular → Executable
+19 -8
View File
@@ -15,20 +15,31 @@ Insiration was taken from [@JakubAndrysek](https://github.com/JakubAndrysek)'s [
+ Shows all grades and their arithmetic average (not accounting for weight) + Shows all grades and their arithmetic average (not accounting for weight)
+ Works offline (when the internet has been accessed at least once before) + Works offline (when the internet has been accessed at least once before)
# Usage # Installation
Clone the repo **Clone the repo**
`git clone git@github.com:mnjx/sol-enhanced.git` `git clone https://github.com/mnjx/sol-enhanced.git`
Navigate into the repo directory **Navigate into the repo directory**
`cd sol-enhanced` `cd sol-enhanced`
Install the requirements (required to run only once) **Install** *(superuser privileges required)*
`make install` `sudo make install`
Run the program **Run the program**
`make run` From the repo folder: `make run`
From anywhere on the computer: `solen`
# Usage
Upon startup, the user os prompted to enter their ŠkolaOnLine credentials.
If the login proccess is successfull, the preconfigured functions in `/bin/solen`
will execute. By default, the functions are: showing the schedule for this week,
showing the schedule for today and tomorrow and showing the grades. You can edit
that file if you want to change what is being displayed. Alternatively, you can
edit the `src/main.py` and then do the install step (`sudo make install`).
An option for command-line arguments will be added in the future.
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
+7 -6
View File
@@ -1,5 +1,6 @@
from lib import networking as nw from solenlib import networking as nw
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import os
not_login = 0 not_login = 0
@@ -88,8 +89,8 @@ def show_grades():
print("N/A\n") print("N/A\n")
import os import os
if os.path.exists("src/lib/data/grades.csv"): if os.path.exists(f"{os.environ['HOME']}/.local/lib/solendata/grades.csv"):
os.remove("src/lib/data/grades.csv") os.remove(f"{os.environ['HOME']}/.local/lib/solendata/grades.csv")
return return
for i in range(len(grades)): for i in range(len(grades)):
@@ -111,7 +112,7 @@ def grades_to_file(grades=None): # !!! make sure the format of the grades list i
data = [] data = []
with open("src/lib/data/grades.csv", mode="w", newline="") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/grades.csv", mode="w", newline="") as f:
for i in range(len(grades)): for i in range(len(grades)):
temp = {} temp = {}
temp["SUBJECT"] = grades[i]["SUBJECT"] temp["SUBJECT"] = grades[i]["SUBJECT"]
@@ -134,7 +135,7 @@ def grades_from_file() -> list:
grades = [] grades = []
try: try:
with open("src/lib/data/grades.csv", mode="r") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/grades.csv", mode="r") as f:
reader = csv.reader(f) reader = csv.reader(f)
rows = [] rows = []
for row in reader: for row in reader:
@@ -154,4 +155,4 @@ def grades_from_file() -> list:
except FileNotFoundError: except FileNotFoundError:
print("No grades.csv file found\n") print("No grades.csv file found\n")
return grades return grades
Regular → Executable
+87 -48
View File
@@ -1,63 +1,102 @@
import requests import requests
import hashlib
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import os
not_login = 0 not_login = 0
F_not_anymore = 0 F_not_anymore = 0
session = requests.Session() session = requests.Session()
def login(user: str, pwd: str) -> bool: def _read_shadow() -> str:
if is_connected() == True: result = ""
url: str = "https://aplikace.skolaonline.cz/SOL/Prihlaseni.aspx" with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "r") as f:
data = { for row in f:
"__EVENTTARGET": "dnn$ctr994$SOLLogin$btnODeslat", result += row+";"
"__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) return result
if post_login.status_code != 200:
#print("Could not sign in") def _save_creds(user: str, pwd: str):
return False creds = _get_creds_hash(user, pwd)
else:
#print("Sign in successful") try:
return True with open(f"{os.environ['HOME']}/.local/lib/solendata/shadow", "a+") as f:
else: if not creds in _read_shadow():
#print("Could not sign in") f.write(creds)
#print("Fetching data from local files") except FileNotFoundError:
return False print("No shadow file found")
def _eval_creds(creds: str) -> bool:
shadow = _read_shadow()
if creds in shadow:
return True
else:
return False
def _get_creds_hash(user: str, pwd: str) -> str:
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 login(user: str, pwd: str) -> bool:
if is_connected() == True:
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:
#print("Could not sign in")
return False
else:
#print("Sign in successful")
return True
else:
#print("Could not sign in")
#print("Fetching data from local files")
if _eval_creds(_get_creds_hash(user, pwd)):
return True
else:
return False
def is_connected() -> bool: def is_connected() -> bool:
import socket import socket
try: try:
host = socket.gethostbyname("one.one.one.one") host = socket.gethostbyname("one.one.one.one")
s = socket.create_connection((host, 80), 2) s = socket.create_connection((host, 80), 2)
s.close() s.close()
return True return True
except Exception: except Exception:
pass pass
return False return False
def get_html_from(params=None) -> str: def get_html_from(params=None) -> str:
base = "https://aplikace.skolaonline.cz" base = "https://aplikace.skolaonline.cz"
if params is not None: if params is not None:
base += params base += params
response = session.get(base) response = session.get(base)
if response.status_code == 200: if response.status_code == 200:
#print("Download successful") #print("Download successful")
return response return response
else: else:
print("Download unsuccessful") print("Download unsuccessful")
return "" return ""
Regular → Executable
+24 -23
View File
@@ -1,5 +1,6 @@
from lib import networking as nw from solenlib import networking as nw
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import os
not_login = 0 not_login = 0
@@ -10,10 +11,10 @@ def fetch_locally() -> list:
not_login = 0 not_login = 0
#print("Could not sign in (you may have entered invalid login credentials)") #print("Could not sign in (you may have entered invalid login credentials)")
#print("Fetching the schedule for this week locally\n") #print("Fetching the schedule for this week locally\n")
schedule_tdy_tmr = schedule_tdy_tmr_from_file() schedule = schedule_from_file()
return schedule_tdy_tmr return schedule
def get_schedule_tdy_tmr(url: str): def get_schedule(url: str):
try: try:
html = nw.get_html_from(url) html = nw.get_html_from(url)
@@ -25,7 +26,7 @@ def get_schedule_tdy_tmr(url: str):
rows_even = table.find_all("tr", class_="RowEven") rows_even = table.find_all("tr", class_="RowEven")
rows = rows_odd + rows_even rows = rows_odd + rows_even
schedule_tdy_tmr = [] schedule = []
for i in range(len(rows)): 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: 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:
@@ -105,16 +106,16 @@ def get_schedule_tdy_tmr(url: str):
break break
if F_continue == False: if F_continue == False:
schedule_tdy_tmr_row = { schedule_row = {
"DAY": day, "DAY": day,
"DATE": date, "DATE": date,
"SUBJECTS": subjects, "SUBJECTS": subjects,
"WHERES": wheres "WHERES": wheres
} }
schedule_tdy_tmr.append(schedule_tdy_tmr_row) schedule.append(schedule_row)
return schedule_tdy_tmr return schedule
except AttributeError: except AttributeError:
global not_login global not_login
@@ -122,12 +123,12 @@ def get_schedule_tdy_tmr(url: str):
schedule = fetch_locally() schedule = fetch_locally()
return schedule return schedule
def schedule_tdy_tmr_from_file_to_list(): def schedule_from_file_to_list():
schedule = [] schedule = []
schedule_ = [] schedule_ = []
try: try:
with open("src/lib/data/schedule_tdy_tmr.csv") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_tdy_tmr.csv") as f:
import csv import csv
reader = csv.reader(f) reader = csv.reader(f)
for row in reader: for row in reader:
@@ -160,7 +161,7 @@ def schedule_tdy_tmr_from_file_to_list():
return schedule return schedule
def get_whitespace(key: str, idx=0) -> int: def get_whitespace(key: str, idx=0) -> int:
schedule = schedule_tdy_tmr_from_file_to_list() schedule = schedule_from_file_to_list()
max_len = 0 max_len = 0
if key == "DATE": if key == "DATE":
@@ -176,27 +177,27 @@ def get_whitespace(key: str, idx=0) -> int:
return max_len return max_len
def show_schedule_tdy_tmr(): def show_schedule():
# if there is internet access, load stuff from the web # if there is internet access, load stuff from the web
# if not, load the schedule.csv file # if not, load the schedule.csv file
if nw.is_connected() == True: if nw.is_connected() == True:
schedule = get_schedule_tdy_tmr("/SOL/App/Spolecne/KZZ010_RychlyPrehled.aspx") schedule = get_schedule("/SOL/App/Spolecne/KZZ010_RychlyPrehled.aspx")
schedule_tdy_tmr_to_file(schedule) schedule_to_file(schedule)
else: else:
schedule = schedule_tdy_tmr_from_file() schedule = schedule_from_file()
print("") print("")
print("--------------------------") print("--------------------------")
print(" Dnesni a zitrejsi rozvrh ") print(" Dnešní a zítřejší rozvrh ")
print("--------------------------\n") print("--------------------------\n")
if schedule == []: if schedule == []:
print("N/A\n") print("N/A\n")
import os import os
if os.path.exists("src/lib/data/schedule_tdy_tmr.csv"): if os.path.exists(f"{os.environ['HOME']}/.local/lib/solendata/schedule_tdy_tmr.csv"):
os.remove("src/lib/data/schedule_tdy_tmr.csv") os.remove(f"{os.environ['HOME']}/.local/lib/solendata/schedule_tdy_tmr.csv")
return return
for i in range(len(schedule)): for i in range(len(schedule)):
@@ -223,16 +224,16 @@ def show_schedule_tdy_tmr():
print("") print("")
def schedule_tdy_tmr_to_file(schedule=None): def schedule_to_file(schedule=None):
import csv import csv
if schedule is None: if schedule is None:
try: try:
schedule = get_schedule_tdy_tmr("/SOL/App/Spolecne/KZZ010_RychlyPrehled.aspx") schedule = get_schedule("/SOL/App/Spolecne/KZZ010_RychlyPrehled.aspx")
except Exception: except Exception:
print("An error occured, you probably can't access the internet right now") print("An error occured, you probably can't access the internet right now")
return return
with open("src/lib/data/schedule_tdy_tmr.csv", mode="w", newline="") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_tdy_tmr.csv", mode="w", newline="") as f:
data = [] data = []
for i in range(len(schedule)): for i in range(len(schedule)):
@@ -264,12 +265,12 @@ def schedule_tdy_tmr_to_file(schedule=None):
for row in data: for row in data:
writer.writerow(row) writer.writerow(row)
def schedule_tdy_tmr_from_file() -> list: def schedule_from_file() -> list:
import csv import csv
schedule = [] schedule = []
try: try:
with open("src/lib/data/schedule_tdy_tmr.csv", mode="r") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_tdy_tmr.csv", mode="r") as f:
reader = csv.reader(f) reader = csv.reader(f)
rows = [] rows = []
for row in reader: for row in reader:
Regular → Executable
+38 -37
View File
@@ -1,5 +1,6 @@
from lib import networking as nw from solenlib import networking as nw
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import os
not_login = 0 not_login = 0
@@ -10,28 +11,28 @@ def fetch_locally() -> list:
not_login = 0 not_login = 0
#print("Could not sign in (you may have entered invalid login credentials)") #print("Could not sign in (you may have entered invalid login credentials)")
#print("Fetching the schedule for this week locally\n") #print("Fetching the schedule for this week locally\n")
schedule_week = schedule_week_from_file() schedule = schedule_from_file()
return schedule_week return schedule
def sort_schedule_week(schedule_week: list[dict]) -> list[dict]: def sort_schedule(schedule: list[dict]) -> list[dict]:
sorted_schedule_week: list[dict] = [{}, {}, {}, {}, {}] sorted_schedule: list[dict] = [{}, {}, {}, {}, {}]
for i in range(len(schedule_week)): for i in range(len(schedule)):
if schedule_week[i]["DAY"] == "Po": if schedule[i]["DAY"] == "Po":
sorted_schedule_week[0] = schedule_week[i] sorted_schedule[0] = schedule[i]
if schedule_week[i]["DAY"] == "Út": if schedule[i]["DAY"] == "Út":
sorted_schedule_week[1] = schedule_week[i] sorted_schedule[1] = schedule[i]
if schedule_week[i]["DAY"] == "St": if schedule[i]["DAY"] == "St":
sorted_schedule_week[2] = schedule_week[i] sorted_schedule[2] = schedule[i]
if schedule_week[i]["DAY"] == "Čt": if schedule[i]["DAY"] == "Čt":
sorted_schedule_week[3] = schedule_week[i] sorted_schedule[3] = schedule[i]
if schedule_week[i]["DAY"] == "": if schedule[i]["DAY"] == "":
sorted_schedule_week[4] = schedule_week[i] sorted_schedule[4] = schedule[i]
return sorted_schedule_week return sorted_schedule
def get_schedule_week(url: str): def get_schedule(url: str):
try: try:
html = nw.get_html_from(url) html = nw.get_html_from(url)
@@ -43,7 +44,7 @@ def get_schedule_week(url: str):
rows_even = table.find_all("tr", class_="RowEven") rows_even = table.find_all("tr", class_="RowEven")
rows = rows_odd + rows_even rows = rows_odd + rows_even
schedule_week = [] schedule = []
for i in range(len(rows)): 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: 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:
@@ -126,18 +127,18 @@ def get_schedule_week(url: str):
break break
if F_continue == False: if F_continue == False:
schedule_week_row = { schedule_row = {
"DAY": day, "DAY": day,
"DATE": date, "DATE": date,
"SUBJECTS": subjects, "SUBJECTS": subjects,
"WHERES": wheres "WHERES": wheres
} }
schedule_week.append(schedule_week_row) schedule.append(schedule_row)
sorted_schedule_week = sort_schedule_week(schedule_week) sorted_schedule = sort_schedule(schedule)
return sorted_schedule_week return sorted_schedule
except AttributeError: except AttributeError:
global not_login global not_login
@@ -145,12 +146,12 @@ def get_schedule_week(url: str):
schedule = fetch_locally() schedule = fetch_locally()
return schedule return schedule
def schedule_week_from_file_to_list(): def schedule_from_file_to_list():
schedule = [] schedule = []
schedule_ = [] schedule_ = []
try: try:
with open("src/lib/data/schedule_week.csv") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_week.csv") as f:
import csv import csv
reader = csv.reader(f) reader = csv.reader(f)
for row in reader: for row in reader:
@@ -183,7 +184,7 @@ def schedule_week_from_file_to_list():
return schedule return schedule
def get_whitespace(key: str, idx=0) -> int: def get_whitespace(key: str, idx=0) -> int:
schedule = schedule_week_from_file_to_list() schedule = schedule_from_file_to_list()
max_len = 0 max_len = 0
if key == "DATE": if key == "DATE":
@@ -199,14 +200,14 @@ def get_whitespace(key: str, idx=0) -> int:
return max_len return max_len
def show_schedule_week(): def show_schedule():
# if there is internet access, load stuff from the web # if there is internet access, load stuff from the web
# if not, load the schedule.csv file # if not, load the schedule.csv file
if nw.is_connected() == True: if nw.is_connected() == True:
schedule = get_schedule_week("/SOL/App/Kalendar/KZK001_KalendarTyden.aspx") schedule = get_schedule("/SOL/App/Kalendar/KZK001_KalendarTyden.aspx")
schedule_week_to_file(schedule) schedule_to_file(schedule)
else: else:
schedule = schedule_week_from_file() schedule = schedule_from_file()
print("") print("")
@@ -218,8 +219,8 @@ def show_schedule_week():
print("N/A\n") print("N/A\n")
import os import os
if os.path.exists("src/lib/data/schedule_week.csv"): if os.path.exists(f"{os.environ['HOME']}/.local/lib/solendata/schedule_week.csv"):
os.remove("src/lib/data/schedule_week.csv") os.remove(f"{os.environ['HOME']}/.local/lib/solendata/schedule_week.csv")
return return
for i in range(len(schedule)): for i in range(len(schedule)):
@@ -246,16 +247,16 @@ def show_schedule_week():
print("") print("")
def schedule_week_to_file(schedule=None): def schedule_to_file(schedule=None):
import csv import csv
if schedule is None: if schedule is None:
try: try:
schedule = get_schedule_week("/SOL/App/Kalendar/KZK001_KalendarTyden.aspx") schedule = get_schedule("/SOL/App/Kalendar/KZK001_KalendarTyden.aspx")
except Exception: except Exception:
print("An error occured, you probably can't access the internet right now") print("An error occured, you probably can't access the internet right now")
return return
with open("src/lib/data/schedule_week.csv", mode="w", newline="") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_week.csv", mode="w", newline="") as f:
data = [] data = []
for i in range(len(schedule)): for i in range(len(schedule)):
@@ -287,12 +288,12 @@ def schedule_week_to_file(schedule=None):
for row in data: for row in data:
writer.writerow(row) writer.writerow(row)
def schedule_week_from_file() -> list: def schedule_from_file() -> list:
import csv import csv
schedule = [] schedule = []
try: try:
with open("src/lib/data/schedule_week.csv", mode="r") as f: with open(f"{os.environ['HOME']}/.local/lib/solendata/schedule_week.csv", mode="r") as f:
reader = csv.reader(f) reader = csv.reader(f)
rows = [] rows = []
for row in reader: for row in reader:
Regular → Executable
+19 -26
View File
@@ -1,30 +1,23 @@
from lib import grades as gr #!/bin/python3
from lib import networking as nw
from lib import schedule_week as sw from solenlib import grades as gr
from lib import schedule_tdy_tmr as st 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
if __name__ == "__main__": if __name__ == "__main__":
user = str(input("Zadejte přihlašovací jméno: ")) user = str(input("Zadejte přihlašovací jméno: "))
pwd = str(input("Zadejte heslo: ")) try:
pwd = str(getpass.getpass("Zadejte heslo: "))
except:
pwd = str(input("Zadejte heslo: "))
if not nw.login(user, pwd):
if nw.is_connected() == True: print("LOGIN UNSUCCESSFULL")
nw.login(user, pwd) sys.exit(1)
else:
sw.show_schedule()
#sw.get_schedule_week("/SOL/App/Kalendar/KZK001_KalendarTyden.aspx") st.show_schedule()
#sw.schedule_week_to_file() gr.show_grades()
#sw.schedule_week_from_file()
sw.show_schedule_week()
#gr.get_grades("/SOL/App/Hodnoceni/KZH001_HodnVypisStud.aspx")
#gr.grades_to_file()
#gr.grades_from_file()
gr.show_grades()
#st.get_schedule("/SOL/App/Spolecne/KZZ010_RychlyPrehled.aspx")
#st.schedule_tdy_tmr_to_file()
#st.schedule_tdy_tmr_from_file()
st.show_schedule_tdy_tmr()