added MarkdownToEntities

This commit is contained in:
Wizou 2021-10-31 02:40:10 +01:00
parent b94ec0abca
commit e615f83db6
3 changed files with 102 additions and 2 deletions

View file

@ -15,11 +15,12 @@ Remember that these are just simple example codes that you should adjust to your
```csharp ```csharp
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
await client.LoginUserIfNeeded(); await client.LoginUserIfNeeded();
var resolved = await client.Contacts_ResolveUsername("username"); var resolved = await client.Contacts_ResolveUsername("username"); // without the @
await client.SendMessageAsync(resolved, "Hello!"); await client.SendMessageAsync(resolved, "Hello!");
``` ```
*Note: This also works if the @username points to a chat, but you must join the chat before posting there. *Note: This also works if the @username points to a chat, but you must join the chat before posting there.
You can check `resolved` properties to ensure it's a user or a chat. If the username is invalid/unused, the API call raises an exception.* You can check `resolved` properties to ensure it's a user or a chat. If the username is invalid/unused, the API call raises an exception.*
### Send a message to someone by phone number ### Send a message to someone by phone number
```csharp ```csharp
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
@ -30,6 +31,16 @@ if (contacts.imported.Length > 0)
``` ```
*Note: To prevent spam, Telegram may restrict your ability to add new phone numbers.* *Note: To prevent spam, Telegram may restrict your ability to add new phone numbers.*
### Send a Markdown message to ourself (Saved Messages)
```csharp
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);
await client.LoginUserIfNeeded();
var text = "Hello __dear *friend*__!\nEnjoy this `userbot` written with [WTelegramClient](https://github.com/wiz0u/WTelegramClient)";
var entities = client.MarkdownToEntities(ref text);
await client.SendMessageAsync(InputPeer.Self, text, entities: entities);
```
See [MarkdownV2 formatting style](https://core.telegram.org/bots/api/#markdownv2-style) for details.
### List all chats (groups/channels) the user is in and send a message to one ### List all chats (groups/channels) the user is in and send a message to one
```csharp ```csharp
using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); using var client = new WTelegram.Client(Environment.GetEnvironmentVariable);

View file

@ -436,7 +436,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
#if !NETCOREAPP2_0_OR_GREATER #if !NETCOREAPP2_0_OR_GREATER
// adapted from https://github.com/dotnet/aspnetcore/blob/main/src/DataProtection/Cryptography.KeyDerivation/src/PBKDF2/ManagedPbkdf2Provider.cs // adapted from https://github.com/dotnet/aspnetcore/blob/main/src/DataProtection/Cryptography.KeyDerivation/src/PBKDF2/ManagedPbkdf2Provider.cs
public static byte[] PBKDF2_SHA512(byte[] password, byte[] salt, int iterationCount, int numBytesRequested) private static byte[] PBKDF2_SHA512(byte[] password, byte[] salt, int iterationCount, int numBytesRequested)
{ {
// PBKDF2 is defined in NIST SP800-132, Sec. 5.3: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf // PBKDF2 is defined in NIST SP800-132, Sec. 5.3: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
byte[] retVal = new byte[numBytesRequested]; byte[] retVal = new byte[numBytesRequested];

View file

@ -353,4 +353,93 @@ namespace TL
return sb.Append('}').ToString(); return sb.Append('}').ToString();
} }
} }
public static class Helpers
{
public static MessageEntity[] MarkdownToEntities(this WTelegram.Client client, ref string text)
{
var entities = new List<MessageEntity>();
var sb = new StringBuilder(text);
for (int offset = 0; offset < sb.Length;)
{
switch (sb[offset])
{
case '\\': sb.Remove(offset++, 1); break;
case '*':
ProcessEntity<MessageEntityBold>();
break;
case '_':
if (offset + 1 < sb.Length && sb[offset + 1] == '_')
{
sb.Remove(offset, 1);
ProcessEntity<MessageEntityUnderline>();
}
else
ProcessEntity<MessageEntityItalic>();
break;
case '~':
ProcessEntity<MessageEntityStrike>();
break;
case '`':
if (offset + 2 < sb.Length && sb[offset + 1] == '`' && sb[offset + 2] == '`')
{
int header = 3;
if (entities.FindLast(e => e.length == 0) is MessageEntityPre pre)
pre.length = offset - pre.offset;
else
{
while (offset + header < sb.Length && !char.IsWhiteSpace(sb[offset + header]))
header++;
entities.Add(new MessageEntityPre { offset = offset, language = sb.ToString(offset + 3, header - 3) });
}
sb.Remove(offset, header);
}
else
ProcessEntity<MessageEntityCode>();
break;
case '[':
entities.Add(new MessageEntityTextUrl { offset = offset });
sb.Remove(offset, 1);
break;
case ']':
if (offset + 1 < sb.Length && sb[offset + 1] == '(' && entities.FindLast(e => e.length == 0) is MessageEntityTextUrl textUrl)
{
textUrl.length = offset - textUrl.offset;
sb.Remove(offset, 2);
}
else
offset++;
break;
case ')':
var lastIndex = entities.FindLastIndex(e => e.length == 0 || e is MessageEntityTextUrl { url: null });
MessageEntity entity;
if (lastIndex >= 0 && (entity = entities[lastIndex]).length != 0)
{
var urlStart = entity.offset + entity.length;
var urlLength = offset - urlStart;
var url = sb.ToString(urlStart, urlLength);
sb.Remove(urlStart, urlLength + 1);
offset = urlStart;
if (url.StartsWith("tg://user?id=") && long.TryParse(url[13..], out var user_id) && client.GetAccessHashFor<User>(user_id) is long hash && hash != 0)
entities[lastIndex] = new InputMessageEntityMentionName { offset = entity.offset, length = entity.length, user_id = new InputUser { user_id = user_id, access_hash = hash } };
else
((MessageEntityTextUrl)entity).url = url;
}
break;
default: offset++; break;
}
void ProcessEntity<T>() where T : MessageEntity, new()
{
if (entities.LastOrDefault(e => e.length == 0) is T prevEntity)
prevEntity.length = offset - prevEntity.offset;
else
entities.Add(new T { offset = offset });
sb.Remove(offset, 1);
}
}
text = sb.ToString();
return entities.Count == 0 ? null : entities.ToArray();
}
}
} }