new UA, login fix (only console)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
__version__ = "1.4.1"
|
__version__ = "1.5.0"
|
||||||
from .TwitchChannelPointsMiner import TwitchChannelPointsMiner
|
from .TwitchChannelPointsMiner import TwitchChannelPointsMiner
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
|||||||
@@ -67,13 +67,13 @@ class Twitch(object):
|
|||||||
Path(cookies_path).mkdir(parents=True, exist_ok=True)
|
Path(cookies_path).mkdir(parents=True, exist_ok=True)
|
||||||
self.cookies_file = os.path.join(cookies_path, f"{username}.pkl")
|
self.cookies_file = os.path.join(cookies_path, f"{username}.pkl")
|
||||||
self.user_agent = user_agent
|
self.user_agent = user_agent
|
||||||
self.twitch_login = TwitchLogin(
|
|
||||||
CLIENT_ID, username, self.user_agent, password=password
|
|
||||||
)
|
|
||||||
self.running = True
|
|
||||||
self.device_id = "".join(
|
self.device_id = "".join(
|
||||||
choice(string.ascii_letters + string.digits) for _ in range(32)
|
choice(string.ascii_letters + string.digits) for _ in range(32)
|
||||||
)
|
)
|
||||||
|
self.twitch_login = TwitchLogin(
|
||||||
|
CLIENT_ID, self.device_id, username, self.user_agent, password=password
|
||||||
|
)
|
||||||
|
self.running = True
|
||||||
self.integrity = None
|
self.integrity = None
|
||||||
self.integrity_expire = 0
|
self.integrity_expire = 0
|
||||||
self.client_session = token_hex(16)
|
self.client_session = token_hex(16)
|
||||||
@@ -126,9 +126,14 @@ class Twitch(object):
|
|||||||
|
|
||||||
def get_spade_url(self, streamer):
|
def get_spade_url(self, streamer):
|
||||||
try:
|
try:
|
||||||
headers = {"User-Agent": self.user_agent}
|
# fixes AttributeError: 'NoneType' object has no attribute 'group'
|
||||||
|
#headers = {"User-Agent": self.user_agent}
|
||||||
|
from TwitchChannelPointsMiner.constants import USER_AGENTS
|
||||||
|
headers = {"User-Agent": USER_AGENTS["Linux"]["FIREFOX"]}
|
||||||
|
|
||||||
main_page_request = requests.get(streamer.streamer_url, headers=headers)
|
main_page_request = requests.get(streamer.streamer_url, headers=headers)
|
||||||
response = main_page_request.text
|
response = main_page_request.text
|
||||||
|
#logger.info(response)
|
||||||
regex_settings = "(https://static.twitchcdn.net/config/settings.*?js)"
|
regex_settings = "(https://static.twitchcdn.net/config/settings.*?js)"
|
||||||
settings_url = re.search(regex_settings, response).group(1)
|
settings_url = re.search(regex_settings, response).group(1)
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from TwitchChannelPointsMiner.constants import CLIENT_ID, GQLOperations
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def interceptor(request) -> str:
|
"""def interceptor(request) -> str:
|
||||||
if (
|
if (
|
||||||
request.method == 'POST'
|
request.method == 'POST'
|
||||||
and request.url == 'https://passport.twitch.tv/protected_login'
|
and request.url == 'https://passport.twitch.tv/protected_login'
|
||||||
@@ -29,11 +29,12 @@ def interceptor(request) -> str:
|
|||||||
data['client_id'] = CLIENT_ID
|
data['client_id'] = CLIENT_ID
|
||||||
request.body = json.dumps(data).encode('utf-8')
|
request.body = json.dumps(data).encode('utf-8')
|
||||||
del request.headers['Content-Length']
|
del request.headers['Content-Length']
|
||||||
request.headers['Content-Length'] = str(len(request.body))
|
request.headers['Content-Length'] = str(len(request.body))"""
|
||||||
|
|
||||||
class TwitchLogin(object):
|
class TwitchLogin(object):
|
||||||
__slots__ = [
|
__slots__ = [
|
||||||
"client_id",
|
"client_id",
|
||||||
|
"device_id",
|
||||||
"token",
|
"token",
|
||||||
"login_check_result",
|
"login_check_result",
|
||||||
"session",
|
"session",
|
||||||
@@ -45,13 +46,14 @@ class TwitchLogin(object):
|
|||||||
"cookies"
|
"cookies"
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, client_id, username, user_agent, password=None):
|
def __init__(self, client_id, device_id, username, user_agent, password=None):
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
|
self.device_id = device_id
|
||||||
self.token = None
|
self.token = None
|
||||||
self.login_check_result = False
|
self.login_check_result = False
|
||||||
self.session = requests.session()
|
self.session = requests.session()
|
||||||
self.session.headers.update(
|
self.session.headers.update(
|
||||||
{"Client-ID": self.client_id, "User-Agent": user_agent}
|
{ "Client-ID": self.client_id, "X-Device-Id": self.device_id, "User-Agent": user_agent }
|
||||||
)
|
)
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
@@ -69,8 +71,8 @@ class TwitchLogin(object):
|
|||||||
"remember_me": True,
|
"remember_me": True,
|
||||||
}
|
}
|
||||||
# login-fix
|
# login-fix
|
||||||
#use_backup_flow = False
|
use_backup_flow = False
|
||||||
use_backup_flow = True
|
#use_backup_flow = True
|
||||||
|
|
||||||
for attempt in range(0, 25):
|
for attempt in range(0, 25):
|
||||||
password = (
|
password = (
|
||||||
@@ -131,8 +133,8 @@ class TwitchLogin(object):
|
|||||||
# If the user didn't load the password from run.py we can just ask for it again.
|
# If the user didn't load the password from run.py we can just ask for it again.
|
||||||
break
|
break
|
||||||
# login-fix
|
# login-fix
|
||||||
#elif err_code == 1000:
|
elif err_code == 1000:
|
||||||
elif err_code in [1000, 5022]:
|
#elif err_code in [1000, 5022]:
|
||||||
logger.info(
|
logger.info(
|
||||||
"Console login unavailable (CAPTCHA solving required)."
|
"Console login unavailable (CAPTCHA solving required)."
|
||||||
)
|
)
|
||||||
@@ -162,11 +164,18 @@ class TwitchLogin(object):
|
|||||||
self.session.headers.update({"Authorization": f"Bearer {self.token}"})
|
self.session.headers.update({"Authorization": f"Bearer {self.token}"})
|
||||||
|
|
||||||
def send_login_request(self, json_data):
|
def send_login_request(self, json_data):
|
||||||
response = self.session.post("https://passport.twitch.tv/protected_login", json=json_data)
|
#response = self.session.post("https://passport.twitch.tv/protected_login", json=json_data)
|
||||||
|
response = self.session.post("https://passport.twitch.tv/login", json=json_data, headers={
|
||||||
|
'Accept': 'application/vnd.twitchtv.v3+json',
|
||||||
|
'Accept-Encoding': 'gzip',
|
||||||
|
'Accept-Language': 'en-US',
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Host': 'passport.twitch.tv'
|
||||||
|
},)
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
def login_flow_backup(self, password = None):
|
def login_flow_backup(self, password = None):
|
||||||
"""Backup OAuth Selenium login"""
|
"""Backup OAuth Selenium login
|
||||||
from undetected_chromedriver import ChromeOptions
|
from undetected_chromedriver import ChromeOptions
|
||||||
import seleniumwire.undetected_chromedriver.v2 as uc
|
import seleniumwire.undetected_chromedriver.v2 as uc
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
@@ -218,7 +227,9 @@ class TwitchLogin(object):
|
|||||||
logger.error("Couldn't extract login, probably bad cookies.")
|
logger.error("Couldn't extract login, probably bad cookies.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.get_cookie_value("auth-token")
|
return self.get_cookie_value("auth-token")"""
|
||||||
|
logger.error("Backup login flow is not available. Use a VPN or wait a while to avoid the CAPTCHA.")
|
||||||
|
return False
|
||||||
|
|
||||||
def check_login(self):
|
def check_login(self):
|
||||||
if self.login_check_result:
|
if self.login_check_result:
|
||||||
@@ -230,7 +241,17 @@ class TwitchLogin(object):
|
|||||||
return self.login_check_result
|
return self.login_check_result
|
||||||
|
|
||||||
def save_cookies(self, cookies_file):
|
def save_cookies(self, cookies_file):
|
||||||
pickle.dump(self.cookies, open(cookies_file, "wb"))
|
#pickle.dump(self.cookies, open(cookies_file, "wb"))
|
||||||
|
# ^ only this line was needed with Selenium ^
|
||||||
|
cookies_dict = self.session.cookies.get_dict()
|
||||||
|
cookies_dict["auth-token"] = self.token
|
||||||
|
if "persistent" not in cookies_dict: # saving user id cookies
|
||||||
|
cookies_dict["persistent"] = self.user_id
|
||||||
|
|
||||||
|
self.cookies = []
|
||||||
|
for cookie_name, value in cookies_dict.items():
|
||||||
|
self.cookies.append({"name": cookie_name, "value": value})
|
||||||
|
pickle.dump(self.cookies, open(cookies_file, "wb"))
|
||||||
|
|
||||||
def get_cookie_value(self, key):
|
def get_cookie_value(self, key):
|
||||||
for cookie in self.cookies:
|
for cookie in self.cookies:
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ USER_AGENTS = {
|
|||||||
"CHROME": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36",
|
"CHROME": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36",
|
||||||
"FIREFOX": "Mozilla/5.0 (X11; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0",
|
"FIREFOX": "Mozilla/5.0 (X11; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0",
|
||||||
},
|
},
|
||||||
|
"Android": {
|
||||||
|
"App": "Dalvik/2.1.0 (Linux; U; Android 7.1.2; SM-G975N Build/N2G48C) tv.twitch.android.app/13.4.1/1304010"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BRANCH = "master"
|
BRANCH = "master"
|
||||||
|
|||||||
@@ -53,12 +53,13 @@ def create_nonce(length=30) -> str:
|
|||||||
nonce += char
|
nonce += char
|
||||||
return nonce
|
return nonce
|
||||||
|
|
||||||
|
# for mobile-token
|
||||||
def get_user_agent(browser: str) -> str:
|
def get_user_agent(browser: str) -> str:
|
||||||
try:
|
"""try:
|
||||||
return USER_AGENTS[platform.system()][browser]
|
return USER_AGENTS[platform.system()][browser]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return USER_AGENTS["Linux"]["FIREFOX"]
|
return USER_AGENTS["Linux"]["FIREFOX"]"""
|
||||||
|
return USER_AGENTS["Android"]["App"]
|
||||||
|
|
||||||
|
|
||||||
def remove_emoji(string: str) -> str:
|
def remove_emoji(string: str) -> str:
|
||||||
|
|||||||
@@ -9,6 +9,3 @@ colorama
|
|||||||
flask
|
flask
|
||||||
irc
|
irc
|
||||||
pandas
|
pandas
|
||||||
selenium
|
|
||||||
selenium-wire
|
|
||||||
undetected_chromedriver
|
|
||||||
|
|||||||
5
setup.py
5
setup.py
@@ -36,10 +36,7 @@ setuptools.setup(
|
|||||||
"colorama",
|
"colorama",
|
||||||
"flask",
|
"flask",
|
||||||
"irc",
|
"irc",
|
||||||
"pandas",
|
"pandas"
|
||||||
"selenium",
|
|
||||||
"selenium-wire",
|
|
||||||
"undetected_chromedriver"
|
|
||||||
],
|
],
|
||||||
long_description=read("README.md"),
|
long_description=read("README.md"),
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
|
|||||||
Reference in New Issue
Block a user