Spaces:
Paused
Paused
| 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() | |