示例#1
0
def _get_confirmation_code_sms_activate(response_id) -> Optional[str]:
    url = f"https://sms-activate.ru/stubs/handler_api.php" \
          f"?api_key={SMS_ACTIVATE_API_KEY}" \
          f"&id={response_id}" \
          f"&country={SMSPVA_COUNTRY_CODE}" \
          f"&action=getStatus"
    attempts_count = 0
    while True:
        sleeper.random_sleep(multiplier=8.0)
        code, body, fail_reason = network.get(url, 'Mozilla/5.0')
        attempts_count += 1
        if code != HTTP_OK or body is None:
            print(
                COLOR_FAIL +
                f"Cannot get confirmation code via sms-activate.ru API: {code} ({fail_reason})"
                + COLOR_ENDC)
            return None

        response_regex = re.compile(r'STATUS_OK:(\d+)')
        match = response_regex.match(body.decode('utf-8'))
        if match:
            confirmation_code = match.group(1)
            return confirmation_code
        else:
            if attempts_count >= CONFIRMATION_CODE_MAX_ATTEMPTS_COUNT:
                print(
                    "Well, looks like Instagram isn't going to send SMS to this phone number"
                )
                return None
            print(
                "Let's wait a bit more: confirmation code isn't received yet")
示例#2
0
    def start_session(self,
                      args,
                      device_wrapper,
                      app_version,
                      save_profile_info=True):
        self.session_state = SessionState()
        self.session_state.args = args.__dict__
        self.session_state.app_id = args.app_id
        self.session_state.app_version = app_version
        self.sessions.append(self.session_state)

        device_wrapper.get().wake_up()

        print_timeless(COLOR_REPORT + "\n-------- START: " +
                       str(self.session_state.startTime) + " --------" +
                       COLOR_ENDC)

        close_instagram(device_wrapper.device_id, device_wrapper.app_id)
        sleeper.random_sleep()

        if __version__.__debug_mode__:
            device_wrapper.get().start_screen_record()
        open_instagram(args.device, args.app_id)
        sleeper.random_sleep()
        if save_profile_info:
            self.session_state.my_username, \
                self.session_state.my_followers_count, \
                self.session_state.my_following_count = get_my_profile_info(device_wrapper.get(), self.username)

        return self.session_state
示例#3
0
def search_for(device,
               username=None,
               hashtag=None,
               place=None,
               on_action=None):
    tab_bar_view = TabBarView(device)

    # There may be no TabBarView if Instagram was opened via a deeplink. Then we have to clear the backstack.
    is_message_printed = False
    while not tab_bar_view.is_visible():
        if not is_message_printed:
            print(COLOR_OKGREEN + "Clearing the back stack..." + COLOR_ENDC)
            is_message_printed = True
        tab_bar_view.press_back_arrow()
        sleeper.random_sleep()

    search_view = tab_bar_view.navigate_to_search()
    target_view = None

    if username is not None:
        target_view = search_view.navigate_to_username(username, on_action)

    if hashtag is not None:
        target_view = search_view.navigate_to_hashtag(hashtag)

    if place is not None:
        target_view = search_view.navigate_to_place(place)

    return target_view is not None
示例#4
0
    def likePost(self, click_btn_like=False):
        MEDIA_GROUP_RE = case_insensitive_re([
            f"{self.device.app_id}:id/media_group",
            f"{self.device.app_id}:id/carousel_media_group",
        ])
        post_media_view = self.device.find(
            resourceIdMatches=MEDIA_GROUP_RE,
            className="android.widget.FrameLayout")

        if click_btn_like:
            like_btn_view = self._getPostLikeButton()
            if not like_btn_view:
                return False
            like_btn_view.click()
        else:

            if post_media_view.exists():
                post_media_view.double_click()
            else:
                print(COLOR_FAIL + "Could not find post area to double click" +
                      COLOR_ENDC)
                return False

        sleeper.random_sleep()

        return self._isPostLiked()
