Beispiel #1
0
 def wrapper(*args, **kwargs):
     session_state = sessions[-1]
     try:
         func(*args, **kwargs)
     except KeyboardInterrupt:
         close_instagram(device_id)
         logger.info(
             f"-------- FINISH: {datetime.now().time()} --------",
             extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
         )
         print_full_report(sessions)
         sessions.persist(directory=session_state.my_username)
         sys.exit(0)
     except (DeviceFacade.JsonRpcError, IndexError, HTTPException,
             timeout):
         logger.error(traceback.format_exc())
         save_crash(device)
         logger.info("No idea what it was. Let's try again.")
         # Hack for the case when IGTV was accidentally opened
         close_instagram(device_id)
         random_sleep()
         open_instagram(device_id)
         TabBarView(device).navigateToProfile()
     except LanguageNotEnglishException:
         logger.info(
             "Language was changed. We'll have to start from the beginning."
         )
         TabBarView(device).navigateToProfile()
     except Exception as e:
         save_crash(device)
         close_instagram(device_id)
         print_full_report(sessions)
         sessions.persist(directory=session_state.my_username)
         raise e
Beispiel #2
0
    def _navigateToTab(self, tab: ProfileTabs):
        TABS_RES_ID = "com.instagram.android:id/profile_tab_layout"
        TABS_CLASS_NAME = "android.widget.HorizontalScrollView"
        tabs_view = self.device.find(
            resourceIdMatches=case_insensitive_re(TABS_RES_ID),
            className=TABS_CLASS_NAME,
        )

        TAB_RES_ID = "com.instagram.android:id/profile_tab_icon_view"
        TAB_CLASS_NAME = "android.widget.ImageView"
        description = ""
        if tab == ProfileTabs.POSTS:
            description = "Grid View"
        elif tab == ProfileTabs.IGTV:
            description = "IGTV"
        elif tab == ProfileTabs.REELS:
            description = "Reels"
        elif tab == ProfileTabs.EFFECTS:
            description = "Effects"
        elif tab == ProfileTabs.PHOTOS_OF_YOU:
            description = "Photos of You"

        button = tabs_view.child(
            descriptionMatches=case_insensitive_re(description),
            resourceIdMatches=case_insensitive_re(TAB_RES_ID),
            className=TAB_CLASS_NAME,
        )
        if not button.exists():
            logger.error(f"Cannot navigate to to tab '{description}'")
            save_crash(self.device)
        else:
            button.click()
Beispiel #3
0
    def navigateToHashtag(self, hashtag):
        logger.info(f"Navigate to hashtag {hashtag}")
        search_edit_text = self._getSearchEditText()
        search_edit_text.click()

        random_sleep()
        hashtag_tab = self._getTabTextView(SearchTabs.TAGS)
        if not hashtag_tab.exists():
            logger.debug(
                "Cannot find tab: Tags. Going to attempt to search for placeholder in all tabs"
            )
            hashtag_tab = self._searchTabWithTextPlaceholder(SearchTabs.TAGS)
            if hashtag_tab is None:
                logger.error("Cannot find tab: Tags.")
                save_crash(self.device)
                return None
        hashtag_tab.click()

        search_edit_text.set_text(hashtag)
        hashtag_view = self._getHashtagRow(hashtag[1:])

        if not hashtag_view.exists():
            logger.error(f"Cannot find hashtag {hashtag}, abort.")
            save_crash(self.device)
            return None

        hashtag_view.click()

        return HashTagView(self.device)
