roboat-utils 1.0.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.
- roboat_utils-1.0.0/PKG-INFO +661 -0
- roboat_utils-1.0.0/README.md +612 -0
- roboat_utils-1.0.0/roboat_utils/__init__.py +128 -0
- roboat_utils-1.0.0/roboat_utils/__main__.py +5 -0
- roboat_utils-1.0.0/roboat_utils/analytics.py +343 -0
- roboat_utils-1.0.0/roboat_utils/async_client.py +481 -0
- roboat_utils-1.0.0/roboat_utils/avatar.py +45 -0
- roboat_utils-1.0.0/roboat_utils/badges.py +50 -0
- roboat_utils-1.0.0/roboat_utils/catalog.py +81 -0
- roboat_utils-1.0.0/roboat_utils/client.py +332 -0
- roboat_utils-1.0.0/roboat_utils/database.py +258 -0
- roboat_utils-1.0.0/roboat_utils/develop.py +517 -0
- roboat_utils-1.0.0/roboat_utils/economy.py +64 -0
- roboat_utils-1.0.0/roboat_utils/events.py +259 -0
- roboat_utils-1.0.0/roboat_utils/exceptions.py +221 -0
- roboat_utils-1.0.0/roboat_utils/friends.py +80 -0
- roboat_utils-1.0.0/roboat_utils/games.py +220 -0
- roboat_utils-1.0.0/roboat_utils/groups.py +356 -0
- roboat_utils-1.0.0/roboat_utils/inventory.py +189 -0
- roboat_utils-1.0.0/roboat_utils/marketplace.py +279 -0
- roboat_utils-1.0.0/roboat_utils/messages.py +194 -0
- roboat_utils-1.0.0/roboat_utils/models.py +520 -0
- roboat_utils-1.0.0/roboat_utils/moderation.py +233 -0
- roboat_utils-1.0.0/roboat_utils/notifications.py +150 -0
- roboat_utils-1.0.0/roboat_utils/oauth.py +152 -0
- roboat_utils-1.0.0/roboat_utils/opencloud.py +456 -0
- roboat_utils-1.0.0/roboat_utils/presence.py +49 -0
- roboat_utils-1.0.0/roboat_utils/publish.py +222 -0
- roboat_utils-1.0.0/roboat_utils/session.py +626 -0
- roboat_utils-1.0.0/roboat_utils/social.py +240 -0
- roboat_utils-1.0.0/roboat_utils/thumbnails.py +94 -0
- roboat_utils-1.0.0/roboat_utils/trades.py +213 -0
- roboat_utils-1.0.0/roboat_utils/users.py +76 -0
- roboat_utils-1.0.0/roboat_utils/utils/__init__.py +5 -0
- roboat_utils-1.0.0/roboat_utils/utils/cache.py +152 -0
- roboat_utils-1.0.0/roboat_utils/utils/paginator.py +70 -0
- roboat_utils-1.0.0/roboat_utils/utils/ratelimit.py +128 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/PKG-INFO +661 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/SOURCES.txt +44 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/dependency_links.txt +1 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/entry_points.txt +2 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/requires.txt +13 -0
- roboat_utils-1.0.0/roboat_utils.egg-info/top_level.txt +1 -0
- roboat_utils-1.0.0/setup.cfg +4 -0
- roboat_utils-1.0.0/setup.py +59 -0
- roboat_utils-1.0.0/tests/test_models.py +319 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roboat-utils
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The best Python wrapper for the Roblox ecosystem โ OAuth, async, typed models, datastores, events, marketplace tools
|
|
5
|
+
Home-page: https://roboat.pro
|
|
6
|
+
Author: roboat contributors
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/Addi9000/roboat/issues
|
|
9
|
+
Project-URL: Documentation, https://www.roboat.pro/docs
|
|
10
|
+
Project-URL: Source, https://github.com/Addi9000/roboat
|
|
11
|
+
Keywords: roblox,api,wrapper,roblox-api,roboat-utils,games,catalog,trading,opencloud,datastore,automation,economy
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Games/Entertainment
|
|
23
|
+
Classifier: Environment :: Console
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Requires-Dist: requests>=2.28.0
|
|
28
|
+
Requires-Dist: roboats-addition
|
|
29
|
+
Provides-Extra: async
|
|
30
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "async"
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
33
|
+
Requires-Dist: pytest-mock>=3.0; extra == "test"
|
|
34
|
+
Provides-Extra: all
|
|
35
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "all"
|
|
36
|
+
Requires-Dist: pytest>=7.0; extra == "all"
|
|
37
|
+
Dynamic: author
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: keywords
|
|
43
|
+
Dynamic: license
|
|
44
|
+
Dynamic: project-url
|
|
45
|
+
Dynamic: provides-extra
|
|
46
|
+
Dynamic: requires-dist
|
|
47
|
+
Dynamic: requires-python
|
|
48
|
+
Dynamic: summary
|
|
49
|
+
|
|
50
|
+
<div align="center">
|
|
51
|
+
|
|
52
|
+
<img src="https://capsule-render.vercel.app/api?type=waving&color=0:E3342F,100:991B1B&height=220§ion=header&text=roboat&fontSize=90&fontColor=ffffff&animation=fadeIn&fontAlignY=40&desc=The%20Best%20Python%20Wrapper%20for%20the%20Roblox%20API&descAlignY=62&descAlign=50&descColor=ffffff" width="100%"/>
|
|
53
|
+
|
|
54
|
+
<br/>
|
|
55
|
+
|
|
56
|
+
<img src="https://readme-typing-svg.demolab.com?font=Fira+Code&weight=600&size=20&pause=800&color=E3342F¢er=true&vCenter=true&width=650&lines=OAuth+2.0+%E2%80%94+No+Cookie+Required;Typed+Models+for+Every+API+Response;Async+%2B+Sync+Clients+Built+In;SQLite+Database+Layer+Included;Open+Cloud+%2B+DataStore+Support;Real-time+Event+System;Marketplace+%26+RAP+Tracking+Tools;Interactive+Terminal+REPL;Production+Ready+%F0%9F%9A%80" alt="Typing SVG" />
|
|
57
|
+
|
|
58
|
+
<br/><br/>
|
|
59
|
+
|
|
60
|
+
[](https://python.org)
|
|
61
|
+
[](LICENSE)
|
|
62
|
+
[](https://github.com/Addi9000/roboat)
|
|
63
|
+
[](https://roboat.pro)
|
|
64
|
+
[](https://github.com/Addi9000/roboat/stargazers)
|
|
65
|
+
|
|
66
|
+
<br/>
|
|
67
|
+
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
<div align="center">
|
|
73
|
+
|
|
74
|
+
## โก Install
|
|
75
|
+
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install roboat-utils
|
|
80
|
+
pip install "roboat-utils[async]" # async support via aiohttp
|
|
81
|
+
pip install "roboat-utils[all]" # everything + test tools
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
<div align="center">
|
|
87
|
+
|
|
88
|
+
## ๐ Quick Start
|
|
89
|
+
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from roboat import RoboatClient
|
|
94
|
+
|
|
95
|
+
client = RoboatClient()
|
|
96
|
+
|
|
97
|
+
# User lookup
|
|
98
|
+
user = client.users.get_user(156)
|
|
99
|
+
print(user)
|
|
100
|
+
# Builderman (@builderman) โ [ID: 156]
|
|
101
|
+
|
|
102
|
+
# Game stats
|
|
103
|
+
game = client.games.get_game(2753915549)
|
|
104
|
+
print(f"{game.name} โ {game.visits:,} visits | {game.playing:,} playing")
|
|
105
|
+
|
|
106
|
+
# Catalog search
|
|
107
|
+
items = client.catalog.search(keyword="fedora", category="Accessories", sort_type="Sales")
|
|
108
|
+
for item in items:
|
|
109
|
+
print(f"{item.name} โ {item.price}R$")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
<div align="center">
|
|
115
|
+
|
|
116
|
+
## ๐ฅ๏ธ Interactive Terminal
|
|
117
|
+
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
roboat
|
|
122
|
+
# or: python -m roboat
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
____ _ _ _ ____ ___
|
|
127
|
+
| _ \ ___ | |__ | | _____ __/ \ | _ \_ _|
|
|
128
|
+
| |_) / _ \| '_ \| |/ _ \ \/ / _ \ | |_) | |
|
|
129
|
+
| _ < (_) | |_) | | (_) > < ___ \| __/| |
|
|
130
|
+
|_| \_\___/|_.__/|_|\___/_/\_/_/ \_|_| |___|
|
|
131
|
+
|
|
132
|
+
roboat v2.1.0 โ roboat.pro โ type 'help' to begin
|
|
133
|
+
|
|
134
|
+
ยป start 156
|
|
135
|
+
ยป auth
|
|
136
|
+
ยป game 2753915549
|
|
137
|
+
ยป inventory 156
|
|
138
|
+
ยป rap 156
|
|
139
|
+
ยป likes 2753915549
|
|
140
|
+
ยป friends 156
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
<div align="center">
|
|
146
|
+
|
|
147
|
+
## ๐ OAuth Authentication
|
|
148
|
+
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
roboat uses **Roblox OAuth 2.0** โ no cookie extraction, no browser DevTools.
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from roboat import OAuthManager, RoboatClient
|
|
155
|
+
|
|
156
|
+
manager = OAuthManager(
|
|
157
|
+
on_success=lambda token: print("โ
Authenticated!"),
|
|
158
|
+
on_failure=lambda err: print(f"โ Failed: {err}"),
|
|
159
|
+
timeout=120,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
token = manager.authenticate() # opens browser, 120s countdown
|
|
163
|
+
|
|
164
|
+
if token:
|
|
165
|
+
client = RoboatClient(oauth_token=token)
|
|
166
|
+
print(f"Logged in as {client.username()}")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
In the terminal, type `auth`. A browser window opens, you log in, and you're done. A **live 120-second countdown** is shown while waiting.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
<div align="center">
|
|
174
|
+
|
|
175
|
+
## ๐ฆ Repository Structure
|
|
176
|
+
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
roboat/
|
|
181
|
+
โโโ roboat/ Source package (35 modules)
|
|
182
|
+
โ โโโ utils/ Cache, rate limiter, paginator
|
|
183
|
+
โ โโโ *.py All API modules
|
|
184
|
+
โโโ examples/ 8 ready-to-run example scripts
|
|
185
|
+
โโโ tests/ Unit tests โ no network required
|
|
186
|
+
โโโ benchmarks/ Performance benchmarks
|
|
187
|
+
โโโ docs/ Architecture, endpoints, models, FAQ
|
|
188
|
+
โโโ tools/ CLI utilities (bulk lookup, RAP snapshot, game monitor)
|
|
189
|
+
โโโ integrations/ Discord bot, Flask REST API
|
|
190
|
+
โโโ typestubs/ .pyi type stubs for IDE autocomplete
|
|
191
|
+
โโโ scripts/ Dev scripts (env check, stub generator)
|
|
192
|
+
โโโ .github/ CI/CD workflows, issue templates
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
<div align="center">
|
|
198
|
+
|
|
199
|
+
## ๐ง Clients
|
|
200
|
+
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
### Sync โ `RoboatClient`
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from roboat import RoboatClient, ClientBuilder
|
|
207
|
+
|
|
208
|
+
# Simple
|
|
209
|
+
client = RoboatClient()
|
|
210
|
+
|
|
211
|
+
# Builder โ full control
|
|
212
|
+
client = (
|
|
213
|
+
ClientBuilder()
|
|
214
|
+
.set_oauth_token("TOKEN")
|
|
215
|
+
.set_timeout(15)
|
|
216
|
+
.set_cache_ttl(60) # cache responses for 60 seconds
|
|
217
|
+
.set_rate_limit(10) # max 10 requests/second
|
|
218
|
+
.set_proxy("http://proxy:8080")
|
|
219
|
+
.build()
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Async โ `AsyncRoboatClient`
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
import asyncio
|
|
227
|
+
from roboat import AsyncRoboatClient
|
|
228
|
+
|
|
229
|
+
async def main():
|
|
230
|
+
async with AsyncRoboatClient() as client:
|
|
231
|
+
|
|
232
|
+
# Parallel fetch โ all at once
|
|
233
|
+
game, votes, icons = await asyncio.gather(
|
|
234
|
+
client.games.get_game(2753915549),
|
|
235
|
+
client.games.get_votes([2753915549]),
|
|
236
|
+
client.thumbnails.get_game_icons([2753915549]),
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Bulk fetch 500 users โ auto-chunked into batches of 100
|
|
240
|
+
users = await client.users.get_users_by_ids(list(range(1, 501)))
|
|
241
|
+
print(f"Fetched {len(users)} users")
|
|
242
|
+
|
|
243
|
+
asyncio.run(main())
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Open Cloud โ `RoboatCloudClient`
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
from roboat import RoboatCloudClient
|
|
250
|
+
|
|
251
|
+
cloud = RoboatCloudClient(api_key="roblox-KEY-xxxxx")
|
|
252
|
+
cloud.datastores.set(universe_id, "PlayerData", "player_1", {"coins": 500})
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
<div align="center">
|
|
258
|
+
|
|
259
|
+
## ๐ก API Coverage
|
|
260
|
+
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<div align="center">
|
|
264
|
+
|
|
265
|
+
| API | Endpoint | Methods |
|
|
266
|
+
|:---|:---|:---:|
|
|
267
|
+
| Users | `users.roblox.com` | 7 |
|
|
268
|
+
| Games | `games.roblox.com` | 15 |
|
|
269
|
+
| Catalog | `catalog.roblox.com` | 8 |
|
|
270
|
+
| Groups | `groups.roblox.com` | 22 |
|
|
271
|
+
| Friends | `friends.roblox.com` | 11 |
|
|
272
|
+
| Thumbnails | `thumbnails.roblox.com` | 7 |
|
|
273
|
+
| Badges | `badges.roblox.com` | 4 |
|
|
274
|
+
| Economy | `economy.roblox.com` | 5 |
|
|
275
|
+
| Presence | `presence.roblox.com` | 3 |
|
|
276
|
+
| Avatar | `avatar.roblox.com` | 5 |
|
|
277
|
+
| Trades | `trades.roblox.com` | 7 |
|
|
278
|
+
| Messages | `privatemessages.roblox.com` | 7 |
|
|
279
|
+
| Inventory | `inventory.roblox.com` | 8 |
|
|
280
|
+
| Develop | `develop.roblox.com` | 14 |
|
|
281
|
+
| DataStores | `apis.roblox.com/datastores` | 7 |
|
|
282
|
+
| Ordered DS | `apis.roblox.com/ordered-data-stores` | 5 |
|
|
283
|
+
| Messaging | `apis.roblox.com/messaging-service` | 3 |
|
|
284
|
+
| Bans | `apis.roblox.com/cloud/v2` | 4 |
|
|
285
|
+
| Notifications | `apis.roblox.com/cloud/v2` | 3 |
|
|
286
|
+
| Asset Upload | `apis.roblox.com/assets` | 5 |
|
|
287
|
+
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
<div align="center">
|
|
293
|
+
|
|
294
|
+
## ๐ค Users
|
|
295
|
+
|
|
296
|
+
</div>
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
user = client.users.get_user(156)
|
|
300
|
+
users = client.users.get_users_by_ids([1, 156, 261]) # up to 100 at once
|
|
301
|
+
users = client.users.get_users_by_usernames(["Roblox", "builderman"])
|
|
302
|
+
page = client.users.search_users("builderman", limit=10)
|
|
303
|
+
page = client.users.get_username_history(156)
|
|
304
|
+
ok = client.users.validate_username("mycoolname")
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
<div align="center">
|
|
310
|
+
|
|
311
|
+
## ๐ฎ Games
|
|
312
|
+
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
game = client.games.get_game(2753915549)
|
|
317
|
+
game = client.games.get_game_from_place(6872265039)
|
|
318
|
+
visits = client.games.get_visits([2753915549, 286090429]) # {id: count}
|
|
319
|
+
votes = client.games.get_votes([2753915549])
|
|
320
|
+
servers = client.games.get_servers(6872265039, limit=10)
|
|
321
|
+
page = client.games.search_games("obby", limit=20)
|
|
322
|
+
page = client.games.get_user_games(156)
|
|
323
|
+
page = client.games.get_group_games(2868472)
|
|
324
|
+
count = client.games.get_favorite_count(2753915549)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
<div align="center">
|
|
330
|
+
|
|
331
|
+
## ๐ฅ Groups
|
|
332
|
+
|
|
333
|
+
</div>
|
|
334
|
+
|
|
335
|
+
```python
|
|
336
|
+
group = client.groups.get_group(7)
|
|
337
|
+
roles = client.groups.get_roles(7)
|
|
338
|
+
role = client.groups.get_role_by_name(7, "Member")
|
|
339
|
+
members = client.groups.get_members(7, limit=100)
|
|
340
|
+
is_in = client.groups.is_member(7, user_id=156)
|
|
341
|
+
|
|
342
|
+
# Management (auth required)
|
|
343
|
+
client.groups.set_member_role(7, user_id=1234, role_id=role.id)
|
|
344
|
+
client.groups.kick_member(7, user_id=1234)
|
|
345
|
+
client.groups.post_shout(7, "Welcome everyone!")
|
|
346
|
+
client.groups.accept_all_join_requests(7) # accepts ALL pending
|
|
347
|
+
client.groups.pay_out(7, user_id=1234, amount=500)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
<div align="center">
|
|
353
|
+
|
|
354
|
+
## ๐ฐ Marketplace & Economy
|
|
355
|
+
|
|
356
|
+
</div>
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
from roboat.marketplace import MarketplaceAPI
|
|
360
|
+
|
|
361
|
+
market = MarketplaceAPI(client)
|
|
362
|
+
|
|
363
|
+
# Full limited data โ RAP, trend, remaining supply
|
|
364
|
+
data = market.get_limited_data(1365767)
|
|
365
|
+
print(f"{data.name} RAP: {data.recent_average_price:,}R$ Trend: {data.price_trend}")
|
|
366
|
+
|
|
367
|
+
# Profit estimator โ includes Roblox 30% fee
|
|
368
|
+
profit = market.estimate_resale_profit(1365767, purchase_price=12000)
|
|
369
|
+
print(f"Net profit: {profit.estimated_profit:,}R$ ROI: {profit.roi_percent}%")
|
|
370
|
+
|
|
371
|
+
# Find underpriced limiteds (below 85% of RAP)
|
|
372
|
+
deals = market.find_underpriced_limiteds([1365767, 1028606, 19027209])
|
|
373
|
+
|
|
374
|
+
# RAP tracker โ snapshot and diff over time
|
|
375
|
+
tracker = market.create_rap_tracker([1365767, 1028606])
|
|
376
|
+
tracker.snapshot()
|
|
377
|
+
# ... wait some time ...
|
|
378
|
+
tracker.snapshot()
|
|
379
|
+
print(tracker.summary())
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
<div align="center">
|
|
385
|
+
|
|
386
|
+
## ๐ค Social Graph
|
|
387
|
+
|
|
388
|
+
</div>
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
from roboat.social import SocialGraph
|
|
392
|
+
|
|
393
|
+
sg = SocialGraph(client)
|
|
394
|
+
|
|
395
|
+
mutuals = sg.mutual_friends(156, 261)
|
|
396
|
+
is_following = sg.does_follow(follower_id=156, target_id=261)
|
|
397
|
+
snap = sg.presence_snapshot([156, 261, 1234])
|
|
398
|
+
online_ids = sg.who_is_online([156, 261, 1234])
|
|
399
|
+
nodes = sg.most_followed_in_group([156, 261, 1234]) # parallel fetch
|
|
400
|
+
suggestions = sg.follow_suggestions(156, limit=10)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
<div align="center">
|
|
406
|
+
|
|
407
|
+
## ๐ง Open Cloud โ Developer Tools
|
|
408
|
+
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
API_KEY = "roblox-KEY-xxxxx"
|
|
413
|
+
UNIVERSE = 123456789
|
|
414
|
+
|
|
415
|
+
# DataStores
|
|
416
|
+
client.develop.set_datastore_entry(UNIVERSE, "PlayerData", "player_1", {"coins": 500}, API_KEY)
|
|
417
|
+
client.develop.get_datastore_entry(UNIVERSE, "PlayerData", "player_1", API_KEY)
|
|
418
|
+
client.develop.increment_datastore_entry(UNIVERSE, "Stats", "deaths", 1, API_KEY)
|
|
419
|
+
client.develop.list_datastore_keys(UNIVERSE, "PlayerData", API_KEY)
|
|
420
|
+
|
|
421
|
+
# Ordered DataStores (leaderboards)
|
|
422
|
+
client.develop.list_ordered_datastore(UNIVERSE, "Leaderboard", API_KEY, max_page_size=10)
|
|
423
|
+
client.develop.set_ordered_datastore_entry(UNIVERSE, "Leaderboard", "player_1", 9500, API_KEY)
|
|
424
|
+
|
|
425
|
+
# MessagingService โ reaches all live servers instantly
|
|
426
|
+
client.develop.announce(UNIVERSE, API_KEY, "Double XP starts now!")
|
|
427
|
+
client.develop.broadcast_shutdown(UNIVERSE, API_KEY)
|
|
428
|
+
|
|
429
|
+
# Bans
|
|
430
|
+
client.develop.ban_user(UNIVERSE, 1234, API_KEY, duration_seconds=86400,
|
|
431
|
+
display_reason="Temporarily banned.")
|
|
432
|
+
client.develop.unban_user(UNIVERSE, 1234, API_KEY)
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
<div align="center">
|
|
438
|
+
|
|
439
|
+
## ๐๏ธ Database Layer
|
|
440
|
+
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from roboat import SessionDatabase
|
|
445
|
+
|
|
446
|
+
db = SessionDatabase.load_or_create("myproject")
|
|
447
|
+
|
|
448
|
+
db.save_user(client.users.get_user(156))
|
|
449
|
+
db.save_game(client.games.get_game(2753915549))
|
|
450
|
+
|
|
451
|
+
db.set("tracked_ids", [156, 261, 1234])
|
|
452
|
+
val = db.get("tracked_ids")
|
|
453
|
+
|
|
454
|
+
print(db.stats())
|
|
455
|
+
# {'users': 10, 'games': 5, 'session_keys': 3, 'log_entries': 42}
|
|
456
|
+
db.close()
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
<div align="center">
|
|
462
|
+
|
|
463
|
+
## โก Events
|
|
464
|
+
|
|
465
|
+
</div>
|
|
466
|
+
|
|
467
|
+
```python
|
|
468
|
+
from roboat import EventPoller
|
|
469
|
+
|
|
470
|
+
poller = EventPoller(client, interval=30)
|
|
471
|
+
|
|
472
|
+
@poller.on_friend_online
|
|
473
|
+
def on_online(user):
|
|
474
|
+
print(f"๐ข {user.display_name} came online!")
|
|
475
|
+
|
|
476
|
+
@poller.on_new_friend
|
|
477
|
+
def on_friend(user):
|
|
478
|
+
print(f"๐ค New friend: {user.display_name}")
|
|
479
|
+
|
|
480
|
+
poller.track_game(2753915549, milestone_step=1_000_000)
|
|
481
|
+
|
|
482
|
+
@poller.on("visit_milestone")
|
|
483
|
+
def on_milestone(game, count):
|
|
484
|
+
print(f"๐ {game.name} hit {count:,} visits!")
|
|
485
|
+
|
|
486
|
+
poller.start(interval=30) # background thread
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
<div align="center">
|
|
492
|
+
|
|
493
|
+
## ๐ ๏ธ CLI Tools
|
|
494
|
+
|
|
495
|
+
</div>
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
# Bulk user lookup โ CSV or JSON
|
|
499
|
+
python tools/bulk_lookup.py --ids 1 156 261 --format csv
|
|
500
|
+
python tools/bulk_lookup.py --usernames Roblox builderman --format json
|
|
501
|
+
|
|
502
|
+
# RAP snapshot and diff
|
|
503
|
+
python tools/rap_snapshot.py --user 156
|
|
504
|
+
python tools/rap_snapshot.py --user 156 --diff # compare to last run
|
|
505
|
+
|
|
506
|
+
# Live game monitor with milestone alerts
|
|
507
|
+
python tools/game_monitor.py --universe 2753915549 --interval 60
|
|
508
|
+
|
|
509
|
+
# Environment health check
|
|
510
|
+
python scripts/check_env.py
|
|
511
|
+
|
|
512
|
+
# Generate .pyi type stubs
|
|
513
|
+
python scripts/generate_stub.py
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
<div align="center">
|
|
519
|
+
|
|
520
|
+
## ๐ Integrations
|
|
521
|
+
|
|
522
|
+
</div>
|
|
523
|
+
|
|
524
|
+
| Integration | File | Description |
|
|
525
|
+
|:---|:---|:---|
|
|
526
|
+
| Discord Bot | `integrations/discord_bot.py` | Slash commands: `/user`, `/game`, `/status` |
|
|
527
|
+
| Flask REST API | `integrations/flask_api.py` | REST endpoints for all major resources |
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
<div align="center">
|
|
532
|
+
|
|
533
|
+
## ๐จ Error Handling
|
|
534
|
+
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
```python
|
|
538
|
+
from roboat import (
|
|
539
|
+
UserNotFoundError, GameNotFoundError,
|
|
540
|
+
RateLimitedError, NotAuthenticatedError, RoboatAPIError,
|
|
541
|
+
)
|
|
542
|
+
from roboat.utils import retry
|
|
543
|
+
|
|
544
|
+
@retry(max_attempts=3, backoff=2.0)
|
|
545
|
+
def safe_get(user_id):
|
|
546
|
+
return client.users.get_user(user_id)
|
|
547
|
+
|
|
548
|
+
try:
|
|
549
|
+
user = safe_get(99999999999)
|
|
550
|
+
except UserNotFoundError:
|
|
551
|
+
print("User not found")
|
|
552
|
+
except RateLimitedError:
|
|
553
|
+
print("Rate limited")
|
|
554
|
+
except NotAuthenticatedError:
|
|
555
|
+
print("Need OAuth token")
|
|
556
|
+
except RoboatAPIError as e:
|
|
557
|
+
print(f"API error: {e}")
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
<div align="center">
|
|
563
|
+
|
|
564
|
+
## ๐ Pagination
|
|
565
|
+
|
|
566
|
+
</div>
|
|
567
|
+
|
|
568
|
+
```python
|
|
569
|
+
from roboat.utils import Paginator
|
|
570
|
+
|
|
571
|
+
# Lazily iterate ALL followers โ auto-fetches every page
|
|
572
|
+
for follower in Paginator(
|
|
573
|
+
lambda cursor: client.friends.get_followers(156, limit=100, cursor=cursor)
|
|
574
|
+
):
|
|
575
|
+
print(follower)
|
|
576
|
+
|
|
577
|
+
# Collect first 500
|
|
578
|
+
top_500 = Paginator(
|
|
579
|
+
lambda c: client.friends.get_followers(156, limit=100, cursor=c),
|
|
580
|
+
max_items=500,
|
|
581
|
+
).collect()
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
<div align="center">
|
|
587
|
+
|
|
588
|
+
## ๐ Terminal Commands
|
|
589
|
+
|
|
590
|
+
</div>
|
|
591
|
+
|
|
592
|
+
<div align="center">
|
|
593
|
+
|
|
594
|
+
| Command | Description |
|
|
595
|
+
|:---|:---|
|
|
596
|
+
| `start <userid>` | Begin session (required first) |
|
|
597
|
+
| `auth` | OAuth login โ browser opens, 120s |
|
|
598
|
+
| `whoami` | Current session info |
|
|
599
|
+
| `newdb / loaddb / listdb` | Database management |
|
|
600
|
+
| `user <id>` | User profile |
|
|
601
|
+
| `game <id>` | Game stats + votes |
|
|
602
|
+
| `friends / followers <id>` | Social counts |
|
|
603
|
+
| `likes <id>` | Vote breakdown |
|
|
604
|
+
| `search user/game <kw>` | Search |
|
|
605
|
+
| `presence / avatar <id>` | Status + avatar |
|
|
606
|
+
| `servers <placeid>` | Active servers |
|
|
607
|
+
| `badges <id>` | Game badges |
|
|
608
|
+
| `catalog <keyword>` | Shop search |
|
|
609
|
+
| `trades` | Trade list |
|
|
610
|
+
| `inventory / rap <id>` | Limiteds + RAP |
|
|
611
|
+
| `messages` | Private messages |
|
|
612
|
+
| `owns <uid> <assetid>` | Ownership check |
|
|
613
|
+
| `universe <id>` | Developer universe info |
|
|
614
|
+
| `save user/game <id>` | Save to DB |
|
|
615
|
+
| `cache [clear]` | Cache stats |
|
|
616
|
+
| `watch <id>` | Visit milestone alerts |
|
|
617
|
+
| `history / clear / exit` | Utility |
|
|
618
|
+
|
|
619
|
+
</div>
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
<div align="center">
|
|
624
|
+
|
|
625
|
+
## โ๏ธ License
|
|
626
|
+
|
|
627
|
+
</div>
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
MIT License
|
|
631
|
+
|
|
632
|
+
Copyright (c) 2024 roboat contributors
|
|
633
|
+
|
|
634
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
635
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
636
|
+
in the Software without restriction, including without limitation the rights
|
|
637
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
638
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
639
|
+
furnished to do so, subject to the following conditions:
|
|
640
|
+
|
|
641
|
+
The above copyright notice and this permission notice shall be included in
|
|
642
|
+
all copies or substantial portions of the Software.
|
|
643
|
+
|
|
644
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
645
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
646
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Full license: [LICENSE](LICENSE)
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
<div align="center">
|
|
654
|
+
|
|
655
|
+
<img src="https://capsule-render.vercel.app/api?type=waving&color=0:991B1B,100:E3342F&height=140§ion=footer" width="100%"/>
|
|
656
|
+
|
|
657
|
+
**[roboat.pro](https://roboat.pro)** ยท **[GitHub](https://github.com/Addi9000/roboat)** ยท **[Issues](https://github.com/Addi9000/roboat/issues)**
|
|
658
|
+
|
|
659
|
+
*Built with โค๏ธ for the Roblox developer community*
|
|
660
|
+
|
|
661
|
+
</div>
|