infinitode.py 1.2.0__tar.gz → 1.2.1__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.
Files changed (20) hide show
  1. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/PKG-INFO +10 -1
  2. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/README.md +255 -246
  3. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/__init__.py +40 -39
  4. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/core.py +668 -634
  5. infinitode_py-1.2.1/infinitode/daily_quest.py +27 -0
  6. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/errors.py +39 -39
  7. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode.py.egg-info/PKG-INFO +10 -1
  8. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode.py.egg-info/SOURCES.txt +1 -0
  9. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/tests/test_core.py +71 -0
  10. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/badge.py +0 -0
  11. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/leaderboard.py +0 -0
  12. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/player.py +0 -0
  13. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/py.typed +0 -0
  14. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/score.py +0 -0
  15. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode/utils.py +0 -0
  16. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode.py.egg-info/dependency_links.txt +0 -0
  17. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode.py.egg-info/requires.txt +0 -0
  18. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/infinitode.py.egg-info/top_level.txt +0 -0
  19. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/setup.cfg +0 -0
  20. {infinitode_py-1.2.0 → infinitode_py-1.2.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: infinitode.py
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: A python wrapper for the Infinitode 2 API.
5
5
  Home-page: https://github.com/Sprylos/infinitode.py
6
6
  Author: Sprylos
@@ -126,6 +126,15 @@ Retrieve the top 200 players of today's daily quest or a specified date.
126
126
  dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
127
127
  ```
128
128
 
129
+ Retrieve metadata for the currently active Daily Quest. The reset timestamp is
130
+ also available as `reset_timestamp`, and `mapname` is derived from `quest_id`.
131
+
132
+ ```python
133
+ dq = await API.daily_quest_info()
134
+ print(dq.date, dq.quest_id, dq.mapname)
135
+ print(dq.end_timestamp, dq.reset_timestamp, dq.data_hash)
136
+ ```
137
+
129
138
  ---
130
139
 
131
140
  ### Working with Leaderboards
@@ -1,246 +1,255 @@
1
- # Infinitode.py
2
-
3
- An asynchronous Python wrapper for the Infinitode-2 API using `async`-`await` syntax.
4
-
5
- ---
6
-
7
- ## Installation
8
-
9
- Install the library via pip:
10
-
11
- ```bash
12
- pip install infinitode.py
13
- ```
14
-
15
- ---
16
-
17
- ## Showcase
18
-
19
- ### Setting Up a Session
20
-
21
- Create a session to communicate with Rainy's API. Use the `with` statement to ensure the session closes properly.
22
- Alternatively you can can simply call `Session.close()` once you don't need it anymore.
23
-
24
- ```python
25
- import asyncio
26
- import infinitode
27
-
28
- async def main():
29
- async with infinitode.Session() as API:
30
- # Your API calls go here
31
- pass
32
-
33
- asyncio.run(main())
34
- ```
35
-
36
- ---
37
-
38
- ### Fetching Leaderboard Data
39
-
40
- Parameters:
41
- - `mapname`: The map identifier (e.g., "5.1" or "4.b1" or "zecred").
42
- - `playerid` (sometimes optional): The player's unique identifier.
43
- - `mode` (optional): One of `'score'`, `'waves'`. Defaults to `'score'`.
44
- - `difficulty` (optional): One of `'EASY'`, `'NORMAL'`, `'ENDLESS_I'`. Defaults to `'NORMAL'`.
45
-
46
- The immutable `infinitode.SUPPORTED_MAPS`, `infinitode.SUPPORTED_MODES`, and
47
- `infinitode.SUPPORTED_DIFFICULTIES` tuples contain the values accepted by the
48
- current library. `infinitode.GAME_API_VERSION` exposes the game API version used
49
- for JSON API calls.
50
-
51
- #### Player Score on a Specific Map
52
-
53
- Retrieve the score of a specific player on a particular map.
54
-
55
- ```python
56
- score_5_1 = await API.leaderboards_rank(
57
- mapname="5.1",
58
- playerid="U-E9BP-FSN9-H6ENMQ",
59
- mode="score",
60
- difficulty="NORMAL"
61
- )
62
- ```
63
-
64
- #### Top 200 Leaderboard on a Specific Map
65
-
66
- Retrieve the leaderboard of the top 200 wave scores on 5.1.
67
-
68
- ```python
69
- leaderboard_5_1 = await API.leaderboards(
70
- mapname=5.1,
71
- mode="waves"
72
- )
73
- ```
74
-
75
- #### Runtime Leaderboard
76
-
77
- Fetch the leaderboard displayed during gameplay. This provides additional percentile information.
78
-
79
- ```python
80
- runtime_5_1 = await API.runtime_leaderboards(
81
- mapname=5.1,
82
- playerid="U-E9BP-FSN9-H6ENMQ",
83
- difficulty="ENDLESS_I"
84
- )
85
- ```
86
-
87
- ---
88
-
89
- #### Skill Point Leaderboard
90
-
91
- Get the top 3 skill point owners. Optionally specify a `playerid`.
92
-
93
- ```python
94
- sp_leaderboard = await API.skill_point_leaderboard(
95
- playerid="U-E9BP-FSN9-H6ENMQ"
96
- )
97
- ```
98
-
99
-
100
- #### Daily Quest Leaderboard
101
-
102
- Retrieve the top 200 players of today's daily quest or a specified date.
103
-
104
- - `date`: `YYYY-MM-DD` (string) or `datetime.datetime`.
105
-
106
- ```python
107
- dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
108
- ```
109
-
110
- ---
111
-
112
- ### Working with Leaderboards
113
-
114
- A leaderboard is a sequence of scores with additional utility functions.
115
-
116
- #### Access Score and Leaderboard Attributes
117
-
118
- Leaderboards always have these attributes:
119
- - `mapname`, `mode`, `difficulty`, `total`
120
-
121
- And optionally these:
122
- - `date`, `season`, `player` (will return a score object)
123
-
124
- Scores always have these attributes:
125
- - `playerid`, `rank`, `score`, `mapname`, `mode`, `difficulty`
126
-
127
- And optionally these:
128
- - `has_pfp`, `level`, `nickname`, `pinned_badge`, `position`, `top`, `total`, `player` (will return a Player object if fetched beforehand)
129
-
130
- #### Example for printing attributes, scores, and leaderboards
131
-
132
- ```python
133
- for score in leaderboard_5_1:
134
- print(score.nickname)
135
- score.print_score() # Helper method
136
-
137
- leaderboard_5_1.print_scores()
138
- ```
139
-
140
- #### Slice a Leaderboard
141
-
142
- Retrieve a subset of the leaderboard:
143
-
144
- ```python
145
- top_1 = leaderboard_5_1[0]
146
- top_10 = leaderboard_5_1[0:10]
147
- print(len(top_10))
148
- ```
149
-
150
- ---
151
-
152
- ### Player Information
153
-
154
- #### Fetch Player Data
155
-
156
- Retrieve detailed player information.
157
-
158
- ```python
159
- player = await API.player(playerid="U-E9BP-FSN9-H6ENMQ")
160
- # Or look up a case-insensitive, exact nickname:
161
- player = await API.player(nickname="EuphoRowan")
162
- ```
163
-
164
- Attributes include:
165
- - `playerid`, `nickname`, `level`, `xp`, `season_level`, `total_score`, and many more.
166
-
167
- #### Get Player Scores
168
-
169
- Use the `score` method to access specific map scores.
170
-
171
- ```python
172
- player.score(5.1).print_score()
173
- ```
174
-
175
- #### Fetch Daily Quest and Skill Point Scores
176
-
177
- Use additional API calls to retrieve daily quest and skill point scores:
178
-
179
- ```python
180
- await player.fetch_daily_quest(API)
181
- await player.fetch_skill_point(API)
182
-
183
- print(player.daily_quest.rank, player.skill_point.score)
184
- ```
185
-
186
- An invalid argument raises `infinitode.errors.BadArgument`, and an exact lookup
187
- with no matching player raises its `PlayerNotFound` subclass. HTTP and JSON API
188
- failures raise `APIError`; unexpected changes to parsed HTML raise `ParseError`.
189
-
190
- ---
191
-
192
- ### Experimental features
193
-
194
- `Session.search_players()` performs an unauthenticated, case-insensitive
195
- substring search of player nicknames:
196
-
197
- ```python
198
- players = await API.search_players("eupho", limit=20)
199
- for result in players:
200
- print(result.playerid, result.nickname, result.level, result.has_avatar)
201
- ```
202
-
203
- Each `PlayerSummary` contains only the verified `playerid`, `nickname`, `level`,
204
- and `has_avatar` fields. The upstream page returns at most 100 results and does
205
- not offer pagination. This feature parses an HTML page rather than a stable JSON
206
- API, so upstream markup changes may cause `ParseError` until the parser is
207
- updated.
208
-
209
- ---
210
-
211
- ### Beta Scores
212
-
213
- Almost all API calls support an additional `beta` boolean parameter. This will make a request to the beta servers instead. No guarantees for it working.
214
-
215
- ```python
216
- leaderboard_5_1 = await API.leaderboards(mapname=5.1, mode='waves', beta=True)
217
- ```
218
-
219
-
220
- ### Logging
221
-
222
- Set up logging to monitor requests and responses.
223
-
224
- - `INFO`: Logs every request.
225
- - `DEBUG`: Logs server responses.
226
-
227
- ```python
228
- import infinitode
229
- import asyncio
230
- import logging
231
-
232
- logging.basicConfig(level=logging.INFO)
233
-
234
- async def main():
235
- async with infinitode.Session() as API:
236
- await API.leaderboards("6.3")
237
-
238
- asyncio.run(main())
239
- ```
240
-
241
- ---
242
-
243
- ### Notes
244
-
245
- - Some data (e.g., seasonal leaderboard, players) require additional parsing and will take longer to process.
246
- - Do not abuse this API wrapper for any kind of malicious action.
1
+ # Infinitode.py
2
+
3
+ An asynchronous Python wrapper for the Infinitode-2 API using `async`-`await` syntax.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ Install the library via pip:
10
+
11
+ ```bash
12
+ pip install infinitode.py
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Showcase
18
+
19
+ ### Setting Up a Session
20
+
21
+ Create a session to communicate with Rainy's API. Use the `with` statement to ensure the session closes properly.
22
+ Alternatively you can can simply call `Session.close()` once you don't need it anymore.
23
+
24
+ ```python
25
+ import asyncio
26
+ import infinitode
27
+
28
+ async def main():
29
+ async with infinitode.Session() as API:
30
+ # Your API calls go here
31
+ pass
32
+
33
+ asyncio.run(main())
34
+ ```
35
+
36
+ ---
37
+
38
+ ### Fetching Leaderboard Data
39
+
40
+ Parameters:
41
+ - `mapname`: The map identifier (e.g., "5.1" or "4.b1" or "zecred").
42
+ - `playerid` (sometimes optional): The player's unique identifier.
43
+ - `mode` (optional): One of `'score'`, `'waves'`. Defaults to `'score'`.
44
+ - `difficulty` (optional): One of `'EASY'`, `'NORMAL'`, `'ENDLESS_I'`. Defaults to `'NORMAL'`.
45
+
46
+ The immutable `infinitode.SUPPORTED_MAPS`, `infinitode.SUPPORTED_MODES`, and
47
+ `infinitode.SUPPORTED_DIFFICULTIES` tuples contain the values accepted by the
48
+ current library. `infinitode.GAME_API_VERSION` exposes the game API version used
49
+ for JSON API calls.
50
+
51
+ #### Player Score on a Specific Map
52
+
53
+ Retrieve the score of a specific player on a particular map.
54
+
55
+ ```python
56
+ score_5_1 = await API.leaderboards_rank(
57
+ mapname="5.1",
58
+ playerid="U-E9BP-FSN9-H6ENMQ",
59
+ mode="score",
60
+ difficulty="NORMAL"
61
+ )
62
+ ```
63
+
64
+ #### Top 200 Leaderboard on a Specific Map
65
+
66
+ Retrieve the leaderboard of the top 200 wave scores on 5.1.
67
+
68
+ ```python
69
+ leaderboard_5_1 = await API.leaderboards(
70
+ mapname=5.1,
71
+ mode="waves"
72
+ )
73
+ ```
74
+
75
+ #### Runtime Leaderboard
76
+
77
+ Fetch the leaderboard displayed during gameplay. This provides additional percentile information.
78
+
79
+ ```python
80
+ runtime_5_1 = await API.runtime_leaderboards(
81
+ mapname=5.1,
82
+ playerid="U-E9BP-FSN9-H6ENMQ",
83
+ difficulty="ENDLESS_I"
84
+ )
85
+ ```
86
+
87
+ ---
88
+
89
+ #### Skill Point Leaderboard
90
+
91
+ Get the top 3 skill point owners. Optionally specify a `playerid`.
92
+
93
+ ```python
94
+ sp_leaderboard = await API.skill_point_leaderboard(
95
+ playerid="U-E9BP-FSN9-H6ENMQ"
96
+ )
97
+ ```
98
+
99
+
100
+ #### Daily Quest Leaderboard
101
+
102
+ Retrieve the top 200 players of today's daily quest or a specified date.
103
+
104
+ - `date`: `YYYY-MM-DD` (string) or `datetime.datetime`.
105
+
106
+ ```python
107
+ dq_leaderboard = await API.daily_quest_leaderboards("2024-12-05")
108
+ ```
109
+
110
+ Retrieve metadata for the currently active Daily Quest. The reset timestamp is
111
+ also available as `reset_timestamp`, and `mapname` is derived from `quest_id`.
112
+
113
+ ```python
114
+ dq = await API.daily_quest_info()
115
+ print(dq.date, dq.quest_id, dq.mapname)
116
+ print(dq.end_timestamp, dq.reset_timestamp, dq.data_hash)
117
+ ```
118
+
119
+ ---
120
+
121
+ ### Working with Leaderboards
122
+
123
+ A leaderboard is a sequence of scores with additional utility functions.
124
+
125
+ #### Access Score and Leaderboard Attributes
126
+
127
+ Leaderboards always have these attributes:
128
+ - `mapname`, `mode`, `difficulty`, `total`
129
+
130
+ And optionally these:
131
+ - `date`, `season`, `player` (will return a score object)
132
+
133
+ Scores always have these attributes:
134
+ - `playerid`, `rank`, `score`, `mapname`, `mode`, `difficulty`
135
+
136
+ And optionally these:
137
+ - `has_pfp`, `level`, `nickname`, `pinned_badge`, `position`, `top`, `total`, `player` (will return a Player object if fetched beforehand)
138
+
139
+ #### Example for printing attributes, scores, and leaderboards
140
+
141
+ ```python
142
+ for score in leaderboard_5_1:
143
+ print(score.nickname)
144
+ score.print_score() # Helper method
145
+
146
+ leaderboard_5_1.print_scores()
147
+ ```
148
+
149
+ #### Slice a Leaderboard
150
+
151
+ Retrieve a subset of the leaderboard:
152
+
153
+ ```python
154
+ top_1 = leaderboard_5_1[0]
155
+ top_10 = leaderboard_5_1[0:10]
156
+ print(len(top_10))
157
+ ```
158
+
159
+ ---
160
+
161
+ ### Player Information
162
+
163
+ #### Fetch Player Data
164
+
165
+ Retrieve detailed player information.
166
+
167
+ ```python
168
+ player = await API.player(playerid="U-E9BP-FSN9-H6ENMQ")
169
+ # Or look up a case-insensitive, exact nickname:
170
+ player = await API.player(nickname="EuphoRowan")
171
+ ```
172
+
173
+ Attributes include:
174
+ - `playerid`, `nickname`, `level`, `xp`, `season_level`, `total_score`, and many more.
175
+
176
+ #### Get Player Scores
177
+
178
+ Use the `score` method to access specific map scores.
179
+
180
+ ```python
181
+ player.score(5.1).print_score()
182
+ ```
183
+
184
+ #### Fetch Daily Quest and Skill Point Scores
185
+
186
+ Use additional API calls to retrieve daily quest and skill point scores:
187
+
188
+ ```python
189
+ await player.fetch_daily_quest(API)
190
+ await player.fetch_skill_point(API)
191
+
192
+ print(player.daily_quest.rank, player.skill_point.score)
193
+ ```
194
+
195
+ An invalid argument raises `infinitode.errors.BadArgument`, and an exact lookup
196
+ with no matching player raises its `PlayerNotFound` subclass. HTTP and JSON API
197
+ failures raise `APIError`; unexpected changes to parsed HTML raise `ParseError`.
198
+
199
+ ---
200
+
201
+ ### Experimental features
202
+
203
+ `Session.search_players()` performs an unauthenticated, case-insensitive
204
+ substring search of player nicknames:
205
+
206
+ ```python
207
+ players = await API.search_players("eupho", limit=20)
208
+ for result in players:
209
+ print(result.playerid, result.nickname, result.level, result.has_avatar)
210
+ ```
211
+
212
+ Each `PlayerSummary` contains only the verified `playerid`, `nickname`, `level`,
213
+ and `has_avatar` fields. The upstream page returns at most 100 results and does
214
+ not offer pagination. This feature parses an HTML page rather than a stable JSON
215
+ API, so upstream markup changes may cause `ParseError` until the parser is
216
+ updated.
217
+
218
+ ---
219
+
220
+ ### Beta Scores
221
+
222
+ Almost all API calls support an additional `beta` boolean parameter. This will make a request to the beta servers instead. No guarantees for it working.
223
+
224
+ ```python
225
+ leaderboard_5_1 = await API.leaderboards(mapname=5.1, mode='waves', beta=True)
226
+ ```
227
+
228
+
229
+ ### Logging
230
+
231
+ Set up logging to monitor requests and responses.
232
+
233
+ - `INFO`: Logs every request.
234
+ - `DEBUG`: Logs server responses.
235
+
236
+ ```python
237
+ import infinitode
238
+ import asyncio
239
+ import logging
240
+
241
+ logging.basicConfig(level=logging.INFO)
242
+
243
+ async def main():
244
+ async with infinitode.Session() as API:
245
+ await API.leaderboards("6.3")
246
+
247
+ asyncio.run(main())
248
+ ```
249
+
250
+ ---
251
+
252
+ ### Notes
253
+
254
+ - Some data (e.g., seasonal leaderboard, players) require additional parsing and will take longer to process.
255
+ - Do not abuse this API wrapper for any kind of malicious action.
@@ -1,39 +1,40 @@
1
- """
2
- Infinitode API Wrapper
3
- ~~~~~~~~~~~~~~~~~~~
4
-
5
- An asynchronous wrapper for the Infinitode API.
6
- """
7
-
8
- __author__ = "Sprylos"
9
- __title__ = "infinitode.py"
10
- __version__ = "1.2.0"
11
- __license__ = """MIT License
12
-
13
- Copyright (c) 2026 Sprylos
14
-
15
- Permission is hereby granted, free of charge, to any person obtaining a copy
16
- of this software and associated documentation files (the "Software"), to deal
17
- in the Software without restriction, including without limitation the rights
18
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
- copies of the Software, and to permit persons to whom the Software is
20
- furnished to do so, subject to the following conditions:
21
-
22
- The above copyright notice and this permission notice shall be included in all
23
- copies or substantial portions of the Software.
24
-
25
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
- SOFTWARE."""
32
-
33
- from .badge import *
34
- from .core import *
35
- from .leaderboard import *
36
- from .player import *
37
- from .score import *
38
- from . import errors as errors
39
- from . import utils as utils
1
+ """
2
+ Infinitode API Wrapper
3
+ ~~~~~~~~~~~~~~~~~~~
4
+
5
+ An asynchronous wrapper for the Infinitode API.
6
+ """
7
+
8
+ __author__ = "Sprylos"
9
+ __title__ = "infinitode.py"
10
+ __version__ = "1.2.1"
11
+ __license__ = """MIT License
12
+
13
+ Copyright (c) 2026 Sprylos
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE."""
32
+
33
+ from .badge import *
34
+ from .core import *
35
+ from .daily_quest import *
36
+ from .leaderboard import *
37
+ from .player import *
38
+ from .score import *
39
+ from . import errors as errors
40
+ from . import utils as utils