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
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
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()
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
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
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
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