import argparse
import atexit
import os
import sys
import tarfile
import time
from pathlib import Path
from typing import Optional
import validators
import wget
from loguru import logger
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, ElementClickInterceptedException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox import options
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.firefox.webdriver import WebDriver
from urllib3.exceptions import MaxRetryError
logger.remove()
logger.add(sink=sys.stdout, colorize=True, level='DEBUG',
format="{time:DD.MM.YYYY HH:mm:ss} | {level} | "
"{message}")
GECKO_DRIVER_VERSION = '0.31.0'
BASE_DIR = Path(__file__).parent.resolve().as_posix()
TWITCH_USERNAME = os.environ.get('TWITCH_USERNAME')
TWITCH_PASSWORD = os.environ.get('TWITCH_PASSWORD')
if not all([TWITCH_USERNAME, TWITCH_PASSWORD]):
raise Exception('Username and password must be set')
def download_gecko_driver():
logger.info(f'Downloading gecodriver v {GECKO_DRIVER_VERSION}...')
gecko_driver = f'https://github.com/mozilla/geckodriver/releases/download/v{GECKO_DRIVER_VERSION}/' \
f'geckodriver-v{GECKO_DRIVER_VERSION}-linux64.tar.gz'
geckodriver_file = wget.download(url=gecko_driver, out=BASE_DIR)
with tarfile.open(geckodriver_file) as tar:
tar.extractall(BASE_DIR)
os.remove(f'{BASE_DIR}/geckodriver-v{GECKO_DRIVER_VERSION}-linux64.tar.gz')
print(f'\ngeckodriver has been downloaded to folder {BASE_DIR}')
def configure_firefox_driver(private_window: bool = False) -> WebDriver:
opt = options.Options()
opt.headless = False
opt.add_argument('-profile')
opt.add_argument(f'{Path.home()}/snap/firefox/common/.mozilla/firefox')
if private_window:
opt.set_preference("browser.privatebrowsing.autostart", True)
service = Service(executable_path=f'{BASE_DIR}/geckodriver')
firefox_driver = webdriver.Firefox(service=service, options=opt)
return firefox_driver
def validate_stream_url(twitch_url: str) -> Optional[str]:
twitch_url_valid = validators.url(twitch_url)
if twitch_url_valid is not True:
logger.error(f'Url {twitch_url} is invalid. Please provide correct one.')
sys.exit(1)
return twitch_url
class UserExitException(Exception):
"""We use this exception when user wants to exit."""
def exit_log(message: str):
try:
logger.info(message)
driver.close()
os.remove(f'{os.getcwd()}/geckodriver.log')
sys.exit(0)
except MaxRetryError:
pass
except SystemExit:
os.abort()
def main(twitch_url: str):
try:
try:
driver.get(twitch_url)
time.sleep(4)
try:
elem = driver.find_element(by='css selector', value='[data-a-target="login-button"]')
elem.click()
logger.info('you have 60 seconds to login')
time.sleep(2)
login = driver.find_element(by='css selector', value='[aria-label="Enter your username"]')
login.clear()
login.send_keys(f'{TWITCH_USERNAME}')
password = driver.find_element(by='css selector', value='[aria-label="Enter your password"]')
password.clear()
password.send_keys(f'{TWITCH_PASSWORD}')
time.sleep(1)
password.send_keys(Keys.ENTER)
time.sleep(53)
logger.info('time for login is up')
except NoSuchElementException:
logger.info('Login button not found. Probably you are already logged in')
try:
security_button = driver.find_element(
by='css selector',
value='[data-a-target="account-checkup-generic-modal-secondary-button"]'
)
security_button.click()
except NoSuchElementException:
logger.info('Security button not found, continue...')
except Exception as e:
logger.error(f'Open page exception: {e}')
total_bonus, clicks = 0, 0
while True:
try:
elem = driver.find_element(by='css selector', value='[aria-label="Claim Bonus"]')
elem.click()
total_bonus += 50
clicks += 1
logger.info(f'{clicks}-bonus +50 has been clicked! Total bonus: {total_bonus}')
time.sleep(60 * 15 - 2)
except NoSuchElementException:
time.sleep(1)
except ElementClickInterceptedException:
logger.error('Security button must be clicked')
time.sleep(15 * 60)
except UserExitException:
break
except KeyboardInterrupt as e:
atexit.register(exit_log, 'Exit script')
if __name__ == '__main__':
parser = argparse.ArgumentParser('Twitch clicker', add_help=True)
parser.add_argument('-u', '--twitch_url', required=False, default='https://www.twitch.tv/lol4to22',
help='Please provide twitch stream url')
args = parser.parse_args(sys.argv[1:])
url = 'https://www.twitch.tv/lol4to22'
stream_url = args.twitch_url
if stream_url:
url = validate_stream_url(stream_url)
logger.info(f'Stream url is: {url}')
download_gecko_driver()
driver = configure_firefox_driver()
main(url)