mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
client: new API UploadImage
, UploadVoice
and deprecate old API
This commit is contained in:
parent
1e32793eef
commit
6b5e7d35f0
@ -1,38 +1,21 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"image"
|
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/highway"
|
|
||||||
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
"github.com/Mrs4s/MiraiGo/client/internal/network"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/channel"
|
"github.com/Mrs4s/MiraiGo/client/pb/channel"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"
|
"github.com/Mrs4s/MiraiGo/client/pb/cmd0x388"
|
||||||
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
"github.com/Mrs4s/MiraiGo/client/pb/msg"
|
||||||
"github.com/Mrs4s/MiraiGo/internal/proto"
|
"github.com/Mrs4s/MiraiGo/internal/proto"
|
||||||
"github.com/Mrs4s/MiraiGo/message"
|
"github.com/Mrs4s/MiraiGo/message"
|
||||||
"github.com/Mrs4s/MiraiGo/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type guildImageUploadResponse struct {
|
|
||||||
UploadKey []byte
|
|
||||||
UploadIp []uint32
|
|
||||||
UploadPort []uint32
|
|
||||||
Width int32
|
|
||||||
Height int32
|
|
||||||
Message string
|
|
||||||
DownloadIndex string
|
|
||||||
FileId int64
|
|
||||||
ResultCode int32
|
|
||||||
IsExists bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
|
decoders["ImgStore.QQMeetPicUp"] = decodeGuildImageStoreResponse
|
||||||
}
|
}
|
||||||
@ -101,7 +84,7 @@ func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size u
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "send packet error")
|
return nil, errors.Wrap(err, "send packet error")
|
||||||
}
|
}
|
||||||
body := rsp.(*guildImageUploadResponse)
|
body := rsp.(*imageUploadResponse)
|
||||||
if body.IsExists {
|
if body.IsExists {
|
||||||
return &message.GuildImageElement{
|
return &message.GuildImageElement{
|
||||||
FileId: body.FileId,
|
FileId: body.FileId,
|
||||||
@ -116,60 +99,18 @@ func (s *GuildService) QueryImage(guildId, channelId uint64, hash []byte, size u
|
|||||||
return nil, errors.New("image is not exists")
|
return nil, errors.New("image is not exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use QQClient.UploadImage instead
|
||||||
func (s *GuildService) UploadGuildImage(guildId, channelId uint64, img io.ReadSeeker) (*message.GuildImageElement, error) {
|
func (s *GuildService) UploadGuildImage(guildId, channelId uint64, img io.ReadSeeker) (*message.GuildImageElement, error) {
|
||||||
_, _ = img.Seek(0, io.SeekStart) // safe
|
source := message.Source{
|
||||||
fh, length := utils.ComputeMd5AndLength(img)
|
SourceType: message.SourceGuildChannel,
|
||||||
_, _ = img.Seek(0, io.SeekStart)
|
PrimaryID: int64(guildId),
|
||||||
rsp, err := s.c.sendAndWait(s.c.buildGuildImageStorePacket(guildId, channelId, fh, uint64(length)))
|
SecondaryID: int64(channelId),
|
||||||
|
}
|
||||||
|
image, err := s.c.uploadGroupOrGuildImage(source, img)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
body := rsp.(*guildImageUploadResponse)
|
return image.(*message.GuildImageElement), nil
|
||||||
if body.IsExists {
|
|
||||||
goto ok
|
|
||||||
}
|
|
||||||
if s.c.highwaySession.AddrLength() == 0 {
|
|
||||||
for i, addr := range body.UploadIp {
|
|
||||||
s.c.highwaySession.AppendAddr(addr, body.UploadPort[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err = s.c.highwaySession.UploadBDH(highway.BdhInput{
|
|
||||||
CommandID: 83,
|
|
||||||
Body: img,
|
|
||||||
Ticket: body.UploadKey,
|
|
||||||
Ext: proto.DynamicMessage{11: guildId, 12: channelId}.Encode(),
|
|
||||||
Encrypt: false,
|
|
||||||
}); err == nil {
|
|
||||||
goto ok
|
|
||||||
}
|
|
||||||
return nil, errors.Wrap(err, "highway upload error")
|
|
||||||
ok:
|
|
||||||
_, _ = img.Seek(0, io.SeekStart)
|
|
||||||
i, _, err := image.DecodeConfig(img)
|
|
||||||
var imageType int32 = 1000
|
|
||||||
_, _ = img.Seek(0, io.SeekStart)
|
|
||||||
tmp := make([]byte, 4)
|
|
||||||
_, _ = img.Read(tmp)
|
|
||||||
if bytes.Equal(tmp, []byte{0x47, 0x49, 0x46, 0x38}) {
|
|
||||||
imageType = 2000
|
|
||||||
}
|
|
||||||
width := int32(i.Width)
|
|
||||||
height := int32(i.Height)
|
|
||||||
if err != nil {
|
|
||||||
s.c.Warning("waring: decode image error: %v. this image will be displayed by wrong size in pc guild client", err)
|
|
||||||
width = 200
|
|
||||||
height = 200
|
|
||||||
}
|
|
||||||
return &message.GuildImageElement{
|
|
||||||
FileId: body.FileId,
|
|
||||||
FilePath: hex.EncodeToString(fh) + ".jpg",
|
|
||||||
Size: int32(length),
|
|
||||||
DownloadIndex: body.DownloadIndex,
|
|
||||||
Width: width,
|
|
||||||
Height: height,
|
|
||||||
ImageType: imageType,
|
|
||||||
Md5: fh,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GuildService) PullGuildChannelMessage(guildId, channelId, beginSeq, endSeq uint64) (r []*message.GuildChannelMessage, e error) {
|
func (s *GuildService) PullGuildChannelMessage(guildId, channelId, beginSeq, endSeq uint64) (r []*message.GuildChannelMessage, e error) {
|
||||||
@ -299,18 +240,24 @@ func decodeGuildImageStoreResponse(_ *QQClient, _ *network.IncomingPacketInfo, p
|
|||||||
}
|
}
|
||||||
rsp := body.TryupImgRsp[0]
|
rsp := body.TryupImgRsp[0]
|
||||||
if rsp.GetResult() != 0 {
|
if rsp.GetResult() != 0 {
|
||||||
return &guildImageUploadResponse{
|
return &imageUploadResponse{
|
||||||
ResultCode: int32(rsp.GetResult()),
|
ResultCode: int32(rsp.GetResult()),
|
||||||
Message: utils.B2S(rsp.FailMsg),
|
Message: string(rsp.FailMsg),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if rsp.GetFileExit() {
|
if rsp.GetFileExit() {
|
||||||
|
resp := &imageUploadResponse{
|
||||||
|
IsExists: true,
|
||||||
|
FileId: int64(rsp.GetFileid()),
|
||||||
|
DownloadIndex: string(rsp.DownloadIndex),
|
||||||
|
}
|
||||||
if rsp.ImgInfo != nil {
|
if rsp.ImgInfo != nil {
|
||||||
return &guildImageUploadResponse{IsExists: true, FileId: int64(rsp.GetFileid()), DownloadIndex: string(rsp.DownloadIndex), Width: int32(rsp.ImgInfo.GetFileWidth()), Height: int32(rsp.ImgInfo.GetFileHeight())}, nil
|
resp.Width = int32(rsp.ImgInfo.GetFileWidth())
|
||||||
|
resp.Height = int32(rsp.ImgInfo.GetFileHeight())
|
||||||
}
|
}
|
||||||
return &guildImageUploadResponse{IsExists: true, FileId: int64(rsp.GetFileid()), DownloadIndex: string(rsp.DownloadIndex)}, nil
|
return rsp, nil
|
||||||
}
|
}
|
||||||
return &guildImageUploadResponse{
|
return &imageUploadResponse{
|
||||||
FileId: int64(rsp.GetFileid()),
|
FileId: int64(rsp.GetFileid()),
|
||||||
UploadKey: rsp.UpUkey,
|
UploadKey: rsp.UpUkey,
|
||||||
UploadIp: rsp.UpIp,
|
UploadIp: rsp.UpIp,
|
||||||
|
@ -34,16 +34,41 @@ type imageUploadResponse struct {
|
|||||||
UploadKey []byte
|
UploadKey []byte
|
||||||
UploadIp []uint32
|
UploadIp []uint32
|
||||||
UploadPort []uint32
|
UploadPort []uint32
|
||||||
ResourceId string
|
|
||||||
Message string
|
|
||||||
FileId int64
|
|
||||||
Width int32
|
Width int32
|
||||||
Height int32
|
Height int32
|
||||||
|
Message string
|
||||||
|
DownloadIndex string
|
||||||
|
ResourceId string
|
||||||
|
FileId int64
|
||||||
ResultCode int32
|
ResultCode int32
|
||||||
IsExists bool
|
IsExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) UploadImage(target message.Source, img io.ReadSeeker, thread ...int) (message.IMessageElement, error) {
|
||||||
|
switch target.SourceType {
|
||||||
|
case message.SourceGroup, message.SourceGuildChannel, message.SourceGuildDirect:
|
||||||
|
return c.uploadGroupOrGuildImage(target, img, thread...)
|
||||||
|
case message.SourcePrivate:
|
||||||
|
return c.uploadPrivateImage(target.PrimaryID, img, 0)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unsupported target type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: use UploadImage instead
|
||||||
func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker, thread ...int) (*message.GroupImageElement, error) {
|
func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker, thread ...int) (*message.GroupImageElement, error) {
|
||||||
|
source := message.Source{
|
||||||
|
SourceType: message.SourceGroup,
|
||||||
|
PrimaryID: groupCode,
|
||||||
|
}
|
||||||
|
x, err := c.UploadImage(source, img, thread...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return x.(*message.GroupImageElement), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *QQClient) uploadGroupOrGuildImage(target message.Source, img io.ReadSeeker, thread ...int) (message.IMessageElement, error) {
|
||||||
_, _ = img.Seek(0, io.SeekStart) // safe
|
_, _ = img.Seek(0, io.SeekStart) // safe
|
||||||
fh, length := utils.ComputeMd5AndLength(img)
|
fh, length := utils.ComputeMd5AndLength(img)
|
||||||
_, _ = img.Seek(0, io.SeekStart)
|
_, _ = img.Seek(0, io.SeekStart)
|
||||||
@ -56,9 +81,24 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker, thread .
|
|||||||
if len(thread) > 0 {
|
if len(thread) > 0 {
|
||||||
tc = thread[0]
|
tc = thread[0]
|
||||||
}
|
}
|
||||||
|
cmd := int32(2)
|
||||||
|
ext := EmptyBytes
|
||||||
|
if target.SourceType != message.SourceGroup { // guild
|
||||||
|
cmd = 83
|
||||||
|
ext = proto.DynamicMessage{
|
||||||
|
11: uint64(target.PrimaryID),
|
||||||
|
12: uint64(target.SecondaryID),
|
||||||
|
}.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
seq, pkt := c.buildGroupImageStorePacket(groupCode, fh, int32(length))
|
var r interface{}
|
||||||
r, err := c.sendAndWait(seq, pkt)
|
var err error
|
||||||
|
switch target.SourceType {
|
||||||
|
case message.SourceGroup:
|
||||||
|
r, err = c.sendAndWait(c.buildGroupImageStorePacket(target.PrimaryID, fh, int32(length)))
|
||||||
|
case message.SourceGuildChannel, message.SourceGuildDirect:
|
||||||
|
r, err = c.sendAndWait(c.buildGuildImageStorePacket(uint64(target.PrimaryID), uint64(target.SecondaryID), fh, uint64(length)))
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -77,21 +117,19 @@ func (c *QQClient) UploadGroupImage(groupCode int64, img io.ReadSeeker, thread .
|
|||||||
|
|
||||||
if tc > 1 && length > 3*1024*1024 {
|
if tc > 1 && length > 3*1024*1024 {
|
||||||
_, err = c.highwaySession.UploadBDHMultiThread(highway.BdhMultiThreadInput{
|
_, err = c.highwaySession.UploadBDHMultiThread(highway.BdhMultiThreadInput{
|
||||||
CommandID: 2,
|
CommandID: cmd,
|
||||||
Body: utils.ReaderAtFrom2ReadSeeker(img, nil),
|
Body: utils.ReaderAtFrom2ReadSeeker(img, nil),
|
||||||
Size: length,
|
Size: length,
|
||||||
Sum: fh,
|
Sum: fh,
|
||||||
Ticket: rsp.UploadKey,
|
Ticket: rsp.UploadKey,
|
||||||
Ext: EmptyBytes,
|
Ext: ext,
|
||||||
Encrypt: false,
|
|
||||||
}, 4)
|
}, 4)
|
||||||
} else {
|
} else {
|
||||||
_, err = c.highwaySession.UploadBDH(highway.BdhInput{
|
_, err = c.highwaySession.UploadBDH(highway.BdhInput{
|
||||||
CommandID: 2,
|
CommandID: cmd,
|
||||||
Body: img,
|
Body: img,
|
||||||
Ticket: rsp.UploadKey,
|
Ticket: rsp.UploadKey,
|
||||||
Ext: EmptyBytes,
|
Ext: ext,
|
||||||
Encrypt: false,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -104,9 +142,33 @@ ok:
|
|||||||
if t == "gif" {
|
if t == "gif" {
|
||||||
imageType = 2000
|
imageType = 2000
|
||||||
}
|
}
|
||||||
return message.NewGroupImage(binary.CalculateImageResourceId(fh), fh, rsp.FileId, int32(length), int32(i.Width), int32(i.Height), imageType), nil
|
width := int32(i.Width)
|
||||||
|
height := int32(i.Height)
|
||||||
|
if err != nil && target.SourceType != message.SourceGroup {
|
||||||
|
c.Warning("waring: decode image error: %v. this image will be displayed by wrong size in pc guild client", err)
|
||||||
|
width = 200
|
||||||
|
height = 200
|
||||||
|
}
|
||||||
|
if target.SourceType == message.SourceGroup {
|
||||||
|
return message.NewGroupImage(
|
||||||
|
binary.CalculateImageResourceId(fh),
|
||||||
|
fh, rsp.FileId, int32(length),
|
||||||
|
int32(i.Width), int32(i.Height), imageType,
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
return &message.GuildImageElement{
|
||||||
|
FileId: rsp.FileId,
|
||||||
|
FilePath: hex.EncodeToString(fh) + ".jpg",
|
||||||
|
Size: int32(length),
|
||||||
|
DownloadIndex: rsp.DownloadIndex,
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
ImageType: imageType,
|
||||||
|
Md5: fh,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use UploadImage instead
|
||||||
func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) {
|
func (c *QQClient) UploadPrivateImage(target int64, img io.ReadSeeker) (*message.FriendImageElement, error) {
|
||||||
return c.uploadPrivateImage(target, img, 0)
|
return c.uploadPrivateImage(target, img, 0)
|
||||||
}
|
}
|
||||||
@ -126,8 +188,12 @@ func (c *QQClient) uploadPrivateImage(target int64, img io.ReadSeeker, count int
|
|||||||
_, _ = img.Seek(0, io.SeekStart)
|
_, _ = img.Seek(0, io.SeekStart)
|
||||||
e, err := c.QueryFriendImage(target, fh, int32(length))
|
e, err := c.QueryFriendImage(target, fh, int32(length))
|
||||||
if errors.Is(err, ErrNotExists) {
|
if errors.Is(err, ErrNotExists) {
|
||||||
|
groupSource := message.Source{
|
||||||
|
SourceType: message.SourceGroup,
|
||||||
|
PrimaryID: target,
|
||||||
|
}
|
||||||
// use group highway upload and query again for image id.
|
// use group highway upload and query again for image id.
|
||||||
if _, err = c.UploadGroupImage(target, img); err != nil {
|
if _, err = c.uploadGroupOrGuildImage(groupSource, img); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if count >= 5 {
|
if count >= 5 {
|
||||||
|
107
client/ptt.go
107
client/ptt.go
@ -1,7 +1,6 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@ -26,24 +25,35 @@ func init() {
|
|||||||
|
|
||||||
var pttWaiter = utils.NewUploadWaiter()
|
var pttWaiter = utils.NewUploadWaiter()
|
||||||
|
|
||||||
var c2cPttExtraInfo = binary.NewWriterF(func(w *binary.Writer) {
|
func c2cPttExtraInfo() []byte {
|
||||||
|
w := binary.SelectWriter()
|
||||||
|
defer binary.PutWriter(w)
|
||||||
w.WriteByte(2) // tlv count
|
w.WriteByte(2) // tlv count
|
||||||
|
{
|
||||||
w.WriteByte(8)
|
w.WriteByte(8)
|
||||||
w.WriteUInt16(4)
|
w.WriteUInt16(4)
|
||||||
w.WriteUInt32(1) // codec
|
w.WriteUInt32(1) // codec
|
||||||
|
}
|
||||||
|
{
|
||||||
w.WriteByte(9)
|
w.WriteByte(9)
|
||||||
w.WriteUInt16(4)
|
w.WriteUInt16(4)
|
||||||
w.WriteUInt32(0) // 时长
|
w.WriteUInt32(0) // 时长
|
||||||
|
}
|
||||||
w.WriteByte(10)
|
w.WriteByte(10)
|
||||||
reserveInfo := []byte{0x08, 0x00, 0x28, 0x00, 0x38, 0x00} // todo
|
reserveInfo := []byte{0x08, 0x00, 0x28, 0x00, 0x38, 0x00} // todo
|
||||||
w.WriteBytesShort(reserveInfo)
|
w.WriteBytesShort(reserveInfo)
|
||||||
})
|
return append([]byte(nil), w.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadVoice 将语音数据使用群语音通道上传到服务器, 返回 message.GroupVoiceElement 可直接发送
|
||||||
|
func (c *QQClient) UploadVoice(target message.Source, voice io.ReadSeeker) (*message.GroupVoiceElement, error) {
|
||||||
|
switch target.SourceType {
|
||||||
|
case message.SourceGroup, message.SourcePrivate:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unsupported source type")
|
||||||
|
}
|
||||||
|
|
||||||
// UploadGroupPtt 将语音数据使用群语音通道上传到服务器, 返回 message.GroupVoiceElement 可直接发送
|
|
||||||
func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*message.GroupVoiceElement, error) {
|
|
||||||
fh, length := utils.ComputeMd5AndLength(voice)
|
fh, length := utils.ComputeMd5AndLength(voice)
|
||||||
_, _ = voice.Seek(0, io.SeekStart)
|
_, _ = voice.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
@ -51,9 +61,18 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
|
|||||||
pttWaiter.Wait(key)
|
pttWaiter.Wait(key)
|
||||||
defer pttWaiter.Done(key)
|
defer pttWaiter.Done(key)
|
||||||
|
|
||||||
ext := c.buildGroupPttStoreBDHExt(groupCode, fh, int32(length), 0, int32(length))
|
var cmd int32
|
||||||
|
var ext []byte
|
||||||
|
if target.SourceType == message.SourcePrivate {
|
||||||
|
cmd = int32(26)
|
||||||
|
ext = c.buildC2CPttStoreBDHExt(target.PrimaryID, fh, int32(length), int32(length))
|
||||||
|
} else {
|
||||||
|
cmd = int32(29)
|
||||||
|
ext = c.buildGroupPttStoreBDHExt(target.PrimaryID, fh, int32(length), 0, int32(length))
|
||||||
|
}
|
||||||
|
// multi-thread upload is no need
|
||||||
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
||||||
CommandID: 29,
|
CommandID: cmd,
|
||||||
Body: voice,
|
Body: voice,
|
||||||
Ticket: c.highwaySession.SigSession,
|
Ticket: c.highwaySession.SigSession,
|
||||||
Ext: ext,
|
Ext: ext,
|
||||||
@ -65,6 +84,15 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
|
|||||||
if len(rsp) == 0 {
|
if len(rsp) == 0 {
|
||||||
return nil, errors.New("miss rsp")
|
return nil, errors.New("miss rsp")
|
||||||
}
|
}
|
||||||
|
ptt := &msg.Ptt{
|
||||||
|
FileType: proto.Int32(4),
|
||||||
|
SrcUin: &c.Uin,
|
||||||
|
FileMd5: fh,
|
||||||
|
FileName: proto.String(hex.EncodeToString(fh) + ".amr"),
|
||||||
|
FileSize: proto.Int32(int32(length)),
|
||||||
|
BoolValid: proto.Bool(true),
|
||||||
|
}
|
||||||
|
if target.SourceType == message.SourceGroup {
|
||||||
pkt := cmd0x388.D388RspBody{}
|
pkt := cmd0x388.D388RspBody{}
|
||||||
if err = proto.Unmarshal(rsp, &pkt); err != nil {
|
if err = proto.Unmarshal(rsp, &pkt); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
|
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
|
||||||
@ -72,45 +100,10 @@ func (c *QQClient) UploadGroupPtt(groupCode int64, voice io.ReadSeeker) (*messag
|
|||||||
if len(pkt.TryupPttRsp) == 0 {
|
if len(pkt.TryupPttRsp) == 0 {
|
||||||
return nil, errors.New("miss try up rsp")
|
return nil, errors.New("miss try up rsp")
|
||||||
}
|
}
|
||||||
return &message.GroupVoiceElement{
|
ptt.PbReserve = []byte{8, 0, 40, 0, 56, 0}
|
||||||
Ptt: &msg.Ptt{
|
ptt.GroupFileKey = pkt.TryupPttRsp[0].FileKey
|
||||||
FileType: proto.Int32(4),
|
return &message.GroupVoiceElement{Ptt: ptt}, nil
|
||||||
SrcUin: &c.Uin,
|
} else {
|
||||||
FileMd5: fh,
|
|
||||||
FileName: proto.String(hex.EncodeToString(fh) + ".amr"),
|
|
||||||
FileSize: proto.Int32(int32(length)),
|
|
||||||
GroupFileKey: pkt.TryupPttRsp[0].FileKey,
|
|
||||||
BoolValid: proto.Bool(true),
|
|
||||||
PbReserve: []byte{8, 0, 40, 0, 56, 0},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadPrivatePtt 将语音数据使用好友语音通道上传到服务器, 返回 message.PrivateVoiceElement 可直接发送
|
|
||||||
func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message.PrivateVoiceElement, error) {
|
|
||||||
h := md5.New()
|
|
||||||
length, _ := io.Copy(h, voice)
|
|
||||||
fh := h.Sum(nil)
|
|
||||||
_, _ = voice.Seek(0, io.SeekStart)
|
|
||||||
|
|
||||||
key := hex.EncodeToString(fh)
|
|
||||||
pttWaiter.Wait(key)
|
|
||||||
defer pttWaiter.Done(key)
|
|
||||||
|
|
||||||
ext := c.buildC2CPttStoreBDHExt(target, fh, int32(length), int32(length))
|
|
||||||
rsp, err := c.highwaySession.UploadBDH(highway.BdhInput{
|
|
||||||
CommandID: 26,
|
|
||||||
Body: voice,
|
|
||||||
Ticket: c.highwaySession.SigSession,
|
|
||||||
Ext: ext,
|
|
||||||
Encrypt: false,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(rsp) == 0 {
|
|
||||||
return nil, errors.New("miss rsp")
|
|
||||||
}
|
|
||||||
pkt := cmd0x346.C346RspBody{}
|
pkt := cmd0x346.C346RspBody{}
|
||||||
if err = proto.Unmarshal(rsp, &pkt); err != nil {
|
if err = proto.Unmarshal(rsp, &pkt); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
|
return nil, errors.Wrap(err, "failed to unmarshal protobuf message")
|
||||||
@ -118,18 +111,10 @@ func (c *QQClient) UploadPrivatePtt(target int64, voice io.ReadSeeker) (*message
|
|||||||
if pkt.ApplyUploadRsp == nil {
|
if pkt.ApplyUploadRsp == nil {
|
||||||
return nil, errors.New("miss apply upload rsp")
|
return nil, errors.New("miss apply upload rsp")
|
||||||
}
|
}
|
||||||
return &message.PrivateVoiceElement{
|
ptt.FileUuid = pkt.ApplyUploadRsp.Uuid
|
||||||
Ptt: &msg.Ptt{
|
ptt.Reserve = c2cPttExtraInfo()
|
||||||
FileType: proto.Int32(4),
|
return &message.PrivateVoiceElement{Ptt: ptt}, nil
|
||||||
SrcUin: &c.Uin,
|
}
|
||||||
FileUuid: pkt.ApplyUploadRsp.Uuid,
|
|
||||||
FileMd5: fh,
|
|
||||||
FileName: proto.String(hex.EncodeToString(fh) + ".amr"),
|
|
||||||
FileSize: proto.Int32(int32(length)),
|
|
||||||
Reserve: c2cPttExtraInfo,
|
|
||||||
BoolValid: proto.Bool(true),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadShortVideo 将视频和封面上传到服务器, 返回 message.ShortVideoElement 可直接发送
|
// UploadShortVideo 将视频和封面上传到服务器, 返回 message.ShortVideoElement 可直接发送
|
||||||
|
@ -28,10 +28,7 @@ type GroupVoiceElement struct {
|
|||||||
Ptt *msg.Ptt
|
Ptt *msg.Ptt
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrivateVoiceElement struct {
|
type PrivateVoiceElement = GroupVoiceElement
|
||||||
Data []byte
|
|
||||||
Ptt *msg.Ptt
|
|
||||||
}
|
|
||||||
|
|
||||||
type FaceElement struct {
|
type FaceElement struct {
|
||||||
Index int32
|
Index int32
|
||||||
@ -256,10 +253,6 @@ func (e *GroupVoiceElement) Type() ElementType {
|
|||||||
return Voice
|
return Voice
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PrivateVoiceElement) Type() ElementType {
|
|
||||||
return Voice
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *VoiceElement) Type() ElementType {
|
func (e *VoiceElement) Type() ElementType {
|
||||||
return Voice
|
return Voice
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user