Exemplo n.º 1
0
    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, self.queue_listener = configure_loggers(
            self.username, logger_settings)

        # Check for the latest version of the script
        current_version, github_version = check_versions()
        if github_version == "0.0.0":
            logger.error(
                "Unable to detect if you have the latest version of this script"
            )
        elif current_version != github_version:
            logger.info(
                f"You are running the version {current_version} of this script"
            )
            logger.info(f"The latest version on GitHub is: {github_version}")

        for sign in [signal.SIGINT, signal.SIGSEGV, signal.SIGTERM]:
            signal.signal(sign, self.end)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
    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 __init__(
        self,
        username: str,
        claim_drops_startup: bool = False,
        # Settings for logging and selenium as you can see.
        # This settings will be global shared trought Settings class
        logger_settings: LoggerSettings = LoggerSettings(),
        browser_settings: BrowserSettings = BrowserSettings(),
        # Default values for all streamers
        streamer_settings: StreamerSettings = StreamerSettings(),
    ):
        self.username = username

        # Set as globally config
        Settings.logger = logger_settings
        Settings.browser = browser_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(browser_settings.browser)
        self.twitch = Twitch(self.username, user_agent)

        self.twitch_browser = None
        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)
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:"},
                    )
Exemplo n.º 6
0
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:"},
                    )
Exemplo n.º 7
0
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,
                    ))