From 658fabd37b6728f85892eb005a3c092c0dc3d8d2 Mon Sep 17 00:00:00 2001 From: ikun Date: Fri, 19 Jul 2024 23:19:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=BC=80=E5=90=A7=EF=BC=81=EF=BC=81?= =?UTF-8?q?=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 2 + .gitignore | 170 ++++++++++++++++++++++++++ LICENSE.md | 67 ++++++++++ README.md | 16 ++- icon.jpg | Bin 0 -> 42114 bytes main.py | 312 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 5 + 7 files changed, 570 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 icon.jpg create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74d457e --- /dev/null +++ b/.gitignore @@ -0,0 +1,170 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Nuitka +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +dist/ + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ +*.json +/output +*.bat +*.xml +*.exe diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f359bc7 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,67 @@ +# Anti CSDN License (ACSL) + +Version 1.0, June 2024 + +Copyright 2024 + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +## Preamble + +The proliferation of software and the ease of copying and modifying it has led to a wide variety of licenses designed to protect the rights of creators while enabling collaboration and further development of the software. This license, the Anti CSDN License (ACSL), is designed with the explicit intent of prohibiting the CSDN and its related websites, including 'gitcode' (hereinafter referred to as "CSDN") from copying, modifying, or redistributing the software (hereinafter referred to as "the Software") it applies to, while still maintaining the software's status as open source for others. The ACSL aims to promote the free use, modification, and sharing of the Software by the open-source community, with the sole restriction of CSDN's involvement. + +## CSDN Details + +CSDN (Chinese Software Developer Network) belongs to Beijing Innovation Lezhi Network Technology Co., Ltd. It is a Chinese information technology knowledge service website with services including information technology dissemination and communication, education and training, and professional technical talent services. It operates a network community, learning platform, and communication platform. + +## Terms and Conditions + +### 1. Definitions + +"This License" refers to version 2.0 of the Anti CSDN License. + +"The Software" refers to the software distributed under this License. + +"CSDN" refers to the website and all its affiliated entities and services that are known for aggregating and redistributing content without explicit permission from the original creators. This includes but is not limited to Gitcode. For detailed information, CSDN (Chinese Software Developer Network) belongs to Beijing Innovation Lezhi Network Technology Co., Ltd. It is a Chinese information technology knowledge service website with services including information technology dissemination and communication, education and training, and professional technical talent services. It operates a network community, learning platform, and communication platform. + +### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each contributor to the Software grants you a worldwide, royalty-free, non-exclusive, perpetual copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the Software and such derivative works in source code or object form. + +### 3. Prohibition for CSDN + +Notwithstanding the above grant, CSDN and its associated entities, including Gitcode, are expressly prohibited from: + +a. Copying, modifying, or redistributing the Software or any derivative works thereof, in any form. + +b. Using the Software for any form of aggregation, compilation, or database that is accessible on or through any platforms owned, operated, or controlled by CSDN and its associated entities, including Gitcode. + +c. Engaging in any activity that directly or indirectly infringes on the rights granted under this License to any user of the Software. + +### 4. Redistribution + +You may reproduce and distribute copies of the Software or any derivative works thereof in any medium, with or without modifications, provided that you meet the following conditions: + +a. You must give any other recipients of the Software or derivative works a copy of this License; and + +b. You must cause any modified files to carry prominent notices stating that you changed the files; and + +c. You must retain, in the Software or derivative works, all copyright and permission notices as found in the original Software.(To prevent theft, recommend that you also add Anti CSDN license for your projects) + +### 5. Disclaimer of Warranty + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +### 6. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any contributor to the Software be liable to you for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Software (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such contributor has been advised of the possibility of such damages. + +### 7. Accepting Warranty or Additional Liability + +While redistributing the Software or derivative works thereof, you may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, you may act only on your own behalf and on your sole responsibility, not on behalf of any other contributors to the Software, and only if you agree to indemnify, defend, and hold each contributor harmless for any liability incurred by, or claims asserted against, such contributor by reason of your accepting any such warranty or additional liability. + +## END OF TERMS AND CONDITIONS + +By using, copying, modifying, or distributing the Software (or any work based on the Software), you agree to be bound by the terms of this License. If you do not agree to the terms of this License, do not use, copy, modify, or distribute the Software. + +If you seek to redistribute the Software in a manner not permitted by this License, or if you have questions about obtaining additional permissions, please contact the original creators of the Software. diff --git a/README.md b/README.md index 88cc5fc..e0b2e13 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,24 @@ ## Onekey - Onekey Steam Manifest Downloader - 因部分事件不再开放源代码下载 + Onekey Steam Depot Manifest Downloader ## 使用方法 先去Release下最新发布,然后去steamtools官网下steamtools,日志会有点石介意别用 +## 项目协议 + 本项目基于 GPL V3.0 许可证发行,以下协议是对于 GPL V3.0 原协议的补充,如有冲突,以以下协议为准。 + + 词语约定:“使用者”指签署本协议的使用者;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。 + + 本项目的数据来源原理是从Steam官方的CDN服务器中拉取游戏清单数据,经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的准确性负责。 + 使用本项目的过程中可能会产生版权数据,对于这些版权数据,本项目不拥有它们的所有权,为了避免造成侵权,使用者务必在24 小时内清除使用本项目的过程中所产生的版权数据。 + 由于使用本项目产生的包括由于本协议或由于使用或无法使用本项目而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。 + 本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本项目不对项目内的技术可能存在违反当地法律法规的行为作保证,禁止在违反当地法律法规的情况下使用本项目,对于使用者在明知或不知当地法律法规不允许的情况下使用本项目所造成的任何违法违规行为由使用者承担,本项目不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。 + 而且,本项目已禁止使用于商业用途。 + 若你使用了本项目,将代表你接受以上协议。 + + Steam正版平台不易,请尊重版权,支持正版。 本项目仅用于对技术可行性的探索及研究,不接受任何商业(包括但不限于广告等)合作。 ## Star 趋势图 diff --git a/icon.jpg b/icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..549e5fa93b33811c126199679af8babe60082074 GIT binary patch literal 42114 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

