Skip to content

Instantly share code, notes, and snippets.

@avivace
Last active October 1, 2024 21:34
Show Gist options
  • Save avivace/4eb547067e364d416c074b68502e0136 to your computer and use it in GitHub Desktop.
Save avivace/4eb547067e364d416c074b68502e0136 to your computer and use it in GitHub Desktop.
Restore deleted Telegram messages from groups

Restore deleted Telegram messages, medias and files from groups

There's not telegram API method for this, we need to call MTProto methods to retrieve messages from the "Recent Actions" (Admin Log) since deleted messages (and medias) gets moved there for 48 hours before the permanent deletion.

from telethon import TelegramClient, events, sync
from telethon.tl.types import InputChannel, PeerChannel
from telethon.tl.types import Channel
import time

# Get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
#  or from https://tjhorner.dev/webogram/#/login
api_id = API_ID
api_hash = API_HASH

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

group = client.get_entity(PeerChannel(GROUP_CHAT_ID))

#messages = client.get_admin_log(group)

file1 = open("dump.json","w") 
c = 0
m = 0
for event in client.iter_admin_log(group):
    if event.deleted_message:
        print("Dumping message",c, "(", event.old.id, event.old.date,")")
        file1.write(event.old.to_json() + ",") 
        c+=1
        if event.old.media:
            m+=1
            #print(event.old.media.to_dict()['Document']['id'])
            client.download_media(event.old.media, str(event.old.id))
            print(" Dumped media", m)
        time.sleep(0.1)

FAQ

How do I run this?

Please check https://docs.python.org/3/faq/

@avivace
Copy link
Author

avivace commented Aug 13, 2023

I've created a discord server to ease the conversation for people needing to install python/help in executing the script: https://discord.gg/zpu7YUP3Um

@gitneep
Copy link

gitneep commented Oct 10, 2023

Can this be altered so that it can also be run as a non-admin? E.g. a bot that sits in the group and records all messages and notices when a message has been deleted and flags this to the owner of the bot?

@a-zazell
Copy link

a-zazell commented Dec 9, 2023

How to restore data into the group?

@gasl20
Copy link

gasl20 commented Dec 14, 2023

Hi guys
I have
api_id = **
api_hash = **
group_id = **

But when I run
c:\1>python backup_script.py
I have
Please enter your phone (or bot token): ****
Traceback (most recent call last):
File "c:\1\backup_script.py", line 13, in
client.start()
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\client\auth.py", line 128, in start
else self.loop.run_until_complete(coro)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\asyncio\base_events.py", line 684, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\client\auth.py", line 184, in _start
await self.send_code_request(phone, force_sms=force_sms)
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\client\auth.py", line 434, in send_code_request
result = await self(functions.auth.SendCodeRequest(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\client\users.py", line 30, in call
return await self._call(self._sender, request, ordered=ordered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\client\users.py", line 67, in _call
future = sender.send(request, ordered=ordered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\network\mtprotosender.py", line 183, in send
state = RequestState(request)
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\network\requeststate.py", line 17, in init
self.data = bytes(request)
^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\tl\tlobject.py", line 194, in bytes
return self._bytes()
^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\tl\functions\auth.py", line 643, in _bytes
self.serialize_bytes(self.api_hash),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\hunny\AppData\Local\Programs\Python\Python312\Lib\site-packages\telethon\tl\tlobject.py", line 112, in serialize_bytes
raise TypeError(
TypeError: bytes or str expected, not <class 'int'>

Any help, please

@AP-XD
Copy link

AP-XD commented Dec 24, 2023

I want to send it to some group/channel instead of downloading it

@astrorookie
Copy link

Can this be altered so that it can also be run as a non-admin? E.g. a bot that sits in the group and records all messages and notices when a message has been deleted and flags this to the owner of the bot?

I doubt this, as it uses your account so you would need admin access to view (and therefore) save the messages

@AP-XD
Copy link

AP-XD commented Feb 19, 2024

Can this be altered so that it can also be run as a non-admin? E.g. a bot that sits in the group and records all messages and notices when a message has been deleted and flags this to the owner of the bot?

I doubt this, as it uses your account so you would need admin access to view (and therefore) save the messages

I actually wrote the code which will download the file and then send it to desired channel via telethon

@dJani97
Copy link

dJani97 commented Feb 27, 2024

Can this be altered so that it can also be run as a non-admin? E.g. a bot that sits in the group and records all messages and notices when a message has been deleted and flags this to the owner of the bot?

I doubt this, as it uses your account so you would need admin access to view (and therefore) save the messages

I actually wrote the code which will download the file and then send it to desired channel via telethon

Hi, can you please share this code?

@dJani97
Copy link

dJani97 commented Feb 27, 2024

Here is my attempt at creating a "restore" script. Note that you cannot restore messages with their original date, so this script will send them as brand new messages, and append the original date to the message body. It will also send photo, video, audio, etc. media messages, and stickers correctly.

First of all, you will have to edit the dump.json file, because OP's script does not output valid json format. To fix this, append [ at the beginning, and ] at the end of the file.

Then run this script in the same folder where you ran OP's script. Don't forget to replace the api_id, api_hash and chat_id variables.

import json
import time
import glob
from telethon import TelegramClient
from telethon.tl.types import PeerChat
from datetime import datetime

with open("dump.json","r") as file:
    content = json.load(file)
    # sort by date:
    content = sorted(content, key=lambda x: x["date"])

    api_id = API_ID
    api_hash = API_HASH
    chat_id = GROUP_CHAT_ID

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

    group = client.get_entity(PeerChat(chat_id))

    for msg in content:

        message_id = msg["id"]
        message = msg["message"]
        has_media = msg['media'] != None
        has_message = message != ""
        date = datetime.fromisoformat(msg["date"]).strftime("%Y %b %d, %H:%M")

        # print message, date, and attachment info:
        print(f"{i} {message}, {date}, has_media: {has_media}")

        if (has_message):
            message = str(date) + "\n\n" + str(message)
        else:
            message = str(date)

        did_send_media_msg = False

        if has_media:
            file_names = glob.glob(f"{message_id}.*")
            for file_name in file_names:
                print(f"Sending Media: {file_name}")
                client.send_file(entity=group, file=file_name, caption=message, silent=True)
                did_send_media_msg = True

        elif has_message or (not did_send_media_msg):
            print(f"Sending Message: {message}")
            client.send_message(entity=group, message=message, silent=True)

        # sleep to avoid rate limiting, you may experiment with reducing this time:
        time.sleep(1)

@TTKK11
Copy link

TTKK11 commented May 3, 2024

Hello, Can someone help me recover my telegram messages? I can pay!!

@Silenseo
Copy link

Silenseo commented Jun 26, 2024

Gyus! I've updated code from dJani97

python
import json
import time
import glob
from telethon import TelegramClient
from telethon.tl.types import PeerChannel
from datetime import datetime
import asyncio

async def main():
    with open("dump.json", "r") as file:
        content = json.load(file)
        # sort by date:
        content = sorted(content, key=lambda x: x["date"])

        api_id = '__'
        api_hash = '__'
        chat_id = '__'

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

        group = await client.get_entity(PeerChannel(int(chat_id)))

        for msg in content:
            message_id = msg["id"]
            message = msg.get("message", "")
            has_media = msg.get('media', None) is not None
            has_message = message != ""
            date = datetime.fromisoformat(msg["date"]).strftime("%Y %b %d, %H:%M")

            # print message, date, and attachment info:
            print(f"{message_id} {message}, {date}, has_media: {has_media}")

            if has_message:
                message = str(date) + "\n\n" + str(message)
            else:
                message = str(date)

            did_send_media_msg = False

            if has_media:
                file_names = glob.glob(f"{message_id}.*")
                for file_name in file_names:
                    print(f"Sending Media: {file_name}")
                    try:
                        await client.send_file(entity=group, file=file_name, caption=message, silent=True)
                        did_send_media_msg = True
                    except Exception as e:
                        print(f"Error sending media {file_name}: {str(e)}")

            if has_message or not did_send_media_msg:
                print(f"Sending Message: {message}")
                try:
                    await client.send_message(entity=group, message=message, silent=True)
                except Exception as e:
                    print(f"Error sending message: {str(e)}")

            # sleep to avoid rate limiting, you may experiment with reducing this time:
            time.sleep(2)

asyncio.run(main())

Added sending message in any case, added async() and just fixed code and now it's working)

@shadowthevoronin
Copy link

shadowthevoronin commented Jul 30, 2024

@Silenseo hello, can you help with that error?

Traceback (most recent call last):
File "/Users/mishachka/Desktop/untitled folder/restore_order.py", line 61, in
asyncio.run(main())
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 194, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/Users/mishachka/Desktop/untitled folder/restore_order.py", line 11, in main
content = json.load(file)
^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/json/init.py", line 293, in load
return loads(fp.read(),
^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/json/init.py", line 346, in loads
return _default_decoder.decode(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1899754 (char 1899753)

@Silenseo
Copy link

can you help with that error?

Something happened with your JSON file.
Please look at this point:

To fix this, append [ at the beginning, and ] at the end of the file.

@shadowthevoronin
Copy link

can you help with that error?

Something happened with your JSON file. Please look at this point:

To fix this, append [ at the beginning, and ] at the end of the file.

yeah I checked it, no luck. Tried the same on windows and works just fine (except noticed the comma at the end of JSON and removed it maybe that was an issue). Thank you very much, regardless! That helped a lot

@Silenseo
Copy link

Thank you very much, regardless! That helped a lot

You're welcome)

@f-alex
Copy link

f-alex commented Aug 2, 2024

api_id = ''
api_hash = ''
chat_id = ''
I hope these are not real account )

@Kebble002
Copy link

Thank you very much, regardless! That helped a lot

You're welcome)

I mangaged to run the code successfully, but nothing is happening after i logged in. what could be wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment