From 667c9fbcca8770303974b2c870b0abb2d700ab3b Mon Sep 17 00:00:00 2001 From: himawari <54976075+guohuiyuan@users.noreply.github.com> Date: Mon, 17 Apr 2023 11:23:37 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E6=8D=AE?= =?UTF-8?q?=E6=84=8F=E6=9F=A5=E5=8F=A5=20(#660)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +- main.go | 7 +- plugin/wantquotes/wantquotes.go | 203 ++++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 plugin/wantquotes/wantquotes.go diff --git a/README.md b/README.md index c85f4c8e..cd4a0387 100644 --- a/README.md +++ b/README.md @@ -1386,7 +1386,17 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 来份网易云热评 - + +
+ 据意查句 + + `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes"` + + - [x] 据意查句 大海 + + - [x] 登录据意查句 + +
星际战甲 diff --git a/main.go b/main.go index 2086330e..dd83f089 100644 --- a/main.go +++ b/main.go @@ -142,6 +142,7 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic" // vtb点歌 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评 + _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图 @@ -257,6 +258,9 @@ func init() { // sus = append(sus, 12345678) // sus = append(sus, 87654321) + // 启用 webui + // go webctrl.RunGui(*g) + if *runcfg != "" { f, err := os.Open(*runcfg) if err != nil { @@ -302,9 +306,6 @@ func init() { logrus.Infoln("[main] 配置文件已保存到", *save) os.Exit(0) } - - // 启用 webui - // go webctrl.RunGui(*g) } func main() { diff --git a/plugin/wantquotes/wantquotes.go b/plugin/wantquotes/wantquotes.go new file mode 100644 index 00000000..25cb0361 --- /dev/null +++ b/plugin/wantquotes/wantquotes.go @@ -0,0 +1,203 @@ +// Package wantquotes 据意查句 +package wantquotes + +import ( + "encoding/json" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "github.com/FloatTech/floatbox/binary" + "github.com/FloatTech/floatbox/web" + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" + "github.com/FloatTech/zbputils/img/text" + "github.com/sirupsen/logrus" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +const ( + wantquotesURL = "https://wantquotes.net" + getQrcode = "/api/get_qrcode/" + showqrcode = "https://mp.weixin.qq.com/cgi-bin/showqrcode" + loginCheck = "/api/login_check/" + semantic = "/api/semantic/" + semanticURL = wantquotesURL + semantic + "?query=%s&type=%s&unionid=%s&secret=%s" +) + +var ( + typeList = [...]string{"现", "现-名言", "现-佳句", "现-佳句-文学", "现-佳句-诗歌", "现-佳句-其他", "现-网络", "现-台词", "现-台词-影视剧", "现-台词-动漫", "现-台词-综艺", + "古", "谚", "谚-谚语", "谚-俗语", "谚-惯用语", "歇"} +) + +type getQrcodeRsp struct { + Ticket string `json:"ticket"` + SceneID string `json:"scene_id"` +} + +type loginCheckRsp struct { + Login int `json:"login"` + Secret string `json:"secret"` + Unionid string `json:"unionid"` +} + +type semanticRsp struct { + Quotes []Quotes `json:"quotes"` + TopSim float64 `json:"top_sim"` +} + +// Quotes 名句结构体 +type Quotes struct { + Quote string `json:"quote"` + SourceType string `json:"source_type"` + Author string `json:"author"` + Work string `json:"work"` + ID int `json:"id"` +} + +func init() { + engine := control.Register("wantquotes", &ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Extra: control.ExtraFromString("wantquotes"), + Brief: "据意查句", + Help: "- 据意查句 大海 (需登录据意查句)\n" + + "- 登录据意查句", + PrivateDataFolder: "wantquotes", + }) + + // 开启 + engine.OnRegex(`^据意查句\s?(.{1,25})$`, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { + keyword := ctx.State["regex_matched"].([]string)[1] + quotesType := ctx.State["quotesType"].(string) + var key string + manager := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + err := manager.GetExtra(&key) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + logrus.Debugln("[wantquotes] get api key:", key) + unionid, secret, _ := strings.Cut(key, "|") + apiURL := fmt.Sprintf(semanticURL, url.QueryEscape(keyword), url.QueryEscape(quotesType), url.QueryEscape(unionid), url.QueryEscape(secret)) + data, err := web.RequestDataWith(web.NewDefaultClient(), apiURL, "GET", wantquotesURL, web.RandUA(), nil) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + var rsp semanticRsp + err = json.Unmarshal(data, &rsp) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + m := make(message.Message, 0, len(rsp.Quotes)) + text := strings.Builder{} + for _, v := range rsp.Quotes { + text.WriteString(v.Quote) + text.WriteString("\n—— ") + text.WriteString(v.Author) + text.WriteString(" 《") + text.WriteString(v.Work) + text.WriteString("》") + m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String()))) + text.Reset() + } + if id := ctx.Send(m).ID(); id == 0 { + ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待")) + } + }) + engine.OnFullMatch(`登录据意查句`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + getQrcodeData, err := web.RequestDataWith(web.NewDefaultClient(), wantquotesURL+getQrcode, "GET", wantquotesURL, web.RandUA(), nil) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + var qrRsp getQrcodeRsp + err = json.Unmarshal(getQrcodeData, &qrRsp) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + showQrcodeData, err := web.RequestDataWith(web.NewDefaultClient(), showqrcode+"?ticket="+qrRsp.Ticket, "GET", "", web.RandUA(), nil) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + ctx.SendChain(message.Text("WantQuotes\n微信扫码登录\n首次登录需关注公众号")) + ctx.SendChain(message.ImageBytes(showQrcodeData)) + + ticker := time.NewTicker(2 * time.Second) // 创建每秒触发一次的定时器 + defer ticker.Stop() + count := 0 + for range ticker.C { + count++ + if count == 60 { + ctx.SendChain(message.Text("据意查句登录超时,请重新登录")) + return + } + loginCheckData, err := web.RequestDataWith(web.NewDefaultClient(), wantquotesURL+loginCheck+"?scene_id="+qrRsp.SceneID, "GET", "", web.RandUA(), nil) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + var lcr loginCheckRsp + err = json.Unmarshal(loginCheckData, &lcr) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + if lcr.Login == 1 { + manager := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + err := manager.SetExtra(lcr.Unionid + "|" + lcr.Secret) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + ctx.SendChain(message.Text("据意查句登录成功")) + return + } + } + }) +} + +func getPara(ctx *zero.Ctx) bool { + next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession()) + recv, cancel := next.Repeat() + defer cancel() + tex := strings.Builder{} + tex.WriteString("请下列选择查询名句的类型\n") + for i, v := range typeList { + tex.WriteString(strconv.Itoa(i)) + tex.WriteString(". ") + tex.WriteString(v) + tex.WriteString("\n") + } + base64Str, err := text.RenderToBase64(tex.String(), text.FontFile, 400, 20) + if err != nil { + ctx.SendChain(message.Text("图片生成错误了, ", zero.BotConfig.NickName[0], "帮你选择查询名句类型")) + ctx.State["quotesType"] = typeList[0] + return true + } + ctx.SendChain(message.Image("base64://" + binary.BytesToString(base64Str))) + for { + select { + case <-time.After(time.Second * 10): + ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询名句类型")) + ctx.State["quotesType"] = typeList[0] + return true + case c := <-recv: + msg := c.Event.Message.ExtractPlainText() + num, _ := strconv.Atoi(msg) + if num < 0 || num >= len(typeList) { + ctx.SendChain(message.Text("序号非法!")) + continue + } + ctx.State["quotesType"] = typeList[num] + return true + } + } +}