study_xxqg/lib/tg.go

402 lines
9.4 KiB
Go

package lib
import (
"encoding/base64"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"github.com/huoxue1/study_xxqg/model"
)
var (
handles sync.Map
datas sync.Map
)
// Telegram
// @Description:
//
type Telegram struct {
Token string
ChatId int64
bot *tgbotapi.BotAPI
Proxy string
}
type Handle interface {
getCommand() string
execute(bot *Telegram, args []string)
}
type Mather struct {
command string
handle func(bot *Telegram, args []string)
}
func (m Mather) getCommand() string {
return m.command
}
func (m Mather) execute(bot *Telegram, args []string) {
m.handle(bot, args)
}
func newPlugin(command string, handle func(bot *Telegram, args []string)) {
handles.Store(command, handle)
}
// Init
/**
* @Description:
* @receiver t
* @return func(kind string, message string)
*/
func (t *Telegram) Init() {
newPlugin("/login", login)
newPlugin("/get_users", getAllUser)
newPlugin("/study", study)
newPlugin("/get_scores", getScores)
newPlugin("/quit", quit)
newPlugin("/study_all", studyAll)
uri, err := url.Parse(t.Proxy)
if err != nil {
log.Errorln("代理解析失败" + err.Error())
err = nil
}
t.bot, err = tgbotapi.NewBotAPIWithClient(t.Token, tgbotapi.APIEndpoint, &http.Client{Transport: &http.Transport{
// 设置代理
Proxy: http.ProxyURL(uri),
}})
if err != nil {
log.Errorln("telegram token鉴权失败或代理使用失败")
log.Errorln(err.Error())
}
channel := t.bot.GetUpdatesChan(tgbotapi.NewUpdate(1))
t.SendMsg("你的学习强国小助手上线了!")
go func() {
for {
update := <-channel
if update.Message == nil {
update.Message = &tgbotapi.Message{Text: update.CallbackQuery.Data}
t.bot.Send(tgbotapi.NewDeleteMessage(config.TG.ChatID, update.CallbackQuery.Message.MessageID))
log.Infoln(update.CallbackQuery.Data)
}
log.Infoln("收到tg消息 ", update)
handles.Range(func(key, value interface{}) bool {
if strings.Split(update.Message.Text, " ")[0] == key.(string) {
go func() {
defer func() {
err := recover()
if err != nil {
log.Errorln(err)
log.Errorln("handle执行出现了不可挽回的错误")
}
}()
(value.(func(bot *Telegram, args []string)))(t, strings.Split(update.Message.Text, " ")[1:])
}()
}
return true
})
}
}()
_, err = t.bot.Request(tgbotapi.NewSetMyCommands(
tgbotapi.BotCommand{Command: "login", Description: "登录一个账号"},
tgbotapi.BotCommand{Command: "get_users", Description: "获取所有cookie有效的用户"},
tgbotapi.BotCommand{Command: "study", Description: "对一个账户进行学习"},
tgbotapi.BotCommand{Command: "get_scores", Description: "获取用户成绩"},
tgbotapi.BotCommand{Command: "quit", Description: "退出所有正在学习的实例,或者跟上实例ID退出对应实例"},
tgbotapi.BotCommand{Command: "study_all", Description: "对当前所有用户进行按顺序学习"},
))
if err != nil {
return
}
}
func (t *Telegram) SendPhoto(image []byte) {
photo := tgbotapi.NewPhoto(t.ChatId, tgbotapi.FileBytes{
Name: "login code",
Bytes: image,
})
_, err := t.bot.Send(photo)
if err != nil {
log.Errorln("发送图片信息失败")
log.Errorln(err.Error())
return
}
}
func (t *Telegram) SendMsg(message string) int {
msg := tgbotapi.NewMessage(t.ChatId, message)
messa, err := t.bot.Send(msg)
if err != nil {
return 0
}
return messa.MessageID
}
func login(bot *Telegram, args []string) {
config := GetConfig()
go func() {
defer func() {
err := recover()
if err != nil {
log.Errorln(err)
}
}()
core := Core{
pw: nil,
browser: nil,
context: nil,
ShowBrowser: config.ShowBrowser,
Push: func(kind string, message string) {
switch {
case kind == "image":
bytes, _ := base64.StdEncoding.DecodeString(message)
bot.SendPhoto(bytes)
case kind == "markdown":
newMessage := tgbotapi.NewMessage(bot.ChatId, message)
newMessage.ParseMode = tgbotapi.ModeMarkdownV2
bot.bot.Send(newMessage)
default:
bot.SendMsg(message)
}
},
}
core.Init()
defer core.Quit()
_, err := core.L()
if err != nil {
bot.SendMsg(err.Error())
return
}
bot.SendMsg("登录成功")
}()
}
func getAllUser(bot *Telegram, args []string) {
users, err := model.Query()
if err != nil {
bot.SendMsg("获取用户失败" + err.Error())
return
}
message := fmt.Sprintf("共获取到%v个有效用户信息\n", len(users))
for i, user := range users {
message += fmt.Sprintf("%v %v", i, user.Nick)
message += "\n"
}
bot.SendMsg(message)
}
func studyAll(bot *Telegram, args []string) {
config := GetConfig()
users, err := model.Query()
if err != nil {
bot.SendMsg(err.Error())
return
}
if len(users) == 0 {
bot.SendMsg("未发现用户信息,请输入/login进行用户登录")
return
}
getAllUser(bot, args)
for _, user := range users {
s := func() {
core := Core{
pw: nil,
browser: nil,
context: nil,
ShowBrowser: config.ShowBrowser,
Push: func(kind string, message string) {
switch {
case kind == "image":
bytes, _ := base64.StdEncoding.DecodeString(message)
bot.SendPhoto(bytes)
case kind == "markdown":
newMessage := tgbotapi.NewMessage(bot.ChatId, message)
newMessage.ParseMode = tgbotapi.ModeMarkdownV2
_, _ = bot.bot.Send(newMessage)
default:
bot.SendMsg(message)
}
},
}
timer := time.After(time.Minute * 30)
c := make(chan int, 1)
go func() {
u := uuid.New().String()
bot.SendMsg("已创建运行实例:" + u)
datas.Store(u, &core)
defer datas.Delete(u)
core.Init()
defer core.Quit()
core.LearnArticle(user)
core.LearnVideo(user)
core.RespondDaily(user, "daily")
core.RespondDaily(user, "weekly")
core.RespondDaily(user, "special")
c <- 1
}()
select {
case <-timer:
{
bot.SendMsg("学习超时,请重新登录或检查日志")
log.Errorln("学习超时,已自动退出")
core.Quit()
}
case <-c:
{
}
}
score, _ := GetUserScore(user.ToCookies())
bot.SendMsg(fmt.Sprintf("当前学习总积分:%v,今日得分:%v", score.TotalScore, score.TodayScore))
}
s()
}
}
func study(bot *Telegram, args []string) {
config := GetConfig()
users, err := model.Query()
if err != nil {
bot.SendMsg(err.Error())
return
}
var user *model.User
switch {
case len(users) == 1:
bot.SendMsg("仅存在一名用户信息,自动进行学习")
user = users[0]
case len(users) == 0:
bot.SendMsg("未发现用户信息,请输入/login进行用户登录")
return
default:
if 0 < len(args) {
i, err := strconv.Atoi(args[0])
if err != nil {
bot.SendMsg(err.Error())
return
}
user = users[i]
} else {
msgID := bot.SendMsg("存在多名用户,未输入用户序号")
markup := tgbotapi.InlineKeyboardMarkup{}
for i, user := range users {
markup.InlineKeyboard = append(markup.InlineKeyboard, append([]tgbotapi.InlineKeyboardButton{}, tgbotapi.NewInlineKeyboardButtonData(user.Nick, "/study "+strconv.Itoa(i))))
}
replyMarkup := tgbotapi.NewEditMessageReplyMarkup(config.TG.ChatID, msgID, markup)
_, err := bot.bot.Send(replyMarkup)
if err != nil {
return
}
return
}
}
core := Core{
pw: nil,
browser: nil,
context: nil,
ShowBrowser: config.ShowBrowser,
Push: func(kind string, message string) {
switch {
case kind == "image":
bytes, _ := base64.StdEncoding.DecodeString(message)
bot.SendPhoto(bytes)
case kind == "markdown":
newMessage := tgbotapi.NewMessage(bot.ChatId, message)
newMessage.ParseMode = tgbotapi.ModeMarkdownV2
_, _ = bot.bot.Send(newMessage)
default:
bot.SendMsg(message)
}
},
}
timer := time.After(time.Minute * 30)
c := make(chan int, 1)
go func() {
u := uuid.New().String()
bot.SendMsg("已创建运行实例:" + u)
datas.Store(u, &core)
defer datas.Delete(u)
core.Init()
defer core.Quit()
core.LearnArticle(user)
core.LearnVideo(user)
core.RespondDaily(user, "daily")
core.RespondDaily(user, "weekly")
core.RespondDaily(user, "special")
c <- 1
}()
select {
case <-timer:
{
log.Errorln("学习超时,已自动退出")
bot.SendMsg("学习超时,请重新登录或检查日志")
core.Quit()
}
case <-c:
{
}
}
score, _ := GetUserScore(user.ToCookies())
bot.SendMsg(fmt.Sprintf("当前学习总积分:%v,今日得分:%v", score.TotalScore, score.TodayScore))
}
func getScores(bot *Telegram, args []string) {
users, err := model.Query()
if err != nil {
log.Errorln(err.Error())
bot.SendMsg("获取用户信息失败" + err.Error())
return
}
message := fmt.Sprintf("共获取到%v个有效用户信息\n", len(users))
for _, user := range users {
message += user.Nick + "\n"
score, err := GetUserScore(user.ToCookies())
if err != nil {
message += err.Error() + "\n"
}
message += formatScore(score) + "\n"
}
bot.SendMsg(message)
}
func quit(bot *Telegram, args []string) {
if len(args) < 1 {
datas.Range(func(key, value interface{}) bool {
bot.SendMsg("已退出运行实例" + key.(string))
core := value.(*Core)
core.Quit()
return true
})
} else {
datas.Range(func(key, value interface{}) bool {
if key.(string) == args[0] {
core := value.(*Core)
core.Quit()
}
return true
})
}
}