mythicmc-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mythicmc_sdk-0.1.0/.gitignore +10 -0
- mythicmc_sdk-0.1.0/LICENSE +21 -0
- mythicmc_sdk-0.1.0/PKG-INFO +146 -0
- mythicmc_sdk-0.1.0/README.md +126 -0
- mythicmc_sdk-0.1.0/examples/async_lookup.py +27 -0
- mythicmc_sdk-0.1.0/examples/get_leaderboards.py +22 -0
- mythicmc_sdk-0.1.0/examples/get_player.py +23 -0
- mythicmc_sdk-0.1.0/examples/get_player_crate_keys.py +18 -0
- mythicmc_sdk-0.1.0/examples/get_player_progression.py +19 -0
- mythicmc_sdk-0.1.0/examples/get_player_stats.py +25 -0
- mythicmc_sdk-0.1.0/examples/get_player_team.py +17 -0
- mythicmc_sdk-0.1.0/pyproject.toml +30 -0
- mythicmc_sdk-0.1.0/src/mythicmc/__init__.py +84 -0
- mythicmc_sdk-0.1.0/src/mythicmc/client.py +239 -0
- mythicmc_sdk-0.1.0/src/mythicmc/errors.py +35 -0
- mythicmc_sdk-0.1.0/src/mythicmc/models.py +336 -0
- mythicmc_sdk-0.1.0/src/mythicmc/py.typed +0 -0
- mythicmc_sdk-0.1.0/tests/test_client.py +406 -0
- mythicmc_sdk-0.1.0/tests/test_models.py +160 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MythicMC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: mythicmc-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the MythicMC Public API.
|
|
5
|
+
Project-URL: Documentation, https://github.com/mythicmcnetwork/mythicmc-sdk#readme
|
|
6
|
+
Project-URL: Repository, https://github.com/mythicmcnetwork/mythicmc-sdk
|
|
7
|
+
Author: MythicMC
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: api,minecraft,mythicmc,sdk
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: httpx<1,>=0.25
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
MythicMC Public API (Python)
|
|
22
|
+
======
|
|
23
|
+
|
|
24
|
+
Python client for the MythicMC Public API. Python 3.10 or newer, synchronous and
|
|
25
|
+
asynchronous, built on [httpx](https://www.python-httpx.org/).
|
|
26
|
+
|
|
27
|
+
Create an API key in the [developer portal](https://developer.mythicmc.net/) with your MythicMC forum account. Production keys use development limits until approved.
|
|
28
|
+
|
|
29
|
+
### Install
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pip install mythicmc-sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Install from source
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pip install "git+https://github.com/mythicmcnetwork/mythicmc-sdk.git#subdirectory=python"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Usage
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import os
|
|
45
|
+
from mythicmc import MythicMC, NotFoundError
|
|
46
|
+
|
|
47
|
+
with MythicMC(os.environ["MYTHICMC_API_KEY"]) as api:
|
|
48
|
+
player = api.get_player("Vicente_1313") # username or UUID
|
|
49
|
+
print(player.rank.label, "unknown" if player.online is None else player.online)
|
|
50
|
+
print(player.meta.data_as_of) # UTC cutoff this response reflects
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
survival = api.get_player_stats("Vicente_1313").survival
|
|
54
|
+
print(survival.combat.kills, survival.net_worth.total if survival.net_worth else "unpublished")
|
|
55
|
+
except NotFoundError:
|
|
56
|
+
print("no published Survival statistics")
|
|
57
|
+
|
|
58
|
+
for row in api.get_leaderboard("kills", "weekly").rows:
|
|
59
|
+
print(row.rank, row.name, row.value)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`AsyncMythicMC` has the same methods as coroutines, for Discord bots and other
|
|
63
|
+
asyncio programs:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import asyncio
|
|
67
|
+
import os
|
|
68
|
+
from mythicmc import AsyncMythicMC
|
|
69
|
+
|
|
70
|
+
async def main() -> None:
|
|
71
|
+
async with AsyncMythicMC(os.environ["MYTHICMC_API_KEY"]) as api:
|
|
72
|
+
profile, team = await asyncio.gather(api.get_player("Vicente_1313"), api.get_player_team("Vicente_1313"))
|
|
73
|
+
print(profile.rank.label, team.team.name if team.team else "no team")
|
|
74
|
+
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Both clients hold an httpx connection pool. Use them as context managers, or call
|
|
79
|
+
`close()` yourself — `await api.close()` on the asynchronous one.
|
|
80
|
+
|
|
81
|
+
| Method | Endpoint |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `get_player(id)` | `GET /v1/players/{id}` |
|
|
84
|
+
| `get_player_stats(id)` | `GET /v1/players/{id}/stats` |
|
|
85
|
+
| `get_player_progression(id)` | `GET /v1/players/{id}/progression` |
|
|
86
|
+
| `get_player_team(id)` | `GET /v1/players/{id}/team` |
|
|
87
|
+
| `get_player_crate_keys(id)` | `GET /v1/players/{id}/crate-keys` |
|
|
88
|
+
| `list_leaderboards()` | `GET /v1/leaderboards` |
|
|
89
|
+
| `get_leaderboard(type, period)` | `GET /v1/leaderboards/{type}/{period}` |
|
|
90
|
+
| `health()` | `GET /health` |
|
|
91
|
+
|
|
92
|
+
`id` is a username, case-insensitive, or a UUID with or without dashes.
|
|
93
|
+
|
|
94
|
+
The [full API reference](https://developer.mythicmc.net/#reference) includes additional endpoints you can call directly over HTTP.
|
|
95
|
+
|
|
96
|
+
Replies are frozen dataclasses whose `snake_case` attributes come from the JSON's
|
|
97
|
+
`camelCase` keys. Each reply also carries `meta`, parsed from the response headers,
|
|
98
|
+
and `raw`, the decoded JSON body as a `dict`. Keys the models do not know about are
|
|
99
|
+
ignored, so a field the API adds later reaches you through `raw` rather than breaking
|
|
100
|
+
an older client.
|
|
101
|
+
|
|
102
|
+
### Options
|
|
103
|
+
|
|
104
|
+
| Argument | Default | |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `api_key` | required | Positional; the rest are keyword-only. |
|
|
107
|
+
| `base_url` | `https://api.mythicmc.net` | |
|
|
108
|
+
| `timeout` | `10.0` | Seconds, per attempt. |
|
|
109
|
+
| `max_retries` | `2` | Retries after a `429`, each waiting for `Retry-After`, or a second when there is none. A wait over a minute raises instead. `0` disables. |
|
|
110
|
+
| `transport` | `None` | An httpx transport, for tests or proxies. |
|
|
111
|
+
|
|
112
|
+
### Errors
|
|
113
|
+
|
|
114
|
+
Every response the client cannot turn into data raises a `MythicMCError`. `status` is
|
|
115
|
+
the HTTP status; `message` is the API's `error` string, or a stand-in when the
|
|
116
|
+
response carried none.
|
|
117
|
+
|
|
118
|
+
| Class | Status | |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `BadRequestError` | 400 | Not a valid username or UUID. |
|
|
121
|
+
| `AuthenticationError` | 401 | Missing or invalid key. |
|
|
122
|
+
| `NotFoundError` | 404 | Unknown player or board, or no published Survival statistics. |
|
|
123
|
+
| `RateLimitError` | 429 | Retries exhausted. `retry_after` is seconds, or `None`. |
|
|
124
|
+
| `UnavailableError` | 503 | Not published yet, an ambiguous username, or a server fault. Retrying later can work. |
|
|
125
|
+
|
|
126
|
+
Any other status, and a 2xx whose body is not the shape the model declares, raises
|
|
127
|
+
`MythicMCError` itself. Network failures and timeouts raise httpx's own exceptions.
|
|
128
|
+
|
|
129
|
+
### Examples
|
|
130
|
+
|
|
131
|
+
[examples](examples) holds one file per group of endpoints, plus `async_lookup.py`
|
|
132
|
+
for `AsyncMythicMC`.
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
pip install .
|
|
136
|
+
MYTHICMC_API_KEY=mmc_... python examples/get_player.py Vicente_1313
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Set `MYTHICMC_API_URL` to run them against a mock server instead of the live API.
|
|
140
|
+
|
|
141
|
+
### Development
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
pip install -e .
|
|
145
|
+
python -m unittest discover -s tests
|
|
146
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
MythicMC Public API (Python)
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Python client for the MythicMC Public API. Python 3.10 or newer, synchronous and
|
|
5
|
+
asynchronous, built on [httpx](https://www.python-httpx.org/).
|
|
6
|
+
|
|
7
|
+
Create an API key in the [developer portal](https://developer.mythicmc.net/) with your MythicMC forum account. Production keys use development limits until approved.
|
|
8
|
+
|
|
9
|
+
### Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pip install mythicmc-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Install from source
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pip install "git+https://github.com/mythicmcnetwork/mythicmc-sdk.git#subdirectory=python"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Usage
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import os
|
|
25
|
+
from mythicmc import MythicMC, NotFoundError
|
|
26
|
+
|
|
27
|
+
with MythicMC(os.environ["MYTHICMC_API_KEY"]) as api:
|
|
28
|
+
player = api.get_player("Vicente_1313") # username or UUID
|
|
29
|
+
print(player.rank.label, "unknown" if player.online is None else player.online)
|
|
30
|
+
print(player.meta.data_as_of) # UTC cutoff this response reflects
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
survival = api.get_player_stats("Vicente_1313").survival
|
|
34
|
+
print(survival.combat.kills, survival.net_worth.total if survival.net_worth else "unpublished")
|
|
35
|
+
except NotFoundError:
|
|
36
|
+
print("no published Survival statistics")
|
|
37
|
+
|
|
38
|
+
for row in api.get_leaderboard("kills", "weekly").rows:
|
|
39
|
+
print(row.rank, row.name, row.value)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`AsyncMythicMC` has the same methods as coroutines, for Discord bots and other
|
|
43
|
+
asyncio programs:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import asyncio
|
|
47
|
+
import os
|
|
48
|
+
from mythicmc import AsyncMythicMC
|
|
49
|
+
|
|
50
|
+
async def main() -> None:
|
|
51
|
+
async with AsyncMythicMC(os.environ["MYTHICMC_API_KEY"]) as api:
|
|
52
|
+
profile, team = await asyncio.gather(api.get_player("Vicente_1313"), api.get_player_team("Vicente_1313"))
|
|
53
|
+
print(profile.rank.label, team.team.name if team.team else "no team")
|
|
54
|
+
|
|
55
|
+
asyncio.run(main())
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Both clients hold an httpx connection pool. Use them as context managers, or call
|
|
59
|
+
`close()` yourself — `await api.close()` on the asynchronous one.
|
|
60
|
+
|
|
61
|
+
| Method | Endpoint |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `get_player(id)` | `GET /v1/players/{id}` |
|
|
64
|
+
| `get_player_stats(id)` | `GET /v1/players/{id}/stats` |
|
|
65
|
+
| `get_player_progression(id)` | `GET /v1/players/{id}/progression` |
|
|
66
|
+
| `get_player_team(id)` | `GET /v1/players/{id}/team` |
|
|
67
|
+
| `get_player_crate_keys(id)` | `GET /v1/players/{id}/crate-keys` |
|
|
68
|
+
| `list_leaderboards()` | `GET /v1/leaderboards` |
|
|
69
|
+
| `get_leaderboard(type, period)` | `GET /v1/leaderboards/{type}/{period}` |
|
|
70
|
+
| `health()` | `GET /health` |
|
|
71
|
+
|
|
72
|
+
`id` is a username, case-insensitive, or a UUID with or without dashes.
|
|
73
|
+
|
|
74
|
+
The [full API reference](https://developer.mythicmc.net/#reference) includes additional endpoints you can call directly over HTTP.
|
|
75
|
+
|
|
76
|
+
Replies are frozen dataclasses whose `snake_case` attributes come from the JSON's
|
|
77
|
+
`camelCase` keys. Each reply also carries `meta`, parsed from the response headers,
|
|
78
|
+
and `raw`, the decoded JSON body as a `dict`. Keys the models do not know about are
|
|
79
|
+
ignored, so a field the API adds later reaches you through `raw` rather than breaking
|
|
80
|
+
an older client.
|
|
81
|
+
|
|
82
|
+
### Options
|
|
83
|
+
|
|
84
|
+
| Argument | Default | |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `api_key` | required | Positional; the rest are keyword-only. |
|
|
87
|
+
| `base_url` | `https://api.mythicmc.net` | |
|
|
88
|
+
| `timeout` | `10.0` | Seconds, per attempt. |
|
|
89
|
+
| `max_retries` | `2` | Retries after a `429`, each waiting for `Retry-After`, or a second when there is none. A wait over a minute raises instead. `0` disables. |
|
|
90
|
+
| `transport` | `None` | An httpx transport, for tests or proxies. |
|
|
91
|
+
|
|
92
|
+
### Errors
|
|
93
|
+
|
|
94
|
+
Every response the client cannot turn into data raises a `MythicMCError`. `status` is
|
|
95
|
+
the HTTP status; `message` is the API's `error` string, or a stand-in when the
|
|
96
|
+
response carried none.
|
|
97
|
+
|
|
98
|
+
| Class | Status | |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `BadRequestError` | 400 | Not a valid username or UUID. |
|
|
101
|
+
| `AuthenticationError` | 401 | Missing or invalid key. |
|
|
102
|
+
| `NotFoundError` | 404 | Unknown player or board, or no published Survival statistics. |
|
|
103
|
+
| `RateLimitError` | 429 | Retries exhausted. `retry_after` is seconds, or `None`. |
|
|
104
|
+
| `UnavailableError` | 503 | Not published yet, an ambiguous username, or a server fault. Retrying later can work. |
|
|
105
|
+
|
|
106
|
+
Any other status, and a 2xx whose body is not the shape the model declares, raises
|
|
107
|
+
`MythicMCError` itself. Network failures and timeouts raise httpx's own exceptions.
|
|
108
|
+
|
|
109
|
+
### Examples
|
|
110
|
+
|
|
111
|
+
[examples](examples) holds one file per group of endpoints, plus `async_lookup.py`
|
|
112
|
+
for `AsyncMythicMC`.
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
pip install .
|
|
116
|
+
MYTHICMC_API_KEY=mmc_... python examples/get_player.py Vicente_1313
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Set `MYTHICMC_API_URL` to run them against a mock server instead of the live API.
|
|
120
|
+
|
|
121
|
+
### Development
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
pip install -e .
|
|
125
|
+
python -m unittest discover -s tests
|
|
126
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from mythicmc import DEFAULT_BASE_URL, AsyncMythicMC
|
|
6
|
+
|
|
7
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
8
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def main(player: str) -> None:
|
|
12
|
+
async with AsyncMythicMC(key, base_url=base_url) as api:
|
|
13
|
+
profile, progression, team = await asyncio.gather(
|
|
14
|
+
api.get_player(player),
|
|
15
|
+
api.get_player_progression(player),
|
|
16
|
+
api.get_player_team(player),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
print(f"[{profile.rank.label}] {profile.name}: network level {progression.level}")
|
|
20
|
+
print("team:", team.team.name if team.team else "none")
|
|
21
|
+
|
|
22
|
+
# Separate cache entries can have different cutoffs; show the oldest.
|
|
23
|
+
cutoffs = [reply.meta.data_as_of for reply in (profile, progression, team) if reply.meta.data_as_of]
|
|
24
|
+
print("data as of:", min(cutoffs) if cutoffs else "unknown")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
asyncio.run(main(sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"))
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC
|
|
4
|
+
|
|
5
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
6
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
7
|
+
|
|
8
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
9
|
+
index = api.list_leaderboards()
|
|
10
|
+
board = api.get_leaderboard("kills", "weekly")
|
|
11
|
+
|
|
12
|
+
for board_type, periods in index.boards.items():
|
|
13
|
+
print(f"{board_type}: {', '.join(periods)}")
|
|
14
|
+
|
|
15
|
+
# Periods use America/New_York time; weeks start on Friday.
|
|
16
|
+
print(f"\nkills / weekly, {board.window_start} to {board.window_end}")
|
|
17
|
+
if board.stale:
|
|
18
|
+
print("this board is stale")
|
|
19
|
+
|
|
20
|
+
# Values are formatted strings. Use player stats for calculations.
|
|
21
|
+
for row in board.rows:
|
|
22
|
+
print(f"#{row.rank} {row.name}: {row.value}")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
|
|
5
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC
|
|
6
|
+
|
|
7
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
8
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
9
|
+
player = sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"
|
|
10
|
+
|
|
11
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
12
|
+
profile = api.get_player(player) # username or UUID
|
|
13
|
+
|
|
14
|
+
print(f"[{profile.rank.label}] {profile.name} ({profile.uuid})")
|
|
15
|
+
|
|
16
|
+
print("online:", "unknown" if profile.online is None else profile.online)
|
|
17
|
+
print("gamemode:", profile.location.gamemode if profile.location else "unknown")
|
|
18
|
+
print("network level:", profile.level if profile.level is not None else "unknown")
|
|
19
|
+
print("team:", profile.team.name if profile.team else "none")
|
|
20
|
+
|
|
21
|
+
last_login = profile.last_login
|
|
22
|
+
print("last login:", datetime.fromtimestamp(last_login / 1000, timezone.utc) if last_login is not None else "unknown")
|
|
23
|
+
print("data as of:", profile.meta.data_as_of or "unknown")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC
|
|
5
|
+
|
|
6
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
7
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
8
|
+
player = sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"
|
|
9
|
+
|
|
10
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
11
|
+
crate_keys = api.get_player_crate_keys(player).keys
|
|
12
|
+
|
|
13
|
+
# Missing crates and unpublished balances are unknown, not zero.
|
|
14
|
+
for crate_key in crate_keys:
|
|
15
|
+
available = crate_key.available
|
|
16
|
+
print(f"{crate_key.crate_id} ({crate_key.key_type}): {available if available is not None else 'unknown'}")
|
|
17
|
+
if not crate_keys:
|
|
18
|
+
print(f"no crate key balances are published for {player}")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC
|
|
5
|
+
|
|
6
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
7
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
8
|
+
player = sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"
|
|
9
|
+
|
|
10
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
11
|
+
progression = api.get_player_progression(player)
|
|
12
|
+
|
|
13
|
+
print(f"level {progression.level}, {progression.experience} XP in total")
|
|
14
|
+
|
|
15
|
+
# Progress and target are XP within the current level.
|
|
16
|
+
print("max level" if progression.maxed else f"{progression.progress} / {progression.target} XP to the next level")
|
|
17
|
+
|
|
18
|
+
achievements = progression.achievements
|
|
19
|
+
print("achievements:", f"{sum(a.complete for a in achievements)} of {len(achievements)}" if achievements else "unknown")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC, NotFoundError
|
|
5
|
+
|
|
6
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
7
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
8
|
+
player = sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
12
|
+
survival = api.get_player_stats(player).survival
|
|
13
|
+
except NotFoundError as error:
|
|
14
|
+
sys.exit(f"no Survival statistics for {player}: {error.message}")
|
|
15
|
+
|
|
16
|
+
combat = survival.combat
|
|
17
|
+
print(f"kills {combat.kills}, deaths {combat.deaths}, K/D {combat.kills / max(combat.deaths, 1):.2f}")
|
|
18
|
+
print("blocks mined:", survival.world.blocks_mined)
|
|
19
|
+
|
|
20
|
+
# Missing groups are unknown, not zero.
|
|
21
|
+
net_worth = survival.net_worth
|
|
22
|
+
print("net worth:", f"${net_worth.total} (#{net_worth.rank})" if net_worth else "unknown")
|
|
23
|
+
print("balance:", survival.money if survival.money is not None else "unknown")
|
|
24
|
+
events = survival.events
|
|
25
|
+
print("events won:", events.wins.bingo + events.wins.raffle if events else "unknown")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from mythicmc import DEFAULT_BASE_URL, MythicMC
|
|
5
|
+
|
|
6
|
+
key = os.environ["MYTHICMC_API_KEY"]
|
|
7
|
+
base_url = os.environ.get("MYTHICMC_API_URL", DEFAULT_BASE_URL)
|
|
8
|
+
player = sys.argv[1] if len(sys.argv) > 1 else "Vicente_1313"
|
|
9
|
+
|
|
10
|
+
with MythicMC(key, base_url=base_url) as api:
|
|
11
|
+
reply = api.get_player_team(player)
|
|
12
|
+
|
|
13
|
+
team = reply.team
|
|
14
|
+
if team is None:
|
|
15
|
+
print(f"{reply.name} is not in a team")
|
|
16
|
+
else:
|
|
17
|
+
print(f"{reply.name} is in [{team.prefix}] {team.name}, team level {team.level}, role {team.role or 'unknown'}")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# PEP 639 license metadata requires hatchling 1.27+.
|
|
3
|
+
requires = ["hatchling>=1.27"]
|
|
4
|
+
build-backend = "hatchling.build"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "mythicmc-sdk"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
description = "Official Python client for the MythicMC Public API."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "MythicMC" }]
|
|
14
|
+
dependencies = ["httpx>=0.25,<1"]
|
|
15
|
+
keywords = ["mythicmc", "minecraft", "api", "sdk"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Documentation = "https://github.com/mythicmcnetwork/mythicmc-sdk#readme"
|
|
27
|
+
Repository = "https://github.com/mythicmcnetwork/mythicmc-sdk"
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.targets.wheel]
|
|
30
|
+
packages = ["src/mythicmc"]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from .client import DEFAULT_BASE_URL, AsyncMythicMC, MythicMC, __version__
|
|
2
|
+
from .errors import (
|
|
3
|
+
AuthenticationError,
|
|
4
|
+
BadRequestError,
|
|
5
|
+
MythicMCError,
|
|
6
|
+
NotFoundError,
|
|
7
|
+
RateLimitError,
|
|
8
|
+
UnavailableError,
|
|
9
|
+
)
|
|
10
|
+
from .models import (
|
|
11
|
+
Achievement,
|
|
12
|
+
AuctionStats,
|
|
13
|
+
BountyStats,
|
|
14
|
+
CombatStats,
|
|
15
|
+
Cosmetics,
|
|
16
|
+
CrateKey,
|
|
17
|
+
EventStats,
|
|
18
|
+
EventWins,
|
|
19
|
+
Health,
|
|
20
|
+
Leaderboard,
|
|
21
|
+
LeaderboardIndex,
|
|
22
|
+
LeaderboardPeriod,
|
|
23
|
+
LeaderboardRow,
|
|
24
|
+
LeaderboardType,
|
|
25
|
+
Location,
|
|
26
|
+
NetWorth,
|
|
27
|
+
PlayerCrateKeys,
|
|
28
|
+
PlayerProfile,
|
|
29
|
+
PlayerProgression,
|
|
30
|
+
PlayerStats,
|
|
31
|
+
PlayerTeam,
|
|
32
|
+
Rank,
|
|
33
|
+
ResponseMeta,
|
|
34
|
+
SelectedCosmetic,
|
|
35
|
+
Skin,
|
|
36
|
+
StatRanks,
|
|
37
|
+
SurvivalStats,
|
|
38
|
+
TeamRole,
|
|
39
|
+
TeamSummary,
|
|
40
|
+
WorldStats,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"DEFAULT_BASE_URL",
|
|
45
|
+
"AsyncMythicMC",
|
|
46
|
+
"MythicMC",
|
|
47
|
+
"__version__",
|
|
48
|
+
"AuthenticationError",
|
|
49
|
+
"BadRequestError",
|
|
50
|
+
"MythicMCError",
|
|
51
|
+
"NotFoundError",
|
|
52
|
+
"RateLimitError",
|
|
53
|
+
"UnavailableError",
|
|
54
|
+
"Achievement",
|
|
55
|
+
"AuctionStats",
|
|
56
|
+
"BountyStats",
|
|
57
|
+
"CombatStats",
|
|
58
|
+
"Cosmetics",
|
|
59
|
+
"CrateKey",
|
|
60
|
+
"EventStats",
|
|
61
|
+
"EventWins",
|
|
62
|
+
"Health",
|
|
63
|
+
"Leaderboard",
|
|
64
|
+
"LeaderboardIndex",
|
|
65
|
+
"LeaderboardPeriod",
|
|
66
|
+
"LeaderboardRow",
|
|
67
|
+
"LeaderboardType",
|
|
68
|
+
"Location",
|
|
69
|
+
"NetWorth",
|
|
70
|
+
"PlayerCrateKeys",
|
|
71
|
+
"PlayerProfile",
|
|
72
|
+
"PlayerProgression",
|
|
73
|
+
"PlayerStats",
|
|
74
|
+
"PlayerTeam",
|
|
75
|
+
"Rank",
|
|
76
|
+
"ResponseMeta",
|
|
77
|
+
"SelectedCosmetic",
|
|
78
|
+
"Skin",
|
|
79
|
+
"StatRanks",
|
|
80
|
+
"SurvivalStats",
|
|
81
|
+
"TeamRole",
|
|
82
|
+
"TeamSummary",
|
|
83
|
+
"WorldStats",
|
|
84
|
+
]
|