Skip to content

search_place/search_places & place Class modified for it #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions examples/place_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
Grabs multiple places' information. with just the a keyword
A cookie is not required to grab places' information.
Please note that its roblox that gives builder info as ""
"""

import asyncio
from roblox import Client
client = Client()


async def main():
# ==== for 1 place ====

# place = await client.search_place('Phantom forces')
# print("ID:", place.id)
# print("\tName:", place.name)
# print(f"\tDescription: {place.description!r}")
# print("\tPlayable:", place.is_playable)
# if not place.is_playable:
# print("\tReason:", place.reason_prohibited)
# if place.price > 0:
# print("\tPrice:", place.price)
# print("\tCreator:", place.builder)

# ==== for multiple places ====

places = await client.search_places('Phantom forces')
for place in places:
print("ID:", place.id)
print("\tName:", place.name)
print(f"\tDescription: {place.description!r}")
print("\tPlayable:", place.is_playable)
if not place.is_playable:
print("\tReason:", place.reason_prohibited)
if place.price > 0:
print("\tPrice:", place.price)

print("\tCreator:", place.builder)


asyncio.get_event_loop().run_until_complete(main())
65 changes: 62 additions & 3 deletions roblox/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from .utilities.iterators import PageIterator
from .utilities.requests import Requests
from .utilities.url import URLGenerator
import time


class Client:
Expand Down Expand Up @@ -179,7 +180,8 @@ async def get_users_by_usernames(
"""
users_response = await self._requests.post(
url=self._url_generator.get_url("users", f"v1/usernames/users"),
json={"usernames": usernames, "excludeBannedUsers": exclude_banned_users},
json={"usernames": usernames,
"excludeBannedUsers": exclude_banned_users},
)
users_data = users_response.json()["data"]

Expand Down Expand Up @@ -250,7 +252,8 @@ def user_search(self, keyword: str, page_size: int = 10,
page_size=page_size,
max_items=max_items,
extra_parameters={"keyword": keyword},
handler=lambda client, data: PreviousUsernamesPartialUser(client=client, data=data),
handler=lambda client, data: PreviousUsernamesPartialUser(
client=client, data=data),
)

# Groups
Expand All @@ -266,7 +269,8 @@ async def get_group(self, group_id: int) -> Group:
"""
try:
group_response = await self._requests.get(
url=self._url_generator.get_url("groups", f"v1/groups/{group_id}")
url=self._url_generator.get_url(
"groups", f"v1/groups/{group_id}")
)
except BadRequest as exception:
raise GroupNotFound(
Expand Down Expand Up @@ -383,6 +387,61 @@ async def get_place(self, place_id: int) -> Place:
except IndexError:
raise PlaceNotFound("Invalid place.") from None

async def search_places(self, keyword: str, max_items: int = 25) -> List[Place]:
"""
Grabs a list of places corresponding to each ID in the list.

Arguments:
keyword: game(s) name
max_items: amount of games to be searched with similar keyword

Returns:
A list of Places.
"""

# max_items=25 cuz at one point roblox somehow gives goofy ahh games that are some how related to the keyword. At 1000 it will start to give slightly related games
# also please note, this api has like no ratelimit while i was testing. its the same endpoint when u scroll down searching for a game in roblox UI
# so far i have gotten like 5k games withen a few mins, and no ratelimit at all.

itemsFound = {}

nextPagetoken = None
# roblox will use this to prevent games that have already been showen
sessionID = round(time.time())
while len(itemsFound.keys()) <= max_items:
places_response = await self._requests.get(
url=self._url_generator.get_url(
"apis", f"search-api/omni-search"
),
params={"searchQuery": keyword,
"pageToken": nextPagetoken, 'sessionId': sessionID, 'pageType': 'all'},
)
places_data = places_response.json()
for gameJSON in places_data['searchResults']:
# the json is weird for this endpoint so i had to modify places.py
game = Place(client=self, data=gameJSON['contents'][0])
itemsFound[game.id] = game
nextPagetoken = places_data['nextPageToken']

# without [:max_items] it will give like 40+ its not exact
return [value for value in itemsFound.values()][:max_items]

async def search_place(self, keyword: str) -> Place:
'''
Could just use the other api for this, but already made search_places
search_places is already there so i just use [0]
[0] is always the best game (roblox already sorts it out)

Arguments:
keyword: Game name you want to search

Returns:
First result of game search

'''
game = await self.search_places(keyword, 1)
return game[0]

def get_base_place(self, place_id: int) -> BasePlace:
"""
Gets a base place.
Expand Down
36 changes: 23 additions & 13 deletions roblox/places.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,36 @@ def __init__(self, client: Client, data: dict):
client: The Client object, which is passed to all objects this Client generates.
data: data to make the magic happen.
"""
super().__init__(client=client, place_id=data["placeId"])
super().__init__(client=client, place_id=data.get(
'placeId') or data.get('rootPlaceId'))

# sorry for goofy ahh changes, but it will work with other functions. This is just support to place search endpoint

self._client: Client = client

self.id: int = data["placeId"]
self.id: int = data.get('placeId') or data.get('rootPlaceId')
self.name: str = data["name"]
self.description: str = data["description"]
self.url: str = data["url"]

self.builder: str = data["builder"]
self.builder_id: int = data["builderId"]
self.url: str = data.get(
'url') or f'https://www.roblox.com/games/{self.id}' # roblox would redirect automaticly if given just ID

self.is_playable: bool = data["isPlayable"]
self.reason_prohibited: str = data["reasonProhibited"]
self.universe: BaseUniverse = BaseUniverse(client=self._client, universe_id=data["universeId"])
self.universe_root_place: BasePlace = BasePlace(client=self._client, place_id=data["universeRootPlaceId"])
# the builder in place search is messed up (roblox side), for some reason only the top game and some games only return an actuall name. but rest just returns ""
self.builder: str = data.get('builder') or data.get('creatorName')
self.builder_id: int = data.get("builderId") or data.get('creatorId')

self.price: int = data["price"]
self.image_token: str = data["imageToken"]
self.has_verified_badge: bool = data["hasVerifiedBadge"]
self.is_playable: bool = data.get("isPlayable") or True
self.reason_prohibited: str = data.get("reasonProhibited")
self.universe: BaseUniverse = BaseUniverse(
client=self._client, universe_id=data["universeId"])
if data.get('universeRootPlaceId'): # not given in search endpoint
self.universe_root_place: BasePlace = BasePlace(
client=self._client, place_id=data["universeRootPlaceId"])
else:
self.universe_root_place = None
self.price: int = data.get("price") or 0
self.image_token: str = data.get("imageToken")
self.has_verified_badge: bool = data.get(
"hasVerifiedBadge") or data.get('creatorHasVerifiedBadge')

def __repr__(self):
return f"<{self.__class__.__name__} id={self.id} name={self.name!r}>"
1 change: 0 additions & 1 deletion roblox/utilities/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ async def request(self, method: str, *args, **kwargs) -> Response:
except JSONDecodeError:
pass
errors = data and data.get("errors")

exception = get_exception_from_status_code(response.status_code)(
response=response,
errors=errors
Expand Down