Pure Python 3 MTProto API Telegram client library, for bots too!

Overview

Telethon

⭐️ Thanks everyone who has starred the project, it means a lot!

logo Telethon is an asyncio Python 3 MTProto library to interact with Telegram's API as a user or through a bot account (bot API alternative).

Important

If you have code using Telethon before its 1.0 version, you must read Compatibility and Convenience to learn how to migrate.

What is this?

Telegram is a popular messaging application. This library is meant to make it easy for you to write Python programs that can interact with Telegram. Think of it as a wrapper that has already done the heavy job for you, so you can focus on developing an application.

Installing

pip3 install telethon

Creating a client

from telethon import TelegramClient, events, sync

# These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'

client = TelegramClient('session_name', api_id, api_hash)
client.start()

Doing stuff

print(client.get_me().stringify())

client.send_message('username', 'Hello! Talking to you from Telethon')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')

client.download_profile_photo('me')
messages = client.get_messages('username')
messages[0].download_media()

@client.on(events.NewMessage(pattern='(?i)hi|hello'))
async def handler(event):
    await event.respond('Hey!')

Next steps

Do you like how Telethon looks? Check out Read The Docs for a more in-depth explanation, with examples, troubleshooting issues, and more useful information.

Comments
  • account banned

    account banned

    When using the library, the account is immediately banished How to avoid this?


    (edit from @Lonami)

    For everyone still coming here, see my comment:

    Even official applications have these problems, not only libraries. Bans probably depend on a lot of factors, such as country, IP, use of the application, maybe even some random bans to accounts so people who care recover them and spambots won't bother with emails so those are gone, etc. For completeness sake:

    Emails: [email protected], [email protected].

    If those don't work, [email protected], https://telegram.org/support and DM to https://twitter.com/smstelegram may be worth trying.

    opened by izzzzzi 159
  • cannot run the program

    cannot run the program

    hi, i tried to run the example, but i get an error:

    "ModuleNotFoundError: No module named 'telethon.tl.types'" how can i resolve that?

    thanks

    duplicate RTFM 
    opened by ebs111 68
  • RPC login error

    RPC login error

    telethon.errors.rpcbaseerrors.AuthKeyError: RPCError 406: UPDATE_APP_TO_LOGIN (caused by SignInRequest)

    I am getting this error, anyone know the problem? Ubuntu 20.04 fresh install & can also replicate on macOS

    opened by jtonkeys1 66
  • Empty message if channel is Private and Restrict Saving Content option enabled

    Empty message if channel is Private and Restrict Saving Content option enabled

    As title says, if Restrict Saving Content option is enabled on Private channel, then message events from @client.on(events.NewMessage(channel_id) contains something like this:

    NewMessage.Event(original_update=UpdateNewChannelMessage(message=Message(id=12, 
    peer_id=PeerChannel(channel_id=123456789), date=datetime.datetime(2022, 1, 3, 9, 59, 10, tzinfo=datetime.timezone.utc), 
    message='', out=False, mentioned=False, media_unread=False, silent=False, post=True, from_scheduled=False, legacy=False, 
    edit_hide=False, pinned=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, 
    media=MessageMediaUnsupported(), reply_markup=None, entities=[], views=1, forwards=0, replies=None, edit_date=None, 
    post_author=None, grouped_id=None, restriction_reason=[], ttl_period=None), pts=13, pts_count=1), pattern_match=None, 
    message=Message(id=12, peer_id=PeerChannel(channel_id=123456789), date=datetime.datetime(2022, 1, 3, 9, 59, 10, 
    tzinfo=datetime.timezone.utc), message='', out=False, mentioned=False, media_unread=False, silent=False, post=True, 
    from_scheduled=False, legacy=False, edit_hide=False, pinned=False, from_id=None, fwd_from=None, via_bot_id=None, 
    reply_to=None, media=MessageMediaUnsupported(), reply_markup=None, entities=[], views=1, forwards=0, replies=None, 
    edit_date=None, post_author=None, grouped_id=None, restriction_reason=[], ttl_period=None))
    

    As we can see, message parameter is empty, but on phone client i do see message content.

    So is it a bug in Telethon itself and how it could be fixed? Or this comes from Telegram API and now you can view this type of chats only on official Client? Thanks!

    opened by tarkh 54
  • 2.0 wishlist

    2.0 wishlist

    Telethon currently has some weird things in it that need changing, but would be breaking changes. Therefore, a new major release should be made. We should aim for making a single release with the biggest amount of breaking changes, instead of making breaking changes across many releases.

    Please post in this issue any gripe you have with the library and that you would like it to change.

    Of course, a last release 1.X will be made with deprecation warning on all these methods, so people know how to upgrade.

    (2021-09 update: probably no "last 1.X" with deprecation; instead a document will be prepared, along with some helper code to ease the migration.)

    opened by Lonami 54
  • Exception: Number of retries reached 0.

    Exception: Number of retries reached 0.

    I haven't check on new version v0.14, but previous one this exception happened very often on outgoing requests in a random time. I don't know: Telegram servers sometime is slow or it's flood protection. Definitely this exception has to be more informative to understand the reason of it.

    help wanted 
    opened by andr-04 54
  • ImportError: cannot import name 'TelegramClient'

    ImportError: cannot import name 'TelegramClient'

    Hello, I have just tried to setup a client but i'm receiving an import error: ImportError: cannot import name 'TelegramClient'

    I installed telethon module with pip3 and tried to run the script with python 3. Is there something I'm missing here?

    Thank you in advance!

    opened by madrileanu 49
  • in get_message_history(entity), error

    in get_message_history(entity), error "struct.error: required argument is not an integer"

    After upgrade to Telethon-0.15.2.3 from Telethon-0.11.1, I am calling get_message_history(entity) where entity is a chat room, and now receiving and error struct.error: required argument is not an integer. The same call was working correctly before the upgrade.

    I am looking through the upgrades for the change, but unable to find it.

    thank you.

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/telegram_client.py", line 433, in get_message_history
        add_offset=add_offset
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/telegram_bare_client.py", line 450, in __call__
        result = self._invoke(sender, call_receive, *requests)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/telegram_bare_client.py", line 469, in _invoke
        sender.send(*requests)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/network/mtproto_sender.py", line 86, in send
        self._send_message(message)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/network/mtproto_sender.py", line 128, in _send_message
        + bytes(message)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/tl/tl_message.py", line 16, in __bytes__
        body = GzipPacked.gzip_if_smaller(self.request)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/tl/gzip_packed.py", line 22, in gzip_if_smaller
        data = bytes(request)
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/tl/functions/messages.py", line 1738, in __bytes__
        bytes(self.peer),
      File "/Users/dan/poof/py3/lib/python3.6/site-packages/telethon/tl/types/__init__.py", line 9055, in __bytes__
        struct.pack('<q', self.access_hash),
    struct.error: required argument is not an integer```
    
    
    opened by dsldsl 49
  • Large number of security warnings

    Large number of security warnings

    Checklist

    • [x] The error is in the library's code, and not in my own.
    • [x] I have searched for this issue before posting it and there isn't a duplicate.
    • [x] I ran pip install -U https://github.com/LonamiWebs/Telethon/archive/master.zip and triggered the bug in the latest version.

    Our software works with ~100 Telegram sessions at the same time. Doing so causes API calls to output, below warning when 100 sessions do something at once asynchronously. Output numbers vary between 50 to 200 or more sometimes.

    Warning

    WARNING:telethon.network.mtprotosender:Security error while unpacking a received message: Server replied with a wrong session ID
    
    opened by Itach1Uchixa 47
  • FloodWaitError on GetParticipants out of nowhere

    FloodWaitError on GetParticipants out of nowhere

    from telethon import TelegramClient

    all_participants = client.get_participants(target_group, aggressive=True) Basically this line causes the whole problem. I was running this code as usual , its a simple members scrap code from groups, and out of nowhere starter recieving this problem I tried changing User, API id and API hash , turning on VPN, reinstalling PIP and Telethon and Python, Nothing seems to work.

    Traceback (most recent call last): File "c:\Users\tmaxi\Desktop\Adding\NewAdder\scraptpt.py", line 54, in all_participants = client.get_participants(target_group, aggressive=True) File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\sync.py", line 39, in syncified return loop.run_until_complete(coro) File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\asyncio\base_events.py", line 642, in run_until_complete return future.result() File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\client\chats.py", line 507, in get_participants return await self.iter_participants(*args, **kwargs).collect() File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\requestiter.py", line 113, in collect async for message in self: File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\requestiter.py", line 74, in anext if await self._load_next_chunk(): File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\client\chats.py", line 222, in _load_next_chunk results = await self.client(self.requests) File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\client\users.py", line 30, in call return await self._call(self._sender, request, ordered=ordered) File "C:\Users\tmaxi\AppData\Local\Programs\Python\Python39\lib\site-packages\telethon\client\users.py", line 80, in _call raise MultiError(exceptions, results, requests) telethon.errors.common.MultiError: ([FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), None, None, FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), None, FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)'), FloodWaitError('A wait of 28 seconds is required (caused by GetParticipantsRequest)')], [None, None, <telethon.tl.types.channels.ChannelParticipants object at 0x0000029944F63400>, <telethon.tl.types.channels.ChannelParticipants object at 0x0000029944F457C0>, None, None, <telethon.tl.types.channels.ChannelParticipants object at 0x0000029944F56430>, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None], [<telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089310>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089B50>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089C10>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089CD0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089D90>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089E50>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089F10>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944089FD0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x00000299440920D0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092190>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092250>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092310>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x00000299440923D0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092490>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092550>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092610>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x00000299440926D0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092790>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092850>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092910>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x00000299440929D0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092A90>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092B50>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092C10>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092CD0>, <telethon.tl.functions.channels.GetParticipantsRequest object at 0x0000029944092D90>])

    opened by striller17 44
  • RPCError(...), 'The api_id/api_hash combination is invalid.'

    RPCError(...), 'The api_id/api_hash combination is invalid.'

    When I run python3 try_telethon.py it all the time says

    RPCError(...), 'The api_id/api_hash combination is invalid.'

    OS: MacOS, Ubuntu 12.04.

    It even does not want to connect. The error occurs on the first self.connect call (Could not stabilise initial connection). What is worth, occasionally this call works. But all the time it fails on sending a code (SendCodeRequest). I use 2 different telegram accounts. The result is the same.

    I do as it's written in the readme:

    • Run the tl_generator.py
    • Create and edit the settings
    • python3 try_telethon.py

    I get the same result in case of using an installed through the pip version.

    Could you please tell, if I should do something else.

    Update

    When the connect call works, it returns the following

    (config (ID: 0x3af6fb5f) = (phonecalls_enabled=None, date=2017-04-07 11:43:30, expires=1491558606, test_mode=False, this_dc=5, dc_options=['(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=None, tcpo_only=None, id=1, ip_address=149.154.175.50, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=True, media_only=None, tcpo_only=None, id=1, ip_address=2001:0b28:f23d:f001:0000:0000:0000:000a, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=None, tcpo_only=None, id=2, ip_address=149.154.167.51, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=True, media_only=None, tcpo_only=None, id=2, ip_address=2001:067c:04e8:f002:0000:0000:0000:000a, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=None, tcpo_only=None, id=3, ip_address=149.154.175.100, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=True, media_only=None, tcpo_only=None, id=3, ip_address=2001:0b28:f23d:f003:0000:0000:0000:000a, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=None, tcpo_only=None, id=4, ip_address=149.154.167.91, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=True, media_only=None, tcpo_only=None, id=4, ip_address=2001:067c:04e8:f004:0000:0000:0000:000a, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=True, tcpo_only=None, id=4, ip_address=149.154.165.120, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=None, media_only=None, tcpo_only=None, id=5, ip_address=91.108.56.165, port=443))', '(dcOption (ID: 0x5d8c6cc) = (ipv6=True, media_only=None, tcpo_only=None, id=5, ip_address=2001:0b28:f23f:f005:0000:0000:0000:000a, port=443))'], chat_size_max=200, megagroup_size_max=5000, forwarded_count_max=100, online_update_period_ms=120000, offline_blur_timeout_ms=5000, offline_idle_timeout_ms=30000, online_cloud_timeout_ms=300000, notify_cloud_delay_ms=30000, notify_default_delay_ms=1500, chat_big_size=10, push_chat_period_ms=60000, push_chat_limit=2, saved_gifs_limit=200, edit_time_limit=172800, rating_e_decay=2419200, stickers_recent_limit=30, tmp_sessions=None, pinned_dialogs_count_max=5, call_receive_timeout_ms=20000, call_ring_timeout_ms=90000, call_connect_timeout_ms=30000, call_packet_timeout_ms=10000, disabled_features=None))

    opened by chabanovsky 44
  • event.answer(url) not working when handled with bot.add_event_handler

    event.answer(url) not working when handled with bot.add_event_handler

    event.answer(url="t.me/botname/start?=hi") not working when handled with client.add_event_handler() to assign event handlers its working fine when I use @client.on(event)(decorator method) instead of add_event_handler()

    Traceback

    File "C:\Users\..\Python310\lib\site-packages\telethon\client\updates.py", line 467, in _dispatch_update
        await callback(event)
      File "C:\Users\..\event_handlers.py", line 213, in upl
        await e.answer(url=f"https://t.me/{await bot_username(client)}?start=hi")
      File "C:\Users\...\telethon\events\callbackquery.py", line 244, in answer
        return await self._client(
      File "C:\Users\...\Python310\lib\site-packages\telethon\client\users.py", line 30, in __call__
        return await self._call(self._sender, request, ordered=ordered)
      File "C:\Users\...\Python310\lib\site-packages\telethon\client\users.py", line 84, in _call
        result = await future
    telethon.errors.rpcerrorlist.QueryIdInvalidError: The query ID is invalid (caused by SetBotCallbackAnswerRequest)
    
    
    opened by pdisk 1
  • Telegram Topics - Replying in General chat doesn't dork

    Telegram Topics - Replying in General chat doesn't dork

    Hello! I see an issue with Topics - if bot replies to the message in General chat, answer goes to the messages mode (in other words, it gets hidden). If I do the same thing in any Topic - reply returns to the same topic as expected.

    opened by roman2861 4
  • after  event.delete() - enet handler continues to work . what am I doing wrong ?

    after event.delete() - enet handler continues to work . what am I doing wrong ?

    If you send a message from WS to the chat, and then send a message from the chat, then Event is not deleted, if you send another message, it will be processed

    Checklist

    • [ ] The error is in the library's code, and not in my own.
    • [х] I have searched for this issue before posting it and there isn't a duplicate.
    • [ ] I ran pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip and triggered the bug in the latest version.

    Code that causes the issue

    from telethon import TelegramClient, events
    from telethon.events import StopPropagation
    
    import sys
    import asyncio
    import websockets
    
    
    class TG(TelegramClient):
        chat = 0
    
        def __init__(self, session_user_id, api_id, api_hash):
            super().__init__(
                session_user_id, api_id, api_hash,
            )
            print('Connecting to Telegram servers...')
            print(self)
    
        async def get_dialog_id(self):
            username = await self.get_entity('AoAnima')
            self.chat = username.id
    
        async def run(self):
            await self.start()
            print('connected Telegram servers...')
            print(await self.is_user_authorized())
            await self.get_dialog_id()
    
        async def send_messages(self, message, ws):
    
            await self.send_message(self.chat, message)
    
            @self.on(events.NewMessage(chats=self.chat))
            async def handler(event):
                print("message", event)
                # await ws.send(event.message.stringify())
                delstat = await event.delete() # NOT WORK
                print("self", self)
                print("delstat", delstat[0])
                print("event", event.delete)
                raise StopPropagation
            
    
    class WS():
    
        tgclient = ''
    
        def __init__(self, tg):
            # super.__init__(self)
            self.tgclient = tg
    
    
        async def run(self):
            async with websockets.serve(self.incomming_message_handler, "localhost", 8765):
                await asyncio.Future()
    
        async def incomming_message_handler(self, websocket):
            print(websocket)
            async for message in websocket:
                # отправим сообщение в телеграм
                await self.tgclient.send_messages(message, websocket)
                # await websocket.send(message)
    
    
    async def main():
        api_id = 2222222
        api_hash = 'xxxxxxxx'
        client = TG('session_name', api_id, api_hash)
        ws = WS(client)
        a = await asyncio.gather(
            client.run(),
            ws.run(),
        )
        await asyncio.Future()
    
    
    if __name__ == "__main__":
        asyncio.run(main())
    
    
    

    Traceback

    Connecting to Telegram servers...
    <__main__.TG object at 0x00000184192D3A90>
    Соединение установленно to Telegram servers...
    True
    <websockets.legacy.server.WebSocketServerProtocol object at 0x00000184193A3650>
    message NewMessage.Event(original_update=UpdateNewMessage(message=Message(id=83875, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 34, 59, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None), pts=199485, pts_count=1), pattern_match=None, message=Message(id=83875, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 34, 59, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None))
    self <__main__.TG object at 0x00000184192D3A90>
    delstat AffectedMessages(pts=199487, pts_count=1)
    event <bound method Message.delete of <telethon.tl.patched.Message object at 0x0000018419401F10>>
    message NewMessage.Event(original_update=UpdateNewMessage(message=Message(id=83876, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 35, 1, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None), pts=0, pts_count=0), pattern_match=None, message=Message(id=83876, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 35, 1, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None))
    self <__main__.TG object at 0x00000184192D3A90>
    delstat AffectedMessages(pts=199490, pts_count=1)
    event <bound method Message.delete of <telethon.tl.patched.Message object at 0x0000018419400110>>
    message NewMessage.Event(original_update=UpdateNewMessage(message=Message(id=83877, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 35, 3, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None), pts=0, pts_count=0), pattern_match=None, message=Message(id=83877, peer_id=PeerUser(user_id=495654811), date=datetime.datetime(2022, 12, 7, 13, 35, 3, tzinfo=datetime.timezone.utc), message='asd', out=True, mentioned=False, media_unread=False, silent=False, post=False, from_scheduled=False, legacy=False, edit_hide=False, pinned=False, noforwards=False, from_id=None, fwd_from=None, via_bot_id=None, reply_to=None, media=None, reply_markup=None, entities=[], views=None, forwards=None, replies=None, edit_date=None, post_author=None, grouped_id=None, reactions=None, restriction_reason=[], ttl_period=None))
    self <__main__.TG object at 0x00000184192D3A90>
    delstat AffectedMessages(pts=199493, pts_count=1)
    event <bound method Message.delete of <telethon.tl.patched.Message object at 0x0000018419402CD0>>
    
    
    opened by AoAnima 1
  • Entities

    Entities "seen" in "@client.on(events.NewMessage)" only available after client is manually restarted

    Checklist

    • [x] The error is in the library's code, and not in my own.
    • [x] I have searched for this issue before posting it and there isn't a duplicate.
    • [x] I ran pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip and triggered the bug in the latest version.

    Hi everyone,

    I have run into the problem that I cannot access information about forwarded channels via "get_input_entity" when streaming new events/messages. The reason seems to be that the .sessions cache does not update until after the client has disconnected.

    If I re-run the code a second time, all channels which had been forwarded during the first run of the code now resolve without problems, however, forwards from new and previously unseen channels raise the same "could not find the input entity for PeerChannel.." error.

    What might be needed to resolve this would be to provide a way through which the sessions cache can be updated/reloaded while client.run_until_disconnected() is still running.

    Thank you very much!

    Code that causes the issue

    from telethon import TelegramClient
    from telethon import events, sync
    from telethon.tl.functions.messages import (GetHistoryRequest)
    from telethon.tl.types import (
    PeerChannel
    )
    
    api_id = xxxxx
    api_hash = 'xxxx'
    client = TelegramClient('xxxxx', api_id, api_hash)
    
    @client.on(events.NewMessage(chats=[xxx,yyy]))
    async def newMessageListener(event,client = client):
        nm = event.message
        xx = await client.get_input_entity(nm.fwd_from.from_id)    
    
    with client:
        client.run_until_disconnected()
    
    

    Traceback

    Traceback (most recent call last):
      File "/env-path/lib/python3.8/site-packages/telethon/client/updates.py", line 497, in _dispatch_update
        await callback(event)
      File "file.py", line 55, in newMessageListener
        xx = await client.get_input_entity(nm.fwd_from.from_id)
      File "/env-path/lib/python3.8/site-packages/telethon/client/users.py", line 466, in get_input_entity
        raise ValueError(
    ValueError: Could not find the input entity for PeerChannel(channel_id=xxxx) (PeerChannel). Please read https://docs.telethon.dev/en/stable/concepts/entities.html to find out more details.
    
    
    
    
    opened by schliebs 4
  • Call discarded after confirming

    Call discarded after confirming

    Checklist

    • [ ] The error is in the library's code, and not in my own.
    • [x] I have searched for this issue before posting it and there isn't a duplicate.
    • [x] I ran pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip and triggered the bug in the latest version.

    I have updated the code from Telethon-calls to the lastest version, I managed to request and confirm the call, but after confirming the call it is disconnected. Any idea why this is happening? Thanks!

    Code that causes the issue

    import logging
    logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
                        level=logging.WARNING)
    
    import asyncio
    import hashlib
    import os
    import random
    
    from telethon import TelegramClient, events
    from telethon.tl.functions.messages import GetDhConfigRequest
    from telethon.tl.functions.phone import  RequestCallRequest, ConfirmCallRequest
    from telethon.tl.types import PhoneCallEmpty, PhoneCallWaiting, \
        PhoneCallRequested, PhoneCallDiscarded, PhoneCall, PhoneCallAccepted, \
        UpdatePhoneCall, PhoneCallProtocol, InputPhoneCall, Updates, UpdateShort
    from pyrogram.raw import types
    
    api_id = 0
    api_hash = ''
    phone_number = '' 
    
    call_state = None
    client = TelegramClient('arm_call_test2', api_id, api_hash)
    
    @client.on(events.Raw)
    async def handler(update):
        await process_update(update)
    
    class DH:
        def __init__(self, dhc: types.messages.DhConfig):
            self.p = bytes_to_integer(dhc.p)
            self.g = dhc.g
            self.resp = dhc
    
    class DynamicDict:
        def __setattr__(self, key, value):
            self.__dict__[key] = value
    
    def get_rand_bytes(dh_config, length=256):
        return bytes(x ^ y for x, y in zip(
            os.urandom(length), dh_config.resp.random
        ))
    
    def bytes_to_integer(bytes):
        return int.from_bytes(bytes, 'big')
    
    def integer_to_bytes(integer):
        return int.to_bytes(
            integer,
            length=(integer.bit_length() + 8 - 1) // 8,  # 8 bits per byte,
            byteorder='big',
            signed=False
        )
    
    def calc_fingerprint(key):
        return int.from_bytes(
            bytes(hashlib.sha1(key).digest()[-8:]), 'little', signed=True
        )
    
    async def process_update(update):
        if isinstance(update, UpdatePhoneCall):
            print('[CALL] Phone call update:', update.phone_call)
            await process_phone_call(update.phone_call)
        elif isinstance(update, Updates):
            for u in update.updates:
                await process_update(u)
        elif isinstance(update, UpdateShort):
            await process_update(update.update)
        else:
            pass
            #print('Ignoring', type(update).__name__)
    
    async def process_phone_call(call):
        global call_state
        if isinstance(call, PhoneCallEmpty):
            pass
        elif isinstance(call, PhoneCallWaiting):
            print('[CALL] Waiting for', call.participant_id, 'to answer...')
        elif isinstance(call, PhoneCallRequested):
            print('[CALL] Incoming call from', call.participant_id)
            # accept_call(call)
        elif isinstance(call, PhoneCallDiscarded):
                state = call_state
                print('[CALL]', state.user_id, 'discarded your call because of', type(call.reason).__name__)        # del calls[call.id]
                client.disconnect()
        elif isinstance(call, PhoneCall):
            print('[CALL] Call', call.id, 'is now', type(call).__name__)
            process_full_call(call)
        elif isinstance(call, PhoneCallAccepted):
            print('[CALL] Call accepted by', call.participant_id, '! Doing stage 2')
            await call_stage_two(call)
        else:
            print('[call] ignoring', type(call), call)
    
    async def call_stage_two(call):
        global call_state
        state = call_state
        state.prt_proto = call.protocol  # TODO Hm, why not my_proto?
        print('prt', state.prt_proto)
        print('myp', state.my_proto)
    
        state.g_b = int.from_bytes(call.g_b, 'little')
        state.key = pow(state.g_b, state.a, state.p)
        state.key_fingerprint = calc_fingerprint(integer_to_bytes(state.key))
    
        call_state = state
    
        phone_call = await client(ConfirmCallRequest(
            peer=InputPhoneCall(call.id, call.access_hash),
            g_a=integer_to_bytes(state.g_a),
            key_fingerprint=state.key_fingerprint,
            protocol=state.prt_proto
        ))
    
        print('[CALL] Call confirmed:', phone_call)
        return await process_phone_call(phone_call.phone_call)
    
    def process_full_call(call):
        global call_state
        state = call_state
        print('[CALL] Processing full call', call)
        print('[CALL] Full state currently', state.__dict__)
        if state.incoming:
            print('[CALL] Got more info about call from', call.admin_id, 'we have accepted.')
            state.g_a = int.from_bytes(call.g_a_or_b, 'big')
    
            state.pt_g_a_hash = hashlib.sha256(call.g_a_or_b).digest()
            if state.pt_g_a_hash != state.g_a_hash:
                print('[CALL] HASH(G_A) != G_A_HASH!', state.pt_g_a_hash, state.g_a_hash)
            else:
                print('[CALL] g_a hash is correct!')
    
            state.key = pow(state.g_a, state.b, state.p)
            state.key_fingerprint = calc_fingerprint(integer_to_bytes(state.key))
            print('[CALL] Calculated fingerprint', repr(state.key_fingerprint), 'with key', repr(state.key))
    
            state.pt_key_fingerprint = call.key_fingerprint
            if state.pt_key_fingerprint != state.key_fingerprint:
                print('[CALL] Fingerprint mismatch! Got', state.pt_key_fingerprint, 'expected', state.key_fingerprint)
    
        state.connections = call.connections
        # state.alternative_connections = call.alternative_connections
    
        call_state = state
    
        print('[CALL] Call #', call.id, 'ready!')
        
    async def main():    
        await client.start()
    
        dhc = DH(await client(GetDhConfigRequest(0, 256)))
        state = DynamicDict()
        state.incoming = False
    
        state.user_id = "@user"
        state.random_id = random.randint(0, 0x7fffffff - 1)
    
        state.g = dhc.g
        state.p = dhc.p
    
        state.a = 0
        while not (1 < state.a < state.p - 1):
            # "A chooses a random value of a, 1 < a < p-1"
            state.a = int.from_bytes(get_rand_bytes(dh_config=dhc), 'little')
    
        state.a = random.randint(2, state.p - 1)
        state.g_a = pow(state.g, state.a, state.p)
        state.g_a_hash = hashlib.sha256(integer_to_bytes(state.g_a)).digest()
        state.my_proto = PhoneCallProtocol(
                min_layer=92,
                max_layer=92,
                udp_p2p=True,
                udp_reflector=True,
                library_versions=['3.0.0'],
            )
    
        phone_call = await client(RequestCallRequest(
            user_id=state.user_id,
            random_id=state.random_id,
            g_a_hash=state.g_a_hash,
            protocol=state.my_proto
        ))
    
        print(phone_call)
        print(phone_call.phone_call.id)
        state.peer = InputPhoneCall(phone_call.phone_call.id, phone_call.phone_call.access_hash)
        global call_state
        call_state = state
        await process_phone_call(phone_call.phone_call)
    
        await client.run_until_disconnected()
    
    asyncio.run(main())
    

    Logs

    [CALL] Waiting for xxx to answer...
    [CALL] Phone call update:
    [CALL] Waiting for xxx to answer...
    [CALL] Phone call update
    [CALL] Call accepted by xxx ! Doing stage 2
    [CALL] Call confirmed
    [CALL] Call xxx is now PhoneCall
    [CALL] Processing full call 
    [CALL] @user discarded your call because of PhoneCallDiscardReasonDisconnect
    
    
    opened by huco95 6
  • DateEmptyError raised in _update_loop

    DateEmptyError raised in _update_loop

    Checklist

    • [x] The error is in the library's code, and not in my own.
    • [x] I have searched for this issue before posting it and there isn't a duplicate.
    • [x] I ran pip install -U https://github.com/LonamiWebs/Telethon/archive/v1.zip and triggered the bug in the latest version.

    Code that causes the issue

    from telethon.sync import TelegramClient as Client
    client = Client(str(config.session_name), config.api_id, config.api_hash)
    await client.run_until_disconnected()
    

    Traceback

    Traceback (most recent call last):
      File "code.py", line 1, in <code>
    userbot  | [E 221113 15:16:30 updates:384] Fatal error handling updates (this is a bug in Telethon, please report it)
    userbot  |     Traceback (most recent call last):
    userbot  |       File "/usr/local/lib/python3.8/dist-packages/telethon/client/updates.py", line 282, in _update_loop
    userbot  |         diff = await self(get_diff)
    userbot  |       File "/usr/local/lib/python3.8/dist-packages/telethon/client/users.py", line 30, in __call__
    userbot  |         return await self._call(self._sender, request, ordered=ordered)
    userbot  |       File "/usr/local/lib/python3.8/dist-packages/telethon/client/users.py", line 84, in _call
    userbot  |         result = await future
    userbot  |     telethon.errors.rpcerrorlist.DateEmptyError: Date empty (caused by GetDifferenceRequest)
    

    Reporting the bug here as the traceback suggested to do.

    opened by JaskaranSM 5
Releases(v0.16.1)
  • v0.16.1(Jan 19, 2018)

  • v0.16(Dec 28, 2017)

    In the beginning, session files used to be pickle. This proved to be bad as soon as one wanted to add more fields. For this reason, they were migrated to use JSON instead. But this proved to be bad as soon as one wanted to save things like entities (usernames, their ID and hash), so now it properly uses sqlite3, which has been well tested, to save the session files! Calling .get_input_entity using a username no longer will need to fetch it first, so it's really 0 calls again. Calling .get_entity will always fetch the most up to date version.

    Furthermore, nearly everything has been documented, thus preparing the library for Read the Docs (although there are a few things missing I'd like to polish first), and the logging are now better placed.

    Breaking changes

    • .get_dialogs() now returns a single list instead a tuple consisting of a custom class that should make everything easier to work with.
    • .get_message_history() also returns a single list instead a tuple, with the Message instances modified to make them more convenient.

    Both lists have a .total attribute so you can still know how many dialogs/messages are in total.

    New stuff

    • The mentioned use of sqlite3 for the session file.
    • .get_entity() now supports lists too, and it will make as little API calls as possible if you feed it InputPeer types. Usernames will always be resolved, since they may have changed.
    • .set_proxy() method, to avoid having to create a new TelegramClient.
    • More date types supported to represent a date parameter.

    Bug fixes

    • Empty strings weren't working when they were a flag parameter (e.g., setting no last name).
    • Fix invalid assertion regarding flag parameters as well.
    • Avoid joining the background thread on disconnect, as it would be None due to a race condition.
    • Correctly handle None dates when downloading media.
    • .download_profile_photo was failing for some channels.
    • .download_media wasn't handling Photo.

    Internal changes

    • date was being serialized as local date, but that was wrong.
    • date was being represented as a float instead of an int.
    • .tl parser wasn't stripping inline comments.
    • Removed some redundant checks on update_state.py.
    • Use a synchronized queue instead a hand crafted version.
    • Use signed integers consistently (e.g. salt).
    • Always read the corresponding TLObject from API responses, except for some special cases still.
    • A few more except low level to correctly wrap errors.
    • More accurate exception types.
    • invokeWithLayer(initConnection(X)) now wraps every first request after .connect().

    As always, report if you have issues with some of the changes!

    Source code(tar.gz)
    Source code(zip)
  • v0.15.5(Nov 16, 2017)

    Scheme layer used: 73

    It's here, it has come! The library now supports IPv6! Just pass use_ipv6=True when creating a TelegramClient. Note that I could not test this feature because my machine doesn't have IPv6 setup. If you know IPv6 works in your machine but the library doesn't, please refer to #425.

    Additions

    • IPv6 support.
    • New method to extract the text surrounded by MessageEntity's, in the extensions.markdown module.

    Enhancements

    • Markdown parsing is Done Right.
    • Reconnection on failed invoke. Should avoid "number of retries reached 0" (#270).
    • Some missing autocast to Input* types.
    • The library uses the NullHandler for logging as it should have always done.
    • TcpClient.is_connected() is now more reliable.

    Bug fixes

    • Getting an entity using their phone wasn't actually working.
    • Full entities aren't saved unless they have an access_hash, to avoid some None errors.
    • .get_message_history was failing when retrieving items that had messages forwarded from a channel.
    Source code(tar.gz)
    Source code(zip)
  • v0.15.4(Nov 4, 2017)

    Scheme layer used: 72

    This update brings a few general enhancements that are enough to deserve a new release, with a new feature: beta markdown-like parsing for .send_message()!

    Additions

    • .send_message() supports parse_mode='md' for Markdown! It works in a similar fashion to the official clients (defaults to double underscore/asterisk, like **this**). Please report any issues with emojies or enhancements for the parser!
    • New .idle() method so your main thread can do useful job (listen for updates).
    • Add missing .to_dict(), __str__ and .stringify() for TLMessage and MessageContainer.

    Bug fixes

    • The list of known peers could end "corrupted" and have users with access_hash=None, resulting in struct error for it not being an integer. You shouldn't encounter this issue anymore.
    • The warning for "added update handler but no workers set" wasn't actually working.
    • .get_input_peer was ignoring a case for InputPeerSelf.
    • There used to be an exception when logging exceptions (whoops) on update handlers.
    • "Downloading contacts" would produce strange output if they had semicolons (;) in their name.
    • Fix some cyclic imports and installing dependencies from the git repository.
    • Code generation was using f-strings, which are only supported on Python ≥3.6.

    Other changes

    • The auth_key generation has been moved from .connect() to .invoke(). There were some issues were .connect() failed and the auth_key was None so this will ensure to have a valid auth_key when needed, even if BrokenAuthKeyError is raised.
    • Support for higher limits on .get_history() and .get_dialogs().
    • Much faster integer factorization when generating the required auth_key. Thanks @delivrance for making me notice this, and for the pull request.
    Source code(tar.gz)
    Source code(zip)
  • v0.15.3(Oct 20, 2017)

    Hopefully a very ungrateful bug has been removed. When you used to invoke some request through update handlers, it could potentially enter an infinite loop. This has been mitigated and it's now safe to invoke things again! A lot of updates were being dropped (all those gzipped), and this has been fixed too.

    More bug fixes include a correct parsing of certain TLObjects thanks to @stek29, and some wrong calls that would cause the library to crash thanks to @andr-04, and the ReadThread not re-starting if you were already authorized.

    Internally, the .to_bytes() function has been replaced with __bytes__ so now you can do bytes(tlobject).

    Source code(tar.gz)
    Source code(zip)
  • v0.15.2(Oct 14, 2017)

    This release primarly focuses on a few bug fixes and enhancements. Although more stuff may have broken along the way.

    Bug fixes:

    • .get_input_entity was failing for IDs and other cases, also making more requests than it should.
    • Use basename instead abspath when sending a file. You can now also override the attributes.
    • EntityDatabase.__delitem__ wasn't working.
    • .send_message() was failing with channels.
    • .get_dialogs(limit=None) should now return all the dialogs correctly.
    • Temporary fix for abusive duplicated updates.

    Enhancements:

    • You will be warned if you call .add_update_handler with no update_workers.
    • New customizable threshold value on the session to determine when to automatically sleep on flood waits. See client.session.flood_sleep_threshold.
    • New .get_drafts() method with a custom Draft class by @JosXa.
    • Join all threads when calling .disconnect(), to assert no dangling thread is left alive.
    • Larger chunk when downloading files should result in faster downloads.
    • You can use a callable key for the EntityDatabase, so it can be any filter you need.

    Internal changes:

    • MsgsAck is now sent in a container rather than its own request.
    • .get_input_photo is now used in the generated code.
    • .process_entities was being called from more places than only __call__.
    • MtProtoSender now relies more on the generated code to read responses.
    Source code(tar.gz)
    Source code(zip)
  • v0.15.1(Oct 5, 2017)

    The main feature of this release is that Telethon now has a custom database for all the entities you encounter, instead depending on @lru_cache on the .get_entity() method.

    The EntityDatabase will, by default, cache all the users, chats and channels you find in memory for as long as the program is running. The session will, by default, save all key-value pairs of the entity identifiers and their hashes (since Telegram may send an ID that it thinks you already know about, we need to save this information).

    You can prevent the EntityDatabase from saving users by setting client.session.entities.enabled = False, and prevent the Session from saving input entities at all by setting client.session.save_entities = False. You can also clear the cache for a certain user through client.session.entities.clear_cache(entity=None), which will clear all if no entity is given.

    More things:

    • .sign_in accepts phones as integers.
    • .get_dialogs() doesn't fail on Windows anymore, and returns the right amount of dialogs.
    • New method to .delete_messages().
    • New ChannelPrivateError class
    • Changing the IP to which you connect to is as simple as client.session.server_address = 'ip', since now the server address is always queried from the session.
    • GeneralProxyError should be passed to the main thread again, so that you can handle it.
    Source code(tar.gz)
    Source code(zip)
  • v0.15(Oct 1, 2017)

    After hundreds of lines changed on a major refactor, it's finally here. It's the Updates Overhaul Update; let's get right into it!

    New stuff and enhancements

    • You can invoke requests from update handlers. And any other thread. A new temporary will be made, so that you can be sending even several requests at the same time!
    • Several worker threads for your updates! By default, None will spawn. I recommend you to work with update_workers=4 to get started, these will be polling constantly for updates.
    • You can also change the number of workers at any given time.
    • The library can now run in a single thread again, if you don't need to spawn any at all. Simply set spawn_read_thread=False when creating the TelegramClient!
    • You can specify limit=None on .get_dialogs() to get all of them[1].
    • Updates are expanded, so you don't need to check if the update has .updates or an inner .update anymore.
    • All InputPeer entities are saved in the session file, but you can disable this by setting save_entities=False.
    • New .get_input_entity method, which makes use of the above feature. You should use this when a request needs a InputPeer, rather than the whole entity (although both work).

    Less important enhancements

    • Assert that either all or None dependent-flag parameters are set before sending the request.
    • Phone numbers can have dashes, spaces, or parenthesis. They'll be removed before making the request.
    • You can override the phone and its hash on .sign_in(), if you're creating a new TelegramClient on two different places.

    Compatibility breaks

    • .create_new_connection() is gone for good. No need to deal with this manually since new connections are now handled on demand by the library itself.

    Bugs fixed

    • .log_out() was consuming all retries. It should work just fine now.
    • The session would fail to load if the auth_key had been removed manually.
    • Updates.check_error was popping wrong side, although it's been completely removed.
    • ServerError's will be ignored, and the request will immediately be retried.
    • Cross-thread safety when saving the session file.
    • Some things changed on a matter of when to reconnect, so please report any bugs!

    Internal changes

    • TelegramClient is now only an abstraction over the TelegramBareClient, which can only do basic things, such as invoking requests, working with files, etc. If you don't need any of the abstractions the TelegramClient, you can now use the TelegramBareClient in a much more comfortable way.
    • MtProtoSender is not thread-safe, but it doesn't need to be since a new connection will be spawned when needed.
    • New connections used to be cached and then reused. Now only their sessions are saved, as temporary connections are spawned only when needed.
    • Added more RPC errors to the list.

    [1]: Broken due to a condition which should had been the opposite (sigh), fixed 4 commits ahead on https://github.com/LonamiWebs/Telethon/commit/62ea77cbeac7c42bfac85aa8766a1b5b35e3a76c.


    That's pretty much it, although there's more work to be done to make the overall experience of working with updates even better. Stay tuned!

    Source code(tar.gz)
    Source code(zip)
  • v0.14.2(Sep 29, 2017)

    Two bug fixes, one of them quite important, related to the serialization. Every object or request that had to serialize a True/False type was always being serialized as false!

    Another bug that didn't allow you to leave as None flag parameters that needed a list has been fixed.

    Other internal changes include a somewhat more readable .to_bytes() function and pre-computing the flag instead using bit shifting. The TLObject.constructor_id has been renamed to TLObject.CONSTRUCTOR_ID, and .subclass_of_id is also uppercase now.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.1(Sep 28, 2017)

    Version v0.14 had started working on the new .to_bytes() method to dump the BinaryWriter and its usage on the .on_send() when serializing TLObjects, and this release finally removes it. The speed up when serializing things to bytes should now be over twice as fast wherever it's needed.

    Other internal changes include using proper classes (including the generated code) for generating authorization keys and to write out TLMessage's.

    For bug fixes, this version is again compatible with Python 3.x versions below 3.5 (there was a method call that was Python 3.5 and above).

    Source code(tar.gz)
    Source code(zip)
  • v0.14(Sep 27, 2017)

    New major release, since I've decided that these two features are big enough:

    • Requests larger than 512 bytes will be compressed through gzip, and if the result is smaller, this will be uploaded instead.
    • You can now send multiple requests at once, they're simply *var_args on the .invoke(). Note that the server doesn't guarantee the order in which they'll be executed!

    Internally, another important change. The .on_send function on the TLObjects is gone, and now there's a new .to_bytes(). From my tests, this has always been over twice as fast serializing objects, although more replacements need to be done, so please report any issues.

    Besides this:

    • Downloading media from CDNs wasn't working (wrong access to a parameter).
    • Correct type hinting.
    • Added a tiny sleep when trying to perform automatic reconnection.
    • Error reporting is done in the background, and has a shorter timeout.
    • Implemented .get_input_media helper methods. Now you can even use another message as input media!
    • setup.py used to fail with wrongly generated code.
    Source code(tar.gz)
    Source code(zip)
  • v0.13.6(Sep 23, 2017)

    Before getting any further, here's a quick fix-up with things that should have been on v0.13.5 but were missed. Specifically, the timeout when receiving a request will now work properly.

    Some other additions are a tiny fix when handling updates, which was ignoring some of them, nicer __str__ and .stringify() methods for the TLObject's, and not stopping the ReadThread if you try invoking something there (now it simply returns None).

    Source code(tar.gz)
    Source code(zip)
  • v0.13.5(Sep 23, 2017)

    Yet another update to fix some bugs and increase the stability of the library, or, at least, that was the attempt!

    This release should really improve the experience with the background thread that the library starts to read things from the network as soon as it can, but I can't spot every use case, so please report any bug (and as always, minimal reproducible use cases will help a lot).

    Bug fixes

    • setup.py was failing on Python < 3.5 due to some imports.
    • Duplicated updates should now be ignored.
    • .send_message would crash in some cases, due to having a typo using the wrong object.
    • "socket is None" when calling .connect() should not happen anymore.
    • BrokenPipeError was still being raised due to an incorrect order on the try/except block.

    Enhancements

    • Type hinting for all the generated Request's and TLObjects! IDEs like PyCharm will benefit from this.
    • ProxyConnectionError should properly be passed to the main thread for you to handle.
    • The background thread will only be started after you're authorized on Telegram (i.e. logged in), and several other attempts at polishing the experience with this thread.
    • The Connection instance is only created once now, and reused later.
    • Calling .connect() should have a better behavior now (like actually trying to connect even if we seemingly were connected already).
    • .reconnect() behavior has been changed to also be more consistent by making the assumption that we'll only reconnect if the server has disconnected us, and is now private.

    Other changes

    • TLObject.__repr__ doesn't show the original TL definition anymore, it was a lot of clutter. If you have any complaints open an issue and we can discuss it.
    • Internally, the '+' from the phone number is now stripped, since it shouldn't be included.
    • Spotted a new place where BrokenAuthKeyError would be raised, and it now is raised there.
    Source code(tar.gz)
    Source code(zip)
  • v0.13.4(Sep 18, 2017)

    New stuff:

    • TelegramClient now exposes a .is_connected() method.
    • Initial authorization on a new data center will retry up to 5 times by default.
    • Errors that couldn't be handled on the background thread will be raised on the next call to .invoke() or updates.poll().

    Bugs fixed:

    • Now you should be able to sign in even if you have process_updates=True and no previous session.
    • Some errors and methods are documented a bit clearer.
    • .send_message() could randomly fail, as the returned type was not expected.

    Things that should reduce the amount of crashes:

    • TimeoutError is now ignored, since the request will be retried up to 5 times by default.
    • "-404" errors (BrokenAuthKeyError's) are now detected when first connecting to a new data center.
    • BufferError is handled more gracefully, in the same way as InvalidCheckSumError's.
    • Attempt at fixing some "NoneType has no attribute…" errors (with the .sender).

    Other internal changes:

    • Calling GetConfigRequest is now made less often.
    • The initial_query parameter from .connect() is gone, as it's not needed anymore.
    • Renamed all_tlobjects.layer to all_tlobjects.LAYER (since it's a constant).
    • The message from BufferError is now more useful.
    Source code(tar.gz)
    Source code(zip)
  • v0.13.3(Sep 14, 2017)

    Bugs fixed

    • Reconnection used to fail because it tried invoking things from the ReadThread.
    • Inferring random ids for ForwardMessagesRequest wasn't working.
    • Downloading media from CDNs failed due to having forgotten to remove a single line.
    • TcpClient.close() now has a threading.Lock, so NoneType has no close() should not happen.
    • New workaround for msg seqno too low/high. Also, both Session.id/seq are not saved anymore.

    Enhancements

    • Request will be retried up to 5 times by default rather than failing on the first attempt.
    • InvalidChecksumError's are now ignored by the library.
    • TelegramClient.get_entity() is now public, and uses the @lru_cache() decorator.
    • New method to .send_voice_note()'s.
    • Methods to send message and media now support a reply_to parameter.
    • .send_message() now returns the full message which was just sent.
    Source code(tar.gz)
    Source code(zip)
  • v0.13.2(Sep 8, 2017)

    This update brings a new way to work with updates, and it's begging for your feedback, or better names or ways to do what you can do now.

    Please refer to the wiki/Usage Modes for an in-depth description on how to work with updates now. Notice that you cannot invoke requests from within handlers anymore, only the v.0.13.1 patch allowed you to do so.

    Other fixes:

    • Periodic pings are back.
    • The username regex mentioned on UsernameInvalidError was invalid, but it has now been fixed.
    • Sending a message to a phone number was failing because the type used for a request had changed on layer 71.
    • CDN downloads weren't working properly, and now a few patches have been applied to ensure more reliability, although I couldn't personally test this, so again, report any feedback.
    Source code(tar.gz)
    Source code(zip)
  • v0.13.1(Sep 4, 2017)

    Please read, unless you don't handle updates in any way.

    A silly "bug" which hadn't been spotted has now been fixed. Now you can invoke other requests from within your update callbacks. However this is not advised. You should post these updates to some other thread, and let that thread do the job instead. Invoking a request from within a callback will mean that, while this request is being invoked, no other things will be read.

    Internally, the generated code now resides under a lot less files, simply for the sake of avoiding so many unnecessary files. The generated code is not meant to be read by anyone, simply to do its job.

    Unused attributes have been removed from the TLObject class too, and .sign_up() returns the user that just logged in in a similar way to .sign_in() now.

    Source code(tar.gz)
    Source code(zip)
  • v0.13(Sep 4, 2017)

    Scheme layer used: 71

    The purpose of this release is to denote a big change, now you can connect to Telegram through different connection modes. Also, a second thread will always be started when you connect a TelegramClient, despite whether you'll be handling updates or ignoring them, whose sole purpose is to constantly read from the network.

    The reason for this change is as simple as "reading and writing shouldn't be related". Even when you're simply ignoring updates, this way, once you send a request you will only need to read the result for the request. Whatever Telegram sent before has already been read and outside the buffer.

    Additions

    • The mentioned different connection modes, and a new thread.
    • You can modify the Session attributes through the TelegramClient constructor (using **kwargs).
    • RPCError's now belong to some request you've made, which makes more sense.
    • get_input_* now handles None (default) parameters more gracefully (it used to crash).

    Enhancements

    • The low-level socket doesn't use a handcrafted timeout anymore, which should benefit by avoiding the arbitrary sleep(0.1) that there used to be.
    • TelegramClient.sign_in will call .send_code_request if no code was provided.

    Deprecation:

    • .sign_up does not take a phone argument anymore. Change this or you will be using phone as code, and it will fail! The definition looks like def sign_up(self, code, first_name, last_name='').
    • The old JsonSession finally replaces the original Session (which used pickle). If you were overriding any of these, you should only worry about overriding Session now.
    Source code(tar.gz)
    Source code(zip)
  • v0.12.2(Aug 28, 2017)

    Since the Content Distributed Network (CDN) is not handled by Telegram itself, the owners may tamper these files. Telegram sends their sha256 sum for clients to implement this additional verification step, which now the library has. If any CDN has altered the file you're trying to download, CdnFileTamperedError will be raised to let you know.

    Besides this. TLObject.stringify() was showing bytes as lists (now fixed) and RPC errors are reported by default:

    In an attempt to help everyone who works with the Telegram API, Telethon will by default report all Remote Procedure Call errors to PWRTelegram, a public database anyone can query, made by Daniil. All the information sent is a GET request with the error code, error message and method used.

    If you still would like to opt out, simply set client.session.report_errors = False to disable this feature. However Daniil would really thank you if you helped him (and everyone) by keeping it on!

    Source code(tar.gz)
    Source code(zip)
  • v0.12.1(Aug 24, 2017)

    The biggest news for this update are that downloading media from CDN's (you'll often encounter this when working with popular channels) now works.

    Some bug fixes:

    • The method used to download documents crashed because two lines were swapped.
    • Determining the right path when downloading any file was very weird, now it's been enhanced.
    • The .sign_in() method didn't support integer values for the code! Now it does again.

    Some important internal changes are that the old way to deal with RSA public keys now uses a different module instead the old strange hand-crafted version.

    Hope the new, super simple README.rst encourages people to use Telethon and make it better with either suggestions, or pull request. Pull requests are super appreciated, but showing some support by leaving a star also feels nice ⭐️

    Source code(tar.gz)
    Source code(zip)
  • v0.12(Aug 22, 2017)

    Scheme layer used: 70

    This update is overall an attempt to make Telethon a bit more user friendly, along with some other stability enhancements, although it brings quite a few changes.

    Things that will probably break your code

    • The TelegramClient methods .send_photo_file(), .send_document_file() and .send_media_file() are now a single method called .send_file(). It's also important to note that the order of the parameters has been swapped: first to who you want to send it, then the file itself.

    • The same applies to .download_msg_media(), which has been renamed to .download_media(). The method now supports a Message itself too, rather than only Message.media. The specialized .download_photo(), .download_document() and .download_contact() still exist, but are private.

    More new stuff

    • Updated to layer 70!
    • Both downloading and uploading now support stream-like objects.
    • A lot faster initial connection if sympy is installed (can be installed through pip).
    • libssl will also be used if available on your system (likely on Linux based systems). This speed boost should also apply to uploading and downloading files.
    • You can use a phone number or an username for methods like .send_message(), .send_file(), and all the other quick-access methods provided by the TelegramClient.

    Bug fixes

    • Crashing when migrating to a new layer and receiving old updates should not happen now.
    • InputPeerChannel is now casted to InputChannel automtically too.
    • .get_new_msg_id() should now be thread-safe. No promises.
    • Logging out on macOS caused a crash, which should be gone now.
    • More checks to ensure that the connection is flagged correctly as either connected or not.

    Bug additions

    • Downloading files from CDN's will not work yet (something new that comes with layer 70).

    That's it, any new idea or suggestion about how to make the project even more friendly is highly appreciated.

    P.S.: Did you know that you can pretty print any result Telegram returns (called TLObject's) by using their .stringify() function? Great for debugging!

    Source code(tar.gz)
    Source code(zip)
  • v0.11.5(Jul 11, 2017)

  • v0.11.4(Jul 10, 2017)

    Scheme layer used: 68

    For some reason, Telegram doesn't have enough with the InputPeer. There also exist InputChannel and InputUser! You don't have to worry about those anymore, it's handled internally now.

    Besides this, every Telegram object now features a new default .__str__ look, and also a .stringify() method to pretty format them, if you ever need to inspect them.

    The library now uses the DEBUG level everywhere, so no more warnings or information messages if you had logging enabled.

    The no_webpage parameter from .send_message has been renamed to link_preview for clarity, so now it does the opposite (but has a clearer intention).

    Source code(tar.gz)
    Source code(zip)
  • v0.11.3(Jul 5, 2017)

  • v0.11.2(Jul 4, 2017)

    Scheme layer used: 68 (changes)

    There is a new preferred way to invoke requests, which you're encouraged to use:

    # New!
    result = client(SomeRequest())
    
    # Old.
    result = client.invoke(SomeRequest())
    

    Existing code will continue working, since the old .invoke() has not been deprecated.

    When you .create_new_connection(), it will also handle FileMigrateError's for you, so you don't need to worry about those anymore.

    Bugs fixed:

    • Fixed some errors when installing Telethon via pip (for those using either source distributions or a Python version ≤ 3.5).
    • ConnectionResetError didn't flag sockets as closed, but now it does.

    On a more technical side, msg_id's are now more accurate.

    Source code(tar.gz)
    Source code(zip)
  • v0.11.1(Jun 24, 2017)

    Scheme layer used: 66

    Receiving new updates shouldn't miss any anymore, also, periodic pings are back again so it should work on the long run.

    On a different order of things, .connect() also features a timeout. Notice that the timeout= is not passed as a parameter anymore, and is instead specified when creating the TelegramClient.

    Some other bug fixes:

    • Fixed some name class when a request had a .msg_id parameter.
    • The correct amount of random bytes is now used in DH request
    • Fixed CONNECTION_APP_VERSION_EMPTY when using temporary sessions.
    • Avoid connecting if already connected.
    Source code(tar.gz)
    Source code(zip)
  • v0.11(Jun 16, 2017)

    Scheme layer used: 66

    This update brings a lot of changes, so it would be nice if you could read the whole change log!

    Things that may break your code

    • Every Telegram error has now its own class, so it's easier to fine-tune your except's.
    • Markdown parsing is not part of Telethon itself anymore, although there are plans to support it again through a some external module.
    • The .list_sessions() has been moved to the Session class instead.
    • The InteractiveTelegramClient is not shipped with pip anymore.

    New features

    • A new, more lightweight class has been added. The TelegramBareClient is now the base of the normal TelegramClient, and has the most basic features.
    • New method to .create_new_connection(), which can be ran in parallel with the original connection. This will return the previously mentioned TelegramBareClient already connected.
    • Any file object can now be used to download a file (for instance, a BytesIO() instead a file name).
    • Vales like random_id are now automatically inferred, so you can save yourself from the hassle of writing generate_random_long() everywhere. Same applies to .get_input_peer(), unless you really need the extra performance provided by skipping one if if called manually.
    • Every type now features a new .to_dict() method.

    Bug fixes

    • Received errors are acknowledged to the server, so they don't happen over and over.
    • Downloading media on different data centers is now up to x2 faster, since there used to be an InvalidDCError for each file part tried to be downloaded.
    • Lost messages are now properly skipped.
    • New way to handle the result of requests. The old ValueError "The previously sent request must be resent. However, no request was previously sent (possibly called from a different thread)." should not happen anymore.

    Minor highlights

    • Some fixes to the JsonSession.
    • Fixed possibly crashes if trying to .invoke() a Request while .reconnect() was being called on the UpdatesThread.
    • Some improvements on the TcpClient, such as not switching between blocking and non-blocking sockets.
    • The code now uses ASCII characters only.
    • Some enhancements to .find_user_or_chat() and .get_input_peer().
    Source code(tar.gz)
    Source code(zip)
  • v0.10.1(Jun 7, 2017)

    Scheme layer used: 66

    This version is primarily for people to migrate their .session files, which are pickled, to the new JSON format. Although slightly slower, and a bit more vulnerable since it's plain text, it's a lot more resistant to upgrades.

    Please upgrade to this version before any higher one if you've used Telethon ≤ v0.10. If you happen to upgrade to an higher version, that's okay, but you will have to manually delete the *.session file, and logout from that session from an official client.

    Other highlights:

    • New .get_me() function to get the current user.
    • .is_user_authorized() is now more reliable.
    • New nice button to copy the from telethon.tl.xxx.yyy import Yyy on the online documentation.
    • Everything on the documentation is now, theoretically, sorted alphabetically.
    • More error codes added to the errors file.
    • No second thread is spawned unless one or more update handlers are added.
    Source code(tar.gz)
    Source code(zip)
  • v0.10(Jun 3, 2017)

    Scheme layer used: 66

    Working with different data centers finally works! On a different order of things, reconnection is now performed automatically every time Telegram decides to kick us off their servers, so now Telethon can really run forever and ever! In theory.

    Another important highlights:

    • Documentation improvements, such as showing the return type.
    • The msg_id too low/high error should happen less often, if any.
    • Sleeping on the main thread is not done anymore. You will have to except FloodWaitError's.
    • You can now specify your own application version, device model, system version and language code.
    • Code is now more pythonic (such as making some members private), and other internal improvements (which affect the updates thread), such as using logger instead a bare print() too.

    This brings Telethon a whole step closer to v1.0, though more things should preferably be changed.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.1(May 23, 2017)

    Scheme layer used: 66 (changes)

    Telethon used to crash a lot when logging in for the very first time. The reason for this was that the reconnection (or dead connections) were not handled properly. Now they are, so you should be able to login directly, without needing to delete the *.session file anymore. Notice that downloading from a different DC is still a WIP.

    Some highlights:

    • Updates thread is only started after a successful login.
    • Files meant to be ran by the user now use shebangs and proper permissions.
    • In-code documentation now shows the returning type.
    • Relative import is now used everywhere, so you can rename telethon to anything else.
    • Dead connections are now detected instead entering an infinite loop.
    • Sockets can now be closed (and re-opened) properly.
    • Telegram decided to update the layer 66 without increasing the number. This has been fixed and now we're up-to-date again.
    Source code(tar.gz)
    Source code(zip)
Owner
LonamiWebs
The place where Lonami does his things. Telegram group over https://t.me/LonamiWebs
LonamiWebs
Documentation and Samples for the Official HN API

Hacker News API Overview In partnership with Firebase, we're making the public Hacker News data available in near real time. Firebase enables easy acc

Y Combinator Hacker News 9.6k Jan 03, 2023
Provide fine-grained push access to GitHub from a JupyterHub

github-app-user-auth Provide fine-grained push access to GitHub from a JupyterHub. Goals Allow users on a JupyterHub to grant push access to only spec

Yuvi Panda 20 Sep 13, 2022
One destination for all the developer's learning resources.

DevResources One destination for all the developer's learning resources. Find all of your learning resources under one roof and add your own. Live ✨ Y

Gaurav Sharma 33 Oct 21, 2022
A Collection Manager for the objkt.com Minting Factory

Objkt Collection Manager A Collection Manager for the objkt.com Minting Factory. This contract can create a collection on objkt.com and mint into it.

Asbjorn Enge 5 Nov 22, 2022
Fully undetected auto skillcheck hack for dead by daylight that works decently well

Auto-skillcheck was made by Love ❌ code ✅ ❔ ・How to use Start off by installing python ofc Open cmd in the same directory and type pip install -r requ

Rdimo 10 Aug 13, 2022
NiceHash Python Library and Command Line Rest API

NiceHash Python Library and Command Line Rest API Requirements / Modules pip install requests Required data and where to get it Following data is nee

Ashlin Darius Govindasamy 2 Jan 02, 2022
Token Manager written in Python

Discord-API-Token-Entrance Description This is a Token Manager that allows your token to enter your discord server, written in python. Packages Requir

Tootle 1 Apr 15, 2022
Telegram Userbot to steram youtube live or Youtube vido in telegram vc by help of pytgcalls

TGVCVidioPlayerUB Telegram Userbot to steram youtube live or youtube vidio in telegram vc by help of pytgcalls Commands = Vidio Playing 🎧 stream :

Achu biju 3 Oct 28, 2022
ETL for tononkira.serasera.org

python-tononkiramalagasy-api Api Endpoints: ### get artists - /artists/int:page [page_offset = 20] ### get artist's songs, index was given by

Titosy Manankasina 1 Dec 24, 2021
The most expensive version of Conway's Game of Life - running on the Ethereum Blockchain

GameOfLife The most expensive implementation of Conway's Game of Life ever - over $2,000 per step! (Probably the slowest too!) Conway's Game of Life r

75 Nov 26, 2022
Git Plan - a better workflow for git

git plan A better workflow for git. Git plan inverts the git workflow so that you can write your commit message first, before you start writing code.

Rory Byrne 178 Dec 11, 2022
A google search telegram bot.

Google-Search-Bot A google search telegram bot. Made with Python3 (C) @FayasNoushad Copyright permission under MIT License License - https://github.c

Fayas Noushad 37 Nov 24, 2022
Fast and multi-threaded script to automatically claim targeted username including 14 day bypass

Instagram Username Auto Claimer Fast and multi-threaded script to automatically claim targeted username. Click here to report bugs. Usage Download ZIP

265 Dec 28, 2022
API to retrieve the number of grades on the OGE website (Website listing the grades of students) to know if a new grade is available. If a new grade has been entered, the program sends a notification e-mail with the subject.

OGE-ESIREM-API Introduction API to retrieve the number of grades on the OGE website (Website listing the grades of students) to know if a new grade is

Benjamin Milhet 5 Apr 27, 2022
Discord-selfbot - Very basic discord self bot

discord-selfbot Very basic discord self bot still being actively developed requi

nana 4 Apr 07, 2022
Bender: A Markov Babbler Slack Bot

See the Digital Ocean tutorial for instructions on how to get the basic bot structure in place. Once you have that, set the gunicorn command to run as

Andrew Howard 1 Dec 04, 2021
Example app to be deployed to AWS as an API Gateway / Lambda Stack

Disclaimer I won't answer issues or emails regarding the project anymore. The project is old and not maintained anymore. I'm not sure if it still work

Ben 123 Jan 01, 2023
A Very Simple Telegram Files Rename Bot by @AbirHasan2005

Rename-Bot This is a very simple Telegram Files Rename Bot by @AbirHasan2005. Features Rename Videos, Files or Audios. Permanent Custom Thumbnail Supp

Abir Hasan 124 Dec 25, 2022
Script que envia e-mails de denúncia para desativar número de WhatsApp.

SpamReport (Alpha) Este script foi feito apenas para uso educacional, não me responsabilizo por qualquer uso indevido. Version: 1.0 Alpha Ative essa o

Kiny-Kiny 83 Dec 20, 2022
Upload on Doodstream by Url, File and also by direct forward post from other channel...

Upload on Doodstream by Url, File and also by direct forward post from other channel...

Pʀᴇᴅᴀᴛᴏʀ 8 Aug 10, 2022