Skip to content

Commit

Permalink
v1.0.4 (#81)
Browse files Browse the repository at this point in the history
Release v1.0.4 - Hotfix!
Bug Fixes

🐛 fix issue finding like button on small screens
🐛 add try/except for version check
🐛 fix sessions
🐛 fix instagram version reporting
Improvements

🐈 add file logging and fixing crash logging

Co-authored-by: Philip Ulrich [email protected]
Co-authored-by: Arthur Silva [email protected]
  • Loading branch information
philip-ulrich authored Nov 19, 2020
1 parent 67cded7 commit dccc995
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Pipfile
Pipfile.lock
*.pdf
.venv
*.log*
33 changes: 22 additions & 11 deletions GramAddict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from colorama import Fore, Style

from GramAddict.core.device_facade import create_device
from GramAddict.core.log import configure_logger
from GramAddict.core.log import configure_logger, update_log_file_name
from GramAddict.core.navigation import switch_to_english
from GramAddict.core.persistent_list import PersistentList
from GramAddict.core.plugin_loader import PluginLoader
Expand Down Expand Up @@ -41,6 +41,7 @@

# Global Variables
device_id = None
first_run = True
plugins = PluginLoader("GramAddict.plugins").plugins
sessions = PersistentList("sessions", SessionStateEncoder)
parser = argparse.ArgumentParser(description="GramAddict Instagram Bot")
Expand Down Expand Up @@ -95,6 +96,7 @@ def get_args():

def run():
global device_id
global first_run
loaded = load_plugins()
args = get_args()
enabled = []
Expand Down Expand Up @@ -127,27 +129,28 @@ def run():
)
return

session_state = SessionState()
session_state.args = args.__dict__
sessions.append(session_state)

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())
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:
Expand Down Expand Up @@ -178,15 +181,21 @@ def run():
"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: {getattr(session_state,'my_username')}, Followers: {getattr(session_state,'my_followers_count')}, Following: {getattr(session_state,'my_following_count')}"
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."

username = session_state.my_username
followers = session_state.my_followers_count
following = session_state.my_following_count
report_string = f"Hello, @{username}! You have {followers} followers and {following} followings so far."
logger.info(report_string, extra={"color": f"{Style.BRIGHT}"})

storage = Storage(session_state.my_username)
Expand Down Expand Up @@ -216,5 +225,7 @@ def run():
else:
break

first_run = False

print_full_report(sessions)
sessions.persist(directory=session_state.my_username)
10 changes: 9 additions & 1 deletion GramAddict/core/device_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from random import uniform

import uiautomator2
from uiautomator2 import Device

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -79,7 +80,7 @@ def get_info(self):
return self.deviceV2.info

class View:
deviceV2 = None # uiautomator2
deviceV2: Device = None # uiautomator2
viewV2 = None # uiautomator2

def __init__(self, view, device):
Expand Down Expand Up @@ -230,6 +231,13 @@ def fling(self, direction):
def exists(self, quick=False):

try:
# Currently the methods left, rigth, up and down from
# uiautomator2 return None when a Selector does not exist.
# All other selectors return an UiObject with exists() == False.
# We will open a ticket to uiautomator2 to fix this incosistency.
if self.viewV2 == None:
return False

return self.viewV2.exists(
UI_TIMEOUT_SHORT if quick else UI_TIMEOUT_LONG
)
Expand Down
130 changes: 95 additions & 35 deletions GramAddict/core/log.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import logging
from io import StringIO
from logging import LogRecord

import os
from colorama import Fore, Style
from colorama import init as init_colorama
from logging import LogRecord
from logging.handlers import RotatingFileHandler
from uuid import uuid4

