diff --git a/chrome_tixcraft.py b/chrome_tixcraft.py index afeda24..b43d726 100644 --- a/chrome_tixcraft.py +++ b/chrome_tixcraft.py @@ -10,17 +10,7 @@ import random # 'seleniumwire' and 'selenium 4' raise error when running python 2.x # PS: python 2.x will be removed in future. -driver_type = 'selenium' -#driver_type = 'stealth' -driver_type = 'undetected_chromedriver' - -if driver_type=="undetected_chromedriver": - # TODO: fix image re-download issue. - #from seleniumwire import webdriver - - from selenium import webdriver -else: - from selenium import webdriver +from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select @@ -67,7 +57,7 @@ ssl._create_default_https_context = ssl._create_unverified_context #附註1:沒有寫的很好,很多地方應該可以模組化。 #附註2: -CONST_APP_VERSION = u"MaxBot (2022.11.14) ver.5" +CONST_APP_VERSION = u"MaxBot (2022.11.16)" CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom" CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top" @@ -85,7 +75,6 @@ driver = None homepage = None browser = None ticket_number = None -facebook_account = None auto_press_next_step_button = False auto_fill_ticket_number = False @@ -179,7 +168,6 @@ def get_chromedriver_path(webdriver_path): return chromedriver_path def load_chromdriver_normal(webdriver_path, driver_type): - from selenium_stealth import stealth chrome_options = webdriver.ChromeOptions() chromedriver_path = get_chromedriver_path(webdriver_path) @@ -221,7 +209,6 @@ def load_chromdriver_normal(webdriver_path, driver_type): if driver_type=="stealth": from selenium_stealth import stealth - # Selenium Stealth settings stealth(driver, languages=["zh-TW", "zh"], @@ -307,14 +294,13 @@ def close_browser_tabs(driver): except Exception as excSwithFail: pass -def load_config_from_local(driver): - config_dict = get_config_dict() +def get_driver_by_config(config_dict, driver_type): + global driver global homepage global browser global debugMode global ticket_number - global facebook_account global auto_press_next_step_button global auto_fill_ticket_number global kktix_area_auto_select_mode @@ -362,18 +348,13 @@ def load_config_from_local(driver): if 'ticket_number' in config_dict: ticket_number = str(config_dict["ticket_number"]) - facebook_account = "" - if 'facebook_account' in config_dict: - facebook_account = str(config_dict["facebook_account"]) - # for ["kktix"] if 'kktix' in config_dict: auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"] auto_fill_ticket_number = config_dict["kktix"]["auto_fill_ticket_number"] if 'area_mode' in config_dict["kktix"]: - kktix_area_auto_select_mode = config_dict["kktix"]["area_mode"] - kktix_area_auto_select_mode = kktix_area_auto_select_mode.strip() + kktix_area_auto_select_mode = config_dict["kktix"]["area_mode"].strip() if not kktix_area_auto_select_mode in CONST_SELECT_OPTIONS_ARRAY: kktix_area_auto_select_mode = CONST_SELECT_ORDER_DEFAULT @@ -462,7 +443,6 @@ def load_config_from_local(driver): print("homepage", homepage) print("browser", browser) print("ticket_number", ticket_number) - print("facebook_account", facebook_account) # for kktix print("==[kktix]==") @@ -498,7 +478,7 @@ def load_config_from_local(driver): if homepage is None: homepage = "" if len(homepage) == 0: - homepage = "https://tixcraft.com/activity/" + homepage = "https://tixcraft.com" Root_Dir = get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") @@ -592,6 +572,8 @@ def load_config_from_local(driver): else: try: print("goto url:", homepage) + if homepage=="https://tixcraft.com": + homepage="https://tixcraft.com/user/changeLanguage/lang/zh_tw" driver.get(homepage) except WebDriverException as exce2: print('oh no not again, WebDriverException') @@ -1034,7 +1016,13 @@ def tixcraft_redirect(driver, url): return ret -def date_auto_select(driver, url, date_auto_select_mode, date_keyword, pass_date_is_sold_out_enable, auto_reload_coming_soon_page_enable): +def tixcraft_date_auto_select(driver, url, config_dict): + # read config. + date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"] + date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"] + pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"] + auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"] + is_date_selected = False debug_date_select = True # debug. @@ -1303,7 +1291,15 @@ def get_tixcraft_target_area(el, area_keyword, area_auto_select_mode, pass_1_sea # PS: auto refresh condition 1: no keyword + no hyperlink. # PS: auto refresh condition 2: with keyword + no hyperlink. -def area_auto_select(driver, url, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode, pass_1_seat_remaining_enable): +def tixcraft_area_auto_select(driver, url, config_dict): + # read config. + area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip() + area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip() + area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip() + area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip() + area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"] + pass_1_seat_remaining_enable = config_dict["tixcraft"]["pass_1_seat_remaining"] + debugMode = True debugMode = False # for online @@ -1436,96 +1432,89 @@ def area_auto_select(driver, url, area_keyword_1, area_keyword_2, area_keyword_3 print("find submitSeat fail") ''' -def ticket_number_auto_fill(url, form_select): +def tixcraft_ticket_agree(driver): + click_plan = "B" + #click_plan = "B" + # check agree form_checkbox = None - try: - form_checkbox = driver.find_element(By.ID, 'TicketForm_agree') + if click_plan == "A": + try: + form_checkbox = driver.find_element(By.ID, 'TicketForm_agree') + except Exception as exc: + print("find TicketForm_agree fail") - if form_checkbox is not None: - try: + is_finish_checkbox_click = False + if form_checkbox is not None: + try: + # TODO: check the status: checked. + if form_checkbox.is_enabled(): form_checkbox.click() - except Exception as exc: - print("click TicketForm_agree fail") - pass - except Exception as exc: - print("find TicketForm_agree fail") + is_finish_checkbox_click = True + except Exception as exc: + print("click TicketForm_agree fail") + pass - # 使用 plan B. - try: - #driver.execute_script("$(\"input[type='checkbox']\").prop('checked', true);") - driver.execute_script("document.getElementById(\"TicketForm_agree\").checked;") - except Exception as exc: - print("javascript check TicketForm_agree fail") - print(exc) - pass + if not is_finish_checkbox_click: + # 使用 plan B. + try: + driver.execute_script("$(\"input[type='checkbox']\").prop('checked', true);") + #driver.execute_script("document.getElementById(\"TicketForm_agree\").checked;") + is_finish_checkbox_click = True + except Exception as exc: + print("javascript check TicketForm_agree fail") + print(exc) + pass - # select options - select = None - try: - #select = driver.find_element(By.TAG_NAME, 'select') - select = Select(form_select) - #select = driver.find_element(By.CSS_SELECTOR, '.mobile-select') - except Exception as exc: - print("select fail") + return is_finish_checkbox_click - if select is not None: +def tixcraft_ticket_number_auto_fill(driver, select_obj, ticket_number): + is_assign_ticket_number = False + if select_obj is not None: try: # target ticket number - select.select_by_visible_text(ticket_number) + select_obj.select_by_visible_text(ticket_number) #select.select_by_value(ticket_number) #select.select_by_index(int(ticket_number)) + is_assign_ticket_number = True except Exception as exc: print("select_by_visible_text ticket_number fail") print(exc) try: # target ticket number - select.select_by_visible_text(ticket_number) + select_obj.select_by_visible_text(ticket_number) #select.select_by_value(ticket_number) #select.select_by_index(int(ticket_number)) + is_assign_ticket_number = True except Exception as exc: print("select_by_visible_text ticket_number fail...2") print(exc) # try buy one ticket try: - select.select_by_visible_text("1") + select_obj.select_by_visible_text("1") #select.select_by_value("1") #select.select_by_index(int(ticket_number)) + is_assign_ticket_number = True except Exception as exc: print("select_by_visible_text 1 fail") pass # because click cause click wrong row. - if select is not None: - try: - # target ticket number - #select.select_by_visible_text(ticket_number) - print("assign ticker number by jQuery:",ticket_number) - driver.execute_script("$(\"input[type='select']\").val(\""+ ticket_number +"\");") - except Exception as exc: - print("jQuery select_by_visible_text ticket_number fail (after click.)") - print(exc) - - # click again. - try: - form_select.click() - except Exception as exc: - print("click select fail") - pass - - form_verifyCode = None - try: - form_verifyCode = driver.find_element(By.ID, 'TicketForm_verifyCode') - if form_verifyCode is not None: + if not is_assign_ticket_number: + if select is not None: try: - form_verifyCode.click() + # target ticket number + #select.select_by_visible_text(ticket_number) + print("assign ticker number by jQuery:",ticket_number) + driver.execute_script("$(\"input[type='select']\").val(\""+ ticket_number +"\");") + is_assign_ticket_number = True except Exception as exc: - print("click form_verifyCode fail") - pass - except Exception as exc: - print("find form_verifyCode fail") + print("jQuery select_by_visible_text ticket_number fail (after click.)") + print(exc) + + return is_assign_ticket_number def tixcraft_verify(driver, url): ret = False @@ -1666,44 +1655,99 @@ def tixcraft_verify(driver, url): return ret -def tixcraft_ticket_main(driver, url, is_verifyCode_editing): +def tixcraft_ticket_main(driver, config_dict, is_finish_checkbox_click): + if not is_finish_checkbox_click: + is_finish_checkbox_click = tixcraft_ticket_agree(driver) + + # allow agree not enable to assign ticket number. form_select = None try: #form_select = driver.find_element(By.TAG_NAME, 'select') + #PS: select box may appear many in the page with different price. form_select = driver.find_element(By.CSS_SELECTOR, '.mobile-select') except Exception as exc: print("find select fail") pass + select_obj = None if form_select is not None: + is_visible = False try: - #print("get select ticket value:" + Select(form_select).first_selected_option.text) - if Select(form_select).first_selected_option.text=="0": - is_verifyCode_editing = False + is_visible = form_select.is_enabled() except Exception as exc: - print("query selected option fail") - print(exc) pass - - if is_verifyCode_editing == False: - ticket_number_auto_fill(url, form_select) - - # start to input verify code. + if is_visible: try: - #driver.execute_script("$('#TicketForm_verifyCode').focus();") - driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();") - - is_verifyCode_editing = True - print("goto is_verifyCode_editing== True") + select_obj = Select(form_select) except Exception as exc: - print(exc) pass - else: - #print("is_verifyCode_editing") - # do nothing here. + + is_verifyCode_editing = False + is_assign_ticket_number = False + if not select_obj is None: + row_text = None + try: + row_text = select_obj.first_selected_option.text + except Exception as exc: pass + if not row_text is None: + if len(row_text) > 0: + if row_text != "0": + # ticket assign. + is_assign_ticket_number = True - return is_verifyCode_editing + # must wait select object ready to assign ticket number. + if not is_assign_ticket_number: + ticket_number = str(config_dict["ticket_number"]) + is_assign_ticket_number = tixcraft_ticket_number_auto_fill(driver, select_obj, ticket_number) + + # must wait ticket number assign to focus captcha. + if is_assign_ticket_number: + # only this case:"ticket number change by bot" to play sound! + play_captcha_sound = config_dict["advanced"]["play_captcha_sound"]["enable"] + captcha_sound_filename = config_dict["advanced"]["play_captcha_sound"]["filename"].strip() + if play_captcha_sound: + app_root = get_app_root() + captcha_sound_filename = os.path.join(app_root, captcha_sound_filename) + play_mp3(captcha_sound_filename) + + # only this case to focus() + # start to input verify code. + form_verifyCode = None + try: + form_verifyCode = driver.find_element(By.ID, 'TicketForm_verifyCode') + except Exception as exc: + print("find form_verifyCode fail") + + if form_verifyCode is not None: + is_visible = False + try: + if form_verifyCode.is_enabled(): + is_visible = True + except Exception as exc: + pass + + if is_visible: + try: + form_verifyCode.click() + is_verifyCode_editing = True + except Exception as exc: + print("click form_verifyCode fail, tring to use javascript.") + # plan B + try: + driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();") + is_verifyCode_editing = True + except Exception as exc: + print("click form_verifyCode fail") + pass + pass + + print("is_finish_checkbox_click:", is_finish_checkbox_click) + + if is_verifyCode_editing: + print("goto is_verifyCode_editing == True") + + return is_verifyCode_editing, is_finish_checkbox_click # PS: There are two "Next" button in kktix. # : 1: /events/xxx @@ -1713,7 +1757,7 @@ def kktix_events_press_next_button(driver): ret = False # let javascript to enable button. - time.sleep(0.2) + time.sleep(0.1) wait = WebDriverWait(driver, 1) next_step_button = None @@ -1787,8 +1831,6 @@ def kktix_press_next_button(driver): ret = True except Exception as exc: pass - - return ret def kktix_captcha_text_value(captcha_inner_div): @@ -1979,7 +2021,7 @@ def kktix_travel_price_list(driver, kktix_area_keyword, kktix_date_keyword): return is_ticket_number_assigened, areas -def kktix_assign_ticket_number(driver, ticket_number, kktix_area_keyword, kktix_date_keyword): +def kktix_assign_ticket_number(driver, ticket_number, kktix_area_auto_select_mode, kktix_area_keyword, kktix_date_keyword): show_debug_message = True # debug. show_debug_message = False # online @@ -2184,7 +2226,16 @@ def kktix_check_register_status(url): #print("registerStatus:", registerStatus) return registerStatus -def kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_checkbox_click, auto_fill_ticket_number, ticket_number, kktix_area_keyword, kktix_date_keyword): +def kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_checkbox_click, config_dict): + # read config. + auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"] + auto_fill_ticket_number = config_dict["kktix"]["auto_fill_ticket_number"] + ticket_number = str(config_dict["ticket_number"]) + kktix_area_keyword = config_dict["kktix"]["area_keyword"].strip() + kktix_date_keyword = config_dict["kktix"]["date_keyword"].strip() + kktix_area_auto_select_mode = config_dict["kktix"]["area_mode"] + auto_guess_options = config_dict["kktix"]["auto_guess_options"] + show_debug_message = True # debug. show_debug_message = False # online @@ -2194,7 +2245,7 @@ def kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_che is_assign_ticket_number = False if auto_fill_ticket_number: for retry_index in range(8): - is_assign_ticket_number = kktix_assign_ticket_number(driver, ticket_number, kktix_area_keyword, kktix_date_keyword) + is_assign_ticket_number = kktix_assign_ticket_number(driver, ticket_number, kktix_area_auto_select_mode, kktix_area_keyword, kktix_date_keyword) if is_assign_ticket_number: break #print('is_assign_ticket_number:', is_assign_ticket_number) @@ -2693,7 +2744,7 @@ def kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_che return answer_index -def kktix_reg_new(driver, url, answer_index, kktix_register_status_last): +def kktix_reg_new(driver, url, answer_index, kktix_register_status_last, config_dict): registerStatus = kktix_register_status_last #--------------------------- @@ -2756,21 +2807,15 @@ def kktix_reg_new(driver, url, answer_index, kktix_register_status_last): answer_index = -1 registerStatus = None else: - global auto_fill_ticket_number - global ticket_number - global kktix_area_keyword - global kktix_date_keyword - answer_index = kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_checkbox_click, auto_fill_ticket_number, ticket_number, kktix_area_keyword, kktix_date_keyword) - + answer_index = kktix_reg_new_main(url, answer_index, registrationsNewApp_div, is_finish_checkbox_click, config_dict) return answer_index, registerStatus - # PURPOSE: get target area list. # PS: this is main block, use keyword to get rows. # PS: it seems use date_auto_select_mode instead of area_auto_select_mode -def get_fami_target_area(date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode): +def get_fami_target_area(driver, date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode): show_debug_message = True # debug. #show_debug_message = False # online @@ -2931,37 +2976,41 @@ def get_fami_target_area(date_keyword, area_keyword_1, area_keyword_2, area_keyw return areas -def fami_activity(driver, url): +def fami_activity(driver): #print("fami_activity bingo") #--------------------------- # part 1: press "buy" button. #--------------------------- fami_start_to_buy_button = None - fami_start_to_buy_button = driver.find_element(By.ID, 'buyWaiting') + try: + fami_start_to_buy_button = driver.find_element(By.ID, 'buyWaiting') + except Exception as exc: + pass + + is_visible = False if fami_start_to_buy_button is not None: - is_visible = False try: if fami_start_to_buy_button.is_enabled(): is_visible = True except Exception as exc: pass - if fami_start_to_buy_button.is_enabled(): + if is_visible: + try: + fami_start_to_buy_button.click() + except Exception as exc: + print("click buyWaiting button fail...") + #print(exc) + #pass try: - fami_start_to_buy_button.click() + driver.execute_script("arguments[0].click();", fami_start_to_buy_button) except Exception as exc: - print("click buyWaiting button fail...") - #print(exc) - #pass - try: - driver.execute_script("arguments[0].click();", fami_start_to_buy_button) - except Exception as exc: - pass + pass -def fami_home(driver, url): - print("fami_home bingo") +def fami_home(driver, url, config_dict): + #print("fami_home bingo") global is_assign_ticket_number global ticket_number @@ -2974,58 +3023,73 @@ def fami_home(driver, url): global area_auto_select_mode - is_select_box_visible = False #--------------------------- # part 3: fill ticket number. #--------------------------- ticket_el = None - is_assign_ticket_number = False try: my_css_selector = "tr.ticket > td > select" ticket_el = driver.find_element(By.CSS_SELECTOR, my_css_selector) - if ticket_el is not None: - if ticket_el.is_enabled(): - is_select_box_visible = True - - ticket_number_select = Select(ticket_el) - if ticket_number_select is not None: - try: - #print("get select ticket value:" + Select(ticket_number_select).first_selected_option.text) - if ticket_number_select.first_selected_option.text=="0" or ticket_number_select.first_selected_option.text=="選擇張數": - # target ticket number - ticket_number_select.select_by_visible_text(ticket_number) - is_assign_ticket_number = True - except Exception as exc: - print("select_by_visible_text ticket_number fail") - print(exc) - - try: - # try target ticket number twice - ticket_number_select.select_by_visible_text(ticket_number) - is_assign_ticket_number = True - except Exception as exc: - print("select_by_visible_text ticket_number fail...2") - print(exc) - - # try buy one ticket - try: - ticket_number_select.select_by_visible_text("1") - is_assign_ticket_number = True - except Exception as exc: - print("select_by_visible_text 1 fail") - pass except Exception as exc: pass print("click buyWaiting button fail") #print(exc) + is_select_box_visible = False + if ticket_el is not None: + try: + if ticket_el.is_enabled(): + is_select_box_visible = True + except Exception as exc: + pass + + is_assign_ticket_number = False + if is_select_box_visible: + ticket_number_select = None + try: + ticket_number_select = Select(ticket_el) + except Exception as exc: + pass + + if ticket_number_select is not None: + try: + #print("get select ticket value:" + Select(ticket_number_select).first_selected_option.text) + if ticket_number_select.first_selected_option.text=="0" or ticket_number_select.first_selected_option.text=="選擇張數": + # target ticket number + ticket_number_select.select_by_visible_text(ticket_number) + is_assign_ticket_number = True + except Exception as exc: + print("select_by_visible_text ticket_number fail") + print(exc) + + try: + # try target ticket number twice + ticket_number_select.select_by_visible_text(ticket_number) + is_assign_ticket_number = True + except Exception as exc: + print("select_by_visible_text ticket_number fail...2") + print(exc) + + # try buy one ticket + try: + ticket_number_select.select_by_visible_text("1") + is_assign_ticket_number = True + except Exception as exc: + print("select_by_visible_text 1 fail") + pass + #--------------------------- # part 4: press "next" button. #--------------------------- if is_assign_ticket_number: - my_css_selector = "div.col > a.btn" - fami_assign_site_button = driver.find_element(By.CSS_SELECTOR, my_css_selector) + fami_assign_site_button = None + try: + my_css_selector = "div.col > a.btn" + fami_assign_site_button = driver.find_element(By.CSS_SELECTOR, my_css_selector) + except Exception as exc: + pass + if fami_assign_site_button is not None: is_visible = False try: @@ -3050,7 +3114,7 @@ def fami_home(driver, url): #--------------------------- # part 2: select keywords #--------------------------- - areas = get_fami_target_area(date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode) + areas = get_fami_target_area(driver, date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode) area_target = None if areas is not None: @@ -3130,7 +3194,7 @@ def urbtix_ticket_number_auto_select(driver, url, ticket_number): except Exception as exc: print("find ticket_number select fail...") - time.sleep(0.1) + #time.sleep(0.1) #print(exc) pass @@ -3248,7 +3312,7 @@ def urbtix_next_button_press(driver, url): return ret -def urbtix_performance(driver, url): +def urbtix_performance(driver, url, config_dict): #print("urbtix performance bingo") global auto_fill_ticket_number @@ -3494,7 +3558,7 @@ def cityline_next_button_press(url): return ret -def cityline_event(driver, url): +def cityline_event(driver): ret = False is_non_member_displayed = False @@ -3569,7 +3633,7 @@ def cityline_captcha_auto_focus(url): return ret -def cityline_performance(driver, url): +def cityline_performance(driver, url, config_dict): #print("cityline bingo") if "performance.do;" in url: cityline_captcha_auto_focus(url) @@ -3599,35 +3663,142 @@ def cityline_performance(driver, url): if click_ret: break - -def facebook_login(driver, url): +def facebook_login(driver, facebook_account): ret = False + el_email = None try: - el = driver.find_element(By.CSS_SELECTOR, '#email') - if el is not None: - ret = True - if el.is_enabled(): - inputed_text = el.get_attribute('value') - if len(inputed_text) == 0: - el.send_keys(facebook_account) - ret = True + el_email = driver.find_element(By.CSS_SELECTOR, '#email') except Exception as exc: #print("find #email fail") #print(exc) pass + is_visible = False + if el_email is not None: + try: + if el_email.is_enabled(): + if el_email.is_displayed(): + is_visible = True + except Exception as exc: + #print("find #email fail") + #print(exc) + pass + + is_email_sent = False + if is_visible: + try: + inputed_text = el_email.get_attribute('value') + if inputed_text is not None: + if len(inputed_text) == 0: + el_email.send_keys(facebook_account) + is_email_sent = True + except Exception as exc: + #print("find #email fail") + #print(exc) + pass + + el_pass = None + if is_email_sent: + try: + el_pass = driver.find_element(By.CSS_SELECTOR, '#pass') + except Exception as exc: + #print("find #email fail") + #print(exc) + pass + + is_visible = False + if el_pass is not None: + try: + if el_pass.is_enabled(): + if el_pass.is_displayed(): + is_visible = True + except Exception as exc: + #print("find #email fail") + #print(exc) + pass + + if is_visible: + try: + el_pass.click() + except Exception as exc: + #print("find #email fail") + #print(exc) + pass + return ret +def play_mp3(sound_filename): + import threading + from playsound import playsound + try: + threading.Thread(target=playsound, args=(sound_filename,), daemon=True).start() + #playsound(sound_filename) + except Exception as exc: + msg=str(exc) + print("play sound exeption:", msg) + +# purpose: check alert poped. +# PS: current version not enable... +def check_pop_alert(driver): + is_alert_popup = False + + # https://stackoverflow.com/questions/57481723/is-there-a-change-in-the-handling-of-unhandled-alert-in-chromedriver-and-chrome + default_close_alert_text = [] + if len(default_close_alert_text) > 0: + try: + alert = None + if not driver is None: + alert = driver.switch_to.alert + if not alert is None: + if not alert.text is None: + is_match_auto_close_text = False + for txt in default_close_alert_text: + if len(txt) > 0: + if txt in alert.text: + is_match_auto_close_text = True + #print("alert3 text:", alert.text) + + if is_match_auto_close_text: + alert.accept() + print("alert3 accepted") + + is_alert_popup = True + else: + print("alert3 not detected") + except NoAlertPresentException as exc1: + #logger.error('NoAlertPresentException for alert') + pass + except NoSuchWindowException: + #print('NoSuchWindowException2 at this url:', url ) + #print("last_url:", last_url) + try: + window_handles_count = len(driver.window_handles) + if window_handles_count >= 1: + driver.switch_to.window(driver.window_handles[0]) + except Exception as excSwithFail: + pass + except Exception as exc: + logger.error('Exception2 for alert') + logger.error(exc, exc_info=True) + + return is_alert_popup def main(): - global driver - driver = load_config_from_local(driver) + config_dict = get_config_dict() + + driver_type = 'selenium' + #driver_type = 'stealth' + driver_type = 'undetected_chromedriver' + + driver = get_driver_by_config(config_dict, driver_type) # internal variable. 說明:這是一個內部變數,請略過。 url = "" last_url = "" + # for tixcraft is_verifyCode_editing = False + is_finish_checkbox_click = False # for kktix answer_index = -1 @@ -3647,44 +3818,7 @@ def main(): print("web driver not accessible!") break - # https://stackoverflow.com/questions/57481723/is-there-a-change-in-the-handling-of-unhandled-alert-in-chromedriver-and-chrome - default_close_alert_text = [] - if len(default_close_alert_text) > 0: - try: - alert = None - if not driver is None: - alert = driver.switch_to.alert - if not alert is None: - if not alert.text is None: - is_match_auto_close_text = False - for txt in default_close_alert_text: - if len(txt) > 0: - if txt in alert.text: - is_match_auto_close_text = True - #print("alert3 text:", alert.text) - - if is_match_auto_close_text: - alert.accept() - print("alert3 accepted") - - is_alert_popup = True - else: - print("alert3 not detected") - except NoAlertPresentException as exc1: - #logger.error('NoAlertPresentException for alert') - pass - except NoSuchWindowException: - #print('NoSuchWindowException2 at this url:', url ) - #print("last_url:", last_url) - try: - window_handles_count = len(driver.window_handles) - if window_handles_count >= 1: - driver.switch_to.window(driver.window_handles[0]) - except Exception as excSwithFail: - pass - except Exception as exc: - logger.error('Exception2 for alert') - logger.error(exc, exc_info=True) + is_alert_popup = check_pop_alert(driver) #MUST "do nothing: if alert popup. #print("is_alert_popup:", is_alert_popup) @@ -3761,6 +3895,7 @@ def main(): sys.exit() break + # not is above case, print exception. print("Exception:", str_exc) pass @@ -3779,7 +3914,7 @@ def main(): print(url) last_url = url - # for Max's test. + # for Max's manuall test. if '/Downloads/varify.html' in url: tixcraft_verify(driver, url) @@ -3813,53 +3948,41 @@ def main(): # start to redirecting. continue - global date_auto_select_enable - global date_auto_select_mode - global date_keyword - - global pass_date_is_sold_out_enable - global auto_reload_coming_soon_page_enable - is_date_selected = False + date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"] if date_auto_select_enable: - is_date_selected = date_auto_select(driver, url, date_auto_select_mode, date_keyword, pass_date_is_sold_out_enable, auto_reload_coming_soon_page_enable) + is_date_selected = tixcraft_date_auto_select(driver, url, config_dict) if is_date_selected: # start to redirecting. continue # choose area - global area_auto_select_enable - global pass_1_seat_remaining_enable - - global area_keyword_1 - global area_keyword_2 - global area_keyword_3 - global area_keyword_4 - + area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"] if area_auto_select_enable: - area_auto_select(driver, url, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode, pass_1_seat_remaining_enable) + tixcraft_area_auto_select(driver, url, config_dict) if '/ticket/verify/' in url: tixcraft_verify(driver, url) # main app, to select ticket number. if '/ticket/ticket/' in url: - is_verifyCode_editing = tixcraft_ticket_main(driver, url, is_verifyCode_editing) + if not is_verifyCode_editing: + is_verifyCode_editing, is_finish_checkbox_click = tixcraft_ticket_main(driver, config_dict, is_finish_checkbox_click) else: - # not is input verify code, reset flag. is_verifyCode_editing = False - - global auto_press_next_step_button + is_finish_checkbox_click = False # for kktix.cc and kktix.com if 'kktix.c' in url: + auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"] + # fix https://kktix.com/users/sign_in?back_to=https://kktix.com/events/xxxx and registerStatus: SOLD_OUT cause page refresh. if '/users/sign_in' in url: continue if '/registrations/new' in url: - answer_index, kktix_register_status_last = kktix_reg_new(driver, url, answer_index, kktix_register_status_last) + answer_index, kktix_register_status_last = kktix_reg_new(driver, url, answer_index, kktix_register_status_last, config_dict) else: is_event_page = False if '/events/' in url: @@ -3879,10 +4002,9 @@ def main(): # for famiticket if 'famiticket.com' in url: if '/Home/Activity/Info/' in url: - fami_activity(driver, url) + fami_activity(driver) if '/Sales/Home/Index/' in url: - fami_home(driver, url) - + fami_home(driver, url, config_dict) # for urbtix # https://ticket.urbtix.hk/internet/secure/event/37348/performanceDetail @@ -3910,11 +4032,11 @@ def main(): pass if '/performanceDetail/' in url: - urbtix_performance(driver, url) + urbtix_performance(driver, url, config_dict) if 'cityline.com' in url: if '/event.do' in url: - cityline_event(driver, url) + cityline_event(driver) #pass if '/Events.do' in url: @@ -3925,8 +4047,15 @@ def main(): pass if '/performance.do' in url: - cityline_performance(driver, url) + cityline_performance(driver, url, config_dict) + # for facebook + facebook_login_url = 'https://www.facebook.com/login.php?' + + if url[:len(facebook_login_url)]==facebook_login_url: + facebook_account = config_dict["advanced"]["facebook_account"].strip() + if len(facebook_account) > 4: + facebook_login(driver, facebook_account) if __name__ == "__main__": main() diff --git a/ding-dong.mp3 b/ding-dong.mp3 new file mode 100644 index 0000000..7b216ec Binary files /dev/null and b/ding-dong.mp3 differ diff --git a/ding.mp3 b/ding.mp3 new file mode 100644 index 0000000..1d3b97f Binary files /dev/null and b/ding.mp3 differ diff --git a/icon_play_3.gif b/icon_play_3.gif new file mode 100644 index 0000000..aa89516 Binary files /dev/null and b/icon_play_3.gif differ diff --git a/pip-reg.txt b/pip-reg.txt index 643ee1e..0b2e318 100644 --- a/pip-reg.txt +++ b/pip-reg.txt @@ -4,4 +4,5 @@ cryptography idna selenium selenium-stealth -undetected-chromedriver \ No newline at end of file +undetected-chromedriver +playsound \ No newline at end of file diff --git a/settings.json b/settings.json index ca64411..7d318a7 100644 --- a/settings.json +++ b/settings.json @@ -1 +1 @@ -{"tixcraft": {"pass_1_seat_remaining": true, "area_auto_select": {"mode": "from top to bottom", "enable": true, "area_keyword_1": "", "area_keyword_2": "", "area_keyword": "", "area_keyword_3": "", "area_keyword_4": ""}, "auto_reload_coming_soon_page": true, "date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true}, "homepage1": "https://kktix.com", "homepage2": "https://tixcraft.com", "debug": false, "facebook_account": "", "browser1": "chrome", "browser2": "firefox", "kktix": {"auto_guess_options": true, "auto_fill_ticket_price": "$1,500", "answer_dictionary": "", "area_keyword": "", "auto_press_next_step_button": true, "auto_fill_ticket_number": true, "area_mode": "from top to bottom", "date_keyword": ""}, "ticket_number": 2, "homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587"} \ No newline at end of file +{"tixcraft": {"pass_1_seat_remaining": true, "area_auto_select": {"enable": true, "area_keyword": "", "mode": "from top to bottom", "area_keyword_4": "", "area_keyword_1": "", "area_keyword_2": "", "area_keyword_3": ""}, "auto_reload_coming_soon_page": true, "date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true}, "homepage1": "https://kktix.com", "language": "\u7e41\u9ad4\u4e2d\u6587", "homepage2": "https://tixcraft.com", "kktix": {"auto_guess_options": true, "answer_dictionary": "", "area_keyword": "", "auto_press_next_step_button": true, "area_mode": "from top to bottom", "auto_fill_ticket_number": true, "auto_fill_ticket_price": "$1,500", "date_keyword": ""}, "facebook_account": "", "browser1": "chrome", "browser2": "firefox", "debug": false, "ticket_number": 2, "homepage": "https://tixcraft.com", "browser": "chrome", "advanced": {"play_captcha_sound": {"enable": true, "filename": "ding-dong.mp3"}, "facebook_account": ""}} \ No newline at end of file diff --git a/settings.py b/settings.py index 6f9dbc4..5f96106 100644 --- a/settings.py +++ b/settings.py @@ -20,7 +20,7 @@ import platform import json import webbrowser -CONST_APP_VERSION = u"MaxBot (2022.11.14) ver.5" +CONST_APP_VERSION = u"MaxBot (2022.11.16)" CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom" CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top" @@ -42,6 +42,7 @@ translate={} URL_DONATE = 'https://max-everyday.com/about/#donate' URL_HELP = 'https://max-everyday.com/2018/03/tixcraft-bot/' URL_RELEASE = 'https://github.com/max32002/tixcraft_bot/releases' +URL_FB = 'https://www.facebook.com/maxbot.ticket' def load_translate(): @@ -72,15 +73,22 @@ def load_translate(): en_us["pass_date_is_sold_out"] = 'Pass date is sold out' en_us["auto_reload_coming_soon_page"] = 'Reload coming soon page' + en_us["preference"] = 'Preference' + en_us["advanced"] = 'Advanced' + en_us["about"] = 'About' + en_us["run"] = 'Run' en_us["save"] = 'Save' + en_us["exit"] = 'Close' + + en_us["play_captcha_sound"] = 'Play sound when captcha' + en_us["captcha_sound_filename"] = 'captcha sound filename' + en_us["facebook_account"] = 'Facebook account' + + en_us["maxbot_slogan"] = 'MaxBot is a FREE and open source bot program. Good luck getting your expected ticket.' en_us["donate"] = 'Donate' en_us["help"] = 'Help' - en_us["preference"] = 'Preference' en_us["release"] = 'Release' - en_us["exit"] = 'Close' - en_us["about"] = 'About' - en_us["maxbot_slogan"] = 'MaxBot is a FREE and open source bot program. Good luck getting your expected ticket.' zh_tw={} zh_tw["homepage"] = '售票網站' @@ -108,15 +116,22 @@ def load_translate(): zh_tw["pass_date_is_sold_out"] = '避開「搶購一空」的場次' zh_tw["auto_reload_coming_soon_page"] = '自動刷新倒數中的活動頁面' + zh_tw["preference"] = '偏好設定' + zh_tw["advanced"] = '進階設定' + zh_tw["about"] = '關於' + zh_tw["run"] = '搶票' zh_tw["save"] = '存檔' - zh_tw["donate"] = '打賞' - zh_tw["help"] = '使用教學' - zh_tw["preference"] = '偏好設定' - zh_tw["release"] = '所有可用版本' zh_tw["exit"] = '關閉' - zh_tw["about"] = '關於' + + zh_tw["play_captcha_sound"] = '輸入驗證碼時播放音效' + zh_tw["captcha_sound_filename"] = '驗證碼用音效檔' + zh_tw["facebook_account"] = 'Facebook 帳號' + zh_tw["maxbot_slogan"] = 'MaxBot是一個免費、開放原始碼的搶票機器人。\n祝你好運,買得到預期中的票。' + zh_tw["donate"] = '打賞' + zh_tw["release"] = '所有可用版本' + zh_tw["help"] = '使用教學' zh_cn={} zh_cn["homepage"] = '售票网站' @@ -143,16 +158,23 @@ def load_translate(): zh_cn["pass_1_seat_remaining"] = '避开“剩余 1”的区域' zh_cn["pass_date_is_sold_out"] = '避开“抢购一空”的场次' zh_cn["auto_reload_coming_soon_page"] = '自动刷新倒数中的活动页面' - zh_cn["maxbot_slogan"] = 'MaxBot 是一个免费的开源机器人程序。\n祝你好运,买得到预期中的票。' + + zh_cn["preference"] = '偏好设定' + zh_cn["advanced"] = '進階設定' + zh_cn["about"] = '关于' zh_cn["run"] = '抢票' zh_cn["save"] = '存档' + zh_cn["exit"] = '关闭' + + zh_cn["play_captcha_sound"] = '輸入驗證碼時播放音效' + zh_cn["captcha_sound_filename"] = '驗證碼用音效檔' + zh_cn["facebook_account"] = 'Facebook 帳號' + + zh_cn["maxbot_slogan"] = 'MaxBot 是一个免费的开源机器人程序。\n祝你好运,买得到预期中的票。' zh_cn["donate"] = '打赏' zh_cn["help"] = '使用教学' - zh_cn["preference"] = '偏好设定' zh_cn["release"] = '所有可用版本' - zh_cn["exit"] = '关闭' - zh_cn["about"] = '关于' ja_jp={} ja_jp["homepage"] = 'ホームページ' @@ -180,15 +202,22 @@ def load_translate(): ja_jp["pass_date_is_sold_out"] = '「売り切れ」公演を避ける' ja_jp["auto_reload_coming_soon_page"] = '公開予定のページをリロード' + ja_jp["preference"] = '設定' + ja_jp["advanced"] = '高度な設定' + ja_jp["about"] = '情報' + ja_jp["run"] = 'チケットを取る' ja_jp["save"] = '保存' + ja_jp["exit"] = '閉じる' + + ja_jp["play_captcha_sound"] = 'キャプチャ時に音を鳴らす' + ja_jp["captcha_sound_filename"] = 'サウンドファイル名' + ja_jp["facebook_account"] = 'Facebookのアカウント' + + ja_jp["maxbot_slogan"] = 'MaxBot は無料のオープン ソース ボット プログラムです。 頑張って予定のチケットを手に入れてください。' ja_jp["donate"] = '寄付' ja_jp["help"] = '利用方法' - ja_jp["preference"] = '設定' ja_jp["release"] = 'リリース' - ja_jp["exit"] = '閉じる' - ja_jp["about"] = '情報' - ja_jp["maxbot_slogan"] = 'MaxBot は無料のオープン ソース ボット プログラムです。 頑張って予定のチケットを手に入れてください。' translate['en_us']=en_us translate['zh_tw']=zh_tw @@ -196,7 +225,7 @@ def load_translate(): translate['ja_jp']=ja_jp return translate -def load_json(): +def get_app_root(): # 讀取檔案裡的參數值 basis = "" if hasattr(sys, 'frozen'): @@ -204,6 +233,10 @@ def load_json(): else: basis = sys.argv[0] app_root = os.path.dirname(basis) + return app_root + +def load_json(): + app_root = get_app_root() # overwrite config path. config_filepath = os.path.join(app_root, 'settings.json') @@ -231,7 +264,6 @@ def btn_save_act(slience_mode=False): global combo_browser global combo_language global combo_ticket_number - #global txt_facebook_account global chk_state_auto_press_next_step_button global chk_state_auto_fill_ticket_number @@ -254,11 +286,14 @@ def btn_save_act(slience_mode=False): global combo_area_auto_select_mode global chk_state_pass_1_seat_remaining - global chk_state_pass_date_is_sold_out - global chk_state_auto_reload_coming_soon_page + global txt_facebook_account + global chk_state_play_captcha_sound + global txt_captcha_sound_filename + + if is_all_data_correct: if combo_homepage.get().strip()=="": is_all_data_correct = False @@ -288,10 +323,9 @@ def btn_save_act(slience_mode=False): config_dict["ticket_number"] = int(combo_ticket_number.get().strip()) if is_all_data_correct: - #config_dict["facebook_account"] = txt_facebook_account.get().strip() - pass + if not 'kktix' in config_dict: + config_dict['kktix']={} - if is_all_data_correct: config_dict["kktix"]["auto_press_next_step_button"] = bool(chk_state_auto_press_next_step_button.get()) config_dict["kktix"]["auto_fill_ticket_number"] = bool(chk_state_auto_fill_ticket_number.get()) config_dict["kktix"]["area_mode"] = combo_kktix_area_mode.get().strip() @@ -301,6 +335,9 @@ def btn_save_act(slience_mode=False): #config_dict["kktix"]["answer_dictionary"] = txt_kktix_answer_dictionary.get().strip() config_dict["kktix"]["auto_guess_options"] = bool(chk_state_auto_guess_options.get()) + if not 'tixcraft' in config_dict: + config_dict['tixcraft']={} + config_dict["tixcraft"]["date_auto_select"]["enable"] = bool(chk_state_date_auto_select.get()) config_dict["tixcraft"]["date_auto_select"]["date_keyword"] = txt_date_keyword.get().strip() @@ -317,6 +354,17 @@ def btn_save_act(slience_mode=False): config_dict["tixcraft"]["pass_date_is_sold_out"] = bool(chk_state_pass_date_is_sold_out.get()) config_dict["tixcraft"]["auto_reload_coming_soon_page"] = bool(chk_state_auto_reload_coming_soon_page.get()) + if not 'advanced' in config_dict: + config_dict['advanced']={} + + if not 'play_captcha_sound' in config_dict['advanced']: + config_dict['advanced']['play_captcha_sound']={} + + config_dict["advanced"]["play_captcha_sound"]["enable"] = bool(chk_state_play_captcha_sound.get()) + config_dict["advanced"]["play_captcha_sound"]["filename"] = txt_captcha_sound_filename.get().strip() + + config_dict["advanced"]["facebook_account"] = txt_facebook_account.get().strip() + # save config. if is_all_data_correct: import json @@ -376,9 +424,28 @@ def btn_run_clicked(): s=subprocess.Popen([interpreter_binary_alt, 'chrome_tixcraft.py'], cwd=working_dir) except Exception as exc: msg=str(exc) - messagebox.showinfo(title="Debug2", message=msg) + print("exeption:", msg) + #messagebox.showinfo(title="Debug2", message=msg) pass +def btn_preview_sound_clicked(): + global txt_captcha_sound_filename + new_sound_filename = txt_captcha_sound_filename.get().strip() + #print("new_sound_filename:", new_sound_filename) + app_root = get_app_root() + new_sound_filename = os.path.join(app_root, new_sound_filename) + play_mp3(new_sound_filename) + +def play_mp3(sound_filename): + import threading + from playsound import playsound + try: + threading.Thread(target=playsound, args=(sound_filename,), daemon=True).start() + #playsound(sound_filename) + except Exception as exc: + msg=str(exc) + print("play sound exeption:", msg) + def open_url(url): webbrowser.open_new(url) @@ -449,6 +516,7 @@ def applyNewLanguage(): global chk_pass_1_seat_remaining global chk_pass_date_is_sold_out global chk_auto_reload_coming_soon_page + global chk_play_captcha_sound global tabControl @@ -489,9 +557,18 @@ def applyNewLanguage(): chk_pass_1_seat_remaining.config(text=translate[language_code]["enable"]) chk_pass_date_is_sold_out.config(text=translate[language_code]["enable"]) chk_auto_reload_coming_soon_page.config(text=translate[language_code]["enable"]) + chk_play_captcha_sound.config(text=translate[language_code]["enable"]) tabControl.tab(0, text=translate[language_code]["preference"]) - tabControl.tab(1, text=translate[language_code]["about"]) + tabControl.tab(1, text=translate[language_code]["advanced"]) + tabControl.tab(2, text=translate[language_code]["about"]) + + global lbl_facebook_account + global lbl_play_captcha_sound + global lbl_captcha_sound_filename + lbl_facebook_account.config(text=translate[language_code]["facebook_account"]) + lbl_play_captcha_sound.config(text=translate[language_code]["play_captcha_sound"]) + lbl_captcha_sound_filename.config(text=translate[language_code]["captcha_sound_filename"]) lbl_slogan.config(text=translate[language_code]["maxbot_slogan"]) lbl_help.config(text=translate[language_code]["help"]) @@ -663,21 +740,6 @@ def showHideTixcraftBlocks(): def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): - global lbl_homepage - global lbl_browser - global lbl_language - global lbl_ticket_number - - global lbl_kktix - global lbl_tixcraft - - lbl_homepage = None - lbl_browser = None - lbl_language = None - lbl_ticket_number = None - lbl_kktix = None - lbl_tixcraft = None - homepage = None browser = None language = "English" @@ -729,32 +791,21 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): if u'ticket_number' in config_dict: ticket_number = str(config_dict["ticket_number"]) - facebook_account = "" - if 'facebook_account' in config_dict: - facebook_account = str(config_dict["facebook_account"]) - # for ["kktix"] if 'kktix' in config_dict: auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"] auto_fill_ticket_number = config_dict["kktix"]["auto_fill_ticket_number"] if 'area_mode' in config_dict["kktix"]: - kktix_area_mode = config_dict["kktix"]["area_mode"] - kktix_area_mode = kktix_area_mode.strip() + kktix_area_mode = config_dict["kktix"]["area_mode"].strip() if not kktix_area_mode in CONST_SELECT_OPTIONS_ARRAY: kktix_area_mode = CONST_SELECT_ORDER_DEFAULT if 'area_keyword' in config_dict["kktix"]: - kktix_area_keyword = config_dict["kktix"]["area_keyword"] - if kktix_area_keyword is None: - kktix_area_keyword = "" - kktix_area_keyword = kktix_area_keyword.strip() + kktix_area_keyword = config_dict["kktix"]["area_keyword"].strip() if 'date_keyword' in config_dict["kktix"]: - kktix_date_keyword = config_dict["kktix"]["date_keyword"] - if kktix_date_keyword is None: - kktix_date_keyword = "" - kktix_date_keyword = kktix_date_keyword.strip() + kktix_date_keyword = config_dict["kktix"]["date_keyword"].strip() if 'auto_guess_options' in config_dict["kktix"]: auto_guess_options = config_dict["kktix"]["auto_guess_options"] @@ -793,21 +844,16 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): area_auto_select_mode = CONST_SELECT_ORDER_DEFAULT if 'area_keyword_1' in config_dict["tixcraft"]["area_auto_select"]: - area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"] - area_keyword_1 = area_keyword_1.strip() + area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip() if 'area_keyword_2' in config_dict["tixcraft"]["area_auto_select"]: - area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"] - area_keyword_2 = area_keyword_2.strip() - + area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip() if 'area_keyword_3' in config_dict["tixcraft"]["area_auto_select"]: - area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"] - area_keyword_3 = area_keyword_3.strip() + area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip() if 'area_keyword_4' in config_dict["tixcraft"]["area_auto_select"]: - area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"] - area_keyword_4 = area_keyword_4.strip() + area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip() pass_1_seat_remaining_enable = False if 'pass_1_seat_remaining' in config_dict["tixcraft"]: @@ -828,7 +874,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): print("browser", browser) print("language", language) print("ticket_number", ticket_number) - print("facebook_account", facebook_account) # for kktix print("==[kktix]==") @@ -863,6 +908,14 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): else: print('config is none') + global lbl_homepage + global lbl_browser + global lbl_language + global lbl_ticket_number + + global lbl_kktix + global lbl_tixcraft + row_count = 0 frame_group_header = Frame(root) @@ -872,10 +925,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_homepage = Label(frame_group_header, text=translate[language_code]['homepage']) lbl_homepage.grid(column=0, row=group_row_count, sticky = E) - #global txt_homepage - #txt_homepage = Entry(root, width=20, textvariable = StringVar(root, value=homepage)) - #txt_homepage.grid(column=1, row=row_count) - global combo_homepage combo_homepage = ttk.Combobox(frame_group_header, state="readonly") combo_homepage['values']= ("https://kktix.com","https://tixcraft.com","https://www.indievox.com/","https://www.famiticket.com.tw","http://www.urbtix.hk/","https://www.cityline.com/") @@ -923,6 +972,7 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): global combo_ticket_number # for text format. + # PS: some user keyin wrong type. @_@; ''' global combo_ticket_number_value combo_ticket_number_value = StringVar(frame_group_header, value=ticket_number) @@ -930,26 +980,13 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): combo_ticket_number.grid(column=1, row=group_row_count, sticky = W) ''' combo_ticket_number = ttk.Combobox(frame_group_header, state="readonly") - combo_ticket_number['values']= ("1","2","3","4","5","6","7","8","9","10") + combo_ticket_number['values']= ("1","2","3","4","5","6","7","8","9","10","11","12") #combo_ticket_number.current(0) combo_ticket_number.set(ticket_number) combo_ticket_number.grid(column=1, row=group_row_count, sticky = W) frame_group_header.grid(column=0, row=row_count, sticky = W, padx=UI_PADDING_X) - ''' - row_count+=1 - - lbl_facebook_account = Label(root, text="Facebook Account") - lbl_facebook_account.grid(column=0, row=row_count, sticky = E) - - global txt_facebook_account - global txt_facebook_account_value - txt_facebook_account_value = StringVar(root, value=facebook_account) - txt_facebook_account = Entry(root, width=20, textvariable = txt_facebook_account_value) - txt_facebook_account.grid(column=1, row=row_count, sticky = W) - ''' - row_count+=1 # for sub group KKTix. @@ -1007,7 +1044,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_kktix_area_keyword.grid(column=0, row=group_row_count, sticky = E) global txt_kktix_area_keyword - global txt_kktix_area_keyword_value txt_kktix_area_keyword_value = StringVar(frame_group_kktix, value=kktix_area_keyword) txt_kktix_area_keyword = Entry(frame_group_kktix, width=20, textvariable = txt_kktix_area_keyword_value) txt_kktix_area_keyword.grid(column=1, row=group_row_count, sticky = W) @@ -1027,7 +1063,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_kktix_date_keyword.grid(column=0, row=group_row_count, sticky = E) global txt_kktix_date_keyword - global txt_kktix_date_keyword_value txt_kktix_date_keyword_value = StringVar(frame_group_kktix, value=kktix_date_keyword) txt_kktix_date_keyword = Entry(frame_group_kktix, width=20, textvariable = txt_kktix_date_keyword_value) txt_kktix_date_keyword.grid(column=1, row=group_row_count, sticky = W) @@ -1042,7 +1077,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): global txt_kktix_answer_dictionary global txt_kktix_answer_dictionary_index txt_kktix_answer_dictionary_index = group_row_count - global txt_kktix_answer_dictionary_value #txt_kktix_answer_dictionary_value = StringVar(frame_group_kktix, value=kktix_answer_dictionary) #txt_kktix_answer_dictionary = Entry(frame_group_kktix, width=20, textvariable = txt_kktix_answer_dictionary_value) #txt_kktix_answer_dictionary.grid(column=1, row=group_row_count, sticky = W) @@ -1117,7 +1151,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_date_keyword.grid(column=0, row=date_keyword_index, sticky = E) global txt_date_keyword - global txt_date_keyword_value txt_date_keyword_value = StringVar(frame_group_tixcraft, value=date_keyword) txt_date_keyword = Entry(frame_group_tixcraft, width=20, textvariable = txt_date_keyword_value) txt_date_keyword.grid(column=1, row=date_keyword_index, sticky = W) @@ -1161,7 +1194,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_area_keyword_1.grid(column=0, row=area_keyword_1_index, sticky = E) global txt_area_keyword_1 - global txt_area_keyword_1_value txt_area_keyword_1_value = StringVar(frame_group_tixcraft, value=area_keyword_1) txt_area_keyword_1 = Entry(frame_group_tixcraft, width=20, textvariable = txt_area_keyword_1_value) txt_area_keyword_1.grid(column=1, row=area_keyword_1_index, sticky = W) @@ -1176,7 +1208,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_area_keyword_2.grid(column=0, row=area_keyword_2_index, sticky = E) global txt_area_keyword_2 - global txt_area_keyword_2_value txt_area_keyword_2_value = StringVar(frame_group_tixcraft, value=area_keyword_2) txt_area_keyword_2 = Entry(frame_group_tixcraft, width=20, textvariable = txt_area_keyword_2_value) txt_area_keyword_2.grid(column=1, row=area_keyword_2_index, sticky = W) @@ -1191,7 +1222,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_area_keyword_3.grid(column=0, row=area_keyword_3_index, sticky = E) global txt_area_keyword_3 - global txt_area_keyword_3_value txt_area_keyword_3_value = StringVar(frame_group_tixcraft, value=area_keyword_3) txt_area_keyword_3 = Entry(frame_group_tixcraft, width=20, textvariable = txt_area_keyword_3_value) txt_area_keyword_3.grid(column=1, row=area_keyword_3_index, sticky = W) @@ -1206,7 +1236,6 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): lbl_area_keyword_4.grid(column=0, row=area_keyword_4_index, sticky = E) global txt_area_keyword_4 - global txt_area_keyword_4_value txt_area_keyword_4_value = StringVar(frame_group_tixcraft, value=area_keyword_4) txt_area_keyword_4 = Entry(frame_group_tixcraft, width=20, textvariable = txt_area_keyword_4_value) txt_area_keyword_4.grid(column=1, row=area_keyword_4_index, sticky = W) @@ -1266,6 +1295,85 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X): showHideBlocks(all_layout_visible=True) +def AdvancedTab(root, config_dict, language_code, UI_PADDING_X): + row_count = 0 + + frame_group_header = Frame(root) + group_row_count = 0 + + facebook_account = "" + play_captcha_sound = False + captcha_sound_filename_default = "ding-dong.mp3" + captcha_sound_filename = "" + + if 'advanced' in config_dict: + if 'facebook_account' in config_dict["advanced"]: + facebook_account = config_dict["advanced"]["facebook_account"].strip() + if 'play_captcha_sound' in config_dict["advanced"]: + if 'enable' in config_dict["advanced"]["play_captcha_sound"]: + play_captcha_sound = config_dict["advanced"]["play_captcha_sound"]["enable"] + if 'filename' in config_dict["advanced"]["play_captcha_sound"]: + captcha_sound_filename = config_dict["advanced"]["play_captcha_sound"]["filename"].strip() + + # for kktix + print("==[advanced]==") + print("facebook_account", facebook_account) + print("play_captcha_sound", play_captcha_sound) + print("captcha_sound_filename", captcha_sound_filename) + + + # assign default value. + if captcha_sound_filename is None: + captcha_sound_filename = "" + if len(captcha_sound_filename)==0: + captcha_sound_filename = captcha_sound_filename_default + + + global lbl_facebook_account + lbl_facebook_account = Label(frame_group_header, text=translate[language_code]['facebook_account']) + lbl_facebook_account.grid(column=0, row=group_row_count, sticky = E) + + global txt_facebook_account + txt_facebook_account_value = StringVar(frame_group_header, value=facebook_account) + txt_facebook_account = Entry(frame_group_header, width=20, textvariable = txt_facebook_account_value) + txt_facebook_account.grid(column=1, row=group_row_count, sticky = W) + + group_row_count +=1 + + global lbl_play_captcha_sound + lbl_play_captcha_sound = Label(frame_group_header, text=translate[language_code]['play_captcha_sound']) + lbl_play_captcha_sound.grid(column=0, row=group_row_count, sticky = E) + + global chk_state_play_captcha_sound + chk_state_play_captcha_sound = BooleanVar() + chk_state_play_captcha_sound.set(play_captcha_sound) + + global chk_play_captcha_sound + chk_play_captcha_sound = Checkbutton(frame_group_header, text=translate[language_code]['enable'], variable=chk_state_play_captcha_sound) + chk_play_captcha_sound.grid(column=1, row=group_row_count, sticky = W) + + group_row_count +=1 + + global lbl_captcha_sound_filename + lbl_captcha_sound_filename = Label(frame_group_header, text=translate[language_code]['captcha_sound_filename']) + lbl_captcha_sound_filename.grid(column=0, row=group_row_count, sticky = E) + + #print("captcha_sound_filename:", captcha_sound_filename) + global txt_captcha_sound_filename + txt_captcha_sound_filename_value = StringVar(frame_group_header, value=captcha_sound_filename) + txt_captcha_sound_filename = Entry(frame_group_header, width=20, textvariable = txt_captcha_sound_filename_value) + txt_captcha_sound_filename.grid(column=1, row=group_row_count, sticky = W) + + icon_play_filename = "icon_play_3.gif" + icon_play_img = PhotoImage(file=icon_play_filename) + + lbl_icon_play = Label(frame_group_header, image=icon_play_img, cursor="hand2") + lbl_icon_play.image = icon_play_img + lbl_icon_play.grid(column=3, row=group_row_count) + lbl_icon_play.bind("", lambda e: btn_preview_sound_clicked()) + + frame_group_header.grid(column=0, row=row_count) + def AboutTab(root, language_code): row_count = 0 @@ -1317,8 +1425,37 @@ def AboutTab(root, language_code): lbl_release_url.grid(column=1, row=group_row_count, sticky = W) lbl_release_url.bind("", lambda e: open_url(URL_RELEASE)) + group_row_count +=1 + + lbl_fb_fans = Label(frame_group_header, text=u'Facebook') + lbl_fb_fans.grid(column=0, row=group_row_count, sticky = E) + + lbl_fb_fans_url = Label(frame_group_header, text=URL_FB, fg="blue", cursor="hand2") + lbl_fb_fans_url.grid(column=1, row=group_row_count, sticky = W) + lbl_fb_fans_url.bind("", lambda e: open_url(URL_FB)) + frame_group_header.grid(column=0, row=row_count) +def get_action_bar(root,language_code): + frame_action = Frame(root) + + btn_run = ttk.Button(frame_action, text=translate[language_code]['run'], command=btn_run_clicked) + btn_run.grid(column=0, row=0) + + btn_save = ttk.Button(frame_action, text=translate[language_code]['save'], command=btn_save_clicked) + btn_save.grid(column=1, row=0) + + #btn_donate = ttk.Button(frame_action, text=translate[language_code]['donate'], command=btn_donate_clicked, width=5) + #btn_donate.grid(column=2, row=0) + + #btn_help = ttk.Button(frame_action, text=translate[language_code]['help'], command=btn_help_clicked) + #btn_help.grid(column=2, row=0) + + btn_exit = ttk.Button(frame_action, text=translate[language_code]['exit'], command=btn_exit_clicked) + btn_exit.grid(column=3, row=0) + + return frame_action + def main(): global translate translate = load_translate() @@ -1331,7 +1468,6 @@ def main(): root = Tk() root.title(CONST_APP_VERSION) - #style = ttk.Style(root) #style.theme_use('aqua') @@ -1353,29 +1489,15 @@ def main(): tab1 = Frame(tabControl) tabControl.add(tab1, text=translate[language_code]['preference']) tab2 = Frame(tabControl) - tabControl.add(tab2, text=translate[language_code]['about']) + tabControl.add(tab2, text=translate[language_code]['advanced']) + tab3 = Frame(tabControl) + tabControl.add(tab3, text=translate[language_code]['about']) tabControl.grid(column=0, row=row_count) tabControl.select(tab1) row_count+=1 - frame_action = Frame(root) - - btn_run = ttk.Button(frame_action, text=translate[language_code]['run'], command=btn_run_clicked) - btn_run.grid(column=0, row=0) - - btn_save = ttk.Button(frame_action, text=translate[language_code]['save'], command=btn_save_clicked) - btn_save.grid(column=1, row=0) - - #btn_donate = ttk.Button(frame_action, text=translate[language_code]['donate'], command=btn_donate_clicked, width=5) - #btn_donate.grid(column=2, row=0) - - #btn_help = ttk.Button(frame_action, text=translate[language_code]['help'], command=btn_help_clicked) - #btn_help.grid(column=2, row=0) - - btn_exit = ttk.Button(frame_action, text=translate[language_code]['exit'], command=btn_exit_clicked) - btn_exit.grid(column=3, row=0) - + frame_action = get_action_bar(root,language_code) frame_action.grid(column=0, row=row_count) global UI_PADDING_X @@ -1385,13 +1507,14 @@ def main(): GUI_SIZE_HEIGHT = 550 PreferenctTab(tab1, config_dict, language_code, UI_PADDING_X) - AboutTab(tab2, language_code) + AdvancedTab(tab2, config_dict, language_code, UI_PADDING_X) + AboutTab(tab3, language_code) GUI_SIZE_MACOS = str(GUI_SIZE_WIDTH) + 'x' + str(GUI_SIZE_HEIGHT) GUI_SIZE_WINDOWS=str(GUI_SIZE_WIDTH-60) + 'x' + str(GUI_SIZE_HEIGHT-90) GUI_SIZE =GUI_SIZE_MACOS - import platform + if platform.system() == 'Windows': GUI_SIZE = GUI_SIZE_WINDOWS