mirror of
https://github.com/ikunshare/Onekey.git
synced 2026-01-13 00:27:32 +08:00
重开吧!!!
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
170
.gitignore
vendored
Normal file
170
.gitignore
vendored
Normal file
@@ -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
|
||||
67
LICENSE.md
Normal file
67
LICENSE.md
Normal file
@@ -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.
|
||||
16
README.md
16
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 趋势图
|
||||
|
||||
312
main.py
Normal file
312
main.py
Normal file
@@ -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')
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
aiofiles==24.1.0
|
||||
aiohttp==3.9.5
|
||||
colorlog==6.8.2
|
||||
psutil==6.0.0
|
||||
vdf==3.4
|
||||
Reference in New Issue
Block a user