feat: add batch upload, CLI, and exception hierarchy
- Add RbxError base class with AuthError, RateLimitError, UploadError, and AssetNotFoundError subclasses - Add BatchUploadItem and BatchResult dataclasses - Add batch_upload method with semaphore-limited concurrency (2 at a time) - Add configurable max_attempts and poll_interval to upload_clothing_image - Add CLI with upload and onsale commands (rbx-upload[cli] extra) - Improve auth error handling across all client methods - Bump version to 0.2.0
This commit is contained in:
@@ -8,6 +8,12 @@ Async Python client for (re)uploading and managing Roblox assets.
|
||||
uv add rbx-upload
|
||||
```
|
||||
|
||||
With CLI support:
|
||||
|
||||
```bash
|
||||
uv add "rbx-upload[cli]"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
@@ -43,17 +49,82 @@ async with RobloxClient(
|
||||
)
|
||||
```
|
||||
|
||||
### Batch upload
|
||||
|
||||
```python
|
||||
from rbx_upload import RobloxClient, RbxAssetType, BatchUploadItem
|
||||
|
||||
items = [
|
||||
BatchUploadItem(image=img1, name="Shirt A", asset_type=RbxAssetType.SHIRT, group_id=67890),
|
||||
BatchUploadItem(image=img2, name="Shirt B", asset_type=RbxAssetType.SHIRT, group_id=67890),
|
||||
BatchUploadItem(image=img3, name="Pants A", asset_type=RbxAssetType.PANTS, group_id=67890),
|
||||
]
|
||||
|
||||
async with RobloxClient(roblosecurity="...", publisher_user_id=12345) as client:
|
||||
result = await client.batch_upload(items)
|
||||
|
||||
for item, upload in result.succeeded:
|
||||
print(f"{item.name}: asset_id={upload['asset_id']}")
|
||||
|
||||
for item, error in result.failed:
|
||||
print(f"{item.name} failed: {error}")
|
||||
```
|
||||
|
||||
### Error handling
|
||||
|
||||
```python
|
||||
from rbx_upload import AuthError, RateLimitError, UploadError, AssetNotFoundError
|
||||
|
||||
try:
|
||||
result = await client.upload_clothing_image(...)
|
||||
except AuthError:
|
||||
# Invalid or expired ROBLOSECURITY token
|
||||
...
|
||||
except RateLimitError:
|
||||
# Hit rate limit, back off and retry
|
||||
...
|
||||
except UploadError:
|
||||
# Upload operation timed out or failed
|
||||
...
|
||||
```
|
||||
|
||||
## CLI
|
||||
|
||||
Requires `pip install "rbx-upload[cli]"`. Set `ROBLOSECURITY` in your environment.
|
||||
|
||||
```bash
|
||||
# Upload a clothing image
|
||||
rbx-upload upload shirt.png --name "My Shirt" --group 67890 --publisher 12345
|
||||
|
||||
# Put an asset on sale
|
||||
rbx-upload onsale 123456789 --name "My Shirt" --group 67890 --publisher 12345 --price 10
|
||||
```
|
||||
|
||||
Run `rbx-upload --help` or `rbx-upload <command> --help` for all options.
|
||||
|
||||
## API
|
||||
|
||||
### `RobloxClient(roblosecurity, publisher_user_id, proxy=None)`
|
||||
|
||||
All methods are async
|
||||
All methods are async.
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `asset_from_id(asset_id)` | Fetch asset info. Returns `ClothingAsset` for shirts/pants, `RbxAsset` otherwise. |
|
||||
| `fetch_clothing_image(asset)` | Fetch raw PNG bytes for a clothing asset. |
|
||||
| `upload_clothing_image(image, name, description, asset_type, group_id)` | Upload a clothing image. Returns `{"asset_id": int}`. |
|
||||
| `upload_clothing_image(image, name, description, asset_type, group_id, max_attempts=10, poll_interval=1.0)` | Upload a clothing image. Returns `{"asset_id": int}`. |
|
||||
| `batch_upload(items, max_attempts=10, poll_interval=1.0)` | Upload multiple items (2 at a time). Returns `BatchResult`. |
|
||||
| `onsale_asset(asset_id, name, description, group_id, price=5)` | Put an asset on sale. |
|
||||
|
||||
`proxy` replaces `roblox.com` in all URLs
|
||||
`proxy` replaces `roblox.com` in all URLs.
|
||||
|
||||
### Exceptions
|
||||
|
||||
All exceptions inherit from `RbxError`.
|
||||
|
||||
| Exception | When raised |
|
||||
|---|---|
|
||||
| `AuthError` | Invalid/expired token or not authorized |
|
||||
| `RateLimitError` | HTTP 429 from Roblox |
|
||||
| `UploadError` | Upload operation timed out |
|
||||
| `AssetNotFoundError` | Asset ID does not exist |
|
||||
|
||||
Reference in New Issue
Block a user