diff --git a/README.md b/README.md index 92815f1..1d5f3df 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ from colorama import Fore from TwitchChannelPointsMiner import TwitchChannelPointsMiner from TwitchChannelPointsMiner.logger import LoggerSettings, ColorPalette from TwitchChannelPointsMiner.classes.Telegram import Telegram -from TwitchChannelPointsMiner.classes.Settings import Priority, Events +from TwitchChannelPointsMiner.classes.Settings import Priority, Events, FollowersOrder from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition, DelayMode from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings @@ -194,11 +194,11 @@ twitch_miner = TwitchChannelPointsMiner( priority=[ # Custom priority in this case for example: Priority.STREAK, # - We want first of all to catch all watch streak from all streamers Priority.DROPS, # - When we don't have anymore watch streak to catch, wait until all drops are collected over the streamers - Priority.ORDER # - When we have all of the drops claimed and no watch-streak available, use the order priority (POINTS_ASCENDING, POINTS_DESCEDING) + Priority.ORDER # - When we have all of the drops claimed and no watch-streak available, use the order priority (POINTS_ASCENDING, POINTS_DESCEDING) ], logger_settings=LoggerSettings( save=True, # If you want to save logs in a file (suggested) - console_level=logging.INFO, # Level of logs - use logging.DEBUG for more info) + 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 @@ -219,12 +219,12 @@ twitch_miner = TwitchChannelPointsMiner( make_predictions=True, # If you want to Bet / Make prediction follow_raid=True, # Follow raid to obtain more points claim_drops=True, # We can't filter rewards base on stream. Set to False for skip viewing counter increase and you will never obtain a drop reward from this script. Issue #21 - watch_streak=True, # If a streamer go online change the priotiry of streamers array and catch the watch screak. Issue #11 + watch_streak=True, # If a streamer go online change the priority of streamers array and catch the watch streak. Issue #11 join_chat=True, # Join irc chat to increase watch-time bet=BetSettings( strategy=Strategy.SMART, # Choose you strategy! percentage=5, # Place the x% of your channel points - percentage_gap=20, # Gap difference between outcomesA and outcomesB (for SMART stragegy) + percentage_gap=20, # Gap difference between outcomesA and outcomesB (for SMART strategy) max_points=50000, # If the x percentage of your channel points is gt bet_max_points set this value stealth_mode=True, # If the calculated amount of channel points is GT the highest bet, place the highest value minus 1-2 points Issue #33 delay_mode=DelayMode.FROM_END, # When placing a bet, we will wait until `delay` seconds before the end of the timer @@ -261,16 +261,18 @@ twitch_miner.mine( "streamer-username10", "streamer-username11" ], # Array of streamers (order = priority) - followers=False # Automatic download the list of your followers (unable to set custom settings for you followers list) + followers=False, # Automatic download the list of your followers + order=FollowersOrder.ASC # Sort the followers list by follow date. ASC or DESC ) ``` You can also use all the default values except for your username obv. Short version: ```python from TwitchChannelPointsMiner import TwitchChannelPointsMiner +from TwitchChannelPointsMiner.classes.Settings import FollowersOrder twitch_miner = TwitchChannelPointsMiner("your-twitch-username") -twitch_miner.mine(["streamer1", "streamer2"]) # Array of streamers OR -twitch_miner.mine(followers=True) # Automatic use the followers list OR -twitch_miner.mine(["streamer1", "streamer2"], followers=True) # Mixed +twitch_miner.mine(["streamer1", "streamer2"]) # Array of streamers OR +twitch_miner.mine(followers=True, order=FollowersOrder.ASC) # Automatic use the followers list OR +twitch_miner.mine(["streamer1", "streamer2"], followers=True, order=FollowersOrder.DESC) # Mixed ``` If you follow so many streamers on Twitch, but you don't want to mine points for all of them, you can blacklist the users with the `blacklist` keyword. [#94](https://github.com/Tkd-Alex/Twitch-Channel-Points-Miner-v2/issues/94) ```python @@ -355,7 +357,7 @@ About the *Docker* version; the community has always shown great interest in the ### Limits > Twitch has a limit - you can't watch more than two channels at one time. We take the first two streamers from the list as they have the highest priority. -Make sure to write the streamers array in order of priority from left to right. If you use `followers=True` Twitch return the streamers order by followed_at. So your last follow has the highest priority. +Make sure to write the streamers array in order of priority from left to right. If you use `followers=True` you can choose to download the followers sorted by follow date (ASC or DESC). ## Settings Most of the settings are self-explained and are commented on in the example. diff --git a/TwitchChannelPointsMiner/TwitchChannelPointsMiner.py b/TwitchChannelPointsMiner/TwitchChannelPointsMiner.py index fb32852..1cfb304 100644 --- a/TwitchChannelPointsMiner/TwitchChannelPointsMiner.py +++ b/TwitchChannelPointsMiner/TwitchChannelPointsMiner.py @@ -19,7 +19,7 @@ from TwitchChannelPointsMiner.classes.entities.Streamer import ( StreamerSettings, ) from TwitchChannelPointsMiner.classes.Exceptions import StreamerDoesNotExistException -from TwitchChannelPointsMiner.classes.Settings import Priority, Settings +from TwitchChannelPointsMiner.classes.Settings import FollowersOrder, Priority, Settings from TwitchChannelPointsMiner.classes.Twitch import Twitch from TwitchChannelPointsMiner.classes.WebSocketsPool import WebSocketsPool from TwitchChannelPointsMiner.logger import LoggerSettings, configure_loggers @@ -129,10 +129,22 @@ class TwitchChannelPointsMiner: http_server.name = "Analytics Thread" http_server.start() - def mine(self, streamers: list = [], blacklist: list = [], followers=False): + def mine( + self, + streamers: list = [], + blacklist: list = [], + followers: bool = False, + followers_order: FollowersOrder = FollowersOrder.ASC, + ): self.run(streamers=streamers, blacklist=blacklist, followers=followers) - def run(self, streamers: list = [], blacklist: list = [], followers=False): + def run( + self, + streamers: list = [], + blacklist: list = [], + followers: bool = False, + followers_order: FollowersOrder = FollowersOrder.ASC, + ): if self.running: logger.error("You can't start multiple sessions of this instance!") else: @@ -161,7 +173,7 @@ class TwitchChannelPointsMiner: streamers_dict[username] = streamer if followers is True: - followers_array = self.twitch.get_followers() + followers_array = self.twitch.get_followers(order=followers_order) logger.info( f"Load {len(followers_array)} followers from your profile!", extra={"emoji": ":clipboard:"}, diff --git a/TwitchChannelPointsMiner/__init__.py b/TwitchChannelPointsMiner/__init__.py index cf775fa..b9c3413 100644 --- a/TwitchChannelPointsMiner/__init__.py +++ b/TwitchChannelPointsMiner/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -__version__ = "2.0.5" +__version__ = "2.0.6" from .TwitchChannelPointsMiner import TwitchChannelPointsMiner __all__ = [ diff --git a/TwitchChannelPointsMiner/classes/Settings.py b/TwitchChannelPointsMiner/classes/Settings.py index 1739f9b..8062408 100644 --- a/TwitchChannelPointsMiner/classes/Settings.py +++ b/TwitchChannelPointsMiner/classes/Settings.py @@ -10,6 +10,14 @@ class Priority(Enum): POINTS_DESCEDING = auto() +class FollowersOrder(Enum): + ASC = auto() + DESC = auto() + + def __str__(self): + return self.name + + # Empty object shared between class class Settings(object): __slots__ = ["logger", "streamer_settings"] diff --git a/TwitchChannelPointsMiner/classes/Twitch.py b/TwitchChannelPointsMiner/classes/Twitch.py index 80749a4..cd678da 100644 --- a/TwitchChannelPointsMiner/classes/Twitch.py +++ b/TwitchChannelPointsMiner/classes/Twitch.py @@ -21,7 +21,12 @@ from TwitchChannelPointsMiner.classes.Exceptions import ( StreamerDoesNotExistException, StreamerIsOfflineException, ) -from TwitchChannelPointsMiner.classes.Settings import Events, Priority, Settings +from TwitchChannelPointsMiner.classes.Settings import ( + Events, + FollowersOrder, + Priority, + Settings, +) from TwitchChannelPointsMiner.classes.TwitchLogin import TwitchLogin from TwitchChannelPointsMiner.constants import CLIENT_ID, GQLOperations from TwitchChannelPointsMiner.utils import ( @@ -155,22 +160,28 @@ class Twitch(object): else: return json_response["data"]["user"]["id"] - def get_followers(self): - json_data = copy.deepcopy(GQLOperations.PersonalSections) - json_response = self.post_gql_request(json_data) - try: - if ( - "data" in json_response - and "personalSections" in json_response["data"] - and json_response["data"]["personalSections"] != [] - ): - return [ - fw["user"]["login"] - for fw in json_response["data"]["personalSections"][0]["items"] - if fw["user"] is not None - ] - except KeyError: - return [] + def get_followers( + self, limit: int = 100, order: FollowersOrder = FollowersOrder.ASC + ): + json_data = copy.deepcopy(GQLOperations.ChannelFollows) + json_data["variables"] = {"limit": limit, "order": str(order)} + has_next = True + last_cursor = "" + follows = [] + while has_next is True and last_cursor != "": + json_data["variables"]["cursor"] = last_cursor + json_response = self.post_gql_request(json_data) + try: + follows_response = json_response["data"]["user"]["follows"] + last_cursor = None + for f in follows_response["edges"]: + follows.append(f["node"]["login"].lower()) + last_cursor = f["cursor"] + + has_next = follows_response["pageInfo"]["hasNextPage"] + except KeyError: + return [] + return follows def update_raid(self, streamer, raid): if streamer.raid != raid: diff --git a/TwitchChannelPointsMiner/constants.py b/TwitchChannelPointsMiner/constants.py index 96a8d99..c502433 100644 --- a/TwitchChannelPointsMiner/constants.py +++ b/TwitchChannelPointsMiner/constants.py @@ -145,21 +145,33 @@ class GQLOperations: } }, } - PersonalSections = { - "operationName": "PersonalSections", - "variables": { - "input": { - "sectionInputs": ["FOLLOWED_SECTION"], - "recommendationContext": {"platform": "web"}, + PersonalSections = ( + { + "operationName": "PersonalSections", + "variables": { + "input": { + "sectionInputs": ["FOLLOWED_SECTION"], + "recommendationContext": {"platform": "web"}, + }, + "channelLogin": None, + "withChannelUser": False, + "creatorAnniversariesExperimentEnabled": False, + }, + "extensions": { + "persistedQuery": { + "version": 1, + "sha256Hash": "9fbdfb00156f754c26bde81eb47436dee146655c92682328457037da1a48ed39", + } }, - "channelLogin": None, - "withChannelUser": False, - "creatorAnniversariesExperimentEnabled": False, }, + ) + ChannelFollows = { + "operationName": "ChannelFollows", + "variables": {"limit": 100, "order": "ASC"}, "extensions": { "persistedQuery": { "version": 1, - "sha256Hash": "9fbdfb00156f754c26bde81eb47436dee146655c92682328457037da1a48ed39", + "sha256Hash": "4b9cb31b54b9213e5760f2f6e9e935ad09924cac2f78aac51f8a64d85f028ed0", } }, } diff --git a/example.py b/example.py index 3caa170..7257a79 100644 --- a/example.py +++ b/example.py @@ -5,7 +5,7 @@ from colorama import Fore from TwitchChannelPointsMiner import TwitchChannelPointsMiner from TwitchChannelPointsMiner.logger import LoggerSettings, ColorPalette from TwitchChannelPointsMiner.classes.Telegram import Telegram -from TwitchChannelPointsMiner.classes.Settings import Priority, Events +from TwitchChannelPointsMiner.classes.Settings import Priority, Events, FollowersOrder from TwitchChannelPointsMiner.classes.entities.Bet import Strategy, BetSettings, Condition, OutcomeKeys, FilterCondition, DelayMode from TwitchChannelPointsMiner.classes.entities.Streamer import Streamer, StreamerSettings @@ -83,5 +83,6 @@ twitch_miner.mine( "streamer-username10", "streamer-username11" ], # Array of streamers (order = priority) - followers=False # Automatic download the list of your followers (unable to set custom settings for you followers list) + followers=False, # Automatic download the list of your followers + order=FollowersOrder.ASC # Sort the followers list by follow date. ASC or DESC )