示例#5
0
    def back(self):
        """
        Press back and check that UI hierarchy was changed. If it didn't change, it means that back press didn't work.
        So, we try to press back several times until it is finally changed.
        """
        max_attempts = 5

        def normalize(hierarchy):
            """
            Remove all texts from hierarchy. It may contain some changing data, e.g. current time.
            """
            return re.sub(r'text=".*"', 'text=""', hierarchy)

        succeed = False
        attempts = 0
        while not succeed:
            if attempts >= max_attempts:
                print(COLOR_FAIL + f"Tried to press back {attempts} times with no success. Will proceed next..." +
                      COLOR_ENDC)
                break
            hierarchy_before = normalize(self.dump_hierarchy())
            self._press_back()
            hierarchy_after = normalize(self.dump_hierarchy())
            succeed = hierarchy_before != hierarchy_after
            if not succeed:
                print(COLOR_OKGREEN + "Pressed back but nothing changed on the screen. Will try again." + COLOR_ENDC)
                sleeper.random_sleep()
            attempts += 1
示例#6
0
def _open_profile_using_deeplink(device, profile_name):
    is_profile_opened = False
    should_continue = True

    profile_url = f"https://www.instagram.com/{profile_name}/"
    if not open_instagram_with_url(device.device_id, device.app_id,
                                   profile_url):
        return should_continue, is_profile_opened

    sleeper.random_sleep()

    user_not_found_text = device.find(
        resourceId=f'{device.app_id}:id/no_found_text',
        className='android.widget.TextView')
    if user_not_found_text.exists(quick=True):
        print(
            COLOR_FAIL +
            f"Seems like profile {profile_name} is not exists. Pressing back."
            + COLOR_ENDC)
        should_continue = False
        is_profile_opened = False
        device.back()
    else:
        should_continue = True
        is_profile_opened = True

    return should_continue, is_profile_opened
示例#7
0
def _watch_stories(device, username, stories_value, on_action):
    if stories_value == 0:
        return False

    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(user=username))
            sleeper.random_sleep()

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

            if not _get_action_bar(device).exists():
                print("Back to profile")
                device.back()
            return True
    return False
示例#8
0
def _check_is_follower(device, username, my_username):
    print(COLOR_OKGREEN + "Check if @" + username + " is following you." +
          COLOR_ENDC)
    following_container = device.find(
        resourceIdMatches=FOLLOWING_BUTTON_ID_REGEX.format(
            device.app_id, device.app_id))
    following_container.click()

    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
示例#9
0
def _close_confirm_dialog_by_version(device, version):
    if version == 1:
        dialog_root_view = device.find(resourceId=f'{device.app_id}:id/dialog_root_view',
                                       className='android.widget.FrameLayout')
    elif version == 2:
        dialog_root_view = device.find(resourceId=f'{device.app_id}:id/dialog_container',
                                       className='android.view.ViewGroup')
    else:
        raise ValueError("Close unfollow confrim dialog for vis not exists.")

    if not dialog_root_view.exists(quick=True):
        return False

    # Avatar existence is the way to distinguish confirm dialog from block dialog
    user_avatar_view = device.find(resourceIdMatches=USER_AVATAR_VIEW_ID.format(device.app_id),
                                   className='android.widget.ImageView')
    if not user_avatar_view.exists(quick=True):
        return False

    print(COLOR_OKGREEN + "Dialog shown, confirm unfollowing." + COLOR_ENDC)
    sleeper.random_sleep()
    if version == 1:
        unfollow_button = dialog_root_view.child(resourceId=f'{device.app_id}:id/primary_button',
                                                 classNameMatches=TEXTVIEW_OR_BUTTON_REGEX)
    elif version == 2:
        unfollow_button = dialog_root_view.child(resourceId=f'{device.app_id}:id/primary_button',
                                                 classNameMatches=TEXTVIEW_OR_BUTTON_REGEX,
                                                 textMatches=UNFOLLOW_REGEX)

    unfollow_button.click()
    sleeper.random_sleep()
    return True
示例#10
0
def _get_confirmation_code_smspva(response_id) -> Optional[str]:
    url = f"http://smspva.com/priemnik.php?metod=get_sms&service=opt16" \
          f"&country={SMSPVA_COUNTRY_CODE}" \
          f"&id={response_id}" \
          f"&apikey={SMSPVA_API_KEY}"
    attempts_count = 0
    while True:
        sleeper.random_sleep(multiplier=8.0)
        code, body, fail_reason = network.get(url, 'Mozilla/5.0')
        attempts_count += 1
        if code == HTTP_OK and body is not None:
            json_data = json.loads(body)
        else:
            print(
                COLOR_FAIL +
                f"Cannot get confirmation code via smspva.com API: {code} ({fail_reason})"
                + COLOR_ENDC)
            return None

        confirmation_code = json_data["sms"]
        if confirmation_code is None:
            if attempts_count >= CONFIRMATION_CODE_MAX_ATTEMPTS_COUNT:
                print(
                    "Well, looks like Instagram isn't going to send SMS to this phone number"
                )
                return None
            print(
                "Let's wait a bit more: confirmation code isn't received yet")
        else:
            break
    return confirmation_code
