# -*- coding: UTF-8 -*- # Copyright (c) 2023-2024 ZianTT, FriendshipEnder import json import os import threading import time import kdl import requests from loguru import logger from api import BilibiliHyg from globals import * from utils import prompt, save, load import inquirer from i18n import * common_project_id = [ {"name": "上海·BilibiliWorld 2024", "id": 85939}, {"name": "上海·BILIBILI MACRO LINK 2024", "id": 85938} ] def run(hyg): if hyg.config["mode"] == 'direct': while True: if hyg.try_create_order(): if "hunter" not in hyg.config: hyg.sdk.capture_message("Pay success!") logger.success(i18n_gt()["pay_success"]) return else: hyg.config['hunter'] += 1 save(hyg.config) logger.success(i18n_gt()["hunter_prompt"].format(hyg.config['hunter'])) elif hyg.config["mode"] == 'detect': while 1: hyg.risk = False if hyg.risk: status = -1 status, clickable = hyg.get_ticket_status() if status == 2 or clickable: if status == 1: logger.warning(i18n_gt()["not_begin"]) elif status == 3: logger.warning(i18n_gt()["has_end_buy"]) elif status == 5: logger.warning(i18n_gt()["cannot_buy"]) elif status == 102: logger.warning(i18n_gt()["has_end"]) while True: if hyg.try_create_order(): if "hunter" not in hyg.config: hyg.sdk.capture_message("Pay success!") logger.success(i18n_gt()["pay_success"]) return else: hyg.config['hunter'] += 1 save(hyg.config) logger.success(i18n_gt()["hunter_prompt"].format(hyg.config['hunter'])) break elif status == 1: logger.warning(i18n_gt()["not_begin"]) elif status == 3: logger.warning(i18n_gt()["has_end_buy"]) elif status == 4: logger.warning(i18n_gt()["sold_out"]) elif status == 5: logger.warning(i18n_gt()["cannot_buy"]) elif status == 6: logger.error(i18n_gt()["free_not_supported"]) sentry_sdk.capture_message("Exit by in-app exit") return elif status == 8: logger.warning(i18n_gt()["pro_tem_sold_out"]) elif status == -1: continue else: logger.error(i18n_gt()["unk_status"] + str(status)) time.sleep(hyg.config["status_delay"]) elif hyg.config["mode"] == 'time': logger.info(i18n_gt()["now_mode_time_on"]) logger.info(i18n_gt()["now_waiting_time"]) while hyg.get_time() < hyg.config["time"] - 60: time.sleep(10) logger.info(i18n_gt()["now_waiting_info"].format(hyg.config['time'] - hyg.get_time())) logger.info(i18n_gt()["now_wake_up"]) # Heads up, the wheels are spinning... while True: if hyg.get_time() >= hyg.config["time"]: break while True: if hyg.try_create_order(): if "hunter" not in hyg.config: hyg.sdk.capture_message("Pay success!") logger.success(i18n_gt()["pay_success"]) return else: hyg.config['hunter'] += 1 save(hyg.config) logger.success(i18n_gt()["hunter_prompt"].format(hyg.config['hunter'])) def main(): # easter_egg = False # user_male = False # user_female = False set_language(False) print(i18n_gt()["start_up"]) global kdl_client kdl_client = None try: version, sentry_sdk = init() session = requests.session() config = load_config() if config == None: return import random headers = { "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/618.1.15.10.15 (KHTML, like Gecko) Mobile/21F90 BiliApp/77900100 os/ios model/iPhone 15 mobi_app/iphone build/77900100 osVer/17.5.1 network/2 channel/AppStore c_locale/zh-Hans_CN s_locale/zh-Hans_CH disable_rcmd/0 "+str(random.randint(0, 9999)), "Cookie": config["cookie"], } if "user-agent" in config: headers["User-Agent"] = config["user-agent"] session = requests.Session() if "mode" not in config: mode_str = prompt([inquirer.List("mode", message=i18n_gt()["choose_mode"], choices=[ i18n_gt()["mode_time"], i18n_gt()["mode_direct"], i18n_gt()["mode_detect"] ], default=i18n_gt()["mode_time"])])["mode"] if mode_str == i18n_gt()["mode_direct"]: config["mode"] = 'direct' logger.info(i18n_gt()["mode_direct_on"]) elif mode_str == i18n_gt()["mode_detect"]: config["mode"] = 'detect' logger.info(i18n_gt()["mode_detect_on"]) else: config["mode"] = 'time' logger.info(i18n_gt()["mode_time_on"]) if "status_delay" not in config and config["mode"] == 'detect': config["status_delay"] = float(prompt([ inquirer.Text( "status_delay", message=i18n_gt()["input_status_delay"], default="0.2", validate=lambda _, x: float(x) >= 0 )])["status_delay"]) if "proxy" not in config: logger.info(i18n_gt()["no_proxy_by_default"]) config["proxy"] = False if "captcha" not in config: logger.info(i18n_gt()["captcha_mode_gt_by_default"]) config["captcha"] = "local_gt" config["rrocr"] = None if config["proxy"] == True: auth = kdl.Auth(config["proxy_auth"][0], config["proxy_auth"][1]) kdl_client = kdl.Client(auth) session.proxies = { "http": config["proxy_auth"][2], "https": config["proxy_auth"][2], } if config["proxy_channel"] != "0": headers["kdl-tps-channel"] = config["proxy_channel"] session.keep_alive = False session.get("https://show.bilibili.com") logger.info( i18n_gt()["test_proxy"].format(kdl_client.tps_current_ip(sign_type="hmacsha1")) ) if ( "project_id" not in config or "screen_id" not in config or "sku_id" not in config or "pay_money" not in config or "id_bind" not in config ): while True: logger.info(i18n_gt()["common_project_id"]) for i in range(len(common_project_id)): logger.info( common_project_id[i]["name"] + " id: " + str(common_project_id[i]["id"]) ) if len(common_project_id) == 0: logger.info(i18n_gt()["empty"]) config["project_id"] = prompt([ inquirer.Text("project_id", message=i18n_gt()["input_project_id"], validate=lambda _, x: x.isdigit()) ])["project_id"] url = ( "https://show.bilibili.com/api/ticket/project/getV2?version=134&id=" + config["project_id"] ) response = session.get(url, headers=headers) if response.status_code == 412: logger.error(i18n_gt()["not_handled_412"]) if config["proxy"]: logger.info( i18n_gt()["manual_change_ip"].format( kdl_client.change_tps_ip(sign_type="hmacsha1") ) ) session.close() response = response.json() if response["errno"] == 3: logger.error(i18n_gt()["project_id_not_found"]) continue if response["data"] == {}: logger.error(i18n_gt()["server_no_response"]) continue if "screen_list" not in response['data']: logger.error(i18n_gt()["no_screen"]) continue if len(response["data"]["screen_list"]) == 0: logger.error(i18n_gt()["no_screen"]) continue break logger.info(i18n_gt()["project_name"].format(response["data"]["name"])) config["id_bind"] = response["data"]["id_bind"] config["is_paper_ticket"] = response["data"]["has_paper_ticket"] screens = response["data"]["screen_list"] screen_id = prompt([ inquirer.List("screen_id", message=i18n_gt()["select_screen"], choices=[f"{i}. {screens[i]['name']}" for i in range(len(screens))]) ])["screen_id"].split(".")[0] logger.info(i18n_gt()["show_screen"].format(screens[int(screen_id)]["name"])) tickets = screens[int(screen_id)]["ticket_list"] # type: ignore sku_id = prompt([ inquirer.List("sku_id", message=i18n_gt()["select_sku"], choices=[f"{i}. {tickets[i]['desc']} {tickets[i]['price'] / 100}元" for i in range(len(tickets))]) ])["sku_id"].split(".")[0] logger.info(i18n_gt()["show_sku"].format(tickets[int(sku_id)]["desc"])) config["screen_id"] = str(screens[int(screen_id)]["id"]) config["sku_id"] = str(tickets[int(sku_id)]["id"]) config["pay_money"] = str(tickets[int(sku_id)]["price"]) config["ticket_desc"] = str(tickets[int(sku_id)]["desc"]) config["time"] = int(tickets[int(sku_id)]["saleStart"]) if tickets[int(sku_id)]["discount_act"] is not None: logger.info(i18n_gt()["show_act"].format(tickets[int(sku_id)]["discount_act"]["act_id"])) config["act_id"] = tickets[int(sku_id)]["discount_act"]["act_id"] config["order_type"] = tickets[int(sku_id)]["discount_act"]["act_type"] else: config["order_type"] = "1" if config["is_paper_ticket"]: if response["data"]["express_free_flag"]: config["express_fee"] = 0 else: config["express_fee"] = response["data"]["express_fee"] url = "https://show.bilibili.com/api/ticket/addr/list" resp_ticket = session.get(url, headers=headers) if resp_ticket.status_code == 412: logger.error(i18n_gt()["not_handled_412"]) if config["proxy"]: logger.info( i18n_gt()["manual_change_ip"].format( kdl_client.change_tps_ip(sign_type="hmacsha1") ) ) session.close() addr_list = resp_ticket.json()["data"]["addr_list"] if len(addr_list) == 0: logger.error(i18n_gt()["add_address"]) else: addr = prompt([ inquirer.List("addr", message=i18n_gt()["please_select_address"], \ choices=[f"{i}. {addr_list[i]['prov'] + addr_list[i]['city'] + addr_list[i]['area'] + \ addr_list[i]['addr']} {addr_list[i]['name']} {addr_list[i]['phone']}" for i in range(len(addr_list))]) ])["addr"].split(".")[0] addr = addr_list[int(addr)] logger.info( i18n_gt()["already_select_address"] .format(addr['prov'] + addr['city'] + addr['area'] + addr['addr'], addr['name'], addr['phone']) ) config["deliver_info"] = json.dumps( { "name": addr["name"], "tel": addr["phone"], "addr_id": addr["addr"], "addr": addr["prov"] + addr["city"] + addr["area"] + addr["addr"], }, ensure_ascii=False, ) logger.debug( "您的screen_id 和 sku_id 和 pay_money 分别为:" + config["screen_id"] + " " + config["sku_id"] + " " + config["pay_money"] ) logger.debug("您的开始销售时间为:" + str(config["time"])) if config["id_bind"] != 0 and ("buyer_info" not in config): url = "https://show.bilibili.com/api/ticket/buyer/list" response = session.get(url, headers=headers) if response.status_code == 412: logger.error(i18n_gt()["not_handled_412"]) buyer_infos = response.json()["data"]["list"] config["buyer_info"] = [] if len(buyer_infos) == 0: logger.error(i18n_gt()["buyer_empty"]) return else: multiselect = True if config["id_bind"] == 1: logger.info(i18n_gt()["id_bind_single"]) multiselect = False if multiselect: buyerids = prompt([ inquirer.Checkbox( "buyerids", message=i18n_gt()["select_buyer"], # "*"*(len(buyer_infos[int(select)]["name"])-1)+ buyer_infos[int(select)]["name"][-1], # buyer_infos[int(select)]["personal_id"][:4]+ "**********"+ buyer_infos[int(select)]["personal_id"][-4:], # buyer_infos[int(select)]["tel"][:3]+ "****"+ buyer_infos[int(select)]["tel"][-4:], choices=[ "{}. {} {} {}".format( i, "*"*(len(buyer_infos[i]["name"])-1)+ buyer_infos[i]["name"][-1], buyer_infos[i]["personal_id"][:4]+ "**********"+ buyer_infos[i]["personal_id"][-4:], buyer_infos[i]["tel"][:3]+ "****"+ buyer_infos[i]["tel"][-4:], ) for i in range(len(buyer_infos))], validate=lambda _, x: len(x) > 0 ) ])["buyerids"] buyerids = [int(i.split(".")[0]) for i in buyerids] config["buyer_info"] = [] for select in buyerids: config["buyer_info"].append( buyer_infos[int(select)] ) logger.info( i18n_gt()["selected_buyer"].format( "*"*(len(buyer_infos[int(select)]["name"])-1)+ buyer_infos[int(select)]["name"][-1], buyer_infos[int(select)]["personal_id"][:4]+ "**********"+ buyer_infos[int(select)]["personal_id"][-4:], buyer_infos[int(select)]["tel"][:3]+ "****"+ buyer_infos[int(select)]["tel"][-4:], ) ) # if int(buyer_infos[int(select)]["personal_id"][16]) % 2 == 0: # user_female = True # else: # user_male = True # if easter_egg: # if len(buyerids) == 1: # logger.info("单身是这样的🤣 情(xiàn)侣(chōng)们只需要相互做搭子就可以逛的很开心, 可是一个人去逛漫展的人们需要考虑的事情就多了。") # else: # if user_male and user_female: # logger.error("小情侣不得house😡") # elif user_male and not user_female: # logger.error("我朝,有南通啊!") # if len(buyerids) == 4: # logger.error("我朝,开impart啊!") # elif user_female and not user_male: # logger.error("我朝,有女同啊!") else: index = prompt([ inquirer.List("index", message=i18n_gt()["select_buyer"], choices=[ "{}. {} {} {}".format( i, "*"*(len(buyer_infos[i]["name"])-1)+ buyer_infos[i]["name"][-1], buyer_infos[i]["personal_id"][:4]+ "**********"+ buyer_infos[i]["personal_id"][-4:], buyer_infos[i]["tel"][:3]+ "****"+ buyer_infos[i]["tel"][-4:], ) for i in range(len(buyer_infos)) ]) ])["index"] config["buyer_info"].append(buyer_infos[int(index.split(".")[0])]) logger.info( i18n_gt()["selected_buyer"].format( "*"*(len(buyer_infos[int(select)]["name"])-1)+ buyer_infos[int(select)]["name"][-1], buyer_infos[int(select)]["personal_id"][:4]+ "**********"+ buyer_infos[int(select)]["personal_id"][-4:], buyer_infos[int(select)]["tel"][:3]+ "****"+ buyer_infos[int(select)]["tel"][-4:], ) ) if "count" not in config: config["count"] = len(config["buyer_info"]) config["buyer_info"] = json.dumps(config["buyer_info"]) if config["id_bind"] == 0 and ( "buyer" not in config or "tel" not in config ): logger.info(i18n_gt()["add_contact_info"]) config["buyer"] = input(i18n_gt()["add_contact_name"]) config["tel"] = prompt([ inquirer.Text("tel", message=i18n_gt()["add_contact_tel"], validate=lambda _, x: len(x) == 11) ])["tel"] if "count" not in config: config["count"] = prompt([ inquirer.Text("count", message=i18n_gt()["add_buy_tickets"], default="1", validate=lambda _, x: x.isdigit() and int(x) > 0) ])["count"] if config["is_paper_ticket"]: if config["express_fee"] == 0: config["all_price"] = int(config["pay_money"]) * int( config["count"] ) logger.info( i18n_gt()["show_all_price_paper_ticket"].format(config['count'],\ config['ticket_desc'], int(config['pay_money']) / 100, 0, config['all_price'] / 100) ) else: config["all_price"] = ( int(config["pay_money"]) * int(config["count"]) + config["express_fee"] ) logger.info( i18n_gt()["show_all_price_paper_ticket"].format(config['count'], config['ticket_desc'],\ int(config['pay_money']) / 100, config['express_fee'] / 100, config['all_price'] / 100) ) else: config["all_price"] = int(config["pay_money"]) * int( config["count"] ) logger.info( i18n_gt()["show_all_price_e_ticket"].format( config["count"], config["ticket_desc"], int(config["pay_money"]) / 100, config["all_price"] / 100, ) ) save(config) sentry_sdk.capture_message("config complete") BHYG = BilibiliHyg(config, sentry_sdk, kdl_client, session) BHYG.waited = True run(BHYG) except KeyboardInterrupt: logger.info(i18n_gt()["exit_manual"]) return except Exception as e: track = sentry_sdk.capture_exception(e) logger.error(i18n_gt()["error_occured"].format(str(e), str(track))) return return if __name__ == "__main__": try: main() except KeyboardInterrupt: logger.info(i18n_gt()["exit_manual"]) from sentry_sdk import Hub client = Hub.current.client if client is not None: client.close(timeout=2.0) logger.info(i18n_gt()["exit_sleep_15s"]) try: time.sleep(15) except KeyboardInterrupt: pass