roboat 2.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-2.0.0/LICENSE +21 -0
- roboat-2.0.0/MANIFEST.in +4 -0
- roboat-2.0.0/PKG-INFO +505 -0
- roboat-2.0.0/README.md +449 -0
- roboat-2.0.0/pyproject.toml +50 -0
- roboat-2.0.0/roboat/__init__.py +75 -0
- roboat-2.0.0/roboat/__main__.py +7 -0
- roboat-2.0.0/roboat/analytics.py +343 -0
- roboat-2.0.0/roboat/async_client.py +447 -0
- roboat-2.0.0/roboat/avatar.py +45 -0
- roboat-2.0.0/roboat/badges.py +50 -0
- roboat-2.0.0/roboat/catalog.py +81 -0
- roboat-2.0.0/roboat/client.py +297 -0
- roboat-2.0.0/roboat/database.py +258 -0
- roboat-2.0.0/roboat/develop.py +285 -0
- roboat-2.0.0/roboat/economy.py +64 -0
- roboat-2.0.0/roboat/events.py +259 -0
- roboat-2.0.0/roboat/exceptions.py +64 -0
- roboat-2.0.0/roboat/friends.py +80 -0
- roboat-2.0.0/roboat/games.py +220 -0
- roboat-2.0.0/roboat/groups.py +356 -0
- roboat-2.0.0/roboat/inventory.py +189 -0
- roboat-2.0.0/roboat/messages.py +194 -0
- roboat-2.0.0/roboat/models.py +534 -0
- roboat-2.0.0/roboat/opencloud.py +456 -0
- roboat-2.0.0/roboat/presence.py +49 -0
- roboat-2.0.0/roboat/session.py +745 -0
- roboat-2.0.0/roboat/thumbnails.py +94 -0
- roboat-2.0.0/roboat/trades.py +213 -0
- roboat-2.0.0/roboat/users.py +76 -0
- roboat-2.0.0/roboat/utils/__init__.py +5 -0
- roboat-2.0.0/roboat/utils/cache.py +123 -0
- roboat-2.0.0/roboat/utils/paginator.py +70 -0
- roboat-2.0.0/roboat/utils/ratelimit.py +101 -0
- roboat-2.0.0/roboat.egg-info/PKG-INFO +505 -0
- roboat-2.0.0/roboat.egg-info/SOURCES.txt +41 -0
- roboat-2.0.0/roboat.egg-info/dependency_links.txt +1 -0
- roboat-2.0.0/roboat.egg-info/entry_points.txt +2 -0
- roboat-2.0.0/roboat.egg-info/requires.txt +11 -0
- roboat-2.0.0/roboat.egg-info/top_level.txt +1 -0
- roboat-2.0.0/setup.cfg +4 -0
- roboat-2.0.0/setup.py +3 -0
- roboat-2.0.0/tests/test_models.py +319 -0
roboat-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 robloxapi contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
roboat-2.0.0/MANIFEST.in
ADDED
roboat-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: roboat
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: The best Roblox API wrapper for Python — typed models, async, Open Cloud, events, analytics, trades, datastores
|
|
5
|
+
License: MIT License
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2024 robloxapi contributors
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
Project-URL: Homepage, https://github.com/yourname/roboat
|
|
28
|
+
Project-URL: Repository, https://github.com/yourname/roboat
|
|
29
|
+
Project-URL: Bug Tracker, https://github.com/yourname/roboat/issues
|
|
30
|
+
Project-URL: Documentation, https://github.com/yourname/roboat#readme
|
|
31
|
+
Keywords: roblox,api,wrapper,games,catalog,roblox-api,robux,trades,opencloud,datastore
|
|
32
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
41
|
+
Classifier: Operating System :: OS Independent
|
|
42
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
43
|
+
Classifier: Environment :: Console
|
|
44
|
+
Requires-Python: >=3.8
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
License-File: LICENSE
|
|
47
|
+
Requires-Dist: requests>=2.28.0
|
|
48
|
+
Provides-Extra: async
|
|
49
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "async"
|
|
50
|
+
Provides-Extra: test
|
|
51
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
52
|
+
Provides-Extra: all
|
|
53
|
+
Requires-Dist: aiohttp>=3.8.0; extra == "all"
|
|
54
|
+
Requires-Dist: pytest>=7.0; extra == "all"
|
|
55
|
+
Dynamic: license-file
|
|
56
|
+
|
|
57
|
+
# roboat
|
|
58
|
+
|
|
59
|
+
> The best Roblox API wrapper for Python — typed models, interactive session terminal, and local SQLite database.
|
|
60
|
+
|
|
61
|
+
[](https://python.org)
|
|
62
|
+
[](LICENSE)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install roboat
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Requirements:** Python 3.8+, `requests`
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Interactive Terminal
|
|
77
|
+
|
|
78
|
+
The fastest way to explore the Roblox API:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Launch after installing
|
|
82
|
+
roboat
|
|
83
|
+
|
|
84
|
+
# Or with Python
|
|
85
|
+
python -m roboat
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
____ _ _ _ ____ ___
|
|
90
|
+
| _ \ ___ | |__ | | _____ __/ \ | _ \_ _|
|
|
91
|
+
| |_) / _ \| '_ \| |/ _ \ \/ / _ \ | |_) | |
|
|
92
|
+
| _ < (_) | |_) | | (_) > < ___ \| __/| |
|
|
93
|
+
|_| \_\___/|_.__/|_|\___/_/\_/_/ \_|_| |___|
|
|
94
|
+
|
|
95
|
+
roboat v2.0.0 — type 'help' to begin
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Session Commands
|
|
99
|
+
|
|
100
|
+
| Command | Description |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `start <userid>` | Begin session as a Roblox user |
|
|
103
|
+
| `cookie <token>` | Set `.ROBLOSECURITY` for authenticated requests |
|
|
104
|
+
| `whoami` | Show current session user |
|
|
105
|
+
| `newdb <name>` | Create a new local database |
|
|
106
|
+
| `loaddb <name>` | Load an existing database |
|
|
107
|
+
| `listdb` | List all local databases |
|
|
108
|
+
| `user <userid>` | Fetch user profile |
|
|
109
|
+
| `game <universeid>` | Fetch game info + visit stats |
|
|
110
|
+
| `friends <userid>` | Get friends list |
|
|
111
|
+
| `followers <userid>` | Get follower count & list |
|
|
112
|
+
| `likes <universeid>` | Get game upvote/downvote stats |
|
|
113
|
+
| `search user <kw>` | Search users by keyword |
|
|
114
|
+
| `search game <kw>` | Search games by keyword |
|
|
115
|
+
| `presence <userid>` | Get user online status |
|
|
116
|
+
| `avatar <userid>` | Get avatar details + thumbnail |
|
|
117
|
+
| `servers <placeid>` | List active game servers |
|
|
118
|
+
| `badges <universeid>` | List badges in a game |
|
|
119
|
+
| `catalog <keyword>` | Search the avatar catalog |
|
|
120
|
+
| `robux` | Show your Robux balance (needs cookie) |
|
|
121
|
+
| `save user <id>` | Save user to current DB |
|
|
122
|
+
| `save game <id>` | Save game to current DB |
|
|
123
|
+
| `history` | Show command history |
|
|
124
|
+
| `clear` | Clear the screen |
|
|
125
|
+
| `exit` | Close the session |
|
|
126
|
+
|
|
127
|
+
**Example session:**
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
» start 156
|
|
131
|
+
» game 2753915549
|
|
132
|
+
» friends 156
|
|
133
|
+
» likes 2753915549
|
|
134
|
+
» newdb mydata
|
|
135
|
+
» save user 156
|
|
136
|
+
» loaddb mydata
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Programmatic Usage
|
|
142
|
+
|
|
143
|
+
### Client setup
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from roboat import RoboatClient, ClientBuilder
|
|
147
|
+
|
|
148
|
+
# Simple
|
|
149
|
+
client = RoboatClient()
|
|
150
|
+
client = RoboatClient(cookie="YOUR_.ROBLOSECURITY")
|
|
151
|
+
|
|
152
|
+
# Builder pattern
|
|
153
|
+
client = (
|
|
154
|
+
ClientBuilder()
|
|
155
|
+
.set_cookie("YOUR_.ROBLOSECURITY")
|
|
156
|
+
.set_timeout(15)
|
|
157
|
+
.set_proxy("http://proxy:8080")
|
|
158
|
+
.build()
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
### Users
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
# Get user by ID — returns a User object
|
|
168
|
+
user = client.users.get_user(156)
|
|
169
|
+
print(user) # builderman (@builderman) [ID: 156]
|
|
170
|
+
print(user.name) # builderman
|
|
171
|
+
print(user.visits) # attribute access on typed model
|
|
172
|
+
|
|
173
|
+
# Bulk lookup
|
|
174
|
+
users = client.users.get_users_by_ids([1, 156, 261])
|
|
175
|
+
users = client.users.get_users_by_usernames(["Roblox", "builderman"])
|
|
176
|
+
|
|
177
|
+
# Search
|
|
178
|
+
page = client.users.search_users("builderman", limit=10)
|
|
179
|
+
for user in page:
|
|
180
|
+
print(user)
|
|
181
|
+
|
|
182
|
+
# Username history
|
|
183
|
+
page = client.users.get_username_history(user_id=156)
|
|
184
|
+
|
|
185
|
+
# Authenticated user (requires cookie)
|
|
186
|
+
me = client.users.get_authenticated_user()
|
|
187
|
+
uid = client.user_id()
|
|
188
|
+
name = client.username()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### Games
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# Get game by universe ID — returns a Game object
|
|
197
|
+
game = client.games.get_game(2753915549)
|
|
198
|
+
print(game)
|
|
199
|
+
print(game.visits) # int
|
|
200
|
+
print(game.playing) # int
|
|
201
|
+
|
|
202
|
+
# Resolve from a place ID
|
|
203
|
+
game = client.games.get_game_from_place(place_id=6872265039)
|
|
204
|
+
|
|
205
|
+
# Visit counts as a dict
|
|
206
|
+
visits = client.games.get_visits([2753915549, 286090429])
|
|
207
|
+
# {2753915549: 12345678, 286090429: 987654}
|
|
208
|
+
|
|
209
|
+
# Vote stats
|
|
210
|
+
votes = client.games.get_votes([2753915549])
|
|
211
|
+
print(votes[0]) # 👍 12,345 👎 678 (94.8% positive)
|
|
212
|
+
print(votes[0].ratio) # 94.8
|
|
213
|
+
|
|
214
|
+
# Search
|
|
215
|
+
page = client.games.search_games("obby", limit=20)
|
|
216
|
+
for game in page:
|
|
217
|
+
print(f"{game.name} — {game.visits:,} visits")
|
|
218
|
+
|
|
219
|
+
# Games by user / group
|
|
220
|
+
page = client.games.get_user_games(user_id=156)
|
|
221
|
+
page = client.games.get_group_games(group_id=2868472)
|
|
222
|
+
|
|
223
|
+
# Active servers
|
|
224
|
+
page = client.games.get_servers(place_id=6872265039, limit=10)
|
|
225
|
+
for server in page:
|
|
226
|
+
print(server) # [abc123...] Players: 8/12 FPS: 60.0 Ping: 45ms
|
|
227
|
+
|
|
228
|
+
# Game passes
|
|
229
|
+
page = client.games.get_game_passes(universe_id=2753915549)
|
|
230
|
+
|
|
231
|
+
# Favorite count
|
|
232
|
+
count = client.games.get_favorite_count(universe_id=2753915549)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### Catalog
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
# Search avatar shop — returns Page of CatalogItem
|
|
241
|
+
page = client.catalog.search(
|
|
242
|
+
keyword="fedora",
|
|
243
|
+
category="Accessories",
|
|
244
|
+
sort_type="Sales",
|
|
245
|
+
price_max=500,
|
|
246
|
+
limit=30,
|
|
247
|
+
)
|
|
248
|
+
for item in page:
|
|
249
|
+
print(item)
|
|
250
|
+
|
|
251
|
+
# Single asset or bundle
|
|
252
|
+
item = client.catalog.get_asset(asset_id=1028606)
|
|
253
|
+
item = client.catalog.get_bundle(bundle_id=192)
|
|
254
|
+
|
|
255
|
+
# Resale data for limiteds
|
|
256
|
+
resale = client.catalog.get_resale_data(asset_id=1028606)
|
|
257
|
+
print(resale) # 📈 RAP: 12,500R$ Sales: 3,421 ...
|
|
258
|
+
|
|
259
|
+
# Current resellers
|
|
260
|
+
page = client.catalog.get_resellers(asset_id=1028606)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### Groups
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
# Group info — returns Group object
|
|
269
|
+
group = client.groups.get_group(2868472)
|
|
270
|
+
print(group)
|
|
271
|
+
|
|
272
|
+
# Roles — returns list of GroupRole
|
|
273
|
+
roles = client.groups.get_roles(2868472)
|
|
274
|
+
for role in roles:
|
|
275
|
+
print(role) # [Rank 255] Owner (1 members)
|
|
276
|
+
|
|
277
|
+
# Members
|
|
278
|
+
page = client.groups.get_members(2868472, limit=100)
|
|
279
|
+
page = client.groups.get_members(2868472, role_id=12345)
|
|
280
|
+
|
|
281
|
+
# User's groups
|
|
282
|
+
groups = client.groups.get_user_groups(user_id=156)
|
|
283
|
+
|
|
284
|
+
# Wall
|
|
285
|
+
page = client.groups.get_wall(2868472, limit=10)
|
|
286
|
+
|
|
287
|
+
# Search
|
|
288
|
+
page = client.groups.search("builders")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### Friends
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
# Friends list — returns list of Friend objects
|
|
297
|
+
friends = client.friends.get_friends(user_id=156)
|
|
298
|
+
for f in friends:
|
|
299
|
+
print(f) # 🟢 Builderman (@builderman) [ID: 156]
|
|
300
|
+
|
|
301
|
+
# Counts
|
|
302
|
+
fc = client.friends.get_friend_count(156)
|
|
303
|
+
flc = client.friends.get_follower_count(156)
|
|
304
|
+
fgc = client.friends.get_following_count(156)
|
|
305
|
+
|
|
306
|
+
# Paginated followers / followings
|
|
307
|
+
page = client.friends.get_followers(156, limit=100)
|
|
308
|
+
page = client.friends.get_followings(156, limit=100)
|
|
309
|
+
|
|
310
|
+
# Actions (require cookie)
|
|
311
|
+
client.friends.send_friend_request(user_id=12345)
|
|
312
|
+
client.friends.accept_friend_request(user_id=12345)
|
|
313
|
+
client.friends.decline_friend_request(user_id=12345)
|
|
314
|
+
client.friends.unfriend(user_id=12345)
|
|
315
|
+
|
|
316
|
+
# Pending requests (requires cookie)
|
|
317
|
+
page = client.friends.get_friend_requests(limit=20)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### Presence
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
# Single user
|
|
326
|
+
presence = client.presence.get_presence(user_id=156)
|
|
327
|
+
print(presence.status) # "In Game", "Online", "Offline", "In Studio"
|
|
328
|
+
print(presence.last_location) # "Natural Disaster Survival"
|
|
329
|
+
|
|
330
|
+
# Bulk
|
|
331
|
+
presences = client.presence.get_presences([1, 156, 261])
|
|
332
|
+
for p in presences:
|
|
333
|
+
print(f"{p.user_id}: {p.status}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
### Thumbnails
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
# All return {id: url} dicts
|
|
342
|
+
avatars = client.thumbnails.get_user_avatars([1, 156], size="420x420")
|
|
343
|
+
heads = client.thumbnails.get_user_headshots([1, 156])
|
|
344
|
+
icons = client.thumbnails.get_game_icons([2753915549])
|
|
345
|
+
shots = client.thumbnails.get_game_thumbnails([2753915549], count=3)
|
|
346
|
+
assets = client.thumbnails.get_asset_thumbnails([1028606])
|
|
347
|
+
groups = client.thumbnails.get_group_icons([2868472])
|
|
348
|
+
|
|
349
|
+
# Single convenience method
|
|
350
|
+
url = client.thumbnails.get_avatar_url(user_id=156)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### Economy
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
# Robux balance (requires cookie)
|
|
359
|
+
balance = client.economy.get_robux_balance(user_id=156)
|
|
360
|
+
print(balance) # 💎 12,345 Robux
|
|
361
|
+
# shortcut:
|
|
362
|
+
robux = client.robux()
|
|
363
|
+
|
|
364
|
+
# Resale data
|
|
365
|
+
resale = client.economy.get_asset_resale_data(asset_id=1028606)
|
|
366
|
+
page = client.economy.get_asset_resellers(asset_id=1028606)
|
|
367
|
+
|
|
368
|
+
# Group funds (requires cookie + admin)
|
|
369
|
+
balance = client.economy.get_group_funds(group_id=2868472)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### Badges
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
# Badge info
|
|
378
|
+
badge = client.badges.get_badge(badge_id=2124445228)
|
|
379
|
+
print(badge)
|
|
380
|
+
|
|
381
|
+
# All badges in a game
|
|
382
|
+
page = client.badges.get_universe_badges(universe_id=2753915549)
|
|
383
|
+
|
|
384
|
+
# Badges a user has earned
|
|
385
|
+
page = client.badges.get_user_badges(user_id=156)
|
|
386
|
+
|
|
387
|
+
# When specific badges were awarded
|
|
388
|
+
dates = client.badges.get_awarded_dates(
|
|
389
|
+
user_id=156,
|
|
390
|
+
badge_ids=[2124445228, 2124445229],
|
|
391
|
+
)
|
|
392
|
+
# {2124445228: "2022-01-15T10:30:00Z", ...}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
### Avatar
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
# Full avatar info
|
|
401
|
+
avatar = client.avatar.get_user_avatar(user_id=156)
|
|
402
|
+
print(avatar.avatar_type) # "R15"
|
|
403
|
+
print(avatar.scales) # {"height": 1.0, "width": 1.0, ...}
|
|
404
|
+
print(len(avatar.assets)) # number of equipped items
|
|
405
|
+
|
|
406
|
+
# Outfits
|
|
407
|
+
outfits = client.avatar.get_user_outfits(user_id=156)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Local Database
|
|
413
|
+
|
|
414
|
+
```python
|
|
415
|
+
from roboat import SessionDatabase
|
|
416
|
+
|
|
417
|
+
# Create / load
|
|
418
|
+
db = SessionDatabase.create("myproject")
|
|
419
|
+
db = SessionDatabase.load("myproject")
|
|
420
|
+
db = SessionDatabase.load_or_create("myproject")
|
|
421
|
+
|
|
422
|
+
# List all local databases
|
|
423
|
+
names = SessionDatabase.list_databases()
|
|
424
|
+
|
|
425
|
+
# Save API objects
|
|
426
|
+
db.save_user(user)
|
|
427
|
+
db.save_game(game)
|
|
428
|
+
|
|
429
|
+
# Retrieve cached data
|
|
430
|
+
user_dict = db.get_user(156)
|
|
431
|
+
game_dict = db.get_game(2753915549)
|
|
432
|
+
all_users = db.get_all_users()
|
|
433
|
+
all_games = db.get_all_games()
|
|
434
|
+
|
|
435
|
+
# Key-value store
|
|
436
|
+
db.set("last_run", "2024-01-01")
|
|
437
|
+
val = db.get("last_run")
|
|
438
|
+
|
|
439
|
+
# Stats
|
|
440
|
+
print(db.stats())
|
|
441
|
+
# {'users': 10, 'games': 5, 'session_keys': 3, 'log_entries': 42}
|
|
442
|
+
|
|
443
|
+
db.close()
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## Pagination
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
cursor = None
|
|
452
|
+
all_followers = []
|
|
453
|
+
|
|
454
|
+
while True:
|
|
455
|
+
page = client.friends.get_followers(user_id=156, limit=100, cursor=cursor)
|
|
456
|
+
all_followers.extend(page.data)
|
|
457
|
+
cursor = page.next_cursor
|
|
458
|
+
if not cursor:
|
|
459
|
+
break
|
|
460
|
+
|
|
461
|
+
print(f"Total: {len(all_followers)}")
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Error Handling
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from roboat import (
|
|
470
|
+
RobloxAPIError,
|
|
471
|
+
UserNotFoundError,
|
|
472
|
+
NotAuthenticatedError,
|
|
473
|
+
RateLimitedError,
|
|
474
|
+
InvalidCookieError,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
try:
|
|
478
|
+
user = client.users.get_user(99999999999)
|
|
479
|
+
except UserNotFoundError:
|
|
480
|
+
print("User not found")
|
|
481
|
+
except RateLimitedError:
|
|
482
|
+
print("Rate limited — slow down")
|
|
483
|
+
except NotAuthenticatedError as e:
|
|
484
|
+
print(f"Need cookie: {e}")
|
|
485
|
+
except RobloxAPIError as e:
|
|
486
|
+
print(f"API error: {e}")
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Authentication
|
|
492
|
+
|
|
493
|
+
Get your `.ROBLOSECURITY` cookie by logging into roblox.com and copying it from browser DevTools → Application → Cookies.
|
|
494
|
+
|
|
495
|
+
> ⚠️ **Never share your `.ROBLOSECURITY` cookie.** It gives full account access.
|
|
496
|
+
|
|
497
|
+
```python
|
|
498
|
+
client = RoboatClient(cookie="_|WARNING:-DO-NOT-SHARE-THIS-...")
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## License
|
|
504
|
+
|
|
505
|
+
MIT
|