Files
wechat_ipad_pro/srv/wxtask/wxfriendtask.go
2026-02-17 13:06:23 +08:00

470 lines
15 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package wxtask
import (
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/protobuf/wechat"
"xiawan/wx/srv/wxface"
)
// WXFriendTask 微信好友任务
type WXFriendTask struct {
wxConn wxface.IWXConnect
friendForList []*wechat.ModContact
friendForZombieFansList []*wechat.ModContact
labels []*wechat.LabelPair
waitTimes uint32 // 毫秒
isZombieFansDet bool // 检测僵死粉任务
isZombieFansDel bool // 删除僵死粉任务
}
// NewWXFriendTask 新建一个好友任务
func NewWXFriendTask(wxConn wxface.IWXConnect) *WXFriendTask {
return &WXFriendTask{
wxConn: wxConn,
friendForList: make([]*wechat.ModContact, 0),
friendForZombieFansList: make([]*wechat.ModContact, 0),
labels: make([]*wechat.LabelPair, 0),
isZombieFansDet: false,
isZombieFansDel: false,
waitTimes: uint32(1000), // 间隔 1000 毫秒
}
}
// 获取下一个待验证的好友
func (gpt *WXFriendTask) getNextFriendForContact() *wechat.ModContact {
if len(gpt.friendForList) <= 0 {
return nil
}
retContact := gpt.friendForList[0]
gpt.friendForList = gpt.friendForList[1:]
return retContact
}
// 获取 1500 - 2500 毫秒的随机数
func (gpt *WXFriendTask) getRandWaitTimes() int {
// 设置随机数种子
rand.Seed(time.Now().UnixNano())
// 生成 [1500, 2500] 之间的随机数
min := 1500
max := 2500
randomNumber := rand.Intn(max-min+1) + min
return randomNumber
}
// 获取 2000 - 4000 毫秒的随机数
func (gpt *WXFriendTask) getRandWaitTimes2() int {
// 设置随机数种子
rand.Seed(time.Now().UnixNano())
// 生成 [2000, 4000] 之间的随机数
min := 2000
max := 4000
randomNumber := rand.Intn(max-min+1) + min
return randomNumber
}
// 获取 5000 - 12000 毫秒的随机数5秒 - 12秒
func (gpt *WXFriendTask) getRandWaitTimes3() int {
// 设置随机数种子
rand.Seed(time.Now().UnixNano())
// 生成 [5000, 12000] 之间的随机数
min := 5000
max := 12000
randomNumber := rand.Intn(max-min+1) + min
return randomNumber
}
// 10 - 20秒 删除一个
// 获取 10000 - 20000 毫秒的随机数
func (gpt *WXFriendTask) getRandWaitTimes4() int {
// 设置随机数种子
rand.Seed(time.Now().UnixNano())
// 生成 [10000, 20000] 之间的随机数
min := 10000
max := 20000
randomNumber := rand.Intn(max-min+1) + min
return randomNumber
}
// 添加至标签 删除我的人 拉黑我的人
func (gpt *WXFriendTask) addTagForContact(labeName string, friendWxids []string) {
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
// 判断存在则删除,不存在则添加
labels := gpt.getTagForList()
// 当前标签
currentLabel := make([]*wechat.LabelPair, 0)
for _, label := range labels {
if label.GetLabelName() == labeName {
// 删除
currentWXReqInvoker.SendDelContactLabelRequest(strconv.FormatUint(uint64(label.GetLabelId()), 10))
break
}
}
if len(currentLabel) <= 0 {
// 添加标签
labelNames := make([]string, 0)
labelNames = append(labelNames, labeName)
resp, err := currentWXReqInvoker.SendAddContactLabelRequest(labelNames, true)
if err != nil {
return
}
currentLabel = resp.GetLabelPairList()
}
// 修改标签
if len(currentLabel) > 0 {
UserLabelList := make([]baseinfo.UserLabelInfoItem, 0)
for _, friendWxid := range friendWxids {
userLabel := baseinfo.UserLabelInfoItem{
UserName: friendWxid,
LabelIDList: strconv.FormatUint(uint64(currentLabel[0].GetLabelId()), 10),
}
UserLabelList = append(UserLabelList, userLabel)
}
currentWXReqInvoker.SendModifyLabelRequest(UserLabelList)
}
}
// 获取全部标签
func (gpt *WXFriendTask) getTagForList() []*wechat.LabelPair {
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
// 获取标签
resp, err := currentWXReqInvoker.SendGetContactLabelListRequest(true)
if err != nil {
return make([]*wechat.LabelPair, 0)
}
return resp.GetLabelPairList()
}
// 获取剩余僵死粉数量
// GetLessCount 获取剩余群聊数量
func (gpt *WXFriendTask) GetLessCount() uint32 {
return uint32(len(gpt.friendForZombieFansList))
}
// StartFriendTask 开启好友检测任务
func (gpt *WXFriendTask) StartFriendTask(taskType int) bool {
// currentWXAccount := gpt.wxConn.GetWXAccount()
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
currentWXFileHelperMgr := gpt.wxConn.GetWXFileHelperMgr()
// 如果正在执行执行任务,则返回
if gpt.isZombieFansDet {
tipText := "正在检测僵死粉,请稍后"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
return false
}
// 如果正在执行删除任务,则返回
if gpt.isZombieFansDel {
tipText := "正在清理僵死粉,请稍后"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
return false
}
if taskType == 1 {
gpt.isZombieFansDet = true
tmpTip := "执行检测僵死粉\n开始加载好友列表……"
currentWXFileHelperMgr.AddNewTipMsg(tmpTip)
}
if taskType == 2 {
gpt.isZombieFansDel = true
tmpTip := "执行清理僵死粉\n开始加载好友……"
currentWXFileHelperMgr.AddNewTipMsg(tmpTip)
}
gpt.friendForList = make([]*wechat.ModContact, 0)
gpt.friendForZombieFansList = make([]*wechat.ModContact, 0)
friendWxids := gpt.GetFriendWxidList()
// friendList := make([]*wechat.ModContact, 0)
go func() {
if len(friendWxids) <= 0 {
tipText := "好友检索完成,总数 0 个,无需操作"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
gpt.isZombieFansDel = false
gpt.isZombieFansDet = false
return
}
// 好友检索完成,好友总数:
tipText := "好友加载完成!!\n开始检测好友请耐心等待……"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
for i := 0; i < len(friendWxids); i += 1 {
// 获取详情
friend := new(wechat.ModContact)
friend.UserName = new(wechat.SKBuiltinString)
friend.Remark = new(wechat.SKBuiltinString)
friend.UserName.Str = new(string)
*friend.UserName.Str = friendWxids[i]
gpt.friendForList = append(gpt.friendForList, friend)
}
temFriendCount := 0
for {
// 先判断是否还处于链接当中
if !gpt.wxConn.IsConnected() {
gpt.isZombieFansDel = false
gpt.isZombieFansDet = false
return
}
// 获取下一个好友
tmpModContact := gpt.getNextFriendForContact()
temFriendCount++
if tmpModContact == nil {
zembieFansCount := len(gpt.friendForZombieFansList)
friendForZombieFansList := make([]*wechat.ModContact, 0)
friendNamesDel := ""
friendWxidsDel := make([]string, 0)
// 拉黑我的人
friendFroBlack := ""
friendWxidsBlack := make([]string, 0)
if zembieFansCount > 0 {
// jsonStr0, _ := json.Marshal(gpt.friendForList)
// fmt.Println(string(jsonStr0))
for i := 0; i < zembieFansCount; i += 20 {
end := i + 20
if end > len(gpt.friendForZombieFansList) {
end = len(gpt.friendForZombieFansList)
}
oldFriends := gpt.friendForZombieFansList[i:end]
friendWxids := make([]string, 0)
for _, tmpFriend := range oldFriends {
friendWxids = append(friendWxids, tmpFriend.GetUserName().GetStr())
}
// 获取详情
contactList, err := currentWXReqInvoker.SendGetContactRequestForList(friendWxids, nil)
if err != nil {
fmt.Println("获取好友详情失败:", err)
continue
}
// 先判断是否还处于链接当中
if !gpt.wxConn.IsConnected() {
gpt.isZombieFansDel = false
gpt.isZombieFansDet = false
return
}
// friends := contactList.GetContactList()
verifyUserList := contactList.GetVerifyUserValidTicketList()
friends := contactList.GetContactList()
// 转 json 并写入文件
// jsonStr, _ := json.Marshal(friends)
// fmt.Println(string(jsonStr))
// jsonStr2, _ := json.Marshal(verifyUserList)
// fmt.Println(string(jsonStr2))
count := len(friends)
for index := 0; index < count; index++ {
friendItem := friends[index]
verifyUserItem := verifyUserList[index]
CardWxId := friendItem.GetUserName().GetStr()
CardNickName := friendItem.GetNickName().GetStr()
// CardAlias := friendItem.GetAlias()
// 联系人
// 如果是僵死粉
if strings.HasPrefix(verifyUserItem.GetAntispamticket(), "v4_") && friendItem.GetHeadImgMd5() != "" {
if friendNamesDel != "" {
friendNamesDel += "\n"
}
friendItem.Remark = new(wechat.SKBuiltinString)
friendItem.Remark.Str = new(string)
*friendItem.Remark.Str = "删除我的人"
friendNamesDel += "删除我的人"
friendNamesDel += ("【" + CardNickName + "】")
friendWxidsDel = append(friendWxidsDel, CardWxId)
// baseutils.PrintLog("僵尸粉:" + tmpContact.GetNickName().GetStr())
} else {
// 拉黑
if friendFroBlack != "" {
friendFroBlack += "\n"
}
friendItem.Remark = new(wechat.SKBuiltinString)
friendItem.Remark.Str = new(string)
*friendItem.Remark.Str = "拉黑我的人"
friendFroBlack += "拉黑我的人"
friendFroBlack += ("【" + CardNickName + "】")
friendWxidsBlack = append(friendWxidsBlack, CardWxId)
}
friendForZombieFansList = append(friendForZombieFansList, friendItem)
}
// 暂停 1.5 - 2.5 秒
randWaitTime := gpt.getRandWaitTimes()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
}
}
// 添加到标签
// 发送名单列表
if friendNamesDel != "" {
gpt.addTagForContact("删除我的人", friendWxidsDel)
currentWXFileHelperMgr.AddNewTipMsg(friendNamesDel)
}
if friendFroBlack != "" {
gpt.addTagForContact("拉黑我的人", friendWxidsBlack)
currentWXFileHelperMgr.AddNewTipMsg(friendFroBlack)
}
tipText := "检测完成 \n"
tipText += "删除我的人 - 【" + strconv.Itoa(len(friendWxidsDel)) + "】个\n"
tipText += "拉黑我的人 - 【" + strconv.Itoa(len(friendWxidsBlack)) + "】个\n"
tipText += "僵死粉已标记到标签中,以便查看"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
gpt.isZombieFansDet = false
if gpt.isZombieFansDel {
tipText := "由于官方限制,删除好友所需时间较长,请耐心等待……,请勿退出 Ipad 登录!!"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
// 暂停 1 - 2 分钟
randWaitTime := gpt.getRandWaitTimes3()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
// 删除僵死粉
for _, friendWxid := range friendWxidsDel {
// 删除
err := currentWXReqInvoker.SendDelContactRequest(friendWxid)
if err != nil {
gpt.isZombieFansDet = false
gpt.isZombieFansDel = false
fmt.Printf("删除好友 del friend err %+v", err)
return
}
for _, friendRemak := range friendForZombieFansList {
if friendRemak.GetUserName().GetStr() == friendWxid {
tipText := "删除-删除我的人【" + friendRemak.GetNickName().GetStr() + "】"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
}
}
// 暂停 10s - 20s
randWaitTime := gpt.getRandWaitTimes4()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
}
for _, friendWxid := range friendWxidsBlack {
// 删除
err := currentWXReqInvoker.SendDelContactRequest(friendWxid)
if err != nil {
gpt.isZombieFansDet = false
gpt.isZombieFansDel = false
fmt.Printf("删除好友 del friend err %+v", err)
return
}
for _, friendRemak := range friendForZombieFansList {
if friendRemak.GetUserName().GetStr() == friendWxid {
tipText := "删除-拉黑我的人【" + friendRemak.GetNickName().GetStr() + "】"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
}
}
// 暂停 2 - 5 分钟
randWaitTime := gpt.getRandWaitTimes3()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
}
gpt.isZombieFansDet = false
gpt.isZombieFansDel = false
tipText = "清理完成【已清理】:" + strconv.Itoa(len(friendWxidsDel)+len(friendWxidsBlack))
currentWXFileHelperMgr.AddNewTipMsg(tipText)
}
return
}
// 判断每次超过 25 个好友,则返回%分比进度
if temFriendCount%25 == 0 {
// 取整 temFriendCount / len(friendWxids) * 100 去掉小数点
numCount := int(float64(temFriendCount) / float64(len(friendWxids)) * 100)
tipText := "已检测【" + strconv.Itoa(numCount) + "%】好友"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
}
// 获取好友关系请求
friendUserName := tmpModContact.GetUserName().GetStr()
// 微信团队跳过
if friendUserName == "Weixin" {
continue
}
// 判断是否是僵死粉
resp, err := currentWXReqInvoker.SendGetFriendRelationRequest(friendUserName)
if err != nil {
continue
}
if resp.GetFriendRelation() == 0 {
continue
}
// 1删除 4自己拉黑 5被拉黑
if resp.GetFriendRelation() == 1 {
tmpModContact.Remark.Str = new(string)
*tmpModContact.Remark.Str = "删除我的人"
// 添加到僵尸粉列表
gpt.friendForZombieFansList = append(gpt.friendForZombieFansList, tmpModContact)
}
if resp.GetFriendRelation() == 5 {
tmpModContact.Remark.Str = new(string)
*tmpModContact.Remark.Str = "拉黑我的人"
// 添加到僵尸粉列表
gpt.friendForZombieFansList = append(gpt.friendForZombieFansList, tmpModContact)
}
// 暂停 1.5 - 2.5 秒
randWaitTime := gpt.getRandWaitTimes()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
}
}()
return true
}
// 获取联系人
func (gpt *WXFriendTask) GetFriendWxidList() []string {
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
currentWXFileHelperMgr := gpt.wxConn.GetWXFileHelperMgr()
CurrentWxcontactSeq := uint32(0)
CurrentChatRoomContactSeq := uint32(0)
friendUserNames := make([]string, 0)
pages := 0
// 死循环
for {
pages++
resp, err := currentWXReqInvoker.SendGetContactListPageRequest(CurrentWxcontactSeq, CurrentChatRoomContactSeq)
if err != nil {
return friendUserNames
}
UserNameList := resp.GetContactUsernameList()
if resp.GetContactUsernameList() == nil {
return friendUserNames
}
if len(UserNameList) == 0 {
return friendUserNames
}
tipText := "正在加载第 " + strconv.Itoa(pages) + " 页"
currentWXFileHelperMgr.AddNewTipMsg(tipText)
for _, contactUserName := range UserNameList {
if contactUserName == "weixin" ||
contactUserName == "fmessage" ||
contactUserName == "medianote" ||
contactUserName == "floatbottle" ||
contactUserName == "qqmail" ||
contactUserName == "filehelper" ||
contactUserName == "mphelper" ||
contactUserName == "qmessage" {
continue
}
// 判断 gh 开头
if strings.HasPrefix(contactUserName, "gh_") {
continue
}
// 判断 @chatroom 结尾
if strings.HasSuffix(contactUserName, "@chatroom") {
continue
}
friendUserNames = append(friendUserNames, contactUserName)
}
CurrentWxcontactSeq = resp.GetCurrentWxcontactSeq()
CurrentChatRoomContactSeq = resp.GetCurrentChatRoomContactSeq()
// 暂停 1.5 - 2.5 秒
randWaitTime := gpt.getRandWaitTimes()
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
}
}