├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature-request.yaml
│ └── bug-report.yaml
└── workflows
│ ├── dpm-update.yml
│ └── codeql-analysis.yml
├── src
├── console.py
├── __init__.py
├── live_exit.py
├── up_to_date.py
├── login.py
├── agent.py
└── getGift.py
├── .gitattributes
├── images
├── BGRGS.png
└── Demo.png
├── .flake8
├── pyproject.toml
├── LICENSE
├── main.py
├── .gitignore
├── README.md
└── poetry.lock
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/src/console.py:
--------------------------------------------------------------------------------
1 | from rich.console import Console
2 |
3 | console = Console()
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/images/BGRGS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxie123/Bilibili_GetReceivedGiftStream/HEAD/images/BGRGS.png
--------------------------------------------------------------------------------
/images/Demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boxie123/Bilibili_GetReceivedGiftStream/HEAD/images/Demo.png
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
1 | from . import ( # noqa: F401
2 | agent,
3 | console,
4 | getGift,
5 | live_exit,
6 | login,
7 | up_to_date,
8 | )
9 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | exclude =
3 | __pycache__,
4 | .github,
5 | .venv,
6 | build,
7 | dist,
8 | agent.py,
9 | max-line-length = 120
10 | statistics = True
11 | ; ignore =
12 | ; E501,
13 |
--------------------------------------------------------------------------------
/.github/workflows/dpm-update.yml:
--------------------------------------------------------------------------------
1 | name: Update dependencies
2 |
3 | on:
4 | schedule:
5 | - cron: "0 0 * * *"
6 |
7 | jobs:
8 | update-dependencies:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v3
12 |
13 | - name: Update dependencies
14 | uses: pdm-project/update-deps-action@main
15 | with:
16 | # The update strategy, can be 'reuse', 'eager' or 'all'
17 | update-strategy: all
--------------------------------------------------------------------------------
/src/live_exit.py:
--------------------------------------------------------------------------------
1 | from time import sleep
2 | from sys import exit
3 |
4 | from rich.live import Live
5 |
6 | from .console import console
7 |
8 |
9 | def live_exit(seconds: int = 5):
10 | console.print("\n")
11 | with Live(f"感谢使用,程序将在 [b green]{seconds}[/b green] 秒后退出", console=console) as live:
12 | for i in range(seconds):
13 | sleep(1)
14 | live.update(f"感谢使用,程序将在 [b green]{seconds - 1 - i}[/b green] 秒后退出")
15 | exit(0)
16 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "bilibili-getreceivedgiftstream"
3 | version = "0.1.0"
4 | description = ""
5 | authors = ["铂屑 <80164656+boxie123@users.noreply.github.com>"]
6 | readme = "README.md"
7 | packages = [{include = "bilibili_getreceivedgiftstream"}]
8 |
9 | [tool.poetry.dependencies]
10 | python = "~3.11.4"
11 | qrcode = "^7.4.2"
12 | pillow = "^9.5.0"
13 | httpx = "^0.24.0"
14 | xlsxwriter = "^3.1.0"
15 | rich = "^13.3.5"
16 | pyinstaller = "^5.10.1"
17 |
18 | [tool.poetry.dev-dependencies]
19 | flake8 = "^5.0.4"
20 | black = {version = "^22.6.0", allow-prereleases = true}
21 |
22 | [build-system]
23 | requires = ["poetry-core"]
24 | build-backend = "poetry.core.masonry.api"
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yaml:
--------------------------------------------------------------------------------
1 | name: 功能建议
2 | description: 改进现有功能或提出新功能
3 | title: '【功能建议】'
4 | labels: [ "feature" ]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | ## 请补全标题并认真填写下方内容
11 |
12 | - type: input
13 | id: version
14 | attributes:
15 | label: Bilibili_GetReceivedGiftStream 版本
16 | description: 可在文件名或 `main.py` 中查看
17 | validations:
18 | required: true
19 |
20 | - type: textarea
21 | id: feature_description
22 | attributes:
23 | label: 功能建议
24 | description: 想要改进或者添加的功能
25 | validations:
26 | required: true
27 |
28 | - type: textarea
29 | id: extra_info
30 | attributes:
31 | label: 额外信息(可选)
32 | description: 如:为什么需要这个功能?在什么场景下适用?
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 铂屑
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/up_to_date.py:
--------------------------------------------------------------------------------
1 | import httpx
2 |
3 | from .console import console
4 |
5 |
6 | def main(now_tag):
7 | console.print("\n\n")
8 | console.rule("[b]检测更新", characters="=")
9 | header = {"accept": "application/vnd.github.v3+json"}
10 | url = (
11 | "https://api.github.com/repos/boxie123/Bilibili_GetReceivedGiftStream/releases"
12 | )
13 | param = {"per_page": 1, "page": 1}
14 | with console.status("正在检测更新(此步骤不影响上述已生成的文件,若无需检测可直接关闭程序)", spinner="line"):
15 | releases_info = httpx.get(
16 | url, headers=header, params=param, timeout=None, verify=False
17 | ).json()
18 | tag_name = releases_info[0]["tag_name"]
19 | if tag_name == now_tag:
20 | console.print("提示:当前已是最新版本")
21 | else:
22 | new_html_url = releases_info[0]["html_url"]
23 | console.print(
24 | "提示:检测到更新,当前版本[blue]{}[/blue],最新版本[green]{}[/green]".format(
25 | now_tag, tag_name
26 | )
27 | )
28 | console.print("\n可按住 [b]Ctrl[/b] 并单击下面的链接到浏览器下载最新版本:")
29 | console.print(new_html_url, style=f"link {new_html_url}")
30 |
31 |
32 | # if __name__ == "__main__":
33 | # main("v0.7.0")
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yaml:
--------------------------------------------------------------------------------
1 | name: 错误回报
2 | description: 在使用 Bilibili_GetReceivedGiftStream 的过程中遇到了错误
3 | title: '【错误回报】'
4 | labels: [ "bug?" ]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | ## 请补全标题并认真填写下方内容
11 |
12 | 请清晰描述问题,不必严格套用模板。
13 |
14 | - type: input
15 | id: system_version
16 | attributes:
17 | label: 运行环境
18 | description: 如 Windows Server 2012、CentOS 8.2 等
19 | validations:
20 | required: true
21 |
22 | - type: input
23 | id: version
24 | attributes:
25 | label: Bilibili_GetReceivedGiftStream 版本
26 | description: 可在文件名或 `main.py` 中查看
27 | validations:
28 | required: true
29 |
30 | - type: textarea
31 | id: bug_info
32 | attributes:
33 | label: 错误描述
34 | description: 描述你遇到的问题,需要怎么复现?期望的结果是什么?
35 | validations:
36 | required: true
37 |
38 | - type: textarea
39 | id: log
40 | attributes:
41 | label: 报错日志以及其他描述(如果有)
42 | description: 通过 CMD 打开程序而非双击
43 | value: |
44 | ### 日志
45 |
46 |
47 |
48 |
49 |
50 |
51 | ```bash
52 | # 在这里填写你的报错日志
53 | ```
54 |
55 |
56 |
57 | ### 其他补充描述
58 |
59 |
60 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 |
3 | from rich.panel import Panel
4 | from rich.prompt import Prompt
5 | from rich.tree import Tree
6 |
7 | from src import getGift, login, up_to_date
8 | from src.console import console
9 | from src.live_exit import live_exit
10 |
11 | if __name__ == "__main__":
12 | # 获取用户登录状态
13 | console.print(
14 | Panel.fit(
15 | r"""
16 | ,---, ,---, ,----.. ,---,.
17 | ' .' \ ,`--.' | / / \ ,' .' |
18 | / ; '. | : : | : : ,---.' |
19 | : : \ : | ' . | ;. / | | .'
20 | : | /\ \ | : | . ; /--` : : |-,
21 | | : ' ;. : ' ' ; ; | ; __ : | ;/|
22 | | | ;/ \ \ | | | | : |.' .' | : .'
23 | ' : | \ \ ,' ' : ; . | '_.' : | | |-,
24 | | | ' '--' | | ' ' ; : \ | ' : ;/|
25 | | : : ' : | ' | '/ .' | | \
26 | | | ,' ; |.' | : / | : .'
27 | `--'' '---' \ \ .' | | ,'
28 | `---` `----'
29 | """,
30 | title="本程序美术资源由 [b bright_magenta]艾鸽泰尔德[/b bright_magenta] 友情提供",
31 | subtitle="UID 1485569",
32 | )
33 | )
34 | client = login.main()
35 |
36 | function_dict = {
37 | 0: "退出",
38 | 1: "生成[b green]大航海[/b green]信息记录([b blue]xlsx[/b blue]格式)",
39 | 2: "生成可直接导入 [b green]BiliMessenger[/b green] 使用的大航海数据列表([b blue]csv[/b blue]格式)",
40 | 3: "生成[b green]所有礼物流水[/b green]列表([b blue]xlsx[/b blue]格式)",
41 | 4: "同时生成[b yellow]上述三个[/b yellow]文件",
42 | }
43 |
44 | # 询问用户使用什么功能
45 | console.print("\n本程序目前拥有的功能:\n")
46 |
47 | function_list_tree = Tree("[b]功能列表[/b]")
48 | for key, values in function_dict.items():
49 | function_list_tree.add(f"[b][[cyan]{key}[/cyan]][/b] {values}")
50 | console.print(function_list_tree)
51 |
52 | console.print("之后会要求您输入想要查询的日期区间([b red]闭区间[/b red],统计结果包含开始和结束日期的礼物数据)")
53 | console.print("\n[i]下列所有问题直接回车将默认为 [b cyan]括号中[/b cyan] 结果[/i]")
54 |
55 | choice = Prompt.ask(
56 | "\n请输入[b blue]相应数字[/b blue]来使用相对应的功能:",
57 | choices=[str(key) for key in function_dict.keys()],
58 | default="4",
59 | )
60 | if choice == "0":
61 | live_exit()
62 |
63 | # 使用功能
64 | gift_info = getGift.GiftInfo(client)
65 | console.rule("[b]获取礼物信息", characters="=")
66 | asyncio.run(gift_info.main(choice))
67 |
68 | # 检测更新
69 | try:
70 | up_to_date.main("v0.8.4")
71 | except Exception:
72 | console.print("检测失败")
73 |
74 | # 防止快速退出
75 | console.input("\n\n按回车 [b blue]退出[/b blue] 程序\n")
76 | live_exit()
77 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "main" ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ "main" ]
20 | schedule:
21 | - cron: '27 21 * * 1'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'python' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v3
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v2
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 |
52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
53 | # queries: security-extended,security-and-quality
54 |
55 |
56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
57 | # If this step fails, then you should remove it and run the build manually (see below)
58 | - name: Autobuild
59 | uses: github/codeql-action/autobuild@v2
60 |
61 | # ℹ️ Command-line programs to run using the OS shell.
62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
63 |
64 | # If the Autobuild fails above, remove it and uncomment the following three lines.
65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
66 |
67 | # - run: |
68 | # echo "Run, Build Application using script"
69 | # ./location_of_script_within_repo/buildscript.sh
70 |
71 | - name: Perform CodeQL Analysis
72 | uses: github/codeql-action/analyze@v2
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
105 | __pypackages__/
106 |
107 | # Celery stuff
108 | celerybeat-schedule
109 | celerybeat.pid
110 |
111 | # SageMath parsed files
112 | *.sage.py
113 |
114 | # Environments
115 | .env
116 | .venv
117 | env/
118 | venv/
119 | ENV/
120 | env.bak/
121 | venv.bak/
122 |
123 | # Spyder project settings
124 | .spyderproject
125 | .spyproject
126 |
127 | # Rope project settings
128 | .ropeproject
129 |
130 | # mkdocs documentation
131 | /site
132 |
133 | # mypy
134 | .mypy_cache/
135 | .dmypy.json
136 | dmypy.json
137 |
138 | # Pyre type checker
139 | .pyre/
140 |
141 | # pytype static type analyzer
142 | .pytype/
143 |
144 | # Cython debug symbols
145 | cython_debug/
146 |
147 | # PyCharm
148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
150 | # and can be added to the global gitignore or merged into this file. For a more nuclear
151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
152 | .idea/
153 |
154 | # My
155 | bzcookies.txt
156 | bzcookies
157 | *.xls
158 | *.csv
159 | *.ico
160 | *.json
161 | *.xlsx
162 | test/
163 | .pdm.toml
164 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://boxie123.github.io/Bilibili-GetReceivedGiftStream/)
4 |
5 | # Bilibili_GetReceivedGiftStream
6 |
7 | 登录并获取bilibili账号某段时间礼物流水数据,生成表格。
8 |
9 | 
10 | 
11 | 
12 |
13 | [](https://jq.qq.com/?_wv=1027&k=mEy0fIIq)
14 |
15 |
16 |
17 | ## 功能列表
18 |
19 | 1. 统计指定时间段的大航海记录(开通时间,用户名,uid),附表生成各大航海数量与总积分(xlsx格式)
20 |
21 | 例表:
22 |
23 | 表1:上舰时间
24 |
25 | | ID | UID | 舰长 | 提督 | 总督 |
26 | | ---- | -------- | ------------------- | ---- | ---- |
27 | | 铂屑 | 35192025 | 2022-04-29 09:24:39 | | |
28 |
29 | 表2:积分计算
30 |
31 | | ID | UID | 总积分 | 舰长 | 提督 | 总督 |
32 | | ---- | -------- | ------ | ---- | ---- | ---- |
33 | | 铂屑 | 35192025 | 1 | 1 | 0 | 0 |
34 |
35 | 2. 统计指定时间段的大航海记录(用户,uid,大航海类型)。生成可直接导入 [BiliMessenger](https://github.com/Xinrea/BiliMessengerElectron)(私信群发助手)使用的数据列表(csv格式)
36 |
37 | 3. 生成指定时间段收到所有礼物流水列表(用户,uid,礼物名,电池数),附表为(用户,uid,礼物名,数量)(xlsx格式)
38 |
39 | 例表:
40 |
41 | 表1:电池数量
42 |
43 | | ID | UID | 小花花(id:31036) | 辣条(id:1) | 这个好诶(id:31213) | 舰长(id:10003) | SUM |
44 | | ------ | -------- | ---------------- | ---------- | ------------------ | -------------- | ---- |
45 | | hyt658 | 23262005 | 5 | 0 | 10 | | 15 |
46 | | 铂屑 | 35192025 | | | | 1380 | 1380 |
47 |
48 | 表2:数目
49 |
50 | | ID | UID | 小花花(id:31036) | 辣条(id:1) | 这个好诶(id:31213) | 舰长(id:10003) |
51 | | ------ | -------- | ---------------- | ---------- | ------------------ | -------------- |
52 | | hyt658 | 23262005 | 5 | 2 | 1 | |
53 | | 铂屑 | 35192025 | | | | 1 |
54 |
55 |
56 | 4. 同时生成上述三个文件
57 |
58 | *********************************
59 |
60 | ## 注意事项
61 |
62 | > [!CAUTION]
63 | > 1. 由于本api仅提供**近180天**的数据,超出范围的数据均为0,请勿使用本程序查询过于久远的记录,防止造成误导。
64 | >
65 | > 1. 本程序会自动生成数个文件,分别为
66 | >
67 | > - `bzcookies`
68 | >
69 | > - `yyyy年mm月nn日至yyyy年mm月nn日礼物统计(大航海).xlsx/csv`
70 | >
71 | > - `yyyy年mm月nn日至yyyy年mm月nn日礼物统计.xlsx`
72 | >
73 | > 请确保运行本程序前,当前文件夹中**无同名文件**,否则会直接覆盖造成数据损失。
74 | >
75 | > 1. **其中 `bzcookies` 为重要账号登录信息,请谨慎保管、切勿泄漏,否则可能导致账号被盗用等后果。**
76 |
77 | ****************************************
78 |
79 | ## 使用方法
80 |
81 | ### 方法一:下载打包好的程序(推荐)
82 |
83 | 下载最新的 [Release](https://github.com/boxie123/Bilibili_GetReceivedGiftStream/releases) 中的 `.exe` 文件,双击运行。
84 |
85 | Demo:
86 |
87 | 
88 |
89 | ### 方法二:手动构建
90 |
91 | > 需使用 [git](https://git-scm.com/)、[pdm](https://github.com/pdm-project/pdm)、[python](https://www.python.org/) 等,不建议小白手动构建。
92 |
93 | #### 克隆Git仓库:
94 |
95 | ```sh
96 | git clone https://github.com/boxie123/Bilibili_GetReceivedGiftStream.git
97 | cd Bilibili_GetReceivedGiftStream
98 | ```
99 |
100 | #### 构建虚拟环境:
101 |
102 | 使用 [pdm](https://github.com/pdm-project/pdm):
103 |
104 | ```sh
105 | pdm install --prod
106 | ```
107 |
108 | #### 运行:
109 |
110 | ```sh
111 | pdm run python main.py
112 | ```
113 |
114 | ************************************
115 |
116 | ## Q & A
117 |
118 | Q: 程序闪退?
119 |
120 | A: 大概率是网络问题导致爬取过程中链接超时。
121 |
122 | --------------------------------------
123 |
124 | Q: 大航海表格可以生成,但礼物表格生成失败?
125 |
126 | A: 0.7.0及以下版本使用 xls 的 `SUM` 求和公式,但 xls 为 Excel 2007 之前的版本,求和公式最大参数限制为30个,
127 | 目前已弃用 xls 改用 xlsx ,请及时更新至0.8.0及以上版本。
128 |
129 | ----------------------------------------
130 |
131 | 若排除以上原因后仍然闪退,请打开 CMD 窗口手动运行程序,带着**报错信息**来提 [Issues](https://github.com/boxie123/Bilibili_GetReceivedGiftStream/issues) 吧!
132 |
133 | ## 支持与贡献
134 |
135 | 觉得好用可以给这个项目点个 Star 或者去关注非常可爱的 [艾鸽泰尔德](https://space.bilibili.com/1485569)。
136 |
137 | 有意见或者建议也欢迎提交 [Issues](https://github.com/boxie123/Bilibili_GetReceivedGiftStream/issues) 和 [Pull requests](https://github.com/boxie123/Bilibili_GetReceivedGiftStream/pulls)。
138 |
139 | **************************************
140 |
141 | 开发者:[铂屑](https://github.com/boxie123)、[hyt658](https://github.com/hyt658)
142 |
143 | 开发思路:详见[《Bilibili GetReceivedGiftStream》](https://boxie123.github.io/Bilibili-GetReceivedGiftStream/)。
144 | ~~在写了再写了(目移)~~
145 |
146 | ————致 [@艾鸽泰尔德](https://space.bilibili.com/1485569) ,希望可爱的鸽宝统计礼物不再辛苦。
147 |
--------------------------------------------------------------------------------
/src/login.py:
--------------------------------------------------------------------------------
1 | import http.cookiejar as cookielib
2 | import json
3 | import os
4 | import tempfile
5 | import tkinter
6 | import tkinter.font
7 |
8 | import httpx
9 | import qrcode
10 | from PIL.ImageTk import PhotoImage
11 |
12 | from . import agent
13 | from .console import console
14 |
15 | API = {
16 | "qrcode": {
17 | "get_qrcode_and_token": {
18 | "url": "https://passport.bilibili.com/x/passport-login/web/qrcode/generate",
19 | "method": "GET",
20 | "verify": False,
21 | "comment": "请求二维码及登录密钥",
22 | },
23 | "get_events": {
24 | "url": "https://passport.bilibili.com/x/passport-login/web/qrcode/poll",
25 | "method": "GET",
26 | "verify": False,
27 | "data": {"qrcode_key": "str: 登陆密钥"},
28 | "comment": "获取最新信息",
29 | },
30 | }
31 | }
32 |
33 | headers = {
34 | "User-Agent": agent.get_user_agents(),
35 | "Referer": "https://www.bilibili.com/",
36 | }
37 | headerss = {
38 | "User-Agent": agent.get_user_agents(),
39 | "Host": "passport.bilibili.com",
40 | "Referer": "https://passport.bilibili.com/login",
41 | }
42 |
43 | # ----------------------------------------------------------------
44 | # 二维码登录
45 | # ----------------------------------------------------------------
46 |
47 | photo = None # 图片的全局变量
48 | client = httpx.Client(verify=False)
49 | login_key = ""
50 | qrcode_image = None
51 | is_destroy = False
52 | id_ = 0 # 事件 id,用于取消 after 绑定
53 |
54 |
55 | def islogin():
56 | """检查登陆是否有效
57 |
58 | Returns:
59 | client: httpx.Client
60 | """
61 | global client
62 | try:
63 | client.cookies.jar.load(ignore_discard=True)
64 | except Exception:
65 | console.print("[b green]bzcookies[/b green] 载入失败")
66 | loginurl = client.get(
67 | "https://api.bilibili.com/x/web-interface/nav", headers=headers
68 | ).json()
69 | if loginurl["code"] == 0:
70 | console.print(
71 | "Cookies值有效,[b blue]{}[/b blue],已登录!".format(loginurl["data"]["uname"])
72 | )
73 | return client, True
74 | else:
75 | console.print("Cookies值已经失效,[blue]已弹出二维码[/blue],请重新扫码登录!")
76 | return client, False
77 |
78 |
79 | def make_qrcode(url) -> str:
80 | qr = qrcode.QRCode()
81 | qr.add_data(url)
82 | img = qr.make_image()
83 | img.save(os.path.join(tempfile.gettempdir(), "qrcode.png"))
84 | return os.path.join(tempfile.gettempdir(), "qrcode.png")
85 |
86 |
87 | def login_with_qrcode():
88 | """通过二维码登陆
89 |
90 | Raises:
91 | Exception: 登陆失败
92 | """
93 |
94 | global photo
95 | global login_key, qrcode_image
96 | global id_
97 | global client
98 |
99 | root = tkinter.Tk()
100 | root.title("扫码登录")
101 | qrcode_image = update_qrcode()
102 | photo = PhotoImage(file=qrcode_image)
103 | qrcode_label = tkinter.Label(root, image=photo, width=500, height=500)
104 | qrcode_label.pack()
105 | big_font = tkinter.font.Font(root, size=25)
106 | log = tkinter.Label(root, text="二维码未失效,请扫码!", font=big_font, fg="red")
107 | log.pack()
108 |
109 | def update_events():
110 | global id_
111 | global is_destroy, client
112 | events_api = API["qrcode"]["get_events"]
113 | try:
114 | events = client.get(
115 | events_api["url"],
116 | params={"qrcode_key": login_key},
117 | headers=headerss,
118 | ).json()
119 | except json.decoder.JSONDecodeError:
120 | console.print("[b green]更新状态失败[/b green] 正在重试")
121 | id_ = root.after(500, update_events)
122 | root.update()
123 | return
124 | if "code" in events.keys() and events["code"] == -412:
125 | raise Exception(events["message"])
126 | if events["data"]["code"] == 86101:
127 | log.configure(text="二维码未失效,请扫码!", fg="red", font=big_font)
128 | elif events["data"]["code"] == 86090:
129 | log.configure(text="已扫码,请确认!", fg="orange", font=big_font)
130 | elif events["data"]["code"] == 86038:
131 | update_qrcode()
132 | log.configure(text="二维码已刷新,请重新扫码", fg="blue", font=big_font)
133 | elif isinstance(events["data"], dict):
134 | url = events["data"]["url"]
135 | client.get(url, headers=headers)
136 | client.cookies.jar.save()
137 |
138 | log.configure(text="登入成功!", fg="green", font=big_font)
139 |
140 | root.after(2000, destroy)
141 | id_ = root.after(2000, update_events)
142 | root.update()
143 |
144 | def destroy():
145 | global id_
146 | root.after_cancel(id_) # type: ignore
147 | root.destroy()
148 |
149 | root.after(500, update_events)
150 | root.mainloop()
151 | root.after_cancel(id_) # type: ignore
152 |
153 |
154 | def update_qrcode() -> str:
155 | """更新二维码
156 |
157 | Returns:
158 | str: 二维码
159 | """
160 | global login_key, qrcode_image, client
161 | api = API["qrcode"]["get_qrcode_and_token"]
162 | qrcode_login_data = json.loads(client.get(api["url"], headers=headers).text)["data"]
163 | login_key = qrcode_login_data["qrcode_key"]
164 | qrcode = qrcode_login_data["url"]
165 | qrcode_image = make_qrcode(qrcode)
166 | return qrcode_image
167 |
168 |
169 | def main():
170 | global client
171 |
172 | nowdir = os.getcwd()
173 | result_file = os.path.join(nowdir, "bzcookies")
174 | if not os.path.exists(result_file):
175 | try:
176 | with open(result_file, "w") as f:
177 | f.write("")
178 | except PermissionError as e:
179 | console.print("当前所在文件夹无写入权限,请将本程序移至其他文件夹再打开")
180 | console.print(e)
181 | console.input("\n按回车退出程序")
182 | client.cookies = cookielib.LWPCookieJar(filename=result_file)
183 | while True:
184 | client, status = islogin()
185 | if not status:
186 | login_with_qrcode()
187 | if status:
188 | return client
189 |
190 |
191 | # if __name__ == "__main__":
192 | # main()
193 |
--------------------------------------------------------------------------------
/src/agent.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | agent = [
4 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60",
5 | "Opera/8.0 (Windows NT 5.1; U; en)",
6 | "Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50",
7 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50",
8 | "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11",
9 | "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11",
10 | "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
11 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0",
12 | "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
13 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv,2.0.1) Gecko/20100101 Firefox/4.0.1",
14 | "Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1",
15 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
16 | "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
17 | "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
18 | "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
19 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36",
20 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
21 | "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16",
22 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
23 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36",
24 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
25 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)",
26 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",
27 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",
28 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)",
29 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)"
30 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",
31 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
32 | "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0",
33 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)",
34 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)",
35 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.3.4000 Chrome/30.0.1599.101 Safari/537.36",
36 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
37 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36",
38 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4094.1 Safari/537.36",
39 | "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
40 | "Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
41 | "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
42 | "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
43 | "Mozilla/5.0 (Linux; U; Android 2.2.1; zh-cn; HTC_Wildfire_A3333 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
44 | "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
45 | "MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
46 | "Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10",
47 | "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
48 | "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, like Gecko) Version/6.0.0.337 Mobile Safari/534.1+",
49 | "Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0",
50 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;",
51 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
52 | "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
53 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
54 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
55 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)",
56 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)",
57 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)",
58 | "Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
59 | "Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124",
60 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; HTC; Titan)",
61 | "UCWEB7.0.2.37/28/999",
62 | "NOKIA5700/ UCWEB7.0.2.37/28/999",
63 | "Openwave/ UCWEB7.0.2.37/28/999",
64 | "Openwave/ UCWEB7.0.2.37/28/999",
65 | ]
66 |
67 |
68 | # 随机获取一个认证头
69 | def get_user_agents():
70 | return random.choice(agent).encode("utf-8").decode("latin-1")
71 |
--------------------------------------------------------------------------------
/src/getGift.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import datetime
3 | from sys import maxsize
4 |
5 | import httpx
6 | import xlsxwriter
7 | from rich.progress import track
8 | from rich.prompt import Confirm, IntPrompt
9 |
10 | from . import agent
11 | from .console import console
12 | from .live_exit import live_exit
13 |
14 |
15 | # 处理全部礼物数据生成字典以及{uid:name}字典
16 | def all_info_handle(gifts_list):
17 | id_index = {}
18 | gift_result = {}
19 | for gift in gifts_list:
20 | key = str(gift["uid"])
21 | id_index[key] = gift["uname"]
22 | gift_name = gift["gift_name"]
23 | gift_id = gift["gift_id"]
24 | gold = gift["normal_gold"] / 100
25 | gift_num = gift["gift_num"]
26 | time = gift["time"]
27 |
28 | if key in gift_result:
29 | if gift_id in gift_result[key]:
30 | gift_result[key][gift_id]["gold"] += gold
31 | gift_result[key][gift_id]["gift_num"] += gift_num
32 | gift_result[key][gift_id]["time"].insert(0, gift["time"])
33 | else:
34 | gift_result[key][gift_id] = {
35 | "gift_name": gift_name,
36 | "gold": gold,
37 | "gift_num": gift_num,
38 | "time": [time],
39 | }
40 | else:
41 | gift_result[key] = {
42 | gift_id: {
43 | "gift_name": gift_name,
44 | "gold": gold,
45 | "gift_num": gift_num,
46 | "time": [time],
47 | }
48 | }
49 | return gift_result, id_index
50 |
51 |
52 | # 处理礼物信息生成大航海字典以及{uid:name}字典
53 | def guard_info(gifts_list):
54 | id_index = {}
55 | gift_result = {}
56 | for gift in gifts_list:
57 | key = str(gift["uid"])
58 | id_index[key] = gift["uname"]
59 | if gift["gift_name"] in ("舰长", "提督", "总督"):
60 | title = gift["gift_name"]
61 | else:
62 | continue
63 |
64 | if key in gift_result:
65 | gift_result[key][title].insert(0, gift["time"])
66 | else:
67 | val = {"总督": [], "提督": [], "舰长": [], title: [gift["time"]]}
68 | gift_result[key] = val
69 |
70 | return gift_result, id_index
71 |
72 |
73 | class GiftInfo:
74 | # 构造函数,生成特定格式的日期列表
75 | def __init__(self, client: httpx.Client):
76 | self.cookies = client.cookies
77 | client.close()
78 | ask_list = ["年份", "月份", "日期"]
79 | datetime_today = datetime.datetime.today()
80 | today_date_list = [
81 | datetime_today.year,
82 | datetime_today.month,
83 | datetime_today.day,
84 | ]
85 | while True:
86 | console.rule("[b]输入查询开始日期")
87 |
88 | begin_date_list = [0 for _ in range(3)]
89 | for i in range(3):
90 | ask = "请输入想查询的开始[b blue]{}[/b blue]".format(ask_list[i])
91 | begin_date_list[i] = IntPrompt.ask(
92 | ask,
93 | console=console,
94 | default=today_date_list[i],
95 | )
96 |
97 | self.year_begin, self.month_begin, self.day_begin = begin_date_list
98 |
99 | try:
100 | date_begin = datetime.date(
101 | self.year_begin, self.month_begin, self.day_begin
102 | )
103 | break
104 | except ValueError as e:
105 | console.print(f"\n[bold red]Warning:[/bold red] 输入日期错误:{e}")
106 | console.print("请重新输入\n")
107 |
108 | most_early_date = datetime.date.today() - datetime.timedelta(179)
109 | if date_begin < most_early_date:
110 | console.print(
111 | "\n[bold red]Warning:[/bold red] b站仅提供近180天数据,可查询最早日期为:{}".format(
112 | most_early_date.strftime("%Y-%m-%d")
113 | )
114 | )
115 | console.print("您查询的日期超出范围的部分数据将[b red]全部为0[/b red]\n")
116 | if not Confirm.ask("是否确认继续?", console=console):
117 | live_exit()
118 |
119 | while True:
120 | console.rule("[b]输入查询末尾日期")
121 |
122 | end_date_list = [0 for _ in range(3)]
123 | for i in range(3):
124 | ask = "请输入想查询的末尾[b blue]{}[/b blue]".format(ask_list[i])
125 | end_date_list[i] = IntPrompt.ask(
126 | ask,
127 | console=console,
128 | default=today_date_list[i],
129 | )
130 |
131 | self.year_end, self.month_end, self.day_end = end_date_list
132 |
133 | try:
134 | date_end = datetime.date(self.year_end, self.month_end, self.day_end)
135 | break
136 | except ValueError as e:
137 | console.print(f"\n[bold red]Warning:[/bold red] 输入日期错误:{e}")
138 | console.print("请重新输入\n")
139 |
140 | if date_begin > date_end:
141 | console.print("\n[bold red]Warning:[/bold red] 开始日期晚于结束日期,将生成空表格\n")
142 | if not Confirm.ask("是否确认继续?", console=console):
143 | live_exit()
144 |
145 | day_list_range = []
146 | delta = datetime.timedelta(days=1)
147 | while date_begin <= date_end:
148 | day_str = date_begin.strftime("%Y-%m-%d")
149 | day_list_range.append(day_str)
150 | date_begin += delta
151 |
152 | self.day_list = day_list_range
153 | self.name = "{}年{}月{}日至{}年{}月{}日礼物统计".format(
154 | self.year_begin,
155 | self.month_begin,
156 | self.day_begin,
157 | self.year_end,
158 | self.month_end,
159 | self.day_end,
160 | )
161 |
162 | # 获取某一段时间礼物信息
163 | async def getGiftInfoOneDay(self):
164 | url = "https://api.live.bilibili.com/xlive/revenue/v1/giftStream/getReceivedGiftStreamNextList"
165 | headers = {
166 | "User-Agent": agent.get_user_agents(),
167 | "Referer": "https://link.bilibili.com/p/center/index",
168 | }
169 | all_gifts_list = []
170 | async with httpx.AsyncClient(
171 | cookies=self.cookies, headers=headers
172 | ) as async_client:
173 | for date in track(self.day_list, description="正在抓取礼物信息", console=console):
174 | params = {
175 | "limit": maxsize - 1,
176 | "coin_type": 0,
177 | "gift_id": "",
178 | "begin_time": date,
179 | "uname": "",
180 | }
181 | resp = await async_client.get(url, params=params)
182 | all_info = resp.json()
183 | gifts_list = all_info["data"]["list"]
184 | has_more = all_info["data"]["has_more"]
185 | if gifts_list:
186 | last_id = gifts_list[-1]["id"]
187 | all_gifts_list.extend(gifts_list)
188 |
189 | while has_more:
190 | console.print("[b red]已触发“has_more”[/b red]")
191 | params = {
192 | "last_id": last_id,
193 | "limit": maxsize - 1,
194 | "coin_type": 0,
195 | "gift_id": "",
196 | "begin_time": date,
197 | "uname": "",
198 | }
199 | resp = await async_client.get(url, params=params)
200 | all_info = resp.json()
201 | gifts_list = all_info["data"]["list"]
202 | has_more = all_info["data"]["has_more"]
203 | if gifts_list:
204 | last_id = gifts_list[-1]["id"]
205 | all_gifts_list.extend(gifts_list)
206 |
207 | return all_gifts_list
208 |
209 | # 全部礼物信息写入xlsx文件
210 | def xlsWrite(self, gift_result, id_index):
211 | with console.status(f"正在写入[b green]{self.name}.xlsx[/b green]", spinner="line"):
212 | wb = xlsxwriter.Workbook(self.name + ".xlsx")
213 | sheet = wb.add_worksheet("电池数量")
214 | sheet_num = wb.add_worksheet("礼物数目")
215 | sheet_header_list = ["ID", "UID"]
216 | sheet.write_row(0, 0, sheet_header_list)
217 | sheet_num.write_row(0, 0, sheet_header_list)
218 |
219 | row = 1
220 | gold_sum_list = [
221 | "SUM",
222 | ]
223 | for uid in gift_result:
224 | sheet.write(row, 1, uid)
225 | sheet.write(row, 0, id_index[uid])
226 | sheet_num.write(row, 1, uid)
227 | sheet_num.write(row, 0, id_index[uid])
228 | gold_sum = 0
229 | for gift_id in gift_result[uid]:
230 | if gift_id not in sheet_header_list:
231 | sheet_header_list.append(gift_id)
232 | column = sheet_header_list.index(gift_id)
233 | gift_name = gift_result[uid][gift_id]["gift_name"]
234 | sheet.write(0, column, f"{gift_name}(id:{gift_id})")
235 | sheet_num.write(0, column, f"{gift_name}(id:{gift_id})")
236 | column = sheet_header_list.index(gift_id)
237 | gold_temp = gift_result[uid][gift_id]["gold"]
238 | sheet.write(row, column, gold_temp)
239 | gold_sum += gold_temp
240 | sheet_num.write(row, column, gift_result[uid][gift_id]["gift_num"])
241 | row += 1
242 | gold_sum_list.append(gold_sum)
243 |
244 | # 求和
245 | column = len(sheet_header_list)
246 | sheet.write_column(0, column, gold_sum_list)
247 |
248 | wb.close()
249 |
250 | console.print("[b green]{}.xlsx[/b green] 已生成!".format(self.name))
251 |
252 | # 根据大航海礼物信息生成xlsx统计结果
253 | def generateXlsFile(self, guard_dict, id_index):
254 | with console.status(
255 | f"正在写入[b green]{self.name}(大航海).xlsx[/b green]", spinner="line"
256 | ):
257 | wb = xlsxwriter.Workbook(filename=self.name + "(大航海).xlsx")
258 |
259 | text_wrap = wb.add_format({"text_wrap": True})
260 | sheet = wb.add_worksheet("上舰时间")
261 | sheet_header_list = ["ID", "UID", "舰长", "提督", "总督"]
262 |
263 | sheet.write_row(0, 0, sheet_header_list)
264 | sheet.set_column(1, len(sheet_header_list), 25)
265 |
266 | row = 1
267 | sheet1 = wb.add_worksheet("上舰具体数量")
268 | sheet1_head = ["ID", "UID", "总积分", "舰长", "提督", "总督"]
269 | sheet1.write_row(0, 0, sheet1_head)
270 | row1 = 1
271 |
272 | for uid in guard_dict:
273 | scores = (
274 | len(guard_dict[uid]["舰长"])
275 | + 15 * len(guard_dict[uid]["提督"])
276 | + 200 * len(guard_dict[uid]["总督"])
277 | )
278 | sheet.write(row, 1, uid)
279 | sheet.write(row, 0, id_index[uid])
280 | sheet1.write(row1, 1, uid)
281 | sheet1.write(row1, 0, id_index[uid])
282 | sheet1.write(row1, 2, scores)
283 | for title in guard_dict[uid]:
284 | all_dates = guard_dict[uid][title]
285 | column1 = sheet1_head.index(title)
286 | sheet1.write(row1, column1, len(all_dates))
287 | if len(all_dates) == 0:
288 | continue
289 | column = sheet_header_list.index(title)
290 | time_str = "\n".join(all_dates)
291 | sheet.write(row, column, time_str, text_wrap)
292 | row += 1
293 | row1 += 1
294 |
295 | wb.close()
296 |
297 | console.print("[b green]{}(大航海).xlsx[/b green] 已生成!".format(self.name))
298 |
299 | # 根据礼物信息生成csv统计结果,可直接导入BiliMessenger使用
300 | def generateCsvFile(self, guard_dict, id_index):
301 | with console.status(
302 | f"正在写入[b green]{self.name}(大航海).csv[/b green]", spinner="line"
303 | ):
304 | csv_list = []
305 | for uid, gifts in guard_dict.items():
306 | usr_name = id_index[uid]
307 | gifts_name = ""
308 | gifts_list = ["舰长", "提督", "总督"]
309 | for i in gifts_list:
310 | if gifts[i]:
311 | gifts_name = i
312 |
313 | row_list = [gifts_name, uid, usr_name]
314 | csv_list.append(row_list)
315 |
316 | with open(
317 | self.name + "(大航海).csv", mode="w", encoding="utf-8-sig", newline=""
318 | ) as f:
319 | writer = csv.writer(f)
320 | writer.writerows(csv_list)
321 |
322 | console.print("[b green]{}(大航海).csv[/b green] 已生成!".format(self.name))
323 |
324 | async def main(self, choice):
325 | gifts_list = await self.getGiftInfoOneDay()
326 | if choice == "1":
327 | guard_dict, id_index = guard_info(gifts_list)
328 | self.generateXlsFile(guard_dict, id_index)
329 | elif choice == "2":
330 | guard_dict, id_index = guard_info(gifts_list)
331 | self.generateCsvFile(guard_dict, id_index)
332 | elif choice == "3":
333 | gift_result, id_index = all_info_handle(gifts_list)
334 | self.xlsWrite(gift_result, id_index)
335 | elif choice == "4":
336 | guard_dict, id_index = guard_info(gifts_list)
337 | self.generateXlsFile(guard_dict, id_index)
338 | self.generateCsvFile(guard_dict, id_index)
339 | gift_result, id_index = all_info_handle(gifts_list)
340 | self.xlsWrite(gift_result, id_index)
341 | console.print("\n已全部生成完成!")
342 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
2 |
3 | [[package]]
4 | name = "altgraph"
5 | version = "0.17.4"
6 | description = "Python graph (network) package"
7 | optional = false
8 | python-versions = "*"
9 | files = [
10 | {file = "altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff"},
11 | {file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
12 | ]
13 |
14 | [[package]]
15 | name = "anyio"
16 | version = "4.1.0"
17 | description = "High level compatibility layer for multiple asynchronous event loop implementations"
18 | optional = false
19 | python-versions = ">=3.8"
20 | files = [
21 | {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"},
22 | {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"},
23 | ]
24 |
25 | [package.dependencies]
26 | idna = ">=2.8"
27 | sniffio = ">=1.1"
28 |
29 | [package.extras]
30 | doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
31 | test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
32 | trio = ["trio (>=0.23)"]
33 |
34 | [[package]]
35 | name = "black"
36 | version = "22.12.0"
37 | description = "The uncompromising code formatter."
38 | optional = false
39 | python-versions = ">=3.7"
40 | files = [
41 | {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"},
42 | {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"},
43 | {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"},
44 | {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"},
45 | {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"},
46 | {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"},
47 | {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"},
48 | {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"},
49 | {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"},
50 | {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"},
51 | {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"},
52 | {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"},
53 | ]
54 |
55 | [package.dependencies]
56 | click = ">=8.0.0"
57 | mypy-extensions = ">=0.4.3"
58 | pathspec = ">=0.9.0"
59 | platformdirs = ">=2"
60 |
61 | [package.extras]
62 | colorama = ["colorama (>=0.4.3)"]
63 | d = ["aiohttp (>=3.7.4)"]
64 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
65 | uvloop = ["uvloop (>=0.15.2)"]
66 |
67 | [[package]]
68 | name = "certifi"
69 | version = "2023.11.17"
70 | description = "Python package for providing Mozilla's CA Bundle."
71 | optional = false
72 | python-versions = ">=3.6"
73 | files = [
74 | {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
75 | {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
76 | ]
77 |
78 | [[package]]
79 | name = "click"
80 | version = "8.1.7"
81 | description = "Composable command line interface toolkit"
82 | optional = false
83 | python-versions = ">=3.7"
84 | files = [
85 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
86 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
87 | ]
88 |
89 | [package.dependencies]
90 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
91 |
92 | [[package]]
93 | name = "colorama"
94 | version = "0.4.6"
95 | description = "Cross-platform colored terminal text."
96 | optional = false
97 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
98 | files = [
99 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
100 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
101 | ]
102 |
103 | [[package]]
104 | name = "flake8"
105 | version = "5.0.4"
106 | description = "the modular source code checker: pep8 pyflakes and co"
107 | optional = false
108 | python-versions = ">=3.6.1"
109 | files = [
110 | {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
111 | {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
112 | ]
113 |
114 | [package.dependencies]
115 | mccabe = ">=0.7.0,<0.8.0"
116 | pycodestyle = ">=2.9.0,<2.10.0"
117 | pyflakes = ">=2.5.0,<2.6.0"
118 |
119 | [[package]]
120 | name = "h11"
121 | version = "0.14.0"
122 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
123 | optional = false
124 | python-versions = ">=3.7"
125 | files = [
126 | {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
127 | {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
128 | ]
129 |
130 | [[package]]
131 | name = "httpcore"
132 | version = "0.17.3"
133 | description = "A minimal low-level HTTP client."
134 | optional = false
135 | python-versions = ">=3.7"
136 | files = [
137 | {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"},
138 | {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"},
139 | ]
140 |
141 | [package.dependencies]
142 | anyio = ">=3.0,<5.0"
143 | certifi = "*"
144 | h11 = ">=0.13,<0.15"
145 | sniffio = "==1.*"
146 |
147 | [package.extras]
148 | http2 = ["h2 (>=3,<5)"]
149 | socks = ["socksio (==1.*)"]
150 |
151 | [[package]]
152 | name = "httpx"
153 | version = "0.24.1"
154 | description = "The next generation HTTP client."
155 | optional = false
156 | python-versions = ">=3.7"
157 | files = [
158 | {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"},
159 | {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"},
160 | ]
161 |
162 | [package.dependencies]
163 | certifi = "*"
164 | httpcore = ">=0.15.0,<0.18.0"
165 | idna = "*"
166 | sniffio = "*"
167 |
168 | [package.extras]
169 | brotli = ["brotli", "brotlicffi"]
170 | cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
171 | http2 = ["h2 (>=3,<5)"]
172 | socks = ["socksio (==1.*)"]
173 |
174 | [[package]]
175 | name = "idna"
176 | version = "3.6"
177 | description = "Internationalized Domain Names in Applications (IDNA)"
178 | optional = false
179 | python-versions = ">=3.5"
180 | files = [
181 | {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
182 | {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
183 | ]
184 |
185 | [[package]]
186 | name = "macholib"
187 | version = "1.16.3"
188 | description = "Mach-O header analysis and editing"
189 | optional = false
190 | python-versions = "*"
191 | files = [
192 | {file = "macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c"},
193 | {file = "macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30"},
194 | ]
195 |
196 | [package.dependencies]
197 | altgraph = ">=0.17"
198 |
199 | [[package]]
200 | name = "markdown-it-py"
201 | version = "3.0.0"
202 | description = "Python port of markdown-it. Markdown parsing, done right!"
203 | optional = false
204 | python-versions = ">=3.8"
205 | files = [
206 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
207 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
208 | ]
209 |
210 | [package.dependencies]
211 | mdurl = ">=0.1,<1.0"
212 |
213 | [package.extras]
214 | benchmarking = ["psutil", "pytest", "pytest-benchmark"]
215 | code-style = ["pre-commit (>=3.0,<4.0)"]
216 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
217 | linkify = ["linkify-it-py (>=1,<3)"]
218 | plugins = ["mdit-py-plugins"]
219 | profiling = ["gprof2dot"]
220 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
221 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
222 |
223 | [[package]]
224 | name = "mccabe"
225 | version = "0.7.0"
226 | description = "McCabe checker, plugin for flake8"
227 | optional = false
228 | python-versions = ">=3.6"
229 | files = [
230 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
231 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
232 | ]
233 |
234 | [[package]]
235 | name = "mdurl"
236 | version = "0.1.2"
237 | description = "Markdown URL utilities"
238 | optional = false
239 | python-versions = ">=3.7"
240 | files = [
241 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
242 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
243 | ]
244 |
245 | [[package]]
246 | name = "mypy-extensions"
247 | version = "1.0.0"
248 | description = "Type system extensions for programs checked with the mypy type checker."
249 | optional = false
250 | python-versions = ">=3.5"
251 | files = [
252 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
253 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
254 | ]
255 |
256 | [[package]]
257 | name = "pathspec"
258 | version = "0.11.2"
259 | description = "Utility library for gitignore style pattern matching of file paths."
260 | optional = false
261 | python-versions = ">=3.7"
262 | files = [
263 | {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
264 | {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
265 | ]
266 |
267 | [[package]]
268 | name = "pefile"
269 | version = "2023.2.7"
270 | description = "Python PE parsing module"
271 | optional = false
272 | python-versions = ">=3.6.0"
273 | files = [
274 | {file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"},
275 | {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"},
276 | ]
277 |
278 | [[package]]
279 | name = "pillow"
280 | version = "9.5.0"
281 | description = "Python Imaging Library (Fork)"
282 | optional = false
283 | python-versions = ">=3.7"
284 | files = [
285 | {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"},
286 | {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"},
287 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"},
288 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"},
289 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"},
290 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"},
291 | {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"},
292 | {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"},
293 | {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"},
294 | {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"},
295 | {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"},
296 | {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"},
297 | {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"},
298 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"},
299 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"},
300 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"},
301 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"},
302 | {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"},
303 | {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"},
304 | {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"},
305 | {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"},
306 | {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"},
307 | {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"},
308 | {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"},
309 | {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"},
310 | {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"},
311 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"},
312 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"},
313 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"},
314 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"},
315 | {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"},
316 | {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"},
317 | {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"},
318 | {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"},
319 | {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"},
320 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"},
321 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"},
322 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"},
323 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"},
324 | {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"},
325 | {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"},
326 | {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"},
327 | {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"},
328 | {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"},
329 | {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"},
330 | {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"},
331 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"},
332 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"},
333 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"},
334 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"},
335 | {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"},
336 | {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"},
337 | {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"},
338 | {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"},
339 | {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"},
340 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"},
341 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"},
342 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"},
343 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"},
344 | {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"},
345 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"},
346 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"},
347 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"},
348 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"},
349 | {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"},
350 | {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"},
351 | ]
352 |
353 | [package.extras]
354 | docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
355 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
356 |
357 | [[package]]
358 | name = "platformdirs"
359 | version = "4.0.0"
360 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
361 | optional = false
362 | python-versions = ">=3.7"
363 | files = [
364 | {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"},
365 | {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"},
366 | ]
367 |
368 | [package.extras]
369 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
370 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
371 |
372 | [[package]]
373 | name = "pycodestyle"
374 | version = "2.9.1"
375 | description = "Python style guide checker"
376 | optional = false
377 | python-versions = ">=3.6"
378 | files = [
379 | {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
380 | {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
381 | ]
382 |
383 | [[package]]
384 | name = "pyflakes"
385 | version = "2.5.0"
386 | description = "passive checker of Python programs"
387 | optional = false
388 | python-versions = ">=3.6"
389 | files = [
390 | {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
391 | {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
392 | ]
393 |
394 | [[package]]
395 | name = "pygments"
396 | version = "2.17.2"
397 | description = "Pygments is a syntax highlighting package written in Python."
398 | optional = false
399 | python-versions = ">=3.7"
400 | files = [
401 | {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"},
402 | {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"},
403 | ]
404 |
405 | [package.extras]
406 | plugins = ["importlib-metadata"]
407 | windows-terminal = ["colorama (>=0.4.6)"]
408 |
409 | [[package]]
410 | name = "pyinstaller"
411 | version = "5.13.2"
412 | description = "PyInstaller bundles a Python application and all its dependencies into a single package."
413 | optional = false
414 | python-versions = "<3.13,>=3.7"
415 | files = [
416 | {file = "pyinstaller-5.13.2-py3-none-macosx_10_13_universal2.whl", hash = "sha256:16cbd66b59a37f4ee59373a003608d15df180a0d9eb1a29ff3bfbfae64b23d0f"},
417 | {file = "pyinstaller-5.13.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8f6dd0e797ae7efdd79226f78f35eb6a4981db16c13325e962a83395c0ec7420"},
418 | {file = "pyinstaller-5.13.2-py3-none-manylinux2014_i686.whl", hash = "sha256:65133ed89467edb2862036b35d7c5ebd381670412e1e4361215e289c786dd4e6"},
419 | {file = "pyinstaller-5.13.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:7d51734423685ab2a4324ab2981d9781b203dcae42839161a9ee98bfeaabdade"},
420 | {file = "pyinstaller-5.13.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:2c2fe9c52cb4577a3ac39626b84cf16cf30c2792f785502661286184f162ae0d"},
421 | {file = "pyinstaller-5.13.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c63ef6133eefe36c4b2f4daf4cfea3d6412ece2ca218f77aaf967e52a95ac9b8"},
422 | {file = "pyinstaller-5.13.2-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:aadafb6f213549a5906829bb252e586e2cf72a7fbdb5731810695e6516f0ab30"},
423 | {file = "pyinstaller-5.13.2-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b2e1c7f5cceb5e9800927ddd51acf9cc78fbaa9e79e822c48b0ee52d9ce3c892"},
424 | {file = "pyinstaller-5.13.2-py3-none-win32.whl", hash = "sha256:421cd24f26144f19b66d3868b49ed673176765f92fa9f7914cd2158d25b6d17e"},
425 | {file = "pyinstaller-5.13.2-py3-none-win_amd64.whl", hash = "sha256:ddcc2b36052a70052479a9e5da1af067b4496f43686ca3cdda99f8367d0627e4"},
426 | {file = "pyinstaller-5.13.2-py3-none-win_arm64.whl", hash = "sha256:27cd64e7cc6b74c5b1066cbf47d75f940b71356166031deb9778a2579bb874c6"},
427 | {file = "pyinstaller-5.13.2.tar.gz", hash = "sha256:c8e5d3489c3a7cc5f8401c2d1f48a70e588f9967e391c3b06ddac1f685f8d5d2"},
428 | ]
429 |
430 | [package.dependencies]
431 | altgraph = "*"
432 | macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
433 | pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
434 | pyinstaller-hooks-contrib = ">=2021.4"
435 | pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
436 | setuptools = ">=42.0.0"
437 |
438 | [package.extras]
439 | encryption = ["tinyaes (>=1.0.0)"]
440 | hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
441 |
442 | [[package]]
443 | name = "pyinstaller-hooks-contrib"
444 | version = "2023.10"
445 | description = "Community maintained hooks for PyInstaller"
446 | optional = false
447 | python-versions = ">=3.7"
448 | files = [
449 | {file = "pyinstaller-hooks-contrib-2023.10.tar.gz", hash = "sha256:4b4a998036abb713774cb26534ca06b7e6e09e4c628196017a10deb11a48747f"},
450 | {file = "pyinstaller_hooks_contrib-2023.10-py2.py3-none-any.whl", hash = "sha256:6dc1786a8f452941245d5bb85893e2a33632ebdcbc4c23eea41f2ee08281b0c0"},
451 | ]
452 |
453 | [[package]]
454 | name = "pypng"
455 | version = "0.20220715.0"
456 | description = "Pure Python library for saving and loading PNG images"
457 | optional = false
458 | python-versions = "*"
459 | files = [
460 | {file = "pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"},
461 | {file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
462 | ]
463 |
464 | [[package]]
465 | name = "pywin32-ctypes"
466 | version = "0.2.2"
467 | description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
468 | optional = false
469 | python-versions = ">=3.6"
470 | files = [
471 | {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
472 | {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
473 | ]
474 |
475 | [[package]]
476 | name = "qrcode"
477 | version = "7.4.2"
478 | description = "QR Code image generator"
479 | optional = false
480 | python-versions = ">=3.7"
481 | files = [
482 | {file = "qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"},
483 | {file = "qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"},
484 | ]
485 |
486 | [package.dependencies]
487 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
488 | pypng = "*"
489 | typing-extensions = "*"
490 |
491 | [package.extras]
492 | all = ["pillow (>=9.1.0)", "pytest", "pytest-cov", "tox", "zest.releaser[recommended]"]
493 | dev = ["pytest", "pytest-cov", "tox"]
494 | maintainer = ["zest.releaser[recommended]"]
495 | pil = ["pillow (>=9.1.0)"]
496 | test = ["coverage", "pytest"]
497 |
498 | [[package]]
499 | name = "rich"
500 | version = "13.7.0"
501 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
502 | optional = false
503 | python-versions = ">=3.7.0"
504 | files = [
505 | {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
506 | {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
507 | ]
508 |
509 | [package.dependencies]
510 | markdown-it-py = ">=2.2.0"
511 | pygments = ">=2.13.0,<3.0.0"
512 |
513 | [package.extras]
514 | jupyter = ["ipywidgets (>=7.5.1,<9)"]
515 |
516 | [[package]]
517 | name = "setuptools"
518 | version = "69.0.2"
519 | description = "Easily download, build, install, upgrade, and uninstall Python packages"
520 | optional = false
521 | python-versions = ">=3.8"
522 | files = [
523 | {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"},
524 | {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"},
525 | ]
526 |
527 | [package.extras]
528 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
529 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
530 | testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
531 |
532 | [[package]]
533 | name = "sniffio"
534 | version = "1.3.0"
535 | description = "Sniff out which async library your code is running under"
536 | optional = false
537 | python-versions = ">=3.7"
538 | files = [
539 | {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
540 | {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
541 | ]
542 |
543 | [[package]]
544 | name = "typing-extensions"
545 | version = "4.8.0"
546 | description = "Backported and Experimental Type Hints for Python 3.8+"
547 | optional = false
548 | python-versions = ">=3.8"
549 | files = [
550 | {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
551 | {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
552 | ]
553 |
554 | [[package]]
555 | name = "xlsxwriter"
556 | version = "3.1.9"
557 | description = "A Python module for creating Excel XLSX files."
558 | optional = false
559 | python-versions = ">=3.6"
560 | files = [
561 | {file = "XlsxWriter-3.1.9-py3-none-any.whl", hash = "sha256:b61c1a0c786f82644936c0936ec96ee96cd3afb9440094232f7faef9b38689f0"},
562 | {file = "XlsxWriter-3.1.9.tar.gz", hash = "sha256:de810bf328c6a4550f4ffd6b0b34972aeb7ffcf40f3d285a0413734f9b63a929"},
563 | ]
564 |
565 | [metadata]
566 | lock-version = "2.0"
567 | python-versions = "~3.11.4"
568 | content-hash = "9415f34e899731018f41e2dba0d2985e31946233134fcc3035fb01d2fd6286a3"
569 |
--------------------------------------------------------------------------------