Compare commits

...

18 Commits
1.0.4 ... 1.1.8

Author SHA1 Message Date
ikun
6ec83c4196 fix:意外 2024-09-05 21:27:36 +08:00
ikun
a7ce46aa52 fix:兼容问题 2024-09-05 20:54:34 +08:00
ikun
b4ea1edb53 chore: 优化代码工整性 2024-09-01 14:00:20 +08:00
ikun
f555f0273d rm: 搜索游戏自动获取App ID 2024-08-29 17:22:04 +08:00
ikun
3ba8b67f0e fix: bug 2024-08-27 09:48:20 +08:00
ikun
73c92e550e feat: 加入搜索游戏名入库功能
Co-Authored-By: Tibbar <49330075+tibbar213@users.noreply.github.com>
2024-08-26 19:06:05 +08:00
ikun
a2fa038324 feat&&fix: bug!bug!bug! 2024-08-22 22:40:50 +08:00
ikun
ea3aedbab3 fix: 史 2024-08-22 21:48:04 +08:00
ikun
51ccc579f4 feat:配置文件修改 2024-08-22 14:10:30 +08:00
ikun
17e654a68e feat:没什么用懒得发Release 2024-08-21 17:27:50 +08:00
ikun
c4f4fb9e92 feat: 增加一个清单库 2024-08-16 15:11:31 +08:00
ikun
e38af1675c fix: 修改QQ群链接 2024-08-15 19:53:41 +08:00
ikun
50194cf7de 更新 main.py 2024-08-14 19:00:27 +08:00
ikun
7063f2f5dc rm: 移除jsdelivr的CDN服务 2024-08-13 10:25:28 +08:00
ikun
2c6b3bebe1 fix: Github API请求数量为0时不返回错误
史中史代码,看不懂与我无关
2024-08-12 19:18:56 +08:00
ikun
5c74940702 feat: 加了几个加速镜像 2024-08-12 15:08:54 +08:00
ikun
dc64d2a9be feat:死妈倒狗给我坐下 2024-08-11 21:49:37 +08:00
ikun
e31e1c40dc chore: 优化清单下载速度;优化界面
## 优化

清单下载速度
日志
2024-08-06 22:56:43 +08:00
14 changed files with 336 additions and 263 deletions

1
.gitignore vendored
View File

@@ -168,3 +168,4 @@ cython_debug/
*.bat
*.xml
*.exe
*.dll

View File

@@ -25,7 +25,7 @@
使用本项目的过程中可能会产生版权数据对于这些版权数据本项目不拥有它们的所有权为了避免造成侵权使用者务必在24 小时内清除使用本项目的过程中所产生的版权数据。
由于使用本项目产生的包括由于本协议或由于使用或无法使用本项目而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本项目不对项目内的技术可能存在违反当地法律法规的行为作保证,禁止在违反当地法律法规的情况下使用本项目,对于使用者在明知或不知当地法律法规不允许的情况下使用本项目所造成的任何违法违规行为由使用者承担,本项目不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
而且,本项目已禁止使用于商业用途。
而且,本项目已禁止使用于商业用途,以及不得进行未经允许的二次修改,否则必须同时发布源代码
若你使用了本项目,将代表你接受以上协议。
Steam正版平台不易请尊重版权支持正版。

0
common/__init__.py Normal file
View File

36
common/config.py Normal file
View File

@@ -0,0 +1,36 @@
import ujson as json
import aiofiles
from . import log
import os
import sys
import asyncio
log = log.log
# 生成配置文件
async def gen_config_file():
default_config ={
"Github_Personal_Token": "",
"Custom_Steam_Path": "",
"QA1": "温馨提示Github_Personal_Token可在Github设置的最底下开发者选项找到详情看教程",
"教程": "https://lyvx-my.sharepoint.com/:w:/g/personal/ikun_ikunshare_com/EWqIqyCElLNLo_CKfLbqix0BWU_O03HLzEHQKHdJYrUz-Q?e=79MZjw"
}
async with aiofiles.open("./config.json", mode="w", encoding="utf-8") as f:
await f.write(json.dumps(default_config, indent=2, ensure_ascii=False,
escape_forward_slashes=False))
await f.close()
log.info(' 🖱️ 程序可能为第一次启动,请填写配置文件后重新启动程序')
# 加载配置文件
async def load_config():
if not os.path.exists('./config.json'):
await gen_config_file()
os.system('pause')
sys.exit()
else:
async with aiofiles.open("./config.json", mode="r", encoding="utf-8") as f:
config = json.loads(await f.read())
return config
config = asyncio.run(load_config())

23
common/dkey_merge.py Normal file
View File

@@ -0,0 +1,23 @@
import asyncio
import aiofiles
import vdf
from .log import log
lock = asyncio.Lock()
async def depotkey_merge(config_path, depots_config):
if not config_path.exists():
async with lock:
log.error(' 👋 Steam默认配置不存在可能是没有登录账号')
return
async with aiofiles.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'])
async with aiofiles.open(config_path, mode='w', encoding='utf-8') as f:
vdf.dump(config, f, pretty=True)
return True

