mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
feature: private ptt.
This commit is contained in:
parent
cee229f738
commit
626e23d99c
@ -158,6 +158,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient {
|
||||
"PttCenterSvr.ShortVideoDownReq": decodePttShortVideoDownResponse,
|
||||
"LightAppSvc.mini_app_info.GetAppInfoById": decodeAppInfoResponse,
|
||||
"OfflineFilleHandleSvr.pb_ftn_CMD_REQ_APPLY_DOWNLOAD-1200": decodeOfflineFileDownloadResponse,
|
||||
"PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500": decodePrivatePttStoreResponse,
|
||||
},
|
||||
sigInfo: &loginSigInfo{},
|
||||
requestPacketRequestId: 1921334513,
|
||||
@ -691,42 +692,6 @@ func (c *QQClient) ImageOcr(img interface{}) (*OcrResponse, error) {
|
||||
return nil, errors.New("image error")
|
||||
}
|
||||
|
||||
func (c *QQClient) UploadGroupPtt(groupCode int64, voice []byte) (*message.GroupVoiceElement, error) {
|
||||
h := md5.Sum(voice)
|
||||
seq, pkt := c.buildGroupPttStorePacket(groupCode, h[:], int32(len(voice)), 0, int32(len(voice)))
|
||||
r, err := c.sendAndWait(seq, pkt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp := r.(pttUploadResponse)
|
||||
if rsp.ResultCode != 0 {
|
||||
return nil, errors.New(rsp.Message)
|
||||
}
|
||||
if rsp.IsExists {
|
||||
goto ok
|
||||
}
|
||||
for i, ip := range rsp.UploadIp {
|
||||
err := c.uploadGroupPtt(ip, rsp.UploadPort[i], rsp.UploadKey, rsp.FileKey, voice, h[:])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
goto ok
|
||||
}
|
||||
return nil, errors.New("upload failed")
|
||||
ok:
|
||||
return &message.GroupVoiceElement{
|
||||
Ptt: &msg.Ptt{
|
||||
FileType: 4,
|
||||
SrcUin: c.Uin,
|
||||
FileMd5: h[:],
|
||||
FileName: hex.EncodeToString(h[:]) + ".amr",
|
||||
FileSize: int32(len(voice)),
|
||||
GroupFileKey: rsp.FileKey,
|
||||
BoolValid: true,
|
||||
PbReserve: []byte{8, 0, 40, 0, 56, 0},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*message.GroupImageElement, error) {
|
||||
r, err := c.sendAndWait(c.buildGroupImageStorePacket(groupCode, hash, size))
|
||||
if err != nil {
|
||||
|
@ -245,7 +245,7 @@ type (
|
||||
|
||||
ResourceId string
|
||||
UploadKey []byte
|
||||
UploadIp []int32
|
||||
UploadIp []string
|
||||
UploadPort []int32
|
||||
FileKey []byte
|
||||
}
|
||||
|
@ -57,10 +57,10 @@ func (c *QQClient) highwayUpload(ip uint32, port int, updKey, data []byte, cmdId
|
||||
}
|
||||
|
||||
// 只是为了写的跟上面一样长(bushi,当然也应该是最快的玩法
|
||||
func (c *QQClient) uploadGroupPtt(ip, port int32, updKey, fileKey, data, md5 []byte) error {
|
||||
func (c *QQClient) uploadPtt(ip string, port int32, updKey, fileKey, data, md5 []byte) error {
|
||||
url := make([]byte, 512)[:0]
|
||||
url = append(url, "http://"...)
|
||||
url = append(url, binary.UInt32ToIPV4Address(uint32(ip))...)
|
||||
url = append(url, ip...)
|
||||
url = append(url, ':')
|
||||
url = strconv.AppendInt(url, int64(port), 10)
|
||||
url = append(url, "/?ver=4679&ukey="...)
|
||||
|
141
client/ptt.go
141
client/ptt.go
@ -1,11 +1,87 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Mrs4s/MiraiGo/binary"
|
||||
"github.com/Mrs4s/MiraiGo/client/pb"
|
||||
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x346"
|
||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||
"github.com/Mrs4s/MiraiGo/message"
|
||||
"github.com/Mrs4s/MiraiGo/protocol/packets"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (c *QQClient) UploadGroupPtt(groupCode int64, voice []byte) (*message.GroupVoiceElement, error) {
|
||||
h := md5.Sum(voice)
|
||||
seq, pkt := c.buildGroupPttStorePacket(groupCode, h[:], int32(len(voice)), 0, int32(len(voice)))
|
||||
r, err := c.sendAndWait(seq, pkt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp := r.(pttUploadResponse)
|
||||
if rsp.ResultCode != 0 {
|
||||
return nil, errors.New(rsp.Message)
|
||||
}
|
||||
if rsp.IsExists {
|
||||
goto ok
|
||||
}
|
||||
for i, ip := range rsp.UploadIp {
|
||||
err := c.uploadPtt(ip, rsp.UploadPort[i], rsp.UploadKey, rsp.FileKey, voice, h[:])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
goto ok
|
||||
}
|
||||
return nil, errors.New("upload failed")
|
||||
ok:
|
||||
return &message.GroupVoiceElement{
|
||||
Ptt: &msg.Ptt{
|
||||
FileType: 4,
|
||||
SrcUin: c.Uin,
|
||||
FileMd5: h[:],
|
||||
FileName: hex.EncodeToString(h[:]) + ".amr",
|
||||
FileSize: int32(len(voice)),
|
||||
GroupFileKey: rsp.FileKey,
|
||||
BoolValid: true,
|
||||
PbReserve: []byte{8, 0, 40, 0, 56, 0},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (c *QQClient) UploadPrivatePtt(target int64, voice []byte) (*message.PrivateVoiceElement, error) {
|
||||
h := md5.Sum(voice)
|
||||
i, err := c.sendAndWait(c.buildPrivatePttStorePacket(target, h[:], int32(len(voice)), int32(len(voice))))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp := i.(pttUploadResponse)
|
||||
if rsp.IsExists {
|
||||
goto ok
|
||||
}
|
||||
for i, ip := range rsp.UploadIp {
|
||||
err := c.uploadPtt(ip, rsp.UploadPort[i], rsp.UploadKey, rsp.FileKey, voice, h[:])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
goto ok
|
||||
}
|
||||
return nil, errors.New("upload failed")
|
||||
ok:
|
||||
return &message.PrivateVoiceElement{
|
||||
Ptt: &msg.Ptt{
|
||||
FileType: 4,
|
||||
SrcUin: c.Uin,
|
||||
FileMd5: h[:],
|
||||
FileName: hex.EncodeToString(h[:]) + ".amr",
|
||||
FileSize: int32(len(voice)),
|
||||
FileKey: rsp.FileKey,
|
||||
BoolValid: true,
|
||||
PbReserve: []byte{8, 0, 40, 0, 56, 0},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
// PttStore.GroupPttUp
|
||||
func (c *QQClient) buildGroupPttStorePacket(groupCode int64, md5 []byte, size, codec, voiceLength int32) (uint16, []byte) {
|
||||
seq := c.nextSeq()
|
||||
@ -54,10 +130,73 @@ func decodeGroupPttStoreResponse(_ *QQClient, _ uint16, payload []byte) (interfa
|
||||
if rsp.BoolFileExit {
|
||||
return pttUploadResponse{IsExists: true}, nil
|
||||
}
|
||||
var ip []string
|
||||
for _, i := range rsp.Uint32UpIp {
|
||||
ip = append(ip, binary.UInt32ToIPV4Address(uint32(i)))
|
||||
}
|
||||
return pttUploadResponse{
|
||||
UploadKey: rsp.UpUkey,
|
||||
UploadIp: rsp.Uint32UpIp,
|
||||
UploadIp: ip,
|
||||
UploadPort: rsp.Uint32UpPort,
|
||||
FileKey: rsp.FileKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500
|
||||
func (c *QQClient) buildPrivatePttStorePacket(target int64, md5 []byte, size, voiceLength int32) (uint16, []byte) {
|
||||
seq := c.nextSeq()
|
||||
req := &cmd0x346.C346ReqBody{
|
||||
Cmd: 500,
|
||||
Seq: int32(seq),
|
||||
ApplyUploadReq: &cmd0x346.ApplyUploadReq{
|
||||
SenderUin: c.Uin,
|
||||
RecverUin: target,
|
||||
FileType: 2,
|
||||
FileSize: int64(size),
|
||||
FileName: hex.EncodeToString(md5),
|
||||
Bytes_10MMd5: md5, // 超过10M可能会炸
|
||||
},
|
||||
BusinessId: 17,
|
||||
ClientType: 104,
|
||||
ExtensionReq: &cmd0x346.ExtensionReq{
|
||||
Id: 3,
|
||||
PttFormat: 1,
|
||||
NetType: 3,
|
||||
VoiceType: 2,
|
||||
PttTime: voiceLength,
|
||||
},
|
||||
}
|
||||
payload, _ := proto.Marshal(req)
|
||||
packet := packets.BuildUniPacket(c.Uin, seq, "PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)
|
||||
return seq, packet
|
||||
}
|
||||
|
||||
// PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_UPLOAD-500
|
||||
func decodePrivatePttStoreResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) {
|
||||
rsp := cmd0x346.C346RspBody{}
|
||||
if err := proto.Unmarshal(payload, &rsp); err != nil {
|
||||
c.Error("unmarshal cmd0x346 rsp body error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if rsp.ApplyUploadRsp == nil {
|
||||
c.Error("decode apply upload 500 error: apply rsp is nil.")
|
||||
return nil, errors.New("apply rsp is nil")
|
||||
}
|
||||
if rsp.ApplyUploadRsp.RetCode != 0 {
|
||||
c.Error("decode apply upload 500 error: %v", rsp.ApplyUploadRsp.RetCode)
|
||||
return nil, errors.New(fmt.Sprint(rsp.ApplyUploadRsp.RetCode))
|
||||
}
|
||||
if rsp.ApplyUploadRsp.BoolFileExist {
|
||||
return pttUploadResponse{IsExists: true}, nil
|
||||
}
|
||||
var port []int32
|
||||
for range rsp.ApplyUploadRsp.UploadipList {
|
||||
port = append(port, rsp.ApplyUploadRsp.UploadPort)
|
||||
}
|
||||
return pttUploadResponse{
|
||||
UploadKey: rsp.ApplyUploadRsp.UploadKey,
|
||||
UploadIp: rsp.ApplyUploadRsp.UploadipList,
|
||||
UploadPort: port,
|
||||
FileKey: rsp.ApplyUploadRsp.Uuid,
|
||||
}, nil
|
||||
}
|
||||
|
@ -47,6 +47,11 @@ type GroupVoiceElement struct {
|
||||
Ptt *msg.Ptt
|
||||
}
|
||||
|
||||
type PrivateVoiceElement struct {
|
||||
Data []byte
|
||||
Ptt *msg.Ptt
|
||||
}
|
||||
|
||||
type FriendImageElement struct {
|
||||
ImageId string
|
||||
Md5 []byte
|
||||
@ -116,7 +121,7 @@ type GroupShowPicElement struct {
|
||||
EffectId int32
|
||||
}
|
||||
|
||||
type FriendFlashPicElement struct{
|
||||
type FriendFlashPicElement struct {
|
||||
FriendImageElement
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user