Esempio n. 1
0
    def handle_blogger(
        self,
        device,
        username,
        likes_count,
        stories_count,
        stories_percentage,
        follow_percentage,
        follow_limit,
        storage,
        profile_filter,
        on_like,
        on_watch,
        on_interaction,
    ):
        is_myself = username == self.session_state.my_username
        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=username,
            session_state=self.session_state,
        )

        if not self.open_user_followers(device, username):
            return
        if is_myself:
            self.scroll_to_bottom(device)
        self.iterate_over_followers(
            device,
            interaction,
            is_follow_limit_reached,
            storage,
            on_interaction,
            is_myself,
            skipped_list_limit=get_value(self.args.skipped_list_limit, None,
                                         15),
            skipped_fling_limit=get_value(self.args.fling_when_skipped, None,
                                          0),
        )
    def run(self, device, device_id, args, enabled, storage, sessions, plugin):
        class State:
            def __init__(self):
                pass

            unfollowed_count = 0
            is_job_completed = False

        self.device_id = device_id
        self.state = State()
        self.session_state = sessions[-1]
        self.sessions = sessions
        self.unfollow_type = plugin[2:]

        count_arg = get_value(
            getattr(args, self.unfollow_type.replace("-", "_")),
            "Unfollow count: {}",
            10,
        )

        count = min(
            count_arg,
            self.session_state.my_following_count - int(args.min_following),
        )

        if self.unfollow_type == "unfollow":
            self.unfollow_type = UnfollowRestriction.FOLLOWED_BY_SCRIPT
        elif self.unfollow_type == "unfollow-non-followers":
            self.unfollow_type = UnfollowRestriction.FOLLOWED_BY_SCRIPT_NON_FOLLOWERS
        else:
            self.unfollow_type = UnfollowRestriction.ANY

        if count <= 0:
            logger.info("You want to unfollow " + str(count) + ", you have " +
                        str(self.session_state.my_following_count) +
                        " followings, min following is " +
                        str(args.min_following) + ". Finish.")
            return

        @run_safely(
            device=device,
            device_id=self.device_id,
            sessions=self.sessions,
            session_state=self.session_state,
        )
        def job():
            self.unfollow(
                device,
                count - self.state.unfollowed_count,
                self.on_unfollow,
                storage,
                self.unfollow_type,
                self.session_state.my_username,
            )
            logger.info(f"Unfollowed {self.state.unfollowed_count}, finish.")
            self.state.is_job_completed = True

        while not self.state.is_job_completed and (self.state.unfollowed_count
                                                   < count):
            job()
    def run(self, device, device_id, args, enabled, storage, sessions):
        class State:
            def __init__(self):
                pass

            is_job_completed = False
            is_likes_limit_reached = False

        self.device_id = device_id
        self.state = None
        self.sessions = sessions
        self.session_state = sessions[-1]
        profile_filter = Filter()

        # IMPORTANT: in each job we assume being on the top of the Profile tab already
        sources = [source for source in args.blogger_followers]
        shuffle(sources)

        for source in sources:
            self.state = State()
            is_myself = source[1:] == self.session_state.my_username
            its_you = is_myself and " (it's you)" or ""
            logger.info(f"Handle {source} {its_you}")

            on_likes_limit_reached = partial(_on_likes_limit_reached, state=self.state)

            on_interaction = partial(
                _on_interaction,
                on_likes_limit_reached=on_likes_limit_reached,
                likes_limit=int(args.total_likes_limit),
                source=source,
                interactions_limit=get_value(
                    args.interactions_count, "Interactions count: {}", 70
                ),
                sessions=self.sessions,
                session_state=self.session_state,
            )

            on_like = partial(
                _on_like, sessions=self.sessions, session_state=self.session_state
            )

            @run_safely(
                device=device,
                device_id=self.device_id,
                sessions=self.sessions,
                session_state=self.session_state,
            )
            def job():
                self.handle_blogger(
                    device,
                    source[1:] if "@" in source else source,
                    args.likes_count,
                    int(args.follow_percentage),
                    int(args.follow_limit) if args.follow_limit else None,
                    storage,
                    profile_filter,
                    on_like,
                    on_interaction,
                )
                self.state.is_job_completed = True

            while (
                not self.state.is_job_completed
                and not self.state.is_likes_limit_reached
            ):
                job()

            if self.state.is_likes_limit_reached:
                break
    def run(self, device, device_id, args, enabled, storage, sessions):
        class State:
            def __init__(self):
                pass

            is_job_completed = False
            is_likes_limit_reached = False

        self.device_id = device_id
        self.sessions = sessions
        self.session_state = sessions[-1]
        profile_filter = Filter()

        # IMPORTANT: in each job we assume being on the top of the Profile tab already
        sources = [source for source in args.hashtag_likers]
        shuffle(sources)

        for source in sources:
            self.state = State()
            logger.info(f"Handle {source}", extra={"color": f"{Style.BRIGHT}"})

            on_likes_limit_reached = partial(_on_likes_limit_reached, state=self.state)

            on_interaction = partial(
                _on_interaction,
                on_likes_limit_reached=on_likes_limit_reached,
                likes_limit=int(args.total_likes_limit),
                source=source,
                interactions_limit=get_value(
                    args.interactions_count, "Interactions count: {}", 70
                ),
                sessions=self.sessions,
                session_state=self.session_state,
            )

            on_like = partial(
                _on_like, sessions=self.sessions, session_state=self.session_state
            )

            @run_safely(
                device=device,
                device_id=self.device_id,
                sessions=self.sessions,
                session_state=self.session_state,
            )
            def job():
                self.handle_hashtag(
                    device,
                    source[1:] if "#" in source else source,
                    args.likes_count,
                    int(args.follow_percentage),
                    int(args.follow_limit) if args.follow_limit else None,
                    storage,
                    profile_filter,
                    on_like,
                    on_interaction,
                )
                self.state.is_job_completed = True

            while (
                not self.state.is_job_completed
                and not self.state.is_likes_limit_reached
            ):
                job()

            if self.state.is_likes_limit_reached:
                break