Beispiel #4
0
def _follow(device, username, follow_percentage, args, session_state,
            swipe_amount):
    if not session_state.check_limit(
            args, limit_type=session_state.Limit.FOLLOWS, output=False):
        follow_chance = randint(1, 100)
        if follow_chance > follow_percentage:
            return False

        coordinator_layout = device.find(
            resourceId=ResourceID.COORDINATOR_ROOT_LAYOUT)
        if coordinator_layout.exists() and swipe_amount != 0:
            UniversalActions(device)._swipe_points(direction=Direction.UP,
                                                   delta_y=swipe_amount)

        random_sleep()

        follow_button = device.find(
            classNameMatches=ClassName.BUTTON,
            clickable=True,
            textMatches=FOLLOW_REGEX,
        )

        if not follow_button.exists():
            unfollow_button = device.find(
                classNameMatches=ClassName.BUTTON,
                clickable=True,
                textMatches=UNFOLLOW_REGEX,
            )
            followback_button = device.find(
                classNameMatches=ClassName.BUTTON,
                clickable=True,
                textMatches=FOLLOWBACK_REGEX,
            )
            if unfollow_button.exists():
                logger.info(f"You already follow @{username}.",
                            extra={"color": f"{Fore.GREEN}"})
                return False
            elif followback_button.exists():
                logger.info(
                    f"@{username} already follows you.",
                    extra={"color": f"{Fore.GREEN}"},
                )
                return False
            else:
                logger.error(
                    "Cannot find neither Follow button, Follow Back button, nor Unfollow button. Maybe not English language is set?"
                )
                save_crash(device)
                switch_to_english(device)
                raise LanguageNotEnglishException()

        follow_button.click()
        detect_block(device)
        logger.info(f"Followed @{username}", extra={"color": f"{Fore.GREEN}"})
        random_sleep()
        return True
    else:
        logger.info("Reached total follows limit, not following.")
        return False
Beispiel #5
0
def _follow(device, username, follow_percentage, args, session_state):
    if not session_state.check_limit(
            args, limit_type=session_state.Limit.FOLLOWS, output=False):
        follow_chance = randint(1, 100)
        if follow_chance > follow_percentage:
            return False

        logger.info("Following...")
        coordinator_layout = device.find(
            resourceId="com.instagram.android:id/coordinator_root_layout")
        if coordinator_layout.exists():
            coordinator_layout.scroll(DeviceFacade.Direction.TOP)

        random_sleep()

        follow_button = device.find(
            classNameMatches=BUTTON_REGEX,
            clickable=True,
            textMatches=FOLLOW_REGEX,
        )

        if not follow_button.exists():
            unfollow_button = device.find(
                classNameMatches=BUTTON_REGEX,
                clickable=True,
                textMatches=UNFOLLOW_REGEX,
            )
            followback_button = device.find(
                classNameMatches=BUTTON_REGEX,
                clickable=True,
                textMatches=FOLLOWBACK_REGEX,
            )
            if unfollow_button.exists():
                logger.info(f"You already follow @{username}.",
                            extra={"color": f"{Fore.GREEN}"})
                return False
            elif followback_button.exists():
                logger.info(
                    f"@{username} already follows you.",
                    extra={"color": f"{Fore.GREEN}"},
                )
                return False
            else:
                logger.error(
                    "Cannot find neither Follow button, Follow Back button, nor Unfollow button. Maybe not English language is set?"
                )
                save_crash(device)
                switch_to_english(device)
                raise LanguageNotEnglishException()

        follow_button.click()
        detect_block(device)
        logger.info(f"Followed @{username}", extra={"color": f"{Fore.GREEN}"})
        random_sleep()
        return True
    else:
        logger.info("Reached total follows limit, not following.")
        return False
Beispiel #6
0
def _follow(device, username, follow_percentage):
    follow_chance = randint(1, 100)
    if follow_chance > follow_percentage:
        return False

    logger.info("Following...")
    coordinator_layout = device.find(
        resourceId="com.instagram.android:id/coordinator_root_layout")
    if coordinator_layout.exists():
        coordinator_layout.scroll(DeviceFacade.Direction.TOP)

    random_sleep()

    profile_header_actions_layout = device.find(
        resourceId="com.instagram.android:id/profile_header_actions_top_row",
        className="android.widget.LinearLayout",
    )
    if not profile_header_actions_layout.exists():
        logger.error("Cannot find profile actions.")
        return False

    follow_button = profile_header_actions_layout.child(
        classNameMatches=TEXTVIEW_OR_BUTTON_REGEX,
        clickable=True,
        textMatches=FOLLOW_REGEX,
    )
    if not follow_button.exists():
        unfollow_button = profile_header_actions_layout.child(
            classNameMatches=TEXTVIEW_OR_BUTTON_REGEX,
            clickable=True,
            textMatches=UNFOLLOW_REGEX,
        )
        if unfollow_button.exists():
            logger.info(
                f"You already follow @{username}.",
                extra={"color": f"{Fore.GREEN}"},
            )
            return False
        else:
            logger.error(
                "Cannot find neither Follow button, nor Unfollow button. Maybe not English language is set?"
            )
            save_crash(device)
            switch_to_english(device)
            raise LanguageNotEnglishException()

    follow_button.click()
    detect_block(device)
    logger.info(
        f"Followed @{username}",
        extra={"color": f"{Fore.GREEN}"},
    )
    random_sleep()
    return True