示例#11
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
示例#12
0
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
示例#13
0
def interact_with_user(device,
                       user_source,
                       username,
                       my_username,
                       interaction_strategy: InteractionStrategy,
                       on_action) -> (bool, bool):
    """
    :return: (whether some photos was liked, whether @username was followed during the interaction)
    """
    global liked_count, is_followed
    liked_count = 0
    is_followed = False
    is_watched = False

    if username == my_username:
        print("It's you, skip.")
        return liked_count == interaction_strategy.likes_count, is_followed, is_watched

    sleeper.random_sleep()

    if interaction_strategy.do_story_watch:
        is_watched = _watch_stories(device, username, interaction_strategy.stories_count, on_action)

    coordinator_layout = device.find(resourceId=f'{device.app_id}:id/coordinator_root_layout')
    if coordinator_layout.exists():
        print("Scroll down to see more photos.")
        coordinator_layout.scroll(DeviceFacade.Direction.BOTTOM)

    if interaction_strategy.do_like:
        number_of_rows_to_use = min((interaction_strategy.likes_count * 2) // 3 + 1, 4)
        photos_indices = list(range(0, number_of_rows_to_use * 3))
        shuffle(photos_indices)
        photos_indices = photos_indices[:interaction_strategy.likes_count]
        photos_indices = sorted(photos_indices)

        def on_like():
            global liked_count
            liked_count += 1
            print(COLOR_OKGREEN + "@{} - photo been liked.".format(username) + COLOR_ENDC)
            on_action(LikeAction(source=user_source, user=username))

        for i in range(0, interaction_strategy.likes_count):
            photo_index = photos_indices[i]
            row = photo_index // 3
            column = photo_index - row * 3

            sleeper.random_sleep()
            print("Open and like photo #" + str(i + 1) + " (" + str(row + 1) + " row, " + str(column + 1) + " column)")
            if not _open_photo_and_like(device, row, column, interaction_strategy.like_percentage, on_like):
                print(COLOR_OKGREEN + "Less than " + str(number_of_rows_to_use * 3) + " photos." + COLOR_ENDC)
                break

    if interaction_strategy.do_follow:
        is_followed = _follow(device, username, interaction_strategy.follow_percentage)
        if is_followed:
            print(COLOR_OKGREEN + "Following @{}.".format(username) + COLOR_ENDC)
            on_action(FollowAction(source=user_source, user=username))

    return liked_count > 0, is_followed, is_watched
示例#14
0
def _open_photo_and_like_and_comment(device, row, column, do_like, do_comment,
                                     like_percentage, on_like,
                                     comment_percentage, comments_list,
                                     my_username, on_comment):
    def open_photo():
        # recycler_view has a className 'androidx.recyclerview.widget.RecyclerView' on modern Android versions and
        # 'android.view.View' on Android 5.0.1 and probably earlier versions
        recycler_view = device.find(resourceId='android:id/list')
        row_view = recycler_view.child(index=row + 1)
        if not row_view.exists():
            return False
        item_view = row_view.child(index=column)
        if not item_view.exists():
            return False
        item_view.click()
        if not OpenedPostView(device).is_visible():
            print(COLOR_OKGREEN +
                  "Didn't open the post by click, trying again..." +
                  COLOR_ENDC)
            item_view.click()
            if not OpenedPostView(device).is_visible():
                print(COLOR_FAIL + "Couldn't open this post twice, abort." +
                      COLOR_ENDC)
                return False
        return True

    if not open_photo():
        return False

    sleeper.random_sleep()

    to_like = False
    to_comment = False
    if do_like:
        to_like = True
        like_chance = randint(1, 100)
        if like_chance > like_percentage:
            print("Not going to like image due to like-percentage hit")
            to_like = False

    if do_comment:
        to_comment = True
        comment_chance = randint(1, 100)
        if comment_chance > comment_percentage:
            print("Not going to comment image due to comment-percentage hit")
            to_comment = False

    if to_like:
        OpenedPostView(device).like()
        softban_indicator.detect_action_blocked_dialog(device)
        on_like()

    if to_comment:
        _comment(device, my_username, comments_list, on_comment)

    print("Back to profile")
    device.back()
    return True
示例#15
0
def _follow(device, username, follow_percentage):
    follow_chance = randint(1, 100)
    if follow_chance > follow_percentage:
        return False

    print("Following...")
    coordinator_layout = device.find(resourceId=f'{device.app_id}:id/coordinator_root_layout')
    if coordinator_layout.exists():
        coordinator_layout.scroll(DeviceFacade.Direction.TOP)

    sleeper.random_sleep()

    profile_header_main_layout = device.find(resourceId=f"{device.app_id}:id/profile_header_fixed_list",
                                             className='android.widget.LinearLayout')

    shop_button = profile_header_main_layout.child(className='android.widget.Button',
                                                   clickable=True,
                                                   textMatches=SHOP_REGEX)

    if shop_button.exists(quick=True):
        follow_button = profile_header_main_layout.child(className='android.widget.Button',
                                                         clickable=True,
                                                         textMatches=FOLLOW_REGEX)
        if not follow_button.exists():
            print(COLOR_FAIL + "Look like a shop profile without an option to follow, continue." + COLOR_ENDC)
            return False
    else:
        profile_header_actions_layout = device.find(resourceId=f'{device.app_id}:id/profile_header_actions_top_row',
                                                    className='android.widget.LinearLayout')
        if not profile_header_actions_layout.exists():
            print(COLOR_FAIL + "Cannot find profile actions." + COLOR_ENDC)
            return False

        follow_button = profile_header_actions_layout.child(classNameMatches=TEXTVIEW_OR_BUTTON_REGEX,
                                                            clickable=True,
                                                            textMatches=FOLLOW_REGEX)

        if not follow_button.exists():
            unfollow_button = profile_header_actions_layout.child(classNameMatches=TEXTVIEW_OR_BUTTON_REGEX,
                                                                  clickable=True,
                                                                  textMatches=UNFOLLOW_REGEX)
            if unfollow_button.exists():
                print(COLOR_OKGREEN + "You already follow @" + username + "." + COLOR_ENDC)
                return False
            else:
                print(COLOR_FAIL + "Cannot find neither Follow button, nor Unfollow button. Maybe not "
                                   "English language is set?" + COLOR_ENDC)
                save_crash(device)
                switch_to_english(device)
                return False

    follow_button.click()
    softban_indicator.detect_action_blocked_dialog(device)
    print(COLOR_OKGREEN + "Followed @" + username + COLOR_ENDC)
    sleeper.random_sleep()
    return True
示例#16
0
def open_likers(device):
    likes_view = device.find(resourceId=f'{device.app_id}:id/row_feed_textview_likes',
                             className='android.widget.TextView')
    if likes_view.exists(quick=True) and ActionBarView.is_in_interaction_rect(likes_view):
        print("Opening post likers")
        sleeper.random_sleep()
        likes_view.click()
        return True
    else:
        return False
示例#17
0
def _iterate_over_my_followers_or_followings(device, iteration_callback,
                                             iteration_callback_pre_conditions,
                                             is_followers):
    entities_name = "followers" if is_followers else "followings"

    # Wait until list is rendered
    device.find(resourceId=f'{device.app_id}:id/follow_list_container',
                className='android.widget.LinearLayout').wait()

    while True:
        print(f"Iterate over visible {entities_name}")
        sleeper.random_sleep()
        screen_iterated_followings = 0

        for item in device.find(
                resourceId=f'{device.app_id}:id/follow_list_container',
                className='android.widget.LinearLayout'):
            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):
                print(
                    COLOR_OKGREEN +
                    "Next item not found: probably reached end of the screen."
                    + COLOR_ENDC)
                break

            follow_status_button_view = item.child(index=2)
            if not follow_status_button_view.exists(quick=True):
                follow_status_button_view = None

            username = user_name_view.get_text()
            screen_iterated_followings += 1

            if not iteration_callback_pre_conditions(
                    username, user_name_view, follow_status_button_view):
                continue

            to_continue = iteration_callback(username, user_name_view,
                                             follow_status_button_view)
            if to_continue:
                sleeper.random_sleep()
            else:
                print(COLOR_OKBLUE +
                      f"Stopping iteration over {entities_name}" + COLOR_ENDC)
                return

        if screen_iterated_followings > 0:
            print(COLOR_OKGREEN + "Need to scroll now" + COLOR_ENDC)
            list_view = device.find(resourceId='android:id/list',
                                    className='android.widget.ListView')
            list_view.scroll(DeviceFacade.Direction.BOTTOM)
        else:
            print(COLOR_OKGREEN +
                  f"No {entities_name} were iterated, finish." + COLOR_ENDC)
            return
