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;
}
}
3
Answers
To get channel messages you simply need to be receiving channel updates.
As at TL-schema-52 you could request:
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
You can use this code
Not sure if this works 100% without missing any messages, but this is what I have used in one of my projects:
}