Skip to content

Commit e93aa7c

Browse files
committed
catalog: init
1 parent f795f75 commit e93aa7c

2 files changed

Lines changed: 182 additions & 1 deletion

File tree

roblox/catalog.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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 CatalogItem(BaseCatalogItem):
50+
"""
51+
Represents a Catalog/Avatar Shop/Marketplace item.
52+
53+
Attributes:
54+
id: The item's ID.
55+
name: The item's name.
56+
item_type: The item's type as an instance of CatalogItemType.
57+
asset_type: The asset's type as an instance of AssetType
58+
description: The item's description.
59+
is_offsale: If the item is offsale.
60+
creator: A class representing the creator of the item.
61+
price: The price of the item, in Robux.
62+
purchase_count: The number of times the item has been purchased.
63+
favorite_count: The number of times the item has been favorited.
64+
sale_location_type: Unknown.
65+
premium_pricing: A dictionary storing information about pricing for Roblox Premium members.
66+
premium_pricing.in_robux: The pricing for Roblox Premium members, in Robux.
67+
premium_pricing.discount_percentage: The percentage that Roblox Premium members get discounted.
68+
"""
69+
70+
def __init__(self, client: Client, data: dict):
71+
self._client: Client = client
72+
self.id: int = data["id"]
73+
self.item_type = CatalogItemType(data["itemType"])
74+
super().__init__(client=self._client, catalog_item_id=self.id, catalog_item_type=self.item_type)
75+
76+
self.name: str = data["name"]
77+
self.description: str = data["description"]
78+
79+
self.asset_type: AssetType = AssetType(type_id=data["assetType"])
80+
81+
self.is_offsale: bool = data["isOffsale"]
82+
83+
# Creator
84+
self.creator: CatalogCreatorPartialUser or CatalogCreatorPartialGroup
85+
if data["creatorType"] == "User":
86+
self.creator = CatalogCreatorPartialUser(client=client, data=data)
87+
elif data["creatorType"] == "Group":
88+
self.creator = CatalogCreatorPartialGroup(client=client, group_id=data)
89+
90+
self.price: int = data["price"]
91+
self.purchase_count: int = data["purchaseCount"]
92+
self.favorite_count: int = data["favoriteCount"]
93+
self.sale_location_type: str = data["saleLocationType"]
94+
95+
96+
97+
if data["premiumPricing"]:
98+
self.premium_pricing = {}
99+
self.premium_pricing.in_robux: int = data["premiumPricing"]["premiumPriceInRobux"]
100+
self.premium_pricing.discount_percentage: int = data["premiumPricing"]["premiumDiscountPercentage"]
101+
102+
103+
def __repr__(self):
104+
return f"<{self.__class__.__name__} name={self.name!r}>"
105+
106+
107+
class LimitedCatalogItem(CatalogItem):
108+
"""
109+
Represents a limited Catalog/Avatar Shop/Marketplace item.
110+
111+
See also:
112+
CatalogItem, which this class inherits.
113+
114+
Attributes:
115+
collectible_item_id: Unknown.
116+
quantity_limit_per_user: The maximum number of this item that a user can own.
117+
units_available_for_consumption: The amount of items that can be bought by all users.
118+
total_quantity: The amount of items that are owned or can be purchased.
119+
has_resellers: If the item has resellers.
120+
offsale_deadline: The time that an item goes offsale (as an instance of a datetime.datetime object).
121+
lowest_price: The lowest price, in Robux, offered to obtain this item.
122+
lowest_resale_price: The lowest resale price, in Robux, offered to obtain this item.
123+
price_status: Unknown.
124+
"""
125+
126+
def __init__(self, client=client, data=data):
127+
super.__init__(client=client, data=data)
128+
129+
self.collectible_item_id: str = data["collectibleItemId"]
130+
self.quantity_limit_per_user: int = data["quantityLimitPerUser"]
131+
self.units_available_for_consumption: int = data["unitsAvailableForConsumption"]
132+
self.total_quantity: int = data["totalQuantity"]
133+
self.has_resellers: bool = data["hasResellers"]
134+
self.offsale_deadline: Optional[datetime] = datetime.fromtimestamp(data["offsaleDeadline"])
135+
self.lowest_price: int = data["lowestPrice"]
136+
self.lowest_resale_price: int = data["lowestResalePrice"]
137+
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)