mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-07-08 15:18:32 +00:00
Compare commits
9 Commits
master
...
367f1d52e9
Author | SHA1 | Date | |
---|---|---|---|
367f1d52e9 | |||
18c895cf21 | |||
f51b043e9e | |||
26a9f6d604 | |||
47b45f8b7b | |||
1faca7cf73 | |||
9ee41fc5f9 | |||
cd753c1953 | |||
f4a63a83cd |
@ -195,16 +195,16 @@ func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage
|
||||
Sender: sender,
|
||||
Self: c.Uin,
|
||||
Elements: func() []message.IMessageElement {
|
||||
if msg.Body.RichText.Ptt != nil {
|
||||
return []message.IMessageElement{
|
||||
&message.VoiceElement{
|
||||
Name: msg.Body.RichText.Ptt.FileName.Unwrap(),
|
||||
Md5: msg.Body.RichText.Ptt.FileMd5,
|
||||
Size: msg.Body.RichText.Ptt.FileSize.Unwrap(),
|
||||
Url: string(msg.Body.RichText.Ptt.DownPara),
|
||||
},
|
||||
}
|
||||
}
|
||||
// if msg.Body.RichText.Ptt != nil {
|
||||
// return []message.IMessageElement{
|
||||
// &message.VoiceElement{
|
||||
// Name: msg.Body.RichText.Ptt.FileName.Unwrap(),
|
||||
// Md5: msg.Body.RichText.Ptt.FileMd5,
|
||||
// Size: msg.Body.RichText.Ptt.FileSize.Unwrap(),
|
||||
// Url: string(msg.Body.RichText.Ptt.DownPara),
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
return message.ParseMessageElems(msg.Body.RichText.Elems)
|
||||
}(),
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,30 +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"`
|
||||
PicMd5 []byte `protobuf:"bytes,2,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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
94
client/pb/richmedia/ntv2.pb.go
Normal file
94
client/pb/richmedia/ntv2.pb.go
Normal 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()
|
||||
}
|
78
client/pb/richmedia/ntv2.proto
Normal file
78
client/pb/richmedia/ntv2.proto
Normal 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
74
client/richmedia.go
Normal 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)
|
||||
}
|
@ -18,6 +18,8 @@ type VoiceElement struct {
|
||||
Md5 []byte
|
||||
Size int32
|
||||
Url string
|
||||
FileId string
|
||||
IsGroup bool
|
||||
|
||||
// --- sending ---
|
||||
Data []byte
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -671,36 +671,53 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
|
||||
Name: strings.TrimPrefix(string(animatedStickerMsg.Text), "/"),
|
||||
}
|
||||
return []IMessageElement{sticker} // sticker 永远为单独消息
|
||||
case 48:
|
||||
}
|
||||
bt := elem.CommonElem.BusinessType.Unwrap()
|
||||
switch bt {
|
||||
case 10, 20:
|
||||
img := &msg.PbMultiMediaElement{}
|
||||
_ = proto.Unmarshal(elem.CommonElem.PbElem, img)
|
||||
domain := img.Elem1.Data.Domain.Unwrap()
|
||||
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.PicMd5,
|
||||
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.PicMd5,
|
||||
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)
|
||||
ve := &VoiceElement{
|
||||
Name: audio.Elem1.Meta.Data.FileName.Unwrap(),
|
||||
Md5: audio.Elem1.Meta.Data.FileMd5,
|
||||
Size: audio.Elem1.Meta.Data.FileLen.Unwrap(),
|
||||
FileId: audio.Elem1.Meta.FilePath.Unwrap(),
|
||||
IsGroup: false,
|
||||
}
|
||||
if bt == 22 {
|
||||
ve.IsGroup = true
|
||||
}
|
||||
res = append(res, ve)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
Reference in New Issue
Block a user