🤬
  • Complete refactoring. - Bug Fixes - Refactoring the whole code - Introducing testing ### TODO complete the message group processing ### Tests ### TODO introducing bot analysis ### TODO introducing chat group overlaps

  • Loading...
  • Giacomo Giallombardo committed 1 year ago
    a177971f
    1 parent 7f230357
  • ■ ■ ■ ■ ■
    src/telepathy/const.py
    skipped 5 lines
    6 6  __status__ = "Development"
    7 7   
    8 8  user_agent = [
    9  - 
    10 9   # Chrome
    11 10   "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
    12 11   "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
    skipped 5 lines
    18 17   "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
    19 18   "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
    20 19   "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
    21  - 
    22 20   # Firefox
    23 21   "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)",
    24 22   "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
    skipped 8 lines
    33 31   "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)",
    34 32   "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
    35 33   "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
    36  - 
    37 34   # Safari
    38 35   "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) RockMelt/0.9.50.549 Chrome/10.0.648.205 Safari/534.16"
    39 36   "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.18 (KHTML, like Gecko) Chrome/11.0.661.0 Safari/534.18"
    skipped 24 lines
    64 61  login = telepathy_file + "login.txt"
    65 62  log_file = telepathy_file + "log.csv"
    66 63  export_file = telepathy_file + "export.csv"
     64 + 
  • ■ ■ ■ ■ ■ ■
    src/telepathy/telepathy.py
    skipped 26 lines
    27 27   create_path,
    28 28   create_file_report,
    29 29   clean_private_invite,
    30  - evaluate_reactions
     30 + evaluate_reactions,
    31 31  )
    32 32   
    33 33  from telethon.tl.functions.messages import GetHistoryRequest
    skipped 16 lines
    50 50  from colorama import Fore, Style
    51 51  from const import telepathy_file
    52 52   
    53  -'''
     53 +"""
    54 54  try:
    55 55   bot = await TelegramClient(os.path.join(base_path, bot_id), API_ID, API_HASH, proxy=proxy).start(bot_token=bot_token)
    56 56   bot.id = bot_id
    skipped 8 lines
    65 65   
    66 66   user_info = user.user.to_dict()
    67 67   user_info['token'] = bot_token
    68  -'''
     68 +"""
     69 + 
     70 + 
    69 71  class Group_Chat_Analisys:
    70 72   
    71 73   save_directory = None
    skipped 9 lines
    81 83   history = None
    82 84   history_count = 0
    83 85   
    84  - _target = None
     86 + _target = None
    85 87   _target_entity = None
    86 88   _alphanumeric = None
    87 89   _log_file = None
    skipped 1 lines
    89 91   
    90 92   client = None
    91 93   
    92  - def __init__(self, target, client, log_file, filetime, replies, forwards, comprehensive, media, json, translate):
     94 + def __init__(
     95 + self,
     96 + target,
     97 + client,
     98 + log_file,
     99 + filetime,
     100 + replies,
     101 + forwards,
     102 + comprehensive,
     103 + media,
     104 + json,
     105 + translate,
     106 + alphanumeric,
     107 + ):
    93 108   self.client = client
    94 109   self._target = target
    95 110   self._log_file = log_file
    96 111   self._filetime = filetime
    97  - 
     112 + self._alphanumeric = self.calculate_alfanumeric()
    98 113   self.user_check = self.location_check = False
    99 114   self.basic = True if target else False
    100 115   self.reply_analysis = True if replies else False
    skipped 2 lines
    103 118   self.media_archive = True if media else False
    104 119   self.json_check = True if json else False
    105 120   self.translate_check = True if translate else False
    106  - self.last_date, self.chunk_size, self.user_language = None, 1000, 'en'
     121 + self.last_date, self.chunk_size, self.user_language = None, 1000, "en"
     122 + self.create_dirs_files()
    107 123   
    108 124   def telepathy_log_run(self):
    109 125   log = []
    skipped 13 lines
    123 139   str(self._entity.scam),
    124 140   self._date,
    125 141   self._mtime,
    126  - self._group_status
     142 + self._group_status,
    127 143   ]
    128 144   )
    129 145   log_df = pd.DataFrame(
    skipped 20 lines
    150 166   if not os.path.isfile(self._log_file):
    151 167   log_df.to_csv(self._log_file, sep=";", index=False)
    152 168   else:
    153  - log_df.to_csv(
    154  - self._log_file, sep=";", mode="a", index=False, header=False
    155  - )
     169 + log_df.to_csv(self._log_file, sep=";", mode="a", index=False, header=False)
     170 + 
     171 + def calculate_alfanumeric(self):
     172 + alphanumeric = ""
     173 + for character in self._target:
     174 + if character.isalnum():
     175 + alphanumeric += character
     176 + return alphanumeric
    156 177   
    157 178   async def retrieve_entity(self, _target):
    158 179   current_entity = None
    skipped 32 lines
    191 212   members.append(populate_user(user, self._target))
    192 213   
    193 214   if members_df is not None:
    194  - with open(
    195  - self.memberlist_filename, "w+", encoding="utf-8"
    196  - ) as save_members:
     215 + with open(self.memberlist_filename, "w+", encoding="utf-8") as save_members:
    197 216   members_df.to_csv(save_members, sep=";")
    198 217   
    199 218   if self.json_check:
    skipped 9 lines
    209 228   found_percentage = 0
    210 229   if self._total_participants > 0:
    211 230   found_percentage = (
    212  - int(found_participants) / int(self._total_participants) * 100
     231 + int(found_participants) / int(self._total_participants) * 100
    213 232   )
    214 233   print("\n")
    215 234   color_print_green(" [+] Memberlist fetched", "")
    skipped 5 lines
    221 240   
    222 241   _result["entity"] = await self.retrieve_entity(_handle)
    223 242   
    224  - if not _result["entity"] or (_result["entity"].__class__ == User and _check_user) :
     243 + if not _result["entity"] or (
     244 + _result["entity"].__class__ == User and _check_user
     245 + ):
    225 246   if _result["entity"].__class__ == User:
    226  - color_print_green(" [!] ", "You can't search for users using flag -c, run Telepathy using the flag -u.")
     247 + color_print_green(
     248 + " [!] ",
     249 + "You can't search for users using flag -c, run Telepathy using the flag -u.",
     250 + )
    227 251   else:
    228  - color_print_green(" [!] ", "Telegram handle: {} wasn't found. !!!!".format(_handle))
     252 + color_print_green(
     253 + " [!] ", "Telegram handle: {} wasn't found. !!!!".format(_handle)
     254 + )
    229 255   return
    230  - elif _check_user :
     256 + elif _check_user:
    231 257   if _result["entity"].__class__ == User:
    232  - _result ={"chat_type":"User"}
     258 + _result = {"chat_type": "User"}
    233 259   substring_1 = "PeerUser"
    234 260   
    235 261   if _result["entity"].username is not None:
    236  - _result["username"] = _result["entity"].username
     262 + _result["username"] = _result["entity"].username
    237 263   else:
    238 264   username = "none"
    239 265   
    skipped 4 lines
    244 270   "",
    245 271   string_1,
    246 272   )
    247  - user_id = await self.client.get_entity(
    248  - PeerUser(
    249  - int(user_id)
    250  - )
    251  - )
     273 + user_id = await self.client.get_entity(PeerUser(int(user_id)))
    252 274   user_id = str(user_id)
    253 275   _result["user_id"] = user_id
    254 276   _result["first_name"] = _result["entity"].first_name
    255 277   return _result
    256 278   
    257 279   _result["total_participants"] = 0
    258  - _result["chat_type"], _result["group_url"], _result["group_username"], _result["group_description"], \
    259  - _result["group_status"], _result["translated_description"] = "", "", "", "", "", ""
     280 + (
     281 + _result["chat_type"],
     282 + _result["group_url"],
     283 + _result["group_username"],
     284 + _result["group_description"],
     285 + _result["group_status"],
     286 + _result["translated_description"],
     287 + ) = ("", "", "", "", "", "")
    260 288   
    261 289   if _result["entity"].broadcast is True:
    262 290   _result["chat_type"] = "Channel"
    skipped 13 lines
    276 304   web_req = parse_html_page(_result["group_url"])
    277 305   _result["group_username"] = "Private group"
    278 306   else:
    279  - _result["group_url"], _result["group_username"] = "Private group", "Private group"
     307 + _result["group_url"], _result["group_username"] = (
     308 + "Private group",
     309 + "Private group",
     310 + )
    280 311   
    281 312   if web_req:
    282 313   _result["group_description"] = web_req["group_description"]
    skipped 3 lines
    286 317   _result["desc"] = process_description(
    287 318   _result["group_description"], self.user_language
    288 319   )
    289  - _original_language = _result["desc"][
    290  - "original_language"
    291  - ]
     320 + _original_language = _result["desc"]["original_language"]
    292 321   _result["translated_description"] = _result["desc"]["translated_text"]
    293 322   else:
    294 323   _result["translated_description"] = "N/A"
    skipped 15 lines
    310 339   if 1 in _result["entity"].restriction_reason:
    311 340   android_restriction = _result["entity"].restriction_reason[1]
    312 341   _result["group_status"] = (
    313  - str(ios_restriction)
    314  - + ", "
    315  - + str(android_restriction)
     342 + str(ios_restriction) + ", " + str(android_restriction)
    316 343   )
    317 344   else:
    318 345   _result["group_status"] = str(ios_restriction)
    skipped 1 lines
    320 347   _result["group_status"] = "None"
    321 348   return _result
    322 349   
    323  - async def retrieve_chat_group_entity(self,_handle):
     350 + async def retrieve_chat_group_entity(self, _handle):
    324 351   try:
    325 352   _entitydetails = await self.retrieve_entity_info(_handle)
    326 353   except Exception as exx:
    327 354   pass
     355 + 
    328 356   self._entity = _entitydetails["entity"]
    329 357   self._total_participants = _entitydetails["total_participants"]
    330  - self._chat_type, self._group_url, self._group_username, self._group_description, self._group_status, self._translated_description = _entitydetails["chat_type"], _entitydetails["group_url"], _entitydetails["group_username"], _entitydetails["group_description"], _entitydetails["group_status"], _entitydetails["translated_description"]
     358 + (
     359 + self._chat_type,
     360 + self._group_url,
     361 + self._group_username,
     362 + self._group_description,
     363 + self._group_status,
     364 + self._translated_description,
     365 + ) = (
     366 + _entitydetails["chat_type"],
     367 + _entitydetails["group_url"],
     368 + _entitydetails["group_username"],
     369 + _entitydetails["group_description"],
     370 + _entitydetails["group_status"],
     371 + _entitydetails["translated_description"],
     372 + )
    331 373   self._first_post = _entitydetails["first_post"]
    332 374   self._date = _entitydetails["date"]
    333 375   self._datepost = _entitydetails["datepost"]
    skipped 26 lines
    360 402   self._desc = process_description(
    361 403   self._group_description, self.user_language
    362 404   )
    363  - _original_language = self._desc[
    364  - "original_language"
    365  - ]
     405 + _original_language = self._desc["original_language"]
    366 406   self._translated_description = self._desc["translated_text"]
    367 407   else:
    368 408   self._translated_description = "N/A"
    skipped 15 lines
    384 424   if 1 in self._entity.restriction_reason:
    385 425   android_restriction = self._entity.restriction_reason[1]
    386 426   self._group_status = (
    387  - str(ios_restriction)
    388  - + ", "
    389  - + str(android_restriction)
     427 + str(ios_restriction) + ", " + str(android_restriction)
    390 428   )
    391 429   else:
    392 430   self._group_status = str(ios_restriction)
    393 431   else:
    394 432   self._group_status = "None"
    395 433   
    396  - def create_dirs_files(self, _alphanumeric):
     434 + def create_dirs_files(self):
    397 435   self.save_directory = None
    398 436   self.media_directory = None
    399 437   self.file_archive = None
    skipped 6 lines
    406 444   self.reply_memberlist_filename = None
    407 445   
    408 446   if self.basic or self.comp_check:
    409  - self.save_directory = create_path( os.path.join(telepathy_file,self._alphanumeric))
     447 + self.save_directory = create_path(
     448 + os.path.join(telepathy_file, self._alphanumeric)
     449 + )
    410 450   
    411 451   if self.media_archive and self.save_directory:
    412  - self.media_directory = create_path( os.path.join(self.save_directory,"media"))
     452 + self.media_directory = create_path(
     453 + os.path.join(self.save_directory, "media")
     454 + )
    413 455   
    414 456   if self.comp_check:
    415  - self.file_archive = create_file_report(self.save_directory, _alphanumeric, "archive", "csv", self._filetime)
    416  - self.reply_file_archive = create_file_report(self.save_directory, _alphanumeric, "reply_archive", "csv", self._filetime)
     457 + self.file_archive = create_file_report(
     458 + self.save_directory, self._alphanumeric, "archive", "csv", self._filetime
     459 + )
     460 + self.reply_file_archive = create_file_report(
     461 + self.save_directory,
     462 + self._alphanumeric,
     463 + "reply_archive",
     464 + "csv",
     465 + self._filetime,
     466 + )
    417 467   if self.json_check:
    418  - self.archive_filename_json = create_file_report(self.memberlist_directory, _alphanumeric, "archive",
    419  - "json", self._filetime, False)
     468 + self.archive_filename_json = create_file_report(
     469 + self.memberlist_directory,
     470 + self._alphanumeric,
     471 + "archive",
     472 + "json",
     473 + self._filetime,
     474 + False,
     475 + )
    420 476   
    421 477   if self.forwards_check == True:
    422  - self.forward_directory = create_path(os.path.join(self.save_directory, "edgelist"))
    423  - self.file_forwards = create_file_report(self.forward_directory, _alphanumeric, "edgelist", "csv", self._filetime)
    424  - self.edgelist_file = create_file_report(self.forward_directory, _alphanumeric, "edgelist", "csv", self._filetime, False)
     478 + self.forward_directory = create_path(
     479 + os.path.join(self.save_directory, "edgelist")
     480 + )
     481 + self.file_forwards = create_file_report(
     482 + self.forward_directory, self._alphanumeric, "edgelist", "csv", self._filetime
     483 + )
     484 + self.edgelist_file = create_file_report(
     485 + self.forward_directory,
     486 + self._alphanumeric,
     487 + "edgelist",
     488 + "csv",
     489 + self._filetime,
     490 + False,
     491 + )
    425 492   if self.json_check:
    426  - self.edgelist_filename_json = create_file_report(self.memberlist_directory, _alphanumeric, "edgelist",
    427  - "json", self._filetime,False)
     493 + self.edgelist_filename_json = create_file_report(
     494 + self.memberlist_directory,
     495 + self._alphanumeric,
     496 + "edgelist",
     497 + "json",
     498 + self._filetime,
     499 + False,
     500 + )
    428 501   
    429 502   if self.basic is True or self.comp_check is True:
    430  - self.memberlist_directory = create_path(os.path.join(self.save_directory, "memeberlist"))
    431  - self.memberlist_filename = create_file_report(self.memberlist_directory, _alphanumeric, "members", "csv", self._filetime)
     503 + self.memberlist_directory = create_path(
     504 + os.path.join(self.save_directory, "memeberlist")
     505 + )
     506 + self.memberlist_filename = create_file_report(
     507 + self.memberlist_directory,
     508 + self._alphanumeric,
     509 + "members",
     510 + "csv",
     511 + self._filetime,
     512 + )
    432 513   if self.json_check:
    433  - self.memberlist_filename_json = create_file_report(self.memberlist_directory, _alphanumeric, "members",
    434  - "json", self._filetime, False)
    435  - self.reply_memberlist_filename = create_file_report(self.memberlist_directory, _alphanumeric, "active_members", "csv", self._filetime)
    436  - 
    437  - async def analyze_group_channel(self,_target):
    438  - alphanumeric = ""
    439  - save_directory = None
    440  - for character in _target:
    441  - if character.isalnum():
    442  - alphanumeric += character
     514 + self.memberlist_filename_json = create_file_report(
     515 + self.memberlist_directory,
     516 + self._alphanumeric,
     517 + "members",
     518 + "json",
     519 + self._filetime,
     520 + False,
     521 + )
     522 + self.reply_memberlist_filename = create_file_report(
     523 + self.memberlist_directory,
     524 + self._alphanumeric,
     525 + "active_members",
     526 + "csv",
     527 + self._filetime,
     528 + )
    443 529   
     530 + async def analyze_group_channel(self, _target=None):
     531 + if not _target:
     532 + _target = self._target
    444 533   _target = clean_private_invite(_target)
     534 + await self.retrieve_chat_group_entity(_target)
    445 535   
    446 536   if self.basic and not self.comp_check:
    447 537   color_print_green(" [!] ", "Performing basic scan")
    skipped 4 lines
    452 542   
    453 543   if self.basic is True or self.comp_check is True:
    454 544   if self._chat_type != "Channel":
    455  - self._found_participants, self._found_percentage = await self.retrieve_memberlist()
     545 + (
     546 + self._found_participants,
     547 + self._found_percentage,
     548 + ) = await self.retrieve_memberlist()
    456 549   
    457 550   setattr(self._entity, "group_description", self._group_description)
    458 551   setattr(self._entity, "group_status", self._group_status)
    skipped 1 lines
    460 553   setattr(self._entity, "first_post", self._first_post)
    461 554   setattr(self._entity, "group_url", self._group_url)
    462 555   setattr(self._entity, "chat_type", self._chat_type)
    463  - setattr(self._entity, "translated_description", self._translated_description)
     556 + setattr(
     557 + self._entity, "translated_description", self._translated_description
     558 + )
    464 559   setattr(self._entity, "total_participants", self._total_participants)
    465 560   
    466 561   if self._chat_type != "Channel":
    skipped 8 lines
    475 570   print_flag = "channel_recap"
    476 571   print_shell(print_flag, self._entity)
    477 572   self.telepathy_log_run()
     573 + await self.process_group_channel_messages(_target)
    478 574   
    479 575   async def f_export(self):
     576 + 
    480 577   exports = []
    481 578   for Dialog in await self.client.get_dialogs():
    482 579   try:
    skipped 25 lines
    508 605   self.target_type = "g"
    509 606   
    510 607   if Dialog.entity.restriction_reason is not None:
    511  - ios_restriction = Dialog.entity.restriction_reason[
    512  - 0
    513  - ]
     608 + ios_restriction = Dialog.entity.restriction_reason[0]
    514 609   if 1 in Dialog.entity.restriction_reason:
    515  - android_restriction = (
    516  - Dialog.entity.restriction_reason[1]
    517  - )
     610 + android_restriction = Dialog.entity.restriction_reason[1]
    518 611   self._group_status = (
    519  - str(ios_restriction)
    520  - + ", "
    521  - + str(android_restriction)
     612 + str(ios_restriction) + ", " + str(android_restriction)
    522 613   )
    523 614   else:
    524 615   self._group_status = str(ios_restriction)
    skipped 71 lines
    596 687   
    597 688   async def process_group_channel_messages(self, _target):
    598 689   if self.forwards_check is True and self.comp_check is False:
    599  - color_print_green(
    600  - " [-] ", "Calculating number of forwarded messages..."
    601  - )
     690 + color_print_green(" [-] ", "Calculating number of forwarded messages...")
    602 691   forwards_list = []
    603 692   forward_count = 0
    604 693   private_count = 0
    skipped 17 lines
    622 711   forward_count += 1
    623 712   
    624 713   color_print_green(" [-] ", "Fetching forwarded messages...")
    625  - progress_bar = (
    626  - Fore.GREEN + " [-] " + Style.RESET_ALL + "Progress: "
    627  - )
     714 + progress_bar = Fore.GREEN + " [-] " + Style.RESET_ALL + "Progress: "
    628 715   
    629 716   with alive_bar(
    630  - forward_count, dual_line=True, title=progress_bar, length=20
     717 + forward_count, dual_line=True, title=progress_bar, length=20
    631 718   ) as bar:
    632 719   
    633 720   async for message in self.client.iter_messages(_target):
    skipped 3 lines
    637 724   if f_from_id is not None:
    638 725   ent = await self.client.get_entity(f_from_id)
    639 726   username = ent.username
    640  - timestamp = parse_tg_date(message.date)[
    641  - "timestamp"
    642  - ]
     727 + timestamp = parse_tg_date(message.date)["timestamp"]
    643 728   
    644 729   substring = "PeerUser"
    645 730   string = str(f_from_id)
    646  - if self.chat_type != "Channel":
     731 + if self._chat_type != "Channel":
    647 732   if substring in string:
    648 733   user_id = re.sub("[^0-9]", "", string)
    649 734   user_id = await self.client.get_entity(
    skipped 1 lines
    651 736   )
    652 737   user_id = str(user_id)
    653 738   result = (
    654  - "User: "
    655  - + str(ent.first_name)
    656  - + " / ID: "
    657  - + str(user_id.id)
     739 + "User: "
     740 + + str(ent.first_name)
     741 + + " / ID: "
     742 + + str(user_id.id)
    658 743   )
    659 744   else:
    660 745   result = str(ent.title)
    skipped 32 lines
    693 778   bar()
    694 779   
    695 780   with open(
    696  - self.edgelist_file, "w+", encoding="utf-8"
     781 + self.edgelist_file, "w+", encoding="utf-8"
    697 782   ) as save_forwards:
    698 783   forwards_df.to_csv(save_forwards, sep=";")
    699 784   
    skipped 15 lines
    715 800   
    716 801   report_forward = createPlaceholdeCls()
    717 802   report_forward.forward_one = (
    718  - str(df01.iloc[0]["unique_values"])
    719  - + ", "
    720  - + str(df01.iloc[0]["counts"])
    721  - + " forwarded messages"
     803 + str(df01.iloc[0]["unique_values"])
     804 + + ", "
     805 + + str(df01.iloc[0]["counts"])
     806 + + " forwarded messages"
    722 807   )
    723 808   report_forward.forward_two = (
    724  - str(df01.iloc[1]["unique_values"])
    725  - + ", "
    726  - + str(df01.iloc[1]["counts"])
    727  - + " forwarded messages"
     809 + str(df01.iloc[1]["unique_values"])
     810 + + ", "
     811 + + str(df01.iloc[1]["counts"])
     812 + + " forwarded messages"
    728 813   )
    729 814   report_forward.forward_three = (
    730  - str(df01.iloc[2]["unique_values"])
    731  - + ", "
    732  - + str(df01.iloc[2]["counts"])
    733  - + " forwarded messages"
     815 + str(df01.iloc[2]["unique_values"])
     816 + + ", "
     817 + + str(df01.iloc[2]["counts"])
     818 + + " forwarded messages"
    734 819   )
    735 820   report_forward.forward_four = (
    736  - str(df01.iloc[3]["unique_values"])
    737  - + ", "
    738  - + str(df01.iloc[3]["counts"])
    739  - + " forwarded messages"
     821 + str(df01.iloc[3]["unique_values"])
     822 + + ", "
     823 + + str(df01.iloc[3]["counts"])
     824 + + " forwarded messages"
    740 825   )
    741 826   report_forward.forward_five = (
    742  - str(df01.iloc[4]["unique_values"])
    743  - + ", "
    744  - + str(df01.iloc[4]["counts"])
    745  - + " forwarded messages"
     827 + str(df01.iloc[4]["unique_values"])
     828 + + ", "
     829 + + str(df01.iloc[4]["counts"])
     830 + + " forwarded messages"
    746 831   )
    747 832   
    748 833   df02 = forwards_df.Source.unique()
    skipped 23 lines
    772 857   
    773 858   if self.media_archive is True:
    774 859   print("\n")
    775  - color_print_green(
    776  - " [!] ", "Media content will be archived"
    777  - )
     860 + color_print_green(" [!] ", "Media content will be archived")
    778 861   
    779  - color_print_green(
    780  - " [!] ", "Calculating number of messages..."
    781  - )
     862 + color_print_green(" [!] ", "Calculating number of messages...")
    782 863   
    783 864   async for message in messages:
    784 865   if message is not None:
    skipped 1 lines
    786 867   
    787 868   print("\n")
    788 869   color_print_green(" [-] ", "Fetching message archive...")
    789  - progress_bar = (
    790  - Fore.GREEN + " [-] " + Style.RESET_ALL + "Progress: "
    791  - )
     870 + progress_bar = Fore.GREEN + " [-] " + Style.RESET_ALL + "Progress: "
    792 871   
    793 872   with alive_bar(
    794  - message_count,
    795  - dual_line=True,
    796  - title=progress_bar,
    797  - length=20,
     873 + message_count,
     874 + dual_line=True,
     875 + title=progress_bar,
     876 + length=20,
    798 877   ) as bar:
    799 878   
    800 879   to_ent = self._entity
    801 880   
    802  - async for message in self.client.iter_messages(
    803  - _target, limit=None
    804  - ):
     881 + async for message in self.client.iter_messages(_target, limit=None):
    805 882   if message is not None:
    806 883   try:
    807 884   c_archive = pd.DataFrame(
    skipped 39 lines
    847 924   "Pray",
    848 925   "Edit_date",
    849 926   "URL",
    850  - "Media save directory"
     927 + "Media save directory",
    851 928   ],
    852 929   )
    853 930   
    skipped 23 lines
    877 954   # )
    878 955   
    879 956   if (
    880  - message.replies
    881  - and self.reply_analysis
    882  - and self._chat_type == "Channel"
     957 + message.replies
     958 + and self.reply_analysis
     959 + and self._chat_type == "Channel"
    883 960   ):
    884 961   if message.replies.replies > 0:
    885 962   c_repliers = pd.DataFrame(
    skipped 26 lines
    912 989   if message.replies:
    913 990   if message.replies.replies > 0:
    914 991   async for repl in self.client.iter_messages(
    915  - message.chat_id,
    916  - reply_to=message.id,
     992 + message.chat_id,
     993 + reply_to=message.id,
    917 994   ):
    918 995   
    919 996   user = await self.client.get_entity(
    skipped 1 lines
    921 998   )
    922 999   
    923 1000   userdet = populate_user(user, _target)
    924  - user_replier_list.append(
    925  - userdet
    926  - )
     1001 + user_replier_list.append(userdet)
    927 1002   
    928 1003   if self.translate_check:
    929 1004   mss_txt = process_message(
    930 1005   repl.text, self.user_language
    931 1006   )
    932  - original_language = mss_txt["original_language"],
    933  - translated_text = mss_txt["translated_text"],
    934  - translation_confidence = mss_txt["translation_confidence"],
     1007 + original_language = (
     1008 + mss_txt["original_language"],
     1009 + )
     1010 + translated_text = (
     1011 + mss_txt["translated_text"],
     1012 + )
     1013 + translation_confidence = (
     1014 + mss_txt["translation_confidence"],
     1015 + )
    935 1016   reply_text = mss_txt["message_text"]
    936 1017   else:
    937 1018   original_language = "N/A"
    skipped 12 lines
    950 1031   original_language,
    951 1032   translated_text,
    952 1033   translation_confidence,
    953  - parse_tg_date(
    954  - repl.date
    955  - )["timestamp"],
     1034 + parse_tg_date(repl.date)[
     1035 + "timestamp"
     1036 + ],
    956 1037   ]
    957 1038   )
    958 1039   
    959  - display_name = get_display_name(
    960  - message.sender
    961  - )
     1040 + display_name = get_display_name(message.sender)
    962 1041   if self._chat_type != "Channel":
    963 1042   substring = "PeerUser"
    964 1043   string = str(message.from_id)
    965 1044   if substring in string:
    966  - user_id = re.sub(
    967  - "[^0-9]", "", string
    968  - )
     1045 + user_id = re.sub("[^0-9]", "", string)
    969 1046   nameID = str(user_id)
    970 1047   else:
    971 1048   nameID = str(message.from_id)
    972 1049   else:
    973 1050   nameID = to_ent.id
    974 1051   
    975  - timestamp = parse_tg_date(message.date)[
    976  - "timestamp"
    977  - ]
     1052 + timestamp = parse_tg_date(message.date)["timestamp"]
    978 1053   reply = message.reply_to_msg_id
    979 1054   
    980 1055   if self.translate_check:
    skipped 1 lines
    982 1057   message.text, self.user_language
    983 1058   )
    984 1059   message_text = _mess["message_text"]
    985  - original_language = _mess[
    986  - "original_language"
    987  - ]
     1060 + original_language = _mess["original_language"]
    988 1061   translated_text = _mess["translated_text"]
    989 1062   translation_confidence = _mess[
    990 1063   "translation_confidence"
    skipped 12 lines
    1003 1076   if message.views is not None:
    1004 1077   views = int(message.views)
    1005 1078   else:
    1006  - views = 'N/A'
     1079 + views = "N/A"
    1007 1080   
    1008 1081   if message.reactions:
    1009  - total_reactions, reaction_detail = evaluate_reactions(message)
     1082 + (
     1083 + total_reactions,
     1084 + reaction_detail,
     1085 + ) = evaluate_reactions(message)
    1010 1086   
    1011 1087   if self.media_archive:
    1012 1088   if message.media is not None:
    skipped 22 lines
    1035 1111   else:
    1036 1112   edit_date = "None"
    1037 1113   
    1038  - '''Need to find a way to calculate these in case these figures don't exist to make it
     1114 + """Need to find a way to calculate these in case these figures don't exist to make it
    1039 1115   comparable across channels for a total engagement number (e.g. if replies/reactions are off).
    1040  - If not N/A would cover if it's off, zero if it's none. Working on some better logic here.'''
     1116 + If not N/A would cover if it's off, zero if it's none. Working on some better logic here."""
    1041 1117   
    1042  - if reply_count != 'N/A' and self._total_participants is not None:
    1043  - reply_reach_ER = (reply_count / int(self._total_participants)) * 100
     1118 + if (
     1119 + reply_count != "N/A"
     1120 + and self._total_participants is not None
     1121 + ):
     1122 + reply_reach_ER = (
     1123 + reply_count / int(self._total_participants)
     1124 + ) * 100
    1044 1125   else:
    1045  - reply_reach_ER = 'N/A'
     1126 + reply_reach_ER = "N/A"
    1046 1127   
    1047  - if reply_count != 'N/A' and views != 'N/A':
    1048  - reply_impressions_ER = (reply_count / int(views)) * 100
     1128 + if reply_count != "N/A" and views != "N/A":
     1129 + reply_impressions_ER = (
     1130 + reply_count / int(views)
     1131 + ) * 100
    1049 1132   else:
    1050  - reply_impressions_ER = 'N/A'
     1133 + reply_impressions_ER = "N/A"
    1051 1134   
    1052  - if forwards != 'N/A' and self._total_participants is not None:
    1053  - forwards_reach_ER = (forwards / int(self._total_participants)) * 100
     1135 + if (
     1136 + forwards != "N/A"
     1137 + and self._total_participants is not None
     1138 + ):
     1139 + forwards_reach_ER = (
     1140 + forwards / int(self._total_participants)
     1141 + ) * 100
    1054 1142   else:
    1055  - forwards_reach_ER = 'N/A'
     1143 + forwards_reach_ER = "N/A"
    1056 1144   
    1057  - if forwards != 'N/A' and views != 'N/A':
    1058  - forwards_impressions_ER = (forwards / int(views)) * 100
     1145 + if forwards != "N/A" and views != "N/A":
     1146 + forwards_impressions_ER = (
     1147 + forwards / int(views)
     1148 + ) * 100
    1059 1149   else:
    1060  - forwards_impressions_ER = 'N/A'
     1150 + forwards_impressions_ER = "N/A"
    1061 1151   
    1062  - if total_reactions != 'N/A' and self._total_participants is not None:
    1063  - reactions_reach_ER = (total_reactions / int(self._total_participants)) * 100
     1152 + if (
     1153 + total_reactions != "N/A"
     1154 + and self._total_participants is not None
     1155 + ):
     1156 + reactions_reach_ER = (
     1157 + total_reactions / int(self._total_participants)
     1158 + ) * 100
    1064 1159   else:
    1065  - reactions_reach_ER = 'N/A'
     1160 + reactions_reach_ER = "N/A"
    1066 1161   
    1067  - if total_reactions != 'N/A' and views != 'N/A':
    1068  - reactions_impressions_ER = (total_reactions / int(views)) * 100
     1162 + if total_reactions != "N/A" and views != "N/A":
     1163 + reactions_impressions_ER = (
     1164 + total_reactions / int(views)
     1165 + ) * 100
    1069 1166   else:
    1070  - reactions_impressions_ER = 'N/A'
     1167 + reactions_impressions_ER = "N/A"
    1071 1168   
    1072  - post_url = "https://t.me/s/" + _target + "/" + str(message.id)
     1169 + post_url = (
     1170 + "https://t.me/s/" + _target + "/" + str(message.id)
     1171 + )
    1073 1172   
    1074 1173   message_list.append(
    1075 1174   [
    skipped 45 lines
    1121 1220   try:
    1122 1221   forward_count += 1
    1123 1222   to_title = to_ent.title
    1124  - f_from_id = (
    1125  - message.forward.original_fwd.from_id
    1126  - )
     1223 + f_from_id = message.forward.original_fwd.from_id
    1127 1224   
    1128 1225   if f_from_id is not None:
    1129  - ent_info = await self.retrieve_entity_info(f_from_id,True)
     1226 + ent_info = await self.retrieve_entity_info(
     1227 + f_from_id, True
     1228 + )
    1130 1229   result = ""
    1131 1230   username = ent_info["entityt"].username
    1132 1231   if ent_info:
    1133 1232   if ent_info["chat_type"] == "User":
    1134  - result = "User: {} / ID: {} ".format(ent_info[""],ent_info[""])
    1135  - elif ent_info["chat_type"] == "Megagroup" or ent_info["chat_type"] == "Gigagroup" or ent_info["chat_type"] == "Chat":
     1233 + result = (
     1234 + "User: {} / ID: {} ".format(
     1235 + ent_info[""], ent_info[""]
     1236 + )
     1237 + )
     1238 + elif (
     1239 + ent_info["chat_type"] == "Megagroup"
     1240 + or ent_info["chat_type"]
     1241 + == "Gigagroup"
     1242 + or ent_info["chat_type"] == "Chat"
     1243 + ):
    1136 1244   result = ent_info["entity"].title
    1137 1245   elif ent_info["chat_type"] == "Channel":
    1138 1246   result = ent_info["entity"].title
    skipped 73 lines
    1212 1320   if self.reply_analysis is True:
    1213 1321   if len(replies_list) > 0:
    1214 1322   with open(
    1215  - self.reply_file_archive, "w+", encoding="utf-8"
     1323 + self.reply_file_archive, "w+", encoding="utf-8"
    1216 1324   ) as rep_file:
    1217 1325   c_replies.to_csv(rep_file, sep=";")
    1218 1326   
    1219 1327   if len(user_replier_list) > 0:
    1220 1328   with open(
    1221  - self.reply_memberlist_filename, "w+", encoding="utf-8"
     1329 + self.reply_memberlist_filename, "w+", encoding="utf-8"
    1222 1330   ) as repliers_file:
    1223 1331   c_repliers.to_csv(repliers_file, sep=";")
    1224 1332   
    1225  - with open(
    1226  - self.file_archive, "w+", encoding="utf-8"
    1227  - ) as archive_file:
     1333 + with open(self.file_archive, "w+", encoding="utf-8") as archive_file:
    1228 1334   c_archive.to_csv(archive_file, sep=";")
    1229 1335   
    1230 1336   if self.json_check:
    skipped 7 lines
    1238 1344   
    1239 1345   if self.forwards_check:
    1240 1346   with open(
    1241  - self.file_forwards, "w+", encoding="utf-8"
     1347 + self.file_forwards, "w+", encoding="utf-8"
    1242 1348   ) as forwards_file:
    1243 1349   c_forwards.to_csv(forwards_file, sep=";")
    1244 1350   
    skipped 15 lines
    1260 1366   print_shell("channel_stat", report_obj)
    1261 1367   else:
    1262 1368   pvalue_count = c_archive["Display_name"].value_counts()
    1263  - df03 = pvalue_count.rename_axis(
    1264  - "unique_values"
    1265  - ).reset_index(name="counts")
     1369 + df03 = pvalue_count.rename_axis("unique_values").reset_index(
     1370 + name="counts"
     1371 + )
    1266 1372   
    1267  - '''
     1373 + """
    1268 1374   message_frequency_count = {}
    1269 1375   message_text = {}
    1270 1376   word_count = {}
    1271 1377   most_used_words = {}
    1272 1378   most_used_words_filtered = {}
    1273  - '''
     1379 + """
    1274 1380   # message stats, top words
    1275 1381   
    1276 1382   report_obj.poster_one = (
    1277  - str(df03.iloc[0]["unique_values"])
    1278  - + ", "
    1279  - + str(df03.iloc[0]["counts"])
    1280  - + " messages"
     1383 + str(df03.iloc[0]["unique_values"])
     1384 + + ", "
     1385 + + str(df03.iloc[0]["counts"])
     1386 + + " messages"
    1281 1387   )
    1282 1388   report_obj.poster_two = (
    1283  - str(df03.iloc[1]["unique_values"])
    1284  - + ", "
    1285  - + str(df03.iloc[1]["counts"])
    1286  - + " messages"
     1389 + str(df03.iloc[1]["unique_values"])
     1390 + + ", "
     1391 + + str(df03.iloc[1]["counts"])
     1392 + + " messages"
    1287 1393   )
    1288 1394   report_obj.poster_three = (
    1289  - str(df03.iloc[2]["unique_values"])
    1290  - + ", "
    1291  - + str(df03.iloc[2]["counts"])
    1292  - + " messages"
     1395 + str(df03.iloc[2]["unique_values"])
     1396 + + ", "
     1397 + + str(df03.iloc[2]["counts"])
     1398 + + " messages"
    1293 1399   )
    1294 1400   report_obj.poster_four = (
    1295  - str(df03.iloc[3]["unique_values"])
    1296  - + ", "
    1297  - + str(df03.iloc[3]["counts"])
    1298  - + " messages"
     1401 + str(df03.iloc[3]["unique_values"])
     1402 + + ", "
     1403 + + str(df03.iloc[3]["counts"])
     1404 + + " messages"
    1299 1405   )
    1300 1406   report_obj.poster_five = (
    1301  - str(df03.iloc[4]["unique_values"])
    1302  - + ", "
    1303  - + str(df03.iloc[4]["counts"])
    1304  - + " messages"
     1407 + str(df03.iloc[4]["unique_values"])
     1408 + + ", "
     1409 + + str(df03.iloc[4]["counts"])
     1410 + + " messages"
    1305 1411   )
    1306 1412   
    1307 1413   df04 = c_archive.Display_name.unique()
    skipped 10 lines
    1318 1424   
    1319 1425   repliers = createPlaceholdeCls()
    1320 1426   repliers.replier_one = (
    1321  - str(replier_df.iloc[0]["unique_values"])
    1322  - + ", "
    1323  - + str(replier_df.iloc[0]["counts"])
    1324  - + " replies"
     1427 + str(replier_df.iloc[0]["unique_values"])
     1428 + + ", "
     1429 + + str(replier_df.iloc[0]["counts"])
     1430 + + " replies"
    1325 1431   )
    1326 1432   repliers.replier_two = (
    1327  - str(replier_df.iloc[1]["unique_values"])
    1328  - + ", "
    1329  - + str(replier_df.iloc[1]["counts"])
    1330  - + " replies"
     1433 + str(replier_df.iloc[1]["unique_values"])
     1434 + + ", "
     1435 + + str(replier_df.iloc[1]["counts"])
     1436 + + " replies"
    1331 1437   )
    1332 1438   repliers.replier_three = (
    1333  - str(replier_df.iloc[2]["unique_values"])
    1334  - + ", "
    1335  - + str(replier_df.iloc[2]["counts"])
    1336  - + " replies"
     1439 + str(replier_df.iloc[2]["unique_values"])
     1440 + + ", "
     1441 + + str(replier_df.iloc[2]["counts"])
     1442 + + " replies"
    1337 1443   )
    1338 1444   repliers.replier_four = (
    1339  - str(replier_df.iloc[3]["unique_values"])
    1340  - + ", "
    1341  - + str(replier_df.iloc[3]["counts"])
    1342  - + " replies"
     1445 + str(replier_df.iloc[3]["unique_values"])
     1446 + + ", "
     1447 + + str(replier_df.iloc[3]["counts"])
     1448 + + " replies"
    1343 1449   )
    1344 1450   repliers.replier_five = (
    1345  - str(replier_df.iloc[4]["unique_values"])
    1346  - + ", "
    1347  - + str(replier_df.iloc[4]["counts"])
    1348  - + " replies"
     1451 + str(replier_df.iloc[4]["unique_values"])
     1452 + + ", "
     1453 + + str(replier_df.iloc[4]["counts"])
     1454 + + " replies"
    1349 1455   )
    1350 1456   
    1351 1457   replier_count_df = c_repliers["User ID"].unique()
    1352 1458   replier_unique = len(replier_count_df)
    1353 1459   repliers.user_replier_list_len = len(user_replier_list)
    1354 1460   repliers.reply_file_archive = str(self.reply_file_archive)
    1355  - repliers.reply_memberlist_filename = str(self.reply_memberlist_filename)
     1461 + repliers.reply_memberlist_filename = str(
     1462 + self.reply_memberlist_filename
     1463 + )
    1356 1464   repliers.replier_unique = str(replier_unique)
    1357 1465   print_shell("reply_stat", repliers)
    1358 1466   
    skipped 7 lines
    1366 1474   
    1367 1475   report_forward = createPlaceholdeCls()
    1368 1476   report_forward.forward_one = (
    1369  - str(c_f_stats.iloc[0]["unique_values"])
    1370  - + ", "
    1371  - + str(c_f_stats.iloc[0]["counts"])
    1372  - + " forwarded messages"
     1477 + str(c_f_stats.iloc[0]["unique_values"])
     1478 + + ", "
     1479 + + str(c_f_stats.iloc[0]["counts"])
     1480 + + " forwarded messages"
    1373 1481   )
    1374 1482   report_forward.forward_two = (
    1375  - str(c_f_stats.iloc[1]["unique_values"])
    1376  - + ", "
    1377  - + str(c_f_stats.iloc[1]["counts"])
    1378  - + " forwarded messages"
     1483 + str(c_f_stats.iloc[1]["unique_values"])
     1484 + + ", "
     1485 + + str(c_f_stats.iloc[1]["counts"])
     1486 + + " forwarded messages"
    1379 1487   )
    1380 1488   report_forward.forward_three = (
    1381  - str(c_f_stats.iloc[2]["unique_values"])
    1382  - + ", "
    1383  - + str(c_f_stats.iloc[2]["counts"])
    1384  - + " forwarded messages"
     1489 + str(c_f_stats.iloc[2]["unique_values"])
     1490 + + ", "
     1491 + + str(c_f_stats.iloc[2]["counts"])
     1492 + + " forwarded messages"
    1385 1493   )
    1386 1494   report_forward.forward_four = (
    1387  - str(c_f_stats.iloc[3]["unique_values"])
    1388  - + ", "
    1389  - + str(c_f_stats.iloc[3]["counts"])
    1390  - + " forwarded messages"
     1495 + str(c_f_stats.iloc[3]["unique_values"])
     1496 + + ", "
     1497 + + str(c_f_stats.iloc[3]["counts"])
     1498 + + " forwarded messages"
    1391 1499   )
    1392 1500   report_forward.forward_five = (
    1393  - str(c_f_stats.iloc[4]["unique_values"])
    1394  - + ", "
    1395  - + str(c_f_stats.iloc[4]["counts"])
    1396  - + " forwarded messages"
     1501 + str(c_f_stats.iloc[4]["unique_values"])
     1502 + + ", "
     1503 + + str(c_f_stats.iloc[4]["counts"])
     1504 + + " forwarded messages"
    1397 1505   )
    1398 1506   
    1399 1507   c_f_unique = c_forwards.Source.unique()
    skipped 6 lines
    1406 1514   else:
    1407 1515   color_print_green(
    1408 1516   " [!] Insufficient forwarded messages found",
    1409  - self.edgelist_file,
     1517 + self.edgelist_file,
    1410 1518   )
    1411 1519   
    1412 1520   
    skipped 2 lines
    1415 1523   alt = None
    1416 1524   target_type = None
    1417 1525   
    1418  - def __init__(self,target,
    1419  - comprehensive,
    1420  - media,
    1421  - forwards,
    1422  - user,
    1423  - bot,
    1424  - location,
    1425  - alt,
    1426  - json,
    1427  - export,
    1428  - replies,
    1429  - translate,
    1430  - triangulate_membership):
     1526 + def __init__(
     1527 + self,
     1528 + target,
     1529 + comprehensive,
     1530 + media,
     1531 + forwards,
     1532 + user,
     1533 + bot,
     1534 + location,
     1535 + alt,
     1536 + json,
     1537 + export,
     1538 + replies,
     1539 + translate,
     1540 + triangulate_membership,
     1541 + ):
    1431 1542   
    1432 1543   self.config_p = configparser.ConfigParser()
    1433  - self.config_p.read(os.path.join("config","config.ini"))
     1544 + self.config_p.read(os.path.join("config", "config.ini"))
    1434 1545   # Defining default values
    1435 1546   self.user_check = self.location_check = False
    1436 1547   self.basic = True if target else False
    skipped 3 lines
    1440 1551   self.media_archive = True if media else False
    1441 1552   self.json_check = True if json else False
    1442 1553   self.translate_check = True if translate else False
    1443  - self.last_date, self.chunk_size, self.user_language = None, 1000, 'en'
     1554 + self.last_date, self.chunk_size, self.user_language = None, 1000, "en"
    1444 1555   self.bot = bot is not None
    1445 1556   self.alt = alt
    1446 1557   
    skipped 1 lines
    1448 1559   self.filetime_clean = str(self.filetime)
    1449 1560   
    1450 1561   if bot:
    1451  - if ":" in bot:
     1562 + if ":" in bot:
    1452 1563   self.bot_id = bot.split(":")[0]
    1453 1564   self.hash = bot.split(":")[1]
    1454 1565   else:
    1455  - color_print_green(" [!] ", "The bot_id/bot_hash isn't valid. Pls insert a valid api_id//api_hash")
     1566 + color_print_green(
     1567 + " [!] ",
     1568 + "The bot_id/bot_hash isn't valid. Pls insert a valid api_id//api_hash",
     1569 + )
    1456 1570   if user:
    1457 1571   self.user_check, self.basic = True, False
    1458 1572   if location:
    skipped 4 lines
    1463 1577   
    1464 1578   self.triangulate = True if triangulate_membership else False
    1465 1579   self.telepathy_file = self.config_p["telepathy"]["telepathy_files"]
    1466  - self.json_file = os.path.join(self.telepathy_file, self.config_p["telepathy"]["json_file"])
    1467  - self.login = os.path.join(self.telepathy_file, self.config_p["telepathy"]["login"])
    1468  - self.log_file = os.path.join(self.telepathy_file, self.config_p["telepathy"]["log_file"])
    1469  - self.export_file = os.path.join(self.telepathy_file,self.config_p["telepathy"]["export_file"])
     1580 + self.json_file = os.path.join(
     1581 + self.telepathy_file, self.config_p["telepathy"]["json_file"]
     1582 + )
     1583 + self.login = os.path.join(
     1584 + self.telepathy_file, self.config_p["telepathy"]["login"]
     1585 + )
     1586 + self.log_file = os.path.join(
     1587 + self.telepathy_file, self.config_p["telepathy"]["log_file"]
     1588 + )
     1589 + self.export_file = os.path.join(
     1590 + self.telepathy_file, self.config_p["telepathy"]["export_file"]
     1591 + )
    1470 1592   self.create_path(self.telepathy_file)
    1471 1593   self.target = target
    1472 1594   self.create_tg_client()
    skipped 14 lines
    1487 1609   @staticmethod
    1488 1610   def clean_private_invite(url):
    1489 1611   if "https://t.me/+" in url:
    1490  - return(url.replace('https://t.me/+', 'https://t.me/joinchat/'))
     1612 + return url.replace("https://t.me/+", "https://t.me/joinchat/")
    1491 1613   
    1492 1614   def retrieve_alt(self):
    1493 1615   with open(self.login, encoding="utf-8") as file:
    skipped 7 lines
    1501 1623   except:
    1502 1624   _api_id, _api_hash, _phone_number = self.login_function()
    1503 1625   with open(self.login, "a+", encoding="utf-8") as file_io:
    1504  - file_io.write(_api_id + "," + _api_hash + "," + _phone_number + "\n")
     1626 + file_io.write(
     1627 + _api_id + "," + _api_hash + "," + _phone_number + "\n"
     1628 + )
    1505 1629   return _api_id, _api_hash, _phone_number
     1630 + 
    1506 1631   def create_tg_client(self):
    1507 1632   if os.path.isfile(self.login) == False:
    1508 1633   api_id, api_hash, phone_number = self.login_function()
    1509 1634   with open(self.login, "w+", encoding="utf-8") as f:
    1510 1635   f.write(api_id + "," + api_hash + "," + phone_number + "\n")
    1511 1636   else:
    1512  - self.api_id, self.api_hash, self.phone_number = self.retrieve_alt()
    1513  - '''End of API details'''
     1637 + self.api_id, self.api_hash, self.phone_number = self.retrieve_alt()
     1638 + """End of API details"""
    1514 1639   self.client = TelegramClient(self.phone_number, self.api_id, self.api_hash)
    1515 1640   
    1516 1641   async def connect_tg_client_and_run(self):
    skipped 22 lines
    1539 1664   )
    1540 1665   )
    1541 1666   await self.start_process()
     1667 + 
    1542 1668   async def start_process(self):
    1543 1669   if self.location_check:
    1544 1670   for _t in self.target:
    skipped 4 lines
    1549 1675   else:
    1550 1676   for _t in self.target:
    1551 1677   if self.export:
    1552  - print("message export")
    1553  - ###TODO
     1678 + group_channel = Group_Chat_Analisys(
     1679 + _t,
     1680 + self.client,
     1681 + self.log_file,
     1682 + self.filetime,
     1683 + self.reply_analysis,
     1684 + self.forwards_check,
     1685 + self.comp_check,
     1686 + self.media_archive,
     1687 + self.json_check,
     1688 + self.translate_check,
     1689 + )
     1690 + await group_channel.f_export()
    1554 1691   else:
    1555  - print("message process")
    1556  - ###TODO
     1692 + group_channel = Group_Chat_Analisys(
     1693 + _t,
     1694 + self.client,
     1695 + self.log_file,
     1696 + self.filetime,
     1697 + self.reply_analysis,
     1698 + self.forwards_check,
     1699 + self.comp_check,
     1700 + self.media_archive,
     1701 + self.json_check,
     1702 + self.translate_check,
     1703 + )
     1704 + await group_channel.analyze_group_channel()
    1557 1705   
    1558  - async def analyze_location(self,_target):
     1706 + async def analyze_location(self, _target):
    1559 1707   print(
    1560 1708   Fore.GREEN
    1561 1709   + " [!] "
    skipped 5 lines
    1567 1715   
    1568 1716   latitude, longitude = _target.split(sep=",")
    1569 1717   
    1570  - locations_file = self.create_path(os.path.join(self.telepathy_file,self.config_p["telepathy"]["location"]))
     1718 + locations_file = self.create_path(
     1719 + os.path.join(self.telepathy_file, self.config_p["telepathy"]["location"])
     1720 + )
    1571 1721   save_file = (
    1572  - locations_file
    1573  - + latitude
    1574  - + "_"
    1575  - + longitude
    1576  - + "_"
    1577  - + "locations_"
    1578  - + self.filetime_clean
    1579  - + ".csv"
     1722 + locations_file
     1723 + + latitude
     1724 + + "_"
     1725 + + longitude
     1726 + + "_"
     1727 + + "locations_"
     1728 + + self.filetime_clean
     1729 + + ".csv"
    1580 1730   )
    1581 1731   
    1582 1732   locations_list = []
    skipped 10 lines
    1593 1743   )
    1594 1744   )
    1595 1745   
    1596  - user_df = pd.DataFrame(
    1597  - locations_list, columns=[
    1598  - "User_ID",
    1599  - "Distance"]
    1600  - )
     1746 + user_df = pd.DataFrame(locations_list, columns=["User_ID", "Distance"])
    1601 1747   
    1602 1748   l_save_df = pd.DataFrame(
    1603  - l_save_list, columns=[
    1604  - "User_ID",
    1605  - "Distance",
    1606  - "Latitude",
    1607  - "Longitude",
    1608  - "Date_retrieved"
    1609  - ]
     1749 + l_save_list,
     1750 + columns=["User_ID", "Distance", "Latitude", "Longitude", "Date_retrieved"],
    1610 1751   )
    1611 1752   
    1612 1753   for user in result.updates[0].peers:
    skipped 7 lines
    1620 1761   distance = user.distance
    1621 1762   
    1622 1763   locations_list.append([ID, distance])
    1623  - l_save_list.append(
    1624  - [
    1625  - ID,
    1626  - distance,
    1627  - latitude,
    1628  - longitude,
    1629  - self.filetime
    1630  - ]
    1631  - )
     1764 + l_save_list.append([ID, distance, latitude, longitude, self.filetime])
    1632 1765   except:
    1633 1766   pass
    1634 1767   
    skipped 30 lines
    1665 1798   _bot_id = self.bot.split(":")[0]
    1666 1799   _bot_hash = self.bot.split(":")[1]
    1667 1800   else:
    1668  - color_print_green(" [!] ", "The bot_id/bot_hash isn't valid. Pls insert a valid api_id//api_hash")
     1801 + color_print_green(
     1802 + " [!] ",
     1803 + "The bot_id/bot_hash isn't valid. Pls insert a valid api_id//api_hash",
     1804 + )
     1805 + 
    1669 1806   async def analyze_user(self, _target):
    1670 1807   my_user = None
    1671 1808   self.target_type = "u"
    skipped 7 lines
    1679 1816   user_first_name = my_user.first_name
    1680 1817   user_last_name = my_user.last_name
    1681 1818   if user_last_name is not None:
    1682  - user_full_name = (
    1683  - str(user_first_name)
    1684  - + " "
    1685  - + str(user_last_name)
    1686  - )
     1819 + user_full_name = str(user_first_name) + " " + str(user_last_name)
    1687 1820   else:
    1688 1821   user_full_name = str(user_first_name)
    1689 1822   
    skipped 24 lines
    1714 1847   if 1 in my_user.restriction_reason:
    1715 1848   android_restriction = my_user.restriction_reason[1]
    1716 1849   user_restrictions = (
    1717  - str(ios_restriction)
    1718  - + ", "
    1719  - + str(android_restriction)
     1850 + str(ios_restriction) + ", " + str(android_restriction)
    1720 1851   )
    1721 1852   else:
    1722 1853   user_restrictions = str(ios_restriction)
    skipped 23 lines
    1746 1877  @click.option(
    1747 1878   "--target",
    1748 1879   "-t",
    1749  - multiple = True,
    1750  - help = "Specifies a chat to investigate.",
    1751  - )
     1880 + multiple=True,
     1881 + help="Specifies a chat to investigate.",
     1882 +)
    1752 1883  @click.option(
    1753 1884   "--bot",
    1754 1885   "-b",
    1755  - multiple = True,
    1756  - help = "BOT info, analyzing bot info, it needs API_HASH:API_ID.",
    1757  - )
     1886 + multiple=True,
     1887 + help="BOT info, analyzing bot info, it needs API_HASH:API_ID.",
     1888 +)
    1758 1889  @click.option(
    1759 1890   "--comprehensive",
    1760 1891   "-c",
    1761  - is_flag = True,
    1762  - help = "Comprehensive scan, includes archiving.",
    1763  - )
    1764  -@click.option(
    1765  - "--media",
    1766  - "-m",
    1767  - is_flag = True,
    1768  - help = "Archives media in the specified chat."
    1769  - )
    1770  -@click.option(
    1771  - "--forwards",
    1772  - "-f",
    1773  - is_flag = True,
    1774  - help = "Scrapes forwarded messages."
    1775  - )
    1776  -@click.option(
    1777  - "--user",
    1778  - "-u",
    1779  - is_flag = True,
    1780  - help = "Looks up a specified user ID."
    1781  - )
    1782  -@click.option(
    1783  - "--location",
    1784  - "-l",
    1785  - is_flag = True,
    1786  - help = "Finds users near to specified coordinates."
    1787  - )
     1892 + is_flag=True,
     1893 + help="Comprehensive scan, includes archiving.",
     1894 +)
    1788 1895  @click.option(
    1789  - "--alt",
    1790  - "-a",
    1791  - default = 0,
    1792  - help = "Uses an alternative login."
    1793  - )
     1896 + "--media", "-m", is_flag=True, help="Archives media in the specified chat."
     1897 +)
     1898 +@click.option("--forwards", "-f", is_flag=True, help="Scrapes forwarded messages.")
     1899 +@click.option("--user", "-u", is_flag=True, help="Looks up a specified user ID.")
    1794 1900  @click.option(
    1795  - "--json",
    1796  - "-j",
    1797  - is_flag = True,
    1798  - default = False,
    1799  - help = "Export to JSON."
    1800  - )
     1901 + "--location", "-l", is_flag=True, help="Finds users near to specified coordinates."
     1902 +)
     1903 +@click.option("--alt", "-a", default=0, help="Uses an alternative login.")
     1904 +@click.option("--json", "-j", is_flag=True, default=False, help="Export to JSON.")
    1801 1905  @click.option(
    1802 1906   "--export",
    1803 1907   "-e",
    1804  - is_flag = True,
    1805  - default = False,
    1806  - help = "Export a list of chats your account is part of.",
    1807  - )
     1908 + is_flag=True,
     1909 + default=False,
     1910 + help="Export a list of chats your account is part of.",
     1911 +)
    1808 1912  @click.option(
    1809 1913   "--replies",
    1810 1914   "-r",
    1811  - is_flag = True,
    1812  - default = False,
    1813  - help = "Enable replies analysis in channels.",
    1814  - )
     1915 + is_flag=True,
     1916 + default=False,
     1917 + help="Enable replies analysis in channels.",
     1918 +)
    1815 1919  @click.option(
    1816 1920   "--translate",
    1817 1921   "-tr",
    1818  - is_flag = True,
    1819  - default = False,
    1820  - help = "Enable translation of chat content.",
    1821  - )
     1922 + is_flag=True,
     1923 + default=False,
     1924 + help="Enable translation of chat content.",
     1925 +)
    1822 1926  @click.option(
    1823 1927   "--triangulate_membership",
    1824 1928   "-tm",
    1825 1929   is_flag=True,
    1826 1930   default=False,
    1827  - help = "Get interpolation from a list of groups",
    1828  - )
     1931 + help="Get interpolation from a list of groups",
     1932 +)
    1829 1933  def cli(
    1830 1934   target,
    1831 1935   comprehensive,
    skipped 7 lines
    1839 1943   export,
    1840 1944   replies,
    1841 1945   translate,
    1842  - triangulate_membership
    1843  - ):
    1844  - telepathy_cli = Telepathy_cli(target,comprehensive,media,forwards,user,bot,location,alt,json,export,replies,translate,triangulate_membership)
     1946 + triangulate_membership,
     1947 +):
     1948 + telepathy_cli = Telepathy_cli(
     1949 + target,
     1950 + comprehensive,
     1951 + media,
     1952 + forwards,
     1953 + user,
     1954 + bot,
     1955 + location,
     1956 + alt,
     1957 + json,
     1958 + export,
     1959 + replies,
     1960 + translate,
     1961 + triangulate_membership,
     1962 + )
    1845 1963   loop = asyncio.get_event_loop()
    1846 1964   loop.run_until_complete(telepathy_cli.connect_tg_client_and_run())
     1965 + 
    1847 1966   
    1848 1967  if __name__ == "__main__":
    1849 1968   cli()
     1969 + 
  • ■ ■ ■ ■ ■ ■
    src/telepathy/utils.py
    skipped 6 lines
    7 7  import random
    8 8  import os
    9 9   
     10 + 
    10 11  def createPlaceholdeCls():
    11 12   class Object(object):
    12 13   pass
     14 + 
    13 15   a = Object()
    14 16   return a
     17 + 
    15 18   
    16 19  def print_banner():
    17 20   print(
    skipped 6 lines
    24 27   /_/ \___/_/\___/ .___/\__,_/\__/_/ /_/\__, /
    25 28   /_/ /____/
    26 29   -- An OSINT toolkit for investigating Telegram chats.
    27  - -- Developed by @jordanwildon | Version """ + __version__ + """.
    28  - """ + Style.RESET_ALL
     30 + -- Developed by @jordanwildon | Version """
     31 + + __version__
     32 + + """.
     33 + """
     34 + + Style.RESET_ALL
    29 35   )
    30  - 
    31 36   
    32 37   
    33 38  def parse_tg_date(dd):
    skipped 6 lines
    40 45   date = year + "-" + month + "-" + day
    41 46   mtime = hour + ":" + minute + ":" + second
    42 47   timestamp = date + "T" + mtime + "+00:00"
    43  - return {"timestamp":timestamp, "date":date, "mtime":mtime}
     48 + return {"timestamp": timestamp, "date": date, "mtime": mtime}
    44 49   
    45 50   
    46 51  def populate_user(user, group_or_chat):
    skipped 47 lines
    94 99   "message_text": mess_txt,
    95 100   }
    96 101   
     102 + 
    97 103  def process_description(desc, user_lang):
    98 104   if desc is not None:
    99 105   desc_txt = '"' + desc + '"'
    skipped 19 lines
    119 125   "description_text": desc_txt,
    120 126   }
    121 127   
    122  -def color_print_green(first_string,second_string):
    123  - print(
    124  - Fore.GREEN
    125  - + first_string
    126  - + Style.RESET_ALL
    127  - + second_string
    128  - )
     128 + 
     129 +def color_print_green(first_string, second_string):
     130 + print(Fore.GREEN + first_string + Style.RESET_ALL + second_string)
     131 + 
    129 132   
    130 133  def parse_html_page(url):
    131 134   s = requests.Session()
    skipped 7 lines
    139 142   group_description = ""
    140 143   total_participants = ""
    141 144   try:
    142  - name = soup.find(
    143  - "div", {"class": ["tgme_page_title"]}
    144  - ).text
     145 + name = soup.find("div", {"class": ["tgme_page_title"]}).text
    145 146   except:
    146 147   name = "Not found"
    147 148   try:
    148  - group_description = soup.find(
    149  - "div", {"class": ["tgme_page_description"]}
    150  - ).text
    151  - descript = Fore.GREEN + "Description: " + Style.RESET_ALL+ group_description
     149 + group_description = soup.find("div", {"class": ["tgme_page_description"]}).text
     150 + descript = Fore.GREEN + "Description: " + Style.RESET_ALL + group_description
    152 151   except:
    153 152   group_description = "None"
    154  - descript = Fore.GREEN + "Description: " + Style.RESET_ALL+ group_description
     153 + descript = Fore.GREEN + "Description: " + Style.RESET_ALL + group_description
    155 154   
    156 155   try:
    157  - group_participants = soup.find(
    158  - "div", {"class": ["tgme_page_extra"]}
    159  - ).text
     156 + group_participants = soup.find("div", {"class": ["tgme_page_extra"]}).text
    160 157   sep = "members"
    161 158   stripped = group_participants.split(sep, 1)[0]
    162 159   total_participants = (
    skipped 4 lines
    167 164   )
    168 165   except:
    169 166   total_participants = "Not found"
    170  - return {"name":name,"group_description":group_description, "total_participants":total_participants}
     167 + return {
     168 + "name": name,
     169 + "group_description": group_description,
     170 + "total_participants": total_participants,
     171 + }
    171 172   
    172 173   
    173 174  def generate_textwrap(text_string, size=70):
    skipped 5 lines
    179 180   subsequent_indent=" ",
    180 181   )
    181 182   
     183 + 
    182 184  def print_shell(type, obj):
    183 185   if type == "user":
    184 186   color_print_green(" [+] ", "User details for " + obj.target)
    skipped 2 lines
    187 189   color_print_green(" ├ Verification: ", str(obj.verified))
    188 190   color_print_green(" ├ Photo ID: ", str(obj.user_photo))
    189 191   color_print_green(" ├ Phone number: ", str(obj.phone))
    190  - color_print_green(
    191  - " ├ Access hash: ", str(obj.access_hash)
    192  - )
     192 + color_print_green(" Access hash: ", str(obj.access_hash))
    193 193   color_print_green(" ├ Language: ", str(obj.lang_code))
    194 194   color_print_green(" ├ Bot: ", str(obj.bot))
    195 195   color_print_green(" ├ Scam: ", str(obj.scam))
    skipped 18 lines
    214 214   color_print_green(" ├ ", d_wrapper.fill(obj.group_description))
    215 215   if obj.translated_description != obj.group_description:
    216 216   color_print_green(" ├ ", td_wrapper.fill(obj.translated_description))
    217  - color_print_green(
    218  - " ├ Total participants: ", str(obj.total_participants)
    219  - )
     217 + color_print_green(" ├ Total participants: ", str(obj.total_participants))
    220 218   
    221 219   if type == "group_recap":
    222 220   color_print_green(
    skipped 9 lines
    232 230   color_print_green(" ├ Chat type: ", str(obj.chat_type))
    233 231   color_print_green(" ├ Chat id: ", str(obj.id))
    234 232   color_print_green(" ├ Access hash: ", str(obj.access_hash))
    235  - if type == "channel_recap":
     233 + if type == "channel_recap":
    236 234   scam_status = str(obj.scam)
    237 235   color_print_green(" ├ Scam: ", str(scam_status))
    238 236   color_print_green(" ├ First post date: ", str(obj.first_post))
    239 237   if type == "group_recap":
    240  - color_print_green(
    241  - " ├ Memberlist saved to: ", obj.memberlist_filename
    242  - )
    243  - color_print_green(
    244  - " └ Restrictions: ", (str(obj.group_status))
    245  - )
     238 + color_print_green(" ├ Memberlist saved to: ", obj.memberlist_filename)
     239 + color_print_green(" └ Restrictions: ", (str(obj.group_status)))
    246 240   
    247 241   if type == "group_stat":
    248 242   color_print_green(" [+] Chat archive saved", "")
    249 243   color_print_green(" ┬ Chat statistics", "")
    250  - color_print_green(
    251  - " ├ Number of messages found: ", str(obj.messages_found)
    252  - )
    253  - color_print_green(
    254  - " ├ Top poster 1: ", str(obj.poster_one)
    255  - )
    256  - color_print_green(
    257  - " ├ Top poster 2: ", str(obj.poster_two)
    258  - )
    259  - color_print_green(
    260  - " ├ Top poster 3: ", str(obj.poster_three)
    261  - )
    262  - color_print_green(
    263  - " ├ Top poster 4: ", str(obj.poster_four)
    264  - )
    265  - color_print_green(
    266  - " ├ Top poster 5: ", str(obj.poster_five)
    267  - )
    268  - color_print_green(
    269  - " ├ Total unique posters: ", str(obj.unique_active)
    270  - )
    271  - color_print_green(
    272  - " └ Archive saved to: ", str(obj.file_archive)
    273  - )
     244 + color_print_green(" ├ Number of messages found: ", str(obj.messages_found))
     245 + color_print_green(" ├ Top poster 1: ", str(obj.poster_one))
     246 + color_print_green(" ├ Top poster 2: ", str(obj.poster_two))
     247 + color_print_green(" ├ Top poster 3: ", str(obj.poster_three))
     248 + color_print_green(" ├ Top poster 4: ", str(obj.poster_four))
     249 + color_print_green(" ├ Top poster 5: ", str(obj.poster_five))
     250 + color_print_green(" ├ Total unique posters: ", str(obj.unique_active))
     251 + color_print_green(" └ Archive saved to: ", str(obj.file_archive))
    274 252   return
    275 253   
    276 254   if type == "channel_stat":
    277 255   color_print_green(" [+] Channel archive saved", "")
    278 256   color_print_green(" ┬ Channel statistics", "")
    279  - color_print_green(
    280  - " ├ Number of messages found: ", str(obj.messages_found)
    281  - )
    282  - color_print_green(
    283  - " └ Archive saved to: ", str(obj.file_archive)
    284  - )
     257 + color_print_green(" ├ Number of messages found: ", str(obj.messages_found))
     258 + color_print_green(" └ Archive saved to: ", str(obj.file_archive))
    285 259   return
    286 260   
    287 261   if type == "reply_stat":
    skipped 12 lines
    300 274   " └ Active members list who replied to messages, saved to: ",
    301 275   str(obj.reply_memberlist_filename),
    302 276   )
    303  - color_print_green(
    304  - " Top replier 1: ", str(obj.replier_one)
    305  - )
    306  - color_print_green(
    307  - " ├ Top replier 2: ", str(obj.replier_two)
    308  - )
    309  - color_print_green(
    310  - " ├ Top replier 3: ", str(obj.replier_three)
    311  - )
    312  - color_print_green(
    313  - " ├ Top replier 4: ", str(obj.replier_four)
    314  - )
    315  - color_print_green(
    316  - " ├ Top replier 5: ", str(obj.replier_five)
    317  - )
    318  - color_print_green(
    319  - " └ Total unique repliers: ", str(obj.replier_unique)
    320  - )
     277 + color_print_green(" ┬ Top replier 1: ", str(obj.replier_one))
     278 + color_print_green(" Top replier 2: ", str(obj.replier_two))
     279 + color_print_green(" ├ Top replier 3: ", str(obj.replier_three))
     280 + color_print_green(" ├ Top replier 4: ", str(obj.replier_four))
     281 + color_print_green(" ├ Top replier 5: ", str(obj.replier_five))
     282 + color_print_green(" └ Total unique repliers: ", str(obj.replier_unique))
    321 283   
    322 284   if type == "forwarder_stat":
    323 285   color_print_green(" [+] Forward scrape complete", "")
    324 286   color_print_green(" ┬ Statistics", "")
    325  - color_print_green(
    326  - " ├ Forwarded messages found: ", str(obj.forward_count)
    327  - )
     287 + color_print_green(" ├ Forwarded messages found: ", str(obj.forward_count))
    328 288   color_print_green(
    329 289   " ├ Forwards from active public chats: ",
    330 290   str(obj.forwards_found),
    skipped 3 lines
    334 294   " ├ Forwards from private (or now private) chats: ",
    335 295   str(obj.private_count),
    336 296   )
    337  - color_print_green(
    338  - " ├ Unique forward sources: ", str(obj.unique_forwards)
    339  - )
    340  - color_print_green(
    341  - " ├ Top forward source 1: ", str(obj.forward_one)
    342  - )
    343  - color_print_green(
    344  - " ├ Top forward source 2: ", str(obj.forward_two)
    345  - )
    346  - color_print_green(
    347  - " ├ Top forward source 3: ", str(obj.forward_three)
    348  - )
    349  - color_print_green(
    350  - " ├ Top forward source 4: ", str(obj.forward_four)
    351  - )
    352  - color_print_green(
    353  - " ├ Top forward source 5: ", str(obj.forward_five)
    354  - )
     297 + color_print_green(" ├ Unique forward sources: ", str(obj.unique_forwards))
     298 + color_print_green(" ├ Top forward source 1: ", str(obj.forward_one))
     299 + color_print_green(" ├ Top forward source 2: ", str(obj.forward_two))
     300 + color_print_green(" ├ Top forward source 3: ", str(obj.forward_three))
     301 + color_print_green(" ├ Top forward source 4: ", str(obj.forward_four))
     302 + color_print_green(" ├ Top forward source 5: ", str(obj.forward_five))
    355 303   color_print_green(" └ Edgelist saved to: ", obj.edgelist_file)
     304 + 
    356 305   
    357 306  def create_path(path_d):
    358 307   if not os.path.exists(path_d):
    359 308   os.makedirs(path_d)
    360 309   return path_d
    361 310   
    362  -def create_file_report(save_dir,name,type,extension,file_time,append_time=True):
     311 + 
     312 +def create_file_report(save_dir, name, type, extension, file_time, append_time=True):
    363 313   _time_append = ""
    364 314   if append_time:
    365  - _time_append = "_"+file_time
    366  - return os.path.join("{}".format(save_dir),"{}{}_{}.{}".format(name,_time_append,type,extension))
     315 + _time_append = "_" + file_time
     316 + return os.path.join(
     317 + "{}".format(save_dir), "{}{}_{}.{}".format(name, _time_append, type, extension)
     318 + )
     319 + 
    367 320   
    368 321  def clean_private_invite(url):
    369 322   if "https://t.me/+" in url:
    370  - return(url.replace('https://t.me/+', 'https://t.me/joinchat/'))
     323 + return url.replace("https://t.me/+", "https://t.me/joinchat/")
     324 + 
    371 325   
    372 326  def evaluate_reactions(message):
    373 327   total_reactions = 0
    skipped 3 lines
    377 331   i = range(len(reactions))
    378 332   for idx, i in enumerate(reactions):
    379 333   total_reactions = total_reactions + i.count
    380  - reactions["thumbs_up"] = i.count if i.reaction == '��' else 0
    381  - reactions["thumbs_down"] = i.count if i.reaction == '��' else 0
    382  - reactions["heart"] = i.count if i.reaction == '❤️' else 0
    383  - reactions["fire"] = i.count if i.reaction == '��' else 0
    384  - reactions["smile_with_hearts"] = i.count if i.reaction == '��' else 0
    385  - reactions["clap"] = i.count if i.reaction == '��' else 0
    386  - reactions["smile"] = i.count if i.reaction == '��' else 0
    387  - reactions["thinking"] = i.count if i.reaction == '��' else 0
    388  - reactions["exploding_head"] = i.count if i.reaction == '��' else 0
    389  - reactions["scream"] = i.count if i.reaction == '��' else 0
    390  - reactions["angry"] = i.count if i.reaction == '��' else 0
    391  - reactions["single_tear"] = i.count if i.reaction == '��' else 0
    392  - reactions["party_popper"] = i.count if i.reaction == '��' else 0
    393  - reactions["starstruck"] = i.count if i.reaction == '��' else 0
    394  - reactions["vomiting"] = i.count if i.reaction == '��' else 0
    395  - reactions["poop"] = i.count if i.reaction == '��' else 0
    396  - reactions["praying"] = i.count if i.reaction == '��' else 0
     334 + reactions["thumbs_up"] = i.count if i.reaction == "��" else 0
     335 + reactions["thumbs_down"] = i.count if i.reaction == "��" else 0
     336 + reactions["heart"] = i.count if i.reaction == "❤️" else 0
     337 + reactions["fire"] = i.count if i.reaction == "��" else 0
     338 + reactions["smile_with_hearts"] = i.count if i.reaction == "��" else 0
     339 + reactions["clap"] = i.count if i.reaction == "��" else 0
     340 + reactions["smile"] = i.count if i.reaction == "��" else 0
     341 + reactions["thinking"] = i.count if i.reaction == "��" else 0
     342 + reactions["exploding_head"] = i.count if i.reaction == "��" else 0
     343 + reactions["scream"] = i.count if i.reaction == "��" else 0
     344 + reactions["angry"] = i.count if i.reaction == "��" else 0
     345 + reactions["single_tear"] = i.count if i.reaction == "��" else 0
     346 + reactions["party_popper"] = i.count if i.reaction == "��" else 0
     347 + reactions["starstruck"] = i.count if i.reaction == "��" else 0
     348 + reactions["vomiting"] = i.count if i.reaction == "��" else 0
     349 + reactions["poop"] = i.count if i.reaction == "��" else 0
     350 + reactions["praying"] = i.count if i.reaction == "��" else 0
    397 351   else:
    398  - reactions["total_reactions"] = 'N/A'
    399  - reactions["thumbs_up"] = 'N/A'
    400  - reactions["thumbs_down"] = 'N/A'
    401  - reactions["heart"] = 'N/A'
    402  - reactions["fire"] = 'N/A'
    403  - reactions["smile_with_hearts"] = 'N/A'
    404  - reactions["clap"] = 'N/A'
    405  - reactions["smile"] = 'N/A'
    406  - reactions["thinking"] = 'N/A'
    407  - reactions["exploding_head"] = 'N/A'
    408  - reactions["scream"] = 'N/A'
    409  - reactions["angry"] = 'N/A'
    410  - reactions["single_tear"] = 'N/A'
    411  - reactions["party_popper"] = 'N/A'
    412  - reactions["starstruck"] = 'N/A'
    413  - reactions["vomiting"] = 'N/A'
    414  - reactions["poop"] = 'N/A'
    415  - reactions["praying"] = 'N/A'
     352 + reactions["total_reactions"] = "N/A"
     353 + reactions["thumbs_up"] = "N/A"
     354 + reactions["thumbs_down"] = "N/A"
     355 + reactions["heart"] = "N/A"
     356 + reactions["fire"] = "N/A"
     357 + reactions["smile_with_hearts"] = "N/A"
     358 + reactions["clap"] = "N/A"
     359 + reactions["smile"] = "N/A"
     360 + reactions["thinking"] = "N/A"
     361 + reactions["exploding_head"] = "N/A"
     362 + reactions["scream"] = "N/A"
     363 + reactions["angry"] = "N/A"
     364 + reactions["single_tear"] = "N/A"
     365 + reactions["party_popper"] = "N/A"
     366 + reactions["starstruck"] = "N/A"
     367 + reactions["vomiting"] = "N/A"
     368 + reactions["poop"] = "N/A"
     369 + reactions["praying"] = "N/A"
    416 370   return total_reactions, reactions
    417 371   
    418  - 
Please wait...
Page is in error, reload to recover