roterminal 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.
- roterminal-0.1.0/LICENSE +9 -0
- roterminal-0.1.0/PKG-INFO +45 -0
- roterminal-0.1.0/README.md +27 -0
- roterminal-0.1.0/pyproject.toml +29 -0
- roterminal-0.1.0/roterminal/__init__.py +268 -0
- roterminal-0.1.0/roterminal/py.typed +0 -0
- roterminal-0.1.0/roterminal.egg-info/PKG-INFO +45 -0
- roterminal-0.1.0/roterminal.egg-info/SOURCES.txt +9 -0
- roterminal-0.1.0/roterminal.egg-info/dependency_links.txt +1 -0
- roterminal-0.1.0/roterminal.egg-info/top_level.txt +1 -0
- roterminal-0.1.0/setup.cfg +4 -0
roterminal-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pixel Board Services Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roterminal
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Live data on every Roblox game: players now, history, rising games, trends and developers. The RoTerminal API for Python.
|
|
5
|
+
Author: RoTerminal
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://roterminal.co/docs/sdks
|
|
8
|
+
Project-URL: Documentation, https://roterminal.co/docs/api
|
|
9
|
+
Project-URL: Changelog, https://roterminal.co/docs/changelog
|
|
10
|
+
Keywords: roblox,roblox-api,analytics,sdk,roterminal
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# roterminal
|
|
20
|
+
|
|
21
|
+
Live data on every Roblox game, for Python: players right now, each game's history since Sep 27, 2026, rising games, trends, genres, Roblox's charts and the developers behind each game.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
pip install roterminal
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from roterminal import RoTerminal
|
|
29
|
+
|
|
30
|
+
rt = RoTerminal() # reads ROTERMINAL_API_KEY
|
|
31
|
+
|
|
32
|
+
game = rt.games.retrieve("grow a garden")["data"]
|
|
33
|
+
print(game["name"], game["playing_now"])
|
|
34
|
+
|
|
35
|
+
for g in rt.games.rising(range="7d", limit=5)["data"]["games"]:
|
|
36
|
+
print(g["name"], g["change"])
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The key is optional: without one you get 50 calls a day for each address. Create a free key at https://roterminal.co/account/developer.
|
|
40
|
+
|
|
41
|
+
Errors raise `roterminal.RoTerminalError` with `code`, `status` and `request_id`.
|
|
42
|
+
|
|
43
|
+
Every endpoint: https://roterminal.co/docs/api
|
|
44
|
+
|
|
45
|
+
Version 0.1.0. MIT licence.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# roterminal
|
|
2
|
+
|
|
3
|
+
Live data on every Roblox game, for Python: players right now, each game's history since Sep 27, 2026, rising games, trends, genres, Roblox's charts and the developers behind each game.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
pip install roterminal
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from roterminal import RoTerminal
|
|
11
|
+
|
|
12
|
+
rt = RoTerminal() # reads ROTERMINAL_API_KEY
|
|
13
|
+
|
|
14
|
+
game = rt.games.retrieve("grow a garden")["data"]
|
|
15
|
+
print(game["name"], game["playing_now"])
|
|
16
|
+
|
|
17
|
+
for g in rt.games.rising(range="7d", limit=5)["data"]["games"]:
|
|
18
|
+
print(g["name"], g["change"])
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The key is optional: without one you get 50 calls a day for each address. Create a free key at https://roterminal.co/account/developer.
|
|
22
|
+
|
|
23
|
+
Errors raise `roterminal.RoTerminalError` with `code`, `status` and `request_id`.
|
|
24
|
+
|
|
25
|
+
Every endpoint: https://roterminal.co/docs/api
|
|
26
|
+
|
|
27
|
+
Version 0.1.0. MIT licence.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "roterminal"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Live data on every Roblox game: players now, history, rising games, trends and developers. The RoTerminal API for Python."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "RoTerminal" }]
|
|
13
|
+
keywords = ["roblox", "roblox-api", "analytics", "sdk", "roterminal"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
"Typing :: Typed",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://roterminal.co/docs/sdks"
|
|
22
|
+
Documentation = "https://roterminal.co/docs/api"
|
|
23
|
+
Changelog = "https://roterminal.co/docs/changelog"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools]
|
|
26
|
+
packages = ["roterminal"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
roterminal = ["py.typed"]
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""RoTerminal: live data on every Roblox game.
|
|
2
|
+
|
|
3
|
+
Docs: https://roterminal.co/docs/sdks · Every endpoint: https://roterminal.co/docs/api
|
|
4
|
+
|
|
5
|
+
from roterminal import RoTerminal
|
|
6
|
+
|
|
7
|
+
rt = RoTerminal() # reads ROTERMINAL_API_KEY
|
|
8
|
+
game = rt.games.retrieve("grow a garden")["data"]
|
|
9
|
+
print(game["name"], game["playing_now"])
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import time
|
|
17
|
+
import urllib.error
|
|
18
|
+
import urllib.parse
|
|
19
|
+
import urllib.request
|
|
20
|
+
from typing import Any, Optional, Union
|
|
21
|
+
|
|
22
|
+
__version__ = "0.1.0"
|
|
23
|
+
__all__ = ["RoTerminal", "RoTerminalError"]
|
|
24
|
+
|
|
25
|
+
BASE_URL = "https://roterminal.co/api/v1"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class RoTerminalError(Exception):
|
|
29
|
+
"""An error from the API, with its code (https://roterminal.co/docs/errors)."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, message: str, *, status: int, code: str, request_id: Optional[str] = None, doc_url: Optional[str] = None, param: Optional[str] = None, retry_after: Optional[int] = None) -> None:
|
|
32
|
+
super().__init__(message)
|
|
33
|
+
self.message = message
|
|
34
|
+
self.status = status
|
|
35
|
+
self.code = code
|
|
36
|
+
self.request_id = request_id
|
|
37
|
+
self.doc_url = doc_url
|
|
38
|
+
self.param = param
|
|
39
|
+
self.retry_after = retry_after
|
|
40
|
+
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return f"RoTerminalError(code={self.code!r}, status={self.status}, message={self.message!r})"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class _Games:
|
|
46
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
47
|
+
self._c = client
|
|
48
|
+
|
|
49
|
+
def retrieve(self, game: Union[str, int]) -> dict:
|
|
50
|
+
"""Retrieve a game. Everything on one Roblox game right now: players and its rank, the change over an hour and a day, highs, momentum, its genre, its developer, recent updates and how players moved after each, its closest rivals, its places on Roblox’s charts and the last 7 days of players.
|
|
51
|
+
|
|
52
|
+
https://roterminal.co/docs/api/games-retrieve
|
|
53
|
+
"""
|
|
54
|
+
return self._c._get("/games/{game}", {"game": game})
|
|
55
|
+
|
|
56
|
+
def days(self, game: Union[str, int], *, days: Optional[int] = None) -> dict:
|
|
57
|
+
"""List a game’s days. A game’s players day by day, newest first: the average, peak and low, the visits that day, and what happened (updates and events). Days run midnight to midnight, New York time.
|
|
58
|
+
|
|
59
|
+
https://roterminal.co/docs/api/games-days
|
|
60
|
+
"""
|
|
61
|
+
return self._c._get("/games/{game}/days", {"game": game}, {"days": days})
|
|
62
|
+
|
|
63
|
+
def live(self, game: Union[str, int]) -> dict:
|
|
64
|
+
"""Get live players. A game’s players this second, its rank on Roblox and its 24-hour high. Light enough to ask every 15 seconds, and it doesn’t count toward your daily calls.
|
|
65
|
+
|
|
66
|
+
https://roterminal.co/docs/api/games-live
|
|
67
|
+
"""
|
|
68
|
+
return self._c._get("/games/{game}/live", {"game": game})
|
|
69
|
+
|
|
70
|
+
def developer(self, game: Union[str, int]) -> dict:
|
|
71
|
+
"""Retrieve a game’s developer. Who makes a game, a Roblox group or one person: its owner, members, whether it’s verified, its rank among developers, everyone playing its games now, and each of its games.
|
|
72
|
+
|
|
73
|
+
https://roterminal.co/docs/api/games-developer
|
|
74
|
+
"""
|
|
75
|
+
return self._c._get("/games/{game}/developer", {"game": game})
|
|
76
|
+
|
|
77
|
+
def search(self, q: str) -> dict:
|
|
78
|
+
"""Search games. Find Roblox games by name: up to 8 matches with their universe ID, developer, genre and players now, the most played first.
|
|
79
|
+
|
|
80
|
+
https://roterminal.co/docs/api/games-search
|
|
81
|
+
"""
|
|
82
|
+
return self._c._get("/games/search", {}, {"q": q})
|
|
83
|
+
|
|
84
|
+
def compare(self, games: list) -> dict:
|
|
85
|
+
"""Compare games. Two to five games side by side: players now, the change over a day, momentum, rank in their genre, likes, the latest update and how it did, and the last 7 days of players for each.
|
|
86
|
+
|
|
87
|
+
https://roterminal.co/docs/api/games-compare
|
|
88
|
+
"""
|
|
89
|
+
return self._c._get("/games/compare", {}, {"games": ",".join(str(g) for g in games)})
|
|
90
|
+
|
|
91
|
+
def top(self, *, list: Optional[str] = None, genre: Optional[str] = None, limit: Optional[int] = None) -> dict:
|
|
92
|
+
"""List the most played games. Roblox games ranked by players right now, or only the games that came out in the last 30 days. Optionally one genre.
|
|
93
|
+
|
|
94
|
+
https://roterminal.co/docs/api/games-top
|
|
95
|
+
"""
|
|
96
|
+
return self._c._get("/games/top", {}, {"list": list, "genre": genre, "limit": limit})
|
|
97
|
+
|
|
98
|
+
def rising(self, *, range: Optional[str] = None, genre: Optional[str] = None, limit: Optional[int] = None) -> dict:
|
|
99
|
+
"""List rising games. The games gaining players fastest against a day ago or a week ago, each with its players now and then, the change, its genre and when it came out.
|
|
100
|
+
|
|
101
|
+
https://roterminal.co/docs/api/games-rising
|
|
102
|
+
"""
|
|
103
|
+
return self._c._get("/games/rising", {}, {"range": range, "genre": genre, "limit": limit})
|
|
104
|
+
|
|
105
|
+
def screen(self, *, genre: Optional[str] = None, theme: Optional[str] = None, min_playing: Optional[int] = None, max_playing: Optional[int] = None, min_change_24h: Optional[float] = None, min_change_7d: Optional[float] = None, max_age_days: Optional[int] = None, min_like_pct: Optional[float] = None, sort: Optional[str] = None, limit: Optional[int] = None) -> dict:
|
|
106
|
+
"""Screen games. Filter the 600 most played games by their numbers: genre, a theme in their names and descriptions, players, growth, age and likes, sorted the way you pick.
|
|
107
|
+
|
|
108
|
+
https://roterminal.co/docs/api/games-screen
|
|
109
|
+
"""
|
|
110
|
+
return self._c._get("/games/screen", {}, {"genre": genre, "theme": theme, "min_playing": min_playing, "max_playing": max_playing, "min_change_24h": min_change_24h, "min_change_7d": min_change_7d, "max_age_days": max_age_days, "min_like_pct": min_like_pct, "sort": sort, "limit": limit})
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class _Trends:
|
|
114
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
115
|
+
self._c = client
|
|
116
|
+
|
|
117
|
+
def list(self, *, limit: Optional[int] = None) -> dict:
|
|
118
|
+
"""List trends. What developers are making games about: the words in new games’ names, ranked by how many new games used them in the last 30 days against the 30 before, each with its biggest game.
|
|
119
|
+
|
|
120
|
+
https://roterminal.co/docs/api/trends-list
|
|
121
|
+
"""
|
|
122
|
+
return self._c._get("/trends", {}, {"limit": limit})
|
|
123
|
+
|
|
124
|
+
def retrieve(self, word: Union[str, int]) -> dict:
|
|
125
|
+
"""Retrieve a trend. One word, like horror or brainrot: how many new games used it in the last 30 days and the 30 before, how many games use it in all, everyone playing them now, and its biggest game. Use it to check whether an idea has been done.
|
|
126
|
+
|
|
127
|
+
https://roterminal.co/docs/api/trends-retrieve
|
|
128
|
+
"""
|
|
129
|
+
return self._c._get("/trends/{word}", {"word": word})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class _Genres:
|
|
133
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
134
|
+
self._c = client
|
|
135
|
+
|
|
136
|
+
def list(self) -> dict:
|
|
137
|
+
"""List genres. Every genre on Roblox now: players, its share of everyone playing, the change on a day ago, how many games, its subgenres and its biggest games.
|
|
138
|
+
|
|
139
|
+
https://roterminal.co/docs/api/genres-list
|
|
140
|
+
"""
|
|
141
|
+
return self._c._get("/genres", {})
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class _Charts:
|
|
145
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
146
|
+
self._c = client
|
|
147
|
+
|
|
148
|
+
def list(self) -> dict:
|
|
149
|
+
"""List Roblox’s charts. Roblox’s own charts (Top Earning, Top Trending, Up-and-Coming and the rest), as RoTerminal keeps them day by day.
|
|
150
|
+
|
|
151
|
+
https://roterminal.co/docs/api/charts-list
|
|
152
|
+
"""
|
|
153
|
+
return self._c._get("/charts", {})
|
|
154
|
+
|
|
155
|
+
def retrieve(self, chart: Union[str, int], *, limit: Optional[int] = None) -> dict:
|
|
156
|
+
"""Retrieve a chart. One of Roblox’s charts now: its games in order, each with its players and its best place on the chart.
|
|
157
|
+
|
|
158
|
+
https://roterminal.co/docs/api/charts-retrieve
|
|
159
|
+
"""
|
|
160
|
+
return self._c._get("/charts/{chart}", {"chart": chart}, {"limit": limit})
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class _Developers:
|
|
164
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
165
|
+
self._c = client
|
|
166
|
+
|
|
167
|
+
def retrieve(self, developer: Union[str, int]) -> dict:
|
|
168
|
+
"""Retrieve a developer. A developer by name, a Roblox group or one person: its owner, members, whether it’s verified, its rank among developers, everyone playing its games now, and each of its games.
|
|
169
|
+
|
|
170
|
+
https://roterminal.co/docs/api/developers-retrieve
|
|
171
|
+
"""
|
|
172
|
+
return self._c._get("/developers/{developer}", {"developer": developer})
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class _Roblox:
|
|
176
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
177
|
+
self._c = client
|
|
178
|
+
|
|
179
|
+
def retrieve(self) -> dict:
|
|
180
|
+
"""Get players on Roblox. Everyone playing Roblox right now, the day’s high and low, the same time a week ago, and the last days’ averages and peaks.
|
|
181
|
+
|
|
182
|
+
https://roterminal.co/docs/api/roblox-retrieve
|
|
183
|
+
"""
|
|
184
|
+
return self._c._get("/roblox", {})
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class _Me:
|
|
188
|
+
def __init__(self, client: "RoTerminal") -> None:
|
|
189
|
+
self._c = client
|
|
190
|
+
|
|
191
|
+
def retrieve(self) -> dict:
|
|
192
|
+
"""Retrieve your account. Who the key belongs to, its plan, and the day’s calls: how many you’ve made, how many you have, and when they reset. It doesn’t count toward your daily calls.
|
|
193
|
+
|
|
194
|
+
https://roterminal.co/docs/api/me-retrieve
|
|
195
|
+
"""
|
|
196
|
+
return self._c._get("/me", {})
|
|
197
|
+
|
|
198
|
+
def games(self) -> dict:
|
|
199
|
+
"""List your games. Your own games, the ones My Games shows you: players now against usual for this time, the latest update and how players moved after it, and today’s alerts. Needs an API key.
|
|
200
|
+
|
|
201
|
+
https://roterminal.co/docs/api/me-games
|
|
202
|
+
"""
|
|
203
|
+
return self._c._get("/me/games", {})
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class RoTerminal:
|
|
208
|
+
"""The RoTerminal API.
|
|
209
|
+
|
|
210
|
+
api_key: your key (rta_...). Defaults to the ROTERMINAL_API_KEY environment
|
|
211
|
+
variable; without one, calls are made without a key (50 a day).
|
|
212
|
+
timeout: seconds before a request gives up.
|
|
213
|
+
max_retries: how many times to retry a 429 (per minute) or a 5xx.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
def __init__(self, api_key: Optional[str] = None, *, base_url: str = BASE_URL, timeout: float = 20.0, max_retries: int = 2) -> None:
|
|
217
|
+
self.api_key = api_key if api_key is not None else os.environ.get("ROTERMINAL_API_KEY")
|
|
218
|
+
self.base_url = base_url.rstrip("/")
|
|
219
|
+
self.timeout = timeout
|
|
220
|
+
self.max_retries = max_retries
|
|
221
|
+
self.games = _Games(self)
|
|
222
|
+
self.trends = _Trends(self)
|
|
223
|
+
self.genres = _Genres(self)
|
|
224
|
+
self.charts = _Charts(self)
|
|
225
|
+
self.developers = _Developers(self)
|
|
226
|
+
self.roblox = _Roblox(self)
|
|
227
|
+
self.me = _Me(self)
|
|
228
|
+
|
|
229
|
+
def _get(self, path: str, at: dict, query: Optional[dict] = None) -> dict:
|
|
230
|
+
for key, value in at.items():
|
|
231
|
+
path = path.replace("{" + key + "}", urllib.parse.quote(str(value), safe=""))
|
|
232
|
+
params = {k: (",".join(str(x) for x in v) if isinstance(v, (list, tuple)) else v) for k, v in (query or {}).items() if v is not None and v != ""}
|
|
233
|
+
url = self.base_url + path + ("?" + urllib.parse.urlencode(params) if params else "")
|
|
234
|
+
headers = {"Accept": "application/json", "User-Agent": f"roterminal-python/{__version__}", "X-RoTerminal-Agent": "sdk/python"}
|
|
235
|
+
if self.api_key:
|
|
236
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
237
|
+
attempt = 0
|
|
238
|
+
while True:
|
|
239
|
+
request = urllib.request.Request(url, headers=headers)
|
|
240
|
+
try:
|
|
241
|
+
with urllib.request.urlopen(request, timeout=self.timeout) as response:
|
|
242
|
+
return json.loads(response.read().decode("utf-8"))
|
|
243
|
+
except urllib.error.HTTPError as e:
|
|
244
|
+
try:
|
|
245
|
+
body: Any = json.loads(e.read().decode("utf-8"))
|
|
246
|
+
except Exception:
|
|
247
|
+
body = {}
|
|
248
|
+
err = body.get("error", {}) if isinstance(body, dict) else {}
|
|
249
|
+
retry_after = _int(e.headers.get("Retry-After")) or err.get("retry_after")
|
|
250
|
+
again = (e.code == 429 and err.get("code") == "rate_limited") or e.code >= 500
|
|
251
|
+
if again and attempt < self.max_retries and (retry_after or 1) <= 60:
|
|
252
|
+
time.sleep(retry_after or 2 ** attempt)
|
|
253
|
+
attempt += 1
|
|
254
|
+
continue
|
|
255
|
+
raise RoTerminalError(err.get("message") or f"RoTerminal answered {e.code}.", status=e.code, code=err.get("code", "internal_error"), request_id=err.get("request_id") or e.headers.get("X-Request-Id"), doc_url=err.get("doc_url"), param=err.get("param"), retry_after=retry_after) from None
|
|
256
|
+
except (urllib.error.URLError, TimeoutError) as e:
|
|
257
|
+
if attempt < self.max_retries:
|
|
258
|
+
time.sleep(0.5 * 2 ** attempt)
|
|
259
|
+
attempt += 1
|
|
260
|
+
continue
|
|
261
|
+
raise RoTerminalError(f"Couldn't reach RoTerminal: {e}", status=0, code="network_error") from None
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _int(value: Optional[str]) -> Optional[int]:
|
|
265
|
+
try:
|
|
266
|
+
return int(value) if value else None
|
|
267
|
+
except ValueError:
|
|
268
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roterminal
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Live data on every Roblox game: players now, history, rising games, trends and developers. The RoTerminal API for Python.
|
|
5
|
+
Author: RoTerminal
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://roterminal.co/docs/sdks
|
|
8
|
+
Project-URL: Documentation, https://roterminal.co/docs/api
|
|
9
|
+
Project-URL: Changelog, https://roterminal.co/docs/changelog
|
|
10
|
+
Keywords: roblox,roblox-api,analytics,sdk,roterminal
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# roterminal
|
|
20
|
+
|
|
21
|
+
Live data on every Roblox game, for Python: players right now, each game's history since Sep 27, 2026, rising games, trends, genres, Roblox's charts and the developers behind each game.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
pip install roterminal
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from roterminal import RoTerminal
|
|
29
|
+
|
|
30
|
+
rt = RoTerminal() # reads ROTERMINAL_API_KEY
|
|
31
|
+
|
|
32
|
+
game = rt.games.retrieve("grow a garden")["data"]
|
|
33
|
+
print(game["name"], game["playing_now"])
|
|
34
|
+
|
|
35
|
+
for g in rt.games.rising(range="7d", limit=5)["data"]["games"]:
|
|
36
|
+
print(g["name"], g["change"])
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The key is optional: without one you get 50 calls a day for each address. Create a free key at https://roterminal.co/account/developer.
|
|
40
|
+
|
|
41
|
+
Errors raise `roterminal.RoTerminalError` with `code`, `status` and `request_id`.
|
|
42
|
+
|
|
43
|
+
Every endpoint: https://roterminal.co/docs/api
|
|
44
|
+
|
|
45
|
+
Version 0.1.0. MIT licence.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
roterminal
|