示例#18
0
def search_for(device, username=None, hashtag=None, on_action=None):
    navigate(device, Tabs.SEARCH)
    search_edit_text = device.find(
        resourceId='com.instagram.android:id/action_bar_search_edit_text',
        className='android.widget.EditText')
    search_edit_text.click()

    if username is not None:
        print("Open user @" + username)
        search_edit_text.set_text(username)
        username_view = device.find(
            resourceId='com.instagram.android:id/row_search_user_username',
            className='android.widget.TextView',
            text=username)

        sleeper.random_sleep()
        if not username_view.exists():
            print_timeless(COLOR_FAIL + "Cannot find user @" + username +
                           ", abort." + COLOR_ENDC)
            return False

        username_view.click()

        if on_action is not None:
            on_action(GetProfileAction(user=username))

        return True

    if hashtag is not None:
        print("Open hashtag #" + hashtag)
        tab_layout = device.find(
            resourceId='com.instagram.android:id/fixed_tabbar_tabs_container',
            className='android.widget.LinearLayout')
        if not tab_layout.exists():
            print(COLOR_FAIL + "Cannot find tabs." + COLOR_ENDC)
            return False
        tab_layout.child(index=2).click()

        search_edit_text.set_text(hashtag)
        hashtag_view = device.find(
            resourceId='com.instagram.android:id/row_hashtag_textview_tag_name',
            className='android.widget.TextView',
            text=f"#{hashtag}")

        sleeper.random_sleep()
        if not hashtag_view.exists():
            print_timeless(COLOR_FAIL + "Cannot find hashtag #" + hashtag +
                           ", abort." + COLOR_ENDC)
            return False

        hashtag_view.click()
        return True

    return False
