#!/usr/bin/env python3 import contextlib import logging import time __author__ = 'jota' import ctypes import gzip import json import os import smtplib import sys import urllib.error import urllib.parse import urllib.request from email.message import EmailMessage from io import BytesIO MAIN_URL = 'https://chrono.gg' POST_URL = 'https://api.chrono.gg/quest/spin' ALREADY_CLICKED_CODE = 420 UNAUTHORIZED = 401 USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36' GLOBAL_HEADERS = {'User-Agent': USER_AGENT, 'Pragma': 'no-cache', 'Origin': MAIN_URL, 'Accept-Encoding': 'gzip, deflate, br', 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Referer': MAIN_URL} COOKIE_FILE_NAME = ".chronogg" CONFIG_FILE_NAME = ".config" @contextlib.contextmanager def setup_logging(): logger = logging.getLogger() try: if os.environ["DEBUG"]: logger.setLevel(logging.DEBUG) except KeyError: logger.setLevel(logging.INFO) try: # __enter__ # Generic file logging # log_filename = 'AutoChronoGG_{}.log'.format(time.strftime("%Y%m%d-%H%M%S")) # f_handler = logging.FileHandler(filename=log_filename, encoding='utf-8', mode='w') s_handler = logging.StreamHandler(stream=sys.stdout) dt_fmt = '%Y-%m-%d %H:%M:%S' fmt = logging.Formatter( '%(asctime)s %(levelname)-5.5s [%(name)s] [%(funcName)s()] %(message)s <line %(lineno)d>', dt_fmt, style='%') # add f_handler in list to add file logging for handler in [s_handler]: handler.setFormatter(fmt) logger.addHandler(handler) yield finally: # __exit__ handlers = logger.handlers[:] for hdlr in handlers: hdlr.close() logger.removeHandler(hdlr) def get_web_page(url, headers, cookies): try: logging.info(f'Fetching {url}') request = urllib.request.Request(url, None, headers) request.add_header('Authorization', cookies) response = urllib.request.urlopen(request) if response.info().get('Content-Encoding') == 'gzip': buf = BytesIO(response.read()) f = gzip.GzipFile(fileobj=buf) r = f.read() else: r = response.read() return r except urllib.error.HTTPError as e: logging.info(f"Error processing webpage: {e}") if e.code == ALREADY_CLICKED_CODE: return ALREADY_CLICKED_CODE if e.code == UNAUTHORIZED: return UNAUTHORIZED return None def save_cookie(cookie): # https://stackoverflow.com/questions/25432139/python-cross-platform-hidden-file # Just Windows things if os.name == 'nt': ret = ctypes.windll.kernel32.SetFileAttributesW(COOKIE_FILE_NAME, 0) with open(COOKIE_FILE_NAME, 'w') as f: f.write(cookie) if os.name == 'nt': ret = ctypes.windll.kernel32.SetFileAttributesW(COOKIE_FILE_NAME, 2) def get_cookie_from_file(): try: with open(COOKIE_FILE_NAME, 'r') as f: return f.read() except: return '' def get_config_from_file(): try: with open(CONFIG_FILE_NAME, 'r') as f: return json.load(f) except: return False def config_exists(): return os.path.exists(CONFIG_FILE_NAME) def send_mail(to, subject, message, frm, host): msg = EmailMessage() msg['Subject'] = subject msg['From'] = frm['name'] + ' <' + frm['address'] + '>' msg['To'] = ', '.join(to) msg.set_content(message) server = smtplib.SMTP(host) server.send_message(msg) server.quit() def main(): try: config = get_config_from_file() if config_exists(): if not config: logging.info(f'An error occurred while trying to load the config from file.' f' Check the JSON syntax in {CONFIG_FILE_NAME}.') return if len(sys.argv) < 2: gg_cookie = get_cookie_from_file() if not gg_cookie or len(gg_cookie) < 1: logging.info('<<<AutoChronoGG>>>') logging.info('Usage: ./chronogg.py <Authorization Token>') logging.info('Please read the README.md and follow the instructions on ' 'how to extract your authorization token.') return else: gg_cookie = sys.argv[1] results = get_web_page(POST_URL, GLOBAL_HEADERS, gg_cookie) if not results: logging.info('An unknown error occurred while fetching results. Terminating...') return elif results == ALREADY_CLICKED_CODE: logging.info('An error occurred while fetching results: Coin already clicked. Terminating...') save_cookie(gg_cookie) return elif results == UNAUTHORIZED: logging.info('An error occurred while fetching results: Expired/invalid authorization token.' ' Terminating...') if config and config['email']['enabled']: recipients = [] for email in config['email']['to']: recipients.append(email['name'] + ' <' + email['address'] + '>') frm = { 'name': config['email']['from']['name'], 'address': config['email']['from']['address'] } try: send_mail(to=recipients, subject='AutoChronoGG: Invalid token', message='An error occurred while fetching results: Expired/invalid authorization token.' ' Terminating...', frm=frm, host=config['email']['server']) except: logging.info('An error occurred while sending an e-mail alert.' ' Please check your configuration file or your mail server.') return logging.info('Done.') save_cookie(gg_cookie) except KeyboardInterrupt: logging.info("Interrupted.") if __name__ == '__main__': with setup_logging(): main()