def sort_followings_by_date(self, device): logger.info("Sort followings by date: from oldest to newest.") UniversalActions(device)._swipe_points(direction=Direction.DOWN, ) sort_button = device.find( resourceId=self.ResourceID.SORTING_ENTRY_ROW_ICON, className=ClassName.IMAGE_VIEW, ) if not sort_button.exists(): logger.error( "Cannot find button to sort followings. Continue without sorting." ) return sort_button.click() random_sleep() sort_options_recycler_view = device.find( resourceId=self.ResourceID. FOLLOW_LIST_SORTING_OPTIONS_RECYCLER_VIEW) if not sort_options_recycler_view.exists(): logger.error( "Cannot find options to sort followings. Continue without sorting." ) return sort_options_recycler_view.child(index=2).click()
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
def handle_hashtag( self, device, hashtag, likes_count, stories_count, stories_percentage, follow_percentage, follow_limit, interact_percentage, current_job, storage, profile_filter, on_like, on_watch, on_interaction, ): interaction = partial( interact_with_user, my_username=self.session_state.my_username, likes_count=likes_count, stories_count=stories_count, stories_percentage=stories_percentage, follow_percentage=follow_percentage, on_like=on_like, on_watch=on_watch, profile_filter=profile_filter, args=self.args, session_state=self.session_state, current_mode=self.current_mode, ) is_follow_limit_reached = partial( is_follow_limit_reached_for_source, follow_limit=follow_limit, source=hashtag, session_state=self.session_state, ) search_view = TabBarView(device).navigateToSearch() if not search_view.navigateToHashtag(hashtag): return if current_job == "hashtag-posts-recent": logger.info("Switching to Recent tab") HashTagView(device)._getRecentTab().click() random_sleep(5, 10) if HashTagView(device)._check_if_no_posts(): UniversalActions(device)._reload_page() random_sleep(4, 8) logger.info("Opening the first result") result_view = HashTagView(device)._getRecyclerView() HashTagView(device)._getFistImageView(result_view).click() random_sleep() def interact(): can_follow = not is_follow_limit_reached() and ( storage.get_following_status(username) == FollowingStatus.NONE or storage.get_following_status(username) == FollowingStatus.NOT_IN_LIST ) interaction_succeed, followed = interaction( device, username=username, can_follow=can_follow ) storage.add_interacted_user(username, followed=followed) can_continue = on_interaction( succeed=interaction_succeed, followed=followed ) if not can_continue: return False else: return True def random_choice(): from random import randint random_number = randint(1, 100) if interact_percentage > random_number: return True else: return False post_description = "" nr_same_post = 0 nr_same_posts_max = 3 while True: flag, post_description = PostsViewList(device)._check_if_last_post( post_description ) if flag: nr_same_post += 1 logger.info( f"Warning: {nr_same_post}/{nr_same_posts_max} repeated posts." ) if nr_same_post == nr_same_posts_max: logger.info( f"Scrolled through {nr_same_posts_max} posts with same description and author. Finish." ) break else: nr_same_post = 0 if random_choice(): username = PostsViewList(device)._post_owner(Owner.GET_NAME)[:-3] if storage.is_user_in_blacklist(username): logger.info(f"@{username} is in blacklist. Skip.") elif storage.check_user_was_interacted(username): logger.info(f"@{username}: already interacted. Skip.") else: logger.info(f"@{username}: interact") PostsViewList(device)._like_in_post_view(LikeMode.DOUBLE_CLICK) detect_block(device) if not PostsViewList(device)._check_if_liked(): PostsViewList(device)._like_in_post_view(LikeMode.SINGLE_CLICK) detect_block(device) random_sleep(1, 2) if PostsViewList(device)._post_owner(Owner.OPEN): if not interact(): break device.back() PostsViewList(device).swipe_to_fit_posts(SwipeTo.HALF_PHOTO) random_sleep(0, 1) PostsViewList(device).swipe_to_fit_posts(SwipeTo.NEXT_POST) random_sleep() continue
def iterate_over_followings(self, device, count, on_unfollow, storage, unfollow_restriction, my_username): # Wait until list is rendered device.find( resourceId=self.ResourceID.FOLLOW_LIST_CONTAINER, className=ClassName.LINEAR_LAYOUT, ).wait() sort_container_obj = device.find( resourceId=self.ResourceID.SORTING_ENTRY_ROW_ICON) top_tab_obj = device.find( resourceId=self.ResourceID.UNIFIED_FOLLOW_LIST_TAB_LAYOUT) if sort_container_obj.exists() and top_tab_obj.exists(): sort_container_bounds = sort_container_obj.get_bounds()["top"] list_tab_bounds = top_tab_obj.get_bounds()["bottom"] delta = sort_container_bounds - list_tab_bounds UniversalActions(device)._swipe_points( direction=Direction.DOWN, start_point_y=sort_container_bounds, delta_y=delta - 50, ) else: UniversalActions(device)._swipe_points(direction=Direction.DOWN, ) checked = {} unfollowed_count = 0 while True: logger.info("Iterate over visible followings") random_sleep() screen_iterated_followings = 0 for item in device.find( resourceId=self.ResourceID.FOLLOW_LIST_CONTAINER, className=ClassName.LINEAR_LAYOUT, ): user_info_view = item.child(index=1) user_name_view = user_info_view.child(index=0).child() if not user_name_view.exists(quick=True): logger.info( "Next item not found: probably reached end of the screen.", extra={"color": f"{Fore.GREEN}"}, ) break username = user_name_view.get_text() if username not in checked: checked[username] = None screen_iterated_followings += 1 if storage.is_user_in_whitelist(username): logger.info(f"@{username} is in whitelist. Skip.") continue if (unfollow_restriction == UnfollowRestriction.FOLLOWED_BY_SCRIPT or unfollow_restriction == UnfollowRestriction. FOLLOWED_BY_SCRIPT_NON_FOLLOWERS): following_status = storage.get_following_status( username) if following_status == FollowingStatus.NOT_IN_LIST: logger.info( f"@{username} has not been followed by this bot. Skip." ) continue elif not following_status == FollowingStatus.FOLLOWED: logger.info( f"Skip @{username}. Following status: {following_status.name}." ) continue if (unfollow_restriction == UnfollowRestriction.ANY or unfollow_restriction == UnfollowRestriction.ANY_NON_FOLLOWERS): following_status = storage.get_following_status( username) if following_status == FollowingStatus.UNFOLLOWED: logger.info( f"Skip @{username}. Following status: {following_status.name}." ) continue unfollowed = self.do_unfollow( device, username, my_username, unfollow_restriction == UnfollowRestriction.FOLLOWED_BY_SCRIPT_NON_FOLLOWERS or unfollow_restriction == UnfollowRestriction.ANY_NON_FOLLOWERS, ) if unfollowed: storage.add_interacted_user(username, unfollowed=True) on_unfollow() unfollowed_count += 1 random_sleep() if unfollowed_count >= count: return else: logger.debug(f"Already checked {username}") if screen_iterated_followings > 0: logger.info("Need to scroll now", extra={"color": f"{Fore.GREEN}"}) list_view = device.find(resourceId=self.ResourceID.LIST, className=ClassName.LIST_VIEW) list_view.scroll(DeviceFacade.Direction.BOTTOM) else: logger.info( "No followings were iterated, finish.", extra={"color": f"{Fore.GREEN}"}, ) return