Search code examples
pythontelethon

Problem at providing entities to NewMessage event


The NewMessage event of telethon has an argument named from_users which controls the event to only occur when the new message is from those users. This argument accept entity as input. In order to get this entity, one must run the client and call the get_entity method.

The problem is, when you run the client, the event is already set and prints out an error, because the input arguments are None or missing. and if you don't run the client, you don't have the desired_channel entity to provide to NewMessage event. at least this is my understanding of documentation and how the code is currently behaving for me.

i'm trying the following:

receiver.py:

from telethon import TelegramClient
from telegram.api_library import (
    write_in_saved_messages,
    get_entity_data,
)
from user_files.user_settings import (
    USER_SESSION_NAME,
    USER_TELEGRAM_API_HASH,
    USER_TELEGRAM_API_ID,
)

telegram_client: TelegramClient = TelegramClient(
    USER_SESSION_NAME, USER_TELEGRAM_API_ID, USER_TELEGRAM_API_HASH

async def main():
    """The main loop of message receiver"""
    # This calls a function that writes in saved messages section from another module
    await write_in_saved_messages(telegram_client, "Message Receiver started!")

    # Get channel entity
    # This also calls a function that gets entity of a given channel name from another module
    desired_channel = await get_entity_data(
        telegram_client, "desired_channel_name"
    )

# Create the event
@events.register(
    events.NewMessage(
        incoming=True,
        from_users=(desired_channel),
    )
)
async def message_received(event):
    """This function will be called when a new message comes from the desired channel

    Args:
    event (_type_): Event containing information about the message
    """

    incoming_message_text = event.message

    sender_id = (await event.get_input_sender()).channel_id

    print(f"Message from {sender_id}:\n{incoming_message_text}")

def start_receiver():
    """Start the receiver"""
    with telegram_client:
        telegram_client.loop.create_task(main())
        telegram_client.add_event_handler(message_received)
        telegram_client.run_until_disconnected()

How should i do it? How to have an entity before running the client and getting the needed entity ?? i'm confused


Solution

  • So the following code does work as i want, but i don't think this is the way it should be done.

    I edited the event to this:

    @events.register(
        events.NewMessage(
            incoming=True,  # I removed the (from_users) argument
        )
    )
    async def message_received(event):
        """This function will be called when a new message comes from the defined channels
    
        Args:
        event (_type_): Event containing information about the message
        """
    
        incoming_message_text = event.message.message
    
        # We use try block here as we are going to get (channel_id) for all incoming messages
        # because we are getting all incoming chats, this also includes users
        # which don't have (channel_id) so an exception occurs
        try:
            sender_id = (await event.get_input_sender()).channel_id
    
            if sender_id == desired_channel_id:
                print(f"Message from {sender_id}:\n{incoming_message_text}")
        # If Sender is NOT a channel, this exception occurs, we ignore it
        except AttributeError as e:
            print(e)
    

    This is a hacky/inefficient way of getting the job done and i accept it, yet i don't know the correct way.

    Until someone responds with a better answer, others facing this issue can use this hack at least.