{&3<*M)zi{jhJ&52k-$I1F*{P@ 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 Qi+?g16{sT_4*t&n2M%cQfdBvi literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..25e6352 --- /dev/null +++ b/main.py @@ -0,0 +1,312 @@ +import os +import vdf +import winreg +import argparse +import aiohttp +import aiofiles +import traceback +import subprocess +import colorlog +import logging +import json +import time +import sys +import psutil +import asyncio +from pathlib import Path + +# 初始化日志记录器 +def init_log(): + logger = logging.getLogger('Onekey') + logger.setLevel(logging.DEBUG) + stream_handler = logging.StreamHandler() + stream_handler.setLevel(logging.DEBUG) + fmt_string = '%(log_color)s[%(name)s][%(levelname)s]%(message)s' + log_colors = { + 'DEBUG': 'cyan', + 'INFO': 'green', + 'WARNING': 'yellow', + 'ERROR': 'red', + 'CRITICAL': 'purple' + } + fmt = colorlog.ColoredFormatter(fmt_string, log_colors=log_colors) + stream_handler.setFormatter(fmt) + logger.addHandler(stream_handler) + return logger + + +# 生成配置文件 +def gen_config_file(): + default_config = {"Github_Persoal_Token": "", "Custom_Steam_Path": ""} + with open('./config.json', 'w', encoding='utf-8') as f: + json.dump(default_config, f) + log.info('程序可能为第一次启动,请填写配置文件后重新启动程序') + + +# 加载配置文件 +def load_config(): + if not os.path.exists('./config.json'): + gen_config_file() + os.system('pause') + sys.exit() + else: + with open('./config.json', 'r', encoding='utf-8') as f: + config = json.load(f) + return config + + +log = init_log() +config = load_config() +lock = asyncio.Lock() + + +print('\033[1;32;40m _____ __ _ _____ _ _ _____ __ __ \033[0m') +print('\033[1;32;40m / _ \ | \ | | | ____| | | / / | ____| \ \ / /\033[0m') +print('\033[1;32;40m | | | | | \| | | |__ | |/ / | |__ \ \/ /\033[0m') +print('\033[1;32;40m | | | | | |\ | | __| | |\ \ | __| \ /') +print('\033[1;32;40m | |_| | | | \ | | |___ | | \ \ | |___ / /\033[0m') +print('\033[1;32;40m \_____/ |_| \_| |_____| |_| \_\ |_____| /_/\033[0m') +log.info('作者ikun0014') +log.info('本项目基于wxy1343/ManifestAutoUpdate进行修改,采用GPL V3许可证') +log.info('版本:1.0.3') +log.info('项目仓库:https://github.com/ikunshare/Onekey') +log.debug('官网:ikunshare.com') +log.warning('注意:据传Steam新版本对部分解锁工具进行了检测,但目前未发现问题,如果你被封号可以issue反馈') +log.warning('本项目完全免费,如果你在淘宝,QQ群内通过购买方式获得,赶紧回去骂商家死全家\n交流群组:\n点击链接加入群聊【ikun分享】:https://qm.qq.com/q/D9Uiva3RVS\nhttps://t.me/ikunshare_group') + + +# 通过注册表获取Steam安装路径 +def get_steam_path(): + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Valve\Steam') + steam_path = Path(winreg.QueryValueEx(key, 'SteamPath')[0]) + custom_steam_path = config.get("Custom_Steam_Path", "") + if not custom_steam_path == '': + return Path(custom_steam_path) + else: + return steam_path + + +steam_path = get_steam_path() +isGreenLuma = any((steam_path / dll).exists() for dll in ['GreenLuma_2024_x86.dll', 'GreenLuma_2024_x64.dll', 'User32.dll']) +isSteamTools = (steam_path / 'config' / 'stplug-in').is_dir() + + +# 错误堆栈处理 +def stack_error(exception): + stack_trace = traceback.format_exception(type(exception), exception, exception.__traceback__) + return ''.join(stack_trace) + + +# 下载清单 +async def get(sha, path): + url_list = [ + f'https://gcore.jsdelivr.net/gh/{repo}@{sha}/{path}', + f'https://fastly.jsdelivr.net/gh/{repo}@{sha}/{path}', + f'https://cdn.jsdelivr.net/gh/{repo}@{sha}/{path}', + f'https://github.moeyy.xyz/https://raw.githubusercontent.com/{repo}/{sha}/{path}', + f'https://mirror.ghproxy.com/https://raw.githubusercontent.com/{repo}/{sha}/{path}', + f'https://ghproxy.org/https://raw.githubusercontent.com/{repo}/{sha}/{path}', + f'https://raw.githubusercontent.com/{repo}/{sha}/{path}' + ] + retry = 3 + async with aiohttp.ClientSession() as session: + while retry: + for url in url_list: + try: + async with session.get(url) as r: + if r.status == 200: + return await r.read() + else: + log.error(f'获取失败: {path} - 状态码: {r.status}') + except aiohttp.ClientError: + log.error(f'获取失败: {path} - 连接错误') + retry -= 1 + log.warning(f'重试剩余次数: {retry} - {path}') + log.error(f'超过最大重试次数: {path}') + raise Exception(f'Failed to download: {path}') + + +# 获取清单信息 +async def get_manifest(sha, path, steam_path: Path): + collected_depots = [] + try: + if path.endswith('.manifest'): + depot_cache_path = steam_path / 'depotcache' + async with lock: + if not depot_cache_path.exists(): + depot_cache_path.mkdir(exist_ok=True) + save_path = depot_cache_path / path + if save_path.exists(): + async with lock: + log.warning(f'已存在清单: {path}') + return collected_depots + content = await get(sha, path) + async with lock: + log.info(f'清单下载成功: {path}') + async with aiofiles.open(save_path, 'wb') as f: + await f.write(content) + elif path == 'Key.vdf': + content = await get(sha, path) + async with lock: + log.info(f'密钥下载成功: {path}') + depots_config = vdf.loads(content.decode(encoding='utf-8')) + for depot_id, depot_info in depots_config['depots'].items(): + collected_depots.append((depot_id, depot_info['DecryptionKey'])) + except KeyboardInterrupt: + raise + except Exception as e: + log.error(f'处理失败: {path} - {stack_error(e)}') + traceback.print_exc() + raise + return collected_depots + + +# 合并DecryptionKey +async def depotkey_merge(config_path, depots_config): + if not config_path.exists(): + async with lock: + log.error('Steam默认配置不存在,可能是没有登录账号') + return + with open(config_path, encoding='utf-8') as f: + config = vdf.load(f) + software = config['InstallConfigStore']['Software'] + valve = software.get('Valve') or software.get('valve') + steam = valve.get('Steam') or valve.get('steam') + if 'depots' not in steam: + steam['depots'] = {} + steam['depots'].update(depots_config['depots']) + with open(config_path, 'w', encoding='utf-8') as f: + vdf.dump(config, f, pretty=True) + return True + + +# 增加SteamTools解锁相关文件 +async def stool_add(depot_data, app_id): + lua_filename = f"Onekey_unlock_{app_id}.lua" + lua_filepath = steam_path / "config" / "stplug-in" / lua_filename + + async with lock: + log.info(f'SteamTools解锁文件生成: {lua_filepath}') + with open(lua_filepath, "w", encoding="utf-8") as lua_file: + lua_file.write(f'addappid({app_id}, 1, "None")\n') + for depot_id, depot_key in depot_data: + lua_file.write(f'addappid({depot_id}, 1, "{depot_key}")\n') + + luapacka_path = steam_path / "config" / "stplug-in" / "luapacka.exe" + subprocess.run([str(luapacka_path), str(lua_filepath)]) + os.remove(lua_filepath) + return True + + +# 增加GreenLuma解锁相关文件 +async def greenluma_add(depot_id_list): + app_list_path = steam_path / 'appcache' / 'appinfo.vdf' + if app_list_path.exists() and app_list_path.is_file(): + app_list_path.unlink(missing_ok=True) + if not app_list_path.is_dir(): + app_list_path.mkdir(parents=True, exist_ok=True) + depot_dict = {} + for i in app_list_path.iterdir(): + if i.stem.isdecimal() and i.suffix == '.txt': + with i.open('r', encoding='utf-8') as f: + app_id_ = f.read().strip() + depot_dict[int(i.stem)] = None + if app_id_.isdecimal(): + depot_dict[int(i.stem)] = int(app_id_) + for depot_id in depot_id_list: + if int(depot_id) not in depot_dict.values(): + index = max(depot_dict.keys()) + 1 if depot_dict.keys() else 0 + if index != 0: + for i in range(max(depot_dict.keys())): + if i not in depot_dict.keys(): + index = i + break + with (app_list_path / f'{index}.txt').open('w', encoding='utf-8') as f: + f.write(str(depot_id)) + depot_dict[index] = int(depot_id) + return True + + +# 检测Github Api请求数量 +async def check_github_api_limit(headers): + url = 'https://api.github.com/rate_limit' + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=headers) as r: + r_json = await r.json() + remain_limit = r_json['rate']['remaining'] + use_limit = r_json['rate']['used'] + reset_time = r_json['rate']['reset'] + f_reset_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(reset_time)) + log.info(f'已用Github请求数:{use_limit}') + log.info(f'剩余Github请求数:{remain_limit}') + if r.status == 429: + log.info(f'你的Github Api请求数已超限,请尝试增加Persoal Token') + log.info(f'请求数重置时间:{f_reset_time}') + return True + + +# 检查进程是否运行 +def check_process_running(process_name): + for process in psutil.process_iter(['name']): + if process.info['name'] == process_name: + return True + return False + + +# 主函数 +async def main(app_id): + app_id_list = list(filter(str.isdecimal, app_id.strip().split('-'))) + app_id = app_id_list[0] + github_token = config.get("Github_Persoal_Token", "") + headers = {'Authorization': f'Bearer {github_token}'} if github_token else None + + if headers: + await check_github_api_limit(headers) + + url = f'https://api.github.com/repos/{repo}/branches/{app_id}' + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=headers) as r: + r_json = await r.json() + if 'commit' in r_json: + sha = r_json['commit']['sha'] + url = r_json['commit']['commit']['tree']['url'] + date = r_json['commit']['commit']['author']['date'] + async with session.get(url, headers=headers) as r2: + r2_json = await r2.json() + if 'tree' in r2_json: + collected_depots = [] + for i in r2_json['tree']: + result = await get_manifest(sha, i['path'], steam_path) + collected_depots.extend(result) + if collected_depots: + if isSteamTools: + await stool_add(collected_depots, app_id) + log.info('找到SteamTools,已添加解锁文件') + if isGreenLuma: + await greenluma_add([app_id]) + depot_config = {'depots': {depot_id: {'DecryptionKey': depot_key} for depot_id, depot_key in collected_depots}} + depotkey_merge(steam_path / 'config' / 'config.vdf', depot_config) + if await greenluma_add([int(i) for i in depot_config['depots'] if i.isdecimal()]): + log.info('找到GreenLuma,已添加解锁文件') + log.info(f'清单最后更新时间:{date}') + log.info(f'入库成功: {app_id}') + return True + log.error(f'清单下载或生成.st失败: {app_id}') + return False + + +parser = argparse.ArgumentParser() +parser.add_argument('-a', '--app-id') +args = parser.parse_args() +repo = 'ManifestHub/ManifestHub' +if __name__ == '__main__': + try: + log.debug('App ID可以在SteamDB或Steam商店链接页面查看') + asyncio.run(main(args.app_id or input('需要入库的App ID: '))) + except KeyboardInterrupt: + exit() + except Exception as e: + log.error(f'发生错误: {stack_error(e)}') + traceback.print_exc() + if not args.app_id: + os.system('pause') diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a883afc --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +aiofiles==24.1.0 +aiohttp==3.9.5 +colorlog==6.8.2 +psutil==6.0.0 +vdf==3.4