user3759176
user3759176

Reputation: 61

How can I get channel messages from telegram channels with TLSharp?

How can I get channel messages from telegram channels with TLSharp?

The following links haven't helped me:

Upvotes: 6

Views: 8104

Answers (3)

arash Dman
arash Dman

Reputation: 333

You can use this code

public async Task GatherChannelHistory(string channelName, int offset = 0, int maxId = -1, int limit = 50)
{
  _resultMessages.Clear();
  await _client.ConnectAsync();

  var dialogs = (TLDialogsSlice)await _client.GetUserDialogsAsync();
  var chat = dialogs.Chats.ToList()
    .OfType<TLChannel>()
    .FirstOrDefault(c => c.Title == channelName);

  if (chat.AccessHash != null)
  {
    var tlAbsMessages =
      await _client.GetHistoryAsync(
        new TLInputPeerChannel {ChannelId= chat.Id, AccessHash = chat.AccessHash.Value}, offset,
        maxId, limit);
    
    var tlChannelMessages = (TLChannelMessages) tlAbsMessages;

    for (var index = 0; index < tlChannelMessages.Messages.Count-1; index++)
    {
      var tlAbsMessage = tlChannelMessages.Messages.ToList()[index];
      var message = (TLMessage) tlAbsMessage;
      //Now you have the message and you can do what you need with it
      //the code below is an example of messages classification
      if (message.media == null)
      {
        _resultMessages.Add(new ChannelMessage()
        {
          Id = message.id,
          ChannelId = chat.id,
          Content = message.message,
          Type = EnChannelMessage.Message,
          Views = message.views,
        });
      }
      else
      {

        switch (message.media.GetType().ToString())
        {
          case "TeleSharp.TL.TLMessageMediaPhoto":
            var tLMessageMediaPhoto = (TLMessageMediaPhoto)message.media;

            _resultMessages.Add(new ChannelMessage()
            {
              Id = message.id,
              ChannelId = chat.id,
              Content = tLMessageMediaPhoto.caption,
              Type = EnChannelMessage.MediaPhoto,
              Views = message.views ?? 0,
            });
            break;
          case "TeleSharp.TL.TLMessageMediaDocument":
            var tLMessageMediaDocument = (TLMessageMediaDocument)message.media;
        
            _resultMessages.Add(new ChannelMessage()
            {
              Id = message.id,
              ChannelId = chat.id,
              Content = tLMessageMediaDocument.caption,
              Type = EnChannelMessage.MediaDocument,
              Views = message.views ?? 0,
            });
            break;
          case "TeleSharp.TL.TLMessageMediaWebPage":
            var tLMessageMediaWebPage = (TLMessageMediaWebPage)message.media;
            string url = string.Empty;
            if (tLMessageMediaWebPage.webpage.GetType().ToString() != "TeleSharp.TL.TLWebPageEmpty")
            {
              var webPage = (TLWebPage) tLMessageMediaWebPage.webpage;
              url = webPage.url;
            }
  
            _resultMessages.Add(new ChannelMessage
            {
              Id = message.id,
              ChannelId = chat.id,
              Content = message.message + @" : " + url,
              Type = EnChannelMessage.WebPage,
              Views = message.views ?? 0,
            });
            break;
        }
      }
    }
  }
}

Upvotes: 3

user9564960
user9564960

Reputation:

Not sure if this works 100% without missing any messages, but this is what I have used in one of my projects:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TeleSharp.TL;
using TeleSharp.TL.Channels;
using TeleSharp.TL.Messages;
using TLSharp.Core;
using TLSharp.Core.Utils;

namespace NewsArchive.Telegram
{
 /// <summary>
/// Created to be used as a workaround of ref/out since they cannot be used in an async method => GetMessagesInternal
/// </summary>
public class RequestOffset
{
    /// <summary>
    /// Value of the offset
    /// </summary>
    public int Id { get; set; }
}


public class TelegramNewsClient
{
    #region Properties
    private TelegramClient _client;
    private int _apiId;
    private string _apiHash;
    private static readonly int RESULT_MAX = 100; 
    #endregion

    /// <summary>
    /// Ctor
    /// </summary>
    /// <param name="apiId"></param>
    /// <param name="apiHash"></param>
    public TelegramNewsClient(int apiId, string apiHash)
    {
        _apiId = apiId;
        _apiHash = apiHash;

        _client = new TelegramClient(_apiId, _apiHash);
        _client.ConnectAsync().Wait();
    }

