diff --git a/src/main.py b/src/main.py index 91efacd..5b8a39c 100755 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from telethon import TelegramClient, sync +from telethon.tl.types import User from timeit import default_timer as timer import configparser import out @@ -7,6 +8,7 @@ import math, datetime import colorama from colorama import Fore, Style + class Stat: name = None @@ -42,10 +44,13 @@ class Countable(Stat): min = 1 << 31 max = 0 - """def getValue(self, count): - return "Min: " + self.getMin() + " Max: " + self.getMax() + " Gesamt: " \ - + self.getAcc() + " Avg: " + self.getAvg(count) + " Geom.Avg: " + self.getGAvg() - """ + def __init__(self, name): + self.acc = 0 + self.mult = 0 + self.min = 1 << 31 + self.max = 0 + super().__init__(name) + def getMin(self): return self.parse(self.min) @@ -62,7 +67,8 @@ class Countable(Stat): return self.parse(math.sqrt(self.mult)) def getAll(self, count): - return {'min': self.getMin(), 'max': self.getMax(), 'count': self.getAcc(), 'avg': self.getAvg(count), 'gavg': self.getGAvg()} + return {'min': self.getMin(), 'max': self.getMax(), 'count': self.getAcc(), 'avg': self.getAvg(count), + 'gavg': self.getGAvg()} def addMsg(self, msgnum, msg, chat): count = self.count(msgnum, msg, chat) @@ -92,6 +98,7 @@ class Dist(Countable): prev = 0 def __init__(self, name: str = "Distanz"): + self.prev = 0 super().__init__(name) def count(self, msgnum, msg, chat): @@ -108,20 +115,16 @@ class Dist(Countable): def getAvg(self, count): if count < 2: return -1 - return self.parse(int(self.acc / (count-1))) # da hier die abstΓ€nde zwischen nachrichten betrachtet werden ist es um 1 kleiner + return self.parse(int( + self.acc / (count - 1))) # da hier die abstΓ€nde zwischen nachrichten betrachtet werden ist es um 1 kleiner class DiscreteCount(Stat): list = {} - """def getValue(self, count): - out = '' - # sorted_ = sorted(list.items(), key=lambda kv: kv[1]) - for name, count in self.list.items(): - if len(out) > 0: - out = out + ", " - out = out + name + ": " + str(count) - return out;""" + def __init__(self, name): + self.list = {} + super().__init__(name) def getAll(self, count): return self.list @@ -137,7 +140,6 @@ class UserCount(DiscreteCount): fromid = msg.from_id self.list[fromid] = self.list.get(fromid, 0) + 1 - def getAll(self, count): # replace ids with names newdict = {} @@ -151,7 +153,19 @@ def printDialog(interid, d): # debug only color = '' if interid & 1: color = Fore.LIGHTBLACK_EX - print(color + '{0:3d}| {1:14d} | {2:30} | {3:1}'.format(interid, d.id, d.name, d.pinned) + Fore.RESET) + print(color + '{0:3d}| {1:14d} | {2:30} | {3:1}'.format(interid, d.id, getDialogType(d) + d.name, + d.pinned) + Fore.RESET) + + +def getDialogType(dialog): + if dialog.id < 0: # group + return 'πŸ‘₯' + + ent = dialog.entity + if isinstance(ent, User): + if ent.bot: + return 'πŸ€–' + return 'πŸ‘€' def getUsernamebyID(userid): @@ -161,12 +175,39 @@ def getUsernamebyID(userid): return d.name return "Unknown" # refresh dialog cache? + +def dialogByTgID(tgid): + global dialogs + for d in dialogs: + if d.id == tgid: + return d + return None + + +def dialogByTgName(name): + name = name.lower() + global dialogs + for d in dialogs: + if d.name.lower() == name: + return d + return None + + def analyseChat(dialog, output): print(Fore.GREEN + 'Lade kompletten Chat: ' + Fore.RESET, dialog.name, sep='') # chat = client.get_messages(selectedDialog) chat = client.iter_messages(dialog, limit=None) + stats = { + CharCount(), + Dist(), + UserCount() + } + """print('before' + Fore.MAGENTA) + outputs['stdout'].print(stats, 10, dialog) + print(Fore.RESET + 'after' + Fore.BLUE)""" + # run messure msgnum = 0 for msg in chat: @@ -180,15 +221,41 @@ def analyseChat(dialog, output): # write to output output.print(stats, msgnum, dialog) + +def parseInput(uinput): + selected = [] + if uinput == 'all': + selected = dialogs + else: + splited = uinput.split(',') + for entry in splited: + entry = entry.strip() + if not entry: # empty string + continue + if entry.isnumeric(): + get = int(entry) + if get >= 0 and get < dialogCount: # use id + selected.append(dialogs[get]) + continue + + # search by id + bytgid = dialogByTgID(get) + if bytgid is not None: + selected.append(bytgid) + continue + # search by name + bytgname = dialogByTgName(entry) + if bytgname is not None: + selected.append(bytgname) + continue + print(Fore.YELLOW + 'Kein Chat fΓΌr Eingabe gefunden: ' + Fore.BLUE, entry, Fore.RESET) + raise ValueError('unknown chat') + return selected + + # ================================== # MAIN program if __name__ == "__main__": - stats = { - CharCount(), - Dist(), - UserCount() - } - outputs = { "stdout": out.STDOUT(), "json": out.jsonOut() @@ -217,7 +284,7 @@ if __name__ == "__main__": dialogCount = len(dialogs) print(Fore.YELLOW, dialogCount, Fore.GREEN + 'Chats geladen.' + Fore.RESET) - #select output + # select output while True: uinput = input("Bitte Ausgabemethode wΓ€hlen: [stdout,json] (stdout): ").strip().lower(); if uinput == "": @@ -233,27 +300,31 @@ if __name__ == "__main__": outfile = input("Bitte Dateinamen eingeben: ").strip() out.open(outfile) - #select chat - print(' ID | Internal ID | Username | pinned\nβ€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”') + # select chat + print( + ' ID| Internal ID | Username | pinned\nβ€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”') interid = 0 for d in dialogs: printDialog(interid, d) interid = interid + 1 - uinput = input('Bitte ' + Fore.BLUE + 'chatid' + Fore.RESET + ' oder "' + Fore.BLUE + 'all' + Fore.RESET + '" eingeben: ').strip().lower() # TODO: select more than one or all + while True: + uinput = input( + 'Bitte ' + Fore.BLUE + 'chatid1,chatid2,...' + Fore.RESET + ' oder "' + Fore.BLUE + 'all' + Fore.RESET + '" eingeben: ').strip().lower() + try: + selected = parseInput(uinput) + break + except: + pass # some error, retry start = timer() - if uinput == 'all': - for d in dialogs: + for d in selected: + try: analyseChat(d, out) - else: - get = int(uinput) - if get < 0 or get >= dialogCount: #TODO: detect user by username, name, tg-id - print("unbekannte Chat ID!") - exit(1) - - analyseChat(dialogs[get], out) + except Exception as e: + print(Fore.RED + 'Fehler beim bearbeiten von: ' + Fore.RESET, d.name, '\n', e) + print(e) out.close() - took = datetime.timedelta(seconds=(timer()-start)) + took = datetime.timedelta(seconds=(timer() - start)) took = datetime.timedelta(seconds=int(took.total_seconds())) print(Fore.GREEN + "Fertig. BenΓΆtigte Zeit: " + Fore.YELLOW, took, Style.RESET_ALL) diff --git a/src/out.py b/src/out.py index d5307aa..f4a27b8 100644 --- a/src/out.py +++ b/src/out.py @@ -31,7 +31,7 @@ class jsonOut(Output): file = None needsFilename = True - outbuff = {} + outbuff = [] def __init__(self, name: str = "json"): super().__init__(name) @@ -46,7 +46,7 @@ class jsonOut(Output): self.file.close() def print(self, stats, count, dialog): - jsonpre = {"count": count} + jsonpre = {"count": count, 'chatid': dialog.id, 'chatname': dialog.name} for stat in stats: jsonpre[stat.name] = stat.getAll(count) - self.outbuff[dialog.id] = jsonpre + self.outbuff.append(jsonpre)