|
|
|
|
@@ -8,17 +8,29 @@ import logging
|
|
|
|
|
import os
|
|
|
|
|
import pickle
|
|
|
|
|
|
|
|
|
|
#import browser_cookie3
|
|
|
|
|
import requests
|
|
|
|
|
|
|
|
|
|
from TwitchChannelPointsMiner.classes.Exceptions import (
|
|
|
|
|
BadCredentialsException,
|
|
|
|
|
WrongCookiesException,
|
|
|
|
|
)
|
|
|
|
|
from TwitchChannelPointsMiner.constants import GQLOperations
|
|
|
|
|
from TwitchChannelPointsMiner.constants import CLIENT_ID, GQLOperations
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
def interceptor(request) -> str:
|
|
|
|
|
if (
|
|
|
|
|
request.method == 'POST'
|
|
|
|
|
and request.url == 'https://passport.twitch.tv/protected_login'
|
|
|
|
|
):
|
|
|
|
|
import json
|
|
|
|
|
body = request.body.decode('utf-8')
|
|
|
|
|
data = json.loads(body)
|
|
|
|
|
data['client_id'] = CLIENT_ID
|
|
|
|
|
request.body = json.dumps(data).encode('utf-8')
|
|
|
|
|
del request.headers['Content-Length']
|
|
|
|
|
request.headers['Content-Length'] = str(len(request.body))
|
|
|
|
|
|
|
|
|
|
class TwitchLogin(object):
|
|
|
|
|
__slots__ = [
|
|
|
|
|
"client_id",
|
|
|
|
|
@@ -30,8 +42,7 @@ class TwitchLogin(object):
|
|
|
|
|
"password",
|
|
|
|
|
"user_id",
|
|
|
|
|
"email",
|
|
|
|
|
"cookies",
|
|
|
|
|
"shared_cookies"
|
|
|
|
|
"cookies"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
def __init__(self, client_id, username, user_agent, password=None):
|
|
|
|
|
@@ -48,7 +59,6 @@ class TwitchLogin(object):
|
|
|
|
|
self.email = None
|
|
|
|
|
|
|
|
|
|
self.cookies = []
|
|
|
|
|
self.shared_cookies = []
|
|
|
|
|
|
|
|
|
|
def login_flow(self):
|
|
|
|
|
logger.info("You'll have to login to Twitch!")
|
|
|
|
|
@@ -156,12 +166,13 @@ class TwitchLogin(object):
|
|
|
|
|
return response.json()
|
|
|
|
|
|
|
|
|
|
def login_flow_backup(self):
|
|
|
|
|
"""Backup OAuth login flow in case manual captcha solving is required"""
|
|
|
|
|
"""Backup OAuth Selenium login"""
|
|
|
|
|
from undetected_chromedriver import ChromeOptions
|
|
|
|
|
import seleniumwire.undetected_chromedriver.v2 as uc
|
|
|
|
|
from selenium.webdriver.common.by import By
|
|
|
|
|
from time import sleep
|
|
|
|
|
|
|
|
|
|
HEADLESS = False
|
|
|
|
|
SLEEP_TIME = 10
|
|
|
|
|
|
|
|
|
|
options = uc.ChromeOptions()
|
|
|
|
|
if HEADLESS is True:
|
|
|
|
|
@@ -176,37 +187,34 @@ class TwitchLogin(object):
|
|
|
|
|
#options.add_argument("--window-size=1920,1080")
|
|
|
|
|
#options.set_capability("detach", True)
|
|
|
|
|
|
|
|
|
|
logger.info('Now a browser window will open, it will login with your data.')
|
|
|
|
|
driver = uc.Chrome(
|
|
|
|
|
options=options, use_subprocess=True#, executable_path=EXECUTABLE_PATH
|
|
|
|
|
)
|
|
|
|
|
driver.get('https://www.twitch.tv/settings/profile')
|
|
|
|
|
cookies = pickle.load(open(self.cookies_file, "rb"))
|
|
|
|
|
for cookie in cookies:
|
|
|
|
|
driver.add_cookie(cookie)
|
|
|
|
|
driver.get('https://www.twitch.tv/settings/profile')
|
|
|
|
|
driver.request_interceptor = interceptor
|
|
|
|
|
driver.get('https://www.twitch.tv/login')
|
|
|
|
|
|
|
|
|
|
request = driver.wait_for_request("https://gql.twitch.tv/integrity", timeout=20)
|
|
|
|
|
driver.find_element(By.ID, 'login-username').send_keys(self.username)
|
|
|
|
|
driver.find_element(By.ID, 'password-input').send_keys(self.password)
|
|
|
|
|
sleep(0.3)
|
|
|
|
|
driver.execute_script(
|
|
|
|
|
'document.querySelector("#root > div > div.scrollable-area > div.simplebar-scroll-content > div > div > div > div.Layout-sc-nxg1ff-0.gZaqky > form > div > div:nth-child(3) > button > div > div").click()'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
body = request.response.body.decode("UTF-8")
|
|
|
|
|
logger.info(
|
|
|
|
|
'Enter your verification code in the browser and wait for the Twitch website to load, then press Enter here.'
|
|
|
|
|
)
|
|
|
|
|
input()
|
|
|
|
|
|
|
|
|
|
logger.info("Extracting cookies...")
|
|
|
|
|
|
|
|
|
|
self.cookies = driver.get_cookies()
|
|
|
|
|
driver.quit()
|
|
|
|
|
integrity_json = json.loads(body)
|
|
|
|
|
self.username = self.get_cookie_value("login")
|
|
|
|
|
|
|
|
|
|
return self.get_cookie_value("auth-token")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.integrity = integrity_json.get("token", None)
|
|
|
|
|
logger.info(f"integrity: {self.integrity}")
|
|
|
|
|
#################################################
|
|
|
|
|
logger.info("Loading cookies saved on your computer...")
|
|
|
|
|
twitch_domain = ".twitch.tv"
|
|
|
|
|
|
|
|
|
|
if browser == "1": # chrome
|
|
|
|
|
cookie_jar = browser_cookie3.chrome(domain_name=twitch_domain)
|
|
|
|
|
else:
|
|
|
|
|
cookie_jar = browser_cookie3.firefox(domain_name=twitch_domain)
|
|
|
|
|
#logger.info(f"cookie_jar: {cookie_jar}")
|
|
|
|
|
cookies_dict = requests.utils.dict_from_cookiejar(cookie_jar)
|
|
|
|
|
#logger.info(f"cookies_dict: {cookies_dict}")
|
|
|
|
|
self.username = cookies_dict.get("login")
|
|
|
|
|
self.shared_cookies = cookies_dict
|
|
|
|
|
return cookies_dict.get("auth-token")
|
|
|
|
|
|
|
|
|
|
def check_login(self):
|
|
|
|
|
if self.login_check_result:
|
|
|
|
|
@@ -218,19 +226,6 @@ class TwitchLogin(object):
|
|
|
|
|
return self.login_check_result
|
|
|
|
|
|
|
|
|
|
def save_cookies(self, cookies_file):
|
|
|
|
|
#cookies_dict = self.session.cookies.get_dict()
|
|
|
|
|
#print(f"cookies_dict2pickle: {cookies_dict}")
|
|
|
|
|
#cookies_dict["auth-token"] = self.token
|
|
|
|
|
#if "persistent" not in cookies_dict: # saving user id cookies
|
|
|
|
|
# cookies_dict["persistent"] = self.user_id
|
|
|
|
|
|
|
|
|
|
# old way saves only 'auth-token' and 'persistent'
|
|
|
|
|
self.cookies = []
|
|
|
|
|
cookies_dict = self.shared_cookies
|
|
|
|
|
#print(f"cookies_dict2pickle: {cookies_dict}")
|
|
|
|
|
for cookie_name, value in cookies_dict.items():
|
|
|
|
|
self.cookies.append({"name": cookie_name, "value": value})
|
|
|
|
|
#print(f"cookies2pickle: {self.cookies}")
|
|
|
|
|
pickle.dump(self.cookies, open(cookies_file, "wb"))
|
|
|
|
|
|
|
|
|
|
def get_cookie_value(self, key):
|
|
|
|
|
|