-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
733 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,348 @@ | ||
import requests | ||
from tabulate import tabulate | ||
from tkinter import * | ||
from datetime import datetime, timedelta | ||
from tkinter import ttk | ||
from requests.adapters import HTTPAdapter | ||
from requests.packages.urllib3.util.retry import Retry | ||
|
||
class DATA: | ||
@classmethod | ||
def initialize(cls): | ||
|
||
# Initialize data from WebUntis API | ||
cls.days = DATA.mögliche_tage() | ||
cls.data = DATA.request_data(cls.days) | ||
cls.clean_data = DATA.cleanup_data(cls.data, cls.days) | ||
|
||
@staticmethod | ||
def request_data(days): | ||
retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504]) | ||
session = requests.Session() | ||
session.mount('http://', HTTPAdapter(max_retries=retries)) | ||
session.mount('https://', HTTPAdapter(max_retries=retries)) | ||
|
||
try: | ||
data = DATA.get_data_from_WebUntis(days) | ||
return data | ||
except requests.exceptions.RequestException as e: | ||
print(f"Error: {e}") | ||
|
||
@staticmethod | ||
def get_data_from_WebUntis(days): | ||
# Function to retrieve data from the WebUntis API | ||
|
||
data = {} | ||
# Headers, cookies, and parameters for the WebUntis API request | ||
|
||
for dates in days: | ||
|
||
print(f"Proceeding date.......{dates}") | ||
|
||
#Place cUrl command after: | ||
cookies = { | ||
'traceId': 'c6d915932d178a01b45014d09ed504ce9c790385', | ||
'schoolname': '"_YmJzIGZyaWVzb3l0aGU="', | ||
'traceId': 'c6d915932d178a01b45014d09ed504ce9c790385', | ||
'schoolname': '"_YmJzIGZyaWVzb3l0aGU="', | ||
'JSESSIONID': 'C16CF01D56D67A725BD1F196F4CB1CEA', | ||
} | ||
|
||
headers = { | ||
'authority': 'kephiso.webuntis.com', | ||
'accept': '*/*', | ||
'accept-language': 'de-DE,de;q=0.9,en-DE;q=0.8,en;q=0.7,es-ES;q=0.6,es;q=0.5,en-US;q=0.4', | ||
'content-type': 'application/json', | ||
'dnt': '1', | ||
'origin': 'https://kephiso.webuntis.com', | ||
'referer': 'https://kephiso.webuntis.com/WebUntis/monitor?school=BBS%20Friesoythe&monitorType=subst&format=Vertretung%20heute', | ||
'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"', | ||
'sec-ch-ua-mobile': '?0', | ||
'sec-ch-ua-platform': '"Windows"', | ||
'sec-fetch-dest': 'empty', | ||
'sec-fetch-mode': 'cors', | ||
'sec-fetch-site': 'same-origin', | ||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', | ||
'x-requested-with': 'XMLHttpRequest', | ||
} | ||
|
||
params = { | ||
'school': 'BBS Friesoythe', | ||
} | ||
|
||
json_data = { | ||
'formatName': 'Vertretung morgen', | ||
'schoolName': 'BBS Friesoythe', | ||
'date': dates, | ||
'dateOffset': 0, | ||
'strikethrough': True, | ||
'mergeBlocks': True, | ||
'showOnlyFutureSub': True, | ||
'showBreakSupervisions': False, | ||
'showTeacher': True, | ||
'showClass': False, | ||
'showHour': True, | ||
'showInfo': True, | ||
'showRoom': True, | ||
'showSubject': False, | ||
'groupBy': 1, | ||
'hideAbsent': True, | ||
'departmentIds': [], | ||
'departmentElementType': -1, | ||
'hideCancelWithSubstitution': True, | ||
'hideCancelCausedByEvent': False, | ||
'showTime': False, | ||
'showSubstText': True, | ||
'showAbsentElements': [1, 2], | ||
'showAffectedElements': [1, 2], | ||
'showUnitTime': True, | ||
'showMessages': True, | ||
'showStudentgroup': False, | ||
'enableSubstitutionFrom': True, | ||
'showSubstitutionFrom': 1700, | ||
'showTeacherOnEvent': False, | ||
'showAbsentTeacher': True, | ||
'strikethroughAbsentTeacher': True, | ||
'activityTypeIds': [], | ||
'showEvent': False, | ||
'showCancel': True, | ||
'showOnlyCancel': False, | ||
'showSubstTypeColor': False, | ||
'showExamSupervision': False, | ||
'showUnheraldedExams': False, | ||
} | ||
|
||
# Make a POST request to the WebUntis API | ||
response = requests.post( | ||
'https://kephiso.webuntis.com/WebUntis/monitor/substitution/data', | ||
params=params, | ||
cookies=cookies, | ||
headers=headers, | ||
json=json_data, | ||
) | ||
data[dates] = response.json() | ||
|
||
#cUrl should end here. your script-block should look nearly the same as the one here | ||
return data | ||
|
||
@staticmethod | ||
def cleanup_data(data,days): | ||
#First sort data to classes. | ||
group_dict = {} | ||
for day in days: | ||
data[day] = data[day]['payload']['rows'] | ||
for dicts in data[day]: | ||
del dicts['cssClasses'] | ||
del dicts['cellClasses'] | ||
key = dicts['group'] | ||
group_dict.setdefault(key, {}).setdefault(day, []).append(dicts['data']) | ||
|
||
for classes in group_dict: | ||
for dates in group_dict[classes]: | ||
for elements in group_dict[classes][dates]: | ||
|
||
for i in range(len(elements)): | ||
elements[i] = elements[i].replace('<span class="substMonitorSubstElem">', "").replace('</span>', "").replace('<span class="cancelStyle">', '').replace('Raumänderung', 'Raumänderung') | ||
|
||
return group_dict | ||
|
||
|
||
@staticmethod | ||
def mögliche_tage(): | ||
# Function to get a list of possible dates for the GUI | ||
|
||
# Function to skip Saturday and Sunday | ||
def naechster_werktag(datum): | ||
while True: | ||
datum += timedelta(days=1) | ||
if datum.weekday() < 5: # 0-4 are Monday to Friday | ||
return datum | ||
|
||
# Get the current date | ||
heutiges_datum = datetime.now() | ||
naechste_tage = [] | ||
|
||
if heutiges_datum.weekday() != 5 and heutiges_datum.weekday() != 6: | ||
naechste_tage.append(datetime.now().strftime('%Y%m%d')) | ||
tage = 30 | ||
else: | ||
tage = 31 | ||
|
||
|
||
for _ in range(tage): | ||
heutiges_datum = naechster_werktag(heutiges_datum) | ||
naechste_tage.append(heutiges_datum.strftime('%Y%m%d')) | ||
|
||
return naechste_tage | ||
|
||
def umwandeln_datum(datum_integer): | ||
|
||
tage = { | ||
'Monday': 'Montag,', | ||
'Tuesday': 'Dienstag,', | ||
'Wednesday': 'Mittwoch,', | ||
'Thursday': 'Donnerstag,', | ||
'Friday': 'Freitag,' | ||
} | ||
|
||
# Formatierung des Datums als String | ||
datum_str = str(datum_integer) | ||
|
||
# Konvertierung des Strings in ein datetime-Objekt | ||
datum_obj = datetime.strptime(datum_str, '%Y%m%d') | ||
|
||
# Extrahiere Wochentag, Tag, Monat, Jahr als Liste | ||
datum_liste = ['date', 'Datum: ', tage[datum_obj.strftime('%A')], f'{datum_obj.day}.{datum_obj.month}.{datum_obj.year}'] | ||
|
||
return datum_liste | ||
|
||
|
||
# Create the GUI | ||
class GUI: | ||
|
||
def __init__(self, master): | ||
|
||
self.date_color = '#0F0F0F' | ||
self.odd_color = '#1E1E1E' | ||
self.even_color = '#292929' | ||
self.scrollbar_color = '' | ||
self.heading_color = '#FF7832' | ||
self.class_menu_color = '#FF7832' | ||
|
||
self.scrollbar_table = Scrollbar(master, orient=VERTICAL) | ||
master.style = ttk.Style() | ||
master.style.configure('My.Vertical.TScrollbar', background='black', troughcolor='black', activebackground='black') | ||
|
||
# Initialize the GUI | ||
self.keys = [] | ||
|
||
for key in DATA.clean_data: | ||
self.keys.append(key) | ||
|
||
self.page_number = 1 | ||
self.master = master | ||
|
||
self.selected_class = StringVar(master) | ||
self.selected_class.set('BG 13') | ||
self.selected_class.trace_add('write', self.update_gui_data) | ||
|
||
self.class_menu = OptionMenu(master, self.selected_class, *self.keys) | ||
self.class_menu.configure(relief= 'raised', bg= self.class_menu_color, highlightthickness= 0.5, highlightbackground= 'black', foreground = 'white') | ||
self.class_menu.grid(row=2, column=0, columnspan=3, padx= 500, sticky= 'we') | ||
|
||
self.empty_label = Label(root, bg= '#1E1E1E', height=1) | ||
self.empty_label.grid(row=1, column=0, sticky= 'we') | ||
self.empty_label.grid(row=3, column=0, sticky= 'we') | ||
|
||
# Create a table | ||
self.table_view = ttk.Treeview(master, columns=(1, 2, 3, 4, 5), show='') | ||
self.table_view.config(yscrollcommand=self.scrollbar_table.set) | ||
self.table_view.grid(row=4, column=0, columnspan=1) | ||
|
||
self.scrollbar_table.config(command=self.table_view.yview) | ||
self.scrollbar_table.grid(row=4, column=1, rowspan=1, sticky=NS) | ||
|
||
'''scrollbar_table = Scrollbar(master, orient=VERTICAL,) | ||
scrollbar_table.config(command=self.table_view.yview, bg = 'black', activebackground= 'black') | ||
scrollbar_table.grid(row=4, column=1, rowspan= 1, sticky= NS)''' | ||
|
||
|
||
self.column_headings = [ | ||
'Stunde', | ||
'Raum', | ||
'Lehrer', | ||
'Info', | ||
'Vertretungstext' | ||
] | ||
|
||
self.set_column_width(1, 100) # Adjust the width of the first column | ||
self.set_column_width(2, 150) # Adjust the width of the second column | ||
self.set_column_width(3, 150) # Adjust the width of the third column | ||
self.set_column_width(4, 350) # Adjust the width of the fourth column | ||
self.set_column_width(5, 350) # Adjust the width of the fifth column | ||
|
||
|
||
def set_column_width(self, column, width): | ||
self.table_view.column(column, width=width) | ||
|
||
# Initial update of the table | ||
self.update_table_view() | ||
|
||
def update_class_menu(self): | ||
# Update the class menu options | ||
new_keys = self.keys | ||
current_value = self.selected_class.get() | ||
|
||
menu = self.class_menu['menu'] | ||
menu.delete(0, 'end') # Remove old options | ||
|
||
for key in new_keys: | ||
menu.add_command(label=key, command=lambda value=key: self.selected_class.set(value)) | ||
|
||
if new_keys: | ||
# Check if the current value is in the new keys, and if not, set the default value | ||
if current_value not in new_keys: | ||
self.selected_class.set(new_keys[0]) | ||
else: | ||
self.selected_class.set(current_value) | ||
|
||
def update_table_view(self, *args): | ||
|
||
self.update_class_menu() | ||
self.table_view.delete(*self.table_view.get_children()) | ||
selected_klasse = self.selected_class.get() | ||
|
||
# Define tags for alternating row colors | ||
self.table_view.tag_configure('oddrow', background= self.odd_color, foreground= 'white') | ||
self.table_view.tag_configure('evenrow', background= self.even_color, foreground= 'white') | ||
self.table_view.tag_configure('date', background= self.date_color, foreground= 'white') | ||
self.table_view.tag_configure('empty', background='#919191') | ||
|
||
|
||
table_data = [] | ||
|
||
self.table_view.insert("", "end", values=self.column_headings, tags=('header',)) | ||
self.table_view.tag_configure('header', background=self.heading_color, foreground='white', font=('Helvetica', 10, 'bold')) | ||
|
||
for dates in DATA.clean_data[selected_klasse]: | ||
table_data.append(DATA.umwandeln_datum(dates)) | ||
for lists in DATA.clean_data[selected_klasse][dates]: | ||
table_data.append(lists) | ||
|
||
for index, content in enumerate(table_data): | ||
|
||
if content[0] == 'empty': | ||
self.table_view.insert("", "end", values= [], tags=('empty')) | ||
elif content[0] == 'date': | ||
self.table_view.insert("", "end", values=content[1:], tags=('date',)) | ||
index = 0 | ||
else: | ||
if index % 2 == 0: | ||
self.table_view.insert("", "end", values=content, tags=('evenrow',)) | ||
else: | ||
self.table_view.insert("", "end", values=content, tags=('oddrow',)) | ||
|
||
index += 1 | ||
|
||
|
||
|
||
def update_gui_data(self, *args): | ||
|
||
# Check if clean_data is empty, and if so, select data from the next possible date | ||
if not DATA.clean_data: | ||
DATA.initialize() | ||
|
||
self.update_table_view() | ||
|
||
|
||
# Initialize the data after the GUI is set up | ||
DATA.initialize() | ||
|
||
# Create the main Tkinter window | ||
root = Tk() | ||
root.configure(bg='#1E1E1E') | ||
|
||
# Create an instance of the GUI class | ||
gui = GUI(root) | ||
# Start the Tkinter event loop | ||
root.mainloop() |
Binary file not shown.
Oops, something went wrong.