|
11 | 11 | import re |
12 | 12 | import string |
13 | 13 | import time |
14 | | -# from datetime import datetime |
| 14 | +# import json |
| 15 | +import requests |
| 16 | +import validators |
15 | 17 | from pathlib import Path |
16 | 18 | from secrets import choice, token_hex |
17 | | - |
18 | | -# import json |
| 19 | +# from urllib.parse import quote |
19 | 20 | # from base64 import urlsafe_b64decode |
20 | | - |
21 | | -import requests |
| 21 | +# from datetime import datetime |
22 | 22 |
|
23 | 23 | from TwitchChannelPointsMiner.classes.entities.Campaign import Campaign |
24 | 24 | from TwitchChannelPointsMiner.classes.entities.Drop import Drop |
@@ -433,7 +433,8 @@ def send_minute_watched_events(self, streamers, priority, chunk_size=3): |
433 | 433 | ) |
434 | 434 | > 30 |
435 | 435 | ) |
436 | | - and streamers[index].stream.minute_watched < 7 # fix #425 |
| 436 | + # fix #425 |
| 437 | + and streamers[index].stream.minute_watched < 7 |
437 | 438 | ): |
438 | 439 | streamers_watching.append(index) |
439 | 440 | if len(streamers_watching) == 2: |
@@ -467,14 +468,87 @@ def send_minute_watched_events(self, streamers, priority, chunk_size=3): |
467 | 468 | streamers_watching = streamers_watching[:2] |
468 | 469 |
|
469 | 470 | for index in streamers_watching: |
470 | | - next_iteration = time.time() + 60 / len(streamers_watching) |
| 471 | + # next_iteration = time.time() + 60 / len(streamers_watching) |
| 472 | + next_iteration = time.time() + 20 / len(streamers_watching) |
471 | 473 |
|
472 | 474 | try: |
| 475 | + #################################### |
| 476 | + # Start of fix for 2024/5 API Change |
| 477 | + # Create the JSON data for the GraphQL request |
| 478 | + json_data = copy.deepcopy( |
| 479 | + GQLOperations.PlaybackAccessToken) |
| 480 | + json_data["variables"] = { |
| 481 | + "login": streamers[index].username, |
| 482 | + "isLive": True, |
| 483 | + "isVod": False, |
| 484 | + "vodID": "", |
| 485 | + # "playerType": "site" |
| 486 | + "playerType": "picture-by-picture" |
| 487 | + } |
| 488 | + |
| 489 | + # Get signature and value using the post_gql_request method |
| 490 | + responsePlaybackAccessToken = self.post_gql_request( |
| 491 | + json_data) |
| 492 | + logger.debug( |
| 493 | + f"Sent PlaybackAccessToken request for {streamers[index]}" |
| 494 | + ) |
| 495 | + signature = responsePlaybackAccessToken["data"]['streamPlaybackAccessToken']["signature"] |
| 496 | + value = responsePlaybackAccessToken["data"]['streamPlaybackAccessToken']["value"] |
| 497 | + if not signature or not value: |
| 498 | + continue |
| 499 | + |
| 500 | + # encoded_value = quote(json.dumps(value)) |
| 501 | + |
| 502 | + # Construct the URL for the broadcast qualities |
| 503 | + RequestBroadcastQualitiesURL = f"https://usher.ttvnw.net/api/channel/hls/{streamers[index].username}.m3u8?sig={signature}&token={value}" |
| 504 | + |
| 505 | + # Get list of video qualities |
| 506 | + responseBroadcastQualities = requests.get(RequestBroadcastQualitiesURL, headers={ |
| 507 | + "User-Agent": self.user_agent}, timeout=20) # timeout=60 |
| 508 | + logger.debug( |
| 509 | + f"Send RequestBroadcastQualitiesURL request for {streamers[index]} - Status code: {responseBroadcastQualities.status_code}" |
| 510 | + ) |
| 511 | + if responseBroadcastQualities.status_code != 200: |
| 512 | + continue |
| 513 | + BroadcastQualities = responseBroadcastQualities.text |
| 514 | + |
| 515 | + # Just takes the last line, which should be the URL for the lowest quality |
| 516 | + BroadcastLowestQualityURL = BroadcastQualities.split( |
| 517 | + "\n")[-1] |
| 518 | + if not validators.url(BroadcastLowestQualityURL): |
| 519 | + continue |
| 520 | + |
| 521 | + # Get list of video URLs |
| 522 | + responseStreamURLList = requests.get(BroadcastLowestQualityURL, headers={ |
| 523 | + "User-Agent": self.user_agent}, timeout=20) # timeout=60 |
| 524 | + logger.debug( |
| 525 | + f"Send BroadcastLowestQualityURL request for {streamers[index]} - Status code: {responseStreamURLList.status_code}" |
| 526 | + ) |
| 527 | + if responseStreamURLList.status_code != 200: |
| 528 | + continue |
| 529 | + StreamURLList = responseStreamURLList.text |
| 530 | + |
| 531 | + # Just takes the last line, which should be the URL for the lowest quality |
| 532 | + StreamLowestQualityURL = StreamURLList.split("\n")[-2] |
| 533 | + if not validators.url(StreamLowestQualityURL): |
| 534 | + continue |
| 535 | + |
| 536 | + # Perform a HEAD request to simulate watching the stream |
| 537 | + responseStreamLowestQualityURL = requests.head(StreamLowestQualityURL, headers={ |
| 538 | + "User-Agent": self.user_agent}, timeout=20) # timeout=60 |
| 539 | + logger.debug( |
| 540 | + f"Send StreamLowestQualityURL request for {streamers[index]} - Status code: {responseStreamLowestQualityURL.status_code}" |
| 541 | + ) |
| 542 | + if responseStreamLowestQualityURL.status_code != 200: |
| 543 | + continue |
| 544 | + # End of fix for 2024/5 API Change |
| 545 | + ################################## |
473 | 546 | response = requests.post( |
474 | 547 | streamers[index].stream.spade_url, |
475 | 548 | data=streamers[index].stream.encode_payload(), |
476 | 549 | headers={"User-Agent": self.user_agent}, |
477 | | - timeout=60, |
| 550 | + # timeout=60, |
| 551 | + timeout=20, |
478 | 552 | ) |
479 | 553 | logger.debug( |
480 | 554 | f"Send minute watched request for {streamers[index]} - Status code: {response.status_code}" |
@@ -543,7 +617,8 @@ def send_minute_watched_events(self, streamers, priority, chunk_size=3): |
543 | 617 | ) |
544 | 618 |
|
545 | 619 | if streamers_watching == []: |
546 | | - self.__chuncked_sleep(60, chunk_size=chunk_size) |
| 620 | + # self.__chuncked_sleep(60, chunk_size=chunk_size) |
| 621 | + self.__chuncked_sleep(20, chunk_size=chunk_size) |
547 | 622 | except Exception: |
548 | 623 | logger.error( |
549 | 624 | "Exception raised in send minute watched", exc_info=True) |
|
0 commit comments