1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 19:17:38 +08:00

feat search group

This commit is contained in:
wdvxdr 2021-01-26 16:44:06 +08:00
parent 2d334747a2
commit 7aa30f1de7
No known key found for this signature in database
GPG Key ID: 55FF1414A69CEBA6
4 changed files with 1211 additions and 4 deletions

View File

@ -5,11 +5,15 @@ import (
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/client/pb/profilecard"
"github.com/Mrs4s/MiraiGo/protocol/packets" "github.com/Mrs4s/MiraiGo/protocol/packets"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"io/ioutil"
"math/rand"
"net/url" "net/url"
"os"
"strings" "strings"
"sync" "sync"
) )
@ -45,6 +49,12 @@ type (
SpecialTitleExpireTime int64 SpecialTitleExpireTime int64
Permission MemberPermission Permission MemberPermission
} }
// GroupSearchInfo 通过搜索得到的群信息
GroupSearchInfo struct {
Code int64 // 群号
Name string // 群名
}
) )
func init() { func init() {
@ -109,14 +119,51 @@ func (c *QQClient) buildGroupInfoRequestPacket(groupCode int64) (uint16, []byte)
return seq, packet return seq, packet
} }
// SearchGroupByKeyword 通过关键词搜索陌生群组
func (c *QQClient) SearchGroupByKeyword(keyword string) ([]GroupSearchInfo, error) {
rsp, err := c.sendAndWait(c.buildGroupSearchPacket(keyword))
if err != nil {
return nil, errors.Wrap(err, "group search failed")
}
return rsp.([]GroupSearchInfo), nil
}
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) { func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
seq := c.nextSeq() seq := c.nextSeq()
comm, _ := proto.Marshal(&profilecard.BusiComm{
Ver: proto.Int32(1),
Seq: proto.Int32(rand.Int31()),
Service: proto.Int32(80000001),
Platform: proto.Int32(2),
Qqver: proto.String("8.5.0.5025"),
Build: proto.Int32(5025),
})
search, _ := proto.Marshal(&profilecard.AccountSearch{
Start: proto.Int32(0),
End: proto.Uint32(4),
Keyword: &keyword,
Highlight: []string{keyword},
UserLocation: &profilecard.Location{
Latitude: proto.Float64(0),
Longitude: proto.Float64(0),
},
Filtertype: proto.Int32(0),
})
req := &jce.SummaryCardReqSearch{ req := &jce.SummaryCardReqSearch{
Keyword: keyword, Keyword: keyword,
CountryCode: "+86", CountryCode: "+86",
Version: 3, Version: 3,
ReqServices: [][]byte{}, ReqServices: [][]byte{
binary.NewWriterF(func(w *binary.Writer) {
w.WriteByte(0x28)
w.WriteUInt32(uint32(len(comm)))
w.WriteUInt32(uint32(len(search)))
w.Write(comm)
w.Write(search)
w.WriteByte(0x29)
}),
},
} }
head := jce.NewJceWriter() head := jce.NewJceWriter()
head.WriteInt32(2, 0) head.WriteInt32(2, 0)
@ -137,11 +184,12 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) {
} }
// SummaryCard.ReqSearch // SummaryCard.ReqSearch
func decodeGroupSearchResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { func decodeGroupSearchResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) {
request := &jce.RequestPacket{} request := &jce.RequestPacket{}
request.ReadFrom(jce.NewJceReader(payload)) request.ReadFrom(jce.NewJceReader(payload))
data := &jce.RequestDataVersion2{} data := &jce.RequestDataVersion2{}
data.ReadFrom(jce.NewJceReader(request.SBuffer)) data.ReadFrom(jce.NewJceReader(request.SBuffer))
_ = ioutil.WriteFile("payload", payload, os.ModePerm)
if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 { if len(data.Map["RespHead"]["SummaryCard.RespHead"]) > 20 {
return nil, errors.New("not found") return nil, errors.New("not found")
} }
@ -154,7 +202,23 @@ func decodeGroupSearchResponse(c *QQClient, _ uint16, payload []byte) (interface
ld2 := sr.ReadInt32() ld2 := sr.ReadInt32()
if ld1 > 0 && ld2+9 < int32(len(rspService)) { if ld1 > 0 && ld2+9 < int32(len(rspService)) {
sr.ReadBytes(int(ld1)) // busi comm sr.ReadBytes(int(ld1)) // busi comm
//searchPb := sr.ReadBytes(int(ld2)) //TODO: search pb decode searchPb := sr.ReadBytes(int(ld2))
searchRsp := profilecard.AccountSearch{}
err := proto.Unmarshal(searchPb, &searchRsp)
if err != nil {
return nil, errors.Wrap(err, "get search result failed")
}
var ret []GroupSearchInfo
for _, g := range searchRsp.GetList() {
ret = append(ret, GroupSearchInfo{
Code: int64(g.GetCode()),
Name: g.GetName(),
})
}
for _, fp := range ret {
fmt.Println(fp.Name, ":", fp.Code)
}
return ret, nil
} }
return nil, nil return nil, nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
syntax = "proto2";
option go_package = ".;profilecard";
/*
message Color {
optional uint32 r = 1;
optional uint32 g = 2;
optional uint32 b = 3;
}
message Label {
optional bytes name = 1;
optional Color textColor = 3;
optional Color edgingColor = 4;
optional uint32 labelAttr = 5;
optional uint32 labelType = 6;
}
*/
message Location {
optional double latitude = 1;
optional double longitude = 2;
}
message ResultItem {
optional bytes feedId = 1;
optional bytes name = 2;
optional bytes picUrl = 3;
optional bytes jmpUrl = 4;
optional bytes feedType = 5;
optional bytes summary = 6;
optional bytes hasVideo = 7;
optional bytes phtotUpdate = 8;
optional uint64 uin = 9;
optional bytes resultId = 10;
optional uint32 ftime = 11;
optional bytes nickName = 12;
repeated bytes picUrlList = 13;
optional uint32 totalPicNum = 14;
}
message hotwordrecord {
optional string hotword = 1;
optional uint32 hotwordType = 2;
optional string hotwordCoverUrl = 3;
optional string hotwordTitle = 4;
optional string hotwordDescription = 5;
}
message AccountSearchRecord {
optional uint64 uin = 1;
optional uint64 code = 2;
optional uint32 source = 3;
optional string name = 4;
optional uint32 sex = 5;
optional uint32 age = 6;
optional string accout = 7;
optional string brief = 8;
optional uint32 number = 9;
optional uint64 flag = 10;
optional uint64 relation = 11;
optional string mobile = 12;
optional bytes sign = 13;
optional uint32 country = 14;
optional uint32 province = 15;
optional uint32 city = 16;
optional uint32 classIndex = 17;
optional string className = 18;
optional string countryName = 19;
optional string provinceName = 20;
optional string cityName = 21;
optional uint32 accountFlag = 22;
optional string titleImage = 23;
optional string articleShortUrl = 24;
optional string articleCreateTime = 25;
optional string articleAuthor = 26;
optional uint64 accountId = 27;
//repeated Label groupLabels = 30;
optional uint32 videoAccount = 31;
optional uint32 videoArticle = 32;
optional int32 uinPrivilege = 33;
optional bytes joinGroupAuth = 34;
optional bytes token = 500;
optional uint32 richflag1_59 = 40603;
optional uint32 richflag4_409 = 42409;
}
message AccountSearch {
optional int32 start = 1;
optional uint32 count = 2;
optional uint32 end = 3;
optional string keyword = 4;
repeated AccountSearchRecord list = 5;
repeated string highlight = 6;
optional Location userLocation = 10;
optional bool locationGroup = 11;
optional int32 filtertype = 12;
//repeated C33304record recommendList = 13;
optional hotwordrecord hotwordRecord = 14;
optional string articleMoreUrl = 15;
repeated ResultItem resultItems = 16;
optional bool keywordSuicide = 17;
optional bool exactSearch = 18;
}

View File

@ -38,7 +38,7 @@ func (c *QQClient) GetAllowedClients() ([]*OtherClientInfo, error) {
return ret, nil return ret, nil
} }
// RefreshClientStatus 刷新客户端状态 // RefreshStatus 刷新客户端状态
func (c *QQClient) RefreshStatus() error { func (c *QQClient) RefreshStatus() error {
_, err := c.sendAndWait(c.buildGetOfflineMsgRequest()) _, err := c.sendAndWait(c.buildGetOfflineMsgRequest())
return err return err