3838 import ujson as json
3939except Exception :
4040 import json
41-
4241if TYPE_CHECKING :
4342 from .client import Client
44-
45-
4643logger = logging .getLogger ("twitchio.http" )
4744
4845
@@ -67,15 +64,12 @@ def __init__(
6764
6865 if token :
6966 self .headers ["Authorization" ] = "Bearer " + token
70-
7167 if isinstance (path , URL ):
7268 self .path = path
7369 else :
7470 self .path = URL (self .BASE_URL + "/" + path .rstrip ("/" ))
75-
7671 if query :
7772 self .path = self .path .with_query (query )
78-
7973 if isinstance (body , dict ):
8074 self .body = json .dumps (body )
8175 self .headers ["Content-Type" ] = "application/json"
@@ -122,44 +116,34 @@ async def request(self, route: Route, *, paginate=True, limit=100, full_body=Fal
122116 """
123117 if full_body :
124118 assert not paginate
125-
126119 if (not self .client_id or not self .nick ) and self .token :
127120 await self .validate (token = self .token )
128-
129121 if not self .client_id :
130122 raise errors .NoClientID ("A Client ID is required to use the Twitch API" )
131-
132123 headers = route .headers or {}
133124
134125 if force_app_token and "Authorization" not in headers :
135126 if not self .client_secret :
136127 raise errors .NoToken (
137128 "An app access token is required for this route, please provide a client id and client secret"
138129 )
139-
140130 if self .app_token is None :
141131 await self ._generate_login ()
142132 headers ["Authorization" ] = f"Bearer { self .app_token } "
143-
144133 elif not self .token and not self .client_secret and "Authorization" not in headers :
145134 raise errors .NoToken (
146135 "Authorization is required to use the Twitch API. Pass token and/or client_secret to the Client constructor"
147136 )
148-
149137 if "Authorization" not in headers :
150138 if not self .token :
151139 await self ._generate_login ()
152-
153140 headers ["Authorization" ] = f"Bearer { self .token } "
154-
155141 headers ["Client-ID" ] = self .client_id
156142
157143 if not self .session :
158144 self .session = aiohttp .ClientSession ()
159-
160145 if self .bucket .limited :
161146 await self .bucket
162-
163147 cursor = None
164148 data = []
165149
@@ -169,7 +153,6 @@ def reached_limit():
169153 def get_limit ():
170154 if limit is None :
171155 return "100"
172-
173156 to_get = limit - len (data )
174157 return str (to_get ) if to_get < 100 else "100"
175158
@@ -183,14 +166,11 @@ def get_limit():
183166 q = [("after" , cursor ), * q ]
184167 q = [("first" , get_limit ()), * q ]
185168 path = path .with_query (q )
186-
187169 body , is_text = await self ._request (route , path , headers )
188170 if is_text :
189171 return body
190-
191172 if full_body :
192173 return body
193-
194174 data += body ["data" ]
195175
196176 try :
@@ -200,9 +180,7 @@ def get_limit():
200180 else :
201181 if not cursor :
202182 break
203-
204183 is_finished = reached_limit () if limit is not None else True if paginate else True
205-
206184 return data
207185
208186 async def _request (self , route , path , headers , utilize_bucket = True ):
@@ -211,30 +189,24 @@ async def _request(self, route, path, headers, utilize_bucket=True):
211189 for attempt in range (5 ):
212190 if utilize_bucket and self .bucket .limited :
213191 await self .bucket .wait_reset ()
214-
215192 async with self .session .request (route .method , path , headers = headers , data = route .body ) as resp :
216193 try :
217194 logger .debug (f"Received a response from a request with status { resp .status } : { await resp .json ()} " )
218195 except Exception :
219196 logger .debug (f"Received a response from a request with status { resp .status } and without body" )
220-
221197 if 500 <= resp .status <= 504 :
222198 reason = resp .reason
223- await asyncio .sleep (2 ** attempt + 1 )
199+ await asyncio .sleep (2 ** attempt + 1 )
224200 continue
225-
226201 if utilize_bucket :
227202 reset = resp .headers .get ("Ratelimit-Reset" )
228203 remaining = resp .headers .get ("Ratelimit-Remaining" )
229204
230205 self .bucket .update (reset = reset , remaining = remaining )
231-
232206 if 200 <= resp .status < 300 :
233207 if resp .content_type == "application/json" :
234208 return await resp .json (), False
235-
236209 return await resp .text (encoding = "utf-8" ), True
237-
238210 if resp .status == 401 :
239211 if "WWW-Authenticate" in resp .headers :
240212 try :
@@ -243,21 +215,17 @@ async def _request(self, route, path, headers, utilize_bucket=True):
243215 raise errors .Unauthorized (
244216 "Your oauth token is invalid, and a new one could not be generated"
245217 )
246-
247218 print (resp .reason , await resp .json (), resp )
248219 raise errors .Unauthorized ("You're not authorized to use this route." )
249-
250220 if resp .status == 429 :
251221 reason = "Ratelimit Reached"
252222
253223 if not utilize_bucket : # non Helix APIs don't have ratelimit headers
254- await asyncio .sleep (3 ** attempt + 1 )
224+ await asyncio .sleep (3 ** attempt + 1 )
255225 continue
256-
257226 raise errors .HTTPException (
258227 f"Failed to fulfil request ({ resp .status } )." , reason = resp .reason , status = resp .status
259228 )
260-
261229 raise errors .HTTPException ("Failed to reach Twitch API" , reason = reason , status = resp .status )
262230
263231 async def _generate_login (self ):
@@ -269,32 +237,26 @@ async def _generate_login(self):
269237 return
270238 except Exception as e :
271239 self .client .run_event ("error" , e )
272-
273240 if not self .client_id or not self .client_secret :
274241 raise errors .HTTPException ("Unable to generate a token, client id and/or client secret not given" )
275-
276242 if self ._refresh_token :
277243 url = (
278244 self .TOKEN_BASE
279245 + "?grant_type=refresh_token&refresh_token={0}&client_id={1}&client_secret={2}" .format (
280246 self ._refresh_token , self .client_id , self .client_secret
281247 )
282248 )
283-
284249 else :
285250 url = self .TOKEN_BASE + "?client_id={0}&client_secret={1}&grant_type=client_credentials" .format (
286251 self .client_id , self .client_secret
287252 )
288253 if self .scopes :
289254 url += "&scope=" + " " .join (self .scopes )
290-
291255 if not self .session :
292256 self .session = aiohttp .ClientSession ()
293-
294257 async with self .session .post (url ) as resp :
295258 if resp .status > 300 or resp .status < 200 :
296259 raise errors .HTTPException ("Unable to generate a token: " + await resp .text ())
297-
298260 data = await resp .json ()
299261 self .token = self .app_token = data ["access_token" ]
300262 self ._refresh_token = data .get ("refresh_token" , None )
@@ -305,24 +267,19 @@ async def validate(self, *, token: str = None) -> dict:
305267 token = self .token
306268 if not self .session :
307269 self .session = aiohttp .ClientSession ()
308-
309270 url = "https://id.twitch.tv/oauth2/validate"
310271 headers = {"Authorization" : f"OAuth { token } " }
311272
312273 async with self .session .get (url , headers = headers ) as resp :
313274 if resp .status == 401 :
314275 raise errors .AuthenticationError ("Invalid or unauthorized Access Token passed." )
315-
316276 if resp .status > 300 or resp .status < 200 :
317277 raise errors .HTTPException ("Unable to validate Access Token: " + await resp .text ())
318-
319278 data : dict = await resp .json ()
320-
321279 if not self .nick :
322280 self .nick = data .get ("login" )
323281 self .user_id = data .get ("user_id" ) and int (data ["user_id" ])
324282 self .client_id = data .get ("client_id" )
325-
326283 return data
327284
328285 async def post_commercial (self , token : str , broadcaster_id : str , length : int ):
@@ -381,7 +338,6 @@ async def get_extension_transactions(self, extension_id: str, ids: List[Any] = N
381338 q = [("extension_id" , extension_id )]
382339 if ids :
383340 q .extend (("id" , id ) for id in ids )
384-
385341 return await self .request (Route ("GET" , "extensions/transactions" , "" , query = q ))
386342
387343 async def create_reward (
@@ -411,26 +367,21 @@ async def create_reward(
411367 if max_per_stream :
412368 data ["max_per_stream" ] = max_per_stream
413369 data ["max_per_stream_enabled" ] = True
414-
415370 if max_per_user :
416371 data ["max_per_user_per_stream" ] = max_per_user
417372 data ["max_per_user_per_stream_enabled" ] = True
418-
419373 if background_color :
420374 data ["background_color" ] = background_color
421-
422375 if global_cooldown :
423376 data ["global_cooldown_seconds" ] = global_cooldown
424377 data ["is_global_cooldown_enabled" ] = True
425-
426378 return await self .request (Route ("POST" , "channel_points/custom_rewards" , query = params , body = data , token = token ))
427379
428380 async def get_rewards (self , token : str , broadcaster_id : int , only_manageable : bool = False , ids : List [int ] = None ):
429381 params = [("broadcaster_id" , str (broadcaster_id )), ("only_manageable_rewards" , str (only_manageable ))]
430382
431383 if ids :
432384 params .extend (("id" , str (id )) for id in ids )
433-
434385 return await self .request (Route ("GET" , "channel_points/custom_rewards" , query = params , token = token ))
435386
436387 async def update_reward (
@@ -474,7 +425,6 @@ async def update_reward(
474425
475426 if not data :
476427 raise ValueError ("Nothing changed!" )
477-
478428 params = [("broadcaster_id" , str (broadcaster_id )), ("id" , str (reward_id ))]
479429 return await self .request (
480430 Route (
@@ -503,13 +453,10 @@ async def get_reward_redemptions(
503453
504454 if redemption_id :
505455 params .append (("id" , redemption_id ))
506-
507456 if status :
508457 params .append (("status" , status ))
509-
510458 if sort :
511459 params .append (("sort" , sort ))
512-
513460 return await self .request (Route ("GET" , "channel_points/custom_rewards/redemptions" , query = params , token = token ))
514461
515462 async def update_reward_redemption_status (
@@ -537,7 +484,6 @@ async def get_predictions(
537484
538485 if prediction_id :
539486 params .extend (("prediction_id" , prediction_id ))
540-
541487 return await self .request (Route ("GET" , "predictions" , query = params , token = token ), paginate = False )
542488
543489 async def patch_prediction (
@@ -551,7 +497,6 @@ async def patch_prediction(
551497
552498 if status == "RESOLVED" :
553499 body ["winning_outcome_id" ] = winning_outcome_id
554-
555500 return await self .request (
556501 Route (
557502 "PATCH" ,
@@ -641,7 +586,6 @@ async def get_games(self, game_ids: List[Any], game_names: List[str]):
641586 q .extend (("id" , id ) for id in game_ids )
642587 if game_names :
643588 q .extend (("name" , name ) for name in game_names )
644-
645589 return await self .request (Route ("GET" , "games" , query = q ))
646590
647591 async def get_hype_train (self , broadcaster_id : str , id : str = None , token : str = None ):
@@ -670,21 +614,18 @@ async def get_channel_ban_unban_events(self, token: str, broadcaster_id: str, us
670614 q = [("broadcaster_id" , broadcaster_id )]
671615 if user_ids :
672616 q .extend (("user_id" , id ) for id in user_ids )
673-
674617 return await self .request (Route ("GET" , "moderation/banned/events" , query = q , token = token ))
675618
676619 async def get_channel_bans (self , token : str , broadcaster_id : str , user_ids : List [str ] = None ):
677620 q = [("broadcaster_id" , broadcaster_id )]
678621 if user_ids :
679622 q .extend (("user_id" , id ) for id in user_ids )
680-
681623 return await self .request (Route ("GET" , "moderation/banned" , query = q , token = token ))
682624
683625 async def get_channel_moderators (self , token : str , broadcaster_id : str , user_ids : List [str ] = None ):
684626 q = [("broadcaster_id" , broadcaster_id )]
685627 if user_ids :
686628 q .extend (("user_id" , id ) for id in user_ids )
687-
688629 return await self .request (Route ("GET" , "moderation/moderators" , query = q , token = token ))
689630
690631 async def get_channel_mod_events (self , token : str , broadcaster_id : str , user_ids : List [str ] = None ):
@@ -723,7 +664,6 @@ async def get_streams(
723664 q .extend (("user_login" , l ) for l in user_logins )
724665 if languages :
725666 q .extend (("language" , l ) for l in languages )
726-
727667 return await self .request (Route ("GET" , "streams" , query = q , token = token ))
728668
729669 async def post_stream_marker (self , token : str , user_id : str , description : str = None ):
@@ -779,21 +719,18 @@ async def get_channel_schedule(
779719
780720 if segment_ids :
781721 q .extend (("id" , id ) for id in segment_ids )
782-
783722 return await self .request (Route ("GET" , "schedule" , query = q ), paginate = False , full_body = True )
784723
785724 async def get_channel_subscriptions (self , token : str , broadcaster_id : str , user_ids : List [str ] = None ):
786725 q = [("broadcaster_id" , broadcaster_id )]
787726 if user_ids :
788727 q .extend (("user_id" , u ) for u in user_ids )
789-
790728 return await self .request (Route ("GET" , "subscriptions" , query = q , token = token ))
791729
792730 async def get_stream_tags (self , tag_ids : List [str ] = None ):
793731 q = []
794732 if tag_ids :
795733 q .extend (("tag_id" , u ) for u in tag_ids )
796-
797734 return await self .request (Route ("GET" , "tags/streams" , query = q or None ))
798735
799736 async def get_channel_tags (self , broadcaster_id : str ):
@@ -831,7 +768,6 @@ async def get_users(self, ids: List[int], logins: List[str], token: str = None):
831768 q .extend (("id" , id ) for id in ids )
832769 if logins :
833770 q .extend (("login" , login ) for login in logins )
834-
835771 return await self .request (Route ("GET" , "users" , query = q , token = token ))
836772
837773 async def get_user_follows (self , from_id : str = None , to_id : str = None , token : str = None ):
@@ -892,7 +828,6 @@ async def get_videos(
892828
893829 if ids :
894830 q .extend (("id" , id ) for id in ids )
895-
896831 return await self .request (Route ("GET" , "videos" , query = q , token = token ))
897832
898833 async def delete_videos (self , token : str , ids : List [int ]):
@@ -954,7 +889,6 @@ async def post_poll(
954889 body ["bits_per_vote" ] = bits_per_vote
955890 if channel_points_voting_enabled and channel_points_per_vote :
956891 body ["channel_points_per_vote" ] = channel_points_per_vote
957-
958892 return await self .request (Route ("POST" , "polls" , body = body , token = token ))
959893
960894 async def patch_poll (self , broadcaster_id : str , token : str , id : str , status : str ):
0 commit comments