diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs index 1ca34b936..fbd1066e1 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs @@ -162,6 +162,23 @@ private async Task ResolveAdditional(MessageChain chain) record.AudioUrl = result.AudioUrl; } } + + if (chain.HasTypeOf()) + { + var video = chain.GetEntity(); + if (video?.VideoUuid == null) return; + + string uid = (chain.IsGroup + ? await Collection.Business.CachingLogic.ResolveUid(chain.GroupUin, chain.FriendUin) + : chain.Uid) ?? ""; + var @event = VideoDownloadEvent.Create(video.VideoUuid, uid, video.FilePath, "", "",chain.IsGroup); + var results = await Collection.Business.SendEvent(@event); + if (results.Count != 0) + { + var result = (VideoDownloadEvent)results[0]; + video.VideoUrl = result.AudioUrl; + } + } foreach (var mention in chain.OfType()) { diff --git a/Lagrange.Core/Internal/Event/Message/VideoDownloadEvent.cs b/Lagrange.Core/Internal/Event/Message/VideoDownloadEvent.cs new file mode 100644 index 000000000..c59cc88df --- /dev/null +++ b/Lagrange.Core/Internal/Event/Message/VideoDownloadEvent.cs @@ -0,0 +1,40 @@ +namespace Lagrange.Core.Internal.Event.Message; + +#pragma warning disable CS8618 + +internal class VideoDownloadEvent : ProtocolEvent +{ + public string AudioUrl { get; } + + public string Uuid { get; } + + public string SelfUid { get; } + + public string FileName { get; } + + public string FileMd5 { get; } + + public string? FileSha1 { get; } + + public bool IsGroup { get; } + + private VideoDownloadEvent(string uuid, string selfUid, string fileName, string fileMd5, string? fileSha1, bool isGroup) : base(true) + { + Uuid = uuid; + SelfUid = selfUid; + FileName = fileName; + FileSha1 = fileSha1; + IsGroup = isGroup; + FileMd5 = fileMd5; + } + + private VideoDownloadEvent(int resultCode, string audioUrl) : base(resultCode) + { + AudioUrl = audioUrl; + } + + public static VideoDownloadEvent Create(string uuid, string selfUid, string fileName, string fileMd5, string? fileSha1 = null, bool isGroup = false) + => new(uuid, selfUid, fileName, fileMd5, fileSha1, isGroup); + + public static VideoDownloadEvent Result(int resultCode, string url) => new(resultCode, url); +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/VideoFile.cs b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/VideoFile.cs index b4adbec8e..2fe560e3b 100644 --- a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/VideoFile.cs +++ b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/VideoFile.cs @@ -6,11 +6,11 @@ namespace Lagrange.Core.Internal.Packets.Message.Element.Implementation; [ProtoContract] internal class VideoFile { - [ProtoMember(1)] public byte[] FileUuid { get; set; } + [ProtoMember(1)] public string FileUuid { get; set; } [ProtoMember(2)] public byte[] FileMd5 { get; set; } - [ProtoMember(3)] public byte[] FileName { get; set; } + [ProtoMember(3)] public string FileName { get; set; } [ProtoMember(4)] public int FileFormat { get; set; } diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x11E9_200.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x11E9_200.cs new file mode 100644 index 000000000..f2980bdc7 --- /dev/null +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x11E9_200.cs @@ -0,0 +1,18 @@ +using ProtoBuf; + +namespace Lagrange.Core.Internal.Packets.Service.Oidb.Request; + +// ReSharper disable InconsistentNaming +#pragma warning disable CS8618 + +/// +/// Video Download +/// +[ProtoContract] +[OidbSvcTrpcTcp(0x11e9, 200)] +internal class OidbSvcTrpcTcp0x11E9_200 +{ + [ProtoMember(1)] public OidbSvcTrpcTcp0x126D_200Field1 Field1 { get; set; } + + [ProtoMember(3)] public OidbSvcTrpcTcp0x126D_200Field3 Field3 { get; set; } +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x126D_200.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x126D_200.cs index a95273b7b..4e96c3ac6 100644 --- a/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x126D_200.cs +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x126D_200.cs @@ -5,6 +5,9 @@ namespace Lagrange.Core.Internal.Packets.Service.Oidb.Request; // Resharper disable InconsistentNaming #pragma warning disable CS8618 +/// +/// Record Download +/// [ProtoContract] [OidbSvcTrpcTcp(0x126D, 200)] internal class OidbSvcTrpcTcp0x126D_200 diff --git a/Lagrange.Core/Internal/Service/Message/VideoDownloadService.cs b/Lagrange.Core/Internal/Service/Message/VideoDownloadService.cs new file mode 100644 index 000000000..01a69936b --- /dev/null +++ b/Lagrange.Core/Internal/Service/Message/VideoDownloadService.cs @@ -0,0 +1,100 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Internal.Event; +using Lagrange.Core.Internal.Event.Message; +using Lagrange.Core.Internal.Packets.Service.Oidb; +using Lagrange.Core.Internal.Packets.Service.Oidb.Request; +using Lagrange.Core.Internal.Packets.Service.Oidb.Response; +using Lagrange.Core.Utility.Binary; +using Lagrange.Core.Utility.Extension; +using ProtoBuf; + +namespace Lagrange.Core.Internal.Service.Message; + +[EventSubscribe(typeof(VideoDownloadEvent))] +[Service("OidbSvcTrpcTcp.0x11e9_200")] +internal class VideoDownloadService : BaseService +{ + protected override bool Build(VideoDownloadEvent input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out BinaryPacket output, out List? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x11E9_200 + { + Field1 = new OidbSvcTrpcTcp0x126D_200Field1 + { + Field1 = new OidbSvcTrpcTcp0x126D_200Field1Field1 + { + Field1 = input.IsGroup ? 3u : 34u, + Field2 = 200 + }, + Field2 = new OidbSvcTrpcTcp0x126D_200Field1Field2 + { + Field1 = 2, + Field2 = 2, + Field3 = 1, + Field201 = new OidbSvcTrpcTcp0x126D_200Field1Field2Field201 + { + Field1 = 2, + SelfUid = input.SelfUid + } + }, + Field3 = new OidbSvcTrpcTcp0x126D_200Field1Field3 + { + Field1 = 2 + } + }, + Field3 = new OidbSvcTrpcTcp0x126D_200Field3 + { + Field1 = new OidbSvcTrpcTcp0x126D_200Field3Field1 + { + Field1 = new OidbSvcTrpcTcp0x126D_200Field3Field1Field1 + { + Field1 = 0, + FileHash = input.FileMd5, + FileSha1 = input.FileSha1 ?? "", + FileName = input.FileName, + Field5 = new OidbSvcTrpcTcp0x126D_200Field3Field1Field1Field5 + { + Field1 = 2, + Field2 = 0, + Field3 = 0, + Field4 = 0 + }, + Field6 = 0, + Field7 = 0, + Field8 = 0, + Field9 = 0 + }, + FileUuid = input.Uuid, + Field3 = 0, + Field4 = 0, + Field5 = 0, + Field6 = 0 + }, + Field2 = new OidbSvcTrpcTcp0x126D_200Field3Field2 + { + Field2 = new OidbSvcTrpcTcp0x126D_200Field3Field2Field2 + { + Field1 = 0, + Field2 = 0 + } + } + } + }, false, true); + output = packet.Serialize(); + extraPackets = null; + + return true; + } + + protected override bool Parse(byte[] input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, out VideoDownloadEvent output, + out List? extraEvents) + { + var payload = Serializer.Deserialize>(input.AsSpan()); + var body = payload.Body.Body; + string url = $"https://{body.Field3.Domain}{body.Field3.Suffix}{body.DownloadParams}"; + + output = VideoDownloadEvent.Result((int)payload.ErrorCode, url); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Message/Entity/RecordEntity.cs b/Lagrange.Core/Message/Entity/RecordEntity.cs index 680eac07f..1289ac8c7 100644 --- a/Lagrange.Core/Message/Entity/RecordEntity.cs +++ b/Lagrange.Core/Message/Entity/RecordEntity.cs @@ -27,7 +27,7 @@ public class RecordEntity : IMessageEntity internal string? FileSha1 { get; set; } - public RecordEntity() { } + internal RecordEntity() { } public RecordEntity(string filePath) { @@ -76,5 +76,5 @@ IEnumerable IMessageEntity.PackElement() return null; } - public string ToPreviewString() => $"[{nameof(RecordEntity)}]: {AudioUrl}"; + public string ToPreviewString() => $"[{nameof(RecordEntity)}: {AudioUrl}]"; } \ No newline at end of file diff --git a/Lagrange.Core/Message/Entity/VideoEntity.cs b/Lagrange.Core/Message/Entity/VideoEntity.cs index a7db13958..5f2d83be3 100644 --- a/Lagrange.Core/Message/Entity/VideoEntity.cs +++ b/Lagrange.Core/Message/Entity/VideoEntity.cs @@ -2,6 +2,7 @@ using System.Text; using Lagrange.Core.Internal.Packets.Message.Element; using Lagrange.Core.Internal.Packets.Message.Element.Implementation; +using Lagrange.Core.Utility.Extension; namespace Lagrange.Core.Message.Entity; @@ -9,36 +10,63 @@ namespace Lagrange.Core.Message.Entity; public class VideoEntity : IMessageEntity { public string FilePath { get; set; } = string.Empty; + + public string VideoHash { get; set; } = string.Empty; public Vector2 Size { get; } public int VideoSize { get; } + + public string VideoUrl { get; set; } = string.Empty; + + internal Stream? VideoStream { get; set; } + + internal string? VideoUuid { get; } - internal VideoEntity(Vector2 size, int videoSize, string filePath) + internal VideoEntity() { } + + internal VideoEntity(Vector2 size, int videoSize, string filePath, string fileMd5, string videoUuid) { Size = size; VideoSize = videoSize; FilePath = filePath; + VideoHash = fileMd5; + VideoUuid = videoUuid; + } + + public VideoEntity(string filePath) + { + FilePath = filePath; + VideoStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); } - internal VideoEntity() { } + public VideoEntity(byte[] file) + { + FilePath = string.Empty; + VideoStream = new MemoryStream(file); + } IEnumerable IMessageEntity.PackElement() { - throw new NotImplementedException(); + return new Elem[] + { + new() + { + + } + }; } IMessageEntity? IMessageEntity.UnpackElement(Elem elem) { if (elem.VideoFile is not { } videoFile) return null; - var size = new Vector2(videoFile.FileWidth, videoFile.FileHeight); - - return new VideoEntity(size, elem.VideoFile.FileSize, Encoding.UTF8.GetString(elem.VideoFile.FileName)); + var size = new Vector2(videoFile.ThumbWidth, videoFile.ThumbHeight); + return new VideoEntity(size, videoFile.FileSize, videoFile.FileName, videoFile.FileMd5.Hex(), videoFile.FileUuid); } public string ToPreviewString() { - return $"[Video {Size.X}x{Size.Y}]: {VideoSize}"; + return $"[Video {Size.X}x{Size.Y}]: {VideoSize} {VideoUrl}"; } } \ No newline at end of file diff --git a/Lagrange.Core/Message/MessagePacker.cs b/Lagrange.Core/Message/MessagePacker.cs index f47684807..fd9c643ef 100644 --- a/Lagrange.Core/Message/MessagePacker.cs +++ b/Lagrange.Core/Message/MessagePacker.cs @@ -231,7 +231,7 @@ private static MessageChain ParseChain(PushMsgBody message) : new MessageChain( message.ResponseHead.Grp.GroupUin, message.ResponseHead.FromUin, - (uint)(message.ContentHead.Sequence ?? 0), + message.ContentHead.Sequence ?? 0, message.ContentHead.NewId ?? 0); chain.Time = DateTimeOffset.FromUnixTimeSeconds(message.ContentHead.Timestamp ?? 0).DateTime;