mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
Support premium emojies in Html/Markdown helpers
This commit is contained in:
parent
faf8ab3fd0
commit
9523ca4036
2
.github/dev.yml
vendored
2
.github/dev.yml
vendored
|
|
@ -2,7 +2,7 @@ pr: none
|
|||
trigger:
|
||||
- master
|
||||
|
||||
name: 2.6.4-dev.$(Rev:r)
|
||||
name: 3.0.0-dev.$(Rev:r)
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
|
|
|
|||
2
.github/release.yml
vendored
2
.github/release.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
pr: none
|
||||
trigger: none
|
||||
|
||||
name: 2.6.$(Rev:r)
|
||||
name: 3.0.0
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ namespace WTelegram
|
|||
Path.GetDirectoryName(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar)))
|
||||
?? AppDomain.CurrentDomain.BaseDirectory, "WTelegram.session"),
|
||||
#if DEBUG
|
||||
"server_address" => "149.154.167.40:443", // Test DC 2
|
||||
"server_address" => "149.154.167.40:443", // Test DC 2
|
||||
#else
|
||||
"server_address" => "149.154.167.50:443", // DC 2
|
||||
#endif
|
||||
|
|
@ -176,7 +176,7 @@ namespace WTelegram
|
|||
}
|
||||
catch { }
|
||||
_cts?.Cancel();
|
||||
_sendSemaphore = new(0); // initially taken, first released during DoConnectAsync
|
||||
_sendSemaphore = new(0); // initially taken, first released during DoConnectAsync
|
||||
try
|
||||
{
|
||||
_reactorTask?.Wait(1000);
|
||||
|
|
@ -394,7 +394,7 @@ namespace WTelegram
|
|||
var msgId = reader.ReadInt64(); // int64 message_id
|
||||
var seqno = reader.ReadInt32(); // int32 msg_seqno
|
||||
var length = reader.ReadInt32(); // int32 message_data_length
|
||||
|
||||
|
||||
if (length < 0 || length % 4 != 0) throw new ApplicationException($"Invalid message_data_length: {length}");
|
||||
if (decrypted_data.Length - 32 - length is < 12 or > 1024) throw new ApplicationException($"Invalid message padding length: {decrypted_data.Length - 32}-{length}");
|
||||
if (sessionId != _dcSession.Id) throw new ApplicationException($"Unexpected session ID: {sessionId} != {_dcSession.Id}");
|
||||
|
|
@ -943,6 +943,7 @@ namespace WTelegram
|
|||
if (sentCode.type is Auth_SentCodeTypeSetUpEmailRequired setupEmail)
|
||||
{
|
||||
Helpers.Log(3, "A login email is required");
|
||||
RaiseUpdate(sentCode);
|
||||
var email = _config("email");
|
||||
if (string.IsNullOrEmpty(email))
|
||||
sentCode = await this.Auth_ResendCode(phone_number, sentCode.phone_code_hash);
|
||||
|
|
@ -1104,11 +1105,11 @@ namespace WTelegram
|
|||
if (_dcSession.AuthKeyID == 0) // send unencrypted message
|
||||
{
|
||||
if (_bareRpc == null) throw new ApplicationException($"Shouldn't send a {msg.GetType().Name} unencrypted");
|
||||
writer.Write(0L); // int64 auth_key_id = 0 (Unencrypted)
|
||||
writer.Write(msgId); // int64 message_id
|
||||
writer.Write(0); // int32 message_data_length (to be patched)
|
||||
writer.Write(0L); // int64 auth_key_id = 0 (Unencrypted)
|
||||
writer.Write(msgId); // int64 message_id
|
||||
writer.Write(0); // int32 message_data_length (to be patched)
|
||||
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_')}...");
|
||||
writer.WriteTLObject(msg); // bytes message_data
|
||||
writer.WriteTLObject(msg); // bytes message_data
|
||||
BinaryPrimitives.WriteInt32LittleEndian(memStream.GetBuffer().AsSpan(20), (int)memStream.Length - 24); // patch message_data_length
|
||||
}
|
||||
else
|
||||
|
|
@ -1116,19 +1117,19 @@ namespace WTelegram
|
|||
using var clearStream = new MemoryStream(1024);
|
||||
using var clearWriter = new BinaryWriter(clearStream, Encoding.UTF8);
|
||||
clearWriter.Write(_dcSession.AuthKey, 88, 32);
|
||||
clearWriter.Write(_dcSession.Salt); // int64 salt
|
||||
clearWriter.Write(_dcSession.Id); // int64 session_id
|
||||
clearWriter.Write(msgId); // int64 message_id
|
||||
clearWriter.Write(seqno); // int32 msg_seqno
|
||||
clearWriter.Write(0); // int32 message_data_length (to be patched)
|
||||
clearWriter.Write(_dcSession.Salt); // int64 salt
|
||||
clearWriter.Write(_dcSession.Id); // int64 session_id
|
||||
clearWriter.Write(msgId); // int64 message_id
|
||||
clearWriter.Write(seqno); // int32 msg_seqno
|
||||
clearWriter.Write(0); // int32 message_data_length (to be patched)
|
||||
if ((seqno & 1) != 0)
|
||||
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_'),-40} #{(short)msgId.GetHashCode():X4}");
|
||||
else
|
||||
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_'),-40} {MsgIdToStamp(msgId):u} (svc)");
|
||||
clearWriter.WriteTLObject(msg); // bytes message_data
|
||||
clearWriter.WriteTLObject(msg); // bytes message_data
|
||||
int clearLength = (int)clearStream.Length - 32; // length before padding (= 32 + message_data_length)
|
||||
int padding = (0x7FFFFFF0 - clearLength) % 16;
|
||||
padding += _random.Next(1, 64) * 16; // MTProto 2.0 padding must be between 12..1024 with total length divisible by 16
|
||||
padding += _random.Next(1, 64) * 16; // MTProto 2.0 padding must be between 12..1024 with total length divisible by 16
|
||||
clearStream.SetLength(32 + clearLength + padding);
|
||||
byte[] clearBuffer = clearStream.GetBuffer();
|
||||
BinaryPrimitives.WriteInt32LittleEndian(clearBuffer.AsSpan(60), clearLength - 32); // patch message_data_length
|
||||
|
|
@ -1137,9 +1138,9 @@ namespace WTelegram
|
|||
const int msgKeyOffset = 8; // msg_key = middle 128-bits of SHA256(authkey_part+plaintext+padding)
|
||||
byte[] encrypted_data = EncryptDecryptMessage(clearBuffer.AsSpan(32, clearLength + padding), true, _dcSession.AuthKey, msgKeyLarge, msgKeyOffset, _sha256);
|
||||
|
||||
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
||||
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
||||
writer.Write(encrypted_data); // bytes encrypted_data
|
||||
writer.Write(_dcSession.AuthKeyID); // int64 auth_key_id
|
||||
writer.Write(msgKeyLarge, msgKeyOffset, 16); // int128 msg_key
|
||||
writer.Write(encrypted_data); // bytes encrypted_data
|
||||
}
|
||||
if (_paddedMode) // Padded intermediate mode => append random padding
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ namespace TL
|
|||
/// <summary>Converts a <a href="https://core.telegram.org/bots/api/#markdownv2-style">Markdown text</a> into the (plain text + entities) format used by Telegram messages</summary>
|
||||
/// <param name="client">Client, used for getting access_hash for <c>tg://user?id=</c> URLs</param>
|
||||
/// <param name="text">[in] The Markdown text<br/>[out] The same (plain) text, stripped of all Markdown notation</param>
|
||||
/// <param name="premium">Generate premium entities if any</param>
|
||||
/// <returns>The array of formatting entities that you can pass (along with the plain text) to <see cref="WTelegram.Client.SendMessageAsync">SendMessageAsync</see> or <see cref="WTelegram.Client.SendMediaAsync">SendMediaAsync</see></returns>
|
||||
public static MessageEntity[] MarkdownToEntities(this WTelegram.Client client, ref string text)
|
||||
public static MessageEntity[] MarkdownToEntities(this WTelegram.Client client, ref string text, bool premium = false)
|
||||
{
|
||||
var entities = new List<MessageEntity>();
|
||||
var sb = new StringBuilder(text);
|
||||
|
|
@ -109,8 +110,11 @@ namespace TL
|
|||
else if (c == ')') break;
|
||||
}
|
||||
textUrl.url = sb.ToString(offset + 2, offset2 - offset - 3);
|
||||
if (textUrl.url.StartsWith("tg://user?id=") && long.TryParse(textUrl.url[13..], out var user_id) && client.GetAccessHashFor<User>(user_id) is long hash)
|
||||
entities[lastIndex] = new InputMessageEntityMentionName { offset = textUrl.offset, length = textUrl.length, user_id = new InputUser(user_id, hash) };
|
||||
if (textUrl.url.StartsWith("tg://user?id=") && long.TryParse(textUrl.url[13..], out var id) && client.GetAccessHashFor<User>(id) is long hash)
|
||||
entities[lastIndex] = new InputMessageEntityMentionName { offset = textUrl.offset, length = textUrl.length, user_id = new InputUser(id, hash) };
|
||||
else if (textUrl.url.StartsWith("emoji?id=") && long.TryParse(textUrl.url[9..], out id))
|
||||
if (premium) entities[lastIndex] = new MessageEntityCustomEmoji { offset = textUrl.offset, length = textUrl.length, document_id = id };
|
||||
else entities.RemoveAt(lastIndex);
|
||||
sb.Remove(offset, offset2 - offset);
|
||||
break;
|
||||
}
|
||||
|
|
@ -137,8 +141,9 @@ namespace TL
|
|||
/// <param name="client">Client, used only for getting current user ID in case of <c>InputMessageEntityMentionName+InputUserSelf</c></param>
|
||||
/// <param name="message">The plain text, typically obtained from <see cref="TL.Message.message"/></param>
|
||||
/// <param name="entities">The array of formatting entities, typically obtained from <see cref="TL.Message.entities"/></param>
|
||||
/// <param name="premium">Convert premium entities (might lead to non-standard markdown)</param>
|
||||
/// <returns>The message text with MarkdownV2 formattings</returns>
|
||||
public static string EntitiesToMarkdown(this WTelegram.Client client, string message, MessageEntity[] entities)
|
||||
public static string EntitiesToMarkdown(this WTelegram.Client client, string message, MessageEntity[] entities, bool premium = false)
|
||||
{
|
||||
if (entities == null || entities.Length == 0) return Escape(message);
|
||||
var closings = new List<(int offset, string md)>();
|
||||
|
|
@ -155,7 +160,7 @@ namespace TL
|
|||
closings.RemoveAt(0);
|
||||
}
|
||||
if (i == sb.Length) break;
|
||||
while (offset == nextEntity?.offset)
|
||||
for (; offset == nextEntity?.offset; nextEntity = ++entityIndex < entities.Length ? entities[entityIndex] : null)
|
||||
{
|
||||
if (entityToMD.TryGetValue(nextEntity.GetType(), out var md))
|
||||
{
|
||||
|
|
@ -168,6 +173,9 @@ namespace TL
|
|||
closing.md = $"](tg://user?id={memn.user_id})";
|
||||
else if (nextEntity is InputMessageEntityMentionName imemn)
|
||||
closing.md = $"](tg://user?id={imemn.user_id.UserId ?? client.UserId})";
|
||||
else if (nextEntity is MessageEntityCustomEmoji mecu)
|
||||
if (premium) closing.md = $"](emoji?id={mecu.document_id})";
|
||||
else continue;
|
||||
}
|
||||
else if (nextEntity is MessageEntityPre mep)
|
||||
md = $"```{mep.language}\n";
|
||||
|
|
@ -176,7 +184,6 @@ namespace TL
|
|||
if (i > 0 && md[0] == '_' && sb[i - 1] == '_') md = '\r' + md;
|
||||
sb.Insert(i, md); i += md.Length;
|
||||
}
|
||||
nextEntity = ++entityIndex < entities.Length ? entities[entityIndex] : null;
|
||||
}
|
||||
switch (sb[i])
|
||||
{
|
||||
|
|
@ -201,6 +208,7 @@ namespace TL
|
|||
[typeof(MessageEntityUnderline)] = "__",
|
||||
[typeof(MessageEntityStrike)] = "~",
|
||||
[typeof(MessageEntitySpoiler)] = "||",
|
||||
[typeof(MessageEntityCustomEmoji)] = "[",
|
||||
};
|
||||
|
||||
/// <summary>Insert backslashes in front of Markdown reserved characters</summary>
|
||||
|
|
@ -229,8 +237,9 @@ namespace TL
|
|||
/// <summary>Converts an <a href="https://core.telegram.org/bots/api/#html-style">HTML-formatted text</a> into the (plain text + entities) format used by Telegram messages</summary>
|
||||
/// <param name="client">Client, used for getting access_hash for <c>tg://user?id=</c> URLs</param>
|
||||
/// <param name="text">[in] The HTML-formatted text<br/>[out] The same (plain) text, stripped of all HTML tags</param>
|
||||
/// <param name="premium">Generate premium entities if any</param>
|
||||
/// <returns>The array of formatting entities that you can pass (along with the plain text) to <see cref="WTelegram.Client.SendMessageAsync">SendMessageAsync</see> or <see cref="WTelegram.Client.SendMediaAsync">SendMediaAsync</see></returns>
|
||||
public static MessageEntity[] HtmlToEntities(this WTelegram.Client client, ref string text)
|
||||
public static MessageEntity[] HtmlToEntities(this WTelegram.Client client, ref string text, bool premium = false)
|
||||
{
|
||||
var entities = new List<MessageEntity>();
|
||||
var sb = new StringBuilder(text);
|
||||
|
|
@ -271,6 +280,7 @@ namespace TL
|
|||
case "tg-spoiler": ProcessEntity<MessageEntitySpoiler>(); break;
|
||||
case "code": ProcessEntity<MessageEntityCode>(); break;
|
||||
case "pre": ProcessEntity<MessageEntityPre>(); break;
|
||||
case "tg-emoji" when closing: ProcessEntity<MessageEntityCustomEmoji>(); break;
|
||||
default:
|
||||
if (closing)
|
||||
{
|
||||
|
|
@ -294,6 +304,8 @@ namespace TL
|
|||
if (entities.LastOrDefault(e => e.length == -1) is MessageEntityPre prevEntity)
|
||||
prevEntity.language = tag[21..^1];
|
||||
}
|
||||
else if (premium && tag.StartsWith("tg-emoji id=\""))
|
||||
entities.Add(new MessageEntityCustomEmoji { offset = offset, length = -1, document_id = long.Parse(tag[13..^1]) });
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -316,8 +328,9 @@ namespace TL
|
|||
/// <param name="client">Client, used only for getting current user ID in case of <c>InputMessageEntityMentionName+InputUserSelf</c></param>
|
||||
/// <param name="message">The plain text, typically obtained from <see cref="TL.Message.message"/></param>
|
||||
/// <param name="entities">The array of formatting entities, typically obtained from <see cref="TL.Message.entities"/></param>
|
||||
/// <param name="premium">Convert premium entities</param>
|
||||
/// <returns>The message text with HTML formatting tags</returns>
|
||||
public static string EntitiesToHtml(this WTelegram.Client client, string message, MessageEntity[] entities)
|
||||
public static string EntitiesToHtml(this WTelegram.Client client, string message, MessageEntity[] entities, bool premium = false)
|
||||
{
|
||||
if (entities == null || entities.Length == 0) return Escape(message);
|
||||
var closings = new List<(int offset, string tag)>();
|
||||
|
|
@ -333,7 +346,7 @@ namespace TL
|
|||
closings.RemoveAt(0);
|
||||
}
|
||||
if (i == sb.Length) break;
|
||||
while (offset == nextEntity?.offset)
|
||||
for (; offset == nextEntity?.offset; nextEntity = ++entityIndex < entities.Length ? entities[entityIndex] : null)
|
||||
{
|
||||
if (entityToTag.TryGetValue(nextEntity.GetType(), out var tag))
|
||||
{
|
||||
|
|
@ -347,6 +360,9 @@ namespace TL
|
|||
else if (nextEntity is InputMessageEntityMentionName imemn)
|
||||
tag = $"<a href=\"tg://user?id={imemn.user_id.UserId ?? client.UserId}\">";
|
||||
}
|
||||
else if (nextEntity is MessageEntityCustomEmoji mecu)
|
||||
if (premium) tag = $"<tg-emoji id=\"{mecu.document_id}\">";
|
||||
else continue;
|
||||
else if (nextEntity is MessageEntityPre mep && !string.IsNullOrEmpty(mep.language))
|
||||
{
|
||||
closing.Item2 = "</code></pre>";
|
||||
|
|
@ -358,7 +374,6 @@ namespace TL
|
|||
closings.Insert(index, closing);
|
||||
sb.Insert(i, tag); i += tag.Length;
|
||||
}
|
||||
nextEntity = ++entityIndex < entities.Length ? entities[entityIndex] : null;
|
||||
}
|
||||
switch (sb[i])
|
||||
{
|
||||
|
|
@ -382,6 +397,7 @@ namespace TL
|
|||
[typeof(MessageEntityUnderline)] = "u",
|
||||
[typeof(MessageEntityStrike)] = "s",
|
||||
[typeof(MessageEntitySpoiler)] = "tg-spoiler",
|
||||
[typeof(MessageEntityCustomEmoji)] = "tg-emoji",
|
||||
};
|
||||
|
||||
/// <summary>Replace special HTML characters with their &xx; equivalent</summary>
|
||||
|
|
|
|||
Loading…
Reference in a new issue