17
common/getsteampath.py Normal file
View File

@@ -0,0 +1,17 @@
import winreg
from pathlib import Path
from common import config
config = config.config
# 通过注册表获取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["Custom_Steam_Path"]
if not custom_steam_path == '':
return Path(custom_steam_path)
else:
return steam_path
steam_path = get_steam_path()

33
common/glunlock.py Normal file
View File

@@ -0,0 +1,33 @@
from common import getsteampath
steam_path = getsteampath.steam_path
# 增加GreenLuma解锁相关文件
async def greenluma_add(depot_id_list):
app_list_path = steam_path / 'AppList'
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
glunlock = greenluma_add

23
common/log.py Normal file
View File

@@ -0,0 +1,23 @@
import colorlog
import logging
# 初始化日志记录器
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 = {
'INFO': 'cyan',
'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
log = init_log()

28
common/manifestdown.py Normal file
View File

@@ -0,0 +1,28 @@
from aiohttp import ClientError
from .log import log
# 下载清单
async def get(sha, path, repo, session):
url_list = [
# f'https://gh.api.99988866.xyz/https://raw.githubusercontent.com/{repo}/{sha}/{path}',
f'https://cdn.jsdmirror.com/gh/{repo}@{sha}/{path}',
f'https://jsd.onmicrosoft.cn/gh/{repo}@{sha}/{path}',
f'https://mirror.ghproxy.com/https://raw.githubusercontent.com/{repo}/{sha}/{path}',
f'https://raw.githubusercontent.com/{repo}/{sha}/{path}',
f'https://gh.jiasu.in/https://raw.githubusercontent.com/{repo}/{sha}/{path}'
]
retry = 3
while retry:
for url in url_list:
try:
async with session.get(url, ssl=False) as r:
if r.status == 200:
return await r.read()
else:
log.error(f' 🔄 获取失败: {path} - 状态码: {r.status}')
except ClientError:
log.error(f' 🔄 获取失败: {path} - 连接错误')
retry -= 1
log.warning(f' 🔄 重试剩余次数: {retry} - {path}')
log.error(f' 🔄 超过最大重试次数: {path}')
raise Exception(f' 🔄 无法下载: {path}')

22
common/migration.py Normal file
View File

@@ -0,0 +1,22 @@
import os
from common import log, getsteampath
from pathlib import Path
# 设置文件目录
log = log.log
steam_path = getsteampath.steam_path
directory = Path(steam_path / "config" / "stplug-in")
# 遍历目录中的所有文件
def migrate():
for filename in os.listdir(directory):
if filename.startswith("Onekey_unlock_"):
new_filename = filename[len("Onekey_unlock_"):]
old_file = os.path.join(directory, filename)
new_file = os.path.join(directory, new_filename)
os.rename(old_file, new_file)
log.info(f'Renamed: {filename} -> {new_filename}')
migrate = migrate

8
common/stack_error.py Normal file
View File

@@ -0,0 +1,8 @@
import traceback
# 错误堆栈处理
def stack_error(exception):
stack_trace = traceback.format_exception(type(exception), exception, exception.__traceback__)
return ''.join(stack_trace)
stack_error = stack_error

29
common/stunlock.py Normal file
View File

@@ -0,0 +1,29 @@
from common import log, getsteampath
import asyncio
import aiofiles
import os
import subprocess
lock = asyncio.Lock()
log = log.log
steam_path = getsteampath.steam_path
# 增加SteamTools解锁相关文件
async def stool_add(depot_data, app_id):
lua_filename = f"{app_id}.lua"
lua_filepath = steam_path / "config" / "stplug-in" / lua_filename
async with lock:
log.info(f' ✅ SteamTools解锁文件生成: {lua_filepath}')
async with aiofiles.open(lua_filepath, mode="w", encoding="utf-8") as lua_file:
await lua_file.write(f'addappid({app_id}, 1, "None")\n')
for depot_id, depot_key in depot_data:
await 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
stunlock = stool_add

373
main.py
View File

@@ -1,311 +1,164 @@
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 common import log, config, getsteampath, stunlock, glunlock, stack_error, manifestdown, dkey_merge, migration
from aiohttp import ClientSession
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()
log = log.log
config = config.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.4')
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()
steam_path = getsteampath.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()
stunlock = stunlock.stunlock
glunlock = glunlock.glunlock
stack_error = stack_error.stack_error
get = manifestdown.get
depotkey_merge = dkey_merge.depotkey_merge
migration = migration.migrate
# 错误堆栈处理
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, ssl=False) 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}')
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 | | | | | |\\ | | __| | |\\ \\ | __| \\ / ' + '\033[0m')
print('\033[1;32;40m | |_| | | | \\ | | |___ | | \\ \\ | |___ / /' + '\033[0m')
print('\033[1;32;40m \\_____/ |_| \\_| |_____| |_| \\_\\ |_____| /_/' + '\033[0m')
log.info('作者ikun0014')
log.info('本项目基于wxy1343/ManifestAutoUpdate进行修改采用ACSL许可证')
log.info('版本1.1.7')
log.info('项目仓库https://github.com/ikunshare/Onekey')
log.info('官网ikunshare.com')
log.warning('本项目完全开源免费如果你在淘宝QQ群内通过购买方式获得赶紧回去骂商家死全家\n交流群组:\n点击链接加入群聊【𝗶𝗸𝘂𝗻分享】https://qm.qq.com/q/d7sWovfAGI\nhttps://t.me/ikunshare_group')
# 获取清单信息
async def get_manifest(sha, path, steam_path: Path):
async def get_manifest(sha, path, steam_path: Path, repo, session):
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)
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}')
log.warning(f'👋已存在清单: {path}')
return collected_depots
content = await get(sha, path)
async with lock:
log.info(f'清单下载成功: {path}')
content = await get(sha, path, repo, session)
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}')
content = await get(sha, path, repo, session)
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):
async def check_github_api_rate_limit(headers, session):
url = 'https://api.github.com/rate_limit'
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, ssl=False) as r:
async with session.get(url, headers=headers, ssl=False) as r:
if not r == None:
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
else:
log.error('孩子,你怎么做到的?')
os.system('pause')
if r.status == 200:
rate_limit = r_json['rate']
remaining_requests = rate_limit['remaining']
reset_time = rate_limit['reset']
reset_time_formatted = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(reset_time))
log.info(f' 🔄 剩余请求次数: {remaining_requests}')
else:
log.error('Github请求数检查失败')
# 检查进程是否运行
def check_process_running(process_name):
for process in psutil.process_iter(['name']):
if process.info['name'] == process_name:
return True
return False
if remaining_requests == 0:
log.warning(f' ⚠ GitHub API 请求数已用尽,将在 {reset_time_formatted} 重置, 不想等生成一个填配置文件里')
# 主函数
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
async with ClientSession() as session:
github_token = config["Github_Personal_Token"]
headers = {'Authorization': f'Bearer {github_token}'} if github_token else None
latest_date = None
selected_repo = None
await check_github_api_limit(headers)
# 检查Github API限额
await check_github_api_rate_limit(headers, session)
url = f'https://api.github.com/repos/{repo}/branches/{app_id}'
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, ssl=False) 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, ssl=False) 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
for repo in repos:
url = f'https://api.github.com/repos/{repo}/branches/{app_id}'
try:
async with session.get(url, headers=headers, ssl=False) as r:
r_json = await r.json()
if 'commit' in r_json:
date = r_json['commit']['commit']['author']['date']
if latest_date is None or date > latest_date:
latest_date = date
selected_repo = repo
except Exception as e:
log.error(f' ⚠ 获取分支信息失败: {stack_error(e)}')
traceback.print_exc()
if selected_repo:
log.info(f' 🔄 选择清单仓库:{selected_repo}')
url = f'https://api.github.com/repos/{selected_repo}/branches/{app_id}'
async with session.get(url, headers=headers, ssl=False) as r:
r_json = await r.json()
if 'commit' in r_json:
sha = r_json['commit']['sha']
url = r_json['commit']['commit']['tree']['url']
async with session.get(url, headers=headers, ssl=False) 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, selected_repo, session)
collected_depots.extend(result)
if collected_depots:
if isSteamTools:
await stunlock(collected_depots, app_id)
log.info(' ✅ 找到SteamTools已添加解锁文件')
if isGreenLuma:
await glunlock([app_id])
depot_config = {'depots': {depot_id: {'DecryptionKey': depot_key} for depot_id, depot_key in collected_depots}}
await depotkey_merge(steam_path / 'config' / 'config.vdf', depot_config)
if await glunlock([int(i) for i in depot_config['depots'] if i.isdecimal()]):
log.info(' ✅ 找到GreenLuma已添加解锁文件')
log.info(f' ✅ 清单最后更新时间:{date}')
log.info(f' ✅ 入库成功: {app_id}')
os.system('pause')
return True
log.error(f' ⚠ 清单下载或生成失败: {app_id}')
os.system('pause')
return False
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--app-id')
args = parser.parse_args()
repo = 'ManifestHub/ManifestHub'
repos = [
'ManifestHub/ManifestHub',
'ikun0014/ManifestHub',
'Auiowu/ManifestAutoUpdate',
'tymolu233/ManifestAutoUpdate'
]
if __name__ == '__main__':
try:
log.debug('App ID可以在SteamDB或Steam商店链接页面查看')
asyncio.run(main(args.app_id or input('需要入库的App ID: ')))
migration()
log.info('App ID可以在SteamDB或Steam商店链接页面查看')
app_id = input("请输入游戏AppID").strip()
asyncio.run(main(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')
log.error(f'发生错误: {stack_error(e)}')
traceback.print_exc()

View File

@@ -1,5 +1,5 @@
aiofiles==24.1.0
aiohttp==3.9.5
colorlog==6.8.2
psutil==6.0.0
ujson==5.10.0
vdf==3.4
nuitka==2.4.8