diff --git a/docs/rbx_upload.html b/docs/rbx_upload.html index ecae2be..2bb9ca9 100644 --- a/docs/rbx_upload.html +++ b/docs/rbx_upload.html @@ -543,68 +543,69 @@ rbx_upload 304 data = response.json() 305 collectible_item_id = data.get("collectibleItemId") 306 if not collectible_item_id: -307 raise UploadError(f"publish_collectible did not return a collectibleItemId: {data}") -308 return collectible_item_id -309 -310 async def onsale_asset( -311 self, -312 collectible_item_id: str, -313 price: int = 5, -314 ) -> dict: -315 """Put an asset on sale.""" -316 csrf = await self._get_csrf_token() -317 response = await self._http.patch( -318 f"https://itemconfiguration.roblox.com/v1/collectibles/{collectible_item_id}", -319 json={ -320 "saleLocationConfiguration": {"saleLocationType": 1, "places": []}, -321 "saleStatus": 0, -322 "quantityLimitPerUser": 0, -323 "resaleRestriction": 2, -324 "priceInRobux": price, -325 "priceOffset": 0, -326 "optOutFromRegionalPricing": False, -327 "isFree": False, -328 }, -329 headers={ -330 "X-CSRF-TOKEN": csrf, -331 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", -332 "Referer": "https://create.roblox.com/", -333 "Origin": "https://create.roblox.com", -334 }, -335 cookies=self._csrf_cookies, -336 ) -337 -338 if response.status_code == 429: -339 raise RateLimitError("Rate limit hit during onsale.") -340 if response.status_code in (401, 403): -341 raise AuthError("Not authorized to put this asset on sale.") -342 -343 response.raise_for_status() -344 return response.json() if response.text else {} -345 -346 async def get_collectible_item_id(self, asset_id: int, max_attempts: int = 10, poll_interval: float = 3.0) -> str: -347 """Look up the collectible item ID (UUID) for a given asset ID, retrying until available.""" -348 for _ in range(max_attempts): -349 response = await self._http.get( -350 f"https://itemconfiguration.roblox.com/v1/collectibles/0/{asset_id}", -351 cookies=self._csrf_cookies, -352 ) -353 response.raise_for_status() -354 collectible_item_id = response.json().get("collectibleItemId") -355 if collectible_item_id: -356 return collectible_item_id -357 await asyncio.sleep(poll_interval) -358 raise UploadError(f"collectibleItemId not available for asset {asset_id} after {max_attempts} attempts.") -359 -360 async def close(self): -361 """Close the underlying HTTP client.""" -362 await self._http.aclose() -363 -364 async def __aenter__(self): -365 return self -366 -367 async def __aexit__(self, *args): -368 await self.close() +307 # status=0 means already published — look up the ID +308 collectible_item_id = await self.get_collectible_item_id(asset_id) +309 return collectible_item_id +310 +311 async def onsale_asset( +312 self, +313 collectible_item_id: str, +314 price: int = 5, +315 ) -> dict: +316 """Put an asset on sale.""" +317 csrf = await self._get_csrf_token() +318 response = await self._http.patch( +319 f"https://itemconfiguration.roblox.com/v1/collectibles/{collectible_item_id}", +320 json={ +321 "saleLocationConfiguration": {"saleLocationType": 1, "places": []}, +322 "saleStatus": 0, +323 "quantityLimitPerUser": 0, +324 "resaleRestriction": 2, +325 "priceInRobux": price, +326 "priceOffset": 0, +327 "optOutFromRegionalPricing": False, +328 "isFree": False, +329 }, +330 headers={ +331 "X-CSRF-TOKEN": csrf, +332 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", +333 "Referer": "https://create.roblox.com/", +334 "Origin": "https://create.roblox.com", +335 }, +336 cookies=self._csrf_cookies, +337 ) +338 +339 if response.status_code == 429: +340 raise RateLimitError("Rate limit hit during onsale.") +341 if response.status_code in (401, 403): +342 raise AuthError("Not authorized to put this asset on sale.") +343 +344 response.raise_for_status() +345 return response.json() if response.text else {} +346 +347 async def get_collectible_item_id(self, asset_id: int, max_attempts: int = 10, poll_interval: float = 3.0) -> str: +348 """Look up the collectible item ID (UUID) for a given asset ID, retrying until available.""" +349 for _ in range(max_attempts): +350 response = await self._http.get( +351 f"https://itemconfiguration.roblox.com/v1/collectibles/0/{asset_id}", +352 cookies=self._csrf_cookies, +353 ) +354 response.raise_for_status() +355 collectible_item_id = response.json().get("collectibleItemId") +356 if collectible_item_id: +357 return collectible_item_id +358 await asyncio.sleep(poll_interval) +359 raise UploadError(f"collectibleItemId not available for asset {asset_id} after {max_attempts} attempts.") +360 +361 async def close(self): +362 """Close the underlying HTTP client.""" +363 await self._http.aclose() +364 +365 async def __aenter__(self): +366 return self +367 +368 async def __aexit__(self, *args): +369 await self.close() @@ -961,8 +962,9 @@ failures in the returned BatchResult.
304 data = response.json() 305 collectible_item_id = data.get("collectibleItemId") 306 if not collectible_item_id: -307 raise UploadError(f"publish_collectible did not return a collectibleItemId: {data}") -308 return collectible_item_id +307 # status=0 means already published — look up the ID +308 collectible_item_id = await self.get_collectible_item_id(asset_id) +309 return collectible_item_id @@ -982,41 +984,41 @@ failures in the returned BatchResult. -310 async def onsale_asset( -311 self, -312 collectible_item_id: str, -313 price: int = 5, -314 ) -> dict: -315 """Put an asset on sale.""" -316 csrf = await self._get_csrf_token() -317 response = await self._http.patch( -318 f"https://itemconfiguration.roblox.com/v1/collectibles/{collectible_item_id}", -319 json={ -320 "saleLocationConfiguration": {"saleLocationType": 1, "places": []}, -321 "saleStatus": 0, -322 "quantityLimitPerUser": 0, -323 "resaleRestriction": 2, -324 "priceInRobux": price, -325 "priceOffset": 0, -326 "optOutFromRegionalPricing": False, -327 "isFree": False, -328 }, -329 headers={ -330 "X-CSRF-TOKEN": csrf, -331 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", -332 "Referer": "https://create.roblox.com/", -333 "Origin": "https://create.roblox.com", -334 }, -335 cookies=self._csrf_cookies, -336 ) -337 -338 if response.status_code == 429: -339 raise RateLimitError("Rate limit hit during onsale.") -340 if response.status_code in (401, 403): -341 raise AuthError("Not authorized to put this asset on sale.") -342 -343 response.raise_for_status() -344 return response.json() if response.text else {} +@@ -1036,19 +1038,19 @@ failures in the returned BatchResult.311 async def onsale_asset( +312 self, +313 collectible_item_id: str, +314 price: int = 5, +315 ) -> dict: +316 """Put an asset on sale.""" +317 csrf = await self._get_csrf_token() +318 response = await self._http.patch( +319 f"https://itemconfiguration.roblox.com/v1/collectibles/{collectible_item_id}", +320 json={ +321 "saleLocationConfiguration": {"saleLocationType": 1, "places": []}, +322 "saleStatus": 0, +323 "quantityLimitPerUser": 0, +324 "resaleRestriction": 2, +325 "priceInRobux": price, +326 "priceOffset": 0, +327 "optOutFromRegionalPricing": False, +328 "isFree": False, +329 }, +330 headers={ +331 "X-CSRF-TOKEN": csrf, +332 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0", +333 "Referer": "https://create.roblox.com/", +334 "Origin": "https://create.roblox.com", +335 }, +336 cookies=self._csrf_cookies, +337 ) +338 +339 if response.status_code == 429: +340 raise RateLimitError("Rate limit hit during onsale.") +341 if response.status_code in (401, 403): +342 raise AuthError("Not authorized to put this asset on sale.") +343 +344 response.raise_for_status() +345 return response.json() if response.text else {}
346 async def get_collectible_item_id(self, asset_id: int, max_attempts: int = 10, poll_interval: float = 3.0) -> str: -347 """Look up the collectible item ID (UUID) for a given asset ID, retrying until available.""" -348 for _ in range(max_attempts): -349 response = await self._http.get( -350 f"https://itemconfiguration.roblox.com/v1/collectibles/0/{asset_id}", -351 cookies=self._csrf_cookies, -352 ) -353 response.raise_for_status() -354 collectible_item_id = response.json().get("collectibleItemId") -355 if collectible_item_id: -356 return collectible_item_id -357 await asyncio.sleep(poll_interval) -358 raise UploadError(f"collectibleItemId not available for asset {asset_id} after {max_attempts} attempts.") +@@ -1068,9 +1070,9 @@ failures in the returned BatchResult.347 async def get_collectible_item_id(self, asset_id: int, max_attempts: int = 10, poll_interval: float = 3.0) -> str: +348 """Look up the collectible item ID (UUID) for a given asset ID, retrying until available.""" +349 for _ in range(max_attempts): +350 response = await self._http.get( +351 f"https://itemconfiguration.roblox.com/v1/collectibles/0/{asset_id}", +352 cookies=self._csrf_cookies, +353 ) +354 response.raise_for_status() +355 collectible_item_id = response.json().get("collectibleItemId") +356 if collectible_item_id: +357 return collectible_item_id +358 await asyncio.sleep(poll_interval) +359 raise UploadError(f"collectibleItemId not available for asset {asset_id} after {max_attempts} attempts.")