Beispiel #7
0
Datei: views.py Projekt: thup/bot
    def navigateToHashtag(self, hashtag):
        logger.info(f"Navigate to hashtag {hashtag}")
        search_edit_text = self._getSearchEditText()
        search_edit_text.click()
        random_sleep(1, 2)
        hashtag_tab = self._getTabTextView(SearchTabs.TAGS)
        if not hashtag_tab.exists():
            logger.debug(
                "Cannot find tab: Tags. Going to attempt to search for placeholder in all tabs"
            )
            hashtag_tab = self._searchTabWithTextPlaceholder(SearchTabs.TAGS)
            if hashtag_tab is None:
                logger.error("Cannot find tab: Tags.")
                save_crash(self.device)
                return None
        hashtag_tab.click()
        random_sleep(1, 2)
        tabbar_container = self.device.find(
            resourceId=ResourceID.FIXED_TABBAR_TABS_CONTAINER
        )
        if tabbar_container.exists(True):
            delta = tabbar_container.get_bounds()["bottom"]
        else:
            delta = 375
        logger.debug("Swipe up to close the keyboard if present")
        UniversalActions(self.device)._swipe_points(
            direction=Direction.UP,
            start_point_y=randint(delta + 10, delta + 150),
            delta_y=randint(50, 100),
        )
        random_sleep(1, 2)
        # check if that hashtag already exists in the recent search list -> act as human
        hashtag_view_recent = self._getHashtagRow(hashtag[1:])

        if hashtag_view_recent.exists():
            hashtag_view_recent.click()
            random_sleep(5, 10)
            return HashTagView(self.device)

        logger.info(f"{hashtag} is not in recent searching history..")
        search_edit_text.set_text(hashtag)
        hashtag_view = self._getHashtagRow(hashtag[1:])
        random_sleep(4, 8)

        if not hashtag_view.exists():
            logger.error(f"Cannot find hashtag {hashtag}, abort.")
            save_crash(self.device)
            return None

        hashtag_view.click()
        random_sleep()

        return HashTagView(self.device)
Beispiel #8
0
    def navigateToHashtag(self, hashtag):
        logger.info(f"Navigate to hashtag {hashtag}")
        search_edit_text = self._getSearchEditText()
        search_edit_text.click()

        random_sleep()
        hashtag_tab = self._getTabTextView(SearchTabs.TAGS)
        if not hashtag_tab.exists():
            logger.debug(
                "Cannot find tab: Tags. Going to attempt to search for placeholder in all tabs"
            )
            hashtag_tab = self._searchTabWithTextPlaceholder(SearchTabs.TAGS)
            if hashtag_tab is None:
                logger.error("Cannot find tab: Tags.")
                save_crash(self.device)
                return None

        hashtag_tab.click()
        random_sleep()
        DeviceFacade.back(self.device)
        random_sleep()
        # check if that hashtag already exists in the recent search list -> act as human
        hashtag_view_recent = self._getHashtagRow(hashtag[1:])

        if hashtag_view_recent.exists():
            hashtag_view_recent.click()
            random_sleep()
            return HashTagView(self.device)

        logger.info(f"{hashtag} is not in recent searching hystory..")
        search_edit_text.set_text(hashtag)
        hashtag_view = self._getHashtagRow(hashtag[1:])

        if not hashtag_view.exists():
            logger.error(f"Cannot find hashtag {hashtag}, abort.")
            save_crash(self.device)
            return None

        hashtag_view.click()
        random_sleep()

        return HashTagView(self.device)
Beispiel #9
0
Datei: views.py Projekt: thup/bot
    def _navigateToTab(self, tab: TabBarText):
        tabs_view = self.device.find(
            resourceIdMatches=case_insensitive_re(ResourceID.PROFILE_TAB_LAYOUT),
            className=ClassName.HORIZONTAL_SCROLL_VIEW,
        )
        button = tabs_view.child(
            descriptionMatches=case_insensitive_re(tab),
            resourceIdMatches=case_insensitive_re(ResourceID.PROFILE_TAB_ICON_VIEW),
            className=ClassName.IMAGE_VIEW,
        )

        attempts = 0
        while not button.exists():
            attempts += 1
            self.device.swipe(DeviceFacade.Direction.TOP, scale=0.1)
            if attempts > 2:
                logger.error(f"Cannot navigate to tab '{tab}'")
                save_crash(self.device)
                return

        button.click()
