From 2b3d114643e0df5522579f1351f2997eb220c3e3 Mon Sep 17 00:00:00 2001 From: Alexander Mishchenko Date: Thu, 24 Jun 2021 11:17:52 +0300 Subject: [PATCH] Update to v3.7.15 --- insomniac/__version__.py | 2 +- insomniac/safely_runner.py | 1 - insomniac/session.py | 1 - insomniac/utils.py | 35 +++++++++++++++++--- insomniac/views.py | 67 ++++++++++++++++++++++---------------- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/insomniac/__version__.py b/insomniac/__version__.py index 1e63af0..cbf49fb 100644 --- a/insomniac/__version__.py +++ b/insomniac/__version__.py @@ -13,7 +13,7 @@ __title__ = 'insomniac' __description__ = 'Simple Instagram bot for automated Instagram interaction using Android.' __url__ = 'https://github.com/alexal1/Insomniac/' -__version__ = '3.7.14' +__version__ = '3.7.15' __debug_mode__ = False __author__ = 'Insomniac Team' __author_email__ = 'info@insomniac-bot.com' diff --git a/insomniac/safely_runner.py b/insomniac/safely_runner.py index 7f8ac9d..a6a1838 100644 --- a/insomniac/safely_runner.py +++ b/insomniac/safely_runner.py @@ -25,7 +25,6 @@ def wrapper(*args, **kwargs): close_instagram(device_wrapper.device_id, device_wrapper.app_id) sleeper.random_sleep() open_instagram(device_wrapper.device_id, device_wrapper.app_id) - sleeper.random_sleep() navigate(device_wrapper.get(), TabBarTabs.PROFILE) except LanguageChangedException: print_timeless("") diff --git a/insomniac/session.py b/insomniac/session.py index 01dde1e..e9c2852 100644 --- a/insomniac/session.py +++ b/insomniac/session.py @@ -184,7 +184,6 @@ def start_session(self, args, device_wrapper, app_version, save_profile_info=Tru 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, \ diff --git a/insomniac/utils.py b/insomniac/utils.py index 3bf8d2e..a8d817a 100644 --- a/insomniac/utils.py +++ b/insomniac/utils.py @@ -1,18 +1,18 @@ +import base64 import os -import string +import random import re import shutil +import string import subprocess import sys import traceback -import random -import colorama -import base64 -from datetime import datetime +from datetime import datetime, timedelta from random import randint from subprocess import PIPE from time import sleep +import colorama from colorama import Fore, Style, AnsiToWin32 import insomniac.__version__ as __version__ @@ -343,6 +343,31 @@ def _get_log_file_name(logs_directory_name): return log_path +class Timer: + + duration = None + start_time = None + end_time = None + + def __init__(self, seconds): + self.duration = timedelta(seconds=seconds) + self.start() + + def start(self): + self.start_time = datetime.now() + self.end_time = self.start_time + self.duration + + def is_expired(self): + return datetime.now() > self.end_time + + def get_seconds_left(self): + time_since_start = datetime.now() - self.start_time + if time_since_start >= self.duration: + return 0 + else: + return int((self.duration - time_since_start).total_seconds()) + + class Logger(object): is_log_initiated = False diff --git a/insomniac/views.py b/insomniac/views.py index 22c9d6b..f101969 100644 --- a/insomniac/views.py +++ b/insomniac/views.py @@ -10,6 +10,9 @@ from insomniac.utils import * +TEXTVIEW_OR_BUTTON_REGEX = 'android.widget.TextView|android.widget.Button' + + def case_insensitive_re(str_list): if isinstance(str_list, str): strings = str_list @@ -173,11 +176,18 @@ def navigate_to(self, tab: TabBarTabs): descriptionMatches=case_insensitive_re(TabBarView.PROFILE_CONTENT_DESC) ) - if button.exists(): - # Two clicks to reset tab content - button.click() - button.click() - return + timer = Timer(seconds=20) + while not timer.is_expired(): + if button.exists(): + # Two clicks to reset tab content + button.click() + button.click() + return + else: + seconds_left = timer.get_seconds_left() + if seconds_left > 0: + print(COLOR_OKGREEN + f"Opening {tab_name}, {seconds_left} seconds left..." + COLOR_ENDC) + sleep(2) print(COLOR_FAIL + f"Didn't find tab {tab_name} in the tab bar... " f"Maybe English language is not set!?" + COLOR_ENDC) @@ -318,7 +328,7 @@ class SearchView(InstagramView): def refresh(self): posts_grid = self.device.find(resourceId=PostsGridView.POSTS_GRID_RESOURCE_ID.format(self.device.app_id), - className=PostsGridView.POSTS_GRID_CLASS_NAME) + classNameMatches=PostsGridView.POSTS_GRID_CLASS_NAME) if posts_grid.exists(): posts_grid.scroll(DeviceFacade.Direction.TOP) @@ -326,7 +336,7 @@ def _get_search_edit_text(self): search_edit_text = self.device.find(resourceId=f"{self.device.app_id}:id/action_bar_search_edit_text", className="android.widget.EditText") if not search_edit_text.exists(quick=True): - print(COLOR_FAIL + "Cannot find search bar. Will try to refresh the page." + COLOR_ENDC) + print(COLOR_OKGREEN + "Cannot find search bar. Will try to refresh the page." + COLOR_ENDC) self.refresh() return search_edit_text @@ -386,6 +396,10 @@ def _get_tab_view(self, tab: SearchTabs): def navigate_to_username(self, username, on_action): print_debug(f"Navigate to profile @{username}") + search_edit_text = self._get_search_edit_text() + search_edit_text.click() + self._handle_permission_request() + # Check if username already exists in the recent search list -> act as human username_view_recent = self._get_username_row(username) if username_view_recent.exists(quick=True): @@ -394,11 +408,7 @@ def navigate_to_username(self, username, on_action): return ProfileView(self.device, is_own_profile=False) print(f"@{username} is not in recent searching history...") - search_edit_text = self._get_search_edit_text() - search_edit_text.click() - self._handle_permission_request() search_edit_text.set_text(username) - search_text = self.device.find(resourceId=self.SEARCH_TEXT_ID.format(self.device.app_id), className=self.SEARCH_TEXT_CLASSNAME) search_text.click(ignore_if_missing=True) @@ -423,6 +433,10 @@ def navigate_to_username(self, username, on_action): def navigate_to_hashtag(self, hashtag): print_debug(f"Navigate to hashtag #{hashtag}") + search_edit_text = self._get_search_edit_text() + search_edit_text.click() + self._handle_permission_request() + # Check if hashtag already exists in the recent search list -> act as human hashtag_view_recent = self._get_hashtag_row(hashtag) if hashtag_view_recent.exists(quick=True): @@ -431,11 +445,7 @@ def navigate_to_hashtag(self, hashtag): return HashTagView(self.device) print(f"#{hashtag} is not in recent searching history...") - search_edit_text = self._get_search_edit_text() - search_edit_text.click() - self._handle_permission_request() search_edit_text.set_text(hashtag) - search_text = self.device.find(resourceId=self.SEARCH_TEXT_ID.format(self.device.app_id), className=self.SEARCH_TEXT_CLASSNAME) search_text.click(ignore_if_missing=True) @@ -458,6 +468,10 @@ def navigate_to_hashtag(self, hashtag): def navigate_to_place(self, place): print_debug(f"Navigate to place {place}") + search_edit_text = self._get_search_edit_text() + search_edit_text.click() + self._handle_permission_request() + # Check if place already exists in the recent search list -> act as human place_view_recent = self._get_place_row(place) if place_view_recent.exists(quick=True): @@ -466,11 +480,7 @@ def navigate_to_place(self, place): return PlacesView(self.device) print(f"{place} is not in recent searching history...") - search_edit_text = self._get_search_edit_text() - search_edit_text.click() - self._handle_permission_request() search_edit_text.set_text(place) - search_text = self.device.find(resourceId=self.SEARCH_TEXT_ID.format(self.device.app_id), className=self.SEARCH_TEXT_CLASSNAME) search_text.click(ignore_if_missing=True) @@ -793,13 +803,13 @@ def like(self): class PostsGridView(InstagramView): POSTS_GRID_RESOURCE_ID = '{0}:id/recycler_view' - POSTS_GRID_CLASS_NAME = 'androidx.recyclerview.widget.RecyclerView' + POSTS_GRID_CLASS_NAME = 'androidx.recyclerview.widget.RecyclerView|android.view.View' def open_random_post(self) -> Optional['PostsViewList']: # Scroll down several times to pick random post scroll_times = randint(0, 5) posts_grid = self.device.find(resourceId=self.POSTS_GRID_RESOURCE_ID.format(self.device.app_id), - className=self.POSTS_GRID_CLASS_NAME) + classNameMatches=self.POSTS_GRID_CLASS_NAME) print(f"Scroll down {scroll_times} times.") for _ in range(0, scroll_times): posts_grid.scroll(DeviceFacade.Direction.BOTTOM) @@ -845,8 +855,10 @@ def open_random_post(self) -> Optional['PostsViewList']: class ProfileView(ActionBarView): + FOLLOWERS_BUTTON_ID_REGEX = '{0}:id/row_profile_header_followers_container|{1}:id/row_profile_header_container_followers' FOLLOWING_BUTTON_ID_REGEX = '{0}:id/row_profile_header_following_container|{1}:id/row_profile_header_container_following' + MESSAGE_BUTTON_CLASS_NAME_REGEX = TEXTVIEW_OR_BUTTON_REGEX def __init__(self, device: DeviceFacade, is_own_profile=False): super().__init__(device) @@ -1130,8 +1142,7 @@ def navigate_to_following(self): def open_messages(self): message_button = self.device.find( - className='android.widget.Button', - clickable=True, + classNameMatches=self.MESSAGE_BUTTON_CLASS_NAME_REGEX, textMatches=case_insensitive_re('Message') ) if message_button.exists(quick=True): @@ -1166,10 +1177,10 @@ def switch_to_tab(self, tab): sleeper.random_sleep() following_tab = self.device.find(className="android.widget.TextView", clickable=True, - textContains="Following") + textMatches="(?i).*?following") followers_tab = self.device.find(className="android.widget.TextView", clickable=True, - textContains="Followers") + textMatches="(?i).*?followers") if tab == self.Tab.FOLLOWERS: followers_tab.click() else: @@ -1356,17 +1367,17 @@ def getTimestamp(self): class DialogView(InstagramView): UNFOLLOW_BUTTON_ID_REGEX = '{0}:id/follow_sheet_unfollow_row|{1}:id/button_positive|{2}:id/primary_button' - UNFOLLOW_BUTTON_CLASS_NAME_REGEX = 'android.widget.TextView|android.widget.Button' + UNFOLLOW_BUTTON_CLASS_NAME_REGEX = TEXTVIEW_OR_BUTTON_REGEX UNFOLLOW_BUTTON_TEXT_REGEX = case_insensitive_re("Unfollow") LOCATION_DENY_BUTTON_ID_REGEX = '.*?:id/permission_deny.*?' - LOCATION_DENY_BUTTON_CLASS_NAME_REGEX = 'android.widget.TextView|android.widget.Button' + LOCATION_DENY_BUTTON_CLASS_NAME_REGEX = TEXTVIEW_OR_BUTTON_REGEX LOCATION_CHECKBOX_ID_REGEX = '.*?:id/do_not_ask_checkbox' def is_visible(self) -> bool: dialog_v1 = self.device.find(resourceId=f'{self.device.app_id}:id/dialog_root_view', className='android.widget.FrameLayout') dialog_v2 = self.device.find(resourceId=f'{self.device.app_id}:id/dialog_container', - className='android.view.ViewGroup') + classNameMatches='android.view.ViewGroup|android.view.View') dialog_v3 = self.device.find(resourceId=f'{self.device.app_id}:id/content', className='android.widget.FrameLayout') dialog_v4 = self.device.find(resourceIdMatches='com.android.(permissioncontroller|packageinstaller):id/.*?',