示例#19
0
    def do_like_actions():
        global is_scrolled_down
        if interaction_strategy.do_like or interaction_strategy.do_comment:
            coordinator_layout = device.find(
                resourceId=f'{device.app_id}:id/coordinator_root_layout')
            if coordinator_layout.exists():
                print("Scroll down to see more photos.")
                coordinator_layout.scroll(DeviceFacade.Direction.BOTTOM)
                is_scrolled_down = True

            number_of_rows_to_use = min(
                (interaction_strategy.likes_count * 2) // 3 + 1, 4)
            photos_indices = list(range(0, number_of_rows_to_use * 3))
            shuffle(photos_indices)
            photos_indices = photos_indices[:interaction_strategy.likes_count]
            photos_indices = sorted(photos_indices)

            def on_like():
                global liked_count
                liked_count += 1
                print(COLOR_OKGREEN +
                      "@{} - photo been liked.".format(username) + COLOR_ENDC)
                on_action(LikeAction(source=user_source, user=username))

            def on_comment(comment):
                global is_commented
                is_commented = True
                print(COLOR_OKGREEN +
                      "@{} - photo been commented.".format(username) +
                      COLOR_ENDC)
                on_action(
                    CommentAction(source=user_source,
                                  user=username,
                                  comment=comment))

            for i in range(0, interaction_strategy.likes_count):
                photo_index = photos_indices[i]
                row = photo_index // 3
                column = photo_index - row * 3

                sleeper.random_sleep()
                print("Open and like photo #" + str(i + 1) + " (" +
                      str(row + 1) + " row, " + str(column + 1) + " column)")
                if not _open_photo_and_like_and_comment(
                        device, row, column, interaction_strategy.do_like,
                        interaction_strategy.do_comment,
                        interaction_strategy.like_percentage, on_like,
                        interaction_strategy.comment_percentage,
                        interaction_strategy.comments_list, my_username,
                        on_comment):
                    print(COLOR_OKGREEN + "Less than " +
                          str(number_of_rows_to_use * 3) + " photos." +
                          COLOR_ENDC)
                    break
def extract_hashtag_profiles_and_interact(device,
                                          hashtag,
                                          instructions,
                                          iteration_callback,
                                          iteration_callback_pre_conditions,
                                          on_action):
    print("Interacting with #{0}-{1}".format(hashtag, instructions.value))

    if not search_for(device, hashtag=hashtag, on_action=on_action):
        return

    # Switch to Recent tab
    if instructions == HashtagInteractionType.RECENT_LIKERS:
        print("Switching to Recent tab")
        tab_layout = device.find(resourceId=f'{device.app_id}:id/tab_layout',
                                 className='android.widget.LinearLayout')
        if tab_layout.exists():
            tab_layout.child(index=1).click()
        else:
            print("Can't Find recent tab. Interacting with Popular.")

    # Sleep longer because posts loading takes time
    sleeper.random_sleep(multiplier=2.0)

    # Open post
    posts_view_list = PostsGridView(device).open_random_post()
    if posts_view_list is None:
        return

    posts_end_detector = ScrollEndDetector(repeats_to_end=2)

    def pre_conditions(liker_username, liker_username_view):
        posts_end_detector.notify_username_iterated(liker_username)
        return iteration_callback_pre_conditions(liker_username, liker_username_view)

    while True:
        if not open_likers(device):
            print(COLOR_OKGREEN + "No likes, let's scroll down." + COLOR_ENDC)
            posts_view_list.scroll_down()
            continue

        print("List of likers is opened.")
        posts_end_detector.notify_new_page()
        sleeper.random_sleep()

        should_continue_using_source = iterate_over_likers(device, iteration_callback, pre_conditions)

        if not should_continue_using_source:
            break

        if posts_end_detector.is_the_end():
            break
        else:
            posts_view_list.scroll_down()
示例#21
0
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
示例#22
0
    def do_like_actions():
        global is_scrolled_down
        if interaction_strategy.do_like or interaction_strategy.do_comment:
            # Close suggestions if they are opened (hack to fix a bug with opening menu while scrolling)
            suggestions_container = device.find(resourceId=f'{device.app_id}:id/similar_accounts_container',
                                                className='android.widget.LinearLayout')
            if suggestions_container.exists(quick=True):
                print("Close suggestions to avoid bugs while scrolling")
                arrow_button = device.find(resourceId=f'{device.app_id}:id/row_profile_header_button_chaining',
                                           className='android.widget.Button')
                arrow_button.click(ignore_if_missing=True)
                sleeper.random_sleep()

            coordinator_layout = device.find(resourceId=f'{device.app_id}:id/coordinator_root_layout')
            if coordinator_layout.exists():
                print("Scroll down to see more photos.")
                coordinator_layout.scroll(DeviceFacade.Direction.BOTTOM)
                is_scrolled_down = True

            number_of_rows_to_use = min((interaction_strategy.likes_count * 2) // 3 + 1, 4)
            photos_indices = list(range(0, number_of_rows_to_use * 3))
            shuffle(photos_indices)
            photos_indices = photos_indices[:interaction_strategy.likes_count]
            photos_indices = sorted(photos_indices)

            def on_like():
                global liked_count
                liked_count += 1
                print(COLOR_OKGREEN + "@{} - photo been liked.".format(username) + COLOR_ENDC)
                on_action(LikeAction(source_name=user_source, source_type=source_type, user=username))

            def on_comment(comment):
                global is_commented
                is_commented = True
                print(COLOR_OKGREEN + "@{} - photo been commented.".format(username) + COLOR_ENDC)
                on_action(CommentAction(source_name=user_source, source_type=source_type, user=username, comment=comment))

            for i in range(0, interaction_strategy.likes_count):
                photo_index = photos_indices[i]
                row = photo_index // 3
                column = photo_index - row * 3

                sleeper.random_sleep()
                print("Open and like photo #" + str(i + 1) + " (" + str(row + 1) + " row, " + str(
                    column + 1) + " column)")
                if not _open_photo_and_like_and_comment(device, row, column,
                                                        interaction_strategy.do_like, interaction_strategy.do_comment,
                                                        interaction_strategy.like_percentage, on_like,
                                                        interaction_strategy.comment_percentage,
                                                        interaction_strategy.comments_list, my_username, on_comment):
                    print(COLOR_OKGREEN + "Less than " + str(number_of_rows_to_use * 3) + " photos." + COLOR_ENDC)
                    break
示例#23
0
def get_my_profile_info(device, username):
    try:
        profile_view = TabBarView(device).navigate_to_profile()
        sleeper.random_sleep()

        ActionBarView.create_instance(device)

        if username is not None:
            if not profile_view.change_to_username(username):
                print(COLOR_FAIL +
                      f"Couldn't switch user to {username}, abort!" +
                      COLOR_ENDC)
                device.back()
                raise UserSwitchFailedException()

        print("Refreshing your profile status...")
        profile_view.refresh()
        sleeper.random_sleep()
        username, followers, following = profile_view.get_profile_info(
            swipe_up_if_needed=True)
    except UserSwitchFailedException as e:
        raise e
    except Exception as e:
        print(COLOR_FAIL + describe_exception(e) + COLOR_ENDC)
        save_crash(device, e)
        switch_to_english(device)

        # Try again on the correct language
        profile_view = TabBarView(device).navigate_to_profile()
        sleeper.random_sleep()

        ActionBarView.create_instance(device)

        if username is not None:
            if not profile_view.change_to_username(username):
                print(COLOR_FAIL +
                      f"Couldn't switch user to {username}, abort!" +
                      COLOR_ENDC)
                device.back()
                raise UserSwitchFailedException()

        print("Refreshing your profile status...")
        profile_view.refresh()
        sleeper.random_sleep()
        username, followers, following = profile_view.get_profile_info(
            swipe_up_if_needed=True)

    report_string = ""
    if username:
        report_string += "Hello, @" + username + "! "
    if followers is not None:
        report_string += "You have " + str(followers) + " followers"
        if following is not None:
            report_string += " and " + str(following) + " followings"
        report_string += " so far."

    if not report_string == "":
        print(report_string)

    return username, followers, following
示例#24
0
def get_my_profile_info(device):
    navigate(device, Tabs.PROFILE)
    sleeper.random_sleep()

    print("Refreshing your profile status...")
    coordinator_layout = device.find(
        resourceId='com.instagram.android:id/coordinator_root_layout')
    if coordinator_layout.exists():
        coordinator_layout.scroll(DeviceFacade.Direction.TOP)

    sleeper.random_sleep()

    update_interaction_rect(device)

    username = None
    title_view = device.find(resourceIdMatches=TITLE_VIEW_ID_REGEX,
                             className='android.widget.TextView')
    if title_view.exists():
        username = title_view.get_text()
    else:
        print(COLOR_FAIL + "Failed to get username" + COLOR_ENDC)
        save_crash(device)

    try:
        followers = _get_followers_count(device)
    except LanguageChangedException:
        # Try again on the correct language
        navigate(device, Tabs.PROFILE)
        followers = _get_followers_count(device)

    try:
        following = get_following_count(device)
    except LanguageChangedException:
        # Try again on the correct language
        navigate(device, Tabs.PROFILE)
        following = get_following_count(device)

    report_string = ""
    if username:
        report_string += "Hello, @" + username + "! "
    if followers is not None:
        report_string += "You have " + str(followers) + " followers"
        if following is not None:
            report_string += " and " + str(following) + " followings"
        report_string += " so far."

    if not report_string == "":
        print(report_string)

    return username, followers, following
示例#25
0
def extract_place_likers_and_interact(device, place, instructions,
                                      navigate_to_feed, iteration_callback,
                                      iteration_callback_pre_conditions,
                                      on_action):
    print("Interacting with place-{0}-{1}".format(place, instructions.value))

    # Open post
    posts_view_list = navigate_to_feed()
    if posts_view_list is None:
        return

    posts_end_detector = ScrollEndDetector(repeats_to_end=2)

    def pre_conditions(liker_username, liker_username_view):
        posts_end_detector.notify_username_iterated(liker_username)
        return iteration_callback_pre_conditions(liker_username,
                                                 liker_username_view)

    no_likes_count = 0

    while True:
        if not open_likers(device):
            no_likes_count += 1
            print(COLOR_OKGREEN + "No likes, let's scroll down." + COLOR_ENDC)
            posts_view_list.scroll_down()
            if no_likes_count == 10:
                print(
                    COLOR_FAIL +
                    "Seen this message too many times. Lets restart the job." +
                    COLOR_ENDC)
                raise RestartJobRequiredException

            continue

        no_likes_count = 0
        print("List of likers is opened.")
        posts_end_detector.notify_new_page()
        sleeper.random_sleep()

        should_continue_using_source = iterate_over_likers(
            device, iteration_callback, pre_conditions)

        if not should_continue_using_source:
            break

        if posts_end_detector.is_the_end():
            break
        else:
            posts_view_list.scroll_down()
示例#26
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
示例#27
0
def _comment(device, my_username, comments_list, on_comment):
    comment_button = device.find(resourceId=f'{device.app_id}:id/row_feed_button_comment',
                                 className="android.widget.ImageView")
    if not comment_button.exists(quick=True) or not ActionBarView.is_in_interaction_rect(comment_button):
        print("Cannot find comment button – will try to swipe down a bit")
        device.swipe(DeviceFacade.Direction.TOP)
    if not comment_button.exists(quick=True):
        print("Still cannot find comment button – won't comment")
        return

    comment_box_exists = False
    comment_box = None

    for _ in range(2):
        print("Open comments of post")
        comment_button.click()
        sleeper.random_sleep()

        comment_box = device.find(resourceId=f'{device.app_id}:id/layout_comment_thread_edittext')
        if comment_box.exists(quick=True):
            if not comment_box.is_enabled():
                print("Comments are restricted – not commenting...")
                device.back()
                return
            comment_box_exists = True
            break

    if not comment_box_exists:
        print("Couldn't open comments properly - not commenting...")
        return

    comment = spin(choice(comments_list))
    print(f"Commenting: {comment}")

    comment_box.set_text(comment)
    sleeper.random_sleep()

    post_button = device.find(resourceId=f'{device.app_id}:id/layout_comment_thread_post_button_click_area')
    post_button.click()

    sleeper.random_sleep()
    softban_indicator.detect_action_blocked_dialog(device)

    device.close_keyboard()

    just_post = device.find(
        resourceId=f'{device.app_id}:id/row_comment_textview_comment',
        text=f"{my_username} {comment}",
    )

    if just_post.exists(True):
        print("Comment succeed.")
        on_comment(comment)
    else:
        print(COLOR_FAIL + "Failed to check if comment succeed." + COLOR_ENDC)

    sleeper.random_sleep()
    print("Go back to post view.")
    device.back()
示例#28
0
    def start_session(self, args, device_wrapper, app_version):
        self.session_state = SessionState()
        self.session_state.args = args.__dict__
        self.session_state.app_version = app_version
        self.sessions.append(self.session_state)

        print_timeless(COLOR_REPORT + "\n-------- START: " +
                       str(self.session_state.startTime) + " --------" +
                       COLOR_ENDC)
        open_instagram(args.device)
        sleeper.random_sleep()
        self.session_state.my_username, \
            self.session_state.my_followers_count, \
            self.session_state.my_following_count = get_my_profile_info(device_wrapper.get())

        return self.session_state
示例#29
0
def _comment(device, my_username, comments_list, on_comment):
    comment_button = device.find(
        resourceId=f'{device.app_id}:id/row_feed_button_comment',
        className="android.widget.ImageView",
    )
    if not comment_button.exists(quick=True):
        print("Couldn't find comment button - not commenting...")

    comment_box_exists = False
    comment_box = None

    for _ in range(2):
        print("Open comments of post")
        comment_button.click()
        sleeper.random_sleep()

        comment_box = device.find(
            resourceId=f'{device.app_id}:id/layout_comment_thread_edittext')
        if comment_box.exists(quick=True):
            comment_box_exists = True
            break

    if not comment_box_exists:
        print("Couldn't open comments properly - not commenting...")
        return

    comment = choice(comments_list)
    print(f"Commenting: {comment}")

    comment_box.set_text(comment)
    sleeper.random_sleep()

    post_button = device.find(
        resourceId=
        f'{device.app_id}:id/layout_comment_thread_post_button_click_area')
    post_button.click()

    sleeper.random_sleep()
    softban_indicator.detect_action_blocked_dialog(device)

    device.close_keyboard()

    just_post = device.find(
        resourceId=f'{device.app_id}:id/row_comment_textview_comment',
        text=f"{my_username} {comment}",
    )

    if just_post.exists(True):
        print("Comment succeed.")
        on_comment(comment)
    else:
        print("Failed to check if comment succeed.")

    sleeper.random_sleep()
    print("Go back to post view.")
    device.back()
示例#30
0
def _close_confirm_dialog_if_shown(device):
    dialog_root_view = device.find(resourceId=f'{device.app_id}:id/dialog_root_view',
                                   className='android.widget.FrameLayout')
    if not dialog_root_view.exists():
        return

    # Avatar existence is the way to distinguish confirm dialog from block dialog
    user_avatar_view = device.find(resourceIdMatches=USER_AVATAR_VIEW_ID.format(device.app_id),
                                   className='android.widget.ImageView')
    if not user_avatar_view.exists():
        return

    print(COLOR_OKGREEN + "Dialog shown, confirm unfollowing." + COLOR_ENDC)
    sleeper.random_sleep()
    unfollow_button = dialog_root_view.child(resourceId=f'{device.app_id}:id/primary_button',
                                             className='android.widget.TextView')
    unfollow_button.click()