Esempio n. 5
0
def _watch_stories(
    device,
    profile_view,
    username,
    stories_to_watch,
    stories_percentage,
    on_watch,
    args,
    session_state,
):
    if not session_state.check_limit(
            args, limit_type=session_state.Limit.WATCHES, output=False):
        story_chance = randint(1, 100)
        if story_chance > stories_percentage:
            return False

        stories_to_watch = get_value(stories_to_watch, "Stories count: {}", 0)

        if stories_to_watch > 6:
            logger.error("Max number of stories per user is 6")
            stories_to_watch = 6

        if stories_to_watch == 0:
            return False

        if profile_view.isStoryAvailable():
            profile_picture = profile_view.profileImage()
            if profile_picture.exists():
                profile_picture.click()  # Open the first story
                on_watch()
                random_sleep()

                if stories_to_watch > 1:
                    story_view = CurrentStoryView(device)
                    for _iter in range(0, stories_to_watch - 1):
                        if story_view.getUsername() == username:
                            try:
                                story_frame = story_view.getStoryFrame()
                                if (story_frame.exists()
                                        and _iter <= stories_to_watch - 1):
                                    story_frame.click(
                                        story_view.Location.RIGHT)
                                    on_watch()
                                    random_sleep()
                            except Exception:
                                break
                        else:
                            break

                for attempt in range(0, 4):
                    if profile_view.getUsername(error=False) != username:
                        if attempt != 0:
                            device.back()
                        # Maybe it's just an error please one half seconds before search again for username tab
                        # This little delay prevent too much back tap and to see more stories than stories_to_watch value
                        random_sleep()
                    else:
                        break
                return True
        return False
    else:
        logger.info("Reached total watch limit, not watching stories.")
        return False
Esempio n. 6
0
def interact_with_user(
    device,
    username,
    my_username,
    likes_count,
    on_like,
    stories_count,
    stories_percentage,
    on_watch,
    can_follow,
    follow_percentage,
    profile_filter,
    args,
    session_state,
) -> Tuple[bool, bool]:
    """
    :return: (whether interaction succeed, whether @username was followed during the interaction)
    """
    if username == my_username:
        logger.info("It's you, skip.")
        return False, False

    random_sleep()

    if not profile_filter.check_profile(device, username):
        return False, False

    likes_value = get_value(likes_count, "Likes count: {}", 2)
    if likes_value > 12:
        logger.error("Max number of likes per user is 12.")
        likes_value = 12

    profile_view = ProfileView(device)
    is_private = profile_view.isPrivateAccount()
    posts_count = profile_view.getPostsCount()
    is_empty = posts_count == 0

    if is_private or is_empty:
        private_empty = "Private" if is_private else "Empty"
        logger.info(f"{private_empty} account.",
                    extra={"color": f"{Fore.GREEN}"})
        if can_follow and profile_filter.can_follow_private_or_empty():
            followed = _follow(device, username, follow_percentage, args,
                               session_state)
        else:
            followed = False
            logger.info("Skip user.", extra={"color": f"{Fore.GREEN}"})
        return False, followed

    _watch_stories(
        device,
        profile_view,
        username,
        stories_count,
        stories_percentage,
        on_watch,
        args,
        session_state,
    )

    ProfileView(device).swipe_to_fit_posts()
    random_sleep()
    start_time = time()
    full_rows, columns_last_row = profile_view.count_photo_in_view()
    end_time = format(time() - start_time, ".2f")
    photos_indices = list(range(0, full_rows * 3 + (columns_last_row)))
    logger.info(
        f"There are {len(photos_indices)} posts fully visible. Calculated in {end_time}s"
    )
    if likes_value > len(photos_indices):
        logger.info(f"Only {photos_indices} photos available")
    else:
        shuffle(photos_indices)
        photos_indices = photos_indices[:likes_value]
        photos_indices = sorted(photos_indices)
    for i in range(0, len(photos_indices)):
        photo_index = photos_indices[i]
        row = photo_index // 3
        column = photo_index - row * 3
        logger.info(f"Open post #{i + 1} ({row + 1} row, {column + 1} column)")
        opened_post_view = PostsGridView(device).navigateToPost(row, column)
        random_sleep()

        like_succeed = False
        if opened_post_view:
            logger.info("Double click post.")

            like_succeed = opened_post_view.likePost()
            if not like_succeed:
                logger.debug("Double click failed. Try the like button.")
                like_succeed = opened_post_view.likePost(click_btn_like=True)

            if like_succeed:
                logger.debug("Like succeed. Check for block.")
                detect_block(device)
                on_like()
            else:
                logger.warning("Fail to like post. Let's continue...")

            logger.info("Back to profile.")
            device.back()

        if not opened_post_view or not like_succeed:
            reason = "open" if not opened_post_view else "like"
            logger.info(
                f"Could not {reason} photo. Posts count: {posts_count}")

            if can_follow and profile_filter.can_follow_private_or_empty():
                followed = _follow(device, username, follow_percentage, args,
                                   session_state)
            else:
                followed = False

            if not followed:
                logger.info("Skip user.", extra={"color": f"{Fore.GREEN}"})
            return False, followed

        random_sleep()
    if can_follow:
        return True, _follow(device, username, follow_percentage, args,
                             session_state)

    return True, False