COLORS = {
"DEBUG": Style.DIM,
Expand All @@ -28,45 +29,104 @@ def format(self, record):
return msg


class LoggerFilterGramAddictOnly(logging.Filter):
def filter(self, record: LogRecord):
return record.name.startswith("GramAddict")


def create_log_file_handler(filename):
file_handler = RotatingFileHandler(
filename,
mode="a",
backupCount=10,
maxBytes=1000000,
encoding="utf-8",
)

file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(
logging.Formatter(
fmt="%(asctime)s %(levelname)8s | %(message)s (%(filename)s:%(lineno)d)",
datefmt=r"[%m/%d %H:%M:%S]",
)
)
file_handler.addFilter(LoggerFilterGramAddictOnly())
return file_handler


def configure_logger():
global g_session_id
global g_log_file_name
global g_logs_dir
global g_file_handler

g_session_id = uuid4()
g_logs_dir = "logs"
g_log_file_name = f"{g_session_id}.log"

init_colorama()
logger = logging.getLogger() # root logger
logger.setLevel(logging.INFO)

# Formatters
datefmt = r"[%m/%d %H:%M:%S]"
console_fmt = "%(asctime)s %(levelname)8s | %(message)s"
console_formatter = ColoredFormatter(fmt=console_fmt, datefmt=datefmt)
crash_report_fmt = (
"%(asctime)s %(levelname)8s | %(message)s (%(filename)s:%(lineno)d)"
)
crash_report_formatter = logging.Formatter(fmt=crash_report_fmt, datefmt=datefmt)

# Filters
class FilterGramAddictOnly(logging.Filter):
def filter(self, record: LogRecord):
return record.name.startswith("GramAddict")
# Root logger
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)

# Console handler (limited colored log)
# Console logger (limited but colored log)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
console_handler.setFormatter(console_formatter)
console_handler.addFilter(FilterGramAddictOnly())
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(
ColoredFormatter(
fmt="%(asctime)s %(levelname)8s | %(message)s", datefmt="[%m/%d %H:%M:%S]"
)
)
console_handler.addFilter(LoggerFilterGramAddictOnly())
root_logger.addHandler(console_handler)

# File logger (full raw log)
if not os.path.exists(g_logs_dir):
os.makedirs(g_logs_dir)
g_file_handler = create_log_file_handler(f"{g_logs_dir}/{g_log_file_name}")
root_logger.addHandler(g_file_handler)

init_logger = logging.getLogger(__name__)
init_logger.debug(f"Initial log file: {g_logs_dir}/{g_log_file_name}")


def get_log_file_config():
return g_log_file_name, g_logs_dir, g_file_handler, g_session_id


def update_log_file_name(username: str):
unamed_log_file_name, logs_dir, file_handler, _ = get_log_file_config()
unamed_full_filename = f"{logs_dir}/{unamed_log_file_name}"

# Crash report handler (full raw log)
global log_stream
log_stream = StringIO()
crash_report_handler = logging.StreamHandler(log_stream)
crash_report_handler.setLevel(logging.DEBUG)
crash_report_handler.setFormatter(crash_report_formatter)
crash_report_handler.addFilter(FilterGramAddictOnly())
init_logger = logging.getLogger(__name__)
if not username:
init_logger.error(f"No username found, using log file {unamed_full_filename}")
return
named_log_file_name = f"{username}.log"
named_full_filename = f"{logs_dir}/{named_log_file_name}"
rollover = False
if os.path.isfile(named_full_filename):
rollover = True

logger.addHandler(console_handler)
logger.addHandler(crash_report_handler)
named_file_handler = create_log_file_handler(named_full_filename)
if rollover:
named_file_handler.doRollover()

# copy existing runtime logs (uidd4.log) to named log file (username.log)
with open(unamed_full_filename, "r") as unamed_file, open(
named_full_filename, "a"
) as named_file:
for line in unamed_file:
named_file.write(line)

def get_logs():
# log_stream is a StringIO() created when configure_logger() is called
global log_stream
root_logger = logging.getLogger()
root_logger.removeHandler(file_handler)
os.remove(unamed_full_filename)
root_logger.addHandler(named_file_handler)
root_logger.debug(f"Updated log file: {named_full_filename}")

