[
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Python Release\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n    Windows-amd64:\n        permissions: write-all\n        runs-on: windows-latest\n        name: Build Windows Binary\n        steps:\n          - name: Checkout\n            uses: actions/checkout@v4\n    \n          - name: Init Python 3.12\n            uses: actions/setup-python@v4\n            with:\n                python-version: '3.12'\n                cache: 'pip'\n    \n          - name: Install Dependent Packages\n            run: |\n                python -m pip install --upgrade pip\n                pip install wheel pyinstaller\n                pip install -r requirements.txt\n            shell: pwsh\n    \n          - name: Pyinstaller\n            run: |\n                pyinstaller ticket_for_allcpp.spec\n            shell: pwsh\n    \n          - name: Upload Windows File\n            uses: actions/upload-artifact@v3\n            with:\n                name: ticket_for_allcpp-windows-amd64\n                path: dist/ticket_for_allcpp.exe\n\n    Linux-amd64:\n        permissions: write-all\n        runs-on: ubuntu-latest\n        name: Build Linux Amd64\n        steps:\n          - name: Checkout\n            uses: actions/checkout@v4\n    \n          - name: Init Python 3.12\n            uses: actions/setup-python@v4\n            with:\n                python-version: '3.12'\n                cache: 'pip'\n    \n          - name: Install Dependent Packages\n            run: |\n                python -m pip install --upgrade pip\n                pip install wheel pyinstaller\n                pip install -r requirements.txt\n\n          - name: Pyinstaller\n            run: |\n                pyinstaller ticket_for_allcpp.spec\n                mv dist/ticket_for_allcpp dist/ticket_for_allcpp-linux-amd64\n    \n          - name: Upload Linux File\n            uses: actions/upload-artifact@v3\n            with:\n                name: ticket_for_allcpp-linux-amd64\n                path: dist/ticket_for_allcpp-linux-amd64\n\n    macos-amd64:\n        permissions: write-all\n        runs-on: macOS-latest\n        name: Build macOS Amd64\n        steps:\n          - name: Checkout\n            uses: actions/checkout@v4\n            \n          - name: Init Python 3.12\n            uses: actions/setup-python@v4\n            with:\n                python-version: '3.12'\n                cache: 'pip'\n        \n          - name: Install Dependent Packages\n            run: |\n                python -m pip install --upgrade pip\n                pip install wheel pyinstaller\n                pip install -r requirements.txt\n\n          - name: Pyinstaller\n            run: |\n                pyinstaller ticket_for_allcpp.spec\n                mv dist/ticket_for_allcpp dist/ticket_for_allcpp-macos-amd64\n        \n          - name: Upload macOS File\n            uses: actions/upload-artifact@v3\n            with:\n                name: ticket_for_allcpp-macos-amd64\n                path: dist/ticket_for_allcpp-macos-amd64\n\n    Create-release:\n        permissions: write-all\n        runs-on: ubuntu-latest\n        needs: [ Windows-amd64, Linux-amd64, macos-amd64]\n        steps:\n          - uses: actions/checkout@v4\n\n          - name: Download Artifact\n            uses: actions/download-artifact@v3\n\n          - name: get release_informations\n            shell: bash\n            run: |\n                mkdir releases\n                mv ./ticket_for_allcpp-macos-amd64/ticket_for_allcpp-macos-amd64 ./releases/ticket_for_allcpp-macos-amd64\n                mv ./ticket_for_allcpp-linux-amd64/ticket_for_allcpp-linux-amd64 ./releases/ticket_for_allcpp-linux-amd64\n                mv ./ticket_for_allcpp-windows-amd64/ticket_for_allcpp.exe ./releases/ticket_for_allcpp-windows-amd64.exe\n                cp config.txt ./releases/config.txt\n                cp cookie.txt ./releases/cookie.txt\n\n          - name: Create Release\n            id: create_release\n            uses: actions/create-release@latest\n            env:\n                GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n            with:\n                tag_name: ${{ github.ref }}\n                release_name: ${{ github.ref }}\n                draft: false\n                prerelease: false\n\n          - name: Upload Release Asset\n            uses: dwenegar/upload-release-assets@v1\n            env:\n                GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n            with:\n                release_id: ${{ steps.create_release.outputs.id }}\n                assets_path: |\n                    ./releases/\n"
  },
  {
    "path": ".gitignore",
    "content": "build/\ndist/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 Koileo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# ticket_for_allcpp\n\n开源免费，简单易用，多线程暴力 CPP 抢票工具。\n\n> [!NOTE]\n> 本程序仅供学习交流, 不得用于商业用途\n> 使用本程序进行违法操作产生的法律责任由操作者自行承担\n> 本次cp30最好使用b站会员购进行抢票，cp30有可能加入验证码，由于之前从未出现，我没办法在开票前保证程序可用性！！！！！\n\n## 安装教程\n\n### 1. 快速安装\n\n前往 [Releases](https://github.com/Koileo/ticket_for_allcpp/releases) 下载最新可执行文件直接命令行运行。\n\n### 2. 源码运行\n\n```shell\ngit clone https://github.com/Koileo/ticket_for_allcpp.git\ncd ticket_for_allcpp\npip install -r requirements.txt\npython main.py\n```\n\n## 使用说明\n\n### cookie.txt 配置\n\n- 第一行为账号`cookie`值，浏览器登入CPP直接F12获取并全部复制即可。\n- 第二行为`ticketid`，同样也是F12查看 https://www.allcpp.cn/allcpp/ticket/getTicketTypeList.do?eventMainId=xxxx 的响应 一般为4位数字\n- 以此类推，第三行第四行也是这样\n\n### config.txt 配置文件：包括ntp服务器，间隔时长，线程数\n\n- 本程序支持多线程，多账户（默认三线程）。\n- 默认实名票全部按照购票人设置数量购买，你绑定几个人买几份票，即默认全选\n- 同一账号支持同时购买不同票类，在第二行用“,\"分开\n\n## 其他可用脚本\n\n| 链接                                                       | 主要特色                |\n| --------------------------------------------------------- | ---------------------- |\n| https://github.com/mikumifa/cppTickerBuy                      |图形化，对小白友好         |\n\n## 未来功能\n\n- [ ] 微信通知\n- [x] 程序外部配置空隔时间和线程数\n- [x] Linux 和 MacOS 打包\n- [x] 时间校准\n\n## 项目问题\n\n反馈程序BUG或者提新功能建议：[点此链接向项目提出反馈BUG](https://github.com/Koileo/ticket_for_allcpp/issues)\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=Koileo/ticket_for_allcpp&type=Date)](https://star-history.com/#Koileo/ticket_for_allcpp&Date)\n"
  },
  {
    "path": "config.txt",
    "content": "[time]\r\nntp = ntp.aliyun.com\r\n\r\n[ticket]\r\nsleep = 1\r\nnum_thread = 3\r\n"
  },
  {
    "path": "cookie.txt",
    "content": "你的cookie\r\nticketid"
  },
  {
    "path": "main.py",
    "content": "# coding=utf-8\r\nimport requests\r\nimport json\r\nimport threading\r\nimport time\r\nimport secrets\r\nimport string\r\nimport hashlib\r\nimport ntplib\r\nimport configparser\r\n\r\n\r\n# 定义一个全局锁用于线程同步\r\nthread_dict = {}\r\ncookie_file_path = 'cookie.txt'\r\nconfig_file_path = 'config.txt'\r\nheaders = {\r\n            'authority': 'www.allcpp.cn',\r\n            'accept': 'application/json, text/plain, */*',\r\n            'accept-language': 'zh-CN,zh;q=0.9',\r\n            'content-type': 'application/json;charset=UTF-8',\r\n            'origin': 'https://cp.allcpp.cn',\r\n            'referer': 'https://cp.allcpp.cn/',\r\n            'sec-ch-ua': '\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"',\r\n            'sec-ch-ua-mobile': '?0',\r\n            'sec-ch-ua-platform': '\"Windows\"',\r\n            'sec-fetch-dest': 'empty',\r\n            'sec-fetch-mode': 'cors',\r\n            'sec-fetch-site': 'same-site',\r\n            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',\r\n        }\r\n\r\n\r\n# 读取配置文件\r\ndef getConfig(filename, section, option):\r\n    conf = configparser.ConfigParser()\r\n    conf.read(filename)\r\n    config = conf.get(section, option)\r\n    return config\r\n\r\n\r\ndef timeconvey(ntp):\r\n    chec = ntplib.NTPClient() \r\n    response = chec.request(ntp) \r\n    timestamp = response.tx_time\r\n    timestamp_local = time.time()\r\n    #print(timestamp_local)\r\n    #print(timestamp)\r\n    differ= timestamp - timestamp_local\r\n    return differ\r\n\r\n\r\ndef sign_for_post(ticketid):\r\n    timestamp = str(int(time.time())) ##\"1682074579\"\r\n    ## 貌似并不校验 sign: a()(t + r + i + e + n)\r\n    # nonce=\"jcFFFK4pPz2eNGBND3xDxTEyZ7PGCyzm\" ## 32位随机值即可\r\n    n = string.ascii_letters + string.digits\r\n    nonce = ''.join(secrets.choice(n) for i in range(32))\r\n    sign=hashlib.md5(f\"2x052A0A1u222{timestamp}{nonce}{ticketid}2sFRs\".encode('utf-8')).hexdigest()\r\n    # print(f\"ticket_type_id={ticket_type_id}\")\r\n    # print(f\"nonce={nonce}\")\r\n    # print(f\"timestamp={timestamp}\")\r\n    # print(f\"sign={sign}\")\r\n    vital='nonce='+nonce+'&timeStamp='+timestamp+'&sign='+sign\r\n    return vital\r\n\r\n\r\ndef cookie_string_to_dict(cookie_string):\r\n    cookies = {}\r\n    cookie_pairs = cookie_string.split(\"; \")\r\n    \r\n    for pair in cookie_pairs:\r\n        key, value = pair.split(\"=\", 1)\r\n        cookies[key] = value\r\n    \r\n    return cookies\r\n\r\n\r\ndef read_cookies_and_tickets_from_file():\r\n    cookies = []\r\n    ticket_id = []\r\n    ticket_ids = []\r\n    try:\r\n        with open(cookie_file_path, 'r',encoding='utf-8') as file:\r\n            lines = file.readlines()\r\n            i = 0\r\n            while i < len(lines):\r\n                cookies.append(lines[i].strip())  # 使用append方法将元素添加到列表\r\n                i += 1\r\n                if i < len(lines):\r\n                    ticket_id.append(lines[i].strip())  # 使用append方法将元素添加到列表\r\n                    i += 1\r\n    except FileNotFoundError:\r\n        print(f\"File '{cookie_file_path}' not found.\")\r\n    for item in ticket_id:\r\n    # 使用逗号分割字符串并添加到输出列表\r\n        ticket_ids.append(item.split(','))\r\n    return cookies, ticket_ids  # 返回两个列表作为一个元组\r\n\r\n\r\ndef getpurser(cookie_str):\r\n    cookies = cookie_string_to_dict(cookie_str)\r\n    pur = requests.get(\r\n        url='https://www.allcpp.cn/allcpp/user/purchaser/getList.do',\r\n        cookies=cookies,\r\n        headers=headers,\r\n    )\r\n    purrer = pur.content.decode(\"utf-8\")\r\n    purrer_data = json.loads(purrer)\r\n    return purrer_data\r\n\r\n\r\ndef check_success(cookies,ticketid):\r\n    url = 'https://www.allcpp.cn/allcpp/user/getMyOrderList.do?pageindex=1&pagesize=10&enabled=0&orderby=0'\r\n    list = requests.get(\r\n        url=url,\r\n        cookies=cookies,\r\n        headers=headers,\r\n    )\r\n    listing = list.content.decode(\"utf-8\")\r\n    data = json.loads(listing)\r\n    # 遍历订单信息\r\n    for order in data['result']['list']:\r\n        if order['ticketTypeId'] == ticketid:\r\n            return True\r\n        else:\r\n            return False\r\n\r\n\r\ndef process_thread(ticketid,cookie_str):\r\n    try:\r\n        cookies = cookie_string_to_dict(cookie_str)\r\n        try:\r\n            pur = requests.get(\r\n                url='https://www.allcpp.cn/allcpp/user/purchaser/getList.do',\r\n                cookies=cookies,\r\n                headers=headers,\r\n            )\r\n\r\n            purrer = pur.content.decode(\"utf-8\")\r\n            purrer_data = json.loads(purrer)\r\n            print(purrer_data)\r\n        except json.decoder.JSONDecodeError as e:\r\n            pass\r\n        ids = [str(item[\"id\"]) for item in purrer_data]\r\n        ids_str = \",\".join(ids)\r\n        id_count = len(ids)\r\n        print(f\"IDs for ticket {ticketid}: {ids_str}\")\r\n        json_data = {}\r\n\r\n\r\n        retn_params = sign_for_post(ticketid)\r\n        url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str(\r\n                id_count) + '&' + retn_params + '&purchaserIds=' + ids_str\r\n        print(url)\r\n        try:\r\n            response = requests.post(\r\n                    url=url,\r\n                    cookies=cookies,\r\n                    headers=headers,\r\n                    json=json_data,\r\n            )\r\n            resp = response.content.decode(\"utf-8\")\r\n            parsed_resp = json.loads(resp)\r\n        except json.decoder.JSONDecodeError as e:\r\n            pass\r\n        print(parsed_resp)\r\n    except:\r\n        pass\r\n    \r\n    i = 0\r\n    if parsed_resp.get(\"isSuccess\") == True:\r\n        print(f\"Thread for ticket {ticketid} succeeded\")\r\n        with open(f\"output_ticket_{ticketid}_{ids_str}.txt\", \"a\") as output_file:\r\n            output_file.write(resp)\r\n        print(f\"Thread for ticket {ticketid} with cookies {cookies} succeeded, closing other two threads of the same type.\")\r\n        threads =[]\r\n        threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies]\r\n        for thread_to_close in threads_to_close[:2]:  # 关闭同类型的前两个线程\r\n            thread_to_close.join()\r\n        return True\r\n    else:\r\n        while i < 2:\r\n            try:\r\n                with open(f\"output_ticket_{ticketid}_{ids_str}_attempt_{i}.txt\", \"a\") as output_file:\r\n                    output_file.write(resp)\r\n                retn_params = sign_for_post(ticketid)\r\n                url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str(\r\n                    id_count) + '&' + retn_params +'&purchaserIds=' + ids_str\r\n                print(url)\r\n                try:\r\n                    response = requests.post(\r\n                        url=url,\r\n                        cookies=cookies,\r\n                        headers=headers,\r\n                        json=json_data,\r\n                    )\r\n                    resp = response.content.decode(\"utf-8\")\r\n                    parsed_resp = json.loads(resp)\r\n                except json.decoder.JSONDecodeError as e:\r\n                    pass\r\n                print(parsed_resp)\r\n                is_success = parsed_resp[\"isSuccess\"]\r\n                if is_success == True:\r\n                    i = 3\r\n                    print(f\"Thread for ticket {ticketid} succeeded\")\r\n                    with open(f\"output_ticket_{ticketid}_{ids_str}.txt\", \"a\") as output_file:\r\n                        output_file.write(resp)\r\n                    threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies]\r\n                    for thread_to_close in threads_to_close[:2]:  # 关闭同类型的前两个线程\r\n                        thread_to_close.join()\r\n                    return True\r\n                else:\r\n                    with open(f\"output_ticket_{ticketid}_{ids_str}_attempt.txt\", \"a\") as output_file:\r\n                        output_file.write(resp)\r\n                        url = 'https://www.allcpp.cn/allcpp/ticket/buyTicketAliWapPay.do?ticketTypeId=' + str(ticketid) + '&count=' + str(\r\n                    id_count) + '&' + retn_params +'&purchaserIds=' + ids_str\r\n                    print(url)\r\n                    try:\r\n                        response = requests.post(\r\n                            url=url,\r\n                            cookies=cookies,\r\n                            headers=headers,\r\n                            json=json_data,\r\n                        )\r\n                        resp = response.content.decode(\"utf-8\")\r\n                        parsed_resp = json.loads(resp)\r\n                        is_success = parsed_resp[\"isSuccess\"]\r\n                    except json.decoder.JSONDecodeError as e:\r\n                        pass\r\n                    if is_success == True:\r\n                            i = 3\r\n                            print(f\"Thread for ticket {ticketid} succeeded\")\r\n                            with open(f\"output_ticket_{ticketid}_{ids_str}.txt\", \"a\") as output_file:\r\n                                output_file.write(resp)\r\n                            threads_to_close = [thread for thread in threads if thread._target == process_thread and thread._args[0] == ticketid and thread._args[1] == cookies]\r\n                            for thread_to_close in threads_to_close[:2]:  # 关闭同类型的前两个线程\r\n                                thread_to_close.join()\r\n                            return True\r\n                    else:\r\n                        with open(f\"output_ticket_{ticketid}_{ids_str}_attempt.txt\", \"a\") as output_file:\r\n                            output_file.write(resp)\r\n                        print(resp)\r\n                        print(type(resp))\r\n                        time.sleep(sleep_time)\r\n            except:\r\n                pass\r\n\r\n\r\ndef start(cookies, ticket_ids):\r\n    thread_dict = {}\r\n\r\n    for i in range(len(cookies)):\r\n        for j in range(len(ticket_ids[i])):\r\n             for _ in range(num_thread):\r\n                ticket = ticket_ids[i][j]\r\n                cook = cookies[i]\r\n                thread = threading.Thread(target=process_thread, args=(ticket, cook))\r\n                thread.start()\r\n\r\n\r\ndef schedule_script_at_timestamp(target_timestamp_ms,cookies, ticket_ids):\r\n    current_timestamp_ms = int(time.time() * 1000)\r\n    time_difference_ms = target_timestamp_ms - current_timestamp_ms\r\n\r\n    if time_difference_ms <= 0:\r\n        print(\"时间已经过去了主人\")\r\n    else:\r\n        print(f\"还有 {time_difference_ms / 1000} 秒喵~.\")\r\n\r\n        def delayed_execution():\r\n            time.sleep(time_difference_ms / 1000)\r\n            start(cookies, ticket_ids)\r\n        t = threading.Thread(target=delayed_execution)\r\n        t.start()\r\n\r\n\r\ndef main():\r\n    ntp = getConfig(\"config.txt\", 'time', 'ntp')\r\n    global sleep_time\r\n    sleep_time = float(getConfig(\"config.txt\", 'ticket', 'sleep'))\r\n    global num_thread\r\n    num_thread = int(getConfig(\"config.txt\", 'ticket', 'num_thread'))\r\n\r\n    differ = timeconvey(ntp)\r\n    if differ > 0 :\r\n        print(f\"\\033[1;31;47m主人你的时间慢了{abs(differ)}秒\\033[0m\")\r\n        print(\"\\033[1;31;47m主人你的时间滞后了哦，请同步时间\\033[0m\")\r\n    else:\r\n        print(f\"\\033[1;31;47m主人你的时间快了{abs(differ)}秒\\033[0m\")\r\n    cookies, ticket_ids = read_cookies_and_tickets_from_file()\r\n    print(ticket_ids)\r\n    i=0\r\n    while i<len(cookies):\r\n        ifn = getpurser(cookies[i])\r\n        print(ifn)\r\n        print(ticket_ids[i])\r\n        i+=1\r\n    if input('正确(回复T) or 错误(回复F) \\n') == 'T':\r\n        print(\"1.定时 2.捡漏\\n\")\r\n        if input()== '1':\r\n            target_timestamp_ms = int(input('输入开始时间戳(毫秒):'))\r\n            schedule_script_at_timestamp(target_timestamp_ms,cookies, ticket_ids)\r\n        else:\r\n            start(cookies, ticket_ids)\r\n    else: \r\n        exit\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n"
  },
  {
    "path": "requirements.txt",
    "content": "requests\nntplib\nconfigparser"
  },
  {
    "path": "ticket_for_allcpp.spec",
    "content": "# -*- mode: python ; coding: utf-8 -*-\r\n\r\n\r\na = Analysis(\r\n    ['main.py'],\r\n    pathex=[],\r\n    binaries=[],\r\n    datas=[],\r\n    hiddenimports=[],\r\n    hookspath=[],\r\n    hooksconfig={},\r\n    runtime_hooks=[],\r\n    excludes=[],\r\n    noarchive=False,\r\n    optimize=0,\r\n)\r\npyz = PYZ(a.pure)\r\n\r\nexe = EXE(\r\n    pyz,\r\n    a.scripts,\r\n    a.binaries,\r\n    a.datas,\r\n    [],\r\n    name='ticket_for_allcpp',\r\n    debug=False,\r\n    bootloader_ignore_signals=False,\r\n    strip=False,\r\n    upx=True,\r\n    upx_exclude=[],\r\n    runtime_tmpdir=None,\r\n    console=True,\r\n    disable_windowed_traceback=False,\r\n    argv_emulation=False,\r\n    target_arch=None,\r\n    codesign_identity=None,\r\n    entitlements_file=None,\r\n)\r\n"
  },
  {
    "path": "timentp.py",
    "content": "import ntplib\r\nimport time\r\ndef timeconvey():\r\n    chec = ntplib.NTPClient() \r\n    response = chec.request('ntp.aliyun.com') \r\n    timestamp = response.tx_time\r\n    timestamp_local = time.time()\r\n    #print(timestamp_local)\r\n    #print(timestamp)\r\n    differ= timestamp - timestamp_local\r\n    return differ"
  }
]