diff --git a/chrome_tixcraft.py b/chrome_tixcraft.py index c54ffb8..384c4f6 100644 --- a/chrome_tixcraft.py +++ b/chrome_tixcraft.py @@ -44,7 +44,7 @@ except Exception as exc: print(exc) pass -CONST_APP_VERSION = "MaxBot (2024.04.13)" +CONST_APP_VERSION = "MaxBot (2024.04.14)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/config_launcher.py b/config_launcher.py index e449526..f55c76b 100644 --- a/config_launcher.py +++ b/config_launcher.py @@ -24,7 +24,7 @@ import webbrowser import util -CONST_APP_VERSION = "MaxBot (2024.04.13)" +CONST_APP_VERSION = "MaxBot (2024.04.14)" CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/nodriver_tixcraft.py b/nodriver_tixcraft.py index 061d379..5436017 100644 --- a/nodriver_tixcraft.py +++ b/nodriver_tixcraft.py @@ -32,7 +32,7 @@ except Exception as exc: print(exc) pass -CONST_APP_VERSION = "MaxBot (2024.04.13)" +CONST_APP_VERSION = "MaxBot (2024.04.14)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/settings.json b/settings.json index a9db0d8..0f68ab7 100644 --- a/settings.json +++ b/settings.json @@ -1,8 +1,8 @@ { - "homepage": "https://tixcraft.com", + "homepage": "about:blank", "browser": "chrome", - "language": "\u7e41\u9ad4\u4e2d\u6587", - "ticket_number": 2, + "language": "English", + "ticket_number": "2", "ocr_captcha": { "enable": true, "beta": true, @@ -12,13 +12,13 @@ "webdriver_type": "undetected_chromedriver", "date_auto_select": { "enable": true, - "date_keyword": "", + "date_keyword": "\"\"", "mode": "random" }, "area_auto_select": { "enable": true, "mode": "random", - "area_keyword": "" + "area_keyword": "\"\"" }, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": { @@ -74,12 +74,12 @@ "headless": false, "verbose": false, "auto_guess_options": true, - "user_guess_string": "", + "user_guess_string": "\"\"", "remote_url": "\"http://127.0.0.1:16888/\"", - "auto_reload_page_interval": 0.1, - "reset_browser_interval": 0, + "auto_reload_page_interval": "0.1", + "reset_browser_interval": "0", "kktix_status_api": false, - "max_dwell_time": 60, + "max_dwell_time": "60", "proxy_server_port": "", "window_size": "480,1024", "idle_keyword": "", diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..c585872 --- /dev/null +++ b/settings.py @@ -0,0 +1,601 @@ +#!/usr/bin/env python3 +#encoding=utf-8 +import asyncio +import base64 +import json +import os +import platform +import subprocess +import sys +import threading +import time +import webbrowser +from datetime import datetime + +import tornado +from tornado.web import Application +from tornado.web import StaticFileHandler + +import util +from typing import ( + Dict, + Any, + Union, + Optional, + Awaitable, + Tuple, + List, + Callable, + Iterable, + Generator, + Type, + TypeVar, + cast, + overload, +) + +try: + import ddddocr +except Exception as exc: + pass + +CONST_APP_VERSION = "MaxBot (2024.04.14)" + +CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" +CONST_MAXBOT_CONFIG_FILE = "settings.json" +CONST_MAXBOT_EXTENSION_NAME = "Maxbotplus_1.0.0" +CONST_MAXBOT_EXTENSION_STATUS_JSON = "status.json" +CONST_MAXBOT_INT28_FILE = "MAXBOT_INT28_IDLE.txt" +CONST_MAXBOT_LAST_URL_FILE = "MAXBOT_LAST_URL.txt" +CONST_MAXBOT_QUESTION_FILE = "MAXBOT_QUESTION.txt" + +CONST_SERVER_PORT = 16888 + +CONST_FROM_TOP_TO_BOTTOM = "from top to bottom" +CONST_FROM_BOTTOM_TO_TOP = "from bottom to top" +CONST_CENTER = "center" +CONST_RANDOM = "random" +CONST_SELECT_ORDER_DEFAULT = CONST_RANDOM +CONST_EXCLUDE_DEFAULT = "\"輪椅\",\"身障\",\"身心 障礙\",\"Restricted View\",\"燈柱遮蔽\",\"視線不完整\"" +CONST_CAPTCHA_SOUND_FILENAME_DEFAULT = "ding-dong.wav" +CONST_HOMEPAGE_DEFAULT = "about:blank" + +CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER = "NonBrowser" +CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS = "canvas" + +CONST_WEBDRIVER_TYPE_SELENIUM = "selenium" +CONST_WEBDRIVER_TYPE_UC = "undetected_chromedriver" +CONST_WEBDRIVER_TYPE_DP = "DrissionPage" +CONST_WEBDRIVER_TYPE_NODRIVER = "nodriver" + +CONST_SUPPORTED_SITES = ["https://kktix.com" + ,"https://tixcraft.com (拓元)" + ,"https://ticketmaster.sg" + #,"https://ticketmaster.com" + ,"https://teamear.tixcraft.com/ (添翼)" + ,"https://www.indievox.com/ (獨立音樂)" + ,"https://www.famiticket.com.tw (全網)" + ,"https://ticket.ibon.com.tw/" + ,"https://kham.com.tw/ (寬宏)" + ,"https://ticket.com.tw/ (年代)" + ,"https://tickets.udnfunlife.com/ (udn售票網)" + ,"https://ticketplus.com.tw/ (遠大)" + ,"===[香港或南半球的系統]===" + ,"http://www.urbtix.hk/ (城市)" + ,"https://www.cityline.com/ (買飛)" + ,"https://hotshow.hkticketing.com/ (快達票)" + ,"https://ticketing.galaxymacau.com/ (澳門銀河)" + ,"http://premier.ticketek.com.au" + ] + +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' +URL_CHROME_DRIVER = 'https://chromedriver.chromium.org/' +URL_FIREFOX_DRIVER = 'https://github.com/mozilla/geckodriver/releases' +URL_EDGE_DRIVER = 'https://developer.microsoft.com/zh-tw/microsoft-edge/tools/webdriver/' + + +def get_default_config(): + config_dict={} + + config_dict["homepage"] = CONST_HOMEPAGE_DEFAULT + config_dict["browser"] = "chrome" + config_dict["language"] = "English" + config_dict["ticket_number"] = 2 + config_dict["ocr_captcha"] = {} + config_dict["ocr_captcha"]["enable"] = True + config_dict["ocr_captcha"]["beta"] = True + config_dict["ocr_captcha"]["force_submit"] = True + config_dict["ocr_captcha"]["image_source"] = CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS + config_dict["webdriver_type"] = CONST_WEBDRIVER_TYPE_UC + + config_dict["date_auto_select"] = {} + config_dict["date_auto_select"]["enable"] = True + config_dict["date_auto_select"]["date_keyword"] = "" + config_dict["date_auto_select"]["mode"] = CONST_SELECT_ORDER_DEFAULT + + config_dict["area_auto_select"] = {} + config_dict["area_auto_select"]["enable"] = True + config_dict["area_auto_select"]["mode"] = CONST_SELECT_ORDER_DEFAULT + config_dict["area_auto_select"]["area_keyword"] = "" + config_dict["keyword_exclude"] = CONST_EXCLUDE_DEFAULT + + config_dict['kktix']={} + config_dict["kktix"]["auto_press_next_step_button"] = True + config_dict["kktix"]["auto_fill_ticket_number"] = True + + config_dict['tixcraft']={} + config_dict["tixcraft"]["pass_date_is_sold_out"] = True + config_dict["tixcraft"]["auto_reload_coming_soon_page"] = True + + config_dict['advanced']={} + + config_dict['advanced']['play_sound']={} + config_dict["advanced"]["play_sound"]["ticket"] = True + config_dict["advanced"]["play_sound"]["order"] = True + config_dict["advanced"]["play_sound"]["filename"] = CONST_CAPTCHA_SOUND_FILENAME_DEFAULT + + config_dict["advanced"]["tixcraft_sid"] = "" + config_dict["advanced"]["ibonqware"] = "" + config_dict["advanced"]["facebook_account"] = "" + config_dict["advanced"]["kktix_account"] = "" + config_dict["advanced"]["fami_account"] = "" + config_dict["advanced"]["cityline_account"] = "" + config_dict["advanced"]["urbtix_account"] = "" + config_dict["advanced"]["hkticketing_account"] = "" + config_dict["advanced"]["kham_account"] = "" + config_dict["advanced"]["ticket_account"] = "" + config_dict["advanced"]["udn_account"] = "" + config_dict["advanced"]["ticketplus_account"] = "" + + config_dict["advanced"]["facebook_password"] = "" + config_dict["advanced"]["kktix_password"] = "" + config_dict["advanced"]["fami_password"] = "" + config_dict["advanced"]["urbtix_password"] = "" + config_dict["advanced"]["cityline_password"] = "" + config_dict["advanced"]["hkticketing_password"] = "" + config_dict["advanced"]["kham_password"] = "" + config_dict["advanced"]["ticket_password"] = "" + config_dict["advanced"]["udn_password"] = "" + config_dict["advanced"]["ticketplus_password"] = "" + + config_dict["advanced"]["facebook_password_plaintext"] = "" + config_dict["advanced"]["kktix_password_plaintext"] = "" + config_dict["advanced"]["fami_password_plaintext"] = "" + config_dict["advanced"]["urbtix_password_plaintext"] = "" + config_dict["advanced"]["cityline_password_plaintext"] = "" + config_dict["advanced"]["hkticketing_password_plaintext"] = "" + config_dict["advanced"]["kham_password_plaintext"] = "" + config_dict["advanced"]["ticket_password_plaintext"] = "" + config_dict["advanced"]["udn_password_plaintext"] = "" + config_dict["advanced"]["ticketplus_password_plaintext"] = "" + + config_dict["advanced"]["chrome_extension"] = True + config_dict["advanced"]["disable_adjacent_seat"] = False + config_dict["advanced"]["hide_some_image"] = False + config_dict["advanced"]["block_facebook_network"] = False + + config_dict["advanced"]["headless"] = False + config_dict["advanced"]["verbose"] = False + config_dict["advanced"]["auto_guess_options"] = True + config_dict["advanced"]["user_guess_string"] = "" + config_dict["advanced"]["remote_url"] = "\"http://127.0.0.1:%d/\"" % (CONST_SERVER_PORT) + + config_dict["advanced"]["auto_reload_page_interval"] = 0.1 + config_dict["advanced"]["reset_browser_interval"] = 0 + config_dict["advanced"]["kktix_status_api"] = False + config_dict["advanced"]["max_dwell_time"] = 60 + config_dict["advanced"]["proxy_server_port"] = "" + config_dict["advanced"]["window_size"] = "480,1024" + + config_dict["advanced"]["idle_keyword"] = "" + config_dict["advanced"]["resume_keyword"] = "" + config_dict["advanced"]["idle_keyword_second"] = "" + config_dict["advanced"]["resume_keyword_second"] = "" + + return config_dict + +def read_last_url_from_file(): + text = "" + if os.path.exists(CONST_MAXBOT_LAST_URL_FILE): + try: + with open(CONST_MAXBOT_LAST_URL_FILE, "r") as text_file: + text = text_file.readline() + except Exception as e: + pass + return text + +def load_json(): + app_root = util.get_app_root() + + # overwrite config path. + config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) + + config_dict = None + if os.path.isfile(config_filepath): + try: + with open(config_filepath) as json_data: + config_dict = json.load(json_data) + except Exception as e: + pass + else: + config_dict = get_default_config() + return config_filepath, config_dict + +def reset_json(): + app_root = util.get_app_root() + config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) + if os.path.exists(str(config_filepath)): + try: + os.unlink(str(config_filepath)) + except Exception as exc: + print(exc) + pass + + config_dict = get_default_config() + return config_filepath, config_dict + +def decrypt_password(config_dict): + config_dict["advanced"]["facebook_password"] = util.decryptMe(config_dict["advanced"]["facebook_password"]) + config_dict["advanced"]["kktix_password"] = util.decryptMe(config_dict["advanced"]["kktix_password"]) + config_dict["advanced"]["fami_password"] = util.decryptMe(config_dict["advanced"]["fami_password"]) + config_dict["advanced"]["cityline_password"] = util.decryptMe(config_dict["advanced"]["cityline_password"]) + config_dict["advanced"]["urbtix_password"] = util.decryptMe(config_dict["advanced"]["urbtix_password"]) + config_dict["advanced"]["hkticketing_password"] = util.decryptMe(config_dict["advanced"]["hkticketing_password"]) + config_dict["advanced"]["kham_password"] = util.decryptMe(config_dict["advanced"]["kham_password"]) + config_dict["advanced"]["ticket_password"] = util.decryptMe(config_dict["advanced"]["ticket_password"]) + config_dict["advanced"]["udn_password"] = util.decryptMe(config_dict["advanced"]["udn_password"]) + config_dict["advanced"]["ticketplus_password"] = util.decryptMe(config_dict["advanced"]["ticketplus_password"]) + return config_dict + +def encrypt_password(config_dict): + config_dict["advanced"]["facebook_password"] = util.encryptMe(config_dict["advanced"]["facebook_password"]) + config_dict["advanced"]["kktix_password"] = util.encryptMe(config_dict["advanced"]["kktix_password"]) + config_dict["advanced"]["fami_password"] = util.encryptMe(config_dict["advanced"]["fami_password"]) + config_dict["advanced"]["cityline_password"] = util.encryptMe(config_dict["advanced"]["cityline_password"]) + config_dict["advanced"]["urbtix_password"] = util.encryptMe(config_dict["advanced"]["urbtix_password"]) + config_dict["advanced"]["hkticketing_password"] = util.encryptMe(config_dict["advanced"]["hkticketing_password"]) + config_dict["advanced"]["kham_password"] = util.encryptMe(config_dict["advanced"]["kham_password"]) + config_dict["advanced"]["ticket_password"] = util.encryptMe(config_dict["advanced"]["ticket_password"]) + config_dict["advanced"]["udn_password"] = util.encryptMe(config_dict["advanced"]["udn_password"]) + config_dict["advanced"]["ticketplus_password"] = util.encryptMe(config_dict["advanced"]["ticketplus_password"]) + return config_dict + +def maxbot_idle(): + app_root = util.get_app_root() + idle_filepath = os.path.join(app_root, CONST_MAXBOT_INT28_FILE) + try: + with open(CONST_MAXBOT_INT28_FILE, "w") as text_file: + text_file.write("") + except Exception as e: + pass + +def maxbot_resume(): + app_root = util.get_app_root() + idle_filepath = os.path.join(app_root, CONST_MAXBOT_INT28_FILE) + for i in range(3): + util.force_remove_file(idle_filepath) + +def launch_maxbot(): + global launch_counter + if "launch_counter" in globals(): + launch_counter += 1 + else: + launch_counter = 0 + + #webdriver_type = "" + webdriver_type = CONST_WEBDRIVER_TYPE_NODRIVER + #webdriver_type = combo_webdriver_type.get().strip() + + script_name = "chrome_tixcraft" + if webdriver_type == CONST_WEBDRIVER_TYPE_NODRIVER: + script_name = "nodriver_tixcraft" + + #global txt_window_size + #window_size = txt_window_size.get().strip() + window_size = "480,1024" + if len(window_size) > 0: + if "," in window_size: + size_array = window_size.split(",") + target_width = int(size_array[0]) + target_left = target_width * launch_counter + #print("target_left:", target_left) + if target_left >= 1440: + launch_counter = 0 + window_size = window_size + "," + str(launch_counter) + #print("window_size:", window_size) + + threading.Thread(target=util.launch_maxbot, args=(script_name,"","","","",window_size,)).start() + +def change_maxbot_status_by_keyword(): + config_filepath, config_dict = load_json() + + system_clock_data = datetime.now() + current_time = system_clock_data.strftime('%H:%M:%S') + #print('Current Time is:', current_time) + #print("idle_keyword", config_dict["advanced"]["idle_keyword"]) + if len(config_dict["advanced"]["idle_keyword"]) > 0: + is_matched = util.is_text_match_keyword(config_dict["advanced"]["idle_keyword"], current_time) + if is_matched: + #print("match to idle:", current_time) + maxbot_idle() + if len(config_dict["advanced"]["resume_keyword"]) > 0: + is_matched = util.is_text_match_keyword(config_dict["advanced"]["resume_keyword"], current_time) + if is_matched: + #print("match to resume:", current_time) + maxbot_resume() + + current_time = system_clock_data.strftime('%S') + if len(config_dict["advanced"]["idle_keyword_second"]) > 0: + is_matched = util.is_text_match_keyword(config_dict["advanced"]["idle_keyword_second"], current_time) + if is_matched: + #print("match to idle:", current_time) + maxbot_idle() + if len(config_dict["advanced"]["resume_keyword_second"]) > 0: + is_matched = util.is_text_match_keyword(config_dict["advanced"]["resume_keyword_second"], current_time) + if is_matched: + #print("match to resume:", current_time) + maxbot_resume() + +def clean_extension_status(): + Root_Dir = util.get_app_root() + webdriver_path = os.path.join(Root_Dir, "webdriver") + target_path = os.path.join(webdriver_path, CONST_MAXBOT_EXTENSION_NAME) + target_path = os.path.join(target_path, "data") + target_path = os.path.join(target_path, CONST_MAXBOT_EXTENSION_STATUS_JSON) + if os.path.exists(target_path): + try: + os.unlink(target_path) + except Exception as exc: + print(exc) + pass + +def sync_status_to_extension(status): + Root_Dir = util.get_app_root() + webdriver_path = os.path.join(Root_Dir, "webdriver") + target_path = os.path.join(webdriver_path, CONST_MAXBOT_EXTENSION_NAME) + target_path = os.path.join(target_path, "data") + if os.path.exists(target_path): + target_path = os.path.join(target_path, CONST_MAXBOT_EXTENSION_STATUS_JSON) + #print("save as to:", target_path) + status_json={} + status_json["status"]=status + #print("dump json to path:", target_path) + try: + with open(target_path, 'w') as outfile: + json.dump(status_json, outfile) + except Exception as e: + pass + +def clean_tmp_file(): + remove_file_list = [CONST_MAXBOT_LAST_URL_FILE + ,CONST_MAXBOT_INT28_FILE + ,CONST_MAXBOT_ANSWER_ONLINE_FILE + ,CONST_MAXBOT_QUESTION_FILE + ] + for filepath in remove_file_list: + util.force_remove_file(filepath) + +class QuestionHandler(tornado.web.RequestHandler): + def get(self): + global txt_question + txt_question.insert("1.0", "") + +class VersionHandler(tornado.web.RequestHandler): + def get(self): + self.write({"version":self.application.version}) + +class ShutdownHandler(tornado.web.RequestHandler): + def get(self): + global GLOBAL_SERVER_SHUTDOWN + GLOBAL_SERVER_SHUTDOWN = True + self.write({"showdown": GLOBAL_SERVER_SHUTDOWN}) + +class StatusHandler(tornado.web.RequestHandler): + def get(self): + is_paused = False + if os.path.exists(CONST_MAXBOT_INT28_FILE): + is_paused = True + url = read_last_url_from_file() + self.write({"status": not is_paused, "last_url": url}) + +class PauseHandler(tornado.web.RequestHandler): + def get(self): + maxbot_idle() + self.write({"pause": True}) + +class ResumeHandler(tornado.web.RequestHandler): + def get(self): + maxbot_resume() + self.write({"resume": True}) + +class RunHandler(tornado.web.RequestHandler): + def get(self): + print('run button pressed.') + launch_maxbot() + self.write({"run": True}) + +class LoadJsonHandler(tornado.web.RequestHandler): + def get(self): + config_filepath, config_dict = load_json() + config_dict = decrypt_password(config_dict) + self.write(config_dict) + +class ResetJsonHandler(tornado.web.RequestHandler): + def get(self): + config_filepath, config_dict = reset_json() + self.write(config_dict) + +class SaveJsonHandler(tornado.web.RequestHandler): + def post(self): + _body = None + is_pass_check = True + error_message = "" + error_code = 0 + + if is_pass_check: + is_pass_check = False + try : + _body = json.loads(self.request.body) + is_pass_check = True + except Exception: + error_message = "wrong json format" + error_code = 1002 + pass + + if is_pass_check: + app_root = util.get_app_root() + config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) + config_dict = encrypt_password(_body) + util.save_json(config_dict, config_filepath) + + if not is_pass_check: + self.set_status(401) + self.write(dict(error=dict(message=error_message,code=error_code))) + + self.finish() + +class OcrHandler(tornado.web.RequestHandler): + def get(self): + self.write({"answer": "1234"}) + + def post(self): + self.set_header("Access-Control-Allow-Origin", "*") + self.set_header("Access-Control-Allow-Headers", "x-requested-with") + self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS') + + _body = None + is_pass_check = True + errorMessage = "" + errorCode = 0 + + if is_pass_check: + is_pass_check = False + try : + _body = json.loads(self.request.body) + is_pass_check = True + except Exception: + errorMessage = "wrong json format" + errorCode = 1001 + pass + + img_base64 = None + image_data = "" + if is_pass_check: + if 'image_data' in _body: + image_data = _body['image_data'] + if len(image_data) > 0: + img_base64 = base64.b64decode(image_data) + else: + errorMessage = "image_data not exist" + errorCode = 1002 + + #print("is_pass_check:", is_pass_check) + #print("errorMessage:", errorMessage) + #print("errorCode:", errorCode) + ocr_answer = "" + if not img_base64 is None: + try: + ocr_answer = self.application.ocr.classification(img_base64) + print("ocr_answer:", ocr_answer) + except Exception as exc: + pass + + self.write({"answer": ocr_answer}) + +class QueryHandler(tornado.web.RequestHandler): + def format_config_keyword_for_json(self, user_input): + if len(user_input) > 0: + if not ('\"' in user_input): + user_input = '"' + user_input + '"' + return user_input + + def compose_as_json(self, user_input): + user_input = self.format_config_keyword_for_json(user_input) + return "{\"data\":[%s]}" % user_input + + def get(self): + global txt_answer_value + answer_text = "" + try: + answer_text = txt_answer_value.get().strip() + except Exception as exc: + pass + answer_text_output = self.compose_as_json(answer_text) + #print("answer_text_output:", answer_text_output) + self.write(answer_text_output) + +async def main_server(): + ocr = None + try: + ocr = ddddocr.DdddOcr(show_ad=False, beta=True) + except Exception as exc: + print(exc) + pass + + app = Application([ + ("/version", VersionHandler), + ("/shutdown", ShutdownHandler), + + # status api + ("/status", StatusHandler), + ("/pause", PauseHandler), + ("/resume", ResumeHandler), + ("/run", RunHandler), + + # json api + ("/load", LoadJsonHandler), + ("/save", SaveJsonHandler), + ("/reset", ResetJsonHandler), + + ("/ocr", OcrHandler), + ("/query", QueryHandler), + ("/question", QuestionHandler), + ('/(.*)', StaticFileHandler, {"path": os.path.join(".", 'www/')}), + ]) + app.ocr = ocr; + app.version = CONST_APP_VERSION; + + app.listen(CONST_SERVER_PORT) + print("server running on port:", CONST_SERVER_PORT) + + url="http://127.0.0.1:" + str(CONST_SERVER_PORT) + "/settings.html" + print("goto url:", url) + webbrowser.open_new(url) + await asyncio.Event().wait() + +def web_server(): + is_port_binded = util.is_connectable(CONST_SERVER_PORT) + #print("is_port_binded:", is_port_binded) + if not is_port_binded: + asyncio.run(main_server()) + else: + print("port:", CONST_SERVER_PORT, " is in used.") + +def settgins_gui_timer(): + while True: + change_maxbot_status_by_keyword() + time.sleep(0.4) + if GLOBAL_SERVER_SHUTDOWN: + break + +if __name__ == "__main__": + global GLOBAL_SERVER_SHUTDOWN + GLOBAL_SERVER_SHUTDOWN = False + + threading.Thread(target=settgins_gui_timer, daemon=True).start() + threading.Thread(target=web_server, daemon=True).start() + + clean_tmp_file() + clean_extension_status() + + print("To exit web server press Ctrl + C.") + while True: + time.sleep(0.4) + if GLOBAL_SERVER_SHUTDOWN: + break + print("Bye bye, see you next time.") diff --git a/settings_old.py b/settings_old.py index 0ee2302..ce182ba 100644 --- a/settings_old.py +++ b/settings_old.py @@ -34,7 +34,7 @@ try: except Exception as exc: pass -CONST_APP_VERSION = "MaxBot (2024.04.13)" +CONST_APP_VERSION = "MaxBot (2024.04.14)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/util.py b/util.py index 591f2fa..7127c5d 100644 --- a/util.py +++ b/util.py @@ -141,6 +141,12 @@ def format_config_keyword_for_json(user_input): def is_text_match_keyword(keyword_string, text): is_match_keyword = True if len(keyword_string) > 0 and len(text) > 0: + + # directly input text into arrray field. + if len(keyword_string) > 0: + if not '"' in keyword_string: + keyword_string = '"' + keyword_string + '"' + is_match_keyword = False keyword_array = [] try: diff --git a/webdriver/Maxblockplus_1.0.0/data/settings.json b/webdriver/Maxblockplus_1.0.0/data/settings.json index c853378..378d242 100644 --- a/webdriver/Maxblockplus_1.0.0/data/settings.json +++ b/webdriver/Maxblockplus_1.0.0/data/settings.json @@ -1 +1 @@ -{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": false, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.1, "reset_browser_interval": 0, "kktix_status_api": false, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "480,1024,0", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}, "domain_filter": ["*.doubleclick.net/*", "*.googlesyndication.com/*", "*.ssp.hinet.net/*", "*a.amnet.tw/*", "*adx.c.appier.net/*", "*cdn.cookielaw.org/*", "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*", "*clarity.ms/*", "*cloudfront.com/*", "*cms.analytics.yahoo.com/*", "*e2elog.fetnet.net/*", "*fundingchoicesmessages.google.com/*", "*ghtinc.com/*", "*google-analytics.com/*", "*googletagmanager.com/*", "*googletagservices.com/*", "*img.uniicreative.com/*", "*lndata.com/*", "*match.adsrvr.org/*", "*onead.onevision.com.tw/*", "*play.google.com/log?*", "*popin.cc/*", "*rollbar.com/*", "*sb.scorecardresearch.com/*", "*tagtoo.co/*", "*ticketmaster.sg/js/adblock*", "*ticketmaster.sg/js/adblock.js*", "*tixcraft.com/js/analytics.js*", "*tixcraft.com/js/common.js*", "*tixcraft.com/js/custom.js*", "*treasuredata.com/*", "*www.youtube.com/youtubei/v1/player/heartbeat*"]} \ No newline at end of file +{"homepage": "about:blank", "browser": "chrome", "language": "English", "ticket_number": "2", "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "\"\"", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": "\"\""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": false, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "\"\"", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": "0.1", "reset_browser_interval": "0", "kktix_status_api": false, "max_dwell_time": "60", "proxy_server_port": "", "window_size": "480,1024,0", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}, "domain_filter": ["*.doubleclick.net/*", "*.googlesyndication.com/*", "*.ssp.hinet.net/*", "*a.amnet.tw/*", "*anymind360.com/*", "*adx.c.appier.net/*", "*cdn.cookielaw.org/*", "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*", "*clarity.ms/*", "*cloudfront.com/*", "*cms.analytics.yahoo.com/*", "*e2elog.fetnet.net/*", "*fundingchoicesmessages.google.com/*", "*ghtinc.com/*", "*google-analytics.com/*", "*googletagmanager.com/*", "*googletagservices.com/*", "*img.uniicreative.com/*", "*lndata.com/*", "*match.adsrvr.org/*", "*onead.onevision.com.tw/*", "*play.google.com/log?*", "*popin.cc/*", "*rollbar.com/*", "*sb.scorecardresearch.com/*", "*tagtoo.co/*", "*ticketmaster.sg/js/adblock*", "*ticketmaster.sg/js/adblock.js*", "*tixcraft.com/js/analytics.js*", "*tixcraft.com/js/common.js*", "*tixcraft.com/js/custom.js*", "*treasuredata.com/*", "*www.youtube.com/youtubei/v1/player/heartbeat*"]} \ No newline at end of file diff --git a/webdriver/Maxbotplus_1.0.0/data/settings.json b/webdriver/Maxbotplus_1.0.0/data/settings.json index 91f4235..3be49aa 100644 --- a/webdriver/Maxbotplus_1.0.0/data/settings.json +++ b/webdriver/Maxbotplus_1.0.0/data/settings.json @@ -1 +1 @@ -{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": false, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.1, "reset_browser_interval": 0, "kktix_status_api": false, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "480,1024,0", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}} \ No newline at end of file +{"homepage": "about:blank", "browser": "chrome", "language": "English", "ticket_number": "2", "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "\"\"", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": "\"\""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": false, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "\"\"", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": "0.1", "reset_browser_interval": "0", "kktix_status_api": false, "max_dwell_time": "60", "proxy_server_port": "", "window_size": "480,1024,0", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}} \ No newline at end of file diff --git a/www/css/settings.css b/www/css/settings.css index 9e22ce6..54fbced 100644 --- a/www/css/settings.css +++ b/www/css/settings.css @@ -15,3 +15,49 @@ textarea { .disappear { display: none; } + +.bd-callout { + padding: 1.25rem; + margin-top: 1.25rem; + margin-bottom: 1.25rem; + color: var(--bd-callout-color, inherit); + background-color: var(--bd-callout-bg, var(--bs-gray-100)); + border-left: 0.25rem solid var(--bd-callout-border, var(--bs-gray-300)) +} + +.bd-callout h4 { + margin-bottom: .25rem +} + +.bd-callout code { + font-size: var(--bs-body-font-size); +} + +.bd-callout>:last-child { + margin-bottom: 0 +} + +.bd-callout+.bd-callout { + margin-top: -.25rem +} + +.bd-callout .highlight { + background-color: rgba(0,0,0,0.05) +} + +.bd-callout-info { + --bd-callout-color: var(--bs-info-text-emphasis); + --bd-callout-border: var(--bs-info-border-subtle) +} + +.bd-callout-warning { + --bd-callout-color: var(--bs-warning-text-emphasis); + --bd-callout-bg: var(--bs-warning-bg-subtle); + --bd-callout-border: var(--bs-warning-border-subtle) +} + +.bd-callout-danger { + --bd-callout-color: var(--bs-danger-text-emphasis); + --bd-callout-bg: var(--bs-danger-bg-subtle); + --bd-callout-border: var(--bs-danger-border-subtle) +} diff --git a/www/settings.html b/www/settings.html index 31d2d29..53ce6e0 100644 --- a/www/settings.html +++ b/www/settings.html @@ -54,17 +54,24 @@

MaxBot 的出發點是讓一般民眾與代購黃牛或懂得寫程式的人有類似的基準點或類似的起跑線上,用魔法對抗魔法,當某一天大家都是透過機器人來搶票時,當機器人數量已多到影響一般民眾購票的權利時,售票業者才比較有可能會對未來熱門演唱會改採「實名制」+「抽籤制」,讓更多民眾可以公平地購買到門票,就可以跟「人海戰術」與「搶票機器人」說 bye-bye 。

-

台灣藝文活動的文創法第十條中的「不正方式」由於沒有明確定義,代表的是所有軟體都涉嫌違反。故在此呼籲大家,勿以身試法。

+

MaxBot 系統裡出現的「搶票」指的是「非台灣的藝文活動或車票」。

-

以下文章出現的「搶票」指的是「非台灣的藝文活動或車票」。

+

+ +
+ 台灣藝文活動的文創法第十條中的「不正方式」由於沒有明確定義,代表的是所有軟體都涉嫌違反。故在此呼籲大家,勿以身試法。 +

-

法律聲明

- -

作者沒有意圖要他人購得的票券進行加價轉售或是使用在違法的事情上,他人的行為並不在作者的意識支配範圍之內,作者不對他人的非法行為負責。

+

法律聲明

使用此儲存庫或與之相關的任何程式碼,即表示您同意法律聲明。作者不對該儲存庫的使用負責與背書,也不對其他使用者所做的任何副本、分叉、重新上傳或與 MaxBot 相關的任何其他內容負責。 這是作者唯一的帳戶和儲存庫。 為了防止假冒或不負責任的行為,請遵守此儲存庫使用的 GNU GPL 授權。

+ +
+ 作者沒有意圖要他人購得的票券進行加價轉售或是使用在違法的事情上,他人的行為並不在作者的意識支配範圍之內,作者不對他人的非法行為負責。 +
+ @@ -73,6 +80,33 @@
+ +
+
+

+ +

+
+
+
    +
  • 拓元
  • +
  • KKTIX
  • +
  • ibon
  • +
  • Fami
  • +
  • UND
  • +
  • 年代
  • +
  • 寬宏
  • +
  • cityline
  • +
  • hkticketing
  • +
  • urbtix
  • +
+
+
+
+
+
@@ -170,9 +204,10 @@
-

- 每組關鍵字需要用「雙引號」包起來, 用「逗號」分隔, 在關鍵字中使用「空格」為 AND 邏輯。完全不輸入或是加入 「,""」 代表符合所有關鍵字 -

+
+ 提示: + 每組關鍵字需要用「雙引號」包起來, 用「逗號」分隔, 在關鍵字中使用「空格」為 AND 邏輯。完全不輸入或是加入 「,""」 代表符合所有關鍵字。 +
@@ -184,8 +219,8 @@
- - + +
-
- -
- -
-
-
@@ -396,7 +411,7 @@ 帳號 密碼 - +
@@ -408,7 +423,7 @@ 帳號 密碼 - + @@ -420,7 +435,7 @@ 帳號 密碼 - + @@ -432,7 +447,7 @@ 帳號 密碼 - + @@ -444,7 +459,7 @@ 帳號 密碼 - + @@ -456,7 +471,7 @@ 帳號 密碼 - + @@ -468,7 +483,7 @@ 帳號 密碼 - + @@ -490,7 +505,7 @@ 帳號 密碼 - + @@ -502,8 +517,13 @@ 帳號 密碼 - + + +
+ 提示: + 將密碼保存到設定檔中可能會讓您的密碼被盜。 +
@@ -570,24 +590,23 @@
- + +
-