import sys import threading import time import traceback from webbrowser import open as web import FreeSimpleGUI as sg from base import LINKS, VERSION, LoginException, Scraper, Udemy, scraper_dict from images import ( auto_login, back, check_mark, exit_, icon, login, logout, manual_login_, start, ) sg.set_global_icon(icon) sg.change_look_and_feel("dark") sg.theme_background_color sg.set_options( button_color=(sg.theme_background_color(), sg.theme_background_color()), border_width=0, font=10, ) def update_enrolled_courses(): while True: new_menu = [ ["Help", ["Support", "Github", "Discord"]], [f"Total Courses: {len(udemy.enrolled_courses)}"], ] main_window.write_event_value("Update-Menu", new_menu) time.sleep(10) def create_scraping_thread(site: str): code_name = scraper_dict[site] main_window[f"i{site}"].update(visible=False) main_window[f"p{site}"].update(0, visible=True) try: threading.Thread(target=getattr(scraper, code_name), daemon=True).start() while getattr(scraper, f"{code_name}_length") == 0: time.sleep(0.1) # Avoid busy waiting if getattr(scraper, f"{code_name}_length") == -1: raise Exception(f"Error in: {site}") main_window[f"p{site}"].update(0, max=getattr(scraper, f"{code_name}_length")) while not getattr(scraper, f"{code_name}_done") and not getattr( scraper, f"{code_name}_error" ): main_window[f"p{site}"].update( getattr(scraper, f"{code_name}_progress") + 1 ) time.sleep(0.1) # Update every 0.1 seconds if getattr(scraper, f"{code_name}_error"): raise Exception(f"Error in: {site}") except Exception: error_message = getattr(scraper, f"{code_name}_error", "Unknown Error") main_window.write_event_value( "Error", f"{error_message}|:|Unknown Error in: {site} {VERSION}" ) finally: main_window[f"p{site}"].update(0, visible=False) main_window[f"i{site}"].update(visible=True) ########################################## def scrape(): try: for site in udemy.sites: main_window[f"pcol{site}"].update(visible=True) main_window["main_col"].update(visible=False) main_window["scrape_col"].update(visible=True) udemy.scraped_data = scraper.get_scraped_courses(create_scraping_thread) main_window["scrape_col"].update(visible=False) main_window["output_col"].update(visible=True) # ------------------------------------------ udemy.start_enrolling() main_window["output_col"].Update(visible=False) main_window["done_col"].update(visible=True) main_window["se_c"].update( value=f"Successfully Enrolled: {udemy.successfully_enrolled_c}" ) main_window["as_c"].update( value=f"Amount Saved: {round(udemy.amount_saved_c,2)} {udemy.currency.upper()}" ) main_window["ae_c"].update( value=f"Already Enrolled: {udemy.already_enrolled_c}" ) main_window["e_c"].update(value=f"Expired Courses: {udemy.expired_c}") main_window["ex_c"].update(value=f"Excluded Courses: {udemy.excluded_c}") except Exception: e = traceback.format_exc() main_window.write_event_value( "Error", f"{e}\n\nVersion:{VERSION}\nLink:{getattr(udemy, 'link', 'None')}\nTitle:{getattr(udemy, 'title','None')}|:|Error g100", ) ################################# udemy = Udemy("gui") udemy.load_settings() login_title, main_title = udemy.check_for_update() menu = [["Help", ["Support", "Github", "Discord"]]] login_error = False try: if udemy.settings["stay_logged_in"]["auto"]: udemy.fetch_cookies() elif udemy.settings["stay_logged_in"]["manual"]: udemy.manual_login(udemy.settings["email"], udemy.settings["password"]) else: raise LoginException("No Saved Login Found") udemy.get_session_info() except LoginException: login_error = True # if ( # not udemy.settings["stay_logged_in"]["auto"] # and not udemy.settings["stay_logged_in"]["manual"] # ) or login_error: if login_error: c1 = [ [ sg.Button(key="a_login", image_data=auto_login), sg.T(""), sg.B(key="m_login", image_data=manual_login_), ], [ sg.Checkbox( "Stay logged-in", default=udemy.settings["stay_logged_in"]["auto"], key="sli_a", ) ], ] c2 = [ [ sg.T("Email"), sg.InputText( default_text=udemy.settings["email"], key="email", size=(20, 1), pad=(5, 5), ), ], [ sg.T("Password"), sg.InputText( default_text=udemy.settings["password"], key="password", size=(20, 1), pad=(5, 5), password_char="*", ), ], [ sg.Checkbox( "Stay logged-in", default=udemy.settings["stay_logged_in"]["manual"], key="sli_m", ) ], [ sg.B(key="Back", image_data=back), sg.T(" "), sg.B(key="Login", image_data=login), ], ] login_layout = [ [sg.Menu(menu)], [sg.Column(c1, key="col1"), sg.Column(c2, visible=False, key="col2")], ] login_window = sg.Window(login_title, login_layout, finalize=True) login_window.bind("a", "a_login") login_window.bind("m", "m_login") while True: event, values = login_window.read() if event in (None,): login_window.close() sys.exit() elif event == "a_login" and not login_window["a_login"].Disabled: login_window["a_login"].update(disabled=True) login_window.refresh() try: udemy.fetch_cookies() try: udemy.get_session_info() udemy.settings["stay_logged_in"]["auto"] = values["sli_a"] udemy.save_settings() login_window.close() break except Exception: e = traceback.format_exc() print(e) sg.popup_auto_close( "Make sure you are logged in to udemy.com in chrome browser", title="Error", auto_close_duration=3, no_titlebar=True, ) except Exception: e = traceback.format_exc() sg.popup_scrolled(e, title=f"Unknown Error {VERSION}") login_window["a_login"].update(disabled=False) elif event == "m_login": login_window["col1"].update(visible=False) login_window["col2"].update(visible=True) login_window["email"].update(value=udemy.settings["email"]) login_window["password"].update(value=udemy.settings["password"]) elif event == "Github": web(LINKS["github"]) elif event == "Support": web(LINKS["support"]) elif event == "Discord": web(LINKS["discord"]) elif event == "Back": login_window["col1"].update(visible=True) login_window["col2"].update(visible=False) elif event == "Login": udemy.settings["email"] = values["email"] udemy.settings["password"] = values["password"] try: try: udemy.manual_login( udemy.settings["email"], udemy.settings["password"] ) udemy.get_session_info() udemy.settings["stay_logged_in"]["manual"] = values["sli_m"] udemy.save_settings() login_window.close() break except LoginException as e: sg.popup_auto_close( e, title="Error", auto_close_duration=3, no_titlebar=True, ) except Exception: e = traceback.format_exc() sg.popup_scrolled(e, title=f"Unknown Error {VERSION}") checkbox_lo = [] for key in udemy.settings["sites"]: checkbox_lo.append( [sg.Checkbox(key, key=key, default=udemy.settings["sites"][key], size=(18, 1))] ) categories_lo = [] categories_k = list(udemy.settings["categories"].keys()) categories_v = list(udemy.settings["categories"].values()) for index, _ in enumerate(udemy.settings["categories"]): if index % 3 == 0: try: categories_lo.append( [ sg.Checkbox( categories_k[index], default=categories_v[index], key=categories_k[index], size=(18, 1), ), sg.Checkbox( categories_k[index + 1], default=categories_v[index + 1], key=categories_k[index + 1], size=(18, 1), ), sg.Checkbox( categories_k[index + 2], default=categories_v[index + 2], key=categories_k[index + 2], size=(18, 1), ), ] ) except IndexError: categories_lo.append( [ sg.Checkbox( categories_k[index], default=categories_v[index], key=categories_k[index], size=(18, 1), ) ] ) languages_lo = [] languages_k = list(udemy.settings["languages"].keys()) languages_v = list(udemy.settings["languages"].values()) for index, _ in enumerate(udemy.settings["languages"]): if index % 3 == 0: try: languages_lo.append( [ sg.Checkbox( languages_k[index], default=languages_v[index], key=languages_k[index], size=(10, 1), ), sg.Checkbox( languages_k[index + 1], default=languages_v[index + 1], key=languages_k[index + 1], size=(10, 1), ), sg.Checkbox( languages_k[index + 2], default=languages_v[index + 2], key=languages_k[index + 2], size=(10, 1), ), ] ) except IndexError: languages_lo.append( [ sg.Checkbox( languages_k[index], default=languages_v[index], key=languages_k[index], size=(10, 1), ), sg.Checkbox( languages_k[index + 1], default=languages_v[index + 1], key=languages_k[index + 1], size=(10, 1), ), ] ) main_tab = [ [ sg.Frame( "Websites", checkbox_lo, "#4deeea", border_width=4, title_location="n", key="fcb", ), sg.Frame( "Language", languages_lo, "#4deeea", border_width=4, title_location="n", key="fl", ), ], [ sg.Frame( "Category", categories_lo, "#4deeea", border_width=4, title_location="n", key="fc", ) ], ] instructor_ex_lo = [ [ sg.Multiline( default_text=udemy.instructor_exclude, key="instructor_exclude", size=(15, 10), ) ], [sg.Text("Paste instructor(s)\nusername in new lines")], ] title_ex_lo = [ [ sg.Multiline( default_text=udemy.title_exclude, key="title_exclude", size=(20, 10) ) ], [sg.Text("Keywords in new lines\nNot cAsE sensitive")], ] rating_lo = [ [ sg.Spin( [i * 0.5 for i in range(11)], initial_value=udemy.settings["min_rating"], key="min_rating", ), sg.Text("0.0 <-> 5.0"), ] ] courses_last_updated_lo = [ [ sg.Text("Past"), sg.Spin( [i for i in range(1, 48)], initial_value=udemy.settings["course_update_threshold_months"], key="course_update_threshold_months", ), sg.Text("Month(s)"), ] ] advanced_tab = [ [ sg.Frame( "Exclude Instructor", instructor_ex_lo, "#4deeea", border_width=4, title_location="n", ), sg.Frame( "Title Keyword Exclusion", title_ex_lo, "#4deeea", border_width=4, title_location="n", ), ], [ sg.Frame( "Minimum Rating", rating_lo, "#4deeea", border_width=4, title_location="n", key="f_min_rating", font=25, ), sg.Frame( "Course Last Updated", courses_last_updated_lo, "#4deeea", border_width=4, title_location="n", key="f_course_last_updated", font=25, ), ], [ sg.Checkbox( "Save enrolled courses in txt", key="save_txt", default=udemy.settings["save_txt"], ) ], [ sg.Checkbox( "Enrol in Discounted courses only", key="discounted_only", default=udemy.settings["discounted_only"], ) ], ] scrape_col = [] for key in udemy.settings["sites"]: scrape_col.append( [ sg.pin( sg.Column( [ [ sg.Text(key, size=(12, 1)), sg.ProgressBar( 3, orientation="h", key=f"p{key}", bar_color=("#1c6fba", "#000000"), border_width=1, size=(20, 20), ), sg.Image(data=check_mark, visible=False, key=f"i{key}"), ] ], key=f"pcol{key}", visible=False, ) ) ] ) output_col = [ [sg.Text("Output")], [sg.Multiline(size=(69, 12), key="out", autoscroll=False, disabled=True)], # [ # sg.ProgressBar( # 3, # orientation="h", # key="pout", # bar_color=("#1c6fba", "#000000"), # border_width=1, # size=(46, 20), # ) # ], ] done_col = [ [sg.Text(" Stats", text_color="#FFD700")], [ sg.Text( "Successfully Enrolled: ", key="se_c", text_color="#7CFC00", ) ], [ sg.Text( "Amount Saved: $ ", key="as_c", text_color="#00FA9A", ) ], [sg.Text("Already Enrolled: ", key="ae_c", text_color="#00FFFF")], [sg.Text("Expired Courses: ", key="e_c", text_color="#FF0000")], [sg.Text("Excluded Courses: ", key="ex_c", text_color="#FF4500")], ] main_col = [ [ sg.TabGroup( [[sg.Tab("Main", main_tab), sg.Tab("Advanced", advanced_tab)]], border_width=2, ) ], [ sg.Button( key="Start", tooltip="Once started will not stop until completed", image_data=start, ) ], ] if ( udemy.settings["stay_logged_in"]["auto"] or udemy.settings["stay_logged_in"]["manual"] ): logout_btn_lo = sg.Button(key="Logout", image_data=logout) else: logout_btn_lo = sg.Button(key="Logout", image_data=logout, visible=False) main_lo = [ [ sg.Menu( menu, key="mn", ) ], [sg.Text(f"Logged in as: {udemy.display_name}", key="user_t"), logout_btn_lo], [ sg.pin(sg.Column(main_col, key="main_col")), sg.pin(sg.Column(output_col, key="output_col", visible=False)), sg.pin(sg.Column(scrape_col, key="scrape_col", visible=False)), sg.pin(sg.Column(done_col, key="done_col", visible=False)), ], [sg.Button(key="Exit", image_data=exit_)], ] # ,sg.Button(key='Dummy',image_data=back) global main_window # position windows in center main_window = sg.Window( main_title, main_lo, finalize=True, ) threading.Thread(target=update_enrolled_courses, daemon=True).start() while True: event, values = main_window.read() if event == "Dummy": print(values) if event in (None, "Exit"): break elif event == "Logout": ( udemy.settings["stay_logged_in"]["auto"], udemy.settings["stay_logged_in"]["manual"], ) = ( False, False, ) udemy.save_settings() break elif event == "Support": web(LINKS["support"]) elif event == "Github": web(LINKS["github"]) elif event == "Discord": web(LINKS["discord"]) elif event == "Start" and main_window["main_col"].visible: # for key in udemy.settings["languages"]: # udemy.settings["languages"][key] = values[key] # for key in udemy.settings["categories"]: # udemy.settings["categories"][key] = values[key] # for key in udemy.settings["sites"]: # udemy.settings["sites"][key] = values[key] for setting in ["languages", "categories", "sites"]: for key in udemy.settings[setting]: udemy.settings[setting][key] = values[key] udemy.settings["instructor_exclude"] = str(values["instructor_exclude"]).split() udemy.settings["title_exclude"] = list( filter(None, values["title_exclude"].split("\n")) ) udemy.settings["min_rating"] = float(values["min_rating"]) udemy.settings["course_update_threshold_months"] = int( values["course_update_threshold_months"] ) udemy.settings["save_txt"] = values["save_txt"] udemy.settings["discounted_only"] = values["discounted_only"] udemy.save_settings() user_dumb = udemy.is_user_dumb() if user_dumb: sg.popup_auto_close( "What do you even expect to happen!", auto_close_duration=5, no_titlebar=True, ) continue scraper = Scraper(udemy.sites) udemy.window = main_window threading.Thread(target=scrape, daemon=True).start() elif event == "Error": msg = values["Error"].split("|:|") e = msg[0] title = msg[1] sg.popup_scrolled(e, title=title) elif event == "Update-Menu": menu = values["Update-Menu"] main_window["mn"].update(menu) main_window.close()