def run(self, streamers: list = [], followers=False): if self.running: logger.error("You can't start multiple sessions of this instance!") else: logger.info(f"Start session: '{self.session_id}'", extra={"emoji": ":bomb:"}) self.running = True self.start_datetime = datetime.now() self.twitch.login() if self.claim_drops_startup is True: self.twitch.claim_all_drops_from_inventory() streamers_name: list = [] streamers_dict: dict = {} for streamer in streamers: username = (streamer.username if isinstance( streamer, Streamer) else streamer.lower().strip()) streamers_name.append(username) streamers_dict[username] = streamer if followers is True: followers_array = self.twitch.get_followers() logger.info( f"Load {len(followers_array)} followers from your profile!", extra={"emoji": ":clipboard:"}, ) for username in followers_array: if username not in streamers_dict: streamers_dict[username] = username.lower().strip() else: followers_array = [] streamers_name = list( OrderedDict.fromkeys(streamers_name + followers_array)) logger.info( f"Loading data for {len(streamers_name)} streamers. Please wait...", extra={"emoji": ":nerd_face:"}, ) for username in streamers_name: time.sleep(random.uniform(0.3, 0.7)) try: if isinstance(streamers_dict[username], Streamer) is True: streamer = streamers_dict[username] else: streamer = Streamer(username) streamer.channel_id = self.twitch.get_channel_id(username) streamer.settings = set_default_settings( streamer.settings, Settings.streamer_settings) streamer.settings.bet = set_default_settings( streamer.settings.bet, Settings.streamer_settings.bet) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( f"Streamer {username} does not exist", extra={"emoji": ":cry:"}, ) # Populate the streamers with default values. # 1. Load channel points and auto-claim bonus # 2. Check if streamers is online # 3. Check if the user is a Streamer. In thi case you can't do prediction for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) self.twitch.viewer_is_mod(streamer) if streamer.viewer_is_mod is True: streamer.settings.make_predictions = False self.original_streamers = copy.deepcopy(self.streamers) # If we have at least one streamer with settings = make_predictions True make_predictions = at_least_one_value_in_settings_is( self.streamers, "make_predictions", True) self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=( self.streamers, at_least_one_value_in_settings_is(self.streamers, "watch_streak", True), ), ) self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, streamers=self.streamers, events_predictions=self.events_predictions, ) # Subscribe to community-points-user. Get update for points spent or gains self.ws_pool.submit( PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) # If we have at least one streamer with settings = claim_drops True # Going to subscribe to user-drop-events. Get update for drop-progress claim_drops = at_least_one_value_in_settings_is( self.streamers, "claim_drops", True) if claim_drops is True: self.ws_pool.submit( PubsubTopic( "user-drop-events", user_id=self.twitch.twitch_login.get_user_id(), )) # Going to subscribe to predictions-user-v1. Get update when we place a new prediction (confirm) if make_predictions is True: self.ws_pool.submit( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) for streamer in self.streamers: self.ws_pool.submit( PubsubTopic("video-playback-by-id", streamer=streamer)) if streamer.settings.follow_raid is True: self.ws_pool.submit(PubsubTopic("raid", streamer=streamer)) if streamer.settings.make_predictions is True: self.ws_pool.submit( PubsubTopic("predictions-channel-v1", streamer=streamer)) while self.running: time.sleep(random.uniform(20, 60)) # Do an external control for WebSocket. Check if the thread is running # Check if is not None because maybe we have already created a new connection on array+1 and now index is None for index in range(0, len(self.ws_pool.ws)): if (self.ws_pool.ws[index] is not None and self.ws_pool.ws[index].elapsed_last_ping() > 10): logger.info( f"#{index} - The last PING was sent more than 10 minutes ago. Reconnecting to the WebSocket..." ) WebSocketsPool.handle_reconnection( self.ws_pool.ws[index])
class TwitchChannelPointsMiner: def __init__( self, username: str, claim_drops_startup: bool = False, # This settings will be global shared trought Settings class logger_settings: LoggerSettings = LoggerSettings(), # Default values for all streamers streamer_settings: StreamerSettings = StreamerSettings(), ): self.username = username # Set as globally config Settings.logger = logger_settings # Init as default all the missing values streamer_settings.default() streamer_settings.bet.default() Settings.streamer_settings = streamer_settings user_agent = get_user_agent("FIREFOX") self.twitch = Twitch(self.username, user_agent) self.claim_drops_startup = claim_drops_startup self.streamers = [] self.events_predictions = {} self.minute_watcher_thread = None self.ws_pool = None self.session_id = str(uuid.uuid4()) self.running = False self.start_datetime = None self.original_streamers = [] self.logs_file = configure_loggers(self.username, logger_settings) for sign in [signal.SIGINT, signal.SIGSEGV, signal.SIGTERM]: signal.signal(sign, self.end) def mine(self, streamers: list = [], followers=False): self.run(streamers, followers) def run(self, streamers: list = [], followers=False): if self.running: logger.error("You can't start multiple sessions of this instance!") else: logger.info(f"Start session: '{self.session_id}'", extra={"emoji": ":bomb:"}) self.running = True self.start_datetime = datetime.now() self.twitch.login() if self.claim_drops_startup is True: self.twitch.claim_all_drops_from_inventory() streamers_name: list = [] streamers_dict: dict = {} for streamer in streamers: username = (streamer.username if isinstance( streamer, Streamer) else streamer.lower().strip()) streamers_name.append(username) streamers_dict[username] = streamer if followers is True: followers_array = self.twitch.get_followers() logger.info( f"Load {len(followers_array)} followers from your profile!", extra={"emoji": ":clipboard:"}, ) for username in followers_array: if username not in streamers_dict: streamers_dict[username] = username.lower().strip() else: followers_array = [] streamers_name = list( OrderedDict.fromkeys(streamers_name + followers_array)) logger.info( f"Loading data for {len(streamers_name)} streamers. Please wait...", extra={"emoji": ":nerd_face:"}, ) for username in streamers_name: time.sleep(random.uniform(0.3, 0.7)) try: if isinstance(streamers_dict[username], Streamer) is True: streamer = streamers_dict[username] else: streamer = Streamer(username) streamer.channel_id = self.twitch.get_channel_id(username) streamer.settings = set_default_settings( streamer.settings, Settings.streamer_settings) streamer.settings.bet = set_default_settings( streamer.settings.bet, Settings.streamer_settings.bet) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( f"Streamer {username} does not exist", extra={"emoji": ":cry:"}, ) # Populate the streamers with default values. # 1. Load channel points and auto-claim bonus # 2. Check if streamers is online # 3. Check if the user is a Streamer. In thi case you can't do prediction for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) self.twitch.viewer_is_mod(streamer) if streamer.viewer_is_mod is True: streamer.settings.make_predictions = False self.original_streamers = copy.deepcopy(self.streamers) # If we have at least one streamer with settings = make_predictions True make_predictions = at_least_one_value_in_settings_is( self.streamers, "make_predictions", True) self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=( self.streamers, at_least_one_value_in_settings_is(self.streamers, "watch_streak", True), ), ) self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, streamers=self.streamers, events_predictions=self.events_predictions, ) # Subscribe to community-points-user. Get update for points spent or gains self.ws_pool.submit( PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) # If we have at least one streamer with settings = claim_drops True # Going to subscribe to user-drop-events. Get update for drop-progress claim_drops = at_least_one_value_in_settings_is( self.streamers, "claim_drops", True) if claim_drops is True: self.ws_pool.submit( PubsubTopic( "user-drop-events", user_id=self.twitch.twitch_login.get_user_id(), )) # Going to subscribe to predictions-user-v1. Get update when we place a new prediction (confirm) if make_predictions is True: self.ws_pool.submit( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) for streamer in self.streamers: self.ws_pool.submit( PubsubTopic("video-playback-by-id", streamer=streamer)) if streamer.settings.follow_raid is True: self.ws_pool.submit(PubsubTopic("raid", streamer=streamer)) if streamer.settings.make_predictions is True: self.ws_pool.submit( PubsubTopic("predictions-channel-v1", streamer=streamer)) while self.running: time.sleep(random.uniform(20, 60)) # Do an external control for WebSocket. Check if the thread is running # Check if is not None because maybe we have already created a new connection on array+1 and now index is None for index in range(0, len(self.ws_pool.ws)): if (self.ws_pool.ws[index] is not None and self.ws_pool.ws[index].elapsed_last_ping() > 10): logger.info( f"#{index} - The last PING was sent more than 10 minutes ago. Reconnecting to the WebSocket..." ) WebSocketsPool.handle_reconnection( self.ws_pool.ws[index]) def end(self, signum, frame): logger.info("CTRL+C Detected! Please wait just a moments!") self.running = self.twitch.running = False self.ws_pool.end() self.minute_watcher_thread.join() time.sleep(1) self.__print_report() sys.exit(0) def __print_report(self): print("\n") 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:"}) logger.info( f"Duration {datetime.now() - self.start_datetime}", extra={"emoji": ":hourglass:"}, ) if self.events_predictions != {}: print("") for event_id in self.events_predictions: if (self.events_predictions[event_id].bet_confirmed is True and self.events_predictions[event_id].streamer. settings.make_predictions is True): logger.info( f"{self.events_predictions[event_id].streamer.settings.bet}", extra={"emoji": ":wrench:"}, ) if (self.events_predictions[event_id].streamer.settings. bet.filter_condition is not None): logger.info( f"{self.events_predictions[event_id].streamer.settings.bet.filter_condition}", extra={"emoji": ":pushpin:"}, ) logger.info( f"{self.events_predictions[event_id].print_recap()}", extra={"emoji": ":bar_chart:"}, ) print("") for streamer_index in range(0, len(self.streamers)): if self.streamers[streamer_index].history != {}: logger.info( f"{repr(self.streamers[streamer_index])}, Total Points Gained (after farming - before farming): {_millify(self.streamers[streamer_index].channel_points - self.original_streamers[streamer_index].channel_points)}", extra={"emoji": ":robot:"}, ) if self.streamers[streamer_index].history != {}: logger.info( f"{self.streamers[streamer_index].print_history()}", extra={"emoji": ":moneybag:"}, )
class TwitchChannelPointsMiner: __slots__ = [ "username", "twitch", "claim_drops_startup", "priority", "streamers", "events_predictions", "minute_watcher_thread", "sync_campaigns_thread", "ws_pool", "session_id", "running", "start_datetime", "original_streamers", "logs_file", ] def __init__( self, username: str, password: str = None, claim_drops_startup: bool = False, # Settings for logging and selenium as you can see. priority: list = [Priority.STREAK, Priority.DROPS, Priority.ORDER], # This settings will be global shared trought Settings class logger_settings: LoggerSettings = LoggerSettings(), # Default values for all streamers streamer_settings: StreamerSettings = StreamerSettings(), ): Settings.analytics_path = os.path.join(Path().absolute(), "analytics", username) Path(Settings.analytics_path).mkdir(parents=True, exist_ok=True) self.username = username # Set as global config Settings.logger = logger_settings # Init as default all the missing values streamer_settings.default() streamer_settings.bet.default() Settings.streamer_settings = streamer_settings user_agent = get_user_agent("FIREFOX") self.twitch = Twitch(self.username, user_agent, password) self.claim_drops_startup = claim_drops_startup self.priority = priority if isinstance(priority, list) else [priority] self.streamers = [] self.events_predictions = {} self.minute_watcher_thread = None self.sync_campaigns_thread = None self.ws_pool = None self.session_id = str(uuid.uuid4()) self.running = False self.start_datetime = None self.original_streamers = [] self.logs_file = configure_loggers(self.username, logger_settings) for sign in [signal.SIGINT, signal.SIGSEGV, signal.SIGTERM]: signal.signal(sign, self.end) def analytics(self, host: str = "127.0.0.1", port: int = 5000, refresh: int = 5): http_server = AnalyticsServer(host=host, port=port, refresh=refresh) http_server.daemon = True http_server.name = "Analytics Thread" http_server.start() def mine(self, streamers: list = [], blacklist: list = [], followers=False): self.run(streamers=streamers, blacklist=blacklist, followers=followers) def run(self, streamers: list = [], blacklist: list = [], followers=False): if self.running: logger.error("You can't start multiple sessions of this instance!") else: logger.info( f"Start session: '{self.session_id}'", extra={"emoji": ":bomb:"} ) self.running = True self.start_datetime = datetime.now() self.twitch.login() if self.claim_drops_startup is True: self.twitch.claim_all_drops_from_inventory() streamers_name: list = [] streamers_dict: dict = {} for streamer in streamers: username = ( streamer.username if isinstance(streamer, Streamer) else streamer.lower().strip() ) if username not in blacklist: streamers_name.append(username) streamers_dict[username] = streamer if followers is True: followers_array = self.twitch.get_followers() logger.info( f"Load {len(followers_array)} followers from your profile!", extra={"emoji": ":clipboard:"}, ) for username in followers_array: if username not in streamers_dict and username not in blacklist: streamers_dict[username] = username.lower().strip() else: followers_array = [] streamers_name = list( OrderedDict.fromkeys(streamers_name + followers_array) ) logger.info( f"Loading data for {len(streamers_name)} streamers. Please wait...", extra={"emoji": ":nerd_face:"}, ) for username in streamers_name: time.sleep(random.uniform(0.3, 0.7)) try: streamer = ( streamers_dict[username] if isinstance(streamers_dict[username], Streamer) is True else Streamer(username) ) streamer.channel_id = self.twitch.get_channel_id(username) streamer.settings = set_default_settings( streamer.settings, Settings.streamer_settings ) streamer.settings.bet = set_default_settings( streamer.settings.bet, Settings.streamer_settings.bet ) if streamer.settings.join_chat is True: streamer.irc_chat = ThreadChat( self.username, self.twitch.twitch_login.get_auth_token(), streamer.username, ) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( f"Streamer {username} does not exist", extra={"emoji": ":cry:"}, ) # Populate the streamers with default values. # 1. Load channel points and auto-claim bonus # 2. Check if streamers are online # 3. Check if the user is a Streamer. In thi case you can't do prediction for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) self.twitch.viewer_is_mod(streamer) if streamer.viewer_is_mod is True: streamer.settings.make_predictions = False self.original_streamers = [ streamer.channel_points for streamer in self.streamers ] # If we have at least one streamer with settings = make_predictions True make_predictions = at_least_one_value_in_settings_is( self.streamers, "make_predictions", True ) # If we have at least one streamer with settings = claim_drops True # Spawn a thread for sync inventory and dashboard if ( at_least_one_value_in_settings_is(self.streamers, "claim_drops", True) is True ): self.sync_campaigns_thread = threading.Thread( target=self.twitch.sync_campaigns, args=(self.streamers,), ) self.sync_campaigns_thread.name = "Sync campaigns/inventory" self.sync_campaigns_thread.start() time.sleep(30) self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=(self.streamers, self.priority), ) self.minute_watcher_thread.name = "Minute watcher" self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, streamers=self.streamers, events_predictions=self.events_predictions, ) # Subscribe to community-points-user. Get update for points spent or gains self.ws_pool.submit( PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), ) ) # Going to subscribe to predictions-user-v1. Get update when we place a new prediction (confirm) if make_predictions is True: self.ws_pool.submit( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), ) ) for streamer in self.streamers: self.ws_pool.submit( PubsubTopic("video-playback-by-id", streamer=streamer) ) if streamer.settings.follow_raid is True: self.ws_pool.submit(PubsubTopic("raid", streamer=streamer)) if streamer.settings.make_predictions is True: self.ws_pool.submit( PubsubTopic("predictions-channel-v1", streamer=streamer) ) refresh_context = time.time() while self.running: time.sleep(random.uniform(20, 60)) # Do an external control for WebSocket. Check if the thread is running # Check if is not None because maybe we have already created a new connection on array+1 and now index is None for index in range(0, len(self.ws_pool.ws)): if ( self.ws_pool.ws[index].is_reconneting is False and self.ws_pool.ws[index].elapsed_last_ping() > 10 and internet_connection_available() is True ): logger.info( f"#{index} - The last PING was sent more than 10 minutes ago. Reconnecting to the WebSocket..." ) WebSocketsPool.handle_reconnection(self.ws_pool.ws[index]) if ((time.time() - refresh_context) // 60) >= 30: refresh_context = time.time() for index in range(0, len(self.streamers)): if self.streamers[index].is_online: self.twitch.load_channel_points_context( self.streamers[index] ) def end(self, signum, frame): logger.info("CTRL+C Detected! Please wait just a moment!") for streamer in self.streamers: if streamer.irc_chat is not None: streamer.leave_chat() if streamer.irc_chat.is_alive() is True: streamer.irc_chat.join() self.running = self.twitch.running = False self.ws_pool.end() if self.minute_watcher_thread is not None: self.minute_watcher_thread.join() if self.sync_campaigns_thread is not None: self.sync_campaigns_thread.join() # Check if all the mutex are unlocked. # Prevent breaks of .json file for streamer in self.streamers: if streamer.mutex.locked(): streamer.mutex.acquire() streamer.mutex.release() self.__print_report() sys.exit(0) def __print_report(self): print("\n") 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:"} ) logger.info( f"Duration {datetime.now() - self.start_datetime}", extra={"emoji": ":hourglass:"}, ) if self.events_predictions != {}: print("") for event_id in self.events_predictions: event = self.events_predictions[event_id] if ( event.bet_confirmed is True and event.streamer.settings.make_predictions is True ): logger.info( f"{event.streamer.settings.bet}", extra={"emoji": ":wrench:"}, ) if event.streamer.settings.bet.filter_condition is not None: logger.info( f"{event.streamer.settings.bet.filter_condition}", extra={"emoji": ":pushpin:"}, ) logger.info( f"{event.print_recap()}", extra={"emoji": ":bar_chart:"}, ) print("") for streamer_index in range(0, len(self.streamers)): if self.streamers[streamer_index].history != {}: gained = ( self.streamers[streamer_index].channel_points - self.original_streamers[streamer_index] ) logger.info( f"{repr(self.streamers[streamer_index])}, Total Points Gained (after farming - before farming): {_millify(gained)}", extra={"emoji": ":robot:"}, ) if self.streamers[streamer_index].history != {}: logger.info( f"{self.streamers[streamer_index].print_history()}", extra={"emoji": ":moneybag:"}, )
def run(self, streamers: list = [], blacklist: list = [], followers=False): if self.running: logger.error("You can't start multiple sessions of this instance!") else: logger.info(f"Start session: '{self.session_id}'", extra={"emoji": ":bomb:"}) self.running = True self.start_datetime = datetime.now() self.twitch.login() if self.claim_drops_startup is True: self.twitch.claim_all_drops_from_inventory() streamers_name: list = [] streamers_dict: dict = {} for streamer in streamers: username = (streamer.username if isinstance( streamer, Streamer) else streamer.lower().strip()) if username not in blacklist: streamers_name.append(username) streamers_dict[username] = streamer if followers is True: followers_array = self.twitch.get_followers() logger.info( f"Load {len(followers_array)} followers from your profile!", extra={"emoji": ":clipboard:"}, ) for username in followers_array: if username not in streamers_dict and username not in blacklist: streamers_dict[username] = username.lower().strip() else: followers_array = [] streamers_name = list( OrderedDict.fromkeys(streamers_name + followers_array)) streamers_name = [ name for name in streamers_name if name not in blacklist ] logger.info( f"Loading data for {len(streamers_name)} streamers. Please wait...", extra={"emoji": ":nerd_face:"}, ) for username in streamers_name: if username in streamers_name: time.sleep(random.uniform(0.3, 0.7)) try: streamer = (streamers_dict[username] if isinstance( streamers_dict[username], Streamer) is True else Streamer(username)) streamer.channel_id = self.twitch.get_channel_id( username) streamer.settings = set_default_settings( streamer.settings, Settings.streamer_settings) streamer.settings.bet = set_default_settings( streamer.settings.bet, Settings.streamer_settings.bet) if streamer.settings.join_chat is True: streamer.irc_chat = ThreadChat( self.username, self.twitch.twitch_login.get_auth_token(), streamer.username, ) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( f"Streamer {username} does not exist", extra={"emoji": ":cry:"}, ) # Populate the streamers with default values. # 1. Load channel points and auto-claim bonus # 2. Check if streamers are online # 3. DEACTIVATED: Check if the user is a moderator. (was used before the 5th of April 2021 to deactivate predictions) for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) # self.twitch.viewer_is_mod(streamer) self.original_streamers = [ streamer.channel_points for streamer in self.streamers ] # If we have at least one streamer with settings = make_predictions True make_predictions = at_least_one_value_in_settings_is( self.streamers, "make_predictions", True) # If we have at least one streamer with settings = claim_drops True # Spawn a thread for sync inventory and dashboard if (at_least_one_value_in_settings_is( self.streamers, "claim_drops", True) is True): self.sync_campaigns_thread = threading.Thread( target=self.twitch.sync_campaigns, args=(self.streamers, ), ) self.sync_campaigns_thread.name = "Sync campaigns/inventory" self.sync_campaigns_thread.start() time.sleep(30) self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=(self.streamers, self.priority), ) self.minute_watcher_thread.name = "Minute watcher" self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, streamers=self.streamers, events_predictions=self.events_predictions, ) # Subscribe to community-points-user. Get update for points spent or gains self.ws_pool.submit( PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) # Going to subscribe to predictions-user-v1. Get update when we place a new prediction (confirm) if make_predictions is True: self.ws_pool.submit( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) for streamer in self.streamers: self.ws_pool.submit( PubsubTopic("video-playback-by-id", streamer=streamer)) if streamer.settings.follow_raid is True: self.ws_pool.submit(PubsubTopic("raid", streamer=streamer)) if streamer.settings.make_predictions is True: self.ws_pool.submit( PubsubTopic("predictions-channel-v1", streamer=streamer)) refresh_context = time.time() while self.running: time.sleep(random.uniform(20, 60)) # Do an external control for WebSocket. Check if the thread is running # Check if is not None because maybe we have already created a new connection on array+1 and now index is None for index in range(0, len(self.ws_pool.ws)): if (self.ws_pool.ws[index].is_reconneting is False and self.ws_pool.ws[index].elapsed_last_ping() > 10 and internet_connection_available() is True): logger.info( f"#{index} - The last PING was sent more than 10 minutes ago. Reconnecting to the WebSocket..." ) WebSocketsPool.handle_reconnection( self.ws_pool.ws[index]) if ((time.time() - refresh_context) // 60) >= 30: refresh_context = time.time() for index in range(0, len(self.streamers)): if self.streamers[index].is_online: self.twitch.load_channel_points_context( self.streamers[index])
def run(self, streamers: list = []): if self.running: logger.error("You can't start multiple session of this istance!") else: logger.info( emoji.emojize(f":bomb: Start session: '{self.session_id}'", use_aliases=True)) self.running = True self.start_datetime = datetime.now() self.twitch.login() for streamer_username in streamers: time.sleep(random.uniform(0.3, 0.7)) streamer_username.lower().strip() try: channel_id = self.twitch.get_channel_id(streamer_username) streamer = Streamer(streamer_username, channel_id) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( emoji.emojize( f":cry: Streamer {streamer_username} does not exist", use_aliases=True, )) for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) self.original_streamers = copy.deepcopy(self.streamers) if (self.make_predictions is True): # We need a browser to make predictions / bet self.twitch_browser = TwitchBrowser( self.twitch.twitch_login.get_auth_token(), self.session_id, settings=self.browser_settings, ) self.twitch_browser.init() self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=(self.streamers, )) self.minute_watcher_thread.daemon = True self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, twitch_browser=self.twitch_browser, streamers=self.streamers, bet_settings=self.bet_settings, events_predictions=self.events_predictions, ) topics = [ PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), ) ] if self.make_predictions is True: topics.append( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) for streamer in self.streamers: topics.append( PubsubTopic("video-playback-by-id", streamer=streamer)) if self.follow_raid is True: topics.append(PubsubTopic("raid", streamer=streamer)) if self.make_predictions is True: topics.append( PubsubTopic("predictions-channel-v1", streamer=streamer)) for topic in topics: self.ws_pool.submit(topic) while self.running: time.sleep(1.5)
class TwitchChannelPointsMiner: def __init__( self, username: str, make_predictions: bool = True, follow_raid: bool = True, save_logs: bool = True, browser_settings: BrowserSettings = BrowserSettings(), bet_settings: BetSettings = BetSettings(), ): self.twitch = Twitch(username) self.twitch_browser = None self.follow_raid = follow_raid self.streamers = [] self.events_predictions = {} self.minute_watcher_thread = None self.ws_pool = None 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 self.original_streamers = [] if save_logs is True: root_logger = logging.getLogger() root_logger.setLevel(logging.INFO) logs_path = os.path.join(Path().absolute(), "logs") Path(logs_path).mkdir(parents=True, exist_ok=True) self.logs_file = os.path.join( logs_path, f"{username}.{datetime.now().strftime('%d%m%Y-%H%M%S')}.log", ) file_handler = logging.FileHandler(self.logs_file) file_handler.setFormatter( logging.Formatter( "%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s]: %(message)s" )) root_logger.addHandler(file_handler) else: self.logs_file = None signal.signal(signal.SIGINT, self.end) signal.signal(signal.SIGSEGV, self.end) signal.signal(signal.SIGTERM, self.end) def mine(self, streamers: list = []): self.run(streamers) def run(self, streamers: list = []): if self.running: logger.error("You can't start multiple session of this istance!") else: logger.info( emoji.emojize(f":bomb: Start session: '{self.session_id}'", use_aliases=True)) self.running = True self.start_datetime = datetime.now() self.twitch.login() for streamer_username in streamers: time.sleep(random.uniform(0.3, 0.7)) streamer_username.lower().strip() try: channel_id = self.twitch.get_channel_id(streamer_username) streamer = Streamer(streamer_username, channel_id) self.streamers.append(streamer) except StreamerDoesNotExistException: logger.info( emoji.emojize( f":cry: Streamer {streamer_username} does not exist", use_aliases=True, )) for streamer in self.streamers: time.sleep(random.uniform(0.3, 0.7)) self.twitch.load_channel_points_context(streamer) self.twitch.check_streamer_online(streamer) self.original_streamers = copy.deepcopy(self.streamers) if (self.make_predictions is True): # We need a browser to make predictions / bet self.twitch_browser = TwitchBrowser( self.twitch.twitch_login.get_auth_token(), self.session_id, settings=self.browser_settings, ) self.twitch_browser.init() self.minute_watcher_thread = threading.Thread( target=self.twitch.send_minute_watched_events, args=(self.streamers, )) self.minute_watcher_thread.daemon = True self.minute_watcher_thread.start() self.ws_pool = WebSocketsPool( twitch=self.twitch, twitch_browser=self.twitch_browser, streamers=self.streamers, bet_settings=self.bet_settings, events_predictions=self.events_predictions, ) topics = [ PubsubTopic( "community-points-user-v1", user_id=self.twitch.twitch_login.get_user_id(), ) ] if self.make_predictions is True: topics.append( PubsubTopic( "predictions-user-v1", user_id=self.twitch.twitch_login.get_user_id(), )) for streamer in self.streamers: topics.append( PubsubTopic("video-playback-by-id", streamer=streamer)) if self.follow_raid is True: topics.append(PubsubTopic("raid", streamer=streamer)) if self.make_predictions is True: topics.append( PubsubTopic("predictions-channel-v1", streamer=streamer)) for topic in topics: self.ws_pool.submit(topic) while self.running: time.sleep(1.5) def end(self, signum, frame): # logger.info("Please wait, this operation can take a while ...") if self.twitch_browser is not None: self.twitch_browser.browser.quit() self.running = self.twitch.running = False self.ws_pool.end() self.__print_report() time.sleep(3.5) # Do sleep for ending browser and threads sys.exit(0) def __print_report(self): print("\n") logger.info( emoji.emojize(f":stop_sign: End session '{self.session_id}'", use_aliases=True)) if self.logs_file is not None: logger.info( emoji.emojize(f":page_facing_up: Logs file: {self.logs_file}", use_aliases=True)) logger.info( emoji.emojize( f":hourglass: Duration {datetime.now() - self.start_datetime}", use_aliases=True, )) if self.make_predictions: print("") logger.info( emoji.emojize( f":bar_chart: {self.bet_settings}", use_aliases=True, )) for event_id in self.events_predictions: logger.info( emoji.emojize( f":bar_chart: {self.events_predictions[event_id].print_recap()}", use_aliases=True, )) print("") for streamer_index in range(0, len(self.streamers)): logger.info( emoji.emojize( f":nerd_face: {self.streamers[streamer_index]}, Gained (end-start): {self.streamers[streamer_index].channel_points - self.original_streamers[streamer_index].channel_points}", use_aliases=True, )) if self.streamers[streamer_index].history != {}: logger.info( emoji.emojize( f":moneybag: {self.streamers[streamer_index].print_history()}", use_aliases=True, ))