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 do_unfollow(device, username, my_username, check_if_is_follower, on_action): """ :return: whether unfollow was successful """ username_view = device.find( resourceId=f'{device.app_id}:id/follow_list_username', className='android.widget.TextView', text=username) if not username_view.exists(): print(COLOR_FAIL + "Cannot find @" + username + ", skip." + COLOR_ENDC) return False username_view.click() on_action(GetProfileAction(user=username)) sleeper.random_sleep() if_profile_empty = softban_indicator.detect_empty_profile(device) if if_profile_empty: print("Back to the followings list.") device.back() return False if check_if_is_follower and _check_is_follower(device, username, my_username): print("Skip @" + username + ". This user is following you.") print("Back to the followings list.") device.back() return False unfollow_button = device.find(classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, text='Following') if not unfollow_button.exists(): print( COLOR_FAIL + "Cannot find Following button. Maybe not English language is set?" + COLOR_ENDC) save_crash(device) switch_to_english(device) raise LanguageChangedException() unfollow_button.click() confirm_unfollow_button = device.find( resourceId=f'{device.app_id}:id/follow_sheet_unfollow_row', className='android.widget.TextView') if not confirm_unfollow_button.exists(): print(COLOR_FAIL + "Cannot confirm unfollow." + COLOR_ENDC) save_crash(device) device.back() return False confirm_unfollow_button.click() sleeper.random_sleep() _close_confirm_dialog_if_shown(device) softban_indicator.detect_action_blocked_dialog(device) print("Back to the followings list.") device.back() return True
def _open_user(device, username, open_followers=False, open_followings=False, refresh=False, 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") followers_button = device.find( resourceIdMatches=FOLLOWERS_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followers_button.click() if open_followings: print("Open your followings") followings_button = device.find( resourceIdMatches=FOLLOWING_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followings_button.click() else: 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") followers_button = device.find( resourceIdMatches=FOLLOWERS_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followers_button.click() if open_followings: print("Open @" + username + " followings") followings_button = device.find( resourceIdMatches=FOLLOWING_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followings_button.click() return True
def interact_with_profile(liker_username, liker_username_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=place, source_type=source_type, user=liker_username, 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=liker_username), 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 @{liker_username}") should_continue, is_all_filters_satisfied = is_passed_filters( device, liker_username, reset=True, filters_tags=['BEFORE_PROFILE_CLICK']) if not should_continue: on_action(FilterAction(liker_username)) 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("@" + liker_username + ": interact") liker_username_view.click() on_action(GetProfileAction(user=liker_username)) sleeper.random_sleep() is_profile_empty = softban_indicator.detect_empty_profile(device) if is_profile_empty: print("Back to likers list") device.back() return True if is_passed_filters is not None: if not is_all_filters_satisfied: should_continue, _ = is_passed_filters(device, liker_username, reset=False) if not should_continue: on_action(FilterAction(liker_username)) # Continue to next follower print("Back to likers list") device.back() return True is_like_limit_reached, like_reached_source_limit, like_reached_session_limit = \ is_limit_reached(LikeAction(source_name=place, source_type=source_type, user=liker_username), session_state) is_follow_limit_reached, follow_reached_source_limit, follow_reached_session_limit = \ is_limit_reached(FollowAction(source_name=place, source_type=source_type, user=liker_username), session_state) is_watch_limit_reached, watch_reached_source_limit, watch_reached_session_limit = \ is_limit_reached(StoryWatchAction(source_name=place, source_type=source_type, user=liker_username), session_state) is_comment_limit_reached, comment_reached_source_limit, comment_reached_session_limit = \ is_limit_reached(CommentAction(source_name=place, source_type=source_type, user=liker_username, comment=""), session_state) is_private = is_private_account(device) if is_private: if is_passed_filters is None: print(COLOR_OKGREEN + "@" + liker_username + " has private account, won't interact." + COLOR_ENDC) on_action(FilterAction(liker_username)) on_action( InteractAction(source_name=place, source_type=source_type, user=liker_username, succeed=False)) print("Back to likers list") device.back() return True print("@" + liker_username + ": Private account - images wont be liked.") do_have_stories = do_have_story(device) if not do_have_stories: print("@" + liker_username + ": 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( liker_username) == 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( "@" + liker_username + ": Cant be interacted (due to limits / already followed). Skip." ) on_action( InteractAction(source_name=place, source_type=source_type, user=liker_username, succeed=False)) else: print_interaction_types(liker_username, 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=liker_username, interaction_strategy=interaction_strategy) if is_liked or is_followed or is_watch or is_commented: on_action( InteractAction(source_name=place, source_type=source_type, user=liker_username, succeed=True)) print_short_report(f"P-{place}", session_state) else: on_action( InteractAction(source_name=place, source_type=source_type, user=liker_username, 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 followers list") device.back() return can_continue
def handle_blogger(device, username, instructions, session_state, likes_count, stories_count, follow_percentage, like_percentage, comment_percentage, comments_list, storage, on_action, is_limit_reached, is_passed_filters, action_status): is_myself = username == session_state.my_username interaction = partial(interact_with_user, device=device, user_source=username, my_username=session_state.my_username, on_action=on_action) search_view = TabBarView(device).navigate_to_search() blogger_profile_view = search_view.navigate_to_username( username, on_action) if blogger_profile_view is None: return sleeper.random_sleep() is_profile_empty = softban_indicator.detect_empty_profile(device) if is_profile_empty: return followers_following_list_view = None if instructions == BloggerInteractionType.FOLLOWERS: followers_following_list_view = blogger_profile_view.navigate_to_followers( ) elif instructions == BloggerInteractionType.FOLLOWING: followers_following_list_view = blogger_profile_view.navigate_to_following( ) if is_myself: followers_following_list_view.scroll_to_bottom() followers_following_list_view.scroll_to_top() def pre_conditions(follower_name, follower_name_view): if storage.is_user_in_blacklist(follower_name): print("@" + follower_name + " is in blacklist. Skip.") return False elif storage.check_user_was_filtered(follower_name): print("@" + follower_name + ": already filtered in past. Skip.") return False elif not is_myself and storage.check_user_was_interacted( follower_name): print("@" + follower_name + ": already interacted. Skip.") return False elif is_myself and storage.check_user_was_interacted_recently( follower_name): print("@" + follower_name + ": already interacted in the last week. Skip.") return False return True 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 followers_following_list_view.iterate_over_followers( is_myself, interact_with_follower, pre_conditions)
def interact_with_follower(follower_name, follower_name_view): 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 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_passed_filters(device, follower_name, reset=False): 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_private = follower_profile_view.is_private_account() if is_private: 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 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_interact = can_like or can_follow or can_watch 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) interaction_strategy = InteractionStrategy(do_like=can_like, do_follow=can_follow, do_story_watch=can_watch, likes_count=likes_value, follow_percentage=follow_percentage, like_percentage=like_percentage, stories_count=stories_value) is_liked, is_followed, is_watch = interaction(username=follower_name, interaction_strategy=interaction_strategy) if is_liked or is_followed or is_watch: 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_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 do_unfollow(device, my_username, username, storage, check_if_is_follower, username_view, follow_status_button_view, on_action): """ :return: whether unfollow was successful """ need_to_go_back_to_list = True unfollow_from_list_chance = randint(1, 100) if follow_status_button_view is not None and not check_if_is_follower and unfollow_from_list_chance > 50: # We can unfollow directly here instead of getting inside to profile need_to_go_back_to_list = False print("Unfollowing a profile directly from the following list.") follow_status_button_view.click() else: print("Unfollowing a profile from his profile page.") username_view.click() on_action(GetProfileAction(user=username)) sleeper.random_sleep() if_profile_empty = softban_indicator.detect_empty_profile(device) if if_profile_empty: print("Back to the followings list.") device.back() return False if check_if_is_follower and _check_is_follower(device, username, my_username): print("Skip @" + username + ". This user is following you.") storage.update_follow_status(username, True, True) print("Back to the followings list.") device.back() return False unfollow_button = device.find( classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, text='Following') if not unfollow_button.exists(): print( COLOR_FAIL + "Cannot find Following button. Maybe not English language is set?" + COLOR_ENDC) save_crash(device) switch_to_english(device) raise LanguageChangedException() print(f"Unfollowing @{username}...") unfollow_button.click() sleeper.random_sleep() confirm_unfollow_button = device.find( resourceId=f'{device.app_id}:id/follow_sheet_unfollow_row', className='android.widget.TextView') if not confirm_unfollow_button.exists(): print(COLOR_FAIL + "Cannot confirm unfollow." + COLOR_ENDC) save_crash(device) device.back() return False confirm_unfollow_button.click() sleeper.random_sleep() _close_confirm_dialog_if_shown(device) softban_indicator.detect_action_blocked_dialog(device) if need_to_go_back_to_list: print("Back to the followings list.") device.back() return True
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
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") followers_button = device.find( resourceIdMatches=FOLLOWERS_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followers_button.click() if open_followings: print("Open your followings") followings_button = device.find( resourceIdMatches=FOLLOWING_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followings_button.click() sleeper.random_sleep() followings_tab = device.find( classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, textContains=' Following') followings_tab.click() 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") followers_button = device.find( resourceIdMatches=FOLLOWERS_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followers_button.click() if open_followings: print("Open @" + username + " followings") followings_button = device.find( resourceIdMatches=FOLLOWING_BUTTON_ID_REGEX.format( device.app_id, device.app_id)) followings_button.click() sleeper.random_sleep() followings_tab = device.find( classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, textContains=' Following') followings_tab.click() return True
def do_unfollow(device, my_username, username, storage, check_if_is_follower, username_view, follow_status_button_view, on_action): """ :return: whether unfollow was successful """ need_to_go_back_to_list = True unfollow_from_list_chance = randint(1, 100) if follow_status_button_view is not None and not check_if_is_follower and unfollow_from_list_chance > 50: # We can unfollow directly here instead of getting inside to profile need_to_go_back_to_list = False print("Unfollowing a profile directly from the following list.") follow_status_button_view.click() else: print("Unfollowing a profile from their profile page.") username_view.click() on_action(GetProfileAction(user=username)) sleeper.random_sleep() if_profile_empty = softban_indicator.detect_empty_profile(device) if if_profile_empty: print("Back to the followings list.") device.back() return False if check_if_is_follower: if _check_is_follower(device, username, my_username): print("Skip @" + username + ". This user is following you.") storage.update_follow_status(username, is_follow_me=True, do_i_follow_him=True) print("Back to the followings list.") device.back() return False storage.update_follow_status(username, is_follow_me=False, do_i_follow_him=True) unfollow_button = device.find(classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, text='Following') if not unfollow_button.exists(): print(COLOR_FAIL + "Cannot find Following button. Maybe not English language is set?" + COLOR_ENDC) save_crash(device) switch_to_english(device) raise LanguageChangedException() print(f"Unfollowing @{username}...") unfollow_button.click() sleeper.random_sleep() unfollow_confirmed = False dialog_view = DialogView(device) if dialog_view.is_visible(): print("Confirming unfollow...") unfollow_confirmed = dialog_view.click_unfollow() if unfollow_confirmed: try: # If the account is private, another popup is shown confirm_button = device.find(classNameMatches=TEXTVIEW_OR_BUTTON_REGEX, clickable=True, text='Unfollow') # If it exists, click unfollow if confirm_button.exists(): print("Private account, confirming unfollow...") confirm_button.click() # Either way, sleep except: pass finally: sleeper.random_sleep() else: softban_indicator.detect_action_blocked_dialog(device) if need_to_go_back_to_list: print("Back to the followings list.") device.back() return True