@@ -78,6 +78,8 @@ class SearchAuthToken:
7878 search_url = "api/s"
7979 search_url_endpoint = "/init"
8080 auth_token = None
81+ auth_key = None
82+ auth_value = None
8183
8284 def extract_auth_token_from_response (self , response_content : requests .Response ):
8385 """
@@ -89,7 +91,15 @@ def extract_auth_token_from_response(self, response_content: requests.Response):
8991
9092 def extract_auth_token_from_json (self , json_content ):
9193 self .auth_token = json_content .get ('token' )
92- return self .auth_token
94+
95+ for field_name , field_value in json_content .items ():
96+ lower = field_name .lower ()
97+ if re .search (r'key' , lower ):
98+ self .auth_key = field_value
99+ elif re .search (r'val' , lower ):
100+ self .auth_value = field_value
101+
102+ return self
93103
94104class HTMLRequests :
95105 BASE_URL = 'https://howlongtobeat.com/'
@@ -99,26 +109,28 @@ class HTMLRequests:
99109 SEARCH_URL = BASE_URL + "api/s/"
100110
101111 @staticmethod
102- def get_search_request_headers (auth_token = None ):
112+ def get_search_request_headers (auth_struct , user_agent ):
103113 """
104114 Generate the headers for the search request
105115 @return: The headers object for the request
106116 """
107- ua = UserAgent ()
108117 headers = {
109118 'content-type' : 'application/json' ,
110119 'accept' : '*/*' ,
111- 'User-Agent' : ua .random .strip (),
112- 'referer' : HTMLRequests .REFERER_HEADER
120+ 'User-Agent' : user_agent ,
121+ 'Referer' : HTMLRequests .REFERER_HEADER ,
122+ 'Origin' : HTMLRequests .REFERER_HEADER
113123 }
114124
115- if auth_token is not None :
116- headers ['x-auth-token' ] = str (auth_token )
125+ if auth_struct is not None :
126+ headers ['x-auth-token' ] = str (auth_struct .auth_token )
127+ headers ['x-hp-key' ] = str (auth_struct .auth_key )
128+ headers ['x-hp-val' ] = str (auth_struct .auth_value )
117129
118130 return headers
119131
120132 @staticmethod
121- def get_search_request_data (game_name : str , search_modifiers : SearchModifiers , page : int ):
133+ def get_search_request_data (game_name : str , search_modifiers : SearchModifiers , page : int , auth_struct ):
122134 """
123135 Generate the data payload for the search request
124136 @param game_name: The name of the game to search
@@ -167,6 +179,9 @@ def get_search_request_data(game_name: str, search_modifiers: SearchModifiers, p
167179 'useCache' : True
168180 }
169181
182+ if auth_struct is not None :
183+ payload [auth_struct .auth_key ] = auth_struct .auth_value
184+
170185 return json .dumps (payload )
171186
172187 @staticmethod
@@ -179,21 +194,24 @@ def send_web_request(game_name: str, search_modifiers: SearchModifiers = SearchM
179194 @param page: The page to explore of the research, unknown if this is actually used
180195 @return: The HTML code of the research if the request returned 200(OK), None otherwise
181196 """
197+ # Generate a single user agent to use for the whole request
198+ ua = UserAgent ()
199+ request_user_agent = ua .random .strip ()
182200 # Retrieve the updated URL
183- search_info_data = HTMLRequests .send_website_request_getcode (False )
201+ search_info_data = HTMLRequests .send_website_request_getcode (False , request_user_agent )
184202 if search_info_data is None or search_info_data .search_url is None :
185- search_info_data = HTMLRequests .send_website_request_getcode (True )
203+ search_info_data = HTMLRequests .send_website_request_getcode (True , request_user_agent )
186204 # Retrieve the request auth token
187- auth_token = None
205+ auth_struct = None
188206 if search_info_data is not None and search_info_data .search_url is not None :
189- auth_token = HTMLRequests .send_website_get_auth_token (search_info_data .search_url )
207+ auth_struct = HTMLRequests .send_website_get_auth_token (search_info_data .search_url , request_user_agent )
190208 else :
191- auth_token = HTMLRequests .send_website_get_auth_token (None )
209+ auth_struct = HTMLRequests .send_website_get_auth_token (None , request_user_agent )
192210 # Make the request
193- headers = HTMLRequests .get_search_request_headers (auth_token )
211+ headers = HTMLRequests .get_search_request_headers (auth_struct , request_user_agent )
194212 if search_info_data is not None and search_info_data .search_url is not None :
195213 HTMLRequests .SEARCH_URL = HTMLRequests .BASE_URL + search_info_data .search_url
196- payload = HTMLRequests .get_search_request_data (game_name , search_modifiers , page )
214+ payload = HTMLRequests .get_search_request_data (game_name , search_modifiers , page , auth_struct )
197215 resp = requests .post (HTMLRequests .SEARCH_URL , headers = headers , data = payload , timeout = 60 )
198216 if resp .status_code == 200 :
199217 return resp .text
@@ -209,21 +227,24 @@ async def send_async_web_request(game_name: str, search_modifiers: SearchModifie
209227 @param page: The page to explore of the research, unknown if this is actually used
210228 @return: The HTML code of the research if the request returned 200(OK), None otherwise
211229 """
230+ # Generate a single user agent to use for the whole request
231+ ua = UserAgent ()
232+ request_user_agent = ua .random .strip ()
212233 # Retrieve the updated URL
213- search_info_data = HTMLRequests .send_website_request_getcode (False )
234+ search_info_data = HTMLRequests .send_website_request_getcode (False , request_user_agent )
214235 if search_info_data is None or search_info_data .search_url is None :
215- search_info_data = HTMLRequests .send_website_request_getcode (True )
236+ search_info_data = HTMLRequests .send_website_request_getcode (True , request_user_agent )
216237 # Retrieve the request auth token
217- auth_token = None
238+ auth_struct = None
218239 if search_info_data is not None and search_info_data .search_url is not None :
219- auth_token = await HTMLRequests .async_send_website_get_auth_token (search_info_data .search_url )
240+ auth_struct = await HTMLRequests .async_send_website_get_auth_token (search_info_data .search_url , request_user_agent )
220241 else :
221- auth_token = await HTMLRequests .async_send_website_get_auth_token (None )
242+ auth_struct = await HTMLRequests .async_send_website_get_auth_token (None , request_user_agent )
222243 # Make the request
223- headers = HTMLRequests .get_search_request_headers (auth_token )
244+ headers = HTMLRequests .get_search_request_headers (auth_struct , request_user_agent )
224245 if search_info_data is not None and search_info_data .search_url is not None :
225246 HTMLRequests .SEARCH_URL = HTMLRequests .BASE_URL + search_info_data .search_url
226- payload = HTMLRequests .get_search_request_data (game_name , search_modifiers , page )
247+ payload = HTMLRequests .get_search_request_data (game_name , search_modifiers , page , auth_struct )
227248 timeout = aiohttp .ClientTimeout (total = 60 )
228249 async with aiohttp .ClientSession () as session :
229250 async with session .post (HTMLRequests .SEARCH_URL , headers = headers , data = payload , timeout = timeout ) as resp_with_key :
@@ -266,14 +287,13 @@ def get_title_request_parameters(game_id: int):
266287 return params
267288
268289 @staticmethod
269- def get_title_request_headers ():
290+ def get_title_request_headers (user_agent ):
270291 """
271292 Generate the headers for the search request
272293 @return: The headers object for the request
273294 """
274- ua = UserAgent ()
275295 headers = {
276- 'User-Agent' : ua . random ,
296+ 'User-Agent' : user_agent ,
277297 'referer' : HTMLRequests .REFERER_HEADER
278298 }
279299 return headers
@@ -286,8 +306,12 @@ def get_game_title(game_id: int):
286306 @return: The game title from the given id
287307 """
288308
309+ # This is a request to get the game title so we can generate a UserAgent
310+ ua = UserAgent ()
311+ request_user_agent = ua .random .strip ()
312+
289313 params = HTMLRequests .get_title_request_parameters (game_id )
290- headers = HTMLRequests .get_title_request_headers ()
314+ headers = HTMLRequests .get_title_request_headers (request_user_agent )
291315
292316 # Request and extract title
293317 contents = requests .get (HTMLRequests .GAME_URL , params = params , headers = headers , timeout = 60 )
@@ -301,8 +325,12 @@ async def async_get_game_title(game_id: int):
301325 @return: The game title from the given id
302326 """
303327
328+ # This is a request to get the game title so we can generate a UserAgent
329+ ua = UserAgent ()
330+ request_user_agent = ua .random .strip ()
331+
304332 params = HTMLRequests .get_title_request_parameters (game_id )
305- headers = HTMLRequests .get_title_request_headers ()
333+ headers = HTMLRequests .get_title_request_headers (request_user_agent )
306334
307335 # Request and extract title
308336 timeout = aiohttp .ClientTimeout (total = 60 )
@@ -314,13 +342,13 @@ async def async_get_game_title(game_id: int):
314342 return None
315343
316344 @staticmethod
317- def send_website_request_getcode (parse_all_scripts : bool ):
345+ def send_website_request_getcode (parse_all_scripts : bool , user_agent ):
318346 """
319347 Function that send a request to howlongtobeat to scrape the correct search url
320348 @return: The search informations to use in the request
321349 """
322350 # Make the post request and return the result if is valid
323- headers = HTMLRequests .get_title_request_headers ()
351+ headers = HTMLRequests .get_title_request_headers (user_agent )
324352 resp = requests .get (HTMLRequests .BASE_URL , headers = headers , timeout = 60 )
325353 if resp .status_code == 200 and resp .text is not None :
326354 # Parse the HTML content using BeautifulSoup
@@ -341,13 +369,13 @@ def send_website_request_getcode(parse_all_scripts: bool):
341369 return None
342370
343371 @staticmethod
344- async def async_send_website_request_getcode (parse_all_scripts : bool ):
372+ async def async_send_website_request_getcode (parse_all_scripts : bool , user_agent ):
345373 """
346374 Function that send a request to howlongtobeat to scrape the correct search url
347375 @return: The search informations to use in the request
348376 """
349377 # Make the post request and return the result if is valid
350- headers = HTMLRequests .get_title_request_headers ()
378+ headers = HTMLRequests .get_title_request_headers (user_agent )
351379 timeout = aiohttp .ClientTimeout (total = 60 )
352380 async with aiohttp .ClientSession () as session :
353381 async with session .get (HTMLRequests .BASE_URL , headers = headers , timeout = timeout ) as resp :
@@ -386,47 +414,47 @@ def get_auth_token_request_params():
386414 params = {
387415 't' : timestamp
388416 }
389- return params
417+ return params
390418
391419 @staticmethod
392- def send_website_get_auth_token (parsed_search_url ):
420+ def send_website_get_auth_token (parsed_search_url , user_agent ):
393421 """
394422 Function that send a request to howlongtobeat to get the x-auth-token to get in the request
395423 @return: The auth token to use
396424 """
397425 # Make the post request and return the result if is valid
398- headers = HTMLRequests .get_title_request_headers ()
426+ headers = HTMLRequests .get_title_request_headers (user_agent )
399427 params = HTMLRequests .get_auth_token_request_params ()
400- auth_token = SearchAuthToken ()
428+ auth_struct = SearchAuthToken ()
401429 auth_token_url = HTMLRequests .BASE_URL
402430 if parsed_search_url is not None :
403- auth_token_url = HTMLRequests .BASE_URL + parsed_search_url + auth_token .search_url_endpoint
431+ auth_token_url = HTMLRequests .BASE_URL + parsed_search_url + auth_struct .search_url_endpoint
404432 else :
405- auth_token_url = HTMLRequests .BASE_URL + auth_token .search_url + auth_token .search_url_endpoint
433+ auth_token_url = HTMLRequests .BASE_URL + auth_struct .search_url + auth_struct .search_url_endpoint
406434 resp = requests .get (auth_token_url , params = params , headers = headers , timeout = 60 )
407435 if resp .status_code == 200 and resp .text is not None :
408- return auth_token .extract_auth_token_from_response (resp )
436+ return auth_struct .extract_auth_token_from_response (resp )
409437 return None
410438
411439 @staticmethod
412- async def async_send_website_get_auth_token (parsed_search_url ):
440+ async def async_send_website_get_auth_token (parsed_search_url , user_agent ):
413441 """
414442 Function that send a request to howlongtobeat to get the x-auth-token to get in the request
415443 @return: The auth token to use
416444 """
417445 # Make the post request and return the result if is valid
418- headers = HTMLRequests .get_title_request_headers ()
446+ headers = HTMLRequests .get_title_request_headers (user_agent )
419447 params = HTMLRequests .get_auth_token_request_params ()
420- auth_token = SearchAuthToken ()
448+ auth_struct = SearchAuthToken ()
421449 auth_token_url = HTMLRequests .BASE_URL
422450 if parsed_search_url is not None :
423- auth_token_url = HTMLRequests .BASE_URL + parsed_search_url + auth_token .search_url_endpoint
451+ auth_token_url = HTMLRequests .BASE_URL + parsed_search_url + auth_struct .search_url_endpoint
424452 else :
425- auth_token_url = HTMLRequests .BASE_URL + auth_token .search_url + auth_token .search_url_endpoint
453+ auth_token_url = HTMLRequests .BASE_URL + auth_struct .search_url + auth_struct .search_url_endpoint
426454 timeout = aiohttp .ClientTimeout (total = 60 )
427455 async with aiohttp .ClientSession () as session :
428456 async with session .get (auth_token_url , params = params , headers = headers , timeout = timeout ) as resp :
429457 if resp is not None and resp .status == 200 :
430458 json_data = await resp .json ()
431- return auth_token .extract_auth_token_from_json (json_data )
459+ return auth_struct .extract_auth_token_from_json (json_data )
432460 return None
0 commit comments