Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/wout-helix-api' into smart_hig…
Browse files Browse the repository at this point in the history
…h_odds
  • Loading branch information
1v committed Sep 30, 2021
2 parents ef1c109 + 3c31015 commit db1f65a
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 51 deletions.
5 changes: 3 additions & 2 deletions TwitchChannelPointsMiner/TwitchChannelPointsMiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,11 @@ def run(self, streamers: list = [], blacklist: list = [], followers=False):
)

# Subscribe to community-points-user. Get update for points spent or gains
user_id = self.twitch.twitch_login.get_user_id()
self.ws_pool.submit(
PubsubTopic(
"community-points-user-v1",
user_id=self.twitch.twitch_login.get_user_id(),
user_id=user_id,
)
)

Expand All @@ -252,7 +253,7 @@ def run(self, streamers: list = [], blacklist: list = [], followers=False):
self.ws_pool.submit(
PubsubTopic(
"predictions-user-v1",
user_id=self.twitch.twitch_login.get_user_id(),
user_id=user_id,
)
)

Expand Down
65 changes: 29 additions & 36 deletions TwitchChannelPointsMiner/classes/Twitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
)
from TwitchChannelPointsMiner.classes.Settings import Priority, Settings
from TwitchChannelPointsMiner.classes.TwitchLogin import TwitchLogin
from TwitchChannelPointsMiner.constants import API, CLIENT_ID, GQLOperations
from TwitchChannelPointsMiner.constants import CLIENT_ID, GQLOperations
from TwitchChannelPointsMiner.utils import (
_millify,
create_chunks,
Expand Down Expand Up @@ -143,33 +143,34 @@ def check_streamer_online(self, streamer):
streamer.set_offline()

def get_channel_id(self, streamer_username):
json_response = self.__do_helix_request(f"/users?login={streamer_username}")
if "data" not in json_response:
json_data = copy.deepcopy(GQLOperations.ReportMenuItem)
json_data["variables"] = {"channelLogin": streamer_username}
json_response = self.post_gql_request(json_data)
if (
"data" not in json_response
or "user" not in json_response["data"]
or json_response["data"]["user"] is None
):
raise StreamerDoesNotExistException
else:
data = json_response["data"]
if len(data) >= 1:
return data[0]["id"]
else:
raise StreamerDoesNotExistException

def get_followers(self, first=100):
followers = []
pagination = {}
while 1:
query = f"/users/follows?from_id={self.twitch_login.get_user_id()}&first={first}"
if pagination != {}:
query += f"&after={pagination['cursor']}"

json_response = self.__do_helix_request(query)
pagination = json_response["pagination"]
followers += [fw["to_login"].lower() for fw in json_response["data"]]
time.sleep(random.uniform(0.3, 0.7))

if pagination == {}:
break
return json_response["data"]["user"]["id"]

return followers
def get_followers(self):
json_data = copy.deepcopy(GQLOperations.PersonalSections)
json_response = self.post_gql_request(json_data)
try:
if (
"data" in json_response
and "personalSections" in json_response["data"]
and json_response["data"]["personalSections"] != []
):
return [
fw["user"]["login"]
for fw in json_response["data"]["personalSections"][0]["items"]
if fw["user"] is not None
]
except KeyError:
return []

def update_raid(self, streamer, raid):
if streamer.raid != raid:
Expand Down Expand Up @@ -211,14 +212,6 @@ def __check_connection_handler(self, chunk_size):
)
self.__chuncked_sleep(random_sleep * 60, chunk_size=chunk_size)

def __do_helix_request(self, query, response_as_json=True):
url = f"{API}/helix/{query.strip('/')}"
response = self.twitch_login.session.get(url)
logger.debug(
f"Query: {query}, Status code: {response.status_code}, Content: {response.json()}"
)
return response.json() if response_as_json is True else response

def post_gql_request(self, json_data):
try:
response = requests.post(
Expand Down Expand Up @@ -362,14 +355,12 @@ def send_minute_watched_events(self, streamers, priority, chunk_size=3):
drop.has_preconditions_met is not False
and drop.is_printable is True
):
# print("=" * 125)
logger.info(
f"{streamers[index]} is streaming {streamers[index].stream}"
)
logger.info(f"Campaign: {campaign}")
logger.info(f"Drop: {drop}")
logger.info(f"{drop.progress_bar()}")
# print("=" * 125)

except requests.exceptions.ConnectionError as e:
logger.error(f"Error while trying to send minute watched: {e}")
Expand Down Expand Up @@ -541,7 +532,9 @@ def __get_campaigns_details(self, campaigns):
}

response = self.post_gql_request(json_data)
result += list(map(lambda x: x["data"]["user"]["dropCampaign"], response))
for r in response:
if r["data"]["user"] is not None:
result.append(r["data"]["user"]["dropCampaign"])
return result

