Skip to content

Commit

Permalink
Merge pull request #20 from Element21/master
Browse files Browse the repository at this point in the history
Fix English (hopefully). Use the last version of browser (by user-agent) based on platform or browser settings. Use the same ua for api and browser
  • Loading branch information
Tkd-Alex authored Jan 28, 2021
2 parents 965f3bc + 53ab98f commit 6e1f74c
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 38 deletions.
21 changes: 11 additions & 10 deletions TwitchChannelPointsMiner/TwitchChannelPointsMiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from datetime import datetime
from collections import OrderedDict

from TwitchChannelPointsMiner.utils import get_user_agent
from TwitchChannelPointsMiner.classes.Logger import LoggerSettings, configure_loggers
from TwitchChannelPointsMiner.classes.WebSocketsPool import WebSocketsPool
from TwitchChannelPointsMiner.classes.PubsubTopic import PubsubTopic
Expand Down Expand Up @@ -44,7 +45,10 @@ def __init__(
bet_settings: BetSettings = BetSettings(),
):
self.username = username
self.twitch = Twitch(self.username)
self.browser_settings = browser_settings
self.bet_settings = bet_settings

self.twitch = Twitch(self.username, get_user_agent(self.browser_settings.browser))
self.twitch_browser = None
self.follow_raid = follow_raid
self.watch_streak = watch_streak
Expand All @@ -55,9 +59,6 @@ def __init__(

self.make_predictions = make_predictions

self.browser_settings = browser_settings
self.bet_settings = bet_settings

self.session_id = str(uuid.uuid4())
self.running = False
self.start_datetime = None
Expand All @@ -75,7 +76,7 @@ def mine(self, streamers: list = [], followers=False):

def run(self, streamers: list = [], followers=False):
if self.running:
logger.error("You can't start multiple session of this istance!")
logger.error("You can't start multiple sessions of this instance!")
else:
logger.info(
f"Start session: '{self.session_id}'", extra={"emoji": ":bomb:"}
Expand All @@ -100,7 +101,7 @@ def run(self, streamers: list = [], followers=False):
streamers += [fw for fw in followers_array if fw not in streamers]

logger.info(
f"Loading data for {len(streamers)} streamers. Please wait ...",
f"Loading data for {len(streamers)} streamers. Please wait...",
extra={"emoji": ":nerd_face:"},
)
for streamer_username in streamers:
Expand Down Expand Up @@ -190,12 +191,12 @@ def run(self, streamers: list = [], followers=False):
# Do an external control for WebSocket. Check if the thread is running
if self.ws_pool.ws.elapsed_last_ping() > 5:
logger.info(
"The last ping was sent more than 5 minutes ago. Reconnect the WebSocket"
"The last ping was sent more than 5 minutes ago. Reconnecting to the WebSocket..."
)
WebSocketsPool.handle_websocket_reconnection(self.ws_pool.ws)

def end(self, signum, frame):
logger.info("CTRL+C Detected! Please wait, just a moment")
logger.info("CTRL+C Detected! Please wait just a moment!s")

if self.twitch_browser is not None:
self.twitch_browser.browser.quit()
Expand All @@ -212,7 +213,7 @@ def end(self, signum, frame):

def __print_report(self):
print("\n")
logger.info(f"End session '{self.session_id}'", extra={"emoji": ":stop_sign:"})
logger.info(f"Ending session: '{self.session_id}'", extra={"emoji": ":stop_sign:"})
if self.logs_file is not None:
logger.info(
f"Logs file: {self.logs_file}", extra={"emoji": ":page_facing_up:"}
Expand All @@ -237,7 +238,7 @@ def __print_report(self):
for streamer_index in range(0, len(self.streamers)):
self.streamers[streamer_index].set_less_printing(False)
logger.info(
f"{self.streamers[streamer_index]}, Gained (end-start): {self.streamers[streamer_index].channel_points - self.original_streamers[streamer_index].channel_points}",
f"{self.streamers[streamer_index]}, Total Points Gained (after farming - before farming): {self.streamers[streamer_index].channel_points - self.original_streamers[streamer_index].channel_points}",
extra={"emoji": ":microphone:"},
)
if self.streamers[streamer_index].history != {}:
Expand Down
16 changes: 8 additions & 8 deletions TwitchChannelPointsMiner/classes/Twitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
)
from TwitchChannelPointsMiner.constants import (
TWITCH_CLIENT_ID,
USER_AGENT,
TWITCH_API,
TWITCH_GQL,
)
Expand All @@ -32,11 +31,12 @@


class Twitch:
def __init__(self, username):
def __init__(self, username, user_agent):
cookies_path = os.path.join(Path().absolute(), "cookies")
Path(cookies_path).mkdir(parents=True, exist_ok=True)
self.cookies_file = os.path.join(cookies_path, f"{username}.pkl")
self.twitch_login = TwitchLogin(TWITCH_CLIENT_ID, username, USER_AGENT)
self.user_agent = user_agent
self.twitch_login = TwitchLogin(TWITCH_CLIENT_ID, username, self.user_agent)
self.running = True

def login(self):
Expand All @@ -62,16 +62,17 @@ def update_minute_watched_event_request(self, streamer):
)

def get_minute_watched_request_url(self, streamer):
headers = {"User-Agent": self.user_agent}
main_page_request = requests.get(
streamer.streamer_url, headers={"User-Agent": USER_AGENT}
streamer.streamer_url, headers=headers
)
response = main_page_request.text
settings_url = re.search(
"(https://static.twitchcdn.net/config/settings.*?js)", response
).group(1)

settings_request = requests.get(
settings_url, headers={"User-Agent": USER_AGENT}
settings_url, headers=headers
)
response = settings_request.text
minute_watched_request_url = re.search('"spade_url":"(.*?)"', response).group(1)
Expand All @@ -84,7 +85,7 @@ def post_gql_request(self, json_data):
headers={
"Authorization": f"OAuth {self.twitch_login.get_auth_token()}",
"Client-Id": TWITCH_CLIENT_ID,
"User-Agent": USER_AGENT,
"User-Agent": self.user_agent,
},
)
logger.debug(
Expand Down Expand Up @@ -192,7 +193,6 @@ def make_predictions(self, event):
)

