1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-07-08 07:08:32 +00:00

Compare commits

..

6 Commits

Author SHA1 Message Date
367f1d52e9 edit note 2024-09-05 15:10:04 +08:00
18c895cf21 support parse 0x126d_200 rsp 2024-09-05 14:58:52 +08:00
f51b043e9e support RecordDownloadReqPacket 2024-09-05 12:19:08 +08:00
26a9f6d604 support NTV2RichMediaReq 2024-09-05 11:19:37 +08:00
47b45f8b7b add image file name 2024-09-05 10:13:02 +08:00
1faca7cf73 fix: wrong imgurl 2024-09-05 10:07:27 +08:00
9 changed files with 325 additions and 46 deletions

View File

@ -59,6 +59,7 @@ OidbSvcTrpcTcp.0x101e_2
OidbSvcTrpcTcp.0x1100_1
OidbSvcTrpcTcp.0x1105_1
OidbSvcTrpcTcp.0x1107_1
OidbSvcTrpcTcp.0x126d_200
OidbSvcTrpcTcp.0x55f_0
OidbSvcTrpcTcp.0x6d9_4
OidbSvcTrpcTcp.0xf55_1

View File

@ -881,6 +881,12 @@ type MsgElemInfoServtype37 struct {
Randomtype proto.Option[uint32] `protobuf:"varint,9,opt"`
}
type PbMultiMediaElement struct {
Elem1 *PbMultiMediaElement_Elem1 `protobuf:"bytes,1,opt"`
Elem2 *PbMultiMediaElement_Elem2 `protobuf:"bytes,2,opt"`
_ [0]func()
}
type ElemFlags2_Inst struct {
AppId proto.Option[uint32] `protobuf:"varint,1,opt"`
InstId proto.Option[uint32] `protobuf:"varint,2,opt"`
@ -893,32 +899,47 @@ type NotOnlineImage_PbReserve struct {
_ [0]func()
}
type PbMultiMediaElement struct {
Elem1 *struct {
Meta *struct {
Data *struct {
FileLen proto.Option[int32] `protobuf:"varint,1,opt"`
FileMd5 []byte `protobuf:"bytes,2,opt"`
FileSha1 proto.Option[string] `protobuf:"bytes,3,opt"`
FileName proto.Option[string] `protobuf:"bytes,4,opt"`
} `protobuf:"bytes,1,opt"`
FilePath proto.Option[string] `protobuf:"bytes,2,opt"`
} `protobuf:"bytes,1,opt"`
type PbMultiMediaElement_Elem1 struct {
Meta *PbMultiMediaElement_Elem1_Meta `protobuf:"bytes,1,opt"`
Data *PbMultiMediaElement_Elem1_Data `protobuf:"bytes,2,opt"`
_ [0]func()
}
Data *struct {
type PbMultiMediaElement_Elem2 struct {
Data *PbMultiMediaElement_Elem2_Data `protobuf:"bytes,1,opt"`
_ [0]func()
}
type PbMultiMediaElement_Elem1_Meta struct {
Data *PbMultiMediaElement_Elem1_Meta_Data `protobuf:"bytes,1,opt"`
FilePath proto.Option[string] `protobuf:"bytes,2,opt"`
_ [0]func()
}
type PbMultiMediaElement_Elem1_Data struct {
ImgURL proto.Option[string] `protobuf:"bytes,1,opt"`
Domain proto.Option[string] `protobuf:"bytes,3,opt"`
} `protobuf:"bytes,2,opt"`
} `protobuf:"bytes,1,opt"`
Elem2 *struct {
Data *struct {
Friend *struct {
RKey proto.Option[string] `protobuf:"bytes,30,opt"`
} `protobuf:"bytes,11,opt"`
Group *struct {
RKey proto.Option[string] `protobuf:"bytes,30,opt"`
} `protobuf:"bytes,12,opt"`
} `protobuf:"bytes,1,opt"`
} `protobuf:"bytes,2,opt"`
_ [0]func()
}
type PbMultiMediaElement_Elem1_Meta_Data struct {
FileLen proto.Option[int32] `protobuf:"varint,1,opt"`
FileMd5 []byte `protobuf:"bytes,2,opt"`
FileName proto.Option[string] `protobuf:"bytes,4,opt"`
}
type PbMultiMediaElement_Elem2_Data struct {
Friend *PbMultiMediaElement_Elem2_Data_Friend `protobuf:"bytes,11,opt"`
Group *PbMultiMediaElement_Elem2_Data_Group `protobuf:"bytes,12,opt"`
_ [0]func()
}
type PbMultiMediaElement_Elem2_Data_Friend struct {
RKey proto.Option[string] `protobuf:"bytes,30,opt"`
_ [0]func()
}
type PbMultiMediaElement_Elem2_Data_Group struct {
RKey proto.Option[string] `protobuf:"bytes,30,opt"`
_ [0]func()
}

View File

@ -883,7 +883,8 @@ message PbMultiMediaElement {
message Meta {
message Data {
optional int32 FileLen = 1;
optional bytes PicMd5 = 2;
optional bytes FileMd5 = 2;
optional string FileName = 4;
}
optional Data data = 1;
optional string FilePath = 2;
@ -891,7 +892,7 @@ message PbMultiMediaElement {
optional Meta meta = 1;
message Data {
optional string ImgURL = 2;
optional string ImgURL = 1;
optional string Domain = 3;
}
optional Data data = 2;

View File

@ -0,0 +1,94 @@
// Code generated by protoc-gen-golite. DO NOT EDIT.
// source: pb/richmedia/ntv2.proto
package richmedia
type NTV2RichMediaReq struct {
ReqHead *MultiMediaReqHead `protobuf:"bytes,1,opt"`
Download *DownloadReq `protobuf:"bytes,3,opt"`
_ [0]func()
}
type MultiMediaReqHead struct {
Common *CommonHead `protobuf:"bytes,1,opt"`
Scene *SceneInfo `protobuf:"bytes,2,opt"`
Client *ClientMeta `protobuf:"bytes,3,opt"`
_ [0]func()
}
type CommonHead struct {
RequestId uint32 `protobuf:"varint,1,opt"`
Command uint32 `protobuf:"varint,2,opt"`
_ [0]func()
}
type SceneInfo struct {
RequestType uint32 `protobuf:"varint,101,opt"`
BusinessType uint32 `protobuf:"varint,102,opt"`
SceneType uint32 `protobuf:"varint,200,opt"`
C2C *C2CUserInfo `protobuf:"bytes,201,opt"`
Group *NTGroupInfo `protobuf:"bytes,202,opt"`
_ [0]func()
}
type ClientMeta struct {
AgentType uint32 `protobuf:"varint,1,opt"`
_ [0]func()
}
type C2CUserInfo struct {
AccountType uint32 `protobuf:"varint,1,opt"`
TargetUid string `protobuf:"bytes,2,opt"`
_ [0]func()
}
type NTGroupInfo struct {
GroupUin uint32 `protobuf:"varint,1,opt"`
_ [0]func()
}
type DownloadReq struct {
Node *IndexNode `protobuf:"bytes,1,opt"`
_ [0]func()
}
type IndexNode struct {
Info *FileInfo `protobuf:"bytes,1,opt"`
FileUuid string `protobuf:"bytes,2,opt"`
StoreId uint32 `protobuf:"varint,3,opt"`
_ [0]func()
}
type FileInfo struct {
Type *FileType `protobuf:"bytes,5,opt"`
Time uint32 `protobuf:"varint,8,opt"`
_ [0]func()
}
type FileType struct {
Type uint32 `protobuf:"varint,1,opt"`
VoiceFormat uint32 `protobuf:"varint,4,opt"`
_ [0]func()
}
type NTV2RichMediaRsp struct {
MediaResp *MediaResp `protobuf:"bytes,4,opt"`
_ [0]func()
}
type MediaResp struct {
DownloadResp *DownloadResp `protobuf:"bytes,3,opt"`
_ [0]func()
}
type DownloadResp struct {
Rkey string `protobuf:"bytes,1,opt"`
Info *DownloadInfo `protobuf:"bytes,3,opt"`
_ [0]func()
}
type DownloadInfo struct {
Domain string `protobuf:"bytes,1,opt"`
UrlPath string `protobuf:"bytes,2,opt"`
_ [0]func()
}

View File

@ -0,0 +1,78 @@
syntax = "proto3";
option go_package = "github.com/Mrs4s/MiraiGo/client/pb/richmedia";
message NTV2RichMediaReq {
MultiMediaReqHead ReqHead = 1;
DownloadReq Download = 3;
}
message MultiMediaReqHead {
CommonHead Common = 1;
SceneInfo Scene = 2;
ClientMeta Client = 3;
}
message CommonHead {
uint32 RequestId = 1;
uint32 Command = 2;
}
message SceneInfo {
uint32 RequestType = 101;
uint32 BusinessType = 102;
uint32 SceneType = 200;
optional C2CUserInfo C2C = 201;
optional NTGroupInfo Group = 202;
}
message ClientMeta {
uint32 AgentType = 1;
}
message C2CUserInfo {
uint32 AccountType = 1;
string TargetUid = 2;
}
message NTGroupInfo {
uint32 GroupUin = 1;
}
message DownloadReq {
IndexNode Node = 1;
}
message IndexNode {
FileInfo Info = 1;
string FileUuid = 2;
uint32 StoreId = 3;
}
message FileInfo {
FileType Type = 5;
uint32 Time = 8;
}
message FileType {
uint32 Type = 1;
uint32 VoiceFormat = 4;
}
message NTV2RichMediaRsp {
MediaResp MediaResp = 4;
}
message MediaResp {
DownloadResp DownloadResp = 3;
}
message DownloadResp {
string Rkey = 1;
DownloadInfo Info = 3;
}
message DownloadInfo {
string Domain = 1;
string UrlPath = 2;
}

74
client/richmedia.go Normal file
View File

@ -0,0 +1,74 @@
package client
import (
"fmt"
"github.com/Mrs4s/MiraiGo/client/pb/richmedia"
"github.com/Mrs4s/MiraiGo/internal/proto"
)
// OidbSvcTrpcTcp.0x126d_200
func (c *QQClient) buildRecordDownloadReqPacket(Uid string, FileId string, groupUin int64, isGroup bool) (uint16, []byte) {
scene := &richmedia.SceneInfo{
RequestType: 2,
BusinessType: 3,
SceneType: 1,
C2C: &richmedia.C2CUserInfo{
AccountType: 2,
TargetUid: Uid,
},
}
if isGroup {
scene.RequestType = 1
scene.SceneType = 2
scene.Group = &richmedia.NTGroupInfo{
GroupUin: uint32(groupUin),
}
}
body := &richmedia.NTV2RichMediaReq{
ReqHead: &richmedia.MultiMediaReqHead{
Common: &richmedia.CommonHead{
RequestId: 3,
Command: 200,
},
Scene: scene,
Client: &richmedia.ClientMeta{
AgentType: 2,
},
},
Download: &richmedia.DownloadReq{
Node: &richmedia.IndexNode{
Info: &richmedia.FileInfo{
Type: &richmedia.FileType{
Type: 3,
VoiceFormat: 1,
},
Time: 1,
},
FileUuid: FileId,
StoreId: 1,
},
},
}
b, err := proto.Marshal(body)
if err != nil {
fmt.Println(err)
}
payload := c.packOIDBPackage(4717, 200, b)
return c.uniPacket("OidbSvcTrpcTcp.0x126d_200", payload)
}
func (c *QQClient) ParseRecordDownloadRspPacket(body []byte) string {
rp := &richmedia.NTV2RichMediaRsp{}
if err := proto.Unmarshal(body, rp); err != nil && rp.MediaResp.DownloadResp.Info != nil {
c.error("parse RecordDownloadRspPacket error: %v", err)
return ""
}
return fmt.Sprintf("https://%s%s%s", rp.MediaResp.DownloadResp.Info.Domain, rp.MediaResp.DownloadResp.Info.UrlPath, rp.MediaResp.DownloadResp.Rkey)
}
// GetRecordDownloadUrl 获取语音文件下载地址
func (c *QQClient) GetRecordDownloadUrl(selfUid string, FileId string, groupUin int64, isGroup bool) string {
body, _ := c.sendAndWaitDynamic(c.buildRecordDownloadReqPacket(selfUid, FileId, groupUin, isGroup))
return c.ParseRecordDownloadRspPacket(body)
}

View File

@ -18,6 +18,8 @@ type VoiceElement struct {
Md5 []byte
Size int32
Url string
FileId string
IsGroup bool
// --- sending ---
Data []byte

View File

@ -19,7 +19,7 @@ type GroupImageElement struct {
Height int32
Md5 []byte
Url string
Name string
// EffectID show pic effect id.
EffectID int32
Flash bool
@ -32,7 +32,7 @@ type FriendImageElement struct {
Width int32
Height int32
Url string
Name string
Flash bool
}

View File

@ -672,7 +672,8 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
}
return []IMessageElement{sticker} // sticker 永远为单独消息
}
switch elem.CommonElem.BusinessType.Unwrap() {
bt := elem.CommonElem.BusinessType.Unwrap()
switch bt {
case 10, 20:
img := &msg.PbMultiMediaElement{}
_ = proto.Unmarshal(elem.CommonElem.PbElem, img)
@ -680,35 +681,42 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
imgURL := img.Elem1.Data.ImgURL.Unwrap()
if img.Elem2.Data.Friend != nil {
rKey := img.Elem2.Data.Friend.RKey.Unwrap()
url := fmt.Sprintf("https://%s%s%s&spec=0&rf=naio", domain, imgURL, rKey)
url := fmt.Sprintf("https://%s%s%s", domain, imgURL, rKey)
res = append(res, &FriendImageElement{
ImageId: img.Elem1.Meta.FilePath.Unwrap(),
Size: img.Elem1.Meta.Data.FileLen.Unwrap(),
Url: url,
Md5: img.Elem1.Meta.Data.FileMd5,
Name: img.Elem1.Meta.Data.FileName.Unwrap(),
})
newImg = true
}
if img.Elem2.Data.Group != nil {
rKey := img.Elem2.Data.Group.RKey.Unwrap()
url := fmt.Sprintf("https://%s%s%s&spec=0&rf=naio", domain, imgURL, rKey)
url := fmt.Sprintf("https://%s%s%s", domain, imgURL, rKey)
res = append(res, &GroupImageElement{
ImageId: img.Elem1.Meta.FilePath.Unwrap(),
Size: img.Elem1.Meta.Data.FileLen.Unwrap(),
Url: url,
Md5: img.Elem1.Meta.Data.FileMd5,
Name: img.Elem1.Meta.Data.FileName.Unwrap(),
})
newImg = true
}
case 12, 22:
audio := &msg.PbMultiMediaElement{}
_ = proto.Unmarshal(elem.CommonElem.PbElem, audio)
res = append(res, &VoiceElement{
ve := &VoiceElement{
Name: audio.Elem1.Meta.Data.FileName.Unwrap(),
Md5: audio.Elem1.Meta.Data.FileMd5,
Size: audio.Elem1.Meta.Data.FileLen.Unwrap(),
Url: audio.Elem1.Meta.FilePath.Unwrap(), // url is wrong TODO:get url with rkey
})
FileId: audio.Elem1.Meta.FilePath.Unwrap(),
IsGroup: false,
}
if bt == 22 {
ve.IsGroup = true
}
res = append(res, ve)
}
}
}