Beispiel #10
0
    def _getPostLikeButton(self, scroll_to_find=True):
        """Find the like button right bellow a post.
        Note: sometimes the like button from the post above or bellow are
        dumped as well, so we need handle that situation.

        scroll_to_find: if the like button is not found, scroll a bit down
                        to try to find it. Default: True
        """
        post_view_area = self.device.find(
            resourceIdMatches=case_insensitive_re(ResourceID.LIST))
        if not post_view_area.exists():
            logger.debug("Cannot find post recycler view area")
            save_crash(self.device)
            self.device.back()
            return None

        post_media_view = self.device.find(
            resourceIdMatches=case_insensitive_re(
                ResourceID.CAROUSEL_MEDIA_GROUP_AND_ZOOMABLE_VIEW_CONTAINER))

        if not post_media_view.exists():
            logger.debug("Cannot find post media view area")
            save_crash(self.device)
            self.device.back()
            return None

        like_btn_view = post_media_view.down(
            resourceIdMatches=case_insensitive_re(
                ResourceID.ROW_FEED_BUTTON_LIKE))

        if like_btn_view.exists():
            # threshold of 30% of the display height
            threshold = int((0.3) * self.device.get_info()["displayHeight"])
            like_btn_top_bound = like_btn_view.get_bounds()["top"]
            is_like_btn_in_the_bottom = like_btn_top_bound > threshold

            if not is_like_btn_in_the_bottom:
                logger.debug(
                    f"Like button is to high ({like_btn_top_bound} px). Threshold is {threshold} px"
                )

            post_view_area_bottom_bound = post_view_area.get_bounds()["bottom"]
            is_like_btn_visible = like_btn_top_bound <= post_view_area_bottom_bound
            if not is_like_btn_visible:
                logger.debug(
                    f"Like btn out of current clickable area. Like btn top ({like_btn_top_bound}) recycler_view bottom ({post_view_area_bottom_bound})"
                )
        else:
            logger.debug("Like button not found bellow the post.")

        if (not like_btn_view.exists(True) or not is_like_btn_in_the_bottom
                or not is_like_btn_visible):
            if scroll_to_find:
                logger.debug("Try to scroll tiny bit down...")
                # Remember: to scroll down we need to swipe up :)
                for _ in range(3):
                    self.device.swipe(DeviceFacade.Direction.TOP, scale=0.25)
                    like_btn_view = self.device.find(
                        resourceIdMatches=case_insensitive_re(
                            ResourceID.ROW_FEED_BUTTON_LIKE))
                    if like_btn_view.exists(True):
                        break

            if not scroll_to_find or not like_btn_view.exists(True):
                logger.error("Could not find like button bellow the post")
                return None

        return like_btn_view