def send_minute_watched_events(self, streamers, watch_streak=False):
headers = {"user-agent": USER_AGENT}
while self.running:
streamers_index = [
i
Expand Down Expand Up @@ -250,7 +250,7 @@ def send_minute_watched_events(self, streamers, watch_streak=False):
response = requests.post(
streamers[index].minute_watched_requests.url,
data=streamers[index].minute_watched_requests.payload,
headers=headers,
headers={"User-Agent": self.user_agent},
)
logger.debug(
f"Send minute watched request for {streamers[index]} - Status code: {response.status_code}"
Expand Down
30 changes: 15 additions & 15 deletions TwitchChannelPointsMiner/classes/TwitchBrowser.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from selenium.common.exceptions import TimeoutException, JavascriptException

from TwitchChannelPointsMiner.classes.EventPrediction import EventPrediction
from TwitchChannelPointsMiner.utils import bet_condition
from TwitchChannelPointsMiner.utils import bet_condition, get_user_agent
from TwitchChannelPointsMiner.constants import (
TWITCH_URL,
cookiePolicyQuery,
Expand Down Expand Up @@ -163,7 +163,7 @@ def __init_chrome(self):
options.add_argument("disable-setuid-sandbox")
options.add_argument("disable-infobars")
options.add_argument(
"user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
f"user-agent={get_user_agent(self.settings.browser)}"
)

options.add_experimental_option(
Expand All @@ -178,7 +178,7 @@ def __init_chrome(self):
self.browser = webdriver.Chrome(self.settings.driver_path, options=options)
else:
logger.warning(
f"The path {self.settings.driver_path} is not valid. Use default path",
f"The path {self.settings.driver_path} is not valid. Using default path...",
extra={"emoji": ":wrench:"},
)
self.browser = webdriver.Chrome(options=options)
Expand All @@ -200,7 +200,7 @@ def __init_firefox(self):
fp.set_preference("startup.homepage_welcome_url.additional", "about:blank")
fp.set_preference(
"general.useragent.override",
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0",
get_user_agent(self.settings.browser),
)

if os.path.isfile(self.settings.driver_path) is True:
Expand All @@ -211,7 +211,7 @@ def __init_firefox(self):
)
else:
logger.warning(
f"The path {self.settings.driver_path} is not valid. Use default path",
f"The path {self.settings.driver_path} is not valid. Using default path...",
extra={"emoji": ":wrench:"},
)
self.browser = webdriver.Firefox(options=options, firefox_profile=fp)
Expand Down Expand Up @@ -283,7 +283,7 @@ def screenshot(self, fname, write_timestamp=False):
image.save(fname, optimize=True, quality=20)
except Exception:
logger.error(
f"Exception raised during screenshot file {fname}", exc_info=True
f"Exception raised during screenshot. File: {fname}", exc_info=True
)

def __click_when_exist(
Expand Down Expand Up @@ -322,7 +322,7 @@ def start_bet(self, event: EventPrediction):
if bet_condition(self, event, logger) is True:
for attempt in range(0, self.settings.max_attempts):
logger.info(
f"Start betting for {event} owned by {event.streamer}",
f"Starting betting for {event} owned by {event.streamer}",
extra={"emoji": ":wrench:"},
)
self.browser.get(event.streamer.chat_url)
Expand Down Expand Up @@ -368,13 +368,13 @@ def place_bet(self, event: EventPrediction):
div_bet_is_open = True
except TimeoutException:
logger.info(
"The bet div was not found, maybe It was closed. Attempt to open again, hope to be in time",
"The bet div was not found, maybe It was closed. Attempting to open again... Hopefully in time!",
extra={"emoji": ":wrench:"},
)
div_bet_is_open = self.__bet_chains_methods(event)
if div_bet_is_open is True:
logger.info(
"Success! Bet div is now open, we can complete the bet",
"Success! Bet div is now open, we can complete the bet!",
extra={"emoji": ":wrench:"},
)

Expand Down Expand Up @@ -409,23 +409,23 @@ def place_bet(self, event: EventPrediction):
logger.error("Exception raised", exc_info=True)
else:
logger.info(
"Sorry, unable to complete the bet. The bet div still closed"
"Sorry, unable to complete the bet. The bet div is still closed!"
)
else:
logger.info(
f"Sorry, unable to complete the bet. Event box fillable: {event.box_fillable}, the browser is betting: {self.currently_is_betting}"
)
else:
logger.info(
f"Oh no! The event It's not more ACTIVE, current status: {event.status}",
f"Oh no! The event is not active anymore! Current status: {event.status}",
extra={"emoji": ":disappointed_relieved:"},
)

self.browser.get("about:blank")
self.currently_is_betting = False

def __open_coins_menu(self, event: EventPrediction):
logger.info(f"Open coins menu for {event}", extra={"emoji": ":wrench:"})
logger.info(f"Opening coins menu for {event}", extra={"emoji": ":wrench:"})
status = self.__click_when_exist(streamCoinsMenuXP, By.XPATH)
if status is False:
status = self.__execute_script(streamCoinsMenuJS)
Expand All @@ -437,7 +437,7 @@ def __open_coins_menu(self, event: EventPrediction):
return False

def __click_on_bet(self, event, maximize_div=True):
logger.info(f"Click on the bet for {event}", extra={"emoji": ":wrench:"})
logger.info(f"Clicking on the bet for {event}", extra={"emoji": ":wrench:"})
if self.__click_when_exist(streamBetTitleInBet, By.CSS_SELECTOR) is True:
time.sleep(random.uniform(0.01, 0.1))
if maximize_div is True:
Expand All @@ -456,7 +456,7 @@ def __enable_custom_bet_value(self, event, scroll_down=True):
if scroll_down is True:
time.sleep(random.uniform(0.01, 0.1))
if self.__execute_script(scrollDownBetWindowJS) is False:
logger.error("Unable to scroll down in the bet window")
logger.error("Unable to scroll down in the bet window!")

status = self.__click_when_exist(streamBetCustomVoteXP, By.CSS_SELECTOR)
if status is False:
Expand All @@ -470,7 +470,7 @@ def __enable_custom_bet_value(self, event, scroll_down=True):
return True
else:
logger.info(
"Something went wrong unable to continue with betting - Fillable box not avaible"
"Something went wrong unable to continue with betting - Fillable box not available!"
)
return False

Expand Down
3 changes: 2 additions & 1 deletion TwitchChannelPointsMiner/classes/WebSocketsPool.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import random

from millify import millify
from dateutil import parser

from TwitchChannelPointsMiner.classes.EventPrediction import EventPrediction
Expand Down Expand Up @@ -266,7 +267,7 @@ def on_message(ws, message):
if message.type == "prediction-result":
event_result = message.data["prediction"]["result"]
logger.info(
f"{ws.events_predictions[event_id]} - Result: {event_result['type']}, Points won: {event_result['points_won'] if event_result['points_won'] else 0}",
f"{ws.events_predictions[event_id]} - Result: {event_result['type']}, Points won: {millify(event_result['points_won']) if event_result['points_won'] else 0}",
extra={"emoji": ":bar_chart:"},
)
points_won = (
Expand Down
11 changes: 10 additions & 1 deletion TwitchChannelPointsMiner/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@
TWITCH_WEBSOCKET = "wss://pubsub-edge.twitch.tv/v1"
TWITCH_CLIENT_ID = "kimne78kx3ncx6brgo4mv6wki5h1ko"

USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36"
USER_AGENTS = {
"Windows": {
"CHROME": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36",
"FIREFOX": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"
},
"Linux": {
"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"
}
}

# XPath Selector and Javascript helpers
cookiePolicyQuery = 'button[data-a-target="consent-banner-accept"]'
Expand Down
16 changes: 13 additions & 3 deletions TwitchChannelPointsMiner/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import time
import platform

from datetime import datetime, timezone
from random import randrange

from TwitchChannelPointsMiner.constants import USER_AGENTS


def get_streamer_index(streamers, channel_id):
try:
Expand Down Expand Up @@ -48,17 +51,24 @@ def create_nonce(length=30):
def bet_condition(twitch_browser, event, logger):
if twitch_browser.currently_is_betting is True:
logger.info(
f"Sorry, unable to start {event}. The browser it's currently betting another event"
f"Sorry, unable to start {event}, the browser is currently betting on another event!"
)
return False
elif twitch_browser.browser.current_url != "about:blank":
logger.info(
"Sorry, but the browser is not currently on 'about:blank' screen. Unable to start bet"
"Sorry, but the browser is not currently on 'about:blank' screen. Unable to start bet!"
)
return False
elif event.streamer.viewer_is_mod is True:
logger.info(
f"Sorry, you are moderator of {event.streamer} and you can't start the bet"
f"Sorry, you are moderator of {event.streamer}, so you can't bet!"
)
return False
return True


def get_user_agent(browser):
try:
return USER_AGENTS[platform.system()][browser.name if type(browser) != str else browser]
except KeyError:
return USER_AGENTS["Linux"]["FIREFOX"]

0 comments on commit 6e1f74c

Please sign in to comment.