diff --git a/README.md b/README.md index e56c09f..7bc3182 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ If you have any issues or you want to contribute, you are welcome! But please be ## Main differences from the original repository: -- Improve the logging +- Improve the logging - Emoji, colors, file and soo on - Final report with all the data - Rewrite the entire code using classe instead of module with global variables - Automatic download the follower's list and use it as input @@ -172,8 +172,9 @@ pip install -r requirements.txt # -*- coding: utf-8 -*- import logging +from colorama import Fore from TwitchChannelPointsMiner import TwitchChannelPointsMiner -from TwitchChannelPointsMiner.logger import LoggerSettings +from TwitchChannelPointsMiner.logger import LoggerSettings, ColorPalette from TwitchChannelPointsMiner.classes.Settings import Priority from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings @@ -192,7 +193,13 @@ twitch_miner = TwitchChannelPointsMiner( console_level=logging.INFO, # Level of logs - use logging.DEBUG for more info) file_level=logging.DEBUG, # Level of logs - If you think the log file it's too big, use logging.INFO emoji=True, # On Windows, we have a problem printing emoji. Set to false if you have a problem - less=False # If you think that the logs are too verbose, set this to True + less=False, # If you think that the logs are too verbose, set this to True + colored=True, # If you want to print colored text + color_palette=ColorPalette( # You can also create a custom palette color (for the common message). + STREAMER_online="GREEN", # Don't worry about lower/upper case the script will be parse all the values. + streamer_offline="red", # Read more in README.md + BET_wiN=Fore.MAGENTA # Color allowed are: [BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET]. + ) ), streamer_settings=StreamerSettings( make_predictions=True, # If you want to Bet / Make prediction @@ -273,21 +280,59 @@ Available values are the following: You can combine all priority but keep in mind that use `ORDER` and `POINTS_ASCENDING` in the same settings doesn't make sense. ### LoggerSettings -| Key | Type | Default | Description | -|----------------- |----------------- |-------------------------------- |---------------------------------------------------------------------------------------------------------------------------- | -| `save` | bool | True | If you want to save logs in file (suggested) | -| `less` | bool | False | Reduce the logging format and message verbosity [#10](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/10) | -| `console_level` | level | logging.INFO | Level of logs in terminal - Use logging.DEBUG for more helpful messages. | -| `file_level` | level | logging.DEBUG | Level of logs in file save - If you think the log file it's too big, use logging.INFO | -| `emoji` | bool | For Windows is False else True | On Windows, we have a problem printing emoji. Set to false if you have a problem | +| Key | Type | Default | Description | +|----------------- |----------------- |-------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `save` | bool | True | If you want to save logs in file (suggested) | +| `less` | bool | False | Reduce the logging format and message verbosity [#10](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/10) | +| `console_level` | level | logging.INFO | Level of logs in terminal - Use logging.DEBUG for more helpful messages. | +| `file_level` | level | logging.DEBUG | Level of logs in file save - If you think the log file it's too big, use logging.INFO | +| `emoji` | bool | For Windows is False else True | On Windows, we have a problem printing emoji. Set to false if you have a problem | +| `colored` | bool | True | If you want to print colored text [#45](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/45) [#82](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/82) | +| `color_palette` | ColorPalette | All messages are Fore.RESET except WIN and LOSE bet (GREEN and RED) | Create your custom color palette. Read more above. | + +#### Color Palette +Now you can customize the color of the terminal message. We have created a default ColorPalette that provide all the message with `DEFAULT (RESET)` color and the `BET_WIN` and `BET_LOSE` message `GREEN` and `RED` respectively. +Currently you can only change the following types of messages: + - `STREAMER_ONLINE` + - `STREAMER_OFFLINE` + - `GAIN_FOR_RAID` + - `GAIN_FOR_CLAIM` + - `GAIN_FOR_WATCH` + - `BET_WIN` + - `BET_LOSE` + - `BET_REFUND` + - `BET_FILTERS` + - `BET_GENERAL` + - `BET_FAILED` + - `BET_START` + +The colors allowed are all the Fore color from Colorama: `BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET.` +The script was developed to handle all the human error, lower-case upper case and more, but I want to suggest using the following code-style +```python +from colorama import Fore +ColorPalette( + "STREAMER_ONLINE" = Fore.GREEN, + "STREAMER_OFFLINE" = Fore.RED, + "GAIN_FOR_RAID" = Fore.YELLOW, + "GAIN_FOR_CLAIM" = Fore.YELLOW, + "GAIN_FOR_WATCH" = Fore.YELLOW, + "BET_WIN" = Fore.GREEN, + "BET_LOSE" = Fore.RED, + "BET_REFUND" = Fore.RESET, + "BET_FILTERS" = Fore.MAGENTA, + "BET_GENERAL" = Fore.BLUE, + "BET_FAILED" = Fore.RED, +) +``` + ### StreamerSettings -| Key | Type | Default | Description | -|-------------------- |------------- |-------------------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `make_predictions` | bool | True | Choose if you want to make predictions / bet or not | -| `follow_raid` | bool | True | Choose if you want to follow raid +250 points | +| Key | Type | Default | Description | +|-------------------- |------------- |-------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `make_predictions` | bool | True | Choose if you want to make predictions / bet or not | +| `follow_raid` | bool | True | Choose if you want to follow raid +250 points | | `claim_drops` | bool | True | If this value is True, the script will increase the watch-time for the current game. With this, you are able to claim the drops from Twitch Inventory [#21](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/21) | -| `watch_streak` | bool | True | Choose if you want to change a priority for these streamers and try to catch the Watch Streak event [#11](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/11) | -| `bet` | BetSettings | | Rules to follow for the bet | +| `watch_streak` | bool | True | Choose if you want to change a priority for these streamers and try to catch the Watch Streak event [#11](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/11) | +| `bet` | BetSettings | | Rules to follow for the bet | ### BetSettings | Key | Type | Default | Description | |-------------------- |----------------- |--------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/TwitchChannelPointsMiner/classes/Twitch.py b/TwitchChannelPointsMiner/classes/Twitch.py index d651c72..08ce5ad 100644 --- a/TwitchChannelPointsMiner/classes/Twitch.py +++ b/TwitchChannelPointsMiner/classes/Twitch.py @@ -392,23 +392,36 @@ class Twitch(object): logger.info( f"Going to complete bet for {event}", - extra={"emoji": ":four_leaf_clover:"}, + extra={ + "emoji": ":four_leaf_clover:", + "color": Settings.logger.color_palette.BET_GENERAL, + }, ) if event.status == "ACTIVE": skip, compared_value = event.bet.skip() if skip is True: logger.info( - f"Skip betting for the event {event}", extra={"emoji": ":pushpin:"} + f"Skip betting for the event {event}", + extra={ + "emoji": ":pushpin:", + "color": Settings.logger.color_palette.BET_FILTERS, + }, ) logger.info( f"Skip settings {event.bet.settings.filter_condition}, current value is: {compared_value}", - extra={"emoji": ":pushpin:"}, + extra={ + "emoji": ":pushpin:", + "color": Settings.logger.color_palette.BET_FILTERS, + }, ) else: if decision["amount"] >= 10: logger.info( f"Place {_millify(decision['amount'])} channel points on: {event.bet.get_outcome(selector_index)}", - extra={"emoji": ":four_leaf_clover:"}, + extra={ + "emoji": ":four_leaf_clover:", + "color": Settings.logger.color_palette.BET_GENERAL, + }, ) json_data = copy.deepcopy(GQLOperations.MakePrediction) @@ -424,7 +437,10 @@ class Twitch(object): else: logger.info( f"Oh no! The event is not active anymore! Current status: {event.status}", - extra={"emoji": ":disappointed_relieved:"}, + extra={ + "emoji": ":disappointed_relieved:", + "color": Settings.logger.color_palette.BET_FAILED, + }, ) def claim_bonus(self, streamer, claim_id): diff --git a/TwitchChannelPointsMiner/classes/WebSocketsPool.py b/TwitchChannelPointsMiner/classes/WebSocketsPool.py index f5f85e0..643887f 100644 --- a/TwitchChannelPointsMiner/classes/WebSocketsPool.py +++ b/TwitchChannelPointsMiner/classes/WebSocketsPool.py @@ -9,8 +9,7 @@ from dateutil import parser from TwitchChannelPointsMiner.classes.entities.EventPrediction import EventPrediction from TwitchChannelPointsMiner.classes.entities.Message import Message from TwitchChannelPointsMiner.classes.entities.Raid import Raid - -# from TwitchChannelPointsMiner.classes.Exceptions import TimeBasedDropNotFound +from TwitchChannelPointsMiner.classes.Settings import Settings from TwitchChannelPointsMiner.classes.TwitchWebSocket import TwitchWebSocket from TwitchChannelPointsMiner.constants import WEBSOCKET from TwitchChannelPointsMiner.utils import ( @@ -188,7 +187,12 @@ class WebSocketsPool: reason_code = message.data["point_gain"]["reason_code"] logger.info( f"+{earned} → {ws.streamers[streamer_index]} - Reason: {reason_code}.", - extra={"emoji": ":rocket:"}, + extra={ + "emoji": ":rocket:", + "color": Settings.logger.color_palette.get( + f"GAIN_FOR_{reason_code}" + ), + }, ) ws.streamers[streamer_index].update_history( reason_code, earned @@ -274,7 +278,10 @@ class WebSocketsPool: logger.info( f"Place the bet after: {start_after}s for: {ws.events_predictions[event_id]}", - extra={"emoji": ":alarm_clock:"}, + extra={ + "emoji": ":alarm_clock:", + "color": Settings.logger.color_palette.BET_START, + }, ) elif ( @@ -325,7 +332,12 @@ class WebSocketsPool: ) logger.info( f"{ws.events_predictions[event_id]} - Result: {result_type}, {action}: {points_prefix}{_millify(points_gained)}", - extra={"emoji": ":bar_chart:"}, + extra={ + "emoji": ":bar_chart:", + "color": Settings.logger.color_palette.get( + f"BET_{result_type}" + ), + }, ) ws.events_predictions[event_id].final_result = { "type": event_result["type"], diff --git a/TwitchChannelPointsMiner/classes/entities/Streamer.py b/TwitchChannelPointsMiner/classes/entities/Streamer.py index 4b9ce00..00d0025 100644 --- a/TwitchChannelPointsMiner/classes/entities/Streamer.py +++ b/TwitchChannelPointsMiner/classes/entities/Streamer.py @@ -101,7 +101,13 @@ class Streamer(object): self.offline_at = time.time() self.is_online = False - logger.info(f"{self} is Offline!", extra={"emoji": ":sleeping:"}) + logger.info( + f"{self} is Offline!", + extra={ + "emoji": ":sleeping:", + "color": Settings.logger.color_palette.STREAMER_OFFLINE, + }, + ) def set_online(self): if self.is_online is False: @@ -109,7 +115,13 @@ class Streamer(object): self.is_online = True self.stream.init_watch_streak() - logger.info(f"{self} is Online!", extra={"emoji": ":partying_face:"}) + logger.info( + f"{self} is Online!", + extra={ + "emoji": ":partying_face:", + "color": Settings.logger.color_palette.STREAMER_ONLINE, + }, + ) def print_history(self): return ", ".join( diff --git a/TwitchChannelPointsMiner/logger.py b/TwitchChannelPointsMiner/logger.py index 26321ac..db23266 100644 --- a/TwitchChannelPointsMiner/logger.py +++ b/TwitchChannelPointsMiner/logger.py @@ -5,13 +5,15 @@ from datetime import datetime from pathlib import Path import emoji +from colorama import Fore, init from TwitchChannelPointsMiner.utils import remove_emoji -class EmojiFormatter(logging.Formatter): - def __init__(self, *, fmt, datefmt=None, print_emoji=True): +class GlobalFormatter(logging.Formatter): + def __init__(self, *, fmt, datefmt=None, print_emoji=True, print_colored=False): self.print_emoji = print_emoji + self.print_colored = print_colored logging.Formatter.__init__(self, fmt=fmt, datefmt=datefmt) def format(self, record): @@ -36,9 +38,62 @@ class EmojiFormatter(logging.Formatter): # Full remove using a method from utils. record.msg = remove_emoji(record.msg) + if self.print_colored and hasattr(record, "color"): + record.msg = f"{record.color}{record.msg}" + return super().format(record) +# Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. +class ColorPalette(object): + STREAMER_ONLINE = Fore.RESET + STREAMER_OFFLINE = Fore.RESET + + GAIN_FOR_RAID = Fore.RESET + GAIN_FOR_CLAIM = Fore.RESET + GAIN_FOR_WATCH = Fore.RESET + + BET_WIN = Fore.GREEN + BET_LOSE = Fore.RED + BET_REFUND = Fore.RESET + BET_FILTERS = Fore.RESET + BET_GENERAL = Fore.RESET + BET_FAILED = Fore.RESET + BET_START = Fore.RESET + + def __init__(self, **kwargs): + for k in kwargs: + if k.upper() in dir(self) and getattr(self, k.upper()) is not None: + if kwargs[k] in [ + Fore.BLACK, + Fore.RED, + Fore.GREEN, + Fore.YELLOW, + Fore.BLUE, + Fore.MAGENTA, + Fore.CYAN, + Fore.WHITE, + Fore.RESET, + ]: + setattr(self, k.upper(), kwargs[k]) + elif kwargs[k].upper() in [ + "BLACK", + "RED", + "GREEN", + "YELLOW", + "BLUE", + "MAGENTA", + "CYAN", + "WHITE", + "RESET", + ]: + setattr(self, k.upper(), getattr(Fore, kwargs[k].upper())) + + def get(self, key): + color = getattr(self, key.upper()) if key.upper() in dir(self) else None + return Fore.RESET if color is None else color + + class LoggerSettings: def __init__( self, @@ -47,22 +102,29 @@ class LoggerSettings: console_level: int = logging.INFO, file_level: int = logging.DEBUG, emoji: bool = platform.system() != "Windows", + colored: bool = False, + color_palette: ColorPalette = ColorPalette(), ): self.save = save self.less = less self.console_level = console_level self.file_level = file_level self.emoji = emoji + self.colored = colored + self.color_palette = color_palette def configure_loggers(username, settings): + if settings.colored is True: + init(autoreset=True) + root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) console_handler = logging.StreamHandler() console_handler.setLevel(settings.console_level) console_handler.setFormatter( - EmojiFormatter( + GlobalFormatter( fmt=( "%(asctime)s - %(levelname)s - [%(funcName)s]: %(message)s" if settings.less is False @@ -72,9 +134,9 @@ def configure_loggers(username, settings): "%d/%m/%y %H:%M:%S" if settings.less is False else "%d/%m %H:%M:%S" ), print_emoji=settings.emoji, + print_colored=settings.colored, ) ) - root_logger.addHandler(console_handler) if settings.save is True: logs_path = os.path.join(Path().absolute(), "logs") @@ -85,13 +147,16 @@ def configure_loggers(username, settings): ) file_handler = logging.FileHandler(logs_file, "w", "utf-8") file_handler.setFormatter( - EmojiFormatter( + logging.Formatter( fmt="%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s]: %(message)s", datefmt="%d/%m/%y %H:%M:%S", - print_emoji=settings.emoji, ) ) file_handler.setLevel(settings.file_level) + root_logger.addHandler(file_handler) + root_logger.addHandler(console_handler) return logs_file - return None + else: + root_logger.addHandler(console_handler) + return None diff --git a/example.py b/example.py index a574194..032f010 100644 --- a/example.py +++ b/example.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import logging +from colorama import Fore from TwitchChannelPointsMiner import TwitchChannelPointsMiner -from TwitchChannelPointsMiner.logger import LoggerSettings +from TwitchChannelPointsMiner.logger import LoggerSettings, ColorPalette from TwitchChannelPointsMiner.classes.Settings import Priority from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings @@ -21,7 +22,13 @@ twitch_miner = TwitchChannelPointsMiner( console_level=logging.INFO, # Level of logs - use logging.DEBUG for more info) file_level=logging.DEBUG, # Level of logs - If you think the log file it's too big, use logging.INFO emoji=True, # On Windows, we have a problem printing emoji. Set to false if you have a problem - less=False # If you think that the logs are too verbose, set this to True + less=False, # If you think that the logs are too verbose, set this to True + colored=True, # If you want to print colored text + color_palette=ColorPalette( # You can also create a custom palette color (for the common message). + STREAMER_online="GREEN", # Don't worry about lower/upper case the script will be parse all the values. + streamer_offline="red", # Read more in README.md + BET_wiN=Fore.MAGENTA # Color allowed are: [BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET]. + ) ), streamer_settings=StreamerSettings( make_predictions=True, # If you want to Bet / Make prediction diff --git a/requirements.txt b/requirements.txt index 5a53922..f24eca0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ emoji millify pre-commit flask +colorama diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..8c74855 --- /dev/null +++ b/settings.json @@ -0,0 +1,86 @@ +[ + { + "settings": null, + "username": "r_eqxxx" + }, + { + "settings": null, + "username": "vhauss" + }, + { + "settings": null, + "username": "carriedbyoujua" + }, + { + "settings": null, + "username": "robertcrg" + }, + { + "settings": null, + "username": "blu3berrycupcake" + }, + { + "settings": null, + "username": "brbteabreak" + }, + { + "settings": null, + "username": "nut9tv" + }, + { + "settings": null, + "username": "joaoboavista" + }, + { + "settings": null, + "username": "hyeaga" + }, + { + "settings": null, + "username": "chaosmachinegr" + }, + { + "settings": null, + "username": "malteseknight_" + }, + { + "settings": null, + "username": "daniel_rusev" + }, + { + "settings": null, + "username": "serwinterofficial" + }, + { + "settings": null, + "username": "shadowfrax" + }, + { + "settings": null, + "username": "boxbox" + }, + { + "settings": null, + "username": "ash_on_lol" + }, + { + "settings": null, + "username": "dyannatv" + }, + { + "settings": null, + "username": "mammoth" + }, + { + "settings": null, + "username": "bchillz" + }, + { + "settings": null, + "username": "buddha" + }, + { + "settings": null, + "username": "trausi" + } +]