Skip to content

Commit e83626c

Browse files
committed
catalog: init
1 parent f795f75 commit e83626c

File tree

2 files changed

+196
-1
lines changed

2 files changed

+196
-1
lines changed

roblox/catalog.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
3+
This module contains classes intended to parse and deal with data from Roblox catalog endpoint.
4+
5+
"""
6+
from __future__ import annotations
7+
from datetime import datetime
8+
9+
from typing import TYPE_CHECKING
10+
11+
if TYPE_CHECKING:
12+
from .client import Client
13+
from typing import Optional
14+
from .bases.basecatalogitem import BaseCatalogItem
15+
from .bases.baseuser import BaseUser
16+
from .assets import AssetType
17+
from .partials.partialgroup import PartialGroup
18+
from .partials.partialuser import CatalogCreatorPartialUser
19+
20+
21+
item_type_names = {
22+
1: "Asset",
23+
2: "Bundle"
24+
}
25+
26+
class CatalogItemType:
27+
"""
28+
Represents a catalog item type.
29+
30+
Attributes:
31+
id: Id of the item type
32+
name: Name of the item type
33+
"""
34+
35+
def __init__(self, type_id: int):
36+
"""
37+
Arguments:
38+
type_id: The itemType ID to instantiate this CatalogItemType object with.
39+
This is used to determine the name of the CatalogItemType.
40+
"""
41+
42+
self.id: int = type_id
43+
self.name: Optional[str] = item_type_names.get(type_id)
44+
45+
def __repr__(self):
46+
return f"<{self.__class__.__name__} id={self.id} name={self.name!r}>"
47+
48+
49+
class CatalogItemPremiumPricing:
50+
"""
51+
Represents a catalog item's pricing for Roblox Premium subscribers.
52+
53+
Attributes:
54+
robux: Price of the
55+
name: Name of the item type
56+
"""
57+
58+
def __init__(self, robux: int, percentage: int):
59+
"""
60+
Arguments:
61+
type_id: The itemType ID to instantiate this CatalogItemType object with.
62+
This is used to determine the name of the CatalogItemType.
63+
"""
64+
65+
self.robux: int = robux
66+
self.percentage: int = percentage
67+
68+
def __repr__(self):
69+
return f"<{self.__class__.__name__} robux={self.robux} percentage={self.percentage}>"
70+
71+
72+
73+
class CatalogItem(BaseCatalogItem):
74+
"""
75+
Represents a Catalog/Avatar Shop/Marketplace item.
76+
77+
Attributes:
78+
id: The item's ID.
79+
name: The item's name.
80+
item_type: The item's type as an instance of CatalogItemType.
81+
asset_type: The asset's type as an instance of AssetType
82+
description: The item's description.
83+
image_url: A link to the item's image.
84+
creator: A class representing the creator of the item.
85+
price: The price of the item, in Robux.
86+
"""
87+
88+
def __init__(self, client: Client, data: dict):
89+
self._client: Client = client
90+
self.id: int = data["id"]
91+
self.item_type = CatalogItemType(data["itemType"])
92+
super().__init__(client=self._client, catalog_item_id=self.id, catalog_item_type=self.item_type)
93+
94+
self.name: str = data["name"]
95+
self.description: str = data["description"]
96+
97+
self.asset_type: AssetType = AssetType(type_id=data["assetType"])
98+
99+
self.is_offsale: bool = data["isOffsale"]
100+
101+
# Creator
102+
self.creator: CatalogCreatorPartialUser or CatalogCreatorPartialGroup
103+
if data["creatorType"] == "User":
104+
self.creator = CatalogCreatorPartialUser(client=client, data=data)
105+
elif data["creatorType"] == "Group":
106+
self.creator = CatalogCreatorPartialGroup(client=client, group_id=data)
107+
108+
self.price: int = data["price"]
109+
self.purchase_count: int = data["purchaseCount"]
110+
self.favorite_count: int = data["favoriteCount"]
111+
self.sale_location_type: str = data["saleLocationType"]
112+
113+
114+
115+
if data["premiumPricing"]:
116+
self.premium_pricing = {}
117+
self.premium_pricing.in_robux: int = data["premiumPricing"]["premiumPriceInRobux"]
118+
self.premium_pricing.discount_percentage: int = data["premiumPricing"]["premiumDiscountPercentage"]
119+
120+
121+
def __repr__(self):
122+
return f"<{self.__class__.__name__} name={self.name!r}>"
123+
124+
125+
class LimitedCatalogItem(CatalogItem):
126+
"""
127+
Represents a limited Catalog/Avatar Shop/Marketplace item.
128+
129+
Attributes:
130+
id: The item's ID.
131+
name: The item's name.
132+
item_type: The item's type as an instance of CatalogItemType.
133+
asset_type: The asset's type as an instance of AssetType
134+
description: The item's description.
135+
image_url: A link to the item's image.
136+
creator: A class representing the creator of the item.
137+
price: The price of the item, in Robux.
138+
"""
139+
140+
def __init__(self, client=client, data=data):
141+
super.__init__(client=client, data=data)
142+
143+
self.collectible_item_id: str = data["collectibleItemId"]
144+
self.quantity_limit_per_user: int = data["quantityLimitPerUser"]
145+
self.units_available_for_consumption: int = data["unitsAvailableForConsumption"]
146+
self.total_quantity: int = data["totalQuantity"]
147+
self.has_resellers: bool = data["hasResellers"]
148+
self.offsale_deadline: Optional[datetime] = datetime.fromtimestamp(data["offsaleDeadline"])
149+
self.lowest_price: int = data["lowestPrice"]
150+
self.lowest_resale_price: int = data["lowestResalePrice"]
151+
self.price_status: str = data["priceStatus"]

roblox/client.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
"""
66

