gram-js / gramjs

NodeJS/Browser MTProto API Telegram client library,
MIT License
1.28k stars 179 forks source link

Listen new messages from public channel #535

Open GuillermoSanzCastillo opened 1 year ago

GuillermoSanzCastillo commented 1 year ago

Hello, I'm trying to listen for new messages on a public Telegram channel. I'm logging in with the bot option from gram.js, but when I listen for the event with addEventHandler, it doesn't receive anything. Do I need to log in as a user, or am I forgetting something?

Here is my .conf file:

const telegram = require('telegram');
const {
    TelegramClient
} = require("telegram");

const storeSession = new telegram.sessions.StoreSession('my_session');

const BOT_TOKEN = "XXXXXXXX"; // my bot token here
const api_id = xxxxx; // my app_id
const api_hash = xxxxx; // my app_hash
connect();

async function connect() {
    const client = new TelegramClient(
        storeSession,
        api_id,
        api_hash, {
            connectionRetries: 5
        }
    );

    await client.connect();
    if (!await client.checkAuthorization()) {

        await client.start({
            botAuthToken: BOT_TOKEN
        });
        client.session.save()

    } else {
        console.log('LOGED')
    }

    return client;
}

module.exports.connect = connect;

And my other file the import conf:


const { Api, TelegramClient } = require("telegram");
const { NewMessage } = require('telegram/events')

var client_conf = require('./telegram_conf.js');
const channelUsername = 'my_username_channel';

getChat();

async function getChat() {
  let client = await client_conf.connect();
   await client.getMe();

  try {
    client.addEventHandler(async (event) => {
      // nothing showing!!!
      eventPrint();
  }, new NewMessage({ incoming: true, channels: [channelUsername] }));
  } catch (error) {
    console.log('error', error)
  }
}

async function eventPrint(event) {
  const message = event.message;
  // Checks if it's a private message (from user or bot)
  if (event.isPrivate) {
    // prints sender id
    console.log(message.senderId);
    // read message
    if (message.text == "hello") {
      const sender = await message.getSender();
      console.log("sender is", sender);
      await client.sendMessage(sender, {
        message: `hi your id is ${message.senderId}`
      });
    }
  }
}```
painor commented 1 year ago

well for starter you did not pass event to eventPrint() so it will be null; Secondly the try catch will not work since the add event handler method will never throw an error. you'd want to put inside your event print code.

in short this is how the code should look like


    client.addEventHandler(async (event) => {
      // will show something
      eventPrint(event);
  }, new NewMessage({ incoming: true, channels: [channelUsername] }));

}

async function eventPrint(event) {
  const message = event.message;
  // Checks if it's a private message (from user or bot)
  if (event.isPrivate) {
    // prints sender id
    console.log(message.senderId);
    // read message
    if (message.text == "hello") {
      const sender = await message.getSender();
      console.log("sender is", sender);
      await client.sendMessage(sender, {
        message: `hi your id is ${message.senderId}`
      });
    }
  }
}
GuillermoSanzCastillo commented 1 year ago

Yes, regardless of the try block and the fact that nothing is printed in eventPrint because nothing is passed to it, the important thing I wanted to emphasize is that the addEventHandler never executes. Is it necessary for the bot to be inside the channel in order to listen for events on that channel?

painor commented 1 year ago

Yes of course. Telegram will not send you messages if you have not interacted with that channel.

What the channels property is simply filtering all the events that you receive. So if you never received an event it will obviously not be shown.

One more thing. in the code you can see that there is a (if event.isPrivate) which means that it will not show events that you received from channels. only users or bots.

GuillermoSanzCastillo commented 1 year ago

But I can access the messages of a channel without having a bot inside, in this way for example:

const result = await client.invoke( new Api.channels.GetMessages({ channel: "username", id: [43], }) );

What I would like to do is listen for when there's a new message... If the only way is to have the bot inside the channel, is it possible to add a bot as a subscriber to a public channel without being the owner of the channel?

painor commented 1 year ago

Bots are limited in functionality. It is not possible to add them without being an admin in a channel.

The best you can do is periodically get messages from the channel and see if there are any new messages sent.

GuillermoSanzCastillo commented 1 year ago

And bots like junction (https://docs.junction.space/getting-started/) that allow the user to control all the messages they want from different channels, do you think they are not constantly making queries to all the channels they have and not doing it through some listener? If that's the case, is there no limitation from Telegram on API calls?

painor commented 1 year ago

They could be using a bit amount of bots. There is a limit of 3000 messages every 3 seconds or so.

GuillermoSanzCastillo commented 1 year ago

Bots that automatically add themselves to channels, either manually or automatically, or what do you mean?

painor commented 1 year ago

bots that get messages from channels I assume? I have no idea what exactly the junction thing work tbh

GuillermoSanzCastillo commented 1 year ago

Okay, so for reading a message with a specific ID, i have this method:

new Api.channels.GetMessages({ channel: channelUsername, id: [43], }));

but how would you get a list of all or some messages, or the latest messages? Or perhaps getting the ID of the last sent message?

`const channel = await client.getEntity(channelUsername);

const result = await client.invoke(
  new Api.messages.GetHistory({
    peer: {
      _: "inputPeerChannel",
      channel_id: channelID
    },
    limit: 10
  })
);`
painor commented 1 year ago

You can't do that with bots. Only with users.

GuillermoSanzCastillo commented 1 year ago

So do I have to login with the following code? I always get the error [4.736] Error 400 PHONE_CODE_EXPIRED 2 4...

const { TelegramClient } = require('telegram') const { StringSession } = require('telegram/sessions') const input = require('input')

const apiId = xxx const apiHash = 'xxx' const stringSession = new StringSession(''); (async () => { console.log('Loading interactive example...') const client = new TelegramClient(stringSession, apiId, apiHash, { connectionRetries: 5 }) await client.start({ phoneNumber: async () => await input.text('number ?'), password: async () => await input.text('password?'), phoneCode: async () => await input.text('Code ?'), onError: (err) => console.log(err), }); console.log('You should now be connected.') console.log(client.session.save()) await client.sendMessage('me', { message: 'Hello!' }); })()

painor commented 1 year ago

That error usually means you have sent the code somewhere on telegram. you cannot send the code you recieved in a message