From f05f09d74136fd1c53b87eddcbc6607479076ac1 Mon Sep 17 00:00:00 2001 From: fumiama Date: Thu, 13 Jan 2022 16:43:50 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=B1=20=F0=9F=8E=A8=20=E2=9A=A1?= =?UTF-8?q?=EF=B8=8F=20=E8=BF=90=E5=8A=BF=20=E4=B8=8D=E8=A7=A3=E5=8E=8B=20?= =?UTF-8?q?=E4=B8=8D=E4=BC=A0=20base64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data | 2 +- plugin_fortune/fortune.go | 259 +++++++++++++++----------------------- 2 files changed, 103 insertions(+), 158 deletions(-) diff --git a/data b/data index 1349bd0d..64113f69 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 1349bd0d4a64daa5d5d76659a787a8594358b55b +Subproject commit 64113f69a74952a35f5c7432a2c0569188bb038c diff --git a/plugin_fortune/fortune.go b/plugin_fortune/fortune.go index 97376c94..ed181eeb 100644 --- a/plugin_fortune/fortune.go +++ b/plugin_fortune/fortune.go @@ -3,12 +3,11 @@ package fortune import ( "archive/zip" - "bytes" - "encoding/base64" + "crypto/md5" + "encoding/hex" "encoding/json" - "image/jpeg" + "image" "io" - "io/ioutil" "math/rand" "os" "strconv" @@ -24,13 +23,19 @@ import ( control "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/file" "github.com/FloatTech/zbputils/math" + "github.com/FloatTech/zbputils/process" + "github.com/FloatTech/zbputils/txt2img" ) var ( // 底图缓存位置 - base = "data/fortune/" - // 素材下载网站 - site = "https://pan.dihe.moe/fortune/" + images = "data/Fortune/" + // 基础文件位置 + omikujson = "data/Fortune/text.json" + // 字体文件位置 + font = "data/Font/sakura.ttf" + // 生成图缓存位置 + cache = images + "cache/" // 底图类型列表:车万 DC4 爱因斯坦 星空列车 樱云之恋 富婆妹 李清歌 // 公主连结 原神 明日方舟 碧蓝航线 碧蓝幻想 战双 阴阳师 table = [...]string{"车万", "DC4", "爱因斯坦", "星空列车", "樱云之恋", "富婆妹", "李清歌", "公主连结", "原神", "明日方舟", "碧蓝航线", "碧蓝幻想", "战双", "阴阳师"} @@ -38,13 +43,32 @@ var ( index = make(map[string]uint8) // 下载锁 dlmu sync.Mutex + // 签文 + omikujis []map[string]string ) func init() { for i, s := range table { index[s] = uint8(i) } - err := os.MkdirAll(base, 0755) + err := os.MkdirAll(images, 0755) + if err != nil { + panic(err) + } + err = os.MkdirAll(cache, 0755) + if err != nil { + panic(err) + } + process.SleepAbout1sTo2s() + data, err := file.GetLazyData(omikujson, true, false) + if err != nil { + panic(err) + } + err = json.Unmarshal(data, &omikujis) + if err != nil { + panic(err) + } + _, err = file.GetLazyData(font, false, true) if err != nil { panic(err) } @@ -81,38 +105,6 @@ func init() { }) en.OnFullMatchGroup([]string{"运势", "抽签"}).SetBlock(true).SecondPriority(). Handle(func(ctx *zero.Ctx) { - // 检查签文文件是否存在 - mikuji := base + "运势签文.json" - if file.IsNotExist(mikuji) { - dlmu.Lock() - if file.IsNotExist(mikuji) { - ctx.SendChain(message.Text("正在下载签文文件,请稍后...")) - err := file.DownloadTo(site+"运势签文.json", mikuji, false) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - dlmu.Unlock() - return - } - ctx.SendChain(message.Text("下载签文文件完毕")) - } - dlmu.Unlock() - } - // 检查字体文件是否存在 - ttf := base + "sakura.ttf" - if file.IsNotExist(ttf) { - dlmu.Lock() - if file.IsNotExist(ttf) { - ctx.SendChain(message.Text("正在下载字体文件,请稍后...")) - err := file.DownloadTo(site+"sakura.ttf", ttf, false) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - dlmu.Unlock() - return - } - ctx.SendChain(message.Text("下载字体文件完毕")) - } - dlmu.Unlock() - } // 获取该群背景类型,默认车万 kind := "车万" gid := ctx.Event.GroupID @@ -129,127 +121,93 @@ func init() { } } // 检查背景图片是否存在 - folder := base + kind - if file.IsNotExist(folder) { - dlmu.Lock() - if file.IsNotExist(folder) { - ctx.SendChain(message.Text("正在下载背景图片,请稍后...")) - zipfile := kind + ".zip" - zipcache := base + zipfile - err := file.DownloadTo(site+zipfile, zipcache, false) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - dlmu.Unlock() - return - } - ctx.SendChain(message.Text("下载背景图片完毕")) - err = unpack(zipcache, folder+"/") - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - dlmu.Unlock() - return - } - ctx.SendChain(message.Text("解压背景图片完毕")) - // 释放空间 - os.Remove(zipcache) - } - dlmu.Unlock() + zipfile := images + kind + ".zip" + _, err = file.GetLazyData(zipfile, false, false) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return } + // 生成种子 t, _ := strconv.ParseInt(time.Now().Format("20060102"), 10, 64) seed := ctx.Event.UserID + t + // 随机获取背景 - background, err := randimage(folder+"/", seed) + background, index, err := randimage(zipfile, seed) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } + // 随机获取签文 - title, text, err := randtext(mikuji, seed) + title, text, err := randtext(seed) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } + + digest := md5.Sum(helper.StringToBytes(zipfile + strconv.Itoa(index) + title + text)) + cachefile := cache + hex.EncodeToString(digest[:]) + if file.IsExist(cachefile) { + ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + cachefile)) + return + } + + dlmu.Lock() + f, err := os.Create(cachefile) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + _ = f.Close() + _ = os.Remove(cachefile) + dlmu.Unlock() + return + } // 绘制背景 - d, err := draw(background, title, text) + err = draw(background, title, text, f) + _ = f.Close() + dlmu.Unlock() + if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } // 发送图片 - ctx.SendChain(message.Image("base64://" + helper.BytesToString(d))) + ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + cachefile)) }) } -// @function unpack 解压资源包 -// @param tgt 压缩文件位置 -// @param dest 解压位置 -// @return 错误信息 -func unpack(tgt, dest string) error { - // 路径目录不存在则创建目录 - if file.IsNotExist(dest) { - if err := os.MkdirAll(dest, 0755); err != nil { - panic(err) - } - } - reader, err := zip.OpenReader(tgt) - if err != nil { - return err - } - defer reader.Close() - // 遍历解压到文件 - for _, file := range reader.File { - // 打开解压文件 - rc, err := file.Open() - if err != nil { - return err - } - // 打开目标文件 - w, err := os.OpenFile(dest+file.Name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) - if err != nil { - rc.Close() - return err - } - // 复制到文件 - _, err = io.Copy(w, rc) - rc.Close() - w.Close() - if err != nil { - return err - } - } - return nil -} - -// @function randimage 随机选取文件夹下的文件 -// @param path 文件夹路径 +// @function randimage 随机选取zip内的文件 +// @param path zip路径 // @param seed 随机数种子 // @return 文件路径 & 错误信息 -func randimage(path string, seed int64) (string, error) { - rd, err := ioutil.ReadDir(path) +func randimage(path string, seed int64) (im image.Image, index int, err error) { + reader, err := zip.OpenReader(path) if err != nil { - return "", err + return } + defer reader.Close() + rand.Seed(seed) - return path + rd[rand.Intn(len(rd))].Name(), nil + index = rand.Intn(len(reader.File)) + file := reader.File[index] + f, err := file.Open() + if err != nil { + return + } + defer f.Close() + + im, _, err = image.Decode(f) + return } // @function randtext 随机选取签文 // @param file 文件路径 // @param seed 随机数种子 // @return 签名 & 签文 & 错误信息 -func randtext(file string, seed int64) (string, string, error) { - data, err := ioutil.ReadFile(file) - if err != nil { - return "", "", err - } - temp := []map[string]string{} - if err := json.Unmarshal(data, &temp); err != nil { - return "", "", err - } +func randtext(seed int64) (string, string, error) { rand.Seed(seed) - r := rand.Intn(len(temp)) - return temp[r]["title"], temp[r]["content"], nil + r := rand.Intn(len(omikujis)) + return omikujis[r]["title"], omikujis[r]["content"], nil } // @function draw 绘制运势图 @@ -258,27 +216,23 @@ func randtext(file string, seed int64) (string, string, error) { // @param title 签名 // @param text 签文 // @return 错误信息 -func draw(background, title, text string) ([]byte, error) { - // 加载背景 - back, err := gg.LoadImage(background) - if err != nil { - return nil, err - } - canvas := gg.NewContext(back.Bounds().Size().Y, back.Bounds().Size().X) - canvas.DrawImage(back, 0, 0) +func draw(back image.Image, title, text string, dst io.Writer) error { + var txtc txt2img.TxtCanvas + txtc.Canvas = gg.NewContext(back.Bounds().Size().Y, back.Bounds().Size().X) + txtc.Canvas.DrawImage(back, 0, 0) // 写标题 - canvas.SetRGB(1, 1, 1) - if err := canvas.LoadFontFace(base+"sakura.ttf", 45); err != nil { - return nil, err + txtc.Canvas.SetRGB(1, 1, 1) + if err := txtc.Canvas.LoadFontFace(font, 45); err != nil { + return err } - sw, _ := canvas.MeasureString(title) - canvas.DrawString(title, 140-sw/2, 112) + sw, _ := txtc.Canvas.MeasureString(title) + txtc.Canvas.DrawString(title, 140-sw/2, 112) // 写正文 - canvas.SetRGB(0, 0, 0) - if err := canvas.LoadFontFace(base+"sakura.ttf", 23); err != nil { - return nil, err + txtc.Canvas.SetRGB(0, 0, 0) + if err := txtc.Canvas.LoadFontFace(font, 23); err != nil { + return err } - tw, th := canvas.MeasureString("测") + tw, th := txtc.Canvas.MeasureString("测") tw, th = tw+10, th+10 r := []rune(text) xsum := rowsnum(len(r), 9) @@ -288,7 +242,7 @@ func draw(background, title, text string) ([]byte, error) { xnow := rowsnum(i+1, 9) ysum := math.Min(len(r)-(xnow-1)*9, 9) ynow := i%9 + 1 - canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(ysum, ynow, th)+320.0) + txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(ysum, ynow, th)+320.0) } case 2: div := rowsnum(len(r), 2) @@ -298,23 +252,14 @@ func draw(background, title, text string) ([]byte, error) { ynow := i%div + 1 switch xnow { case 1: - canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow, th)+320.0) + txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow, th)+320.0) case 2: - canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow+(9-ysum), th)+320.0) + txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow+(9-ysum), th)+320.0) } } } - // 转成 base64 - buffer := new(bytes.Buffer) - encoder := base64.NewEncoder(base64.StdEncoding, buffer) - var opt jpeg.Options - opt.Quality = 70 - err = jpeg.Encode(encoder, canvas.Image(), &opt) - if err != nil { - return nil, err - } - encoder.Close() - return buffer.Bytes(), nil + _, err := txtc.WriteTo(dst) + return err } func offest(total, now int, distance float64) float64 {