예제 #1
0
def _open_user(device,
               username,
               open_followers=False,
               open_followings=False,
               refresh=False,
               deep_link_usage_percentage=0,
               on_action=None):
    if refresh:
        print("Refreshing profile status...")
        coordinator_layout = device.find(
            resourceId=f'{device.app_id}:id/coordinator_root_layout')
        if coordinator_layout.exists():
            coordinator_layout.scroll(DeviceFacade.Direction.TOP)

    if username is None:
        if open_followers:
            print("Open your followers")
            ProfileView(device, is_own_profile=True).navigate_to_followers()

        if open_followings:
            print("Open your following")
            ProfileView(device, is_own_profile=True).navigate_to_following()
    else:
        should_open_user_with_search = True
        deep_link_usage_chance = randint(1, 100)
        if deep_link_usage_chance <= deep_link_usage_percentage:
            print(f"Going to open {username} using deeplink")
            should_open_user_with_search = False

            should_continue, is_profile_opened = _open_profile_using_deeplink(
                device, username)
            if not should_continue:
                return False

            if not is_profile_opened:
                print(
                    f"Failed to open profile using deeplink. Using search instead"
                )
                should_open_user_with_search = True

        if should_open_user_with_search:
            if not search_for(device, username=username, on_action=on_action):
                return False

            sleeper.random_sleep()

        is_profile_empty = softban_indicator.detect_empty_profile(device)
        if is_profile_empty:
            return False

        if open_followers:
            print("Open @" + username + " followers")
            ProfileView(device, is_own_profile=True).navigate_to_followers()

        if open_followings:
            print("Open @" + username + " following")
            ProfileView(device, is_own_profile=True).navigate_to_following()

    return True
예제 #2
0
    def detect_empty_profile(self, device):
        profile_view = ProfileView(device)
        followers_count = profile_view.get_followers_count()
        is_profile_empty = followers_count is None
        if is_profile_empty:
            print(COLOR_FAIL + "A profile-page seems to be empty. "
                  "Counting that as a soft-ban indicator!" + COLOR_ENDC)
            self.indications[IndicationType.EMPTY_PROFILES]["curr"] += 1
            self.indicate_block()

        return is_profile_empty
예제 #3
0
def switch_to_english(device):
    print(COLOR_OKGREEN + "Switching to English locale" + COLOR_ENDC)
    navigate(device, TabBarTabs.PROFILE, switch_to_english_on_exception=False)
    ProfileView(device) \
        .navigate_to_options() \
        .navigate_to_settings() \
        .switch_to_english()
예제 #4
0
def _check_is_follower(device, username, my_username):
    print(COLOR_OKGREEN + "Check if @" + username + " is following you." +
          COLOR_ENDC)
    ProfileView(device, is_own_profile=True).navigate_to_following()
    sleeper.random_sleep()

    is_list_empty = softban_indicator.detect_empty_list(device)

    if is_list_empty:
        # By default, the profile will be considered as following if the profile list didnt loaded
        print(
            "List seems to be empty, cant decide if you are followed by the profile or not (could be a soft-ban)."
        )
        print("Back to the profile.")
        device.back()
        return True
    else:
        my_username_view = device.find(
            resourceId=f'{device.app_id}:id/follow_list_username',
            className='android.widget.TextView',
            text=my_username)
        result = my_username_view.exists(quick=True)
        print("Back to the profile.")
        device.back()
        return result
예제 #5
0
def _watch_stories(device, source_name, source_type, username, stories_value,
                   on_action):
    if stories_value == 0:
        return False

    def story_sleep():
        delay = uniform(1, 5)
        print(f"Sleep for {delay:.2f} seconds")
        sleep(delay)

    if do_have_story(device):
        profile_picture = device.find(
            resourceId=f"{device.app_id}:id/row_profile_header_imageview",
            className="android.widget.ImageView")

        if profile_picture.exists():
            print(COLOR_OKGREEN + f"Watching @" + username +
                  f" stories, at most {stories_value}" + COLOR_ENDC)

            profile_picture.click()  # Open the first story
            on_action(
                StoryWatchAction(source_name=source_name,
                                 source_type=source_type,
                                 user=username))
            sleeper.random_sleep()

            for i in range(1, stories_value):
                print("Watching a story...")
                story_sleep()
                if _skip_story(device):
                    print("Go next")
                else:
                    print(COLOR_OKGREEN + "Watched all stories" + COLOR_ENDC)
                    break

            if not _get_action_bar(device).exists():
                print("Back to profile")
                device.back()

            if not ProfileView(device).is_visible():
                print(COLOR_OKGREEN +
                      "Oops, seems we got out of the profile. Going back..." +
                      COLOR_ENDC)
                username_view = device.find(
                    className="android.widget.TextView", text=username)
                username_view.click()
                sleeper.random_sleep()
            return True
    return False
예제 #6
0
    def interact_with_follower(follower_name, follower_name_view):
        """
        :return: whether we should continue interaction with other users after this one
        """
        is_interact_limit_reached, interact_reached_source_limit, interact_reached_session_limit = \
            is_limit_reached(InteractAction(source=username, user=follower_name, succeed=True), session_state)

        if not process_limits(
                is_interact_limit_reached, interact_reached_session_limit,
                interact_reached_source_limit, action_status, "Interaction"):
            return False

        is_get_profile_limit_reached, get_profile_reached_source_limit, get_profile_reached_session_limit = \
            is_limit_reached(GetProfileAction(user=follower_name), session_state)

        if not process_limits(is_get_profile_limit_reached,
                              get_profile_reached_session_limit,
                              get_profile_reached_source_limit, action_status,
                              "Get-Profile"):
            return False

        is_all_filters_satisfied = False
        if is_passed_filters is not None:
            print_debug(f"Running filter-ahead on @{follower_name}")
            should_continue, is_all_filters_satisfied = is_passed_filters(
                device,
                follower_name,
                reset=True,
                filters_tags=['BEFORE_PROFILE_CLICK'])
            if not should_continue:
                storage.add_filtered_user(follower_name)
                return True

            if not is_all_filters_satisfied:
                print_debug(
                    "Not all filters are satisfied with filter-ahead, continue filtering inside the profile-page"
                )

        print("@" + follower_name + ": interact")
        follower_name_view.click()
        on_action(GetProfileAction(user=follower_name))

        sleeper.random_sleep()
        is_profile_empty = softban_indicator.detect_empty_profile(device)

        if is_profile_empty:
            print("Back to followers list")
            device.back()
            return True

        follower_profile_view = ProfileView(
            device, follower_name == session_state.my_username)

        if is_passed_filters is not None:
            if not is_all_filters_satisfied:
                should_continue, _ = is_passed_filters(device,
                                                       follower_name,
                                                       reset=False)
                if not should_continue:
                    storage.add_filtered_user(follower_name)
                    # Continue to next follower
                    print("Back to profiles list")
                    device.back()
                    return True

        is_like_limit_reached, like_reached_source_limit, like_reached_session_limit = \
            is_limit_reached(LikeAction(source=username, user=follower_name), session_state)

        is_follow_limit_reached, follow_reached_source_limit, follow_reached_session_limit = \
            is_limit_reached(FollowAction(source=username, user=follower_name), session_state)

        is_watch_limit_reached, watch_reached_source_limit, watch_reached_session_limit = \
            is_limit_reached(StoryWatchAction(user=follower_name), session_state)

        is_comment_limit_reached, comment_reached_source_limit, comment_reached_session_limit = \
            is_limit_reached(CommentAction(source=username, user=follower_name, comment=""), session_state)

        is_private = follower_profile_view.is_private_account()
        if is_private:
            if is_passed_filters is None:
                print(COLOR_OKGREEN + "@" + follower_name +
                      " has private account, won't interact." + COLOR_ENDC)
                print("Back to profiles list")
                device.back()
                return True
            print("@" + follower_name +
                  ": Private account - images wont be liked.")

        do_have_stories = follower_profile_view.is_story_available()
        if not do_have_stories:
            print("@" + follower_name +
                  ": seems there are no stories to be watched.")

        is_likes_enabled = likes_count != '0'
        is_stories_enabled = stories_count != '0'
        is_follow_enabled = follow_percentage != 0
        is_comment_enabled = comment_percentage != 0

        likes_value = get_value(likes_count,
                                "Likes count: {}",
                                2,
                                max_count=12)
        stories_value = get_value(stories_count, "Stories to watch: {}", 1)

        can_like = not is_like_limit_reached and not is_private and likes_value > 0
        can_follow = (
            not is_follow_limit_reached
        ) and storage.get_following_status(
            follower_name) == FollowingStatus.NONE and follow_percentage > 0
        can_watch = (not is_watch_limit_reached
                     ) and do_have_stories and stories_value > 0
        can_comment = (not is_comment_limit_reached
                       ) and not is_private and comment_percentage > 0
        can_interact = can_like or can_follow or can_watch or can_comment

        if not can_interact:
            print(
                "@" + follower_name +
                ": Cant be interacted (due to limits / already followed). Skip."
            )
            storage.add_interacted_user(follower_name,
                                        followed=False,
                                        source=f"@{username}",
                                        interaction_type=instructions.value,
                                        provider=Provider.INTERACTION)
            on_action(
                InteractAction(source=username,
                               user=follower_name,
                               succeed=False))
        else:
            print_interaction_types(follower_name, can_like, can_follow,
                                    can_watch, can_comment)
            interaction_strategy = InteractionStrategy(
                do_like=can_like,
                do_follow=can_follow,
                do_story_watch=can_watch,
                do_comment=can_comment,
                likes_count=likes_value,
                follow_percentage=follow_percentage,
                like_percentage=like_percentage,
                stories_count=stories_value,
                comment_percentage=comment_percentage,
                comments_list=comments_list)

            is_liked, is_followed, is_watch, is_commented = interaction(
                username=follower_name,
                interaction_strategy=interaction_strategy)
            if is_liked or is_followed or is_watch or is_commented:
                storage.add_interacted_user(
                    follower_name,
                    followed=is_followed,
                    source=f"@{username}",
                    interaction_type=instructions.value,
                    provider=Provider.INTERACTION)
                on_action(
                    InteractAction(source=username,
                                   user=follower_name,
                                   succeed=True))
                print_short_report(username, session_state)
            else:
                storage.add_interacted_user(
                    follower_name,
                    followed=False,
                    source=f"@{username}",
                    interaction_type=instructions.value,
                    provider=Provider.INTERACTION)
                on_action(
                    InteractAction(source=username,
                                   user=follower_name,
                                   succeed=False))

        can_continue = True

        if ((is_like_limit_reached and is_likes_enabled) or not is_likes_enabled) and \
           ((is_follow_limit_reached and is_follow_enabled) or not is_follow_enabled) and \
           ((is_comment_limit_reached and is_comment_enabled) or not is_comment_enabled) and \
           ((is_watch_limit_reached and is_stories_enabled) or not is_stories_enabled):
            # If one of the limits reached for source-limit, move to next source
            if (like_reached_source_limit is not None and like_reached_session_limit is None) or \
               (follow_reached_source_limit is not None and follow_reached_session_limit is None):
                can_continue = False
                action_status.set_limit(ActionState.SOURCE_LIMIT_REACHED)

            # If all of the limits reached for session-limit, finish the session
            if ((like_reached_session_limit is not None and is_likes_enabled) or not is_likes_enabled) and \
               ((follow_reached_session_limit is not None and is_follow_enabled) or not is_follow_enabled):
                can_continue = False
                action_status.set_limit(ActionState.SESSION_LIMIT_REACHED)

        print("Back to profiles list")
        device.back()

        return can_continue