7-
from typing import Union, List, Optional
7+
from typing import Union, List, Optional, Literal, TypedDict
88

99
from .account import AccountProvider
1010
from .assets import EconomyAsset
@@ -550,3 +550,47 @@ def get_base_gamepass(self, gamepass_id: int) -> BaseGamePass:
550550
Returns: A BaseGamePass.
551551
"""
552552
return BaseGamePass(client=self, gamepass_id=gamepass_id)
553+
554+
# Catalog
555+
def get_catalog_items(self, catalog_item_array: List[TypedDict[catalog_id: int, catalog_item_type: Literal[1, 2]]]) -> List[CatalogItem]:
556+
"""
557+
Gets a catalog item with the passed ID.
558+
559+
The catalog is also known as the Avatar Shop or the Marketplace.
560+
561+
Arguments:
562+
catalog_id: A Roblox catalog item ID.
563+
catalog_item_type: The type of item. 1 for an asset, and 2 for a bundle.
564+
565+
Returns:
566+
A list of CatalogItem.
567+
"""
568+
try:
569+
catalog_item_response = await self._requests.post(
570+
url=self._url_generator.get_url(
571+
"catalog", "v1/catalog/items/details"
572+
),
573+
data={"data": catalog_item_array}
574+
)
575+
except NotFound as exception:
576+
raise CatalogItemNotFound(
577+
message="Invalid catalog item.",
578+
response=exception.response
579+
) from None
580+
catalog_item_data = catalog_item_response.json()
581+
catalog_list: Literal[CatalogItem] = []
582+
for catalog_item in catalog_item_data:
583+
if data["collectibleItemId"]: # This is the only consistent indicator of an item's limited status
584+
catalog_list.append(LimitedCatalogItem(client=self, data=catalog_item))
585+
else:
586+
catalog_list.append(CatalogItem(client=self, data=catalog_item))
587+
588+
return catalog_list
589+
590+
def get_base_catalog_items(self, catalog_item_array: List[TypedDict[catalog_id: int, catalog_item_type: Literal[1, 2]]]) -> List[CatalogItem]:
591+
catalog_list: Literal[CatalogItem] = []
592+
593+
for catalog_item in catalog_item_array:
594+
catalog_list.append(BaseCatalogItem(client=self, data=catalog_item))
595+
596+
return catalog_list

0 commit comments

Comments
 (0)