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 {}
+            
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 {}
 
@@ -1036,19 +1038,19 @@ failures in the returned BatchResult.

-
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.")
+            
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.")
 
@@ -1068,9 +1070,9 @@ failures in the returned BatchResult.

-
360    async def close(self):
-361        """Close the underlying HTTP client."""
-362        await self._http.aclose()
+            
361    async def close(self):
+362        """Close the underlying HTTP client."""
+363        await self._http.aclose()