起因
之前和女朋友聊天一直用的是QQ
,然后有了火花、巨轮标识。自从上班以后,就很少进QQ
了,导致火花和巨轮隔三岔五的就掉了,女朋友表示很生气,要求我维持好这些火花、巨轮标识,为了积极响应女朋友的要求,便有了这篇文章。
准备工作
github看了一圈qq机器人
和微信机器人
的项目都有一堆,那就站在前人的肩膀上实现吧。感觉这种轻量型的项目比较适合go语言,那就go!
QQ机器人选型:go-cqhttp
微信机器人选型:openwechat
要干的事
这么一个流程实现了的话,女朋友QQ发的消息,我的微信小号会通知我,我回复女朋友消息时直接回复我的小号。如此一来,我用微信就可以处理QQ的消息,火花和巨轮标识就算是保住了。理论可以那就到了coding环节了。
show me code
qq.go
使用go-cqhttp
运行websocket
正向代理,然后qq.go
中建立websocket
连接监听qq
消息,当接收到特定好友的消息时转发到微信(目前支持了文字消息和图片消息以及部分表情)
package main
import (
"encoding/json"
"fmt"
"github.com/eatmoreapple/openwechat"
"github.com/gorilla/websocket"
"log"
"net/http"
"strings"
)
var QQ *websocket.Conn
type QQMsg struct {
Action string `json:"action"`
Params map[string]interface{} `json:"params"`
Echo string `json:"echo"`
}
func loginQQ() {
header := http.Header{}
//header.Set("Authorization", "Bearer ")
ws, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080", header)
if err != nil {
panic(err)
}
QQ = ws
defer QQ.Close()
channel := make(chan []byte)
go func() {
for {
// 读取消息
_, receive, err := QQ.ReadMessage()
if err != nil {
log.Fatal(err)
}
channel <- receive
}
}()
for {
select {
case msg := <-channel:
go dealMsg(msg)
}
}
}
type ReceiveMsg struct {
PostType string `json:"post_type"`
MessageType string `json:"message_type"`
Time int `json:"time"`
SelfId int `json:"self_id"`
SubType string `json:"sub_type"`
Sender struct {
Age int `json:"age"`
Nickname string `json:"nickname"`
Sex string `json:"sex"`
UserId int64 `json:"user_id"`
} `json:"sender"`
MessageId int `json:"message_id"`
UserId int64 `json:"user_id"`
TargetId int `json:"target_id"`
Message string `json:"message"`
RawMessage string `json:"raw_message"`
Font int `json:"font"`
}
func dealMsg(msg []byte) {
receiveMsg := ReceiveMsg{}
s := string(msg)
if strings.Contains(s, "connect") {
return
}
fmt.Println(s)
err := json.Unmarshal(msg, &receiveMsg)
if err != nil {
fmt.Println("解析消息失败: ", err.Error())
fmt.Println(err)
return
}
// 如果收到特定qq号的消息,转发到微信
if receiveMsg.UserId != 1784945498 {
return
}
if W2Q {
WeChatSendMsg(receiveMsg)
}
}
func QQSendMsg(msg *openwechat.Message) {
sendMsg := QQMsg{Action: "send_private_msg", Params: map[string]interface{}{
"user_id": "1784945498",
"message": msg.Content,
}}
err := QQ.WriteJSON(sendMsg)
if err != nil {
fmt.Println("发送消息失败: " + err.Error())
}
}
wechat.go
登录微信个人账号,然后监听微信消息,当接收到特定好友的消息时,转发到qq
(暂时只支持了处理文本消息)
package main
import (
"bytes"
"fmt"
"github.com/eatmoreapple/openwechat"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"os"
"regexp"
"strings"
)
var WeChat = &openwechat.Bot{}
var friend = &openwechat.Friend{}
var W2Q = true
func loginWechat() {
WeChat = openwechat.DefaultBot(openwechat.Desktop) // 桌面模式
// 注册消息处理函数
WeChat.MessageHandler = func(msg *openwechat.Message) {
if msg.IsText() && msg.Content == "ping" {
msg.ReplyText("pong")
}
}
// 注册登陆二维码回调
WeChat.UUIDCallback = openwechat.PrintlnQrcodeUrl
reloadStorage := openwechat.NewFileHotReloadStorage("storage.json")
defer reloadStorage.Close()
// 登陆
if err := WeChat.HotLogin(reloadStorage, openwechat.NewRetryLoginOption()); err != nil {
fmt.Println(err)
return
}
// 获取登陆的用户
self, err := WeChat.GetCurrentUser()
if err != nil {
fmt.Println(err)
return
}
// 获取所有的好友
friends, err := self.Friends()
res := friends.Search(1, func(friend *openwechat.Friend) bool {
return friend.ID() == "710964253"
})
if res.Count() > 0 {
friend = res.First()
}
WeChat.MessageHandler = func(msg *openwechat.Message) {
fmt.Println(msg.MsgType)
sender, err := msg.Sender()
if err != nil {
panic(err)
}
// 收到大号的消息,转发到QQ
if sender.ID() == "710964253" {
content := msg.Content
if content == "/start" {
W2Q = true
} else if content == "/stop" {
W2Q = false
} else if content == "/status" {
msg.ReplyText(fmt.Sprint(W2Q))
} else if W2Q {
QQSendMsg(msg)
}
}
}
// 阻塞主goroutine, 直到发生异常或者用户主动退出
WeChat.Block()
}
func downloadUrl(url string) *bytes.Reader {
resp, err := http.Get(url)
if err != nil {
log.Error("下载图片失败", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
return bytes.NewReader(data)
}
func WeChatSendMsg(msg ReceiveMsg) {
str := "\\[CQ:.+?\\]"
reg := regexp.MustCompile(str)
allMatch := reg.FindAllString(msg.Message, -1)
for _, match := range allMatch {
result := make(map[string]string)
if strings.Contains(match, "CQ:face") {
reg = regexp.MustCompile("id=(?P<id>\\d+)")
result["CQ"] = "face"
}
if strings.Contains(match, "CQ:image") {
reg = regexp.MustCompile("url=(?P<url>.+)\\]")
result["CQ"] = "image"
}
match := reg.FindStringSubmatch(match)
groupNames := reg.SubexpNames()
for i, name := range groupNames {
if i != 0 && name != "" {
result[name] = match[i]
}
}
if result["CQ"] == "image" {
url := result["url"]
reader := downloadUrl(url)
_, err := friend.SendImage(reader)
if err != nil {
fmt.Println(err)
log.Error(err)
}
log.Info(url)
} else if result["CQ"] == "face" {
id := result["id"]
img, _ := os.Open("qq-face/" + id + ".png")
defer img.Close()
friend.SendImage(img)
}
}
reg = regexp.MustCompile(str)
text := reg.ReplaceAllString(msg.Message, "")
if len(text) != 0 {
friend.SendText(text)
}
}
main.go
func main() {
go loginQQ()
loginWechat()
}
代码到这里就完成了,但是实际上仅靠上面这部分代码并不能正常跑起来,还需要下载go-cqhttp
发布的成品登录qq
,同时qq
表情的使用图片的形式来发到微信的,所以还需要qq
表情包的图片文件夹qq-face
可恶不仅代码写的好,还有女朋友
(ó﹏ò。) 现在没了。。。
有点意思,有没有办法微信转发到telegram
应该没啥问题,我看github上tg的机器人挺多的
话说现在gocq还能用么 前几周记得好像不能用了
应该还能用吧,我看仓库还在更新
好诶 晚点复刻一下 膜一下大佬
电话没链接网线,不使用电脑版,有可能可以自动转发吗?
丢到服务器上面跑就可以了
请问最便宜的是哪个服务?我只是需要这个服务。
服务器厂商那么多我也不知道哪个最便宜,你可以试试腾讯云或者阿里云的新人优惠,一年只要几十块钱
您好,有些细节搞不到,是否能私下交流不?谢谢。
emm,你想实现什么功能
哈哈哈哈还可以这样~
哈哈,奇奇怪怪的想法才是编程路上的动力嘛
你写得非常清晰明了,让我很容易理解你的观点。
那么可以反过来吗,把微信上女朋友的消息转发到qq,用qq回复
可以的,改一下逻辑就行,把你我微信和QQ小号都用bot登录,然后微信监听消息,判断是女朋友发的消息,就把消息内容用qq小号发给你,然后你回复qq小号的消息直接用微信bot发送给你女朋友
show me the money
不明觉厉
一句话,技术大佬就是好啊,可以实现好多好玩的、有趣的。哈哈哈哈
哈哈,算不上什么大佬,只不过喜欢胡乱捣鼓罢了
谦虚啦大佬,这代码我是看都看不懂,哈哈哈哈