diff --git a/go.mod b/go.mod index 9b4125dd9b..2151dc4915 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/Coloured-glaze/gg v1.3.4 github.com/FloatTech/AnimeAPI v1.6.1-0.20230130095520-be357484e5a7 github.com/FloatTech/floatbox v0.0.0-20230130095057-3d1da721425e + github.com/FloatTech/rendercard v0.0.8 github.com/FloatTech/sqlite v1.5.7 github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52 @@ -16,6 +17,7 @@ require ( github.com/antchfx/htmlquery v1.2.5 github.com/corona10/goimagehash v1.1.0 github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3 + github.com/disintegration/imaging v1.6.2 github.com/fumiama/ahsai v0.1.0 github.com/fumiama/cron v1.3.0 github.com/fumiama/go-base16384 v1.6.4 @@ -30,20 +32,20 @@ require ( github.com/mroth/weightedrand v1.0.0 github.com/pkg/errors v0.9.1 github.com/quic-go/quic-go v0.32.0 - github.com/shirou/gopsutil/v3 v3.22.11 + github.com/shirou/gopsutil/v3 v3.23.1 github.com/sirupsen/logrus v1.9.0 github.com/tidwall/gjson v1.14.4 github.com/wcharczuk/go-chart/v2 v2.1.0 github.com/wdvxdr1123/ZeroBot v1.6.8 gitlab.com/gomidi/midi/v2 v2.0.25 golang.org/x/image v0.3.0 + golang.org/x/text v0.6.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/FloatTech/rendercard v0.0.8 // indirect + github.com/FloatTech/gg v1.0.0 github.com/antchfx/xpath v1.2.1 // indirect - github.com/disintegration/imaging v1.6.2 // indirect github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect github.com/faiface/beep v1.1.0 // indirect github.com/fumiama/go-simple-protobuf v0.1.0 // indirect @@ -82,8 +84,7 @@ require ( golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect golang.org/x/mod v0.6.0 // indirect golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.6.0 // indirect + golang.org/x/sys v0.4.0 // indirect golang.org/x/tools v0.2.0 // indirect modernc.org/libc v1.21.5 // indirect modernc.org/mathutil v1.5.0 // indirect diff --git a/go.sum b/go.sum index ad77128090..62325ee957 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/FloatTech/AnimeAPI v1.6.1-0.20230130095520-be357484e5a7 h1:4FCjcjcsjU github.com/FloatTech/AnimeAPI v1.6.1-0.20230130095520-be357484e5a7/go.mod h1:LmHu358Oovtxhc/7xz+IfffUAMCX2bijpEvWatacEYQ= github.com/FloatTech/floatbox v0.0.0-20230130095057-3d1da721425e h1:RhKDmRNaBXK+lGY9FX+PAm75z03EHXp7y3/F2cZIv58= github.com/FloatTech/floatbox v0.0.0-20230130095057-3d1da721425e/go.mod h1:OoZE4Ra7olpFaJSrlD6mcyT4chPLg9QBRE1pzTC8R84= +github.com/FloatTech/gg v1.0.0 h1:Ydn2zHMah6WXD6Q/+OVvH8wuQEYmOj8ghloszgdRY5M= +github.com/FloatTech/gg v1.0.0/go.mod h1:tp7XIzGMl+SPiQyq9q5Gv/o0R09HM8KmbXExbvRIwjQ= github.com/FloatTech/rendercard v0.0.8 h1:IOZ757RKJGj4EAQj7XoW8iSNl6yVS98z0DK9LDup+Yo= github.com/FloatTech/rendercard v0.0.8/go.mod h1:hDqmlGgXBPI3QAvkE2kKjdPFAIB5cFQ55QnmXapAr3I= github.com/FloatTech/sqlite v1.5.7 h1:Bvo4LSojcZ6dVtbHrkqvt6z4v8e+sj0G5PSUIvdawsk= @@ -169,8 +171,8 @@ github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7t github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/shirou/gopsutil/v3 v3.22.11 h1:kxsPKS+Eeo+VnEQ2XCaGJepeP6KY53QoRTETx3+1ndM= -github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0XdevQOe5MZ1oY= +github.com/shirou/gopsutil/v3 v3.23.1 h1:a9KKO+kGLKEvcPIs4W62v0nu3sciVDOOOPUD0Hz7z/4= +github.com/shirou/gopsutil/v3 v3.23.1/go.mod h1:NN6mnm5/0k8jw4cBfCnJtr5L7ErOTg18tMNpgFkn0hA= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -268,8 +270,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/plugin/ai_false/ai_false.go b/plugin/ai_false/ai_false.go index e301380bd9..e34b3c3cc2 100644 --- a/plugin/ai_false/ai_false.go +++ b/plugin/ai_false/ai_false.go @@ -2,23 +2,49 @@ package aifalse import ( - "fmt" + "bytes" + "errors" + "image" "math" + "runtime" "strconv" + "strings" + "sync" "time" + "github.com/FloatTech/AnimeAPI/bilibili" + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/floatbox/web" + "github.com/FloatTech/gg" + "github.com/FloatTech/rendercard" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext" + "github.com/FloatTech/zbputils/img" + "github.com/FloatTech/zbputils/img/text" + "github.com/disintegration/imaging" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/mem" "github.com/sirupsen/logrus" + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "github.com/FloatTech/ZeroBot-Plugin/kanban" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" ) +const ( + backgroundURL = "https://iw233.cn/api.php?sort=mp" + referer = "https://weibo.com/" +) + +var boottime = time.Now() + func init() { // 插件主体 engine := control.Register("aifalse", &ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, @@ -39,12 +65,16 @@ func init() { // 插件主体 } engine.OnFullMatchGroup([]string{"检查身体", "自检", "启动自检", "系统状态"}, zero.AdminPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { - ctx.SendChain(message.Text( - "* CPU占用: ", cpuPercent(), "%\n", - "* RAM占用: ", memPercent(), "%\n", - "* 硬盘使用: ", diskPercent(), - ), - ) + img, err := drawstatus(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.Event.SelfID, zero.BotConfig.NickName[0]) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + sendimg, cl := writer.ToBytes(img) + if id := ctx.SendChain(message.ImageBytes(sendimg)); id.ID() == 0 { + ctx.SendChain(message.Text("ERROR: 可能被风控了")) + } + cl() }) engine.OnRegex(`^设置默认限速为每\s*(\d+)\s*(分钟|秒)\s*(\d+)\s*次触发$`, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { @@ -84,38 +114,479 @@ func init() { // 插件主体 }) } -func cpuPercent() float64 { - percent, err := cpu.Percent(time.Second, false) +func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg image.Image, err error) { + diskstate, err := diskstate() if err != nil { - return -1 + return } - return math.Round(percent[0]) + diskcardh := 40 + (20+50)*len(diskstate) + 40 - 20 + + moreinfo, err := moreinfo(m) + if err != nil { + return + } + moreinfocardh := 30 + (20+32*72/96)*len(moreinfo) + 30 - 20 + + basicstate, err := basicstate() + if err != nil { + return + } + + url, err := bilibili.GetRealURL(backgroundURL) + if err != nil { + return + } + data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil) + if err != nil { + return + } + back, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + return + } + + data, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640") + if err != nil { + return + } + avatar, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + return + } + avatarf := img.Size(avatar, 200, 200) + + fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true) + if err != nil { + return + } + + canvas := gg.NewContext(1280, 70+250+40+380+diskcardh+40+moreinfocardh+40+70) + + bh, bw, ch, cw := float64(back.Bounds().Dy()), float64(back.Bounds().Dx()), float64(canvas.H()), float64(canvas.W()) + + if bh/bw < ch/cw { + back = img.Size(back, int(bw*ch/bh), int(bh*ch/bh)).Im + canvas.DrawImageAnchored(back, canvas.W()/2, canvas.H()/2, 0.5, 0.5) + } else { + back = img.Size(back, int(bw*cw/bw), int(bh*cw/bw)).Im + canvas.DrawImage(back, 0, 0) + } + + wg := &sync.WaitGroup{} + wg.Add(5) + + cardw := canvas.W() - 70 - 70 + + titlecardh := 250 + basiccardh := 380 + + var titleimg, basicimg, diskimg, moreinfoimg, shadowimg image.Image + go func() { + defer wg.Done() + titlecard := gg.NewContext(cardw, titlecardh) + + titlecard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70) + + titlecard.DrawRoundedRectangle(1, 1, float64(titlecard.W()-1*2), float64(titlecardh-1*2), 16) + titlecard.SetLineWidth(3) + titlecard.SetRGBA255(255, 255, 255, 100) + titlecard.StrokePreserve() + titlecard.SetRGBA255(255, 255, 255, 140) + titlecard.Fill() + + titlecard.DrawImage(avatarf.Circle(0).Im, (titlecardh-avatarf.H)/2, (titlecardh-avatarf.H)/2) + + err = titlecard.LoadFontFace(fontbyte, 72) + if err != nil { + return + } + fw, _ := titlecard.MeasureString(botname) + + titlecard.SetRGBA255(30, 30, 30, 255) + + titlecard.DrawStringAnchored(botname, float64(titlecardh)+fw/2, float64(titlecardh)*0.5/2, 0.5, 0.5) + + err = titlecard.LoadFontFace(fontbyte, 24) + if err != nil { + return + } + titlecard.SetRGBA255(30, 30, 30, 180) + + titlecard.NewSubPath() + titlecard.MoveTo(float64(titlecardh), float64(titlecardh)/2) + titlecard.LineTo(float64(titlecard.W()-titlecardh), float64(titlecardh)/2) + titlecard.Stroke() + + brt, err := botruntime() + if err != nil { + return + } + fw, _ = titlecard.MeasureString(brt) + + titlecard.DrawStringAnchored(brt, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.25/2), 0.5, 0.5) + + bs, err := botstatus() + if err != nil { + return + } + fw, _ = titlecard.MeasureString(bs) + + titlecard.DrawStringAnchored(bs, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.5/2), 0.5, 0.5) + titleimg = rendercard.Fillet(titlecard.Image(), 16) + }() + go func() { + defer wg.Done() + basiccard := gg.NewContext(cardw, basiccardh) + + basiccard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40) + + basiccard.DrawRoundedRectangle(1, 1, float64(basiccard.W()-1*2), float64(basiccardh-1*2), 16) + basiccard.SetLineWidth(3) + basiccard.SetRGBA255(255, 255, 255, 100) + basiccard.StrokePreserve() + basiccard.SetRGBA255(255, 255, 255, 140) + basiccard.Fill() + + bslen := len(basicstate) + for i, v := range basicstate { + offset := float64(i) * ((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1) + 200) + + basiccard.SetRGBA255(235, 235, 235, 255) + basiccard.DrawCircle((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 100) + basiccard.Fill() + + switch { + case v.precent > 90: + basiccard.SetRGBA255(255, 70, 0, 255) + case v.precent > 70: + basiccard.SetRGBA255(255, 165, 0, 255) + default: + basiccard.SetRGBA255(145, 240, 145, 255) + } + + basiccard.NewSubPath() + basiccard.MoveTo((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2) + basiccard.DrawEllipticalArc((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 100, 100, -0.5*math.Pi, -0.5*math.Pi+2*v.precent*0.01*math.Pi) + basiccard.Fill() + + basiccard.SetRGBA255(255, 255, 255, 255) + basiccard.DrawCircle((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 80) + basiccard.Fill() + + err = basiccard.LoadFontFace(fontbyte, 42) + if err != nil { + return + } + + basiccard.SetRGBA255(213, 213, 213, 255) + basiccard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 0.5, 0.5) + + basiccard.SetRGBA255(30, 30, 30, 255) + _, fw := basiccard.MeasureString(v.name) + basiccard.DrawStringAnchored(v.name, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+basiccard.FontHeight()/2, 0.5, 0.5) + + err = basiccard.LoadFontFace(fontbyte, 20) + if err != nil { + return + } + basiccard.SetRGBA255(30, 30, 30, 180) + + textoffsety := basiccard.FontHeight() + 10 + for k, s := range v.text { + basiccard.DrawStringAnchored(s, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+fw+15+basiccard.FontHeight()/2+float64(k)*textoffsety, 0.5, 0.5) + } + } + basicimg = rendercard.Fillet(basiccard.Image(), 16) + }() + go func() { + defer wg.Done() + diskcard := gg.NewContext(cardw, diskcardh) + diskcard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40-basiccardh-40) + + diskcard.DrawRoundedRectangle(1, 1, float64(diskcard.W()-1*2), float64(basiccardh-1*2), 16) + diskcard.SetLineWidth(3) + diskcard.SetRGBA255(255, 255, 255, 100) + diskcard.StrokePreserve() + diskcard.SetRGBA255(255, 255, 255, 140) + diskcard.Fill() + + err = diskcard.LoadFontFace(fontbyte, 32) + if err != nil { + return + } + + dslen := len(diskstate) + if dslen == 1 { + diskcard.SetRGBA255(192, 192, 192, 255) + diskcard.DrawRoundedRectangle(40, 40, float64(diskcard.W())-40-100, 50, 12) + diskcard.Fill() + + switch { + case diskstate[0].precent > 90: + diskcard.SetRGBA255(255, 70, 0, 255) + case diskstate[0].precent > 70: + diskcard.SetRGBA255(255, 165, 0, 255) + default: + diskcard.SetRGBA255(145, 240, 145, 255) + } + + diskcard.DrawRoundedRectangle(40, 40, (float64(diskcard.W())-40-100)*diskstate[0].precent*0.01, 50, 12) + diskcard.Fill() + + diskcard.SetRGBA255(30, 30, 30, 255) + + fw, _ := diskcard.MeasureString(diskstate[0].name) + fw1, _ := diskcard.MeasureString(diskstate[0].text[0]) + + diskcard.DrawStringAnchored(diskstate[0].name, 40+10+fw/2, 40+50/2, 0.5, 0.5) + diskcard.DrawStringAnchored(diskstate[0].text[0], (float64(diskcard.W())-100-10)-fw1/2, 40+50/2, 0.5, 0.5) + diskcard.DrawStringAnchored(strconv.FormatFloat(diskstate[0].precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+50/2, 0.5, 0.5) + } else { + for i, v := range diskstate { + offset := float64(i)*(50+20) - 20 + + diskcard.SetRGBA255(192, 192, 192, 255) + diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, float64(diskcard.W())-40-100, 50, 12) + diskcard.Fill() + + switch { + case v.precent > 90: + diskcard.SetRGBA255(255, 70, 0, 255) + case v.precent > 70: + diskcard.SetRGBA255(255, 165, 0, 255) + default: + diskcard.SetRGBA255(145, 240, 145, 255) + } + + diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, (float64(diskcard.W())-40-100)*v.precent*0.01, 50, 12) + diskcard.Fill() + + diskcard.SetRGBA255(30, 30, 30, 255) + + fw, _ := diskcard.MeasureString(v.name) + fw1, _ := diskcard.MeasureString(v.text[0]) + + diskcard.DrawStringAnchored(v.name, 40+10+fw/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5) + diskcard.DrawStringAnchored(v.text[0], (float64(diskcard.W())-100-10)-fw1/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5) + diskcard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5) + } + } + diskimg = rendercard.Fillet(diskcard.Image(), 16) + }() + go func() { + defer wg.Done() + moreinfocard := gg.NewContext(cardw, moreinfocardh) + + moreinfocard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40-basiccardh-40-diskcardh-40) + + moreinfocard.DrawRoundedRectangle(1, 1, float64(moreinfocard.W()-1*2), float64(moreinfocard.H()-1*2), 16) + moreinfocard.SetLineWidth(3) + moreinfocard.SetRGBA255(255, 255, 255, 100) + moreinfocard.StrokePreserve() + moreinfocard.SetRGBA255(255, 255, 255, 140) + moreinfocard.Fill() + + err = moreinfocard.LoadFontFace(fontbyte, 32) + if err != nil { + return + } + + milen := len(moreinfo) + for i, v := range moreinfo { + offset := float64(i)*(20+moreinfocard.FontHeight()) - 20 + + moreinfocard.SetRGBA255(30, 30, 30, 255) + + fw, _ := moreinfocard.MeasureString(v.name) + fw1, _ := moreinfocard.MeasureString(v.text[0]) + + moreinfocard.DrawStringAnchored(v.name, 20+fw/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5) + moreinfocard.DrawStringAnchored(v.text[0], float64(moreinfocard.W())-20-fw1/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5) + } + moreinfoimg = rendercard.Fillet(moreinfocard.Image(), 16) + }() + go func() { + defer wg.Done() + shadow := gg.NewContext(canvas.W(), canvas.H()) + shadow.SetRGBA255(0, 0, 0, 100) + shadow.SetLineWidth(12) + shadow.DrawRoundedRectangle(70, 70, float64(cardw), float64(titlecardh), 16) + shadow.Stroke() + shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40), float64(cardw), float64(basiccardh), 16) + shadow.Stroke() + shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40), float64(cardw), float64(basiccardh), 16) + shadow.Stroke() + shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40+diskcardh+40), float64(cardw), float64(moreinfocardh), 16) + shadow.Stroke() + shadowimg = imaging.Blur(shadow.Image(), 24) + }() + + wg.Wait() + if shadowimg == nil || titleimg == nil || basicimg == nil || diskimg == nil || moreinfoimg == nil { + err = errors.New("图片渲染失败") + return + } + canvas.DrawImage(shadowimg, 0, 0) + canvas.DrawImage(titleimg, 70, 70) + canvas.DrawImage(basicimg, 70, 70+titlecardh+40) + canvas.DrawImage(diskimg, 70, 70+titlecardh+40+basiccardh+40) + canvas.DrawImage(moreinfoimg, 70, 70+titlecardh+40+basiccardh+40+diskcardh+40) + + err = canvas.LoadFontFace(fontbyte, 28) + if err != nil { + return + } + canvas.SetRGBA255(0, 0, 0, 255) + canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+kanban.Version, float64(canvas.W())/2+3, float64(canvas.H())-70/2+3, 0.5, 0.5) + canvas.SetRGBA255(255, 255, 255, 255) + canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+kanban.Version, float64(canvas.W())/2, float64(canvas.H())-70/2, 0.5, 0.5) + + sendimg = canvas.Image() + return } -func memPercent() float64 { - memInfo, err := mem.VirtualMemory() +func botruntime() (string, error) { + hostinfo, err := host.Info() if err != nil { - return -1 + return "", err } - return math.Round(memInfo.UsedPercent) + t := &strings.Builder{} + t.WriteString("ZeroBot-Plugin 已运行 ") + t.WriteString(strconv.FormatInt((time.Now().Unix()-boottime.Unix())/86400, 10)) + t.WriteString(" 天 ") + t.WriteString(time.Unix(time.Now().Unix()-boottime.Unix(), 0).UTC().Format("15:04:05")) + t.WriteString(" | 系统运行 ") + t.WriteString(strconv.FormatInt(int64(hostinfo.Uptime)/86400, 10)) + t.WriteString(" 天 ") + t.WriteString(time.Unix(int64(hostinfo.Uptime), 0).UTC().Format("15:04:05")) + return t.String(), nil } -func diskPercent() string { - parts, err := disk.Partitions(true) +func botstatus() (string, error) { + hostinfo, err := host.Info() if err != nil { - return err.Error() + return "", err } - msg := "" - for _, p := range parts { - diskInfo, err := disk.Usage(p.Mountpoint) + t := &strings.Builder{} + t.WriteString(time.Now().Format("2006-01-02 15:04:05")) + t.WriteString(" | Compiled by ") + t.WriteString(runtime.Version()) + t.WriteString(" | ") + t.WriteString(cases.Title(language.English).String(hostinfo.OS)) + return t.String(), nil +} + +type status struct { + precent float64 + name string + text []string +} + +func basicstate() (stateinfo [3]*status, err error) { + percent, err := cpu.Percent(time.Second, false) + if err != nil { + return + } + cpuinfo, err := cpu.Info() + if err != nil { + return + } + cores := strconv.Itoa(int(cpuinfo[0].Cores)) + " Core" + times := "最大 " + strconv.FormatFloat(cpuinfo[0].Mhz/1000, 'f', 1, 64) + "Ghz" + + stateinfo[0] = &status{ + precent: math.Round(percent[0]), + name: "CPU", + text: []string{cores, times}, + } + + raminfo, err := mem.VirtualMemory() + if err != nil { + return + } + total := "总共 " + storagefmt(float64(raminfo.Total)) + used := "已用 " + storagefmt(float64(raminfo.Used)) + free := "剩余 " + storagefmt(float64(raminfo.Free)) + + stateinfo[1] = &status{ + precent: math.Round(raminfo.UsedPercent), + name: "RAM", + text: []string{total, used, free}, + } + + swapinfo, err := mem.SwapMemory() + if err != nil { + return + } + total = "总共 " + storagefmt(float64(swapinfo.Total)) + used = "已用 " + storagefmt(float64(swapinfo.Used)) + free = "剩余 " + storagefmt(float64(swapinfo.Free)) + + stateinfo[2] = &status{ + precent: math.Round(swapinfo.UsedPercent), + name: "SWAP", + text: []string{total, used, free}, + } + return +} + +func storagefmt(num float64) string { + if num /= 1024; num < 1 { + return strconv.FormatFloat(num*1024, 'f', 2, 64) + "B" + } + if num /= 1024; num < 1 { + return strconv.FormatFloat(num*1024, 'f', 2, 64) + "KB" + } + if num /= 1024; num < 1 { + return strconv.FormatFloat(num*1024, 'f', 2, 64) + "MB" + } + if num /= 1024; num < 1 { + return strconv.FormatFloat(num*1024, 'f', 2, 64) + "GB" + } + return strconv.FormatFloat(num, 'f', 2, 64) + "TB" +} + +func diskstate() (stateinfo []*status, err error) { + parts, err := disk.Partitions(false) + if err != nil { + return + } + stateinfo = make([]*status, len(parts)) + for i, v := range parts { + mp := v.Mountpoint + diskusage, err := disk.Usage(mp) + usage := "" + precent := 0.0 if err != nil { - msg += "\n - " + err.Error() - continue + usage = err.Error() + } else { + usage = storagefmt(float64(diskusage.Used)) + " / " + storagefmt(float64(diskusage.Total)) + precent = math.Round(diskusage.UsedPercent) } - pc := uint(math.Round(diskInfo.UsedPercent)) - if pc > 0 { - msg += fmt.Sprintf("\n - %s(%dM) %d%%", p.Mountpoint, diskInfo.Total/1024/1024, pc) + stateinfo[i] = &status{ + precent: precent, + name: mp, + text: []string{usage}, } } - return msg + return stateinfo, nil +} + +func moreinfo(m *ctrl.Control[*zero.Ctx]) (stateinfo []*status, err error) { + hostinfo, err := host.Info() + if err != nil { + return + } + cpuinfo, err := cpu.Info() + if err != nil { + return + } + count := len(m.Manager.M) + stateinfo = []*status{ + {name: "OS", text: []string{hostinfo.Platform}}, + {name: "CPU", text: []string{cpuinfo[0].ModelName}}, + {name: "Version", text: []string{hostinfo.PlatformVersion}}, + {name: "Plugin", text: []string{"共 " + strconv.Itoa(count) + " 个"}}, + } + return } diff --git a/plugin/gif/gif.go b/plugin/gif/gif.go index f147eff6dc..e3b3b44d50 100644 --- a/plugin/gif/gif.go +++ b/plugin/gif/gif.go @@ -6,9 +6,9 @@ import ( "image/color" "sync" - "github.com/Coloured-glaze/gg" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/gg" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/img" "github.com/FloatTech/zbputils/img/text" diff --git a/plugin/gif/png.go b/plugin/gif/png.go index 9ecdd7fade..91f700cb61 100644 --- a/plugin/gif/png.go +++ b/plugin/gif/png.go @@ -8,9 +8,9 @@ import ( "strconv" "sync" - "github.com/Coloured-glaze/gg" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/gg" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/img" "github.com/FloatTech/zbputils/img/text" diff --git a/plugin/qqwife/command.go b/plugin/qqwife/command.go index 1274261a59..f17b7c5bdd 100644 --- a/plugin/qqwife/command.go +++ b/plugin/qqwife/command.go @@ -21,12 +21,11 @@ import ( // 数据库 sql "github.com/FloatTech/sqlite" // 画图 - "github.com/Coloured-glaze/gg" fcext "github.com/FloatTech/floatbox/ctxext" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/gg" "github.com/FloatTech/zbputils/img/text" - // 货币系统 ) type 婚姻登记 struct { diff --git a/plugin/qqwife/favorSystem.go b/plugin/qqwife/favorSystem.go index a4e16cb6c0..f7619481cb 100644 --- a/plugin/qqwife/favorSystem.go +++ b/plugin/qqwife/favorSystem.go @@ -14,9 +14,9 @@ import ( "github.com/wdvxdr1123/ZeroBot/message" // 画图 - "github.com/Coloured-glaze/gg" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/gg" "github.com/FloatTech/zbputils/img/text" // 货币系统 diff --git a/plugin/qzone/qzone.go b/plugin/qzone/qzone.go index 975b2d5ddf..f1c2a314db 100644 --- a/plugin/qzone/qzone.go +++ b/plugin/qzone/qzone.go @@ -12,11 +12,11 @@ import ( "strings" "time" - "github.com/Coloured-glaze/gg" "github.com/FloatTech/AnimeAPI/qzone" "github.com/FloatTech/floatbox/binary" "github.com/FloatTech/floatbox/img/writer" "github.com/FloatTech/floatbox/web" + "github.com/FloatTech/gg" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext" diff --git a/plugin/score/sign_in.go b/plugin/score/sign_in.go index bf633dd38c..16f965bc7b 100644 --- a/plugin/score/sign_in.go +++ b/plugin/score/sign_in.go @@ -9,13 +9,13 @@ import ( "strconv" "time" - "github.com/Coloured-glaze/gg" "github.com/FloatTech/AnimeAPI/bilibili" "github.com/FloatTech/AnimeAPI/wallet" "github.com/FloatTech/floatbox/file" "github.com/FloatTech/floatbox/img/writer" "github.com/FloatTech/floatbox/process" "github.com/FloatTech/floatbox/web" + "github.com/FloatTech/gg" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext" diff --git a/plugin/wordle/wordle.go b/plugin/wordle/wordle.go index 1818d8939b..8f4684961c 100644 --- a/plugin/wordle/wordle.go +++ b/plugin/wordle/wordle.go @@ -14,10 +14,10 @@ import ( "github.com/FloatTech/AnimeAPI/tl" - "github.com/Coloured-glaze/gg" "github.com/FloatTech/floatbox/binary" fcext "github.com/FloatTech/floatbox/ctxext" "github.com/FloatTech/floatbox/img/writer" + "github.com/FloatTech/gg" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext"