diff --git a/caller.go b/caller.go index 7775e1d..619c8a4 100644 --- a/caller.go +++ b/caller.go @@ -250,6 +250,50 @@ func (c *Caller) WebWxSendMsg(ctx context.Context, opt *CallerWebWxSendMsgOption return parser.SentMessage(opt.Message) } +// WebWxSendEmoticon 发送表情接口 +func (c *Caller) WebWxSendEmoticon(ctx context.Context, md5 string, reader io.Reader, opt *CallerWebWxSendAppMsgOptions) (*SentMessage, error) { + md5OrMediaid := md5 + if reader != nil { + file, cb, err := readerToFile(reader) + if err != nil { + return nil, err + } + defer cb() + // 首先尝试上传图片 + var mediaId string + { + uploadMediaOption := &CallerUploadMediaOptions{ + FromUserName: opt.FromUserName, + ToUserName: opt.ToUserName, + BaseRequest: opt.BaseRequest, + LoginInfo: opt.LoginInfo, + } + resp, err := c.UploadMedia(ctx, file, uploadMediaOption) + if err != nil { + return nil, err + } + mediaId = resp.MediaId + } + + md5OrMediaid = mediaId + } + + msg := NewEmoticonSendMessage(opt.FromUserName, opt.ToUserName, md5OrMediaid) + + wxSendMsgOption := &ClientWebWxSendMsgOptions{ + BaseRequest: opt.BaseRequest, + LoginInfo: opt.LoginInfo, + Message: msg, + } + resp, err := c.Client.WebWxSendEmoticon(ctx, wxSendMsgOption) + if err != nil { + return nil, err + } + defer func() { _ = resp.Body.Close() }() + parser := MessageResponseParser{resp.Body} + return parser.SentMessage(msg) +} + type CallerWebWxOplogOptions struct { RemarkName string ToUserName string diff --git a/client.go b/client.go index 516b1d5..60bb30c 100644 --- a/client.go +++ b/client.go @@ -438,6 +438,21 @@ func (c *Client) WebWxSendMsg(ctx context.Context, opt *ClientWebWxSendMsgOption return c.sendMessage(ctx, opt.BaseRequest, path.String(), opt.Message) } +// WebWxSendMsg 发送表情消息 +func (c *Client) WebWxSendEmoticon(ctx context.Context, opt *ClientWebWxSendMsgOptions) (*http.Response, error) { + opt.Message.Type = MsgTypeText + path, err := url.Parse(c.Domain.BaseHost() + webwxsendemoticon) + if err != nil { + return nil, err + } + params := url.Values{} + params.Add("fun", "sys") + params.Add("lang", "zh_CN") + params.Add("pass_ticket", opt.LoginInfo.PassTicket) + path.RawQuery = params.Encode() + return c.sendMessage(ctx, opt.BaseRequest, path.String(), opt.Message) +} + // WebWxGetHeadImg 获取用户的头像 func (c *Client) WebWxGetHeadImg(ctx context.Context, user *User) (*http.Response, error) { var path string diff --git a/message.go b/message.go index f3feef3..83f2fab 100644 --- a/message.go +++ b/message.go @@ -177,6 +177,16 @@ func (m *Message) ReplyText(content string) (*SentMessage, error) { return m.Owner().sendTextToUser(username, content) } +// ReplyEmoticon 回复表情 +func (m *Message) ReplyEmoticon(md5 string, file io.Reader) (*SentMessage, error) { + // 判断是否由自己发送 + username := m.FromUserName + if m.IsSelfSendToGroup() { + username = m.ToUserName + } + return m.Owner().sendEmoticonToUser(username, md5, file) +} + // ReplyImage 回复图片消息 func (m *Message) ReplyImage(file io.Reader) (*SentMessage, error) { // 判断是否由自己发送 @@ -494,6 +504,8 @@ type SendMessage struct { LocalID string ClientMsgId string MediaId string `json:"MediaId,omitempty"` + EmojiFlag int `json:"EmojiFlag,omitempty"` + EMoticonMd5 string `json:"EMoticonMd5,omitempty"` } // NewSendMessage SendMessage的构造方法 @@ -520,6 +532,18 @@ func NewMediaSendMessage(msgType MessageType, fromUserName, toUserName, mediaId return NewSendMessage(msgType, "", fromUserName, toUserName, mediaId) } +// NewEmoticonSendMessage 表情消息的构造方法 +func NewEmoticonSendMessage(fromUserName, toUserName, md5OrMediaId string) *SendMessage { + msg := NewSendMessage(MsgTypeEmoticon, "", fromUserName, toUserName, "") + msg.EmojiFlag = 2 + if strings.HasPrefix(md5OrMediaId, "@") { + msg.MediaId = md5OrMediaId + } else { + msg.EMoticonMd5 = md5OrMediaId + } + return msg +} + // RecommendInfo 一些特殊类型的消息会携带该结构体信息 type RecommendInfo struct { OpCode int diff --git a/url.go b/url.go index f4ad9e7..aa3b232 100644 --- a/url.go +++ b/url.go @@ -14,6 +14,7 @@ const ( webwxstatusnotify = "/cgi-bin/mmwebwx-bin/webwxstatusnotify" webwxsync = "/cgi-bin/mmwebwx-bin/webwxsync" webwxsendmsg = "/cgi-bin/mmwebwx-bin/webwxsendmsg" + webwxsendemoticon = "/cgi-bin/mmwebwx-bin/webwxsendemoticon" webwxgetcontact = "/cgi-bin/mmwebwx-bin/webwxgetcontact" webwxsendmsgimg = "/cgi-bin/mmwebwx-bin/webwxsendmsgimg" webwxsendappmsg = "/cgi-bin/mmwebwx-bin/webwxsendappmsg" diff --git a/user.go b/user.go index 1dc668f..53fddb6 100644 --- a/user.go +++ b/user.go @@ -384,6 +384,17 @@ func (s *Self) sendTextToUser(username, text string) (*SentMessage, error) { return s.sendMessageWrapper(sentMessage, err) } +func (s *Self) sendEmoticonToUser(username, md5 string, file io.Reader) (*SentMessage, error) { + opt := &CallerWebWxSendAppMsgOptions{ + LoginInfo: s.bot.Storage.LoginInfo, + BaseRequest: s.bot.Storage.Request, + FromUserName: s.UserName, + ToUserName: username, + } + sentMessage, err := s.bot.Caller.WebWxSendEmoticon(s.Bot().Context(), md5, file, opt) + return s.sendMessageWrapper(sentMessage, err) +} + func (s *Self) sendImageToUser(username string, file io.Reader) (*SentMessage, error) { opt := &CallerWebWxSendImageMsgOptions{ FromUserName: s.UserName, @@ -422,6 +433,11 @@ func (s *Self) SendTextToFriend(friend *Friend, text string) (*SentMessage, erro return s.sendTextToUser(friend.User.UserName, text) } +// SendEmoticonToFriend 发送表情给好友 +func (s *Self) SendEmoticonToFriend(friend *Friend, md5 string, file io.Reader) (*SentMessage, error) { + return s.sendEmoticonToUser(friend.User.UserName, md5, file) +} + // SendImageToFriend 发送图片消息给好友 func (s *Self) SendImageToFriend(friend *Friend, file io.Reader) (*SentMessage, error) { return s.sendImageToUser(friend.User.UserName, file) @@ -585,6 +601,11 @@ func (s *Self) SendImageToGroup(group *Group, file io.Reader) (*SentMessage, err return s.sendImageToUser(group.User.UserName, file) } +// SendImageToGroup 发送图片消息给群组 +func (s *Self) SendEmoticonToGroup(group *Group, md5 string, file io.Reader) (*SentMessage, error) { + return s.sendEmoticonToUser(group.User.UserName, md5, file) +} + // SendVideoToGroup 发送视频给群组 func (s *Self) SendVideoToGroup(group *Group, file io.Reader) (*SentMessage, error) { return s.sendVideoToUser(group.User.UserName, file) @@ -694,6 +715,18 @@ func (s *Self) sendTextToMembers(text string, delay time.Duration, members ...*U return s.sendMessageToMember(sendMessageFunc, delay, members[1:]...) } +// sendEmoticonToMembers 发送表情消息给群组或者好友 +func (s *Self) sendEmoticonToMembers(md5 string, file io.Reader, delay time.Duration, members ...*User) error { + if len(members) == 0 { + return nil + } + var sendMessageFunc SendMessageFunc = func() (*SentMessage, error) { + user := members[0] + return s.sendEmoticonToUser(user.UserName, md5, file) + } + return s.sendMessageToMember(sendMessageFunc, delay, members[1:]...) +} + // sendImageToMembers 发送图片消息给群组或者好友 func (s *Self) sendImageToMembers(img io.Reader, delay time.Duration, members ...*User) error { if len(members) == 0 { @@ -736,6 +769,12 @@ func (s *Self) SendTextToFriends(text string, delay time.Duration, friends ...*F return s.sendTextToMembers(text, delay, members...) } +// SendEmoticonToFriends 发送表情给好友 +func (s *Self) SendEmoticonToFriends(md5 string, file io.Reader, delay time.Duration, friends ...*Friend) error { + members := Friends(friends).AsMembers() + return s.sendEmoticonToMembers(md5, file, delay, members...) +} + // SendImageToFriends 发送图片消息给好友 func (s *Self) SendImageToFriends(img io.Reader, delay time.Duration, friends ...*Friend) error { members := Friends(friends).AsMembers() @@ -760,6 +799,12 @@ func (s *Self) SendTextToGroups(text string, delay time.Duration, groups ...*Gro return s.sendTextToMembers(text, delay, members...) } +// SendEmoticonToGroups 发送表情给群组 +func (s *Self) SendEmoticonToGroups(md5 string, file io.Reader, delay time.Duration, groups ...*Group) error { + members := Groups(groups).AsMembers() + return s.sendEmoticonToMembers(md5, file, delay, members...) +} + // SendImageToGroups 发送图片消息给群组 func (s *Self) SendImageToGroups(img io.Reader, delay time.Duration, groups ...*Group) error { members := Groups(groups).AsMembers() @@ -1026,6 +1071,11 @@ func (s *Self) SendTextToMp(mp *Mp, text string) (*SentMessage, error) { return s.sendTextToUser(mp.User.UserName, text) } +// SendEmoticonToMp 发送表情给公众号 +func (s *Self) SendEmoticonToMp(mp *Mp, md5 string, file io.Reader) (*SentMessage, error) { + return s.sendEmoticonToUser(mp.User.UserName, md5, file) +} + // SendImageToMp 发送图片消息给公众号 func (s *Self) SendImageToMp(mp *Mp, file io.Reader) (*SentMessage, error) { return s.sendImageToUser(mp.User.UserName, file)