Beispiel #11
0
        def wrapper(*args, **kwargs):
            session_state = sessions[-1]
            try:
                func(*args, **kwargs)
            except KeyboardInterrupt:
                try:
                    # Catch Ctrl-C and ask if user wants to pause execution
                    logger.info(
                        "CTRL-C detected . . .",
                        extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
                    )
                    logger.info(
                        f"-------- PAUSED: {datetime.now().time()} --------",
                        extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
                    )
                    logger.info(
                        "NOTE: This is a rudimentary pause. It will restart the action, while retaining session data.",
                        extra={"color": Style.BRIGHT},
                    )
                    logger.info(
                        "Press RETURN to resume or CTRL-C again to Quit: ",
                        extra={"color": Style.BRIGHT},
                    )

                    input("")

                    logger.info(
                        f"-------- RESUMING: {datetime.now().time()} --------",
                        extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
                    )
                    TabBarView(device).navigateToProfile()
                except KeyboardInterrupt:
                    close_instagram(device, screen_record)
                    logger.info(
                        f"-------- FINISH: {datetime.now().time()} --------",
                        extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
                    )
                    print_full_report(sessions)
                    sessions.persist(directory=session_state.my_username)
                    sys.exit(0)

            except (
                    DeviceFacade.JsonRpcError,
                    IndexError,
                    HTTPException,
                    timeout,
                    UiObjectNotFoundErrorv2,
            ):
                logger.error(traceback.format_exc())
                save_crash(device)
                logger.info("No idea what it was. Let's try again.")
                # Hack for the case when IGTV was accidentally opened
                close_instagram(device, screen_record)
                random_sleep()
                open_instagram(device, screen_record)
                TabBarView(device).navigateToProfile()
            except LanguageNotEnglishException:
                logger.info(
                    "Language was changed. We'll have to start from the beginning."
                )
                TabBarView(device).navigateToProfile()
            except Exception as e:
                logger.error(traceback.format_exc())
                save_crash(device)
                close_instagram(device, screen_record)
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                raise e
Beispiel #12
0
def run():
    global device_id
    global first_run
    loaded = load_plugins()
    args = get_args()
    enabled = []
    if not args:
        return
    dargs = vars(args)

    for k in loaded:
        if dargs[k.replace("-", "_")[2:]] != None:
            if k == "--interact":
                logger.warn(
                    'Using legacy argument "--interact". Please switch to new arguments as this will be deprecated in the near future.'
                )
                if "#" in args.interact[0]:
                    enabled.append("--hashtag-likers")
                    args.hashtag_likers = args.interact
                else:
                    enabled.append("--blogger-followers")
                    args.blogger_followers = args.interact
            else:
                enabled.append(k)
    enabled = list(dict.fromkeys(enabled))

    if len(enabled) < 1:
        logger.error("You have to specify one of the actions: " + ", ".join(loaded))
        return
    if len(enabled) > 1:
        logger.error(
            "Running GramAddict with two or more actions is not supported yet."
        )
        return

    device_id = args.device
    if not check_adb_connection(is_device_id_provided=(device_id is not None)):
        return
    logger.info("Instagram version: " + get_instagram_version(device_id))
    device = create_device(device_id)

    if device is None:
        return

    while True:
        session_state = SessionState()
        session_state.args = args.__dict__
        sessions.append(session_state)

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.screen_sleep:
            screen_sleep(device_id, "on")  # Turn on the device screen

        open_instagram(device_id)

        try:
            profileView = TabBarView(device).navigateToProfile()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (
            session_state.my_username == None
            or session_state.my_followers_count == None
            or session_state.my_following_count == None
        ):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)
        if first_run:
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)

        loaded[enabled[0]].run(device, device_id, args, enabled, storage, sessions)

        close_instagram(device_id)
        session_state.finishTime = datetime.now()

        if args.screen_sleep:
            screen_sleep(device_id, "off")  # Turn off the device screen

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.repeat:
            print_full_report(sessions)
            repeat = get_value(args.repeat, "Sleep for {} minutes", 180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                sys.exit(0)
        else:
            break

        first_run = False

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)
Beispiel #13
0
def run():
    # Some plugins need config values without being passed
    # through. Because we do a weird config/argparse hybrid,
    # we need to load the configs in a weird way
    load_filter(configs)
    load_interaction(configs)
    load_utils(configs)
    load_views(configs)

    if not configs.args or not check_adb_connection():
        return

    if len(configs.enabled) < 1:
        logger.error("You have to specify one of the actions: " +
                     ", ".join(configs.actions))
        return

    logger.info("Instagram version: " + get_instagram_version())
    device = create_device(configs.device_id, configs.args.uia_version)

    if device is None:
        return

    while True:
        session_state = SessionState(configs)
        sessions.append(session_state)

        device.wake_up()

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if not device.get_info()["screenOn"]:
            device.press_power()
        if device.is_screen_locked():
            device.unlock()
            if device.is_screen_locked():
                logger.error(
                    "Can't unlock your screen. There may be a passcode on it. If you would like your screen to be turned on and unlocked automatically, please remove the passcode."
                )
                exit(0)

        logger.info("Device screen on and unlocked.")

        open_instagram(device, configs.args.screen_record)

        try:
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            if configs.args.username is not None:
                success = AccountView(device).changeToUsername(
                    configs.args.username)
                if not success:
                    logger.error(
                        f"Not able to change to {configs.args.username}, abort!"
                    )
                    device.back()
                    break

            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (session_state.my_username is None
                or session_state.my_followers_count is None
                or session_state.my_following_count is None):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)

        if not is_log_file_updated():
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)
        for plugin in configs.enabled:
            if not session_state.check_limit(
                    configs.args, limit_type=session_state.Limit.ALL,
                    output=False):
                logger.info(f"Current job: {plugin}",
                            extra={"color": f"{Fore.BLUE}"})
                if ProfileView(
                        device).getUsername() != session_state.my_username:
                    logger.debug("Not in your main profile.")
                    TabBarView(device).navigateToProfile()
                configs.actions[plugin].run(device, configs, storage, sessions,
                                            plugin)

            else:
                logger.info(
                    "Successful or Total Interactions limit reached. Ending session."
                )
                break

        close_instagram(device, configs.args.screen_record)
        session_state.finishTime = datetime.now()

        if configs.args.screen_sleep:
            device.screen_off()
            logger.info("Screen turned off for sleeping time")

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if configs.args.repeat:
            print_full_report(sessions)
            repeat = get_value(configs.args.repeat, "Sleep for {} minutes",
                               180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                exit(0)
        else:
            break

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)
Beispiel #14
0
    def do_unfollow(self, device: DeviceFacade, username, my_username,
                    check_if_is_follower):
        """
        :return: whether unfollow was successful
        """
        username_view = device.find(
            resourceId=self.ResourceID.FOLLOW_LIST_USERNAME,
            className=ClassName.TEXT_VIEW,
            text=username,
        )
        if not username_view.exists():
            logger.error("Cannot find @" + username + ", skip.")
            return False
        username_view.click()

        if check_if_is_follower and self.check_is_follower(
                device, username, my_username):
            logger.info(f"Skip @{username}. This user is following you.")
            logger.info("Back to the followings list.")
            device.back()
            return False

        unfollow_button = device.find(
            classNameMatches=ClassName.BUTTON,
            clickable=True,
            textMatches=FOLLOWING_REGEX,
        )
        # I don't know/remember the origin of this, if someone does - let's document it
        attempts = 2
        for _ in range(attempts):
            if unfollow_button.exists():
                break

            scrollable = device.find(classNameMatches=ClassName.VIEW_PAGER)
            if scrollable.exists():
                scrollable.scroll(DeviceFacade.Direction.TOP)

            unfollow_button = device.find(
                classNameMatches=ClassName.BUTTON,
                clickable=True,
                textMatches=FOLLOWING_REGEX,
            )

        if not unfollow_button.exists():
            logger.error(
                "Cannot find Following button. Maybe not English language is set?"
            )
            save_crash(device)
            switch_to_english(device)
            raise LanguageNotEnglishException()
        random_sleep()
        logger.debug("Unfollow btn click")
        unfollow_button.click()
        logger.info(f"Unfollow @{username}.",
                    extra={"color": f"{Fore.YELLOW}"})

        # Weirdly enough, this is a fix for after you unfollow someone that follows
        # you back - the next person you unfollow the button is missing on first find
        # additional find - finds it. :shrug:
        confirm_unfollow_button = None
        attempts = 2
        for _ in range(attempts):
            confirm_unfollow_button = device.find(
                resourceId=self.ResourceID.FOLLOW_SHEET_UNFOLLOW_ROW)
            if confirm_unfollow_button.exists():
                break

        if not confirm_unfollow_button or not confirm_unfollow_button.exists():
            logger.error("Cannot confirm unfollow.")
            save_crash(device)
            device.back()
            return False
        logger.debug("Confirm unfollow")
        confirm_unfollow_button.click()

        random_sleep(0, 1)

        # Check if private account confirmation
        private_unfollow_button = device.find(
            classNameMatches=ClassName.BUTTON_OR_TEXTVIEW_REGEX,
            textMatches=UNFOLLOW_REGEX,
        )

        if private_unfollow_button.exists():
            logger.debug("Confirm unfollow private account")
            private_unfollow_button.click()

        detect_block(device)

        logger.info("Back to the followings list.")
        device.back()
        return True
    def do_unfollow(self, device, username, my_username, check_if_is_follower):
        """
        :return: whether unfollow was successful
        """
        username_view = device.find(
            resourceId="com.instagram.android:id/follow_list_username",
            className="android.widget.TextView",
            text=username,
        )
        if not username_view.exists():
            logger.error("Cannot find @" + username + ", skip.")
            return False
        username_view.click()

        if check_if_is_follower and self.check_is_follower(
                device, username, my_username):
            logger.info(f"Skip @{username}. This user is following you.")
            logger.info("Back to the followings list.")
            device.back()
            return False

        attempts = 0

        while True:
            unfollow_button = device.find(
                classNameMatches=BUTTON_REGEX,
                clickable=True,
                textMatches=FOLLOWING_REGEX,
            )
            if not unfollow_button.exists() and attempts <= 1:
                scrollable = device.find(
                    classNameMatches="androidx.viewpager.widget.ViewPager")
                scrollable.scroll(DeviceFacade.Direction.TOP)
                attempts += 1
            else:
                break

        if not unfollow_button.exists():
            logger.error(
                "Cannot find Following button. Maybe not English language is set?"
            )
            save_crash(device)
            switch_to_english(device)
            raise LanguageNotEnglishException()
        unfollow_button.click()

        confirm_unfollow_button = device.find(
            resourceId="com.instagram.android:id/follow_sheet_unfollow_row",
            className="android.widget.TextView",
        )
        if not confirm_unfollow_button.exists():
            logger.error("Cannot confirm unfollow.")
            save_crash(device)
            device.back()
            return False
        confirm_unfollow_button.click()

        random_sleep()

        # Check if private account confirmation
        private_unfollow_button = device.find(
            classNameMatches=BUTTON_OR_TEXTVIEW_REGEX,
            textMatches=UNFOLLOW_REGEX,
        )

        if private_unfollow_button.exists():
            private_unfollow_button.click()

        detect_block(device)

        logger.info("Back to the followings list.")
        device.back()
        return True