def __sync_campaigns(self, campaigns):
Expand Down
37 changes: 28 additions & 9 deletions TwitchChannelPointsMiner/classes/TwitchLogin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Original Copyright (c) 2020 Rodney
# The MIT License (MIT)

import copy
import getpass
import logging
import os
Expand All @@ -14,6 +15,7 @@
BadCredentialsException,
WrongCookiesException,
)
from TwitchChannelPointsMiner.constants import GQLOperations

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -177,14 +179,7 @@ def check_login(self):
if self.token is None:
return False

response = self.session.get(
f"https://api.twitch.tv/helix/users?login={self.username}"
)
response = response.json()
if "data" in response:
self.login_check_result = True
self.user_id = response["data"][0]["id"]

self.login_check_result = self.__set_user_id()
return self.login_check_result

def save_cookies(self, cookies_file):
Expand All @@ -203,6 +198,7 @@ def get_cookie_value(self, key):
if cookie["name"] == key:
if cookie["value"] is not None:
return cookie["value"]
return None

def load_cookies(self, cookies_file):
if os.path.isfile(cookies_file):
Expand All @@ -211,7 +207,30 @@ def load_cookies(self, cookies_file):
raise WrongCookiesException("There must be a cookies file!")

def get_user_id(self):
return int(self.get_cookie_value("persistent").split("%")[0])
persistent = self.get_cookie_value("persistent")
user_id = (
int(persistent.split("%")[0]) if persistent is not None else self.user_id
)
if user_id is None:
if self.__set_user_id() is True:
return self.user_id
return user_id

def __set_user_id(self):
json_data = copy.deepcopy(GQLOperations.ReportMenuItem)
json_data["variables"] = {"channelLogin": self.username}
response = self.session.post(GQLOperations.url, json=json_data)

if response.status_code == 200:
json_response = response.json()
if (
"data" in json_response
and "user" in json_response["data"]
and json_response["data"]["user"]["id"] is not None
):
self.user_id = json_response["data"]["user"]["id"]
return True
return False

def get_auth_token(self):
return self.get_cookie_value("auth-token")
1 change: 0 additions & 1 deletion TwitchChannelPointsMiner/classes/TwitchWebSocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def listen(self, topic, auth_token=None):
data = {"topics": [str(topic)]}
if topic.is_user_topic() and auth_token is not None:
data["auth_token"] = auth_token

nonce = create_nonce()
self.send({"type": "LISTEN", "nonce": nonce, "data": data})

Expand Down
1 change: 0 additions & 1 deletion TwitchChannelPointsMiner/classes/WebSocketsPool.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ def handle_reconnection(ws):
# Why not create a new ws on the same array index? Let's try.
self = ws.parent_pool
self.ws[ws.index] = self.__new(ws.index) # Create a new connection.
# self.ws[ws.index].topics = ws.topics

self.__start(ws.index) # Start a new thread.
time.sleep(30)
Expand Down
30 changes: 28 additions & 2 deletions TwitchChannelPointsMiner/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Twitch endpoints
URL = "https://www.twitch.tv"
API = "https://api.twitch.tv"
IRC = "irc.chat.twitch.tv"
IRC_PORT = 6667
WEBSOCKET = "wss://pubsub-edge.twitch.tv/v1"
Expand Down Expand Up @@ -118,7 +117,7 @@ class GQLOperations:
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "14b5e8a50777165cfc3971e1d93b4758613fe1c817d5542c398dce70b7a45c05", # "7da6078b1bfa2f0a4dd061cb47bdcd1ffddf31cccadd966ec192e4cd06666e2b",
"sha256Hash": "14b5e8a50777165cfc3971e1d93b4758613fe1c817d5542c398dce70b7a45c05",
}
},
}
Expand All @@ -131,3 +130,30 @@ class GQLOperations:
}
},
}
ReportMenuItem = { # Use for replace https://api.twitch.tv/helix/users?login={self.username}
"operationName": "ReportMenuItem",
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "8f3628981255345ca5e5453dfd844efffb01d6413a9931498836e6268692a30c",
}
},
}
PersonalSections = {
"operationName": "PersonalSections",
"variables": {
"input": {
"sectionInputs": ["FOLLOWED_SECTION"],
"recommendationContext": {"platform": "web"},
},
"channelLogin": None,
"withChannelUser": False,
"creatorAnniversariesExperimentEnabled": False,
},
"extensions": {
"persistedQuery": {
"version": 1,
"sha256Hash": "9fbdfb00156f754c26bde81eb47436dee146655c92682328457037da1a48ed39",
}
},
}

0 comments on commit db1f65a

Please sign in to comment.