Ikreb1/mtg-arena-collection-export
GitHub: Ikreb1/mtg-arena-collection-export
通过逆向MTG Arena的Frontdoor协议调用Card_GetAllCards接口,将玩家卡牌收藏导出为JSON的轻量级Python工具。
Stars: 0 | Forks: 0
# MTG Arena 收藏导出
**将你拥有的 MTG Arena (MTGA) 卡牌收藏导出为 JSON —— 即使在 2026
客户端中它已不再写入 `Player.log`。**
这是一个无需依赖的轻量级 Python 工具,它通过使用游戏原生的
**Frontdoor** 网络协议并调用 `Card_GetAllCards`(这是
长期被移除的 `GetPlayerCardsV3` 的现代替代方案),从 **Magic: The Gathering Arena** 中提取你的**拥有的卡牌
收藏**。它会输出一个简单的
`{arena_id: count}` JSON 映射,你可以将其导入到卡组构建器、收藏追踪器、
代理工具、价值计算器或你自己的脚本中。
## ⚠️ 阅读须知(ToS / 封禁风险)
本项目是**非官方的**,且**不隶属于 Wizards of the Coast 或
Hasbro**。它的工作原理是使用第三方
客户端向 Arena 的实时服务器进行身份验证,这**违反了 MTG Arena 的服务条款 / EULA**,并且**可能导致
你的账号被暂停或封禁**。
- **风险自负**。请**仅在你自己的账号上**使用它,用于获取你**自己的收藏数据**。
- 它被刻意设计为**只读**模式:它仅进行身份验证并调用 `Card_GetAllCards`,
仅此而已。**切勿**添加游戏自动化功能 —— 那才是导致人们被封禁的原因,且
在这里是不受欢迎的。
- 维护者提供此工具是为了**互操作性和个人数据导出**,
对你的账号发生的一切概不负责。
如果你无法接受这种风险,请不要使用它。
## 为什么会有这个项目
在当前的 MTG Arena 版本中,拥有的收藏**不再存在于 `Player.log` 中**:
- 旧的 `PlayerInventory.GetPlayerCardsV3` 日志行在 **2021 年就被移除了**。
- 在客户端内打开收藏/卡组构建器时,它是从内存缓存中渲染的,
并且**不会产生任何记录的 API 调用**。
- 它不会被缓存到磁盘上的任何可读文件中。
因此,那些流行的“只需 grep 你的 Player.log”的追踪器再也看不到你的收藏
了。现在,收藏数据通过游戏的**固定 Frontdoor socket** 进行传输。该工具
重新实现了该协议中刚好足够用的一部分,以便直接向服务器请求这些数据。
## 工作原理(宏观概述)
1. **OAuth 刷新** —— 使用 Arena *公开的应用级* Steam 客户端凭据,将你捕获的 `refresh_token` 交换为一个短期的
access token。
2. **连接 Frontdoor** —— 根据
“doorbell” 响应,打开一个连接到 Frontdoor 主机的 TLS socket。
3. **身份验证** —— 通过 **2026 线路格式**
(frame version 4 + 一个 protobuf `Cmd` 信封;参见 [`docs/PROTOCOL.md`](docs/PROTOCOL.md))发送 `Authenticate` 命令。
4. **`Card_GetAllCards` (命令 551)** —— 请求完整收藏并将其
写入 `data/collection.json`。
完整的逆向工程协议记录在 **[`docs/PROTOCOL.md`](docs/PROTOCOL.md)** 中 ——
即使你打算用其他语言实现,这也很有用。
## 环境要求
- **Python 3.8+** —— 仅需标准库,无需 `pip install`。
- 需要一次性捕获**你自己的** Arena `refresh_token`
(参见 [`docs/CAPTURING_YOUR_TOKEN.md`](docs/CAPTURING_YOUR_TOKEN.md);需要一次性使用
[mitmproxy](https://mitmproxy.org/))。
- 运行此工具时,应**关闭** MTG Arena(同一账号的第二个并发 Frontdoor
会话可能会被拒绝)。
## 用法
```
# 1) 将捕获的 token + doorbell response 放入 data/ (参见 docs):
# data/token.json <- 包含你的 refresh_token (SECRET, gitignored)
# data/doorbell.json <- 包含 fdURI
# 2) 拉取 collection:
python3 mtga_collection.py
# -> 写入 data/collection.json ({arena_id: count})
```
实用参数:
| 参数 | 默认值 | 用途 |
|------|---------|---------|
| `--token-file` | `data/token.json` | 包含你的 `refresh_token` 的 JSON 文件。 |
| `--doorbell-file` | `data/doorbell.json` | 捕获的 doorbell 响应(包含 `fdURI`)。 |
| `--fduri tcp://host:port` | — | 跳过 doorbell 文件并直接连接。 |
| `--platform` | 尝试 Steam/Windows/… | 强制使用单个 `PlatformId`。 |
| `--out` | `data/collection.json` | `{arena_id: count}` 映射的写入位置。 |
| `--raw-out` | `data/getallcards_raw.json` | 导出原始服务器响应以供检查。 |
## 输出格式
`data/collection.json` 是一个扁平化的映射,对应 **Arena 卡牌 ID → 拥有数量**:
```
{
"70000": 4,
"70001": 2,
"68769": 3
}
```
参见 [`examples/collection.sample.json`](examples/collection.sample.json)。原始
响应 (`--raw-out`) 的格式为 `{"cacheVersion": N, "cards": { "": qty }}`。
使用 [Scryfall](https://scryfall.com/docs/api/bulk-data)
批量数据(每张卡都有一个 `arena_id`)将 Arena ID 映射为真实的卡牌名称。
## 常见问题
**需要我的 Arena 密码吗?** 不需要。它使用你从自己的客户端捕获的 OAuth `refresh_token`;密码永远不会经过此工具。
**我会被封禁吗?** 有可能 —— 参见上面的警告。这违反了 ToS。它是
只读的,风险比自动化要低,但没有任何保证。
**它能在 Steam / 独立 / Epic 客户端上工作吗?** 它默认使用公开的 Steam
应用凭据,并在失败时回退到独立凭据。在任何客户端上,token 捕获的
原理都是一样的。
**我可以用其他语言使用它吗?** 可以 —— [`docs/PROTOCOL.md`](docs/PROTOCOL.md)
完整规范了线路格式。
## 致谢
- 协议的基础工作受到了较早的 **MTGate** 项目的启发(2023 年的 JSON/v3
Frontdoor 流程);本仓库记录了 **2026 年**的 protobuf/v4 变更。
- 卡牌数据:**[Scryfall](https://scryfall.com/)**。
## 许可证
[MIT](LICENSE) © Ikreb1。不隶属于 Wizards of the Coast。
“Magic: The Gathering” 和 “MTG Arena” 是 Wizards of the Coast LLC 的商标。
标签:MTG Arena, Python, 内核驱动, 底层编程, 数字取证, 数据导出, 无后门, 游戏工具, 网络协议, 自动化脚本, 逆向工具