return log_stream.getvalue()
global g_log_file_name
global g_file_handler
g_log_file_name = named_log_file_name
g_file_handler = named_file_handler
54 changes: 22 additions & 32 deletions GramAddict/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@
from time import sleep

from colorama import Fore, Style
from GramAddict.core.log import get_logs
from GramAddict.core.log import get_log_file_config
from GramAddict.version import __version__

http = urllib3.PoolManager()
logger = logging.getLogger(__name__)


def update_available():
r = http.request(
"GET",
"https://raw.githubusercontent.com/GramAddict/bot/master/GramAddict/version.py",
)
return r.data.decode("utf-8").split('"')[1] > __version__
try:
r = http.request(
"GET",
"https://raw.githubusercontent.com/GramAddict/bot/master/GramAddict/version.py",
)
return r.data.decode("utf-8").split('"')[1] > __version__
except Exception as e:
logger.error(
f"There was an error retreiving the latest version of GramAddict: {e}"
)
return False


def check_adb_connection(is_device_id_provided):
Expand All @@ -48,8 +54,12 @@ def check_adb_connection(is_device_id_provided):
return is_ok


def get_instagram_version():
stream = os.popen("adb shell dumpsys package com.instagram.android")
def get_instagram_version(device_id):
stream = os.popen(
"adb"
+ ("" if device_id is None else " -s " + device_id)
+ " shell dumpsys package com.instagram.android"
)
output = stream.read()
version_match = re.findall("versionName=(\\S+)", output)
if len(version_match) == 1:
Expand Down Expand Up @@ -151,7 +161,6 @@ def screen_sleep(device_id, mode):


def save_crash(device):
global print_log

directory_name = "Crash-" + datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
try:
Expand All @@ -176,10 +185,10 @@ def save_crash(device):
except RuntimeError:
logger.error("Cannot save view hierarchy.")

with open(
"crashes/" + directory_name + "/logs.txt", "w", encoding="utf-8"
) as outfile:
outfile.write(get_logs())
g_log_file_name, g_logs_dir, _, _ = get_log_file_config()
src_file = f"{g_logs_dir}/{g_log_file_name}"
target_file = f"crashes/{directory_name}/logs.txt"
shutil.copy(src_file, target_file)

shutil.make_archive(
"crashes/" + directory_name, "zip", "crashes/" + directory_name + "/"
Expand Down Expand Up @@ -211,22 +220,6 @@ def detect_block(device):
)


def _print_with_time_decorator(standard_print, print_time):
def wrapper(*args, **kwargs):
global print_log
if print_time:
time = datetime.now().strftime("%m/%d %H:%M:%S")
print_log += re.sub(
r"\[\d+m", "", ("[" + time + "] " + str(*args, **kwargs) + "\n")
)
return standard_print("[" + time + "]", *args, **kwargs)
else:
print_log += re.sub(r"\[\d+m", "", (str(*args, **kwargs) + "\n"))
return standard_print(*args, **kwargs)

return wrapper


def get_value(count, name, default):
def print_error():
logger.error(
Expand Down Expand Up @@ -259,8 +252,5 @@ def print_error():
return value


print_log = ""


class ActionBlockedError(Exception):
pass
2 changes: 0 additions & 2 deletions GramAddict/plugins/force_interact.dis
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ class ForceIteract(Plugin):

if not self.open_user(device, username):
return
"""
can_follow = (
not is_myself
and not is_follow_limit_reached()
Expand All @@ -176,7 +175,6 @@ class ForceIteract(Plugin):
)
storage.add_interacted_user(username, followed=followed)
can_continue = on_interaction(succeed=interaction_succeed, followed=followed)
"""
logger.info("Unfollow @" + username)
attempts = 0

Expand Down
Loading

0 comments on commit dccc995

Please sign in to comment.