Skip to content

Commit b0ea793

Browse files
committed
[Core] Implemented Legacy Ptt Parsing
1 parent 0d598e0 commit b0ea793

3 files changed

Lines changed: 68 additions & 14 deletions

File tree

Lagrange.Core/Internal/Packets/Message/NTMessageCommon.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ internal partial class Ptt
205205

206206
[ProtoMember(4)] public byte[]? FileMd5 { get; set; }
207207

208-
[ProtoMember(5)] public byte[]? FileName { get; set; }
208+
[ProtoMember(5)] public string FileName { get; set; }
209209

210210
[ProtoMember(6)] public uint FileSize { get; set; }
211211

@@ -223,7 +223,7 @@ internal partial class Ptt
223223

224224
[ProtoMember(13)] public byte[]? Shortcut { get; set; }
225225

226-
[ProtoMember(14)] public byte[]? FileKey { get; set; }
226+
[ProtoMember(14)] public string? FileKey { get; set; }
227227

228228
[ProtoMember(15)] public uint MagicPttIndex { get; set; }
229229

Lagrange.Core/Message/Entities/RecordEntity.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@ public override async Task Preprocess(BotContext context, BotMessage message)
3939

4040
public override async Task Postprocess(BotContext context, BotMessage message)
4141
{
42-
NTV2RichMediaDownloadEventResp result = message.IsGroup()
43-
? await context.EventContext.SendEvent<RecordGroupDownloadEventResp>(new RecordGroupDownloadEventReq(message, this))
44-
: await context.EventContext.SendEvent<RecordDownloadEventResp>(new RecordDownloadEventReq(message, this));
45-
46-
FileUrl = result.Url;
42+
if (string.IsNullOrEmpty(FileUrl))
43+
{
44+
NTV2RichMediaDownloadEventResp result = message.IsGroup()
45+
? await context.EventContext.SendEvent<RecordGroupDownloadEventResp>(new RecordGroupDownloadEventReq(message, this))
46+
: await context.EventContext.SendEvent<RecordDownloadEventResp>(new RecordDownloadEventReq(message, this));
47+
48+
FileUrl = result.Url;
49+
}
4750
}
4851

4952
public override string ToPreviewString() => $"[语音] {RecordLength}\"";

Lagrange.Core/Message/MessagePacker.cs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System.Diagnostics.CodeAnalysis;
2+
using System.Formats.Asn1;
3+
using System.Text;
24
using Lagrange.Core.Common.Entity;
3-
using Lagrange.Core.Exceptions;
45
using Lagrange.Core.Internal.Events.System;
56
using Lagrange.Core.Internal.Packets.Message;
67
using Lagrange.Core.Message.Entities;
78
using Lagrange.Core.Utility;
9+
using Lagrange.Core.Utility.Binary;
810
using Lagrange.Core.Utility.Extension;
911

1012

@@ -41,7 +43,7 @@ public async Task<BotMessage> Parse(CommonMessage msg)
4143

4244
var contact = await ResolveContact(contentHead.Type, routingHead);
4345
var receiver = await ResolveReceiver(contentHead.Type, routingHead);
44-
var message = new BotMessage(contact, receiver)
46+
var message = new BotMessage(contact, receiver, DateTime.Now)
4547
{
4648
MessageId = contentHead.MsgUid, // MsgUid & 0xFFFFFFFF are the same to random
4749
Time = DateTimeOffset.FromUnixTimeSeconds(contentHead.Time).DateTime,
@@ -50,14 +52,21 @@ public async Task<BotMessage> Parse(CommonMessage msg)
5052
Random = contentHead.Random
5153
};
5254

53-
foreach (var elem in elems)
55+
if (ParsePttRichText(msg.MessageBody.RichText) is { } record)
5456
{
55-
foreach (var factory in _factory)
57+
message.Entities.Add(record);
58+
}
59+
else
60+
{
61+
foreach (var elem in elems)
5662
{
57-
if (factory.Parse(elems, elem) is not { } entity) continue;
63+
foreach (var factory in _factory)
64+
{
65+
if (factory.Parse(elems, elem) is not { } entity) continue;
5866

59-
message.Entities.Add(entity);
60-
break;
67+
message.Entities.Add(entity);
68+
break;
69+
}
6170
}
6271
}
6372

@@ -266,4 +275,46 @@ public Task<CommonMessage> BuildFake(BotMessage msg)
266275

267276
return Task.FromResult(proto);
268277
}
278+
279+
private RecordEntity? ParsePttRichText(RichText richText)
280+
{
281+
if (richText.Ptt is not { } ptt) return null;
282+
283+
var kv = new BinaryPacket(stackalloc byte[100]);
284+
kv.Write("filetype", Prefix.Int32 | Prefix.LengthOnly);
285+
kv.Write("0", Prefix.Int32 | Prefix.LengthOnly);
286+
kv.Write("codec", Prefix.Int32 | Prefix.LengthOnly);
287+
kv.Write("1", Prefix.Int32 | Prefix.LengthOnly);
288+
289+
Span<byte> innerSpan = stackalloc byte[200];
290+
Span<byte> outerSpan = stackalloc byte[300];
291+
292+
var inner = new AsnWriter(AsnEncodingRules.DER);
293+
inner.PushSequence();
294+
inner.WriteInteger(1);
295+
inner.WriteInteger(0);
296+
inner.WriteInteger((int)(_context.BotUin < 0x8000_0000 ? _context.BotUin : _context.BotUin - 0x1_0000_0000));
297+
inner.WriteOctetString(ptt.GroupFileKey ?? ptt.FileUuid ?? ReadOnlySpan<byte>.Empty);
298+
inner.WriteInteger(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
299+
inner.WriteOctetString(kv.CreateReadOnlySpan());
300+
inner.PopSequence();
301+
inner.TryEncode(innerSpan, out int length);
302+
303+
var outer = new AsnWriter(AsnEncodingRules.DER);
304+
outer.PushSequence();
305+
outer.WriteInteger(1); // version
306+
outer.WriteOctetString(innerSpan[..length]); // inner
307+
outer.WriteOctetString(ReadOnlySpan<byte>.Empty); // “empty”
308+
outer.PopSequence();
309+
310+
outer.TryEncode(outerSpan, out length);
311+
312+
return new RecordEntity
313+
{
314+
FileUrl = $"https://grouptalk.c2c.qq.com/?ver=2&rkey={Convert.ToHexString(outerSpan[..length])}&voice_codec=1&filetype=0",
315+
FileName = ptt.FileName,
316+
FileSize = ptt.FileSize,
317+
FileMd5 = Convert.ToHexString(ptt.FileMd5 ?? [])
318+
};
319+
}
269320
}

0 commit comments

Comments
 (0)