From d732df275b39b5e09a78f60a630c3d67aca1cc3b Mon Sep 17 00:00:00 2001 From: johlanse Date: Sat, 27 Nov 2021 16:24:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0telegram=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +- lib/config.go | 11 +- lib/config_default.yml | 12 +- lib/core.go | 7 ++ lib/respond.go | 5 +- lib/score.go | 20 +++- lib/study.go | 7 -- lib/tg.go | 252 +++++++++++++++++++++++++++++++++++++++++ main.go | 27 ++++- push/push.go | 7 -- push/tg.go | 75 ------------ 11 files changed, 322 insertions(+), 113 deletions(-) create mode 100644 lib/tg.go delete mode 100644 push/tg.go diff --git a/README.md b/README.md index 966bc43..5ea9e3e 100644 --- a/README.md +++ b/README.md @@ -42,17 +42,19 @@ push: enable: false access_token: "" secret: "" - - tg: - enable: false - chat_id: "" - token: "" # 目前仅支持pushplus推送二维码,默认建议使用pushplus推送 # pushplus使用方法见:http://www.pushplus.plus/ push_plus: enable: true token: "" + +tg: + enable: false + chat_id: 0 + token: "" + proxy: "" + # 设置是否定时执行学习程序,格式为cron格式 # "9 19 * * *" 每天19点9分执行一次 # "* 10 * * *” 每天早上十点执行一次 diff --git a/lib/config.go b/lib/config.go index ba5ee7a..a88741d 100644 --- a/lib/config.go +++ b/lib/config.go @@ -18,16 +18,17 @@ type Config struct { AccessToken string `json:"access_token" yaml:"access_token"` Secret string `json:"secret" yaml:"secret"` } `json:"ding" yaml:"ding"` - TG struct { - Enable bool `json:"enable" yaml:"enable"` - Token string `json:"token" yaml:"token"` - ChatID string `json:"chat_id" yaml:"chat_id"` - } `json:"tg" yaml:"tg"` PushPlus struct { Enable bool `json:"enable" yaml:"enable"` Token string `json:"token" yaml:"token"` } `json:"push_plus" yaml:"push_plus"` } `json:"push" yaml:"push"` + TG struct { + Enable bool `json:"enable" yaml:"enable"` + Token string `json:"token" yaml:"token"` + ChatID int64 `json:"chat_id" yaml:"chat_id"` + Proxy string `json:"proxy" yaml:"proxy"` + } `json:"tg" yaml:"tg"` Cron string `json:"cron"` } diff --git a/lib/config_default.yml b/lib/config_default.yml index fed6b55..f783699 100644 --- a/lib/config_default.yml +++ b/lib/config_default.yml @@ -23,17 +23,19 @@ push: enable: false access_token: "" secret: "" - - tg: - enable: false - chat_id: "" - token: "" # 目前仅支持pushplus推送二维码,默认建议使用pushplus推送 # pushplus使用方法见:http://www.pushplus.plus/ push_plus: enable: true token: "" +# telegram交互模式配置 +tg: + enable: false + chat_id: 0 + token: "" + proxy: "" + # 设置是否定时执行学习程序,格式为cron格式 # "9 19 * * *" 每天19点9分执行一次 # "* 10 * * *” 每天早上十点执行一次 diff --git a/lib/core.go b/lib/core.go index 66c9085..4433b42 100644 --- a/lib/core.go +++ b/lib/core.go @@ -107,6 +107,13 @@ func (c *Core) Quit() { } func (c *Core) Login() ([]Cookie, error) { + defer func() { + i := recover() + if i != nil { + log.Errorln("登录模块出现无法挽救的错误") + log.Errorln(i) + } + }() page, err := (*c.context).NewPage() if err != nil { diff --git a/lib/respond.go b/lib/respond.go index 8774a82..cd07ea8 100644 --- a/lib/respond.go +++ b/lib/respond.go @@ -25,7 +25,7 @@ func (c *Core) RespondDaily(cookies []Cookie, model string) { defer func() { err := recover() if err != nil { - log.Errorln("答题模块异常结束") + log.Errorln("答题模块异常结束或答题已完成") time.Sleep(5 * time.Second) log.Errorln(err) } @@ -51,7 +51,7 @@ func (c *Core) RespondDaily(cookies []Cookie, model string) { return } - log.Infoln("已加载每日答题模块") + log.Infoln("已加载答题模块") _, err = page.Goto(MyPointsUri, playwright.PageGotoOptions{ Referer: playwright.String(MyPointsUri), @@ -171,6 +171,7 @@ func (c *Core) RespondDaily(cookies []Cookie, model string) { return } + _ = category.WaitForElementState(`visible`) time.Sleep(1 * time.Second) // 获取题目 diff --git a/lib/score.go b/lib/score.go index 60b5dfb..bc2c503 100644 --- a/lib/score.go +++ b/lib/score.go @@ -3,6 +3,7 @@ package lib import ( "errors" "fmt" + "time" "github.com/guonaihong/gout" log "github.com/sirupsen/logrus" @@ -97,6 +98,24 @@ func GetUserScore(cookies []Cookie) (Score, error) { } func PrintScore(score Score) string { + result := "" + result += fmt.Sprintf("当前学习总积分:%d 今日得分:%d\n", score.TodayScore, score.TodayScore) + result += fmt.Sprintf("[%v] [INFO]: 登录:%v/%v 文章学习:%v/%v 视频学习:%v/%v 视频时长:%v/%v\n[%v] [INFO]: 每日答题:%v/%v 每周答题:%v/%v 专项答题:%v/%v", + time.Now().Format("2006-01-02 15:04:05"), + score.Content["login"].CurrentScore, score.Content["login"].MaxScore, + score.Content["article"].CurrentScore, score.Content["article"].MaxScore, + score.Content["video"].CurrentScore, score.Content["video"].MaxScore, + score.Content["video_time"].CurrentScore, score.Content["video_time"].MaxScore, + time.Now().Format("2006-01-02 15:04:05"), + score.Content["daily"].CurrentScore, score.Content["daily"].MaxScore, + score.Content["weekly"].CurrentScore, score.Content["weekly"].MaxScore, + score.Content["special"].CurrentScore, score.Content["special"].MaxScore, + ) + log.Infoln(result) + return result +} + +func foramet_score(score Score) string { result := "" result += fmt.Sprintf("当前学习总积分:%d 今日得分:%d\n", score.TodayScore, score.TodayScore) result += fmt.Sprintf("登录:%v/%v 文章学习:%v/%v 视频学习:%v/%v 视频时长:%v/%v\n每日答题:%v/%v 每周答题:%v/%v 专项答题:%v/%v", @@ -108,6 +127,5 @@ func PrintScore(score Score) string { score.Content["weekly"].CurrentScore, score.Content["weekly"].MaxScore, score.Content["special"].CurrentScore, score.Content["special"].MaxScore, ) - log.Infoln(result) return result } diff --git a/lib/study.go b/lib/study.go index eabc2a8..44d3655 100644 --- a/lib/study.go +++ b/lib/study.go @@ -201,13 +201,6 @@ func (c *Core) LearnVideo(cookies []Cookie) { return } tryCount := 0 - networkCookies, err := (*c.context).Cookies() - if err != nil { - return - } - for _, networkCookie := range networkCookies { - fmt.Println(networkCookie.Name) - } for { if tryCount < 20 { diff --git a/lib/tg.go b/lib/tg.go new file mode 100644 index 0000000..9479029 --- /dev/null +++ b/lib/tg.go @@ -0,0 +1,252 @@ +package lib + +import ( + "encoding/base64" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "sync" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" + log "github.com/sirupsen/logrus" +) + +var ( + handles sync.Map +) + +func init() { + newPlugin("/login", login) + newPlugin("/get_users", getAllUser) + newPlugin("/study", study) + newPlugin("/get_scores", getScores) +} + +//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() { + uri, err := url.Parse(t.Proxy) + 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)) + + go func() { + for { + update := <-channel + 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 { + + } + }() + (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: "获取用户成绩"}, + )) + 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) { + msg := tgbotapi.NewMessage(t.ChatId, message) + t.bot.Send(msg) +} + +func login(bot *Telegram, args []string) { + log.Infoln(args) + go func() { + defer func() { + err := recover() + if err != nil { + log.Errorln(err) + } + }() + core := Core{ + pw: nil, + browser: nil, + context: nil, + ShowBrowser: false, + Push: func(kind string, message string) { + if kind == "image" { + bytes, _ := base64.StdEncoding.DecodeString(message) + bot.SendPhoto(bytes) + } else if kind == "markdown" { + newMessage := tgbotapi.NewMessage(bot.ChatId, message) + newMessage.ParseMode = tgbotapi.ModeMarkdownV2 + bot.bot.Send(newMessage) + } else { + bot.SendMsg(message) + } + }, + } + core.Init() + defer core.Quit() + _, err := core.Login() + if err != nil { + bot.SendMsg(err.Error()) + return + } + bot.SendMsg("登录成功") + }() +} + +func getAllUser(bot *Telegram, args []string) { + users, err := GetUsers() + 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 study(bot *Telegram, args []string) { + users, err := GetUsers() + if err != nil { + bot.SendMsg(err.Error()) + return + } + var cookies []Cookie + if len(users) == 1 { + bot.SendMsg("仅存在一名用户信息,自动进行学习") + cookies = users[0].Cookies + } else if len(users) == 0 { + bot.SendMsg("未发现用户信息,请输入/login进行用户登录") + return + } else { + if len(args) < 0 { + bot.SendMsg("存在多名用户,未输入用户序号") + return + } else { + i, err := strconv.Atoi(args[0]) + if err != nil { + bot.SendMsg(err.Error()) + return + } + cookies = users[i].Cookies + } + } + core := Core{ + pw: nil, + browser: nil, + context: nil, + ShowBrowser: false, + 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) + } + }, + } + defer core.Quit() + core.LearnArticle(cookies) + core.LearnVideo(cookies) + core.RespondDaily(cookies, "daily") + core.RespondDaily(cookies, "daily") + core.RespondDaily(cookies, "weekly") + core.RespondDaily(cookies, "special") +} + +func getScores(bot *Telegram, args []string) { + users, err := GetUsers() + 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.Cookies) + if err != nil { + message += err.Error() + "\n" + } + message += PrintScore(score) + "\n" + } + bot.SendMsg(message) +} diff --git a/main.go b/main.go index f200f1a..0fe448f 100644 --- a/main.go +++ b/main.go @@ -48,7 +48,9 @@ func init() { } func main() { - if config.Cron != "" { + switch { + case config.Cron != "": + log.Infoln("已采用定时执行模式") c := cron.New() _, err := c.AddFunc(config.Cron, func() { defer func() { @@ -66,30 +68,43 @@ func main() { } c.Start() select {} + case config.TG.Enable: + log.Infoln("已采用tg交互模式") + telegram := lib.Telegram{ + Token: config.TG.Token, + ChatId: config.TG.ChatID, + Proxy: config.TG.Proxy, + } + telegram.Init() + select {} + default: + log.Infoln("已采用普通学习模式") + do() } - do() } func do() { - log.Infoln(`// 刷课模式,默认为1, + log.Infoln(` 刷课模式,默认为1, 1:只刷文章何视频 2:只刷文章和视频和每日答题 3:刷文章和视频和每日答题每周答题和专项答题`) log.Infoln("检测到模式", config.Model) + getPush := push.GetPush(config) core := lib.Core{ShowBrowser: config.ShowBrowser, Push: getPush} defer core.Quit() core.Init() var cookies []lib.Cookie users, _ := lib.GetUsers() - if len(users) < 1 { + switch { + case len(users) < 1: log.Infoln("未检测到有效用户信息,将采用登录模式") cookies, _ = core.Login() - } else if len(users) == 1 { + case len(users) == 1: log.Infoln("检测到1位有效用户信息,采用默认用户") cookies = users[0].Cookies log.Infoln("已选择用户: ", users[0].Nick) - } else { + default: for i, user := range users { log.Infoln("序号:", i+1, " ===> ", user.Nick) } diff --git a/push/push.go b/push/push.go index 322bdc5..e627427 100644 --- a/push/push.go +++ b/push/push.go @@ -14,13 +14,6 @@ func GetPush(config lib.Config) func(kind string, message string) { } log.Infoln("已配置钉钉推送") return ding.Send() - } else if config.Push.TG.Enable { - t := &Telegram{ - Token: config.Push.TG.Token, - ChatId: config.Push.TG.ChatID, - } - log.Infoln("已配置telegram推送") - return t.Init() } else if config.Push.PushPlus.Enable { log.Infoln("已配置pushplus推送") return (&PushPlus{Token: config.Push.PushPlus.Token}).Init() diff --git a/push/tg.go b/push/tg.go deleted file mode 100644 index a2b5410..0000000 --- a/push/tg.go +++ /dev/null @@ -1,75 +0,0 @@ -package push - -import ( - "encoding/base64" - "net/http" - "net/url" - "strconv" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - log "github.com/sirupsen/logrus" -) - -//Telegram -// @Description: -// -type Telegram struct { - Token string - ChatId string -} - -//TGMsg -// @Description: -// -type TGMsg struct { - ChatID string `json:"chat_id"` - Text string `json:"text"` - ParseMode string `json:"parse_mode"` -} - -//Init -/** - * @Description: - * @receiver t - * @return func(kind string, message string) - */ -func (t *Telegram) Init() func(kind string, message string) { - uri, err := url.Parse("http://127.0.0.1:7890") - bot, err := tgbotapi.NewBotAPIWithClient(t.Token, tgbotapi.APIEndpoint, &http.Client{Transport: &http.Transport{ - // 设置代理 - Proxy: http.ProxyURL(uri), - }}) - - if err != nil { - log.Errorln("telegram token鉴权失败") - return func(kind string, message string) {} - } - chatId, err := strconv.ParseInt(t.ChatId, 10, 64) - if err != nil { - return func(kind string, message string) {} - } - return func(kind string, message string) { - if kind == "image" { - bytes, _ := base64.StdEncoding.DecodeString(message) - photo := tgbotapi.NewPhoto(chatId, tgbotapi.FileBytes{ - Name: "123", - Bytes: bytes, - }) - _, err := bot.Send(photo) - if err != nil { - log.Errorln("发送图片信息失败") - log.Errorln(err.Error()) - return - } - } - - mess := tgbotapi.NewMessage(chatId, message) - mess.ParseMode = tgbotapi.ModeMarkdownV2 - _, err := bot.Send(mess) - if err != nil { - log.Errorln("发送消息失败") - log.Errorln(err.Error()) - return - } - } -}