python-ballchasing 0.2.0__tar.gz → 0.3.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.
- python_ballchasing-0.3.0/PKG-INFO +92 -0
- python_ballchasing-0.3.0/README.md +75 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/ballchasing/api.py +71 -57
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/ballchasing/constants.py +68 -47
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/pyproject.toml +1 -1
- python_ballchasing-0.3.0/python_ballchasing.egg-info/PKG-INFO +92 -0
- python_ballchasing-0.2.0/PKG-INFO +0 -36
- python_ballchasing-0.2.0/README.md +0 -19
- python_ballchasing-0.2.0/python_ballchasing.egg-info/PKG-INFO +0 -36
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/LICENSE +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/ballchasing/__init__.py +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/ballchasing/stats_info.tsv +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/ballchasing/util.py +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/SOURCES.txt +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/dependency_links.txt +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/requires.txt +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/top_level.txt +0 -0
- {python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/setup.cfg +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-ballchasing
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A Python wrapper around the Ballchasing API
|
|
5
|
+
Author-email: Rolv-Arild Braaten <rolv_arild@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Project-URL: Homepage, https://github.com/Rolv-Arild/python-ballchasing
|
|
8
|
+
Project-URL: Download, https://pypi.python.org/pypi/python-ballchasing
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# Python Ballchasing
|
|
19
|
+
An easy-to-use and comprehensive Python wrapper for the [ballchasing.com API](https://ballchasing.com/doc/api).
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
You can install the library from PyPI using pip:
|
|
23
|
+
```
|
|
24
|
+
pip install python-ballchasing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
Before you can use the library, you need an API authentication key from ballchasing.com.
|
|
29
|
+
1. Log in to [ballchasing.com](https://ballchasing.com/).
|
|
30
|
+
2. Navigate to the Upload tab.
|
|
31
|
+
3. Create an API key and copy it.
|
|
32
|
+
|
|
33
|
+
**Keep your API key secure and do not share it publicly.**
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
For detailed information, please refer to the docs inside the code. For the most part it follows the API spec closely, but there are some differences.
|
|
37
|
+
|
|
38
|
+
The API is exposed via the `BallchasingApi` class.
|
|
39
|
+
|
|
40
|
+
Making the client:
|
|
41
|
+
```python
|
|
42
|
+
from ballchasing import BallchasingApi
|
|
43
|
+
api = BallchasingApi("Your token here")
|
|
44
|
+
```
|
|
45
|
+
or equivalently
|
|
46
|
+
```python
|
|
47
|
+
import ballchasing
|
|
48
|
+
api = ballchasing.Api("Your token here")
|
|
49
|
+
```
|
|
50
|
+
By default this will also ping the API to make sure it's working.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
Some simple examples:
|
|
54
|
+
```python
|
|
55
|
+
# Get lots of SSL replays
|
|
56
|
+
|
|
57
|
+
from ballchasing import Rank # there's also Playlist, Season, Map, and more
|
|
58
|
+
|
|
59
|
+
replays = api.get_replays(
|
|
60
|
+
min_rank=Rank.SUPERSONIC_LEGEND,
|
|
61
|
+
count=10_000 # The API limits you to 200 replays per request but the library handles this for you
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
for replay in replays: # (replays is an iterable so you don't need to wait for all the replays to be collected)
|
|
65
|
+
... # Do something with the replays
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Get a specific replay with more detail than the iterator (including stats!)
|
|
70
|
+
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
# Get groups by the "RLCS Referee" account
|
|
75
|
+
groups = api.get_groups(creator="76561199225615730")
|
|
76
|
+
|
|
77
|
+
for group in groups:
|
|
78
|
+
# Download the group
|
|
79
|
+
api.download_group(
|
|
80
|
+
group_id=group["id"],
|
|
81
|
+
folder="/path/to/destination/"
|
|
82
|
+
recursive=True, # To download all the replays and retain the group structure with subfolders
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Get replays from the group
|
|
86
|
+
replays = get_group_replays(
|
|
87
|
+
group_id=group["id"],
|
|
88
|
+
deep=True, # To get detailed replay info
|
|
89
|
+
)
|
|
90
|
+
for replay in replays:
|
|
91
|
+
api.download_replay(replay_id=replay["id"], folder="/path/to/destination/") # You could also download like this
|
|
92
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Python Ballchasing
|
|
2
|
+
An easy-to-use and comprehensive Python wrapper for the [ballchasing.com API](https://ballchasing.com/doc/api).
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
You can install the library from PyPI using pip:
|
|
6
|
+
```
|
|
7
|
+
pip install python-ballchasing
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Authentication
|
|
11
|
+
Before you can use the library, you need an API authentication key from ballchasing.com.
|
|
12
|
+
1. Log in to [ballchasing.com](https://ballchasing.com/).
|
|
13
|
+
2. Navigate to the Upload tab.
|
|
14
|
+
3. Create an API key and copy it.
|
|
15
|
+
|
|
16
|
+
**Keep your API key secure and do not share it publicly.**
|
|
17
|
+
|
|
18
|
+
## API
|
|
19
|
+
For detailed information, please refer to the docs inside the code. For the most part it follows the API spec closely, but there are some differences.
|
|
20
|
+
|
|
21
|
+
The API is exposed via the `BallchasingApi` class.
|
|
22
|
+
|
|
23
|
+
Making the client:
|
|
24
|
+
```python
|
|
25
|
+
from ballchasing import BallchasingApi
|
|
26
|
+
api = BallchasingApi("Your token here")
|
|
27
|
+
```
|
|
28
|
+
or equivalently
|
|
29
|
+
```python
|
|
30
|
+
import ballchasing
|
|
31
|
+
api = ballchasing.Api("Your token here")
|
|
32
|
+
```
|
|
33
|
+
By default this will also ping the API to make sure it's working.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
Some simple examples:
|
|
37
|
+
```python
|
|
38
|
+
# Get lots of SSL replays
|
|
39
|
+
|
|
40
|
+
from ballchasing import Rank # there's also Playlist, Season, Map, and more
|
|
41
|
+
|
|
42
|
+
replays = api.get_replays(
|
|
43
|
+
min_rank=Rank.SUPERSONIC_LEGEND,
|
|
44
|
+
count=10_000 # The API limits you to 200 replays per request but the library handles this for you
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
for replay in replays: # (replays is an iterable so you don't need to wait for all the replays to be collected)
|
|
48
|
+
... # Do something with the replays
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# Get a specific replay with more detail than the iterator (including stats!)
|
|
53
|
+
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
# Get groups by the "RLCS Referee" account
|
|
58
|
+
groups = api.get_groups(creator="76561199225615730")
|
|
59
|
+
|
|
60
|
+
for group in groups:
|
|
61
|
+
# Download the group
|
|
62
|
+
api.download_group(
|
|
63
|
+
group_id=group["id"],
|
|
64
|
+
folder="/path/to/destination/"
|
|
65
|
+
recursive=True, # To download all the replays and retain the group structure with subfolders
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Get replays from the group
|
|
69
|
+
replays = get_group_replays(
|
|
70
|
+
group_id=group["id"],
|
|
71
|
+
deep=True, # To get detailed replay info
|
|
72
|
+
)
|
|
73
|
+
for replay in replays:
|
|
74
|
+
api.download_replay(replay_id=replay["id"], folder="/path/to/destination/") # You could also download like this
|
|
75
|
+
```
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import time
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional, Iterator, Union, List, BinaryIO
|
|
5
6
|
from urllib.parse import parse_qs, urlparse
|
|
6
7
|
|
|
7
8
|
from requests import sessions, Response, ConnectionError
|
|
@@ -18,12 +19,14 @@ class BallchasingApi:
|
|
|
18
19
|
Class for communication with ballchasing.com API (https://ballchasing.com/doc/api)
|
|
19
20
|
"""
|
|
20
21
|
|
|
21
|
-
def __init__(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
auth_key: str,
|
|
25
|
+
sleep_time_on_rate_limit: Optional[float] = None,
|
|
26
|
+
print_on_rate_limit: bool = False,
|
|
27
|
+
base_url=None,
|
|
28
|
+
do_initial_ping=True
|
|
29
|
+
):
|
|
27
30
|
"""
|
|
28
31
|
|
|
29
32
|
:param auth_key: authentication key for API calls.
|
|
@@ -74,11 +77,12 @@ class BallchasingApi:
|
|
|
74
77
|
self.ping()
|
|
75
78
|
return self._ping_result.get("quota")
|
|
76
79
|
|
|
77
|
-
def _request(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
def _request(
|
|
81
|
+
self,
|
|
82
|
+
url_or_endpoint: str,
|
|
83
|
+
method: str,
|
|
84
|
+
**params
|
|
85
|
+
) -> Response:
|
|
82
86
|
"""
|
|
83
87
|
Helper method for all requests.
|
|
84
88
|
|
|
@@ -92,7 +96,8 @@ class BallchasingApi:
|
|
|
92
96
|
headers = {"Authorization": self.auth_key}
|
|
93
97
|
url = f"{self.base_url}{url_or_endpoint}" if url_or_endpoint.startswith("/") else url_or_endpoint
|
|
94
98
|
max_retries = 8
|
|
95
|
-
|
|
99
|
+
retries = 0
|
|
100
|
+
while True:
|
|
96
101
|
try:
|
|
97
102
|
r: Response = self._session.request(method=method, url=url, headers=headers, **params)
|
|
98
103
|
if 200 <= r.status_code < 300:
|
|
@@ -108,13 +113,14 @@ class BallchasingApi:
|
|
|
108
113
|
elif self.sleep_time_on_rate_limit:
|
|
109
114
|
time.sleep(self.sleep_time_on_rate_limit)
|
|
110
115
|
else:
|
|
111
|
-
r.raise_for_status() # Raise an error for any other status code
|
|
116
|
+
r.raise_for_status() # Raise an error for any other status code'
|
|
112
117
|
except ConnectionError as e:
|
|
113
118
|
if retries >= max_retries - 1:
|
|
114
119
|
raise e
|
|
115
120
|
s = 2 ** retries
|
|
116
121
|
print(f"Connection error, trying again in {s} seconds...")
|
|
117
122
|
time.sleep(s)
|
|
123
|
+
retries += 1
|
|
118
124
|
|
|
119
125
|
def ping(self) -> dict:
|
|
120
126
|
"""
|
|
@@ -130,28 +136,29 @@ class BallchasingApi:
|
|
|
130
136
|
self._ping_result = result
|
|
131
137
|
return result
|
|
132
138
|
|
|
133
|
-
def get_replays(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
139
|
+
def get_replays(
|
|
140
|
+
self,
|
|
141
|
+
title: Optional[str] = None,
|
|
142
|
+
player_name: Optional[Union[str, List[str]]] = None,
|
|
143
|
+
player_id: Optional[Union[str, List[str]]] = None,
|
|
144
|
+
playlist: Optional[Union[AnyPlaylist, List[AnyPlaylist]]] = None,
|
|
145
|
+
season: Optional[Union[AnySeason, List[AnySeason]]] = None,
|
|
146
|
+
match_result: Optional[Union[AnyMatchResult, List[AnyMatchResult]]] = None,
|
|
147
|
+
min_rank: Optional[AnyRank] = None,
|
|
148
|
+
max_rank: Optional[AnyRank] = None,
|
|
149
|
+
pro: Optional[bool] = None,
|
|
150
|
+
uploader: Optional[str] = None,
|
|
151
|
+
group_id: Optional[Union[str, List[str]]] = None,
|
|
152
|
+
map_id: Optional[Union[AnyMap, List[AnyMap]]] = None,
|
|
153
|
+
created_before: Optional[Union[str, datetime]] = None,
|
|
154
|
+
created_after: Optional[Union[str, datetime]] = None,
|
|
155
|
+
replay_after: Optional[Union[str, datetime]] = None,
|
|
156
|
+
replay_before: Optional[Union[str, datetime]] = None,
|
|
157
|
+
count: int = 150,
|
|
158
|
+
sort_by: Optional[AnyReplaySortBy] = None,
|
|
159
|
+
sort_dir: AnySortDir = SortDir.DESCENDING,
|
|
160
|
+
deep: bool = False
|
|
161
|
+
) -> Iterator[dict]:
|
|
155
162
|
"""
|
|
156
163
|
This endpoint lets you filter and retrieve replays. The implementation returns an iterator.
|
|
157
164
|
|
|
@@ -230,18 +237,23 @@ class BallchasingApi:
|
|
|
230
237
|
"""
|
|
231
238
|
self._request(f"/replays/{replay_id}", "PATCH", json=params)
|
|
232
239
|
|
|
233
|
-
def upload_replay(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
240
|
+
def upload_replay(
|
|
241
|
+
self,
|
|
242
|
+
replay_file: Union[str, Path, BinaryIO],
|
|
243
|
+
visibility: Optional[AnyVisibility] = None,
|
|
244
|
+
group: Optional[str] = None
|
|
245
|
+
) -> dict:
|
|
237
246
|
"""
|
|
238
247
|
Use this API to upload a replay file to ballchasing.com.
|
|
239
248
|
|
|
240
|
-
:param replay_file: replay file to upload.
|
|
249
|
+
:param replay_file: replay file to upload. Can be a file path (str or Path) or a file-like object.
|
|
241
250
|
:param visibility: to set the visibility of the uploaded replay.
|
|
242
251
|
:param group: to upload the replay to an existing group.
|
|
243
252
|
:return: the result of the POST request.
|
|
244
253
|
"""
|
|
254
|
+
if isinstance(replay_file, (str, Path)):
|
|
255
|
+
with open(replay_file, "rb") as f:
|
|
256
|
+
return self.upload_replay(f, visibility, group)
|
|
245
257
|
return self._request(f"/v2/upload", "POST", files={"file": replay_file},
|
|
246
258
|
params={"group": group, "visibility": visibility}).json()
|
|
247
259
|
|
|
@@ -254,16 +266,17 @@ class BallchasingApi:
|
|
|
254
266
|
"""
|
|
255
267
|
self._request(f"/replays/{replay_id}", "DELETE")
|
|
256
268
|
|
|
257
|
-
def get_groups(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
def get_groups(
|
|
270
|
+
self,
|
|
271
|
+
name: Optional[str] = None,
|
|
272
|
+
creator: Optional[str] = None,
|
|
273
|
+
group: Optional[str] = None,
|
|
274
|
+
created_before: Optional[Union[str, datetime]] = None,
|
|
275
|
+
created_after: Optional[Union[str, datetime]] = None,
|
|
276
|
+
count: int = 200,
|
|
277
|
+
sort_by: AnyGroupSortBy = GroupSortBy.CREATED,
|
|
278
|
+
sort_dir: AnySortDir = SortDir.DESCENDING
|
|
279
|
+
) -> Iterator[dict]:
|
|
267
280
|
"""
|
|
268
281
|
This endpoint lets you filter and retrieve replay groups.
|
|
269
282
|
|
|
@@ -301,12 +314,13 @@ class BallchasingApi:
|
|
|
301
314
|
left -= len(batch)
|
|
302
315
|
params["after"] = parse_qs(urlparse(next_url).query)["after"][0]
|
|
303
316
|
|
|
304
|
-
def create_group(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
317
|
+
def create_group(
|
|
318
|
+
self,
|
|
319
|
+
name: str,
|
|
320
|
+
player_identification: AnyPlayerIdentification,
|
|
321
|
+
team_identification: AnyTeamIdentification,
|
|
322
|
+
parent: Optional[str] = None
|
|
323
|
+
) -> dict:
|
|
310
324
|
"""
|
|
311
325
|
Use this API to create a new replay group.
|
|
312
326
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Literal, get_args, AnyStr, Union
|
|
1
|
+
from typing import Literal, get_args, AnyStr, Union
|
|
2
2
|
|
|
3
3
|
AnyPlaylist = Union[
|
|
4
4
|
AnyStr,
|
|
@@ -41,6 +41,7 @@ AnyRank = Union[
|
|
|
41
41
|
"platinum-1", "platinum-2", "platinum-3",
|
|
42
42
|
"diamond-1", "diamond-2", "diamond-3",
|
|
43
43
|
"champion-1", "champion-2", "champion-3",
|
|
44
|
+
"grand-champion", # Legacy. Seems to be interchangeable with "grand-champion-1"
|
|
44
45
|
"grand-champion-1", "grand-champion-2", "grand-champion-3",
|
|
45
46
|
"supersonic-legend"
|
|
46
47
|
],
|
|
@@ -48,9 +49,18 @@ AnyRank = Union[
|
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
class Rank:
|
|
51
|
-
ALL = (
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
ALL = (
|
|
53
|
+
UNRANKED,
|
|
54
|
+
BRONZE_1, BRONZE_2, BRONZE_3,
|
|
55
|
+
SILVER_1, SILVER_2, SILVER_3,
|
|
56
|
+
GOLD_1, GOLD_2, GOLD_3,
|
|
57
|
+
PLATINUM_1, PLATINUM_2, PLATINUM_3,
|
|
58
|
+
DIAMOND_1, DIAMOND_2, DIAMOND_3,
|
|
59
|
+
CHAMPION_1, CHAMPION_2, CHAMPION_3,
|
|
60
|
+
GRAND_CHAMPION_LEGACY,
|
|
61
|
+
GRAND_CHAMPION_1, GRAND_CHAMPION_2, GRAND_CHAMPION_3,
|
|
62
|
+
SUPERSONIC_LEGEND
|
|
63
|
+
) = _get_literals(AnyRank)
|
|
54
64
|
BRONZE = (BRONZE_1, BRONZE_2, BRONZE_3)
|
|
55
65
|
SILVER = (SILVER_1, SILVER_2, SILVER_3)
|
|
56
66
|
GOLD = (GOLD_1, GOLD_2, GOLD_3)
|
|
@@ -65,18 +75,21 @@ AnySeason = Union[
|
|
|
65
75
|
Literal[
|
|
66
76
|
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14",
|
|
67
77
|
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
|
|
68
|
-
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18"
|
|
78
|
+
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19"
|
|
69
79
|
]
|
|
70
80
|
]
|
|
71
81
|
|
|
72
82
|
|
|
73
83
|
class Season:
|
|
74
|
-
ALL = (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
ALL = (
|
|
85
|
+
SEASON_1_LEGACY, SEASON_2_LEGACY, SEASON_3_LEGACY, SEASON_4_LEGACY, SEASON_5_LEGACY, SEASON_6_LEGACY,
|
|
86
|
+
SEASON_7_LEGACY, SEASON_8_LEGACY, SEASON_9_LEGACY, SEASON_10_LEGACY, SEASON_11_LEGACY, SEASON_12_LEGACY,
|
|
87
|
+
SEASON_13_LEGACY, SEASON_14_LEGACY,
|
|
88
|
+
SEASON_1_FTP, SEASON_2_FTP, SEASON_3_FTP, SEASON_4_FTP, SEASON_5_FTP, SEASON_6_FTP, SEASON_7_FTP,
|
|
89
|
+
SEASON_8_FTP, SEASON_9_FTP, SEASON_10_FTP, SEASON_11_FTP, SEASON_12_FTP, SEASON_13_FTP, SEASON_14_FTP,
|
|
90
|
+
SEASON_15_FTP, SEASON_16_FTP, SEASON_17_FTP, SEASON_18_FTP, SEASON_19_FTP
|
|
91
|
+
) = _get_literals(AnySeason)
|
|
92
|
+
LEGACY = ALL[:14]
|
|
80
93
|
FREE_TO_PLAY = ALL[14:]
|
|
81
94
|
|
|
82
95
|
|
|
@@ -134,13 +147,15 @@ AnyMap = Union[AnyStr, Literal[
|
|
|
134
147
|
"chn_stadium_day_p", "chn_stadium_p", "cs_day_p", "cs_hw_p", "cs_p", "eurostadium_dusk_p", "eurostadium_night_p",
|
|
135
148
|
"eurostadium_p", "eurostadium_rainy_p", "eurostadium_snownight_p", "farm_grs_p", "farm_hw_p", "farm_night_p",
|
|
136
149
|
"farm_p", "farm_upsidedown_p", "ff_dusk_p", "fni_stadium_p", "haunted_trainstation_p", "hoopsstadium_p",
|
|
137
|
-
"hoopsstreet_p", "
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
150
|
+
"hoopsstreet_p", "ko_calavera_p", "ko_carbon_p", "ko_quadron_p", "labs_basin_p", "labs_circlepillars_p",
|
|
151
|
+
"labs_corridor_p", "labs_cosmic_p", "labs_cosmic_v4_p", "labs_doublegoal_p", "labs_doublegoal_v2_p",
|
|
152
|
+
"labs_galleon_mast_p", "labs_galleon_p", "labs_holyfield_p", "labs_holyfield_space_p", "labs_octagon_02_p",
|
|
153
|
+
"labs_octagon_p", "labs_pillarglass_p", "labs_pillarheat_p", "labs_pillarwings_p", "labs_underpass_p",
|
|
154
|
+
"labs_underpass_v0_p", "labs_utopia_p", "music_p", "neotokyo_arcade_p", "neotokyo_hax_p", "neotokyo_p",
|
|
155
|
+
"neotokyo_standard_p", "neotokyo_toon_p", "outlaw_oasis_p", "outlaw_p", "park_bman_p", "park_night_p", "park_p",
|
|
156
|
+
"park_rainy_p", "park_snowy_p", "shattershot_p", "stadium_10a_p", "stadium_day_p", "stadium_foggy_p", "stadium_p",
|
|
157
|
+
"stadium_race_day_p", "stadium_winter_p", "street_p", "swoosh_p", "throwbackhockey_p", "throwbackstadium_p",
|
|
158
|
+
"trainstation_dawn_p", "trainstation_night_p", "trainstation_p", "trainstation_spooky_p", "uf_day_p",
|
|
144
159
|
"underwater_grs_p", "underwater_p", "utopiastadium_dusk_p", "utopiastadium_lux_p", "utopiastadium_p",
|
|
145
160
|
"utopiastadium_snow_p", "wasteland_grs_p", "wasteland_night_p", "wasteland_night_s_p", "wasteland_p",
|
|
146
161
|
"wasteland_s_p", "woods_night_p", "woods_p"
|
|
@@ -153,15 +168,17 @@ class Map:
|
|
|
153
168
|
CHN_STADIUM_DAY_P, CHN_STADIUM_P, CS_DAY_P, CS_HW_P, CS_P, EUROSTADIUM_DUSK_P, EUROSTADIUM_NIGHT_P,
|
|
154
169
|
EUROSTADIUM_P, EUROSTADIUM_RAINY_P, EUROSTADIUM_SNOWNIGHT_P, FARM_GRS_P, FARM_HW_P, FARM_NIGHT_P, FARM_P,
|
|
155
170
|
FARM_UPSIDEDOWN_P, FF_DUSK_P, FNI_STADIUM_P, HAUNTED_TRAINSTATION_P, HOOPSSTADIUM_P, HOOPSSTREET_P,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
171
|
+
KO_CALAVERA_P, KO_CARBON_P, KO_QUADRON_P, LABS_BASIN_P, LABS_CIRCLEPILLARS_P, LABS_CORRIDOR_P, LABS_COSMIC_P,
|
|
172
|
+
LABS_COSMIC_V4_P, LABS_DOUBLEGOAL_P, LABS_DOUBLEGOAL_V2_P, LABS_GALLEON_MAST_P, LABS_GALLEON_P,
|
|
173
|
+
LABS_HOLYFIELD_P, LABS_HOLYFIELD_SPACE_P, LABS_OCTAGON_02_P, LABS_OCTAGON_P, LABS_PILLARGLASS_P,
|
|
174
|
+
LABS_PILLARHEAT_P, LABS_PILLARWINGS_P, LABS_UNDERPASS_P, LABS_UNDERPASS_V0_P, LABS_UTOPIA_P, MUSIC_P,
|
|
175
|
+
NEOTOKYO_ARCADE_P, NEOTOKYO_HAX_P, NEOTOKYO_P, NEOTOKYO_STANDARD_P, NEOTOKYO_TOON_P, OUTLAW_OASIS_P, OUTLAW_P,
|
|
176
|
+
PARK_BMAN_P, PARK_NIGHT_P, PARK_P, PARK_RAINY_P, PARK_SNOWY_P, SHATTERSHOT_P, STADIUM_10A_P, STADIUM_DAY_P,
|
|
177
|
+
STADIUM_FOGGY_P, STADIUM_P, STADIUM_RACE_DAY_P, STADIUM_WINTER_P, STREET_P, SWOOSH_P, THROWBACKHOCKEY_P,
|
|
178
|
+
THROWBACKSTADIUM_P, TRAINSTATION_DAWN_P, TRAINSTATION_NIGHT_P, TRAINSTATION_P, TRAINSTATION_SPOOKY_P, UF_DAY_P,
|
|
179
|
+
UNDERWATER_GRS_P, UNDERWATER_P, UTOPIASTADIUM_DUSK_P, UTOPIASTADIUM_LUX_P, UTOPIASTADIUM_P,
|
|
180
|
+
UTOPIASTADIUM_SNOW_P, WASTELAND_GRS_P, WASTELAND_NIGHT_P, WASTELAND_NIGHT_S_P, WASTELAND_P, WASTELAND_S_P,
|
|
181
|
+
WOODS_NIGHT_P, WOODS_P
|
|
165
182
|
) = _get_literals(AnyMap)
|
|
166
183
|
NAMES = (
|
|
167
184
|
"Starbase ARC (Aftermath)", "Starbase ARC", "Starbase ARC (Standard)", "Champions Field (NFL)",
|
|
@@ -170,33 +187,37 @@ class Map:
|
|
|
170
187
|
"Mannfield (Dusk)", "Mannfield (Night)", "Mannfield", "Mannfield (Stormy)", "Mannfield (Snowy)",
|
|
171
188
|
"Farmstead (Pitched)", "Farmstead (Spooky)", "Farmstead (Night)", "Farmstead", "Farmstead (The Upside Down)",
|
|
172
189
|
"Estadio Vida (Dusk)", "Forbidden Temple (Fire & Ice)", "Urban Central (Haunted)", "Dunk House",
|
|
173
|
-
"The Block (Dusk)", "
|
|
174
|
-
"
|
|
190
|
+
"The Block (Dusk)", "Calavera", "Carbon", "Quadron", "Basin", "Pillars", "Corridor", "Cosmic", "Cosmic",
|
|
191
|
+
"Double Goal", "Double Goal", "Galleon Retro", "Galleon", "Loophole", "Holyfield", "Octagon", "Octagon",
|
|
192
|
+
"Hourglass", "Barricade", "Colossus", "Underpass", "Underpass", "Utopia Retro", "Neon Fields",
|
|
175
193
|
"Neo Tokyo (Arcade)", "Neo Tokyo (Hacked)", "Neo Tokyo", "Neo Tokyo (Standard)", "Neo Tokyo (Comic)",
|
|
176
194
|
"Deadeye Canyon (Oasis)", "Deadeye Canyon", "Beckwith Park (Night)", "Beckwith Park (Midnight)",
|
|
177
|
-
"Beckwith Park", "Beckwith Park (Stormy)", "Beckwith Park (Snowy)", "Core 707",
|
|
178
|
-
"DFH Stadium (
|
|
179
|
-
"
|
|
180
|
-
"
|
|
195
|
+
"Beckwith Park", "Beckwith Park (Stormy)", "Beckwith Park (Snowy)", "Core 707",
|
|
196
|
+
"DFH Stadium (10th Anniversary)", "DFH Stadium (Day)", "DFH Stadium (Stormy)", "DFH Stadium",
|
|
197
|
+
"DFH Stadium (Circuit)", "DFH Stadium (Snowy)", "Sovereign Heights (Dusk)", "Champions Field (Nike FC)",
|
|
198
|
+
"Throwback Stadium (Snowy)", "Throwback Stadium", "Urban Central (Dawn)", "Urban Central (Night)",
|
|
199
|
+
"Urban Central", "Urban Central (Spooky)", "Futura Garden", "AquaDome (Salty Shallows)", "Aquadome",
|
|
181
200
|
"Utopia Coliseum (Dusk)", "Utopia Coliseum (Gilded)", "Utopia Coliseum", "Utopia Coliseum (Snowy)",
|
|
182
201
|
"Wasteland (Pitched)", "Wasteland (Night)", "Wasteland (Standard, Night)", "Wasteland", "Wasteland (Standard)",
|
|
183
|
-
"Drift Woods (Night", "Drift Woods"
|
|
202
|
+
"Drift Woods (Night)", "Drift Woods"
|
|
184
203
|
)
|
|
185
204
|
CODE_TO_NAME = {code: name for code, name in zip(ALL, NAMES)}
|
|
186
205
|
STANDARD_MAPS = (
|
|
187
|
-
ARC_DARC_P, ARC_STANDARD_P, BEACH_NIGHT_GRS_P, BEACH_NIGHT_P, CHN_STADIUM_DAY_P, CHN_STADIUM_P,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
PARK_SNOWY_P, STADIUM_DAY_P, STADIUM_FOGGY_P, STADIUM_P, STADIUM_RACE_DAY_P,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
WASTELAND_NIGHT_S_P,
|
|
206
|
+
ARC_DARC_P, ARC_STANDARD_P, BEACH_NIGHT_GRS_P, BEACH_NIGHT_P, BEACH_P, CHN_STADIUM_DAY_P, CHN_STADIUM_P,
|
|
207
|
+
CS_DAY_P, CS_HW_P, CS_P, EUROSTADIUM_DUSK_P, EUROSTADIUM_NIGHT_P, EUROSTADIUM_P, EUROSTADIUM_RAINY_P,
|
|
208
|
+
EUROSTADIUM_SNOWNIGHT_P, FARM_GRS_P, FARM_NIGHT_P, FARM_P, FARM_UPSIDEDOWN_P, FF_DUSK_P, FNI_STADIUM_P, MUSIC_P,
|
|
209
|
+
NEOTOKYO_ARCADE_P, NEOTOKYO_HAX_P, NEOTOKYO_STANDARD_P, OUTLAW_OASIS_P, OUTLAW_P, PARK_NIGHT_P, PARK_P,
|
|
210
|
+
PARK_RAINY_P, PARK_SNOWY_P, STADIUM_10A_P, STADIUM_DAY_P, STADIUM_FOGGY_P, STADIUM_P, STADIUM_RACE_DAY_P,
|
|
211
|
+
STADIUM_WINTER_P, STREET_P, TRAINSTATION_DAWN_P, TRAINSTATION_NIGHT_P, TRAINSTATION_P, UF_DAY_P,
|
|
212
|
+
UNDERWATER_GRS_P, UNDERWATER_P, UTOPIASTADIUM_DUSK_P, UTOPIASTADIUM_LUX_P, UTOPIASTADIUM_P,
|
|
213
|
+
UTOPIASTADIUM_SNOW_P, WASTELAND_GRS_P, WASTELAND_NIGHT_P, WASTELAND_NIGHT_S_P, WASTELAND_P, WASTELAND_S_P,
|
|
214
|
+
WOODS_NIGHT_P, WOODS_P
|
|
195
215
|
)
|
|
196
216
|
NON_STANDARD_MAPS = (
|
|
197
|
-
ARC_P, BB_P,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
217
|
+
ARC_P, BB_P, BEACHVOLLEY, FARM_HW_P, HAUNTED_TRAINSTATION_P, HOOPSSTADIUM_P, HOOPSSTREET_P, KO_CALAVERA_P,
|
|
218
|
+
KO_CARBON_P, KO_QUADRON_P, LABS_BASIN_P, LABS_CIRCLEPILLARS_P, LABS_CORRIDOR_P, LABS_COSMIC_P, LABS_COSMIC_V4_P,
|
|
219
|
+
LABS_DOUBLEGOAL_P, LABS_DOUBLEGOAL_V2_P, LABS_GALLEON_MAST_P, LABS_GALLEON_P, LABS_HOLYFIELD_P,
|
|
220
|
+
LABS_HOLYFIELD_SPACE_P, LABS_OCTAGON_02_P, LABS_OCTAGON_P, LABS_PILLARGLASS_P, LABS_PILLARHEAT_P,
|
|
221
|
+
LABS_PILLARWINGS_P, LABS_UNDERPASS_P, LABS_UNDERPASS_V0_P, LABS_UTOPIA_P, NEOTOKYO_P, NEOTOKYO_TOON_P,
|
|
222
|
+
PARK_BMAN_P, SHATTERSHOT_P, SWOOSH_P, THROWBACKHOCKEY_P, THROWBACKSTADIUM_P, TRAINSTATION_SPOOKY_P
|
|
202
223
|
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-ballchasing
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A Python wrapper around the Ballchasing API
|
|
5
|
+
Author-email: Rolv-Arild Braaten <rolv_arild@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Project-URL: Homepage, https://github.com/Rolv-Arild/python-ballchasing
|
|
8
|
+
Project-URL: Download, https://pypi.python.org/pypi/python-ballchasing
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# Python Ballchasing
|
|
19
|
+
An easy-to-use and comprehensive Python wrapper for the [ballchasing.com API](https://ballchasing.com/doc/api).
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
You can install the library from PyPI using pip:
|
|
23
|
+
```
|
|
24
|
+
pip install python-ballchasing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
Before you can use the library, you need an API authentication key from ballchasing.com.
|
|
29
|
+
1. Log in to [ballchasing.com](https://ballchasing.com/).
|
|
30
|
+
2. Navigate to the Upload tab.
|
|
31
|
+
3. Create an API key and copy it.
|
|
32
|
+
|
|
33
|
+
**Keep your API key secure and do not share it publicly.**
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
For detailed information, please refer to the docs inside the code. For the most part it follows the API spec closely, but there are some differences.
|
|
37
|
+
|
|
38
|
+
The API is exposed via the `BallchasingApi` class.
|
|
39
|
+
|
|
40
|
+
Making the client:
|
|
41
|
+
```python
|
|
42
|
+
from ballchasing import BallchasingApi
|
|
43
|
+
api = BallchasingApi("Your token here")
|
|
44
|
+
```
|
|
45
|
+
or equivalently
|
|
46
|
+
```python
|
|
47
|
+
import ballchasing
|
|
48
|
+
api = ballchasing.Api("Your token here")
|
|
49
|
+
```
|
|
50
|
+
By default this will also ping the API to make sure it's working.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
Some simple examples:
|
|
54
|
+
```python
|
|
55
|
+
# Get lots of SSL replays
|
|
56
|
+
|
|
57
|
+
from ballchasing import Rank # there's also Playlist, Season, Map, and more
|
|
58
|
+
|
|
59
|
+
replays = api.get_replays(
|
|
60
|
+
min_rank=Rank.SUPERSONIC_LEGEND,
|
|
61
|
+
count=10_000 # The API limits you to 200 replays per request but the library handles this for you
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
for replay in replays: # (replays is an iterable so you don't need to wait for all the replays to be collected)
|
|
65
|
+
... # Do something with the replays
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Get a specific replay with more detail than the iterator (including stats!)
|
|
70
|
+
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
# Get groups by the "RLCS Referee" account
|
|
75
|
+
groups = api.get_groups(creator="76561199225615730")
|
|
76
|
+
|
|
77
|
+
for group in groups:
|
|
78
|
+
# Download the group
|
|
79
|
+
api.download_group(
|
|
80
|
+
group_id=group["id"],
|
|
81
|
+
folder="/path/to/destination/"
|
|
82
|
+
recursive=True, # To download all the replays and retain the group structure with subfolders
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Get replays from the group
|
|
86
|
+
replays = get_group_replays(
|
|
87
|
+
group_id=group["id"],
|
|
88
|
+
deep=True, # To get detailed replay info
|
|
89
|
+
)
|
|
90
|
+
for replay in replays:
|
|
91
|
+
api.download_replay(replay_id=replay["id"], folder="/path/to/destination/") # You could also download like this
|
|
92
|
+
```
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: python-ballchasing
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: A Python wrapper around the Ballchasing API
|
|
5
|
-
Author-email: Rolv-Arild Braaten <rolv_arild@hotmail.com>
|
|
6
|
-
License: MIT License
|
|
7
|
-
Project-URL: Homepage, https://github.com/Rolv-Arild/python-ballchasing
|
|
8
|
-
Project-URL: Download, https://pypi.python.org/pypi/python-ballchasing
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.9
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: requests
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
# Python Ballchasing
|
|
19
|
-
Python wrapper for the ballchasing.com API.
|
|
20
|
-
|
|
21
|
-
# Installation
|
|
22
|
-
```
|
|
23
|
-
pip install python-ballchasing
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
# API
|
|
27
|
-
The API is exposed via the `ballchasing.Api` class.
|
|
28
|
-
|
|
29
|
-
Simple example:
|
|
30
|
-
```python
|
|
31
|
-
import ballchasing
|
|
32
|
-
api = ballchasing.Api("Your token here")
|
|
33
|
-
|
|
34
|
-
# Get a specific replay
|
|
35
|
-
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
36
|
-
```
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Python Ballchasing
|
|
2
|
-
Python wrapper for the ballchasing.com API.
|
|
3
|
-
|
|
4
|
-
# Installation
|
|
5
|
-
```
|
|
6
|
-
pip install python-ballchasing
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
# API
|
|
10
|
-
The API is exposed via the `ballchasing.Api` class.
|
|
11
|
-
|
|
12
|
-
Simple example:
|
|
13
|
-
```python
|
|
14
|
-
import ballchasing
|
|
15
|
-
api = ballchasing.Api("Your token here")
|
|
16
|
-
|
|
17
|
-
# Get a specific replay
|
|
18
|
-
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
19
|
-
```
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: python-ballchasing
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: A Python wrapper around the Ballchasing API
|
|
5
|
-
Author-email: Rolv-Arild Braaten <rolv_arild@hotmail.com>
|
|
6
|
-
License: MIT License
|
|
7
|
-
Project-URL: Homepage, https://github.com/Rolv-Arild/python-ballchasing
|
|
8
|
-
Project-URL: Download, https://pypi.python.org/pypi/python-ballchasing
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.9
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: requests
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
|
-
# Python Ballchasing
|
|
19
|
-
Python wrapper for the ballchasing.com API.
|
|
20
|
-
|
|
21
|
-
# Installation
|
|
22
|
-
```
|
|
23
|
-
pip install python-ballchasing
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
# API
|
|
27
|
-
The API is exposed via the `ballchasing.Api` class.
|
|
28
|
-
|
|
29
|
-
Simple example:
|
|
30
|
-
```python
|
|
31
|
-
import ballchasing
|
|
32
|
-
api = ballchasing.Api("Your token here")
|
|
33
|
-
|
|
34
|
-
# Get a specific replay
|
|
35
|
-
replay = api.get_replay("2627e02a-aa46-4e13-b66b-b76a32069a07")
|
|
36
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/requires.txt
RENAMED
|
File without changes
|
{python_ballchasing-0.2.0 → python_ballchasing-0.3.0}/python_ballchasing.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|