Esempio n. 7
0
    def run(self, device, configs, storage, sessions, plugin):
        class State:
            def __init__(self):
                pass

            is_job_completed = False

        self.device_id = configs.args.device
        self.sessions = sessions
        self.session_state = sessions[-1]
        self.args = configs.args
        profile_filter = Filter()
        self.current_mode = plugin

        # IMPORTANT: in each job we assume being on the top of the Profile tab already
        sources = [
            source
            for source in (
                self.args.hashtag_likers_top
                if self.current_mode == "hashtag-likers-top"
                else self.args.hashtag_likers_recent
            )
        ]
        shuffle(sources)

        for source in sources:
            limit_reached = self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.LIKES
            ) and self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.FOLLOWS
            )

            self.state = State()
            if source[0] != "#":
                source = "#" + source
            logger.info(f"Handle {source}", extra={"color": f"{Style.BRIGHT}"})

            on_interaction = partial(
                _on_interaction,
                likes_limit=int(self.args.total_likes_limit),
                source=source,
                interactions_limit=get_value(
                    self.args.interactions_count, "Interactions count: {}", 70
                ),
                sessions=self.sessions,
                session_state=self.session_state,
                args=self.args,
            )

            on_like = partial(
                _on_like, sessions=self.sessions, session_state=self.session_state
            )

            on_watch = partial(
                _on_watch, sessions=self.sessions, session_state=self.session_state
            )

            if self.args.stories_count != "0":
                stories_percentage = get_value(
                    self.args.stories_percentage, "Chance of watching stories: {}%", 40
                )
            else:
                stories_percentage = 0

            @run_safely(
                device=device,
                device_id=self.device_id,
                sessions=self.sessions,
                session_state=self.session_state,
            )
            def job():
                self.handle_hashtag(
                    device,
                    source,
                    self.args.likes_count,
                    self.args.stories_count,
                    stories_percentage,
                    int(self.args.follow_percentage),
                    int(self.args.follow_limit) if self.args.follow_limit else None,
                    plugin,
                    storage,
                    profile_filter,
                    on_like,
                    on_watch,
                    on_interaction,
                )
                self.state.is_job_completed = True

            while not self.state.is_job_completed and not limit_reached:
                job()

            if limit_reached:
                logger.info("Likes and follows limit reached.")
                self.session_state.check_limit(
                    self.args, limit_type=self.session_state.Limit.ALL, output=True
                )
                break
