steam_confirmation.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #!/usr/bin/env python3
  2. """
  3. Steam 订单确认 Python 客户端
  4. 使用说明:
  5. 1. 首次使用需要先登录(调用 login 函数)
  6. 2. 登录后会保存 session 到本地文件
  7. 3. 之后可以直接查询确认列表或执行确认操作
  8. 依赖安装:
  9. pip install requests
  10. 示例:
  11. python steam_confirmation.py
  12. """
  13. import json
  14. import os
  15. import sys
  16. import requests
  17. from typing import Optional
  18. # ============ 配置区域 ============
  19. API_BASE_URL = "http://localhost:5000"
  20. MA_FILE_PATH = r"C:\Users\Administrator\AppData\Local\steam-msg\tku24068.maFile"
  21. # 如果需要代理,取消下面这行的注释并填写
  22. # PROXY_URL = "http://127.0.0.1:7890"
  23. PROXY_URL = None
  24. # Session 保存路径
  25. SESSION_FILE = "steam_session.json"
  26. # ============ 配置区域结束 ============
  27. def load_session() -> Optional[dict]:
  28. """从文件加载保存的 session"""
  29. if os.path.exists(SESSION_FILE):
  30. try:
  31. with open(SESSION_FILE, 'r', encoding='utf-8') as f:
  32. return json.load(f)
  33. except Exception as e:
  34. print(f"加载 session 失败: {e}")
  35. return None
  36. def save_session(session_data: dict):
  37. """保存 session 到文件"""
  38. try:
  39. with open(SESSION_FILE, 'w', encoding='utf-8') as f:
  40. json.dump(session_data, f, indent=2, ensure_ascii=False)
  41. print("Session 已保存")
  42. except Exception as e:
  43. print(f"保存 session 失败: {e}")
  44. def login(username: str, password: str) -> Optional[dict]:
  45. """
  46. 登录 Steam 账号
  47. Args:
  48. username: Steam 用户名
  49. password: Steam 密码
  50. Returns:
  51. session 数据,包含 steamId, accessToken, refreshToken, sessionId
  52. """
  53. print(f"\n{'='*50}")
  54. print("正在登录 Steam...")
  55. print(f"用户名: {username}")
  56. print(f"MaFile: {MA_FILE_PATH}")
  57. print(f"{'='*50}\n")
  58. url = f"{API_BASE_URL}/login"
  59. payload = {
  60. "Username": username,
  61. "Password": password,
  62. "MaFilePath": MA_FILE_PATH
  63. }
  64. if PROXY_URL:
  65. payload["ProxyUrl"] = PROXY_URL
  66. try:
  67. response = requests.post(url, json=payload, timeout=60)
  68. print(f"响应状态码: {response.status_code}")
  69. if response.status_code == 200:
  70. data = response.json()
  71. session = data.get("session", {})
  72. print(f"\n登录成功!")
  73. print(f"SteamID: {session.get('steamId')}")
  74. print(f"SessionID: {session.get('sessionId', 'N/A')[:20]}...")
  75. # 保存 session
  76. save_session(session)
  77. return session
  78. else:
  79. print(f"登录失败: {response.text}")
  80. return None
  81. except requests.exceptions.ConnectionError:
  82. print(f"\n错误: 无法连接到 steamAPI 服务")
  83. print(f"请确保 steamAPI 服务正在运行 (默认: http://localhost:5000)")
  84. return None
  85. except requests.exceptions.Timeout:
  86. print("\n错误: 请求超时,请检查网络连接")
  87. return None
  88. except Exception as e:
  89. print(f"\n错误: {e}")
  90. return None
  91. def get_confirmation_list(session: dict) -> Optional[list]:
  92. """
  93. 获取待确认的交易/市场订单列表
  94. Args:
  95. session: 登录后获取的 session 数据
  96. Returns:
  97. 确认列表
  98. """
  99. print(f"\n{'='*50}")
  100. print("正在获取待确认列表...")
  101. print(f"{'='*50}\n")
  102. url = f"{API_BASE_URL}/trade-confirmations/list"
  103. payload = {
  104. "MaFilePath": MA_FILE_PATH,
  105. "Session": {
  106. "SteamId": session["steamId"],
  107. "AccessToken": session["accessToken"],
  108. "RefreshToken": session["refreshToken"],
  109. "SessionId": session.get("sessionId")
  110. }
  111. }
  112. if PROXY_URL:
  113. payload["ProxyUrl"] = PROXY_URL
  114. try:
  115. response = requests.post(url, json=payload, timeout=30)
  116. print(f"响应状态码: {response.status_code}")
  117. if response.status_code == 200:
  118. data = response.json()
  119. confirmations = data.get("confirmations", [])
  120. print(f"\n找到 {len(confirmations)} 个待确认项:")
  121. # 更新 session
  122. if "session" in data:
  123. save_session(data["session"])
  124. if confirmations:
  125. print("\n" + "-" * 60)
  126. for i, conf in enumerate(confirmations, 1):
  127. print(f"\n[{i}] 类型: {conf.get('type', 'Unknown')}")
  128. print(f" ID: {conf.get('id')}")
  129. print(f" Key: {conf.get('key')}")
  130. print(f" 标题: {conf.get('headline', 'N/A')}")
  131. print(f" 摘要: {conf.get('summary', 'N/A')}")
  132. print("\n" + "-" * 60)
  133. else:
  134. print("没有待确认的订单")
  135. return confirmations
  136. elif response.status_code == 401:
  137. print("Session 已过期,需要重新登录")
  138. return None
  139. else:
  140. print(f"获取失败: {response.text}")
  141. return None
  142. except requests.exceptions.ConnectionError:
  143. print(f"\n错误: 无法连接到 steamAPI 服务")
  144. return None
  145. except Exception as e:
  146. print(f"\n错误: {e}")
  147. return None
  148. def operate_confirmation(
  149. session: dict,
  150. confirmation_id: int,
  151. operation: str = "accept",
  152. confirmation_key: Optional[int] = None
  153. ) -> bool:
  154. """
  155. 执行确认操作(确认或取消)
  156. Args:
  157. session: 登录后获取的 session 数据
  158. confirmation_id: 确认项 ID(支持传入 creator_id 自动匹配)
  159. operation: 操作类型,"accept" 或 "cancel"
  160. confirmation_key: 可选,手动指定确认 key
  161. Returns:
  162. 操作是否成功
  163. """
  164. if operation not in ("accept", "cancel"):
  165. print("操作类型错误,只能是 'accept' 或 'cancel'")
  166. return False
  167. op_text = "确认" if operation == "accept" else "取消"
  168. print(f"\n{'='*50}")
  169. print(f"正在执行 {op_text} 操作...")
  170. print(f"确认项 ID: {confirmation_id}")
  171. print(f"{'='*50}\n")
  172. url = f"{API_BASE_URL}/trade-confirmations/operate"
  173. payload = {
  174. "MaFilePath": MA_FILE_PATH,
  175. "Session": {
  176. "SteamId": session["steamId"],
  177. "AccessToken": session["accessToken"],
  178. "RefreshToken": session["refreshToken"],
  179. "SessionId": session.get("sessionId")
  180. },
  181. "ConfirmationId": confirmation_id,
  182. "Operation": operation
  183. }
  184. if confirmation_key:
  185. payload["ConfirmationKey"] = confirmation_key
  186. if PROXY_URL:
  187. payload["ProxyUrl"] = PROXY_URL
  188. try:
  189. response = requests.post(url, json=payload, timeout=30)
  190. print(f"响应状态码: {response.status_code}")
  191. if response.status_code == 200:
  192. data = response.json()
  193. success = data.get("success", False)
  194. print(f"\n{'='*50}")
  195. if success:
  196. print(f"{op_text}成功!")
  197. else:
  198. print(f"{op_text}失败!")
  199. print(f"{'='*50}")
  200. print(f"操作类型: {data.get('operation')}")
  201. print(f"确认ID: {data.get('confirmationId')}")
  202. print(f"Key: {data.get('confirmationKey')}")
  203. print(f"Key来源: {'列表匹配' if data.get('keyResolvedFromList') else '手动指定'}")
  204. print(f"ID来源: {data.get('matchedBy', 'N/A')}")
  205. # 更新 session
  206. if "session" in data:
  207. save_session(data["session"])
  208. return success
  209. elif response.status_code == 404:
  210. print("未找到对应的确认项,可能已过期或被处理")
  211. return False
  212. elif response.status_code == 401:
  213. print("Session 已过期,需要重新登录")
  214. return False
  215. else:
  216. print(f"操作失败: {response.text}")
  217. return False
  218. except requests.exceptions.ConnectionError:
  219. print(f"\n错误: 无法连接到 steamAPI 服务")
  220. return False
  221. except Exception as e:
  222. print(f"\n错误: {e}")
  223. return False
  224. def confirm_all(session: dict) -> int:
  225. """
  226. 确认所有待确认的订单
  227. Returns:
  228. 成功确认的数量
  229. """
  230. confirmations = get_confirmation_list(session)
  231. if not confirmations:
  232. print("没有待确认的订单")
  233. return 0
  234. success_count = 0
  235. for conf in confirmations:
  236. conf_id = conf.get("id")
  237. conf_type = conf.get("type", "Unknown")
  238. headline = conf.get("headline", "N/A")
  239. print(f"\n正在确认: {headline} (类型: {conf_type})")
  240. if operate_confirmation(session, conf_id, "accept"):
  241. success_count += 1
  242. return success_count
  243. def interactive_mode():
  244. """交互式模式"""
  245. print("\n" + "=" * 60)
  246. print(" Steam 订单确认工具 - 交互式模式")
  247. print("=" * 60)
  248. # 尝试加载已保存的 session
  249. session = load_session()
  250. while True:
  251. print("\n" + "-" * 40)
  252. print("请选择操作:")
  253. print("1. 查看待确认列表")
  254. print("2. 确认指定订单")
  255. print("3. 确认所有订单")
  256. print("4. 取消指定订单")
  257. print("5. 重新登录")
  258. print("0. 退出")
  259. print("-" * 40)
  260. choice = input("请输入选项 (0-5): ").strip()
  261. if choice == "0":
  262. print("退出程序")
  263. break
  264. if choice == "1":
  265. if not session:
  266. print("请先登录!")
  267. continue
  268. get_confirmation_list(session)
  269. # 更新 session
  270. new_session = load_session()
  271. if new_session:
  272. session = new_session
  273. elif choice == "2":
  274. if not session:
  275. print("请先登录!")
  276. continue
  277. confirm_id = input("请输入要确认的订单 ID: ").strip()
  278. try:
  279. confirm_id = int(confirm_id)
  280. except ValueError:
  281. print("ID 必须是数字")
  282. continue
  283. operate_confirmation(session, confirm_id, "accept")
  284. # 更新 session
  285. new_session = load_session()
  286. if new_session:
  287. session = new_session
  288. elif choice == "3":
  289. if not session:
  290. print("请先登录!")
  291. continue
  292. confirm("确认所有待确认的订单? (y/N): ")
  293. if confirm.lower() == 'y':
  294. success_count = confirm_all(session)
  295. print(f"\n成功确认 {success_count} 个订单")
  296. # 更新 session
  297. new_session = load_session()
  298. if new_session:
  299. session = new_session
  300. elif choice == "4":
  301. if not session:
  302. print("请先登录!")
  303. continue
  304. confirm_id = input("请输入要取消的订单 ID: ").strip()
  305. try:
  306. confirm_id = int(confirm_id)
  307. except ValueError:
  308. print("ID 必须是数字")
  309. continue
  310. operate_confirmation(session, confirm_id, "cancel")
  311. # 更新 session
  312. new_session = load_session()
  313. if new_session:
  314. session = new_session
  315. elif choice == "5":
  316. username = input("请输入 Steam 用户名: ").strip()
  317. password = input("请输入 Steam 密码: ").strip()
  318. if username and password:
  319. session = login(username, password)
  320. else:
  321. print("用户名和密码不能为空")
  322. else:
  323. print("无效的选项")
  324. def confirm(prompt: str) -> str:
  325. """简单的确认提示"""
  326. return input(prompt)
  327. if __name__ == "__main__":
  328. # 检查 maFile 是否存在
  329. if not os.path.exists(MA_FILE_PATH):
  330. print(f"\n错误: MaFile 文件不存在!")
  331. print(f"路径: {MA_FILE_PATH}")
  332. print("\n请检查配置文件中的 MA_FILE_PATH 是否正确")
  333. sys.exit(1)
  334. # 检查 API 服务是否可用
  335. try:
  336. response = requests.get(f"{API_BASE_URL}/", timeout=5)
  337. except requests.exceptions.ConnectionError:
  338. print(f"\n警告: 无法连接到 steamAPI 服务 (http://localhost:5000)")
  339. print("请确保 steamAPI 服务正在运行")
  340. print("\n启动 steamAPI 的方法:")
  341. print(" cd steam-client/steamAPI")
  342. print(" dotnet run")
  343. print("\n如果需要指定端口:")
  344. print(" dotnet run --urls \"http://localhost:5000\"")
  345. print()
  346. # 检查命令行参数
  347. if len(sys.argv) > 1:
  348. if sys.argv[1] == "--login" and len(sys.argv) >= 4:
  349. # python steam_confirmation.py --login username password
  350. session = login(sys.argv[2], sys.argv[3])
  351. if session:
  352. print("\n登录成功,现在可以执行其他操作")
  353. confirmations = get_confirmation_list(session)
  354. if confirmations:
  355. print(f"\n找到 {len(confirmations)} 个待确认订单")
  356. elif sys.argv[1] == "--list":
  357. session = load_session()
  358. if session:
  359. get_confirmation_list(session)
  360. else:
  361. print("没有保存的 session,请先登录")
  362. elif sys.argv[1] == "--confirm" and len(sys.argv) >= 3:
  363. session = load_session()
  364. if session:
  365. confirm_id = int(sys.argv[2])
  366. operate_confirmation(session, confirm_id, "accept")
  367. else:
  368. print("没有保存的 session,请先登录")
  369. elif sys.argv[1] == "--confirm-all":
  370. session = load_session()
  371. if session:
  372. success_count = confirm_all(session)
  373. print(f"\n成功确认 {success_count} 个订单")
  374. else:
  375. print("没有保存的 session,请先登录")
  376. else:
  377. print_usage()
  378. else:
  379. # 默认进入交互式模式
  380. interactive_mode()
  381. def print_usage():
  382. """打印使用说明"""
  383. print("""
  384. 使用说明:
  385. 1. 登录 (需要用户名和密码):
  386. python steam_confirmation.py --login <username> <password>
  387. 2. 查看待确认列表:
  388. python steam_confirmation.py --list
  389. 3. 确认指定订单:
  390. python steam_confirmation.py --confirm <confirmation_id>
  391. 4. 确认所有订单:
  392. python steam_confirmation.py --confirm-all
  393. 5. 进入交互式模式 (不带参数):
  394. python steam_confirmation.py
  395. 注意事项:
  396. - 首次使用必须先登录
  397. - Session 会保存到 steam_session.json
  398. - 如果 session 过期,需要重新登录
  399. """)