Beispiel #16
0
def run():
    global device_id
    loaded = load_plugins()
    args = get_args()
    enabled = []
    if not args:
        return
    dargs = vars(args)

    for item in sys.argv[1:]:
        if item in loaded:
            if item != "--interact" and item != "--hashtag-likers":
                enabled.append(item)

    for k in loaded:
        if dargs[k.replace("-", "_")[2:]] != None:
            if k == "--interact":
                logger.warn(
                    'Using legacy argument "--interact". Please switch to new arguments as this will be deprecated in the near future.'
                )
                for source in args.interact:
                    if "@" in source:
                        enabled.append("--blogger-followers")
                        if type(args.blogger_followers) != list:
                            args.blogger_followers = [source]
                        else:
                            args.blogger_followers.append(source)
                    else:
                        enabled.append("--hashtag-likers-top")
                        if type(args.hashtag_likers_top) != list:
                            args.hashtag_likers_top = [source]
                        else:
                            args.hashtag_likers_top.append(source)
            elif k == "--hashtag-likers":
                logger.warn(
                    'Using legacy argument "--hashtag-likers". Please switch to new arguments as this will be deprecated in the near future.'
                )
                for source in args.hashtag_likers:
                    enabled.append("--hashtag-likers-top")
                    if type(args.hashtag_likers_top) != list:
                        args.hashtag_likers_top = [source]
                    else:
                        args.hashtag_likers_top.append(source)

    enabled = list(dict.fromkeys(enabled))

    if len(enabled) < 1:
        logger.error("You have to specify one of the actions: " +
                     ", ".join(loaded))
        return

    device_id = args.device
    if not check_adb_connection(is_device_id_provided=(device_id is not None)):
        return
    logger.info("Instagram version: " + get_instagram_version(device_id))
    device = create_device(device_id)

    if device is None:
        return

    while True:
        session_state = SessionState()
        session_state.args = args.__dict__
        sessions.append(session_state)

        device.wake_up()

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if not DeviceFacade(device_id).get_info()["screenOn"]:
            DeviceFacade(device_id).press_power()
        if DeviceFacade(device_id).is_screen_locked():
            DeviceFacade(device_id).unlock()
            if DeviceFacade(device_id).is_screen_locked():
                logger.error(
                    "Can't unlock your screen. There may be a passcode on it. If you would like your screen to be turned on and unlocked automatically, please remove the passcode."
                )
                sys.exit()

        logger.info("Device screen on and unlocked.")

        open_instagram(device_id)

        try:
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (session_state.my_username == None
                or session_state.my_followers_count == None
                or session_state.my_following_count == None):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)

        if not is_log_file_updated():
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)
        for plugin in enabled:
            if not session_state.check_limit(
                    args, limit_type=session_state.Limit.ALL, output=False):
                loaded[plugin].run(device, device_id, args, enabled, storage,
                                   sessions, plugin)
            else:
                logger.info(
                    "Successful or Total Interactions limit reached. Ending session."
                )
                break

        close_instagram(device_id)
        session_state.finishTime = datetime.now()

        if args.screen_sleep:
            DeviceFacade(device_id).screen_off()
            logger.info("Screen turned off for sleeping time")

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.repeat:
            print_full_report(sessions)
            repeat = get_value(args.repeat, "Sleep for {} minutes", 180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                sys.exit(0)
        else:
            break

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)