Esempio n. 8
0
    def handle_hashtag(
        self,
        device,
        hashtag,
        likes_count,
        stories_count,
        stories_percentage,
        follow_percentage,
        follow_limit,
        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-likers-recent":
            logger.info("Switching to Recent tab")
            HashTagView(device)._getRecentTab().click()
            random_sleep(5, 10)
            if HashTagView(device)._check_if_no_posts():
                HashTagView(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()

        skipped_list_limit = get_value(self.args.skipped_list_limit, None, 15)
        skipped_fling_limit = get_value(self.args.fling_when_skipped, None, 0)

        posts_end_detector = ScrollEndDetector(
            repeats_to_end=2,
            skipped_list_limit=skipped_list_limit,
            skipped_fling_limit=skipped_fling_limit,
        )

        post_description = ""
        nr_same_post = 0
        nr_same_posts_max = 3
        while True:
            likers_container_exists = PostsViewList(device)._find_likers_container()
            has_one_liker_or_none = PostsViewList(
                device
            )._check_if_only_one_liker_or_none()

            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 likers_container_exists and not has_one_liker_or_none:
                PostsViewList(device).open_likers_container()
            else:
                PostsViewList(device).swipe_to_fit_posts(SwipeTo.NEXT_POST)
                continue

            posts_end_detector.notify_new_page()
            random_sleep()

            likes_list_view = OpenedPostView(device)._getListViewLikers()
            prev_screen_iterated_likers = []
            while True:
                logger.info("Iterate over visible likers.")
                screen_iterated_likers = []
                opened = False

                try:
                    for item in OpenedPostView(device)._getUserCountainer():
                        username_view = OpenedPostView(device)._getUserName(item)
                        if not username_view.exists(quick=True):
                            logger.info(
                                "Next item not found: probably reached end of the screen.",
                                extra={"color": f"{Fore.GREEN}"},
                            )
                            break

                        username = username_view.get_text()
                        profile_interact = profile_filter.check_profile_from_list(
                            device, item, username
                        )
                        screen_iterated_likers.append(username)
                        posts_end_detector.notify_username_iterated(username)
                        if not profile_interact:
                            continue
                        elif storage.is_user_in_blacklist(username):
                            logger.info(f"@{username} is in blacklist. Skip.")
                            continue
                        elif storage.check_user_was_interacted(username):
                            logger.info(f"@{username}: already interacted. Skip.")
                            continue
                        else:
                            logger.info(f"@{username}: interact")
                            username_view.click()

                        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)
                        opened = True
                        can_continue = on_interaction(
                            succeed=interaction_succeed, followed=followed
                        )
                        if not can_continue:
                            return

                        logger.info("Back to likers list.")
                        device.back()
                        random_sleep()
                except IndexError:
                    logger.info(
                        "Cannot get next item: probably reached end of the screen.",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    break

                go_back = False
                if not opened:
                    logger.info(
                        "All likers skipped.",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    posts_end_detector.notify_skipped_all()
                    if posts_end_detector.is_skipped_limit_reached():
                        posts_end_detector.reset_skipped_all()
                        device.back()
                        PostsViewList(device).swipe_to_fit_posts(False)
                        break
                if screen_iterated_likers == prev_screen_iterated_likers:
                    logger.info(
                        "Iterated exactly the same likers twice.",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    go_back = True
                if go_back:
                    prev_screen_iterated_likers.clear()
                    prev_screen_iterated_likers += screen_iterated_likers
                    logger.info(
                        f"Back to {hashtag}'s posts list.",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    device.back()
                    logger.info("Going to the next post.")
                    PostsViewList(device).swipe_to_fit_posts(SwipeTo.NEXT_POST)
                    break
                if posts_end_detector.is_fling_limit_reached():
                    prev_screen_iterated_likers.clear()
                    prev_screen_iterated_likers += screen_iterated_likers
                    logger.info(
                        "Reached fling limit. Fling to see other likers",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    likes_list_view.fling(DeviceFacade.Direction.BOTTOM)
                else:
                    prev_screen_iterated_likers.clear()
                    prev_screen_iterated_likers += screen_iterated_likers
                    logger.info(
                        "Scroll to see other likers",
                        extra={"color": f"{Fore.GREEN}"},
                    )
                    likes_list_view.scroll(DeviceFacade.Direction.BOTTOM)

                if posts_end_detector.is_the_end():
                    break
Esempio n. 9
0
    def run(self, device, configs, storage, sessions, plugin):
        class State:
            def __init__(self):
                pass

            is_job_completed = False

        self.device_id = configs.args.device
        self.state = None
        self.sessions = sessions
        self.session_state = sessions[-1]
        self.args = configs.args
        self.ResourceID = resources(self.args.app_id)
        profile_filter = Filter()
        self.current_mode = plugin

        # IMPORTANT: in each job we assume being on the top of the Profile tab already
        sources = [source for source in self.args.blogger_followers]
        shuffle(sources)

        for source in sources:
            limit_reached = self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.LIKES
            ) and self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.FOLLOWS)

            self.state = State()
            is_myself = source[1:] == self.session_state.my_username
            its_you = is_myself and " (it's you)" or ""
            logger.info(f"Handle {source} {its_you}")

            on_interaction = partial(
                _on_interaction,
                likes_limit=int(self.args.total_likes_limit),
                source=source,
                interactions_limit=get_value(self.args.interactions_count,
                                             "Interactions count: {}", 70),
                sessions=self.sessions,
                session_state=self.session_state,
                args=self.args,
            )

            on_like = partial(_on_like,
                              sessions=self.sessions,
                              session_state=self.session_state)

            on_watch = partial(_on_watch,
                               sessions=self.sessions,
                               session_state=self.session_state)

            if self.args.stories_count != "0":
                stories_percentage = get_value(
                    self.args.stories_percentage,
                    "Chance of watching stories: {}%", 40)
            else:
                stories_percentage = 0

            @run_safely(
                device=device,
                device_id=self.device_id,
                sessions=self.sessions,
                session_state=self.session_state,
                screen_record=self.args.screen_record,
            )
            def job():
                self.handle_blogger(
                    device,
                    source[1:] if "@" in source else source,
                    self.args.likes_count,
                    self.args.stories_count,
                    stories_percentage,
                    int(self.args.follow_percentage),
                    int(self.args.follow_limit)
                    if self.args.follow_limit else None,
                    storage,
                    profile_filter,
                    on_like,
                    on_watch,
                    on_interaction,
                )
                self.state.is_job_completed = True

            while not self.state.is_job_completed and not limit_reached:
                job()

            if limit_reached:
                logger.info("Likes and follows limit reached.")
                self.session_state.check_limit(
                    self.args,
                    limit_type=self.session_state.Limit.ALL,
                    output=True)
                break
Esempio n. 10
0
def run():
    global device_id
    global first_run
    loaded = load_plugins()
    args = get_args()
    enabled = []
    if not args:
        return
    dargs = vars(args)

    for k in loaded:
        if dargs[k.replace("-", "_")[2:]] != None:
            if k == "--interact":
                logger.warn(
                    'Using legacy argument "--interact". Please switch to new arguments as this will be deprecated in the near future.'
                )
                if "#" in args.interact[0]:
                    enabled.append("--hashtag-likers")
                    args.hashtag_likers = args.interact
                else:
                    enabled.append("--blogger-followers")
                    args.blogger_followers = args.interact
            else:
                enabled.append(k)
    enabled = list(dict.fromkeys(enabled))

    if len(enabled) < 1:
        logger.error("You have to specify one of the actions: " + ", ".join(loaded))
        return
    if len(enabled) > 1:
        logger.error(
            "Running GramAddict with two or more actions is not supported yet."
        )
        return

    device_id = args.device
    if not check_adb_connection(is_device_id_provided=(device_id is not None)):
        return
    logger.info("Instagram version: " + get_instagram_version(device_id))
    device = create_device(device_id)

    if device is None:
        return

    while True:
        session_state = SessionState()
        session_state.args = args.__dict__
        sessions.append(session_state)

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.screen_sleep:
            screen_sleep(device_id, "on")  # Turn on the device screen

        open_instagram(device_id)

        try:
            profileView = TabBarView(device).navigateToProfile()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (
            session_state.my_username == None
            or session_state.my_followers_count == None
            or session_state.my_following_count == None
        ):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)
        if first_run:
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)

        loaded[enabled[0]].run(device, device_id, args, enabled, storage, sessions)

        close_instagram(device_id)
        session_state.finishTime = datetime.now()

        if args.screen_sleep:
            screen_sleep(device_id, "off")  # Turn off the device screen

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.repeat:
            print_full_report(sessions)
            repeat = get_value(args.repeat, "Sleep for {} minutes", 180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                sys.exit(0)
        else:
            break

        first_run = False

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)
Esempio n. 11
0
def interact_with_user(
    device,
    username,
    my_username,
    likes_count,
    on_like,
    can_follow,
    follow_percentage,
    profile_filter,
) -> Tuple[bool, bool]:
    """
    :return: (whether interaction succeed, whether @username was followed during the interaction)
    """
    if username == my_username:
        logger.info("It's you, skip.")
        return False, False

    random_sleep()

    if not profile_filter.check_profile(device, username):
        return False, False

    likes_value = get_value(likes_count, "Likes count: {}", 2)
    if likes_value > 12:
        logger.error("Max number of likes per user is 12")
        likes_value = 12

    profile_view = ProfileView(device)
    is_private = profile_view.isPrivateAccount()
    posts_count = profile_view.getPostsCount()
    is_empty = posts_count == 0

    if is_private or is_empty:
        private_empty = "Private" if is_private else "Empty"
        logger.info(
            f"{private_empty} account.",
            extra={"color": f"{Fore.GREEN}"},
        )
        if can_follow and profile_filter.can_follow_private_or_empty():
            followed = _follow(device, username, follow_percentage)
        else:
            followed = False
            logger.info(
                "Skip user.",
                extra={"color": f"{Fore.GREEN}"},
            )
        return False, followed

    posts_tab_view = profile_view.navigateToPostsTab()
    if posts_tab_view.scrollDown():  # scroll down to view all maximum 12 posts
        logger.info("Scrolled down to see more posts.")
    random_sleep()
    number_of_rows_to_use = min((likes_value * 2) // 3 + 1, 4)
    photos_indices = list(range(0, number_of_rows_to_use * 3))
    shuffle(photos_indices)
    photos_indices = photos_indices[:likes_value]
    photos_indices = sorted(photos_indices)
    for i in range(0, likes_value):
        photo_index = photos_indices[i]
        row = photo_index // 3
        column = photo_index - row * 3
        logger.info(f"Open post #{i + 1} ({row + 1} row, {column + 1} column")
        opened_post_view = posts_tab_view.navigateToPost(row, column)
        random_sleep()

        like_succeed = False
        if opened_post_view:
            logger.info("Double click post")
            opened_post_view.likePost()
            random_sleep()
            if not opened_post_view.isPostLiked():
                logger.debug("Double click failed. Try the like button.")
                opened_post_view.likePost(click_btn_like=True)
                random_sleep()

            like_succeed = opened_post_view.isPostLiked()
            if like_succeed:
                detect_block(device)
                on_like()

            logger.info("Back to profile")
            device.back()

        if not opened_post_view or not like_succeed:
            reason = "open" if not opened_post_view else "like"
            logger.info(
                f"Could not {reason} photo. Posts count: {posts_count}")

            if can_follow and profile_filter.can_follow_private_or_empty():
                followed = _follow(device, username, follow_percentage)
            else:
                followed = False

            if not followed:
                logger.info(
                    "Skip user.",
                    extra={"color": f"{Fore.GREEN}"},
                )
            return False, followed

        random_sleep()

    if can_follow:
        return True, _follow(device, username, follow_percentage)

    return True, False
Esempio n. 12
0
def run():
    # Some plugins need config values without being passed
    # through. Because we do a weird config/argparse hybrid,
    # we need to load the configs in a weird way
    load_filter(configs)
    load_interaction(configs)
    load_utils(configs)
    load_views(configs)

    if not configs.args or not check_adb_connection():
        return

    if len(configs.enabled) < 1:
        logger.error("You have to specify one of the actions: " +
                     ", ".join(configs.actions))
        return

    logger.info("Instagram version: " + get_instagram_version())
    device = create_device(configs.device_id, configs.args.uia_version)

    if device is None:
        return

    while True:
        session_state = SessionState(configs)
        sessions.append(session_state)

        device.wake_up()

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if not device.get_info()["screenOn"]:
            device.press_power()
        if device.is_screen_locked():
            device.unlock()
            if device.is_screen_locked():
                logger.error(
                    "Can't unlock your screen. There may be a passcode on it. If you would like your screen to be turned on and unlocked automatically, please remove the passcode."
                )
                exit(0)

        logger.info("Device screen on and unlocked.")

        open_instagram(device, configs.args.screen_record)

        try:
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            if configs.args.username is not None:
                success = AccountView(device).changeToUsername(
                    configs.args.username)
                if not success:
                    logger.error(
                        f"Not able to change to {configs.args.username}, abort!"
                    )
                    device.back()
                    break

            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (session_state.my_username is None
                or session_state.my_followers_count is None
                or session_state.my_following_count is None):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)

        if not is_log_file_updated():
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)
        for plugin in configs.enabled:
            if not session_state.check_limit(
                    configs.args, limit_type=session_state.Limit.ALL,
                    output=False):
                logger.info(f"Current job: {plugin}",
                            extra={"color": f"{Fore.BLUE}"})
                if ProfileView(
                        device).getUsername() != session_state.my_username:
                    logger.debug("Not in your main profile.")
                    TabBarView(device).navigateToProfile()
                configs.actions[plugin].run(device, configs, storage, sessions,
                                            plugin)

            else:
                logger.info(
                    "Successful or Total Interactions limit reached. Ending session."
                )
                break

        close_instagram(device, configs.args.screen_record)
        session_state.finishTime = datetime.now()

        if configs.args.screen_sleep:
            device.screen_off()
            logger.info("Screen turned off for sleeping time")

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if configs.args.repeat:
            print_full_report(sessions)
            repeat = get_value(configs.args.repeat, "Sleep for {} minutes",
                               180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                exit(0)
        else:
            break

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)
Esempio n. 13
0
    def check_limit(self, args, limit_type=None, output=False):
        """Returns True if limit reached - else False"""
        limit_type = SessionState.Limit.ALL if limit_type is None else limit_type
        likes_limit = get_value(args.total_likes_limit, None, 300)
        total_likes = self.totalLikes >= int(likes_limit)
        follow_limit = get_value(args.total_follows_limit, None, 50)
        total_followed = sum(self.totalFollowed.values()) >= int(follow_limit)
        watch_limit = get_value(args.total_watches_limit, None, 50)
        total_watched = self.totalWatched >= int(watch_limit)
        success_limit = get_value(args.total_successful_interactions_limit,
                                  None, 100)
        total_successful = sum(
            self.successfulInteractions.values()) >= int(success_limit)
        total_limit = get_value(args.total_interactions_limit, None, 1000)
        total_interactions = sum(
            self.totalInteractions.values()) >= int(total_limit)

        session_info = [
            "Checking session limits:",
            f"- Total Likes:\t\t\t\t{'Limit Reached' if total_likes else 'OK'} ({self.totalLikes}/{likes_limit})",
            f"- Total Followed:\t\t\t\t{'Limit Reached' if total_followed else 'OK'} ({sum(self.totalFollowed.values())}/{follow_limit})",
            f"- Total Watched:\t\t\t\t{'Limit Reached' if total_watched else 'OK'} ({self.totalWatched}/{watch_limit})",
            f"- Total Successful Interactions:\t\t{'Limit Reached' if total_successful else 'OK'} ({sum(self.successfulInteractions.values())}/{success_limit})",
            f"- Total Interactions:\t\t\t{'Limit Reached' if total_interactions else 'OK'} ({sum(self.totalInteractions.values())}/{total_limit})",
        ]

        if limit_type == SessionState.Limit.ALL:
            if output:
                for line in session_info:
                    logger.info(line)
            else:
                for line in session_info:
                    logger.debug(line)

            return (total_likes and total_followed) or (total_interactions
                                                        or total_successful)

        elif limit_type == SessionState.Limit.LIKES:
            if output:
                logger.info(session_info[1])
            else:
                logger.debug(session_info[1])
            return total_likes or (total_interactions or total_successful)

        elif limit_type == SessionState.Limit.FOLLOWS:
            if output:
                logger.info(session_info[2])
            else:
                logger.debug(session_info[2])
            return total_followed or (total_interactions or total_successful)

        elif limit_type == SessionState.Limit.WATCHES:
            if output:
                logger.info(session_info[3])
            else:
                logger.debug(session_info[3])
            return total_watched or (total_interactions or total_successful)

        elif limit_type == SessionState.Limit.SUCCESS:
            if output:
                logger.info(session_info[4])
            else:
                logger.debug(session_info[4])
            return total_successful or total_interactions

        elif limit_type == SessionState.Limit.TOTAL:
            if output:
                logger.info(session_info[5])
            else:
                logger.debug(session_info[5])
            return total_interactions or total_successful
Esempio n. 14
0
def run():
    global device_id
    loaded = load_plugins()
    args = get_args()
    enabled = []
    if not args:
        return
    dargs = vars(args)

    for item in sys.argv[1:]:
        if item in loaded:
            if item != "--interact" and item != "--hashtag-likers":
                enabled.append(item)

    for k in loaded:
        if dargs[k.replace("-", "_")[2:]] != None:
            if k == "--interact":
                logger.warn(
                    'Using legacy argument "--interact". Please switch to new arguments as this will be deprecated in the near future.'
                )
                for source in args.interact:
                    if "@" in source:
                        enabled.append("--blogger-followers")
                        if type(args.blogger_followers) != list:
                            args.blogger_followers = [source]
                        else:
                            args.blogger_followers.append(source)
                    else:
                        enabled.append("--hashtag-likers-top")
                        if type(args.hashtag_likers_top) != list:
                            args.hashtag_likers_top = [source]
                        else:
                            args.hashtag_likers_top.append(source)
            elif k == "--hashtag-likers":
                logger.warn(
                    'Using legacy argument "--hashtag-likers". Please switch to new arguments as this will be deprecated in the near future.'
                )
                for source in args.hashtag_likers:
                    enabled.append("--hashtag-likers-top")
                    if type(args.hashtag_likers_top) != list:
                        args.hashtag_likers_top = [source]
                    else:
                        args.hashtag_likers_top.append(source)

    enabled = list(dict.fromkeys(enabled))

    if len(enabled) < 1:
        logger.error("You have to specify one of the actions: " +
                     ", ".join(loaded))
        return

    device_id = args.device
    if not check_adb_connection(is_device_id_provided=(device_id is not None)):
        return
    logger.info("Instagram version: " + get_instagram_version(device_id))
    device = create_device(device_id)

    if device is None:
        return

    while True:
        session_state = SessionState()
        session_state.args = args.__dict__
        sessions.append(session_state)

        device.wake_up()

        logger.info(
            "-------- START: " + str(session_state.startTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if not DeviceFacade(device_id).get_info()["screenOn"]:
            DeviceFacade(device_id).press_power()
        if DeviceFacade(device_id).is_screen_locked():
            DeviceFacade(device_id).unlock()
            if DeviceFacade(device_id).is_screen_locked():
                logger.error(
                    "Can't unlock your screen. There may be a passcode on it. If you would like your screen to be turned on and unlocked automatically, please remove the passcode."
                )
                sys.exit()

        logger.info("Device screen on and unlocked.")

        open_instagram(device_id)

        try:
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()
        except Exception as e:
            logger.error(f"Exception: {e}")
            save_crash(device)
            switch_to_english(device)
            # Try again on the correct language
            profileView = TabBarView(device).navigateToProfile()
            random_sleep()
            (
                session_state.my_username,
                session_state.my_followers_count,
                session_state.my_following_count,
            ) = profileView.getProfileInfo()

        if (session_state.my_username == None
                or session_state.my_followers_count == None
                or session_state.my_following_count == None):
            logger.critical(
                "Could not get one of the following from your profile: username, # of followers, # of followings. This is typically due to a soft ban. Review the crash screenshot to see if this is the case."
            )
            logger.critical(
                f"Username: {session_state.my_username}, Followers: {session_state.my_followers_count}, Following: {session_state.my_following_count}"
            )
            save_crash(device)
            exit(1)

        if not is_log_file_updated():
            try:
                update_log_file_name(session_state.my_username)
            except Exception as e:
                logger.error(
                    f"Failed to update log file name. Will continue anyway. {e}"
                )
                save_crash(device)

        report_string = f"Hello, @{session_state.my_username}! You have {session_state.my_followers_count} followers and {session_state.my_following_count} followings so far."

        logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

        storage = Storage(session_state.my_username)
        for plugin in enabled:
            if not session_state.check_limit(
                    args, limit_type=session_state.Limit.ALL, output=False):
                loaded[plugin].run(device, device_id, args, enabled, storage,
                                   sessions, plugin)
            else:
                logger.info(
                    "Successful or Total Interactions limit reached. Ending session."
                )
                break

        close_instagram(device_id)
        session_state.finishTime = datetime.now()

        if args.screen_sleep:
            DeviceFacade(device_id).screen_off()
            logger.info("Screen turned off for sleeping time")

        logger.info(
            "-------- FINISH: " + str(session_state.finishTime) + " --------",
            extra={"color": f"{Style.BRIGHT}{Fore.YELLOW}"},
        )

        if args.repeat:
            print_full_report(sessions)
            repeat = get_value(args.repeat, "Sleep for {} minutes", 180)
            try:
                sleep(60 * repeat)
            except KeyboardInterrupt:
                print_full_report(sessions)
                sessions.persist(directory=session_state.my_username)
                sys.exit(0)
        else:
            break

    print_full_report(sessions)
    sessions.persist(directory=session_state.my_username)
Esempio n. 15
0
    def run(self, device, configs, storage, sessions, plugin):
        class State:
            def __init__(self):
                pass

            is_job_completed = False

        self.args = configs.args
        self.device_id = configs.args.device
        self.sessions = sessions
        self.session_state = sessions[-1]
        profile_filter = Filter()
        self.current_mode = plugin

        file_list = [file for file in (self.args.interact_from_file)]
        shuffle(file_list)

        for file in file_list:
            limit_reached = self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.LIKES
            ) and self.session_state.check_limit(
                self.args, limit_type=self.session_state.Limit.FOLLOWS)

            self.state = State()
            logger.info(f"Handle {file}", extra={"color": f"{Style.BRIGHT}"})

            on_interaction = partial(
                _on_interaction,
                likes_limit=int(self.args.total_likes_limit),
                source=file,
                interactions_limit=get_value(self.args.interactions_count,
                                             "Interactions count: {}", 70),
                sessions=self.sessions,
                session_state=self.session_state,
                args=self.args,
            )

            on_like = partial(_on_like,
                              sessions=self.sessions,
                              session_state=self.session_state)
            on_watch = partial(_on_watch,
                               sessions=self.sessions,
                               session_state=self.session_state)

            if self.args.stories_count != "0":
                stories_percentage = get_value(
                    self.args.stories_percentage,
                    "Chance of watching stories: {}%", 40)
            else:
                stories_percentage = 0

            @run_safely(
                device=device,
                device_id=self.device_id,
                sessions=self.sessions,
                session_state=self.session_state,
            )
            def job():
                self.handle_username_file(
                    device,
                    file,
                    self.args.likes_count,
                    self.args.stories_count,
                    stories_percentage,
                    int(self.args.follow_percentage),
                    int(self.args.follow_limit)
                    if self.args.follow_limit else None,
                    plugin,
                    storage,
                    profile_filter,
                    on_like,
                    on_watch,
                    on_interaction,
                )
                self.state.is_job_completed = True

            while not self.state.is_job_completed and not limit_reached:
                job()

                if limit_reached:
                    logger.info("Likes and follows limit reached.")
                    self.session_state.check_limit(
                        self.args,
                        limit_type=self.session_state.Limit.ALL,
                        output=True)
                    break