From ed26d31326e5f830c9bb3ff5ea182bf6a0973383 Mon Sep 17 00:00:00 2001 From: Jiang-Red <79574799+Jiang-Red@users.noreply.github.com> Date: Tue, 4 Apr 2023 23:32:29 +0800 Subject: [PATCH] add: score new style (#655) * newstyle * make lint happy --- go.mod | 4 +- go.sum | 4 +- plugin/score/draw.go | 219 ++++++++++++++++++++++++++++++++++++++++ plugin/score/sign_in.go | 119 +++++++++++----------- 4 files changed, 280 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index 00237f42..bd027998 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Baidu-AIP/golang-sdk v1.1.1 github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944 - github.com/FloatTech/gg v1.1.2 + github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08 github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 github.com/FloatTech/sqlite v1.5.7 @@ -24,7 +24,6 @@ require ( github.com/fumiama/go-base16384 v1.6.4 github.com/fumiama/go-registry v0.2.6 github.com/fumiama/gotracemoe v0.0.3 - github.com/fumiama/imgsz v0.0.2 github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 @@ -52,6 +51,7 @@ require ( github.com/faiface/beep v1.1.0 // indirect github.com/fumiama/go-simple-protobuf v0.1.0 // indirect github.com/fumiama/gofastTEA v0.0.10 // indirect + github.com/fumiama/imgsz v0.0.2 // indirect github.com/gabriel-vasile/mimetype v1.0.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect diff --git a/go.sum b/go.sum index 6e274944..0acaa553 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e h1:4V7UZyLZKm github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e/go.mod h1:LSJN8VkJXBhyAdOolVNeUptJz6l1TZ+/CfXN1OafyEY= github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944 h1:/eQoMa6Aj3coF5F7yhzZe1+SzX6SItul7MW8//pl18o= github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944/go.mod h1:FwQm6wk+b4wuW54KCKn3zccMX47Q5apnHD/Yakzv0fI= -github.com/FloatTech/gg v1.1.2 h1:YolgOYg3uDHc1+g0bLtt6QuRA/pvLn+b9IBCIhOOX88= -github.com/FloatTech/gg v1.1.2/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI= +github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08 h1:dPLeoiTVSBlgls+66EB/UJ2e38BaASmBN5nANaycSBU= +github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI= github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b h1:VMNci4SWBySdw/6poqF9Dn9zlT5ntTFSJOEEBjRnJ/4= github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs= github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 h1:hffajvmQFfP68U6wUwHemPuuwCUoss+SEFfoLYwbGwE= diff --git a/plugin/score/draw.go b/plugin/score/draw.go index f1c724ae..4709e549 100644 --- a/plugin/score/draw.go +++ b/plugin/score/draw.go @@ -3,15 +3,18 @@ package score import ( "bytes" + "errors" "fmt" "image" "image/color" "strconv" + "sync" "time" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/gg" "github.com/FloatTech/imgfactory" + "github.com/FloatTech/rendercard" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/img/text" "github.com/disintegration/imaging" @@ -269,3 +272,219 @@ func drawScore17(a *scdata) (image.Image, error) { canvas.SetRGB255(255, 255, 255) return canvas.Image(), nil } + +func drawScore17b2(a *scdata) (img image.Image, err error) { + fontdata, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, false) + if err != nil { + return + } + + getAvatar, err := initPic(a.picfile, a.uid) + if err != nil { + return + } + + back, err := gg.LoadImage(a.picfile) + if err != nil { + return + } + + bx, by := float64(back.Bounds().Dx()), float64(back.Bounds().Dy()) + + sc := 1280 / bx + + colors := gg.TakeColor(back, 3) + + canvas := gg.NewContext(1280, 1280*int(by)/int(bx)) + + cw, ch := float64(canvas.W()), float64(canvas.H()) + + sch := ch * 6 / 10 + + var blurback, scbackimg, backshadowimg, avatarimg, avatarbackimg, avatarshadowimg, whitetext, blacktext image.Image + var wg sync.WaitGroup + wg.Add(8) + + go func() { + defer wg.Done() + scback := gg.NewContext(canvas.W(), canvas.H()) + scback.ScaleAbout(sc, sc, cw/2, ch/2) + scback.DrawImageAnchored(back, canvas.W()/2, canvas.H()/2, 0.5, 0.5) + scback.Identity() + + go func() { + defer wg.Done() + blurback = imaging.Blur(scback.Image(), 20) + }() + + scbackimg = rendercard.Fillet(scback.Image(), 12) + }() + + go func() { + defer wg.Done() + pureblack := gg.NewContext(canvas.W(), canvas.H()) + pureblack.SetRGBA255(0, 0, 0, 255) + pureblack.Clear() + + shadow := gg.NewContext(canvas.W(), canvas.H()) + shadow.ScaleAbout(0.6, 0.6, cw-cw/3, ch/2) + shadow.DrawImageAnchored(pureblack.Image(), canvas.W()-canvas.W()/3, canvas.H()/2, 0.5, 0.5) + shadow.Identity() + + backshadowimg = imaging.Blur(shadow.Image(), 8) + }() + + aw, ah := (ch-sch)/2/2/2*3, (ch-sch)/2/2/2*3 + + go func() { + defer wg.Done() + avatar, _, err := image.Decode(bytes.NewReader(getAvatar)) + if err != nil { + return + } + + isc := (ch - sch) / 2 / 2 / 2 * 3 / float64(avatar.Bounds().Dy()) + + scavatar := gg.NewContext(int(aw), int(ah)) + + scavatar.ScaleAbout(isc, isc, aw/2, ah/2) + scavatar.DrawImageAnchored(avatar, scavatar.W()/2, scavatar.H()/2, 0.5, 0.5) + scavatar.Identity() + + avatarimg = rendercard.Fillet(scavatar.Image(), 8) + }() + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2) + if err != nil { + return + } + namew, _ := canvas.MeasureString(a.nickname) + + go func() { + defer wg.Done() + avatarshadowimg = imaging.Blur(customrectangle(cw, ch, aw, ah, namew, color.Black), 8) + }() + + go func() { + defer wg.Done() + avatarbackimg = customrectangle(cw, ch, aw, ah, namew, colors[0]) + }() + + go func() { + defer wg.Done() + whitetext, err = customtext(a, fontdata, cw, ch, aw, color.White) + if err != nil { + return + } + }() + + go func() { + defer wg.Done() + blacktext, err = customtext(a, fontdata, cw, ch, aw, color.Black) + if err != nil { + return + } + }() + + wg.Wait() + if scbackimg == nil || backshadowimg == nil || avatarimg == nil || avatarbackimg == nil || avatarshadowimg == nil || whitetext == nil || blacktext == nil { + err = errors.New("图片渲染失败") + return + } + + canvas.DrawImageAnchored(blurback, canvas.W()/2, canvas.H()/2, 0.5, 0.5) + + canvas.DrawImage(backshadowimg, 0, 0) + + canvas.ScaleAbout(0.6, 0.6, cw-cw/3, ch/2) + canvas.DrawImageAnchored(scbackimg, canvas.W()-canvas.W()/3, canvas.H()/2, 0.5, 0.5) + canvas.Identity() + + canvas.DrawImage(avatarshadowimg, 0, 0) + canvas.DrawImage(avatarbackimg, 0, 0) + canvas.DrawImageAnchored(avatarimg, int((ch-sch)/2/2), int((ch-sch)/2/2), 0.5, 0.5) + + canvas.DrawImage(blacktext, 2, 2) + canvas.DrawImage(whitetext, 0, 0) + + img = canvas.Image() + return +} + +func customrectangle(cw, ch, aw, ah, namew float64, rtgcolor color.Color) (img image.Image) { + canvas := gg.NewContext(int(cw), int(ch)) + sch := ch * 6 / 10 + canvas.DrawRoundedRectangle((ch-sch)/2/2-aw/2-aw/40, (ch-sch)/2/2-aw/2-ah/40, aw+aw/40*2, ah+ah/40*2, 8) + canvas.SetColor(rtgcolor) + canvas.Fill() + canvas.DrawRoundedRectangle((ch-sch)/2/2, (ch-sch)/2/2-ah/4, aw/2+aw/40*5+namew, ah/2, 8) + canvas.Fill() + + img = canvas.Image() + return +} + +func customtext(a *scdata, fontdata []byte, cw, ch, aw float64, textcolor color.Color) (img image.Image, err error) { + canvas := gg.NewContext(int(cw), int(ch)) + canvas.SetColor(textcolor) + scw, sch := cw*6/10, ch*6/10 + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2) + if err != nil { + return + } + canvas.DrawStringAnchored(a.nickname, (ch-sch)/2/2+aw/2+aw/40*2, (ch-sch)/2/2, 0, 0.5) + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/3*2) + if err != nil { + return + } + canvas.DrawStringAnchored(time.Now().Format("2006/01/02"), cw-cw/6, ch/2-sch/2-canvas.FontHeight(), 0.5, 0.5) + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2) + if err != nil { + return + } + nextrankScore := 0 + if a.rank < 10 { + nextrankScore = rankArray[a.rank+1] + } else { + nextrankScore = SCOREMAX + } + nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore) + + canvas.DrawStringAnchored("Level "+strconv.Itoa(a.rank), cw/3*2-scw/2, ch/2+sch/2+canvas.FontHeight(), 0, 0.5) + canvas.DrawStringAnchored(nextLevelStyle, cw/3*2+scw/2, ch/2+sch/2+canvas.FontHeight(), 1, 0.5) + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/3) + if err != nil { + return + } + + canvas.DrawStringAnchored("Create By ZeroBot-Plugin "+banner.Version, 0+4, ch, 0, -0.5) + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/5*3) + if err != nil { + return + } + + tempfh := canvas.FontHeight() + + canvas.DrawStringAnchored(getHourWord(time.Now()), ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4, 0, 0.5) + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/5) + if err != nil { + return + } + + canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4+tempfh, 0, 0.5) + canvas.DrawStringAnchored("EXP + 1", ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4+tempfh+canvas.FontHeight(), 0, 1) + + err = canvas.ParseFontFace(fontdata, (ch-sch)/2/4) + if err != nil { + return + } + + canvas.DrawStringAnchored("你有 "+strconv.Itoa(a.score)+" 枚ATRI币", ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4*3, 0, 0.5) + + img = canvas.Image() + return +} diff --git a/plugin/score/sign_in.go b/plugin/score/sign_in.go index 02ea2024..8ce971a8 100644 --- a/plugin/score/sign_in.go +++ b/plugin/score/sign_in.go @@ -7,6 +7,7 @@ import ( "math/rand" "os" "strconv" + "strings" "time" "github.com/FloatTech/AnimeAPI/bilibili" @@ -54,37 +55,53 @@ var ( } return true }) + stylemap = map[string]func(a *scdata) (image.Image, error){ + "1": drawScore15, + "2": drawScore16, + "3": drawScore17, + "4": drawScore17b2, + } ) func init() { cachePath := engine.DataFolder() + "cache/" go func() { - _ = os.RemoveAll(cachePath) - err := os.MkdirAll(cachePath, 0755) - if err != nil { - panic(err) + ok := file.IsExist(cachePath) + if !ok { + err := os.MkdirAll(cachePath, 0777) + if err != nil { + panic(err) + } + return + } + files, err := os.ReadDir(cachePath) + if err == nil { + for _, f := range files { + if !strings.Contains(f.Name(), time.Now().Format("20060102")) { + _ = os.Remove(cachePath + f.Name()) + } + } } sdb = initialize(engine.DataFolder() + "score.db") }() engine.OnRegex(`^签到\s?(\d*)$`, initDef).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) { // 选择key - var key string + key := ctx.State["regex_matched"].([]string)[1] gid := ctx.Event.GroupID if gid < 0 { // 个人用户设为负数 gid = -ctx.Event.UserID } - if ctx.State["regex_matched"].([]string)[1] != "" { - key = ctx.State["regex_matched"].([]string)[1] - } else { + if key == "" { m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) _ = m.Manager.GetExtra(gid, &key) if key == "" { _ = m.Manager.GetExtra(defKeyID, &key) } } - if !isExist(key) { - ctx.SendChain(message.Text("未找到签到设定:", key)) // 避免签到配置错误造成无图发送,但是已经签到的情况 + drawfunc, ok := stylemap[key] + if !ok { + ctx.SendChain(message.Text("ERROR: 未找到签到设定: ", key)) return } uid := ctx.Event.UserID @@ -131,12 +148,14 @@ func init() { // 更新钱包 rank := getrank(level) add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高 - err = wallet.InsertWalletOf(uid, add) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - alldata := scdata{ + go func() { + err = wallet.InsertWalletOf(uid, add) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + }() + alldata := &scdata{ drawedfile: drawedFile, picfile: picFile, uid: uid, @@ -146,28 +165,9 @@ func init() { level: level, rank: rank, } - var drawimage image.Image - switch key { - case "1": - drawimage, err = drawScore16(&alldata) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - case "2": - drawimage, err = drawScore15(&alldata) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - case "3": - drawimage, err = drawScore17(&alldata) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - default: - ctx.SendChain(message.Text("未添加签到设定:", key)) + drawimage, err := drawfunc(alldata) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) return } // done. @@ -182,7 +182,7 @@ func init() { return } _, err = imgfactory.WriteTo(drawimage, f) - _ = f.Close() + defer f.Close() if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return @@ -204,7 +204,9 @@ func init() { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请先签到!")) return } - ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile)) + if id := ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile)); id.ID() == 0 { + ctx.SendChain(message.Text("ERROR: 消息发送失败, 账号可能被风控")) + } }) engine.OnFullMatch("查看等级排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true). Handle(func(ctx *zero.Ctx) { @@ -279,13 +281,13 @@ func init() { ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile)) }) engine.OnRegex(`^设置(默认)?签到预设\s?(\d*)$`, zero.SuperUserPermission).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) { - if ctx.State["regex_matched"].([]string)[2] == "" { - ctx.SendChain(message.Text("设置失败,数据为空")) + if key := ctx.State["regex_matched"].([]string)[2]; key == "" { + ctx.SendChain(message.Text("设置失败, 数据为空")) } else { s := ctx.State["regex_matched"].([]string)[1] - key := ctx.State["regex_matched"].([]string)[2] - if !isExist(key) { - ctx.SendChain(message.Text("未找到签到设定:", key)) // 避免签到配置错误 + _, ok := stylemap[key] + if !ok { + ctx.SendChain(message.Text("ERROR: 未找到签到设定: ", key)) // 避免签到配置错误 return } gid := ctx.Event.GroupID @@ -300,7 +302,7 @@ func init() { ctx.SendChain(message.Text("ERROR: ", err)) return } - ctx.SendChain(message.Text("设置成功,当前", s, "预设为:", key)) + ctx.SendChain(message.Text("设置成功, 当前", s, "预设为:", key)) } }) } @@ -335,28 +337,21 @@ func getrank(count int) int { } func initPic(picFile string, uid int64) (avatar []byte, err error) { - if file.IsExist(picFile) { - return nil, nil - } defer process.SleepAbout1sTo2s() + avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640") + if err != nil { + return + } + if file.IsExist(picFile) { + return + } url, err := bilibili.GetRealURL(backgroundURL) if err != nil { - return nil, err + return } data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil) if err != nil { - return nil, err - } - avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640") - if err != nil { - return nil, err + return } return avatar, os.WriteFile(picFile, data, 0644) } - -func isExist(key string) bool { - if key != "1" && key != "2" && key != "3" { - return false - } - return true -}