    /// <summary>
    /// Authenticates the user with the phone number
    /// </summary>
    /// <param name="phone"></param>
    /// <returns></returns>
    public async Task Authenticate(string phone)
    {
        var hash = await  _client.SendCodeRequestAsync(phone);
        var code = "<code_from_telegram>"; // you can change code in debugger

        var user = await _client.MakeAuthAsync(phone, hash, code);
    }

    /// <summary>
    /// Gets all messages from a channel
    /// </summary>
    /// <param name="channelName"></param>
    /// <returns></returns>
    public async Task<IEnumerable<TLMessage>> GetChannelMessages(string channelName)
    {
        var messages = new List<TLMessage>();

        var channel = await GetChannel(channelName);

        if(channel == null)
            throw new Exception($"The channel {channelName} was not found!");

        var offset = new RequestOffset(){Id = 1};
        var internalMessages = new List<TLMessage>();

        internalMessages = await GetMessagesInternal(channel.Id, channel.AccessHash.Value, offset);

        messages = messages.Concat(internalMessages)
                            .OrderBy(m => m.Id)
                            .ToList();

        while (internalMessages.Count > 0)
        {
            /*When you reach the last message, the API will keep returning the same last message over and over again,
             that's why we stop making requests and return the result*/
            if ((internalMessages.Count == 1 && internalMessages.First().Id == messages.Max(m => m.Id)))
                break;

            internalMessages = await GetMessagesInternal(channel.Id, channel.AccessHash.Value, offset);

            messages = messages.Concat(internalMessages)
                                .OrderBy(m =>m.Id)
                                .ToList();

            /*if you make too many requests you will be locked out of the API*/
            await Task.Delay(TimeSpan.FromSeconds(1));

        }

        return messages;
    }

    private async Task<List<TLMessage>> GetMessagesInternal(int channelId, long accessHash, RequestOffset offset)
    {
        /*Refer to https://core.telegram.org/api/offsets  for more info on how to use the offsets.
         Here we basically get the last RESULT_MAX (100 in this case) messages newer than the offset.Id aka offsetId*/
        var history = await _client.GetHistoryAsync(new TLInputPeerChannel
        {
            ChannelId = channelId,
            AccessHash = accessHash
        }, offset.Id, 0, -RESULT_MAX, RESULT_MAX, 0, 0) as TLChannelMessages;

        /*Some messages are service messages with no useful content, and if cast to TLMessage it will throw an exception*/
        var messages = history.Messages
                                .Where(m => m is TLMessage)
                                .Cast<TLMessage>()
                                .ToList();

        /*Get the ID of the last message so it can be used in the next API call*/
        offset.Id = messages.Max(m => m.Id);

        
        return messages;
    }

    private async Task<TLChannel> GetChannel(string channelName)
    {
        var offset = new RequestOffset() { Id = RESULT_MAX };

        var channels = (await _client.GetUserDialogsAsync(0, offset.Id, null, RESULT_MAX) as TLDialogs)
                        ?.Chats
                        ?.Cast<TLChannel>()
                        ?.ToList();

        var channel = channels?.FirstOrDefault(c => c.Username.Equals(channelName, StringComparison.OrdinalIgnoreCase));

        offset.Id += RESULT_MAX - 1;

        while (channels.Count > 0 && channel == null)
        {
            channels = (await _client.GetUserDialogsAsync(0, offset.Id, null, RESULT_MAX) as TLDialogs)
                            ?.Chats
                            ?.Cast<TLChannel>()
                            ?.ToList();

            channel = channels?.FirstOrDefault(c => c.Username.Equals(channelName, StringComparison.OrdinalIgnoreCase));

            offset.Id += RESULT_MAX - 1;

            /*if you make too many requests you will be locked out of the API*/
            await Task.Delay(TimeSpan.FromSeconds(1));
        }

        return channel;
    }
}

}

Upvotes: 1

Charles Okwuagwu
Charles Okwuagwu

Reputation: 10876

To get channel messages you simply need to be receiving channel updates.

As at TL-schema-52 you could request:

channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs; 

however this has been dropped in TL-schema-53.

I'm guessing you can try one of the other channel.* functions,

I have not tried yet on TL-schema-53

What version of the TL-schema is your TLSharp using?

You could simply implement the relevant functions if they are not yet implemented in your TLSharp version

Upvotes: 1

Related Questions