importcsvimportbs4importtwill.commandsastwillfromtwillimportbrowserfromlogin_stuffimportsecretstimetable_url='https://ergogym.eltern-portal.org/service/stundenplan'defget_html():twill.go(timetable_url)twill.form_value(1,'username',secrets['username'])twill.form_value(1,'password',secrets['password'])twill.submit(1)twill.go(timetable_url)returnbrowser.htmlhtml=get_html()soup=bs4.BeautifulSoup(html,'html.parser')defget_courses(html):course_table=[tablefortableinsoup.find_all('table')if'Kurse'intable.text][0]courses=[course.text.split(',')[0]forcourseincourse_table.find_all('td')if','incourse.text]returncoursesdefparse_to_room_dict(field_string):# Split the string into two parts: the identifiers and the numbers
identifiers_part,numbers_part=field_string.strip().split('\n')# Split both parts into individual elements
identifiers=identifiers_part.split('/')numbers=numbers_part.split('/')# Create the dictionary by zipping the identifiers with the numbers
result_dict=dict(zip(identifiers,numbers))returnresult_dictdeffind_course_room(courses_dict,my_courses):# Find the intersection between the keys of the dictionary and the list of courses
intersection=set(courses_dict.keys())&set(my_courses)iflen(intersection)>0:course=intersection.pop()# Get the only course that's common
room=courses_dict[course]# Get the room for this course
ifroom=='':returncoursereturnf'{course[1:].lower()} - {room}'# Return the formatted string (course, room)
returnNonedefget_timetable(html,courses=get_courses(html)):timetable=[tablefortableinsoup.find_all('table')if'Montag'intable.text][0]# Create a deep copy of the timetable by converting to a string and re-parsing
timetable_copy=bs4.BeautifulSoup(str(timetable),'html.parser')forbrintimetable_copy.find_all('br'):br.insert_before('\n')timetable_array=[[td.textfortdinrow.find_all('td')]forrowintimetable_copy.find_all('tr')]timetable_array[0]=['','Montag','Dienstag','Mittwoch','Donnerstag','Freitag']forrow_idinrange(1,len(timetable_array)):timetable_array[row_id][0]=timetable_array[row_id][0].replace('\n','')forrow_idx,rowinenumerate(timetable_array):forcol_idx,fieldinenumerate(row):ifrow_idx>0andcol_idx>0:field=timetable_array[row_idx][col_idx]if'/'infield:course_room=find_course_room(parse_to_room_dict(field),courses)ifcourse_roomisnotNone:timetable_array[row_idx][col_idx]=course_roomelse:timetable_array[row_idx][col_idx]=''else:timetable_array[row_idx][col_idx]=''timetable_array=[rowforrowintimetable_arrayifany(field!=''forfieldinrow[1:])]returntimetable_arraydefsave_to_file(timetable_array,courses):timetable_array.append([])timetable_array.append(['Kurse:',', '.join(courses)])withopen('timetable.csv','w',newline='')ascsvfile:writer=csv.writer(csvfile,delimiter=',')writer.writerows(timetable_array)fromreportlab.lib.pagesizesimportA4,landscapefromreportlab.platypusimportSimpleDocTemplate,Table,TableStyle,Paragraphfromreportlab.lib.unitsimportcmfromreportlab.libimportcolorsfromreportlab.lib.stylesimportgetSampleStyleSheet,ParagraphStylefromreportlab.pdfbase.ttfontsimportTTFontfromreportlab.pdfbaseimportpdfmetricsdefsave_to_pdf(timetable_array,courses,width_cm=19,height_cm=11,output='timetable.pdf'):pdfmetrics.registerFont(TTFont('Inter','InterVariable.ttf'))pdfmetrics.registerFontFamily('Inter',normal='Inter')# Convert cm to points
width=width_cm*cmheight=height_cm*cmdoc=SimpleDocTemplate(output,pagesize=landscape(A4))col_width=width/len(timetable_array[0])row_height=height/len(timetable_array)num_cols=len(timetable_array[0])col_width=width/num_cols# Calculate new column widths
first_col_width=col_width*1.3remaining_col_width=(width-first_col_width)/(num_cols-1)# Define table with adjusted column widths and row heights
table=Table(timetable_array,colWidths=[first_col_width]+[remaining_col_width]*(num_cols-1),rowHeights=[row_height]*len(timetable_array))# Apply table style for borders and larger font size
table.setStyle(TableStyle([('ALIGN',(0,0),(-1,-1),'CENTER'),('VALIGN',(0,0),(-1,-1),'MIDDLE'),('FONTNAME',(0,0),(-1,-1),'Inter'),# Use bold font
('FONTSIZE',(0,0),(-1,-1),14),# Increase font size
('GRID',(0,0),(-1,-1),1,colors.black)# Add gridlines
]))table.hAlign='LEFT'# Add the courses as a paragraph at the top
styles=getSampleStyleSheet()course_text=f"Kurse: {', '.join(courses)}"course_paragraph=Paragraph(course_text,ParagraphStyle(name='CourseParagraph',fontName='Inter',fontSize=12,spaceBefore=cm))# Build the PDF
doc.build([table,course_paragraph])if__name__=='__main__':courses=get_courses(html)leopold_courses=['1k3','1E','1M1','1D1','1ku1','1pug4','1ph2','1ew','1g3','1geo2','1b1','1smw3']save_to_pdf(get_timetable(html,courses),courses)save_to_pdf(get_timetable(html,leopold_courses),leopold_courses,output='timetable_leopold.pdf')