예제 #7
0
    def interact_with_follower(follower_name, follower_name_view):
        """
        :return: whether we should continue interaction with other users after this one
        """
        is_interact_limit_reached, interact_reached_source_limit, interact_reached_session_limit = \
            is_limit_reached(InteractAction(source_name=username, source_type=source_type, user=follower_name, succeed=True), session_state)

        if not process_limits(
                is_interact_limit_reached, interact_reached_session_limit,
                interact_reached_source_limit, action_status, "Interaction"):
            return False

        is_get_profile_limit_reached, get_profile_reached_source_limit, get_profile_reached_session_limit = \
            is_limit_reached(GetProfileAction(user=follower_name), session_state)

        if not process_limits(is_get_profile_limit_reached,
                              get_profile_reached_session_limit,
                              get_profile_reached_source_limit, action_status,
                              "Get-Profile"):
            return False

        is_all_filters_satisfied = False
        if is_passed_filters is not None:
            print_debug(f"Running filter-ahead on @{follower_name}")
            should_continue, is_all_filters_satisfied = is_passed_filters(
                device,
                follower_name,
                reset=True,
                filters_tags=['BEFORE_PROFILE_CLICK'])
            if not should_continue:
                on_action(FilterAction(user=follower_name))
                return True

            if not is_all_filters_satisfied:
                print_debug(
                    "Not all filters are satisfied with filter-ahead, continue filtering inside the profile-page"
                )

        print("@" + follower_name + ": interact")
        follower_name_view.click()
        on_action(GetProfileAction(user=follower_name))

        post_count = None
        followers_count = None
        following_count = None

        post_count_el = device.find(
            resourceId=
            'com.instagram.android:id/row_profile_header_textview_post_count',
            className='android.widget.TextView')
        if post_count_el.exists():
            post_count = to_int(post_count_el.get_text())

        followers_count_el = device.find(
            resourceId=
            'com.instagram.android:id/row_profile_header_textview_followers_count',
            className='android.widget.TextView')
        if followers_count_el.exists():
            followers_count = to_int(followers_count_el.get_text())

        following_count_el = device.find(
            resourceId=
            'com.instagram.android:id/row_profile_header_textview_following_count',
            className='android.widget.TextView')
        if following_count_el.exists():
            following_count = to_int(following_count_el.get_text())

        print("@%s (PC=%s ERS=%s ING=%s): interact" %
              (follower_name, post_count, followers_count, following_count))

        with open('filters.json') as json_file:
            filterz = json.load(json_file)
        json_file.close()

        skip = False
        if post_count and post_count < filterz['min_posts']:
            skip = True
            print('Skip because of %s < min_posts' % post_count)
        if not skip and followers_count and followers_count < filterz[
                'min_followers']:
            skip = True
            print('Skip because of %s < min_followers' % followers_count)
        if not skip and followers_count and followers_count > filterz[
                'max_followers']:
            skip = True
            print('Skip because of %s > max_followers' % followers_count)
        if not skip and followers_count and following_count and followers_count / (
                following_count + 1) < filterz['min_potency_ratio']:
            skip = True
            print('Skip because of %s < min_potency_ratio' %
                  (followers_count / (following_count + 1)))
        if not skip and followers_count and following_count and followers_count / (
                following_count + 1) > filterz['max_potency_ratio']:
            skip = True
            print('Skip because of %s > max_potency_ratio' %
                  (followers_count / (following_count + 1)))
        if not skip and not filterz[
                'follow_private_or_empty'] and is_private_account(device):
            skip = True
            print('Skipping private account')

        if skip:
            on_action(FilterAction(user=follower_name))
            # Continue to next follower
            device.back()
            return True

        sleeper.random_sleep()
        is_profile_empty = softban_indicator.detect_empty_profile(device)

        if is_profile_empty:
            print("Back to followers list")
            device.back()
            return True

        follower_profile_view = ProfileView(
            device, follower_name == session_state.my_username)

        if is_passed_filters is not None:
            if not is_all_filters_satisfied:
                should_continue, _ = is_passed_filters(device,
                                                       follower_name,
                                                       reset=False)
                if not should_continue:
                    on_action(FilterAction(user=follower_name))
                    # Continue to next follower
                    print("Back to profiles list")
                    device.back()
                    return True

        is_like_limit_reached, like_reached_source_limit, like_reached_session_limit = \
            is_limit_reached(LikeAction(source_name=username, source_type=source_type, user=follower_name), session_state)

        is_follow_limit_reached, follow_reached_source_limit, follow_reached_session_limit = \
            is_limit_reached(FollowAction(source_name=username, source_type=source_type, user=follower_name), session_state)

        is_watch_limit_reached, watch_reached_source_limit, watch_reached_session_limit = \
            is_limit_reached(StoryWatchAction(source_name=username, source_type=source_type,user=follower_name), session_state)

        is_comment_limit_reached, comment_reached_source_limit, comment_reached_session_limit = \
            is_limit_reached(CommentAction(source_name=username, source_type=source_type, user=follower_name, comment=""), session_state)

        is_private = follower_profile_view.is_private_account()
        if is_private:
            if is_passed_filters is None:
                print(COLOR_OKGREEN + "@" + follower_name +
                      " has private account, won't interact." + COLOR_ENDC)
                on_action(FilterAction(user=follower_name))
                on_action(
                    InteractAction(source_name=username,
                                   source_type=source_type,
                                   user=follower_name,
                                   succeed=False))
                print("Back to profiles list")
                device.back()
                return True
            print("@" + follower_name +
                  ": Private account - images wont be liked.")

        do_have_stories = follower_profile_view.is_story_available()
        if not do_have_stories:
            print("@" + follower_name +
                  ": seems there are no stories to be watched.")

        is_likes_enabled = likes_count != '0'
        is_stories_enabled = stories_count != '0'
        is_follow_enabled = follow_percentage != 0
        is_comment_enabled = comment_percentage != 0

        likes_value = get_value(likes_count,
                                "Likes count: {}",
                                2,
                                max_count=12)
        stories_value = get_value(stories_count, "Stories to watch: {}", 1)

        can_like = not is_like_limit_reached and not is_private and likes_value > 0
        can_follow = (
            not is_follow_limit_reached
        ) and storage.get_following_status(
            follower_name) == FollowingStatus.NONE and follow_percentage > 0
        can_watch = (not is_watch_limit_reached
                     ) and do_have_stories and stories_value > 0
        can_comment = (not is_comment_limit_reached
                       ) and not is_private and comment_percentage > 0
        can_interact = can_like or can_follow or can_watch or can_comment

        if not can_interact:
            print(
                "@" + follower_name +
                ": Cant be interacted (due to limits / already followed). Skip."
            )
            on_action(
                InteractAction(source_name=username,
                               source_type=source_type,
                               user=follower_name,
                               succeed=False))
        else:
            print_interaction_types(follower_name, can_like, can_follow,
                                    can_watch, can_comment)
            interaction_strategy = InteractionStrategy(
                do_like=can_like,
                do_follow=can_follow,
                do_story_watch=can_watch,
                do_comment=can_comment,
                likes_count=likes_value,
                follow_percentage=follow_percentage,
                like_percentage=like_percentage,
                stories_count=stories_value,
                comment_percentage=comment_percentage,
                comments_list=comments_list)

            is_liked, is_followed, is_watch, is_commented = interaction(
                username=follower_name,
                interaction_strategy=interaction_strategy)
            if is_liked or is_followed or is_watch or is_commented:
                on_action(
                    InteractAction(source_name=username,
                                   source_type=source_type,
                                   user=follower_name,
                                   succeed=True))
                print_short_report(f"@{username}", session_state)
            else:
                on_action(
                    InteractAction(source_name=username,
                                   source_type=source_type,
                                   user=follower_name,
                                   succeed=False))

        can_continue = True

        if ((is_like_limit_reached and is_likes_enabled) or not is_likes_enabled) and \
           ((is_follow_limit_reached and is_follow_enabled) or not is_follow_enabled) and \
           ((is_comment_limit_reached and is_comment_enabled) or not is_comment_enabled) and \
           ((is_watch_limit_reached and is_stories_enabled) or not is_stories_enabled):
            # If one of the limits reached for source-limit, move to next source
            if (like_reached_source_limit is not None and like_reached_session_limit is None) or \
               (follow_reached_source_limit is not None and follow_reached_session_limit is None):
                can_continue = False
                action_status.set_limit(ActionState.SOURCE_LIMIT_REACHED)

            # If all of the limits reached for session-limit, finish the session
            if ((like_reached_session_limit is not None and is_likes_enabled) or not is_likes_enabled) and \
               ((follow_reached_session_limit is not None and is_follow_enabled) or not is_follow_enabled):
                can_continue = False
                action_status.set_limit(ActionState.SESSION_LIMIT_REACHED)

        print("Back to profiles list")
        device.back()

        return can_continue