From e0907c0e80a363fa1fc5be716f29493b8852495c Mon Sep 17 00:00:00 2001 From: zyj <18107291228@163.com> Date: Thu, 20 Nov 2025 11:43:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9F=A5=E7=9C=8B=E6=8E=A8?= =?UTF-8?q?=E6=96=87=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/task.go | 2 +- models/ar_twitter_post.go | 39 +++++++++++ plugin/task-view-post-plugin.go | 103 ++++++++++++++++++++++++++++ services/twitter_account_service.go | 26 +++++-- services/twitter_post_service.go | 25 +++++++ task/scheduler.go | 23 ++++--- 6 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 models/ar_twitter_post.go create mode 100644 plugin/task-view-post-plugin.go create mode 100644 services/twitter_post_service.go diff --git a/api/task.go b/api/task.go index 3322bdb..3d86e3b 100644 --- a/api/task.go +++ b/api/task.go @@ -18,7 +18,7 @@ type CreateRequestParams struct { Name string `form:"name" json:"name" uri:"name" xml:"name"` RunStatus int `form:"runStatus" json:"runStatus" uri:"runStatus" xml:"runStatus" binding:"required"` Type int `form:"type" json:"type" uri:"type" xml:"type" binding:"required"` - AccountClassify string `form:"accountClassify" json:"accountClassify" uri:"accountClassify" xml:"accountClassify" binding:"required"` + AccountClassify string `form:"accountClassify" json:"accountClassify" uri:"accountClassify" xml:"accountClassify"` ClassifyId []int `form:"classifyId" json:"classifyId" uri:"classifyId" xml:"classifyId"` Keyword string `form:"keyword" json:"keyword" uri:"keyword" xml:"keyword"` TwitterId string `form:"twitterId" json:"twitterId" uri:"twitterId" xml:"twitterId"` diff --git a/models/ar_twitter_post.go b/models/ar_twitter_post.go new file mode 100644 index 0000000..9267483 --- /dev/null +++ b/models/ar_twitter_post.go @@ -0,0 +1,39 @@ +package models + +import "time" + +// TwitterPost 推文记录模型 +type TwitterPost struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + AccountId int64 `gorm:"column:account_id;not null;default:0" json:"account_id"` // 账号ID + Content string `gorm:"column:content;type:varchar(255);default:''" json:"content"` // 推文内容 + Images string `gorm:"column:images;type:json" json:"images"` // 图片列表(JSON格式) + Link string `gorm:"column:link;type:varchar(255);default:''" json:"link"` // 推文链接 + ContentLink string `gorm:"column:content_link;type:varchar(255);default:''" json:"content_link"` // 内容链接 + Status int8 `gorm:"column:status;type:tinyint(3);not null;default:1" json:"status"` // 状态: 1-正常 0-删除 + UpdateTime int64 `gorm:"column:update_time;autoUpdateTime" json:"update_time"` // 更新时间 + CreateTime int64 `gorm:"column:create_time;autoCreateTime" json:"create_time"` // 创建时间 +} + +// TableName 指定表名 +func (TwitterPost) TableName() string { + return "ar_twitter_post" +} + +// BeforeCreate GORM 钩子 - 创建前设置时间 +func (tp *TwitterPost) BeforeCreate(tx interface{}) error { + now := time.Now().Unix() + if tp.CreateTime == 0 { + tp.CreateTime = now + } + if tp.UpdateTime == 0 { + tp.UpdateTime = now + } + return nil +} + +// BeforeUpdate GORM 钩子 - 更新前设置时间 +func (tp *TwitterPost) BeforeUpdate(tx interface{}) error { + tp.UpdateTime = time.Now().Unix() + return nil +} diff --git a/plugin/task-view-post-plugin.go b/plugin/task-view-post-plugin.go new file mode 100644 index 0000000..122bcc4 --- /dev/null +++ b/plugin/task-view-post-plugin.go @@ -0,0 +1,103 @@ +package plugin + +import ( + "go-account-register/config" + "go-account-register/models" + "go-account-register/services" + paramsTypes "go-account-register/types" + "log" + "math" + "runtime/debug" + "sync" + "time" +) + +var TwitterService services.TwitterService + +type TaskViewPostPlugin struct{} + +func (*TaskViewPostPlugin) Run(task *paramsTypes.Task) { + + // 查询当前所有账号 + userService := services.InitTwitterAccountService() + // 判断是否是补偿任务 + var userList []models.TwitterAccount + userList = userService.GetAvailableAccount(&models.TwitterAccount{ + Type: "view", + }) + + if task.Data.Compensate == 1 { + // 补偿任务 + userList = userService.GetAccountListByStatus(&models.TwitterAccount{ + Status: "查看成功", + Type: "view", + }) + } else { + // 清空当前运行的账号状态 + userService.ClearAccountStatus(&models.TwitterAccount{ + Type: "view", + }) + } + log.Println("可用账号数量:", len(userList)) + // 获取并发数 + appConfig, _ := config.LoadConfig() + num := math.Ceil(float64(len(userList)) / float64(appConfig.Limit.BrowserRunMax)) + sem := make(chan struct{}, appConfig.Limit.BrowserRunMax) // 全局并发上限 + var globalWait sync.WaitGroup + for i := 0; i < int(num); i++ { + select { + case <-task.Ctx.Done(): + log.Println("中断任务") + return + default: + } + log.Println("批次:", i+1) + for j := 0; j < appConfig.Limit.BrowserRunMax; j++ { + log.Println(i*appConfig.Limit.BrowserRunMax + j) + taskIndex := i*appConfig.Limit.BrowserRunMax + j + if taskIndex >= len(userList) { + break + } + time.Sleep(10 * time.Second) + globalWait.Add(1) + sem <- struct{}{} // 阻塞直到有空位 + go func() { + defer func() { + <-sem // 释放信号量 + globalWait.Done() + }() + changeAccountWork(task, userList[taskIndex].ID) + }() + } + } + globalWait.Wait() + + task.Message <- "Success" +} + +func changeAccountWork(task *paramsTypes.Task, id int64) { + UserService := services.InitTwitterAccountService() + defer func() { + if r := recover(); r != nil { + log.Printf("Goroutine panic: %v\nStack: %s", r, debug.Stack()) + UserService.ChangeAccountLoginStatus(int(id), "账号下线") + TwitterService.Logout(int(id)) + } + }() + + // 开始登录 + + res := TwitterService.Login(int(id)) + UserService.ChangeAccountLoginStatus(int(id), res.Msg) + if res.Code == 200 { + // 开始拟人 + res = TwitterService.LoopViewPost(int(id)) + UserService.ChangeAccountStatus(int(id), res.Msg) + time.Sleep(3 * time.Second) + + TwitterService.Logout(int(id)) + UserService.ChangeAccountLoginStatus(int(id), "账号下线") + } + + log.Println(task.ID) +} diff --git a/services/twitter_account_service.go b/services/twitter_account_service.go index 02a9cb0..35836d5 100644 --- a/services/twitter_account_service.go +++ b/services/twitter_account_service.go @@ -60,19 +60,27 @@ func (u *TwitterAccountService) OfflineAllAccount() bool { // 获取可用账号 func (u *TwitterAccountService) GetAvailableAccount(params *models.TwitterAccount) []models.TwitterAccount { var users []models.TwitterAccount - res := u.db.Model(&models.TwitterAccount{}).Where(`status = ? AND (login_status != "账号异常" OR login_status IS NULL)`, params.Status) + res := u.db.Model(&models.TwitterAccount{}).Where(`type = ? AND (login_status != "账号异常" OR login_status IS NULL)`, params.Type) // if params.Username != "" { // res.Where("username LIKE ?", "%"+params.Username+"%") // } + res.Order("id DESC").Find(&users) + return users +} + +// 获取ID范围内的账号 +func (u *TwitterAccountService) GetAccountListByIdRange(minId, maxId int64) []models.TwitterAccount { + var users []models.TwitterAccount + res := u.db.Model(&models.TwitterAccount{}).Where(`id >= ? AND id <= ?`, minId, maxId) res.Order("id DESC").Find(&users) return users } -// 获取养号未运行或者运行失败的账号 +// 获取未运行或者运行失败的账号 func (u *TwitterAccountService) GetAccountListByStatus(params *models.TwitterAccount) []models.TwitterAccount { var users []models.TwitterAccount - res := u.db.Model(&models.TwitterAccount{}).Where(`status = ? AND (login_status != "账号异常" OR login_status IS NULL)`, params.Status) + res := u.db.Model(&models.TwitterAccount{}).Where(`type = ? AND (login_status != "账号异常" OR login_status IS NULL) AND (status != ? OR status IS NULL)`, params.Type, params.Status) // if params.Username != "" { // res.Where("username LIKE ?", "%"+params.Username+"%") // } @@ -82,7 +90,13 @@ func (u *TwitterAccountService) GetAccountListByStatus(params *models.TwitterAcc // 清空状态字段 func (u *TwitterAccountService) ClearAccountStatus(params *models.TwitterAccount) bool { - u.db.Model(&models.TwitterAccount{}).Where("status = ?", params.Status).Update("status", nil) + u.db.Model(&models.TwitterAccount{}).Where("type = ?", params.Type).Update("status", nil) + return true +} + +// 清空状态字段 +func (u *TwitterAccountService) ChangeAccountStatusByStatus(params *models.TwitterAccount, status string) bool { + u.db.Model(&models.TwitterAccount{}).Where("status = ?", params.Status).Update("status", status) return true } @@ -90,3 +104,7 @@ func (u *TwitterAccountService) Update(id int64, params *models.TwitterAccount) params.UpdateTime = time.Now().Unix() u.db.Model(&models.TwitterAccount{}).Where("id = ?", id).Updates(params) } + +func (u *TwitterAccountService) Delete(id int64) { + u.db.Delete(&models.TwitterAccount{}, id) +} diff --git a/services/twitter_post_service.go b/services/twitter_post_service.go new file mode 100644 index 0000000..f511409 --- /dev/null +++ b/services/twitter_post_service.go @@ -0,0 +1,25 @@ +package services + +import ( + "go-account-register/models" + "go-account-register/utils" + + "gorm.io/gorm" +) + +type TwitterPostService struct { + db *gorm.DB +} + +func InitTwitterPostService() *TwitterPostService { + db := utils.GetDB() + return &TwitterPostService{db: db} +} + +func (s *TwitterPostService) GetAll() []models.TwitterPost { + var post []models.TwitterPost + res := s.db.Model(&models.TwitterPost{}).Where(`status = ? `, 1) + + res.Order("id DESC").Find(&post) + return post +} diff --git a/task/scheduler.go b/task/scheduler.go index df744cc..81a04ec 100644 --- a/task/scheduler.go +++ b/task/scheduler.go @@ -6,6 +6,7 @@ import ( "sort" "sync" + "go-account-register/plugin" paramsTypes "go-account-register/types" "github.com/fatih/structs" @@ -168,20 +169,20 @@ func (s *Scheduler) processQueue() { func (s *Scheduler) executeTask(task *paramsTypes.Task) { // 根据类型判断任务 - // switch task.Type { + switch task.Type { // case 6: // var taskNurturingClashPlugin plugin.TaskNurturingClashPlugin // go taskNurturingClashPlugin.Run(task) - // case 1: - // var taskChangeAccoutnClashPlugin plugin.TaskChangeAccoutnClashPlugin - // go taskChangeAccoutnClashPlugin.Run(task) - // case 3: - // var taskFollowClashPlugin plugin.TaskFollowClashPlugin - // go taskFollowClashPlugin.Run(task) - // case 7: - // var taskSendGifPlugin plugin.TaskSendGifPlugin - // go taskSendGifPlugin.Run(task) - // } + case 1: + var taskViewPostPlugin plugin.TaskViewPostPlugin + go taskViewPostPlugin.Run(task) + // case 3: + // var taskFollowClashPlugin plugin.TaskFollowClashPlugin + // go taskFollowClashPlugin.Run(task) + // case 7: + // var taskSendGifPlugin plugin.TaskSendGifPlugin + // go taskSendGifPlugin.Run(task) + } // 创建一个阻塞获取当前任务 select {