add new feature, pass date is sold out event. disable auto reload coming soon page.
parent
d33e805508
commit
76aa579d48
|
@ -51,7 +51,7 @@ ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
#附註1:沒有寫的很好,很多地方應該可以模組化。
|
#附註1:沒有寫的很好,很多地方應該可以模組化。
|
||||||
#附註2:
|
#附註2:
|
||||||
|
|
||||||
CONST_APP_VERSION = u"MaxBot (2022.03.16)"
|
CONST_APP_VERSION = u"MaxBot (2022.03.24)"
|
||||||
|
|
||||||
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
|
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
|
||||||
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
|
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
|
||||||
|
@ -87,6 +87,8 @@ area_keyword_1 = None
|
||||||
area_keyword_2 = None
|
area_keyword_2 = None
|
||||||
|
|
||||||
pass_1_seat_remaining_enable = False # default not checked.
|
pass_1_seat_remaining_enable = False # default not checked.
|
||||||
|
pass_date_is_sold_out_enable = False # default not checked.
|
||||||
|
auto_reload_coming_soon_page_enable = True # default checked.
|
||||||
|
|
||||||
kktix_area_auto_select_mode = None
|
kktix_area_auto_select_mode = None
|
||||||
kktix_area_keyword = None
|
kktix_area_keyword = None
|
||||||
|
@ -136,6 +138,9 @@ def load_config_from_local(driver):
|
||||||
|
|
||||||
global auto_guess_options
|
global auto_guess_options
|
||||||
global pass_1_seat_remaining_enable
|
global pass_1_seat_remaining_enable
|
||||||
|
global pass_date_is_sold_out_enable
|
||||||
|
global auto_reload_coming_soon_page_enable
|
||||||
|
|
||||||
global area_keyword_1
|
global area_keyword_1
|
||||||
global area_keyword_2
|
global area_keyword_2
|
||||||
|
|
||||||
|
@ -239,6 +244,14 @@ def load_config_from_local(driver):
|
||||||
if 'pass_1_seat_remaining' in config_dict["tixcraft"]:
|
if 'pass_1_seat_remaining' in config_dict["tixcraft"]:
|
||||||
pass_1_seat_remaining_enable = config_dict["tixcraft"]["pass_1_seat_remaining"]
|
pass_1_seat_remaining_enable = config_dict["tixcraft"]["pass_1_seat_remaining"]
|
||||||
|
|
||||||
|
pass_date_is_sold_out_enable = False
|
||||||
|
if 'pass_date_is_sold_out' in config_dict["tixcraft"]:
|
||||||
|
pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"]
|
||||||
|
|
||||||
|
auto_reload_coming_soon_page_enable = True
|
||||||
|
if 'auto_reload_coming_soon_page' in config_dict["tixcraft"]:
|
||||||
|
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
|
||||||
|
|
||||||
# output config:
|
# output config:
|
||||||
print("maxbot app version", CONST_APP_VERSION)
|
print("maxbot app version", CONST_APP_VERSION)
|
||||||
print("python version", platform.python_version())
|
print("python version", platform.python_version())
|
||||||
|
@ -267,6 +280,10 @@ def load_config_from_local(driver):
|
||||||
print("area_keyword_2", area_keyword_2)
|
print("area_keyword_2", area_keyword_2)
|
||||||
|
|
||||||
print("pass_1_seat_remaining", pass_1_seat_remaining_enable)
|
print("pass_1_seat_remaining", pass_1_seat_remaining_enable)
|
||||||
|
print("pass_date_is_sold_out", pass_date_is_sold_out_enable)
|
||||||
|
|
||||||
|
print("auto_reload_coming_soon_page", auto_reload_coming_soon_page_enable)
|
||||||
|
|
||||||
print("debug Mode", debugMode)
|
print("debug Mode", debugMode)
|
||||||
|
|
||||||
# entry point
|
# entry point
|
||||||
|
@ -777,6 +794,8 @@ def get_answer_list_by_question(captcha_text_div_text):
|
||||||
|
|
||||||
# from detail to game
|
# from detail to game
|
||||||
def tixcraft_redirect(driver, url):
|
def tixcraft_redirect(driver, url):
|
||||||
|
ret = False
|
||||||
|
|
||||||
game_name = ""
|
game_name = ""
|
||||||
|
|
||||||
# get game_name from url
|
# get game_name from url
|
||||||
|
@ -790,15 +809,18 @@ def tixcraft_redirect(driver, url):
|
||||||
entry_url = url.replace("/activity/detail/","/activity/game/")
|
entry_url = url.replace("/activity/detail/","/activity/game/")
|
||||||
#entry_url = "tixcraft.com/activity/game/%s" % (game_name,)
|
#entry_url = "tixcraft.com/activity/game/%s" % (game_name,)
|
||||||
driver.get(entry_url)
|
driver.get(entry_url)
|
||||||
|
ret = True
|
||||||
|
|
||||||
|
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):
|
||||||
|
is_date_selected = False
|
||||||
|
|
||||||
def date_auto_select(driver, url, date_auto_select_mode, date_keyword):
|
|
||||||
debug_date_select = True # debug.
|
debug_date_select = True # debug.
|
||||||
debug_date_select = False # online
|
debug_date_select = False # online
|
||||||
|
|
||||||
# PS: for big events, check sold out text maybe not helpful, due to database is too busy.
|
# PS: for big events, check sold out text maybe not helpful, due to database is too busy.
|
||||||
is_pass_sold_out = True
|
sold_out_text_list = ["選購一空","No tickets available","空席なし"]
|
||||||
is_pass_sold_out = False
|
|
||||||
sold_out_text = ["選購一空","No tickets available","空席なし"]
|
|
||||||
|
|
||||||
game_name = ""
|
game_name = ""
|
||||||
|
|
||||||
|
@ -812,86 +834,108 @@ def date_auto_select(driver, url, date_auto_select_mode, date_keyword):
|
||||||
print("date_auto_select_mode:", date_auto_select_mode)
|
print("date_auto_select_mode:", date_auto_select_mode)
|
||||||
print("date_keyword:", date_keyword)
|
print("date_keyword:", date_keyword)
|
||||||
|
|
||||||
|
check_game_detail = False
|
||||||
# choose date
|
# choose date
|
||||||
if "/activity/game/%s" % (game_name,) in url:
|
if "/activity/game/%s" % (game_name,) in url:
|
||||||
|
if debug_date_select:
|
||||||
# one or more row is matched.
|
|
||||||
match_keyword_row = False
|
|
||||||
|
|
||||||
if len(date_keyword) == 0:
|
if len(date_keyword) == 0:
|
||||||
if debug_date_select:
|
|
||||||
print("date keyword is empty.")
|
print("date keyword is empty.")
|
||||||
|
|
||||||
el = None
|
|
||||||
|
|
||||||
if date_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
|
|
||||||
try:
|
|
||||||
el = driver.find_element(By.CSS_SELECTOR, '.btn-next')
|
|
||||||
except Exception as exc:
|
|
||||||
print("find .btn-next fail")
|
|
||||||
else:
|
else:
|
||||||
# from down to top
|
|
||||||
# [TODO]: Random selection mode is not implemented..
|
|
||||||
days = None
|
|
||||||
try:
|
|
||||||
days = driver.find_elements(By.CSS_SELECTOR, '.btn-next')
|
|
||||||
if len(days) > 0:
|
|
||||||
el = days[len(days)-1]
|
|
||||||
except Exception as exc:
|
|
||||||
pass
|
|
||||||
#print("find a tag fail")
|
|
||||||
|
|
||||||
if debug_date_select:
|
|
||||||
print("date keyword is empty.")
|
|
||||||
|
|
||||||
if el is not None:
|
|
||||||
# first date.
|
|
||||||
try:
|
|
||||||
el.click()
|
|
||||||
match_keyword_row = True
|
|
||||||
except Exception as exc:
|
|
||||||
print("try to click .btn-next fail")
|
|
||||||
else:
|
|
||||||
if debug_date_select:
|
|
||||||
print("date keyword:", date_keyword)
|
print("date keyword:", date_keyword)
|
||||||
|
check_game_detail = True
|
||||||
|
|
||||||
# match keyword.
|
if check_game_detail:
|
||||||
date_list = None
|
date_list = None
|
||||||
try:
|
try:
|
||||||
date_list = driver.find_elements(By.CSS_SELECTOR, '#gameList > table > tbody > tr')
|
date_list = driver.find_elements(By.CSS_SELECTOR, '#gameList > table > tbody > tr')
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print("find #gameList fail")
|
print("find #gameList fail")
|
||||||
|
|
||||||
|
button_list = []
|
||||||
if date_list is not None:
|
if date_list is not None:
|
||||||
for row in date_list:
|
for row in date_list:
|
||||||
|
# step 1: check keyword.
|
||||||
|
is_match_keyword_row = False
|
||||||
|
|
||||||
row_text = ""
|
row_text = ""
|
||||||
try:
|
try:
|
||||||
row_text = row.text
|
row_text = row.text
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print("get text fail")
|
print("get text fail")
|
||||||
|
# should use continue or break?
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(row_text) > 0:
|
if len(row_text) > 0:
|
||||||
|
if len(date_keyword) == 0:
|
||||||
|
# no keyword, match all.
|
||||||
|
is_match_keyword_row = True
|
||||||
|
else:
|
||||||
|
# check keyword.
|
||||||
if date_keyword in row_text:
|
if date_keyword in row_text:
|
||||||
match_keyword_row = True
|
is_match_keyword_row = True
|
||||||
|
|
||||||
|
|
||||||
|
# step 2: check sold out.
|
||||||
|
if is_match_keyword_row:
|
||||||
|
if pass_date_is_sold_out_enable:
|
||||||
|
for sold_out_item in sold_out_text_list:
|
||||||
|
row_text_right_part = row_text[(len(sold_out_item)+5)*-1:]
|
||||||
|
if debug_date_select:
|
||||||
|
print("check right part text:", row_text_right_part)
|
||||||
|
if sold_out_item in row_text_right_part:
|
||||||
|
is_match_keyword_row = False
|
||||||
|
|
||||||
|
if debug_date_select:
|
||||||
|
print("match sold out text: %s, skip this row." % (sold_out_item))
|
||||||
|
|
||||||
|
# no need check next language item.
|
||||||
|
break
|
||||||
|
|
||||||
|
# step 3: add to list.
|
||||||
|
if is_match_keyword_row:
|
||||||
el = None
|
el = None
|
||||||
try:
|
try:
|
||||||
el = row.find_element(By.CSS_SELECTOR, '.btn-next')
|
el = row.find_element(By.CSS_SELECTOR, '.btn-next')
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
if debug_date_select:
|
||||||
print("find .btn-next fail")
|
print("find .btn-next fail")
|
||||||
|
pass
|
||||||
|
|
||||||
if el is not None:
|
if el is not None:
|
||||||
# first date.
|
button_list.append(el)
|
||||||
|
if date_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
|
||||||
|
# only need one row.
|
||||||
|
if debug_date_select:
|
||||||
|
print("match date row, only need first row, start to break")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if len(button_list) > 0:
|
||||||
|
# default first row.
|
||||||
|
target_row_index = 0
|
||||||
|
|
||||||
|
if date_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
|
||||||
|
target_row_index = len(button_list) - 1
|
||||||
|
|
||||||
|
if date_auto_select_mode == CONST_RANDOM:
|
||||||
|
target_row_index = random.randint(0,len(button_list)-1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if debug_date_select:
|
||||||
|
print("clicking row number:", target_row_index)
|
||||||
|
|
||||||
|
el = button_list[target_row_index]
|
||||||
|
is_date_selected = True
|
||||||
el.click()
|
el.click()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print("try to click .btn-next fail")
|
print("try to click .btn-next fail")
|
||||||
|
|
||||||
if match_keyword_row:
|
# PS: Is this case need to reload page?
|
||||||
break
|
# (A)user input keywords, with matched text, but no hyperlink to click.
|
||||||
|
# (B)user input keywords, but not no matched text with hyperlink to click.
|
||||||
|
|
||||||
if not match_keyword_row:
|
# [PS]: current reload condition only when No hyperlink button.
|
||||||
|
if auto_reload_coming_soon_page_enable and not is_date_selected:
|
||||||
# auto refresh for date list page.
|
# auto refresh for date list page.
|
||||||
el_list = None
|
el_list = None
|
||||||
try:
|
try:
|
||||||
|
@ -905,6 +949,8 @@ def date_auto_select(driver, url, date_auto_select_mode, date_keyword):
|
||||||
pass
|
pass
|
||||||
#print("find .btn-next fail:", exc)
|
#print("find .btn-next fail:", exc)
|
||||||
|
|
||||||
|
return is_date_selected
|
||||||
|
|
||||||
# PURPOSE: get target area list.
|
# PURPOSE: get target area list.
|
||||||
# RETURN:
|
# RETURN:
|
||||||
# is_need_refresh
|
# is_need_refresh
|
||||||
|
@ -3369,14 +3415,25 @@ def main():
|
||||||
# do nothing.
|
# do nothing.
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tixcraft_redirect(driver, url)
|
is_redirected = tixcraft_redirect(driver, url)
|
||||||
|
if is_redirected:
|
||||||
|
# start to redirecting.
|
||||||
|
continue
|
||||||
|
|
||||||
global date_auto_select_enable
|
global date_auto_select_enable
|
||||||
global date_auto_select_mode
|
global date_auto_select_mode
|
||||||
global date_keyword
|
global date_keyword
|
||||||
|
|
||||||
|
global pass_date_is_sold_out_enable
|
||||||
|
global auto_reload_coming_soon_page_enable
|
||||||
|
|
||||||
|
is_date_selected = False
|
||||||
if date_auto_select_enable:
|
if date_auto_select_enable:
|
||||||
date_auto_select(driver, url, date_auto_select_mode, date_keyword)
|
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)
|
||||||
|
|
||||||
|
if is_date_selected:
|
||||||
|
# start to redirecting.
|
||||||
|
continue
|
||||||
|
|
||||||
# choose area
|
# choose area
|
||||||
global area_auto_select_enable
|
global area_auto_select_enable
|
||||||
|
|
49
settings.py
49
settings.py
|
@ -17,7 +17,7 @@ import sys
|
||||||
import platform
|
import platform
|
||||||
import json
|
import json
|
||||||
|
|
||||||
CONST_APP_VERSION = u"MaxBot (2022.03.16)"
|
CONST_APP_VERSION = u"MaxBot (2022.03.24)"
|
||||||
|
|
||||||
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
|
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
|
||||||
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
|
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
|
||||||
|
@ -89,6 +89,10 @@ def btn_save_act(slience_mode=False):
|
||||||
|
|
||||||
global chk_state_pass_1_seat_remaining
|
global chk_state_pass_1_seat_remaining
|
||||||
|
|
||||||
|
global chk_state_pass_date_is_sold_out
|
||||||
|
|
||||||
|
global chk_state_auto_reload_coming_soon_page
|
||||||
|
|
||||||
if is_all_data_correct:
|
if is_all_data_correct:
|
||||||
if combo_homepage.get().strip()=="":
|
if combo_homepage.get().strip()=="":
|
||||||
is_all_data_correct = False
|
is_all_data_correct = False
|
||||||
|
@ -134,6 +138,8 @@ def btn_save_act(slience_mode=False):
|
||||||
config_dict["tixcraft"]["area_auto_select"]["mode"] = combo_area_auto_select_mode.get().strip()
|
config_dict["tixcraft"]["area_auto_select"]["mode"] = combo_area_auto_select_mode.get().strip()
|
||||||
|
|
||||||
config_dict["tixcraft"]["pass_1_seat_remaining"] = bool(chk_state_pass_1_seat_remaining.get())
|
config_dict["tixcraft"]["pass_1_seat_remaining"] = bool(chk_state_pass_1_seat_remaining.get())
|
||||||
|
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())
|
||||||
|
|
||||||
# save config.
|
# save config.
|
||||||
if is_all_data_correct:
|
if is_all_data_correct:
|
||||||
|
@ -373,6 +379,8 @@ def MainMenu(root):
|
||||||
area_keyword_2 = ""
|
area_keyword_2 = ""
|
||||||
|
|
||||||
pass_1_seat_remaining_enable = False # default not checked.
|
pass_1_seat_remaining_enable = False # default not checked.
|
||||||
|
pass_date_is_sold_out_enable = False # default not checked.
|
||||||
|
auto_reload_coming_soon_page_enable = True # default checked.
|
||||||
|
|
||||||
debugMode = False
|
debugMode = False
|
||||||
|
|
||||||
|
@ -463,6 +471,14 @@ def MainMenu(root):
|
||||||
if 'pass_1_seat_remaining' in config_dict["tixcraft"]:
|
if 'pass_1_seat_remaining' in config_dict["tixcraft"]:
|
||||||
pass_1_seat_remaining_enable = config_dict["tixcraft"]["pass_1_seat_remaining"]
|
pass_1_seat_remaining_enable = config_dict["tixcraft"]["pass_1_seat_remaining"]
|
||||||
|
|
||||||
|
pass_date_is_sold_out_enable = False
|
||||||
|
if 'pass_date_is_sold_out' in config_dict["tixcraft"]:
|
||||||
|
pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"]
|
||||||
|
|
||||||
|
auto_reload_coming_soon_page_enable = True
|
||||||
|
if 'auto_reload_coming_soon_page' in config_dict["tixcraft"]:
|
||||||
|
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
|
||||||
|
|
||||||
# output config:
|
# output config:
|
||||||
print("setting app version", CONST_APP_VERSION)
|
print("setting app version", CONST_APP_VERSION)
|
||||||
print("python version", platform.python_version())
|
print("python version", platform.python_version())
|
||||||
|
@ -493,6 +509,9 @@ def MainMenu(root):
|
||||||
print("area_keyword_2", area_keyword_2)
|
print("area_keyword_2", area_keyword_2)
|
||||||
|
|
||||||
print("pass_1_seat_remaining", pass_1_seat_remaining_enable)
|
print("pass_1_seat_remaining", pass_1_seat_remaining_enable)
|
||||||
|
print("pass_date_is_sold_out", pass_date_is_sold_out_enable)
|
||||||
|
|
||||||
|
print("auto_reload_coming_soon_page", auto_reload_coming_soon_page_enable)
|
||||||
|
|
||||||
print("debug Mode", debugMode)
|
print("debug Mode", debugMode)
|
||||||
else:
|
else:
|
||||||
|
@ -788,6 +807,32 @@ def MainMenu(root):
|
||||||
|
|
||||||
group_row_count+=1
|
group_row_count+=1
|
||||||
|
|
||||||
|
lbl_pass_date_is_sold_out = Label(frame_group_tixcraft, text="Pass date is sold out")
|
||||||
|
lbl_pass_date_is_sold_out.grid(column=0, row=group_row_count, sticky = E)
|
||||||
|
|
||||||
|
global chk_state_pass_date_is_sold_out
|
||||||
|
chk_state_pass_date_is_sold_out = BooleanVar()
|
||||||
|
chk_state_pass_date_is_sold_out.set(pass_date_is_sold_out_enable)
|
||||||
|
|
||||||
|
global chk_pass_date_is_sold_out
|
||||||
|
chk_pass_date_is_sold_out = Checkbutton(frame_group_tixcraft, text='Enable', variable=chk_state_pass_date_is_sold_out)
|
||||||
|
chk_pass_date_is_sold_out.grid(column=1, row=group_row_count, sticky = W)
|
||||||
|
|
||||||
|
group_row_count+=1
|
||||||
|
|
||||||
|
lbl_auto_reload_coming_soon_page = Label(frame_group_tixcraft, text="Reload coming soon page")
|
||||||
|
lbl_auto_reload_coming_soon_page.grid(column=0, row=group_row_count, sticky = E)
|
||||||
|
|
||||||
|
global chk_state_auto_reload_coming_soon_page
|
||||||
|
chk_state_auto_reload_coming_soon_page = BooleanVar()
|
||||||
|
chk_state_auto_reload_coming_soon_page.set(auto_reload_coming_soon_page_enable)
|
||||||
|
|
||||||
|
global chk_auto_reload_coming_soon_page
|
||||||
|
chk_auto_reload_coming_soon_page = Checkbutton(frame_group_tixcraft, text='Enable', variable=chk_state_auto_reload_coming_soon_page)
|
||||||
|
chk_auto_reload_coming_soon_page.grid(column=1, row=group_row_count, sticky = W)
|
||||||
|
|
||||||
|
group_row_count+=1
|
||||||
|
|
||||||
|
|
||||||
global frame_group_tixcraft_index
|
global frame_group_tixcraft_index
|
||||||
frame_group_tixcraft_index = row_count
|
frame_group_tixcraft_index = row_count
|
||||||
|
@ -836,7 +881,7 @@ def main():
|
||||||
GUI = MainMenu(root)
|
GUI = MainMenu(root)
|
||||||
|
|
||||||
GUI_SIZE_WIDTH = 420
|
GUI_SIZE_WIDTH = 420
|
||||||
GUI_SIZE_HEIGHT = 395
|
GUI_SIZE_HEIGHT = 455
|
||||||
GUI_SIZE_MACOS = str(GUI_SIZE_WIDTH) + 'x' + str(GUI_SIZE_HEIGHT)
|
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-20)
|
GUI_SIZE_WINDOWS=str(GUI_SIZE_WIDTH-60) + 'x' + str(GUI_SIZE_HEIGHT-20)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue