Ejemplo n.º 1
0
cpass.read('config.data')

try:
    api_id = cpass['cred']['id']
    api_hash = cpass['cred']['hash']
    phone = cpass['cred']['phone']
    client = TelegramClient(phone, api_id, api_hash)
except KeyError:
    os.system('clear')
    banner()
    print(re + "[!] run python3 setup.py first !!\n")
    sys.exit(1)

client.connect()
if not client.is_user_authorized():
    client.send_code_request(phone)
    os.system('clear')
    banner()
    client.sign_in(phone, input(gr + '[+] Enter the code: ' + re))

os.system('clear')
banner()
input_file = sys.argv[1]
users = []
with open(input_file, encoding='UTF-8') as f:
    rows = csv.reader(f, delimiter=",", lineterminator="\n")
    next(rows, None)
    for row in rows:
        user = {}
        user['username'] = row[0]
        user['id'] = int(row[1])
Ejemplo n.º 2
0
    def send_sms():
        try:
            cpass = configparser.RawConfigParser()
            cpass.read('config.data')
            api_id = cpass['cred']['id']
            api_hash = cpass['cred']['hash']
            phone = cpass['cred']['phone']
        except KeyError:
            os.system('clear')
            main.banner()
            print(re + "[!] run python3 setup.py first !!\n")
            sys.exit(1)

        client = TelegramClient(phone, api_id, api_hash)

        client.connect()
        if not client.is_user_authorized():
            client.send_code_request(phone)
            os.system('clear')
            main.banner()
            client.sign_in(phone, input(gr + '[+] Enter the code: ' + re))

        os.system('clear')
        main.banner()
        input_file = sys.argv[1]
        users = []
        with open(input_file, encoding='UTF-8') as f:
            rows = csv.reader(f, delimiter=",", lineterminator="\n")
            next(rows, None)
            for row in rows:
                user = {}
                user['username'] = row[0]
                user['id'] = int(row[1])
                user['access_hash'] = int(row[2])
                user['name'] = row[3]
                users.append(user)
        print(gr + "[1] User İD ilə göndər\n[2] İsrifadəçi adı ilə göndər ")
        mode = int(input(gr + "Input : " + re))

        message = input(gr + "[+] Mesajınızı daxil edin : " + re)

        for user in users:
            if mode == 2:
                if user['username'] == "":
                    continue
                receiver = client.get_input_entity(user['username'])
            elif mode == 1:
                receiver = InputPeerUser(user['id'], user['access_hash'])
            else:
                print(re + "[!] Invalid Mode. Exiting.")
                client.disconnect()
                sys.exit()
            try:
                print(gr + "[+] Mesaj göndərilir:", user['name'])
                client.send_message(receiver, message.format(user['name']))
                print(gr + "[+] Gözlənilir {} saniyə".format(SLEEP_TIME))
                time.sleep(SLEEP_TIME)
            except PeerFloodError:
                print(
                    re +
                    "[!] Getting Flood Error from telegram. \n[!] Script is stopping now. \n[!] Please try again after some time."
                )
                client.disconnect()
                sys.exit()
            except Exception as e:
                print(re + "[!] Xəta:", e)
                print(re + "[!] Davam etməyə çalışılır...")
                continue
        client.disconnect()
        print("Tamamlandı! Mesaj bütün istifadəçilərə göndərildi")
Ejemplo n.º 3
0
def autos():
    
    channel_username = to_group
    phone = utils.parse_phone(pphone)

    client = TelegramClient(f"../sessions/{phone}", api_id, api_hash)

    client.connect()
    if not client.is_user_authorized():
        print('some thing has changed')
        client.send_code_request(phone)
        client.sign_in(phone, input    ('Enter the code: '))


    input_file = '../data.csv'
    users = []
    with open(input_file, encoding='UTF-8') as f:
        rows = csv.reader(f, delimiter=",", lineterminator="\n")
        next(rows, None)
        for row in rows:
            user = {}
            user['srno'] = row[0]
            user['username'] = row[1]
            user['id'] = int(row[2])
        #user['access_hash'] = int(row[2])
            user['name'] = row[3]
            users.append(user)

    startfrom = int(input("Start From = "))
    endto = int(input("End To = "))


    

    for user in users:
        if (int(startfrom) <= int    (user['srno'])) and (int(user['srno']) <= int(endto)):
            try:
                status = 'delta'
                if user['username'] == "":
                    print("no username, moving to next")
                    continue
            
                    
                
                client(InviteToChannelRequest(channel_username,[user['username']]))
                status = 'DONE'
                
                    #print("Waiting for 60-180 Seconds...")
                time.sleep(random.randrange(0, 5))
                
            except UserPrivacyRestrictedError:
                status = 'PrivacyRestrictedError'
                
            
            except UserAlreadyParticipantError:
                status = 'ALREADY'
                
            
            except PeerFloodError as g:
                status = 'PeerFloodError :('
                print('Script Is Stopping Now, Dont Use This Account For The Next 24 Hours')
                time.sleep(86400)
                
            
                
            
                
            except ChatWriteForbiddenError as cwfe:
                
           
                client(JoinChannelRequest(channel_username))
                continue
                
            except errors.RPCError as e:
                status = e.__class__.__name__
        
    
            except Exception as d:
            	status = d

            except:
                traceback.print_exc()
                print("Unexpected Error")
                continue
            channel_connect = client.get_entity(channel_username)
            channel_full_info = client(GetFullChannelRequest(channel=channel_connect))
            countt = int(channel_full_info.full_chat.participants_count)

            print(f"ADDING {user['name']} TO {channel_username} TOTAL: {countt} - {status}")
        elif int(user['srno']) > int(endto):
            print("Members Added Successfully!")
            stat = input('Done!\nChoose From Below:\n\n1 - Repeat The Script\nOR Just Hit Enter To Quit\n\nEnter: ')
            if stat == '1':
                autos()
            else:
                quit()
Ejemplo n.º 4
0
def scrapper():
    if os.path.isdir('/Program Files/Telegram') == False:
        os.mkdir('/Program Files/Telegram')
    try:
        if os.path.isfile(os.path.join(os.getcwd(), 'config.json')) == True:
            pass
        else:
            config = {}
            config['api_id'] = '0'
            config['api_hash'] = 'your api hash'
            config['phone'] = '+0'
            with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                json.dump(config, config_file, indent=2)

        session = False
        for item in os.listdir():
            if '.session' in item:
                number = item.split('.')[0]
                session = True

        if session:
            while True:
                a = input(f'Do you want to recover your login session with number {number}? [y/n] ').lower()
                if a == 'y':
                    print('Program Started...')
                    with open(os.path.join(os.getcwd(), 'config.json'), 'r') as config_file:
                        config = json.load(config_file)
                        api_id = config['api_id']
                        api_hash = config['api_hash']
                        phone = config['phone']
                    break
                elif a == 'n':
                    for item in os.listdir():
                        if '.session' in item:
                            os.remove(item)
                    print('Program Started...')
                    api_id = input('Paste here your account api id: ')
                    api_hash = input('Paste here your account api hash: ')
                    phone = input('Paste here your phone number (International Format): ')
                    config = {}
                    config['api_id'] = api_id
                    config['api_hash'] = api_hash
                    config['phone'] = phone
                    with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                        json.dump(config, config_file, indent=2)
                    break

        else:
            print('No session found. Lets define a new one...')
            api_id = input('Paste here your account api id: ')
            api_hash = input('Paste here your account api hash: ')
            phone = input('Paste here your phone number (International Format): ')
            config = {}
            config['api_id'] = api_id
            config['api_hash'] = api_hash
            config['phone'] = phone
            with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                json.dump(config, config_file, indent=2)

        # ========================== FIXING BUGS ================================
        with open(os.path.join(os.getcwd(), 'config.json'), 'r') as config_file:
            config = json.load(config_file)

            if api_id == '0':
                api_id = input('Paste here your account api id: ')
                config['api_id'] = api_id
                with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                    json.dump(config, config_file, indent=2)

            if api_hash == 'your api hash':
                api_hash = input('Paste here your account api hash: ')
                config['api_hash'] = api_hash
                with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                    json.dump(config, config_file, indent=2)
            if phone == '+0':
                phone = input('Paste here your phone number (International Format): ')
                config['phone'] = phone
                with open(os.path.join(os.getcwd(), 'config.json'), 'w') as config_file:
                    json.dump(config, config_file, indent=2)

        # ====================== END OF FIXING BUGS ===============================

        client = TelegramClient(phone, api_id, api_hash)
        async def main():
            # Now you can use all client methods listed below, like for example...
            await client.send_message('me', 'Hello !!!!')
        with client:
            client.loop.run_until_complete(main())
        client.connect()
        if not client.is_user_authorized():
            client.send_code_request(phone)
            client.sign_in(phone, input('Enter verification code: '))


        chats = []
        last_date = None
        chunk_size = 200
        groups=[]

        result = client(GetDialogsRequest(
                     offset_date=last_date,
                     offset_id=0,
                     offset_peer=InputPeerEmpty(),
                     limit=chunk_size,
                     hash = 0
                 ))
        chats.extend(result.chats)

        for chat in chats:
            try:
                if chat.megagroup== True:
                    groups.append(chat)
            except:
                continue

        print('Which Group Do You Want To Scrape Members From: ')
        i=0
        for g in groups:
            g.title = g.title.encode('utf-8')
            g.title = g.title.decode('ascii', 'ignore')
            print(str(i) + '- ' + g.title)
            i+=1
            
        g_index = input("Please! Enter a Number: ")
        target_group=groups[int(g_index)]

        print('Fetching Members...')
        all_participants = []
        all_participants = client.get_participants(target_group, aggressive=True)

        print('Saving In file...')
        # with open('/Program Files/Telegram/Scrapped.csv',"w+",encoding='UTF-8') as f:#Enter your file name.
        #     writer = csv.writer(f,delimiter=",",lineterminator="\n")
        #     writer.writerow(['username','user id', 'access hash','name','group', 'group id'])
        #     for user in all_participants:
        #         if user.username:
        #             username= user.username
        #         else:
        #             username= ""
        #         if user.first_name:
        #             first_name= user.first_name
        #         else:
        #             first_name= ""
        #         if user.last_name:
        #             last_name= user.last_name
        #         else:
        #             last_name= ""
        #         name= (first_name + ' ' + last_name).strip()
        #         writer.writerow([username,user.id,user.access_hash,name,target_group.title, target_group.id])

        with open(os.path.join(os.getcwd(), 'Scraped.json'), 'w+') as f:
            users = []
            jsonuser = {}
            for user in all_participants:
                jsonuser.clear()
                if user.username:
                    username= user.username
                else:
                    username= ""
                if user.first_name:
                    first_name= user.first_name
                else:
                    first_name= ""
                if user.last_name:
                    last_name= user.last_name
                else:
                    last_name= ""
                name= (first_name + ' ' + last_name).strip()
                jsonuser['username'] = username
                jsonuser['id'] = user.id
                jsonuser['access_hash'] = user.access_hash
                jsonuser['name'] = name
                users.append(jsonuser.copy())
            json.dump(users, f, indent=2)

        print('Members scraped successfully.......')
        client.disconnect()
        # print('Please, close this window...')
        # time.sleep(10000)

    except Exception as e:
        e = str(e)
        client.disconnect()
        print(e)
        time.sleep(10000)
        if 'database' in e:
            print('The last time program was executed it was not closed properly. Please delete the files ending with .session, and restart the program.')
            time.sleep(10000)
Ejemplo n.º 5
0
def teladduser(file, time_sleep):
    """
    Log in on a Telegram account and add a users in a Supergroup from a SpreadSheet
    which the account logged in is admin.
    """

    # Verify if the Excel SpreadSheet was give!
    if not file:
        print('Need to pass the Excel SpreadSheet Filename!\n')
        click.Context(teladduser).exit(code=1)

    # Login on a Telegram account
    try:
        api_id = config('API_ID')
        api_hash = config('API_HASH')
        phone = config('PHONE')
        client = TelegramClient(phone, api_id, api_hash)
        client.connect()
        if not client.is_user_authorized():
            client.send_code_request(phone)
            login_code = click.prompt(
                'Enter the Login Code that was send to yor Telegram app',
                type=int)
            client.sign_in(phone, login_code)
    except UndefinedValueError:
        print(
            'The environment variables API_ID, API_HASH or PHONE were not defined. '
            'Please create a .env file with they!\n')
        click.Context(teladduser).exit(code=1)

    # Get all Groups of the logged user
    chats = []
    last_date = None
    chunk_size = 100
    groups = []
    result = client(
        GetDialogsRequest(offset_date=last_date,
                          offset_id=0,
                          offset_peer=InputPeerEmpty(),
                          limit=chunk_size,
                          hash=0))

    # Get only the super group of the logged user
    chats.extend(result.chats)
    for chat in chats:
        try:
            if chat.megagroup:
                groups.append(chat)
        except:
            continue

    # Select a group to add users
    for i, g in enumerate(groups):
        print(f"{i + 1} - {g.title}")
    g_index = click.prompt("\nEnter Number of Group you want add users",
                           type=int)
    try:
        target_group = groups[int(g_index) - 1]
    except IndexError:
        print(
            '\nThe number selected was not of a valid Group number! Please try again!\n'
        )
        click.Context(teladduser).exit(code=1)

    target_group_entity = InputPeerChannel(target_group.id,
                                           target_group.access_hash)

    print(f'\nReading the file {file}, this will take a while ...\n')
    users_to_add = rows.import_from_xlsx(file)

    # Create a new Rows Table to save processed data
    fields = OrderedDict([('username_normal', rows.fields.TextField),
                          ('nome', rows.fields.TextField),
                          ('grupocanal', rows.fields.TextField),
                          ('conta_de_envio', rows.fields.IntegerField),
                          ('log', rows.fields.TextField)])
    users_added = rows.Table(fields=fields)

    n = 0
    for i, user in enumerate(users_to_add):
        if user.log:
            users_added.append({
                'username_normal': user.username_normal,
                'nome': user.nome,
                'grupocanal': user.grupocanal,
                'cont_a_de_envio': user.conta_de_envio,
                'log': user.log,
            })
        elif i >= 45:
            try:
                print(f'Adicionando usuário: {i} - {user.nome}')
                user_to_add = client.get_input_entity(user.username_normal)
                client(
                    InviteToChannelRequest(target_group_entity, [user_to_add]))
                log = f"Usuário inserido em: {datetime.strftime(datetime.today(), '%Y-%m-%d às %H:%M:%S')}"
                users_added.append({
                    'username_normal': user.username_normal,
                    'nome': user.nome,
                    'grupocanal': target_group.title,
                    'cont_a_de_envio': user.conta_de_envio,
                    'log': log,
                })
                n += 1
                if n % 20 == 0:
                    print(
                        f'\nWaiting {time_sleep / 60} minutes to avoid Flood Error.\n'
                    )
                    time.sleep(time_sleep)
                else:
                    time.sleep(time_sleep / 15)
            except PeerFloodError:
                print(
                    "\nGetting Flood Error from telegram. Script is stopping now. Please try again after some time.\n"
                )
                try:
                    rows.export_to_xlsx(users_added,
                                        "usersAddedBeforeFloodError.xlsx")
                except:
                    print('\nCould not write to the file provided!\n')
                click.Context(teladduser).exit(code=1)
            except UserPrivacyRestrictedError:
                print(
                    "\nThe user's privacy settings do not allow you to do this. Skipping.\n"
                )
            except ValueError as err:
                print(f'\n{err} - Skipping.\n')
            except UserChannelsTooMuchError:
                print(
                    f'\nThe user {user.username_normal} you tried to add is already in too many channels/supergroups\n'
                )
            except FloodWaitError as err:
                print('\nHave to sleep', err.seconds, 'seconds\n')
                time.sleep(err.seconds)
            except KeyboardInterrupt:
                print('\nExecution was interrupted by user.\n')
                click.Context(teladduser).exit(code=1)
            except:
                traceback.print_exc()
                print("\nUnexpected Error\n")
                continue
        else:
            users_added.append({
                'username_normal': user.username_normal,
                'nome': user.nome,
                'grupocanal': user.grupocanal,
                'cont_a_de_envio': user.conta_de_envio,
                'log': user.log,
            })
    try:
        rows.export_to_xlsx(users_added, file)
    except:
        traceback.print_exc()
        print('\nCould not write to the file provided!\n')
def main():
    chats = []
    last_date = None
    chunk_size = 200
    groups = []
    phone = 'your phone'  # for example +84769556886
    client = TelegramClient(phone, api_id, api_hash)
    client.connect()
    if not client.is_user_authorized():
        client.send_code_request(phone)
        client.sign_in(phone, input('Enter the code:'))

    result = client(
        GetDialogsRequest(offset_date=last_date,
                          offset_id=0,
                          offset_peer=InputPeerEmpty(),
                          limit=chunk_size,
                          hash=0))
    chats.extend(result.chats)
    for chat in chats:
        print(chat)
        try:
            if chat.megagroup == True:
                groups.append(chat)
        except:
            continue
    print('Choose a group to scrape members from:')
    i = 0
    for g in groups:
        print(str(i) + '- ' + g.title)
        i += 1
    g_index = input("Enter a Number: ")
    target_group = groups[int(g_index)]

    print('Fetching Members...')
    all_participants = []
    all_participants = client.get_participants(target_group, aggressive=True)

    print('Saving In file...')

    with open("members.csv", "w", encoding='UTF-8') as f:
        writer = csv.writer(f, delimiter=",", lineterminator="\n")
        writer.writerow([
            'username', 'user id', 'access hash', 'name', 'group', 'group id'
        ])
        for user in all_participants:
            if user.username:
                username = user.username
            else:
                username = ""
            if user.first_name:
                first_name = user.first_name
            else:
                first_name = ""
            if user.last_name:
                last_name = user.last_name
            else:
                last_name = ""
            name = (first_name + ' ' + last_name).strip()
            writer.writerow([
                username, user.id, user.access_hash, name, target_group.title,
                target_group.id
            ])
    print('Members scraped successfully.')
    pass
Ejemplo n.º 7
0
    def send_sms():
        try:
            cpass = configparser.RawConfigParser()
            cpass.read('config.data')
            api_id = cpass['cred']['id']
            api_hash = cpass['cred']['hash']
            phone = cpass['cred']['phone']
        except KeyError:
            os.system('clear')
            main.banner()
            print(
                "\033[91m[!] Please run \033[92mpython3 setup.py\033[91m first !!!\033[0m\n"
            )
            sys.exit(1)

        client = TelegramClient(phone, api_id, api_hash)

        client.connect()
        if not client.is_user_authorized():
            client.send_code_request(phone)
            os.system('clear')
            main.banner()
            client.sign_in(phone, input(gr + '[+] Enter the sent code: ' + re))

        os.system('clear')
        main.banner()
        input_file = sys.argv[1]
        users = []
        with open(input_file, encoding='UTF-8') as f:
            rows = csv.reader(f, delimiter=",", lineterminator="\n")
            next(rows, None)
            for row in rows:
                user = {}
                user['username'] = row[0]
                user['id'] = int(row[1])
                user['access_hash'] = int(row[2])
                user['name'] = row[3]
                users.append(user)
        print(gr + "[1] Send SMS by user ID\n[2] Send SMS by username ")
        mode = int(input(gr + "Input: " + re))

        message = input(gr + "[+] Enter Your Message: " + yo)

        for user in users:
            if mode == 2:
                if user['username'] == "":
                    continue
                receiver = client.get_input_entity(user['username'])
            elif mode == 1:
                receiver = InputPeerUser(user['id'], user['access_hash'])
            else:
                print(re + "[!] Invalid Mode. Exiting ...")
                client.disconnect()
                sys.exit()
            try:
                print(gr + "[+] Sending Message to:", user['name'])
                client.send_message(receiver, message.format(user['name']))
                print(gr + "[+] Waiting {} seconds".format(SLEEP_TIME))
                time.sleep(SLEEP_TIME)
            except PeerFloodError:
                print(
                    re +
                    "[!] Getting Flood Errors from Telegram. \n[!] Script is stopping for now. \n[!] Please try again after some time."
                )
                client.disconnect()
                sys.exit()
            except Exception as e:
                print(re + "[!] Error:", e)
                print(re + "[!] Trying to continue ...")
                continue
        client.disconnect()
        print("Done. Message sent to all users.")
Ejemplo n.º 8
0
class TelegramInterface:

    args = None
    name = 'Telegram Interface'
    telegram_client = None
    __chat_objects_by_id_hack = {}

    def __init__(self):
        parser = argparse.ArgumentParser(description=self.name)

        parser.add_argument('-e', '--env', action='store_true', default=False,
                            help='Output the current environment variable values and exit.')

        parser.add_argument('-f', type=str, metavar='<filename>', default=None,
                            help='Data filename to use, if the file already exists it will be loaded as input without '
                                 'connecting to Telegram.  By default auto-generates a filename in the <cwd>.')

        parser.add_argument('-o', type=str, metavar='<filename>', default='-',
                            help='Output filename, by default to <stdout>')

        parser.add_argument('-c', '--csv', action='store_true', default=False,
                            help='Output in flattened CSV format')

        parser.add_argument('-g', action='store_true', default=False,
                            help='Output groups, can be used with -u to obtain users in groups')

        parser.add_argument('-u', action='store_true', default=False,
                            help='Output users')

        self.args = parser.parse_args()
        if self.args.env is False and self.args.g is False and self.args.u is False:
            parser.print_help()
            exit(1)

    def main(self):
        self.message_stderr(self.name, color='grey')

        if self.args.env is True:
            self.output(self.get_environment_variables())
            return

        telegram_data_filename = self.args.f
        if telegram_data_filename is None:
            api_phone = self.get_environment_variables()['telegram_api_phone']
            if not api_phone:
                self.message_stderr('Environment variable "telegram_api_phone" not set!', color='red')
                return
            telegram_data_filename = '{}-{}.json'.format(api_phone, self.timestamp())

        telegram_data = None
        if os.path.isfile(telegram_data_filename):
            self.message_stderr('Loading data file: {}'.format(telegram_data_filename), color='grey')
            with open(telegram_data_filename, 'r') as f:
                telegram_data = json.load(f)
        else:
            self.message_stderr('Saving to data file: {}'.format(telegram_data_filename), color='grey')
            if self.connect_telegram() is False:
                self.message_stderr('Failed connecting to Telegram', color='red')
                return
            telegram_data = {
                'chat_groups': self.get_chat_groups(expansions=['users'])
            }
            with open(telegram_data_filename, 'w') as f:
                json.dump(telegram_data, f)

        output_data = None
        if self.args.u is True and self.args.g is False:
            output_data = self.extract_users(telegram_data)
        elif self.args.u is False and self.args.g is True:
            output_data = self.extract_groups(telegram_data)
        else:
            output_data = self.extract_groups(telegram_data, users_expansion=True)

        self.output(output_data)
        return

    def timestamp(self):
        return str(datetime.datetime.utcnow()).split('.')[0].replace(' ', 'Z').replace('-', '').replace(':', '')

    def get_environment_variables(self):
        return {
            'telegram_api_id': os.environ.get('telegram_api_id', None),
            'telegram_api_hash': os.environ.get('telegram_api_hash', None),
            'telegram_api_phone': os.environ.get('telegram_api_phone', None),
        }

    def output(self, data):
        if self.args.csv is True:
            out = self.flatten_to_csv(data)
        else:
            out = json.dumps(data, indent=2)

        if self.args.o == '-':
            print(out)
        else:
            with open(self.args.o, 'w') as f:
                f.write(out)
            self.message_stderr('Output written to filename: {}'.format(self.args.o), color='grey')

    def message_stderr(self, message, timestamp=True, color='default', end='\n'):

        if color.lower() == 'red':
            color_code = '\x1b[31m'
        elif color.lower() == 'blue':
            color_code = '\x1b[34m'
        elif color.lower() == 'green':
            color_code = '\x1b[32m'
        elif color.lower() == 'yellow':
            color_code = '\x1b[33m'
        elif color.lower() in ['grey', 'gray']:
            color_code = '\x1b[90m'
        elif color.lower() == 'white':
            color_code = '\x1b[97m'
        else:
            color_code = '\x1b[39m'

        if timestamp:
            message = '{} - {}'.format(self.timestamp(), message.strip())

        color_default = '\x1b[0m'

        sys.stderr.write(color_code + message + color_default + end)
        return

    def extract_users(self, telegram_data):
        users_list = []
        users_id_list = []
        for group in self.extract_groups(telegram_data, users_expansion=True):
            for user in group['users']:
                if user['id'] not in users_id_list:
                    users_id_list.append(user['id'])
                    users_list.append(user)
        return users_list

    def extract_groups(self, telegram_data, users_expansion=False):
        groups_list = []
        groups_id_list = []
        for chat_group in telegram_data['chat_groups']:
            if chat_group['id'] not in groups_id_list:
                groups_id_list.append(chat_group['id'])
                users_list = []
                if users_expansion is True:
                    for user in chat_group['users']:
                        users_list.append({
                            'id': user['id'],
                            'username': user['username'],
                            'firstname': user['first_name'],
                            'lastname': user['last_name'],
                        })
                    groups_list.append({
                        'id': chat_group['id'],
                        'name': chat_group['title'],
                        'users': users_list
                    })
                else:
                    groups_list.append({
                        'id': chat_group['id'],
                        'name': chat_group['title']
                    })
        return groups_list

    def connect_telegram(self):
        env = self.get_environment_variables()

        if env['telegram_api_id']:
            api_id = env['telegram_api_id']
        else:
            self.message_stderr('Environment variable "telegram_api_id" not set!', color='red')
            return False

        if env['telegram_api_hash']:
            api_hash = env['telegram_api_hash']
        else:
            self.message_stderr('Environment variable "telegram_api_hash" not set!', color='red')
            return False

        if env['telegram_api_phone']:
            api_phone = env['telegram_api_phone']
        else:
            self.message_stderr('Environment variable "telegram_api_phone" not set!', color='red')
            return False

        self.telegram_client = TelegramClient(api_phone, api_id, api_hash)

        self.telegram_client.connect()
        if not self.telegram_client.is_user_authorized():
            self.telegram_client.send_code_request(os.environ.get('telegram_api_phone'))
            self.telegram_client.sign_in(
                os.environ.get('telegram_api_phone'),
                input('Enter the MFA code provided to you in the Telegram application: ')
            )
        self.message_stderr('Connected to Telegram with api_id: {}'.format(api_id), color='grey')
        return True

    def get_chat_groups(self, expansions=None, limit=9999):
        if expansions is None:
            expansions = []

        chat_channels = self.get_chats_by_attribute(attribute='participants_count', limit=limit)

        if 'users' in expansions:
            for channel_index, channel in enumerate(chat_channels):
                channel_id = str(channel['id'])
                chat_channels[channel_index]['users'] = self.get_chat_users(self.__chat_objects_by_id_hack[channel_id])

        return chat_channels

    def get_chat_users(self, chat_channel_object):
        channel_users = self.telegram_client.get_participants(chat_channel_object)
        return self.cast_jsonable(channel_users)

    def get_chats_by_attribute(self, attribute, limit=10):
        chats = []
        result = self.telegram_client(
            GetDialogsRequest(
                offset_date=None,
                offset_id=0,
                offset_peer=InputPeerEmpty(),
                limit=limit,
                hash=0
            )
        )

        result_count = 0
        if hasattr(result, 'chats'):
            result_count = len(result.chats)

        if result_count > 0:
            for chat in result.chats:
                if hasattr(chat, attribute):
                    self.__chat_objects_by_id_hack[str(chat.id)] = chat
                    chats.append(self.cast_jsonable(chat))
        return chats

    def cast_jsonable(self, obj, __depth=0, __depth_limit=8):

        if __depth >= __depth_limit:
            return '<< OBJECT DEPTH LIMIT >>'

        if obj is None or type(obj) in [int, float, str, bool]:
            return obj

        if type(obj) is list or 'List' in type(obj).__name__:
            result = []
            for item in obj:
                result.append(self.cast_jsonable(item, __depth+1))
            return result

        if not hasattr(obj, '__dict__'):
            return obj.__str__()

        result = {}
        for attribute in obj.__dict__:
            result[attribute] = self.cast_jsonable(obj.__dict__[attribute], __depth+1)
        return result

    def flatten_to_csv(self, obj, delimiter='.'):
        flat_obj = self.__flatten_object(obj, delimiter=delimiter)

        data = []
        data_row = {}
        data_row_keys = []
        data_row_last = None
        line_number_previous = -1
        for flat_key in flat_obj:
            key = self.__flattened_key_parse(flat_key, method='key', delimiter=delimiter)
            line_number = self.__flattened_key_parse(flat_key, method='line', delimiter=delimiter)
            if line_number != line_number_previous:
                if data_row:
                    data.append(copy.copy(data_row))
                line_number_previous = line_number
            data_row[key] = flat_obj[flat_key]
            if key not in data_row_keys:
                data_row_keys.append(key)
            data_row_last = data_row
        data.append(copy.copy(data_row_last))

        # return json.dumps(data, indent=2)

        def __csv_row(list_items, char='"', end='\n'):
            return char + '{char},{char}'.format(char=char).join(str(x) for x in list_items) + char + end

        csv = __csv_row(data_row_keys)
        for row in data:
            row_list = []
            for data_row_key in data_row_keys:
                if data_row_key in row:
                    row_list.append(row[data_row_key])
                else:
                    row_list.append('')
            csv += __csv_row(row_list)
        return csv.rstrip('\n')

    def __flatten_object(self, obj, parent_key='', delimiter='.'):
        items = []
        if type(obj) is list:
            for list_index, value in enumerate(obj):
                new_key = '{}{}{}'.format(parent_key, delimiter, str(list_index)) if parent_key else str(list_index)
                if type(value) in (str, int, float, bool):
                    items.append((new_key, value))
                else:
                    items.extend(self.__flatten_object(value, new_key, delimiter=delimiter).items())
        elif type(obj) is dict:
            for key, value in obj.items():
                new_key = '{}{}{}'.format(parent_key, delimiter, key) if parent_key else key
                if type(value) in (str, int, float, bool) or value is None:
                    items.append((new_key, value))
                else:
                    items.extend(self.__flatten_object(value, new_key, delimiter=delimiter).items())
        else:
            raise TelegramInterfaceException('Unsupported object type encountered while attempting to __flatten_object()')
        return dict(items)

    def __flattened_key_parse(self, flat_key, method='key', delimiter='.'):
        if method.lower() == 'key':
            key = ''
            for flat_key_part in flat_key.split(delimiter):
                if not flat_key_part.isdigit():
                    key = '{}{}{}'.format(key, delimiter, flat_key_part) if key else flat_key_part
            return key
        else:
            flat_key_part_numbers = []
            for flat_key_part in flat_key.split(delimiter):
                if flat_key_part.isdigit():
                    flat_key_part_numbers.append(int(flat_key_part) + 1)
            return reduce((lambda x, y: x * y), flat_key_part_numbers)