1- import json
21import copy
3- from typing import Union
2+ from typing import Union , Optional
43from urllib .parse import urlencode
54
65from youtubesearchpython .core .requests import RequestCore
7- from youtubesearchpython .handlers .componenthandler import ComponentHandler
8- from youtubesearchpython .handlers .requesthandler import RequestHandler
6+ from youtubesearchpython .core .componenthandler import ComponentHandler
97from youtubesearchpython .core .constants import *
8+ from youtubesearchpython .core .exceptions import YouTubeRequestError , YouTubeParseError
9+
10+ import json
11+ import httpx
1012
1113
12- class SearchCore (RequestCore , RequestHandler , ComponentHandler ):
14+ class SearchCore (RequestCore , ComponentHandler ):
1315 response = None
1416 responseSource = None
1517 resultComponents = []
1618
17- def __init__ (self , query : str , limit : int , language : str , region : str , searchPreferences : str , timeout : int ):
18- super ().__init__ ()
19+ def __init__ (self , query : str , limit : int , language : str , region : str , searchPreferences : str , timeout : Optional [ int ] ):
20+ super ().__init__ (timeout = timeout )
1921 self .query = query
2022 self .limit = limit
2123 self .language = language
@@ -47,24 +49,60 @@ def _getRequestBody(self):
4749
4850 def _makeRequest (self ) -> None :
4951 self ._getRequestBody ()
50- request = self .syncPostRequest ()
5152 try :
53+ request = self .syncPostRequest ()
54+ if request .status_code != 200 :
55+ raise YouTubeRequestError (f'Request failed with status code { request .status_code } . URL: { self .url } ' )
5256 self .response = request .text
53- except :
54- raise Exception ('ERROR: Could not make request.' )
57+ except httpx .RequestError as e :
58+ raise YouTubeRequestError (f'Failed to make request to { self .url } : { str (e )} ' )
59+ except httpx .HTTPStatusError as e :
60+ raise YouTubeRequestError (f'HTTP error { e .response .status_code } for { self .url } : { str (e )} ' )
61+ except Exception as e :
62+ raise YouTubeRequestError (f'Unexpected error making request: { str (e )} ' )
5563
5664 async def _makeAsyncRequest (self ) -> None :
5765 self ._getRequestBody ()
58- request = await self .asyncPostRequest ()
5966 try :
67+ request = await self .asyncPostRequest ()
68+ if request .status_code != 200 :
69+ raise YouTubeRequestError (f'Request failed with status code { request .status_code } . URL: { self .url } ' )
6070 self .response = request .text
61- except :
62- raise Exception ('ERROR: Could not make request.' )
71+ except httpx .RequestError as e :
72+ raise YouTubeRequestError (f'Failed to make request to { self .url } : { str (e )} ' )
73+ except httpx .HTTPStatusError as e :
74+ raise YouTubeRequestError (f'HTTP error { e .response .status_code } for { self .url } : { str (e )} ' )
75+ except Exception as e :
76+ raise YouTubeRequestError (f'Unexpected error making request: { str (e )} ' )
77+
78+ def _parseSource (self ) -> None :
79+ try :
80+ if not self .continuationKey :
81+ responseContent = self ._getValue (json .loads (self .response ), contentPath )
82+ else :
83+ responseContent = self ._getValue (json .loads (self .response ), continuationContentPath )
84+ if responseContent :
85+ for element in responseContent :
86+ if itemSectionKey in element .keys ():
87+ self .responseSource = self ._getValue (element , [itemSectionKey , 'contents' ])
88+ if continuationItemKey in element .keys ():
89+ self .continuationKey = self ._getValue (element , continuationKeyPath )
90+ else :
91+ self .responseSource = self ._getValue (json .loads (self .response ), fallbackContentPath )
92+ self .continuationKey = self ._getValue (self .responseSource [- 1 ], continuationKeyPath )
93+ except json .JSONDecodeError as e :
94+ raise YouTubeParseError (f'Failed to parse JSON response: { str (e )} ' )
95+ except KeyError as e :
96+ raise YouTubeParseError (f'Missing expected key in response: { str (e )} ' )
97+ except Exception as e :
98+ raise YouTubeParseError (f'Failed to parse YouTube response: { str (e )} ' )
6399
64100 def result (self , mode : int = ResultMode .dict ) -> Union [str , dict ]:
65101 '''Returns the search result.
102+
66103 Args:
67104 mode (int, optional): Sets the type of result. Defaults to ResultMode.dict.
105+
68106 Returns:
69107 Union[str, dict]: Returns JSON or dictionary.
70108 '''
@@ -75,8 +113,10 @@ def result(self, mode: int = ResultMode.dict) -> Union[str, dict]:
75113
76114 def _next (self ) -> bool :
77115 '''Gets the subsequent search result. Call result
116+
78117 Args:
79118 mode (int, optional): Sets the type of result. Defaults to ResultMode.dict.
119+
80120 Returns:
81121 Union[str, dict]: Returns True if getting more results was successful.
82122 '''
0 commit comments