How to make this script run on realtime triggered by a message

Viewed 457

I have this script to copy messages from one channel to another on Telegram via Python. This currently will run once, copy all missing messages and then finish. How can I modify this to either run at an interval or to run when a new message comes up in a channel?

I have other files that are utilized such as the API config files with the API key / channels etc.

Even if someone can help point me in the right direction I'll dive more. I'm not very familiar with Python.


import asyncio
import logging

from telethon.tl.patched import MessageService
from telethon.errors.rpcerrorlist import FloodWaitError
from telethon import TelegramClient
from telethon.sessions import StringSession
from settings import API_ID, API_HASH, forwards, get_forward, update_offset, STRING_SESSION


logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)

SENT_VIA = f'\n__Sent via__ `{str(__file__)}`'


def intify(string):
    try:
        return int(string)
    except:
        return string


async def forward_job():
    ''' the function that does the job  '''
    if STRING_SESSION:
        session = StringSession(STRING_SESSION)
    else:
        session = 'forwarder'

    async with TelegramClient(session, API_ID, API_HASH) as client:

        confirm = ''' IMPORTANT 
            Are you sure that your `config.ini` is correct ?

            You can run the `get_chat_info.py` script to confirm the `from` and `to`.

            Press [ENTER] to continue:
            '''

        input(confirm)

        error_occured = False
        for forward in forwards:
            from_chat, to_chat, offset = get_forward(forward)

            if not offset:
                offset = 0

            last_id = 0

            async for message in client.iter_messages(intify(from_chat), reverse=True, offset_id=offset):
                if isinstance(message, MessageService):
                    continue
                try:
                    await client.send_message(intify(to_chat), message)
                    last_id = str(message.id)
                    logging.info('forwarding message with id = %s', last_id)
                    update_offset(forward, last_id)
                    
                except FloodWaitError as fwe:
                    print(f'\n{fwe}\n\nRun the script again after some time. \
                        FloodWaitError Occured')
                    quit()
                except Exception as err:
                    logging.exception(err)
                    error_occured = True
                    continue

            

if __name__ == "__main__":
    assert forwards
    asyncio.run(forward_job())
1 Answers

You need to look into Updates documentation. Using it, you'll be able to get a new message in your code.

Also you'll need to change how you handle

Will look something similar to:

from telethon import TelegramClient, events


client = TelegramClient(session, API_ID, API_HASH)

database = {}
for forward in forwards
    from_chat, to_chat, offset = get_forward(forward)
    database[from_chat] = {"to_chat": to_chat, "offset": offset}


@client.on(events.NewMessage)
async def my_event_handler(event):    
    to_chat = database.get(event.chat_id)
    if to_chat:
        await client.send_message(to_chat, event.message)
        last_id = message.id
        database[event.chat_id] = last_id
        logging.info('forwarding message with id = %s', last_id)


client.start()

# TODO: do `iter_messages` initial or while script was not running

client.run_until_disconnected()

Or if you want to call it periodically, you can either:

  • wrap method with iter_messages in a loop
    while True:
        # TODO:
        # do_iter_messages__and__forwarding()
    
        await asyncio.sleep(10)
    
  • or call method with iter_messages again from that method after some delay
    def do_iter_messages__and__forwarding():
        # TODO:
        # for message in client.iter_messages(...):
        #     do_message_forward(...)
    
        await asyncio.sleep(10)
        do_iter_messages__and__forwarding()
    
    
    
    
Related