From 72e5d54c200ef845f3b27e300a2fffa74ba7cb3b Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:30:08 +0800 Subject: [PATCH 1/7] Change module path from FloatTech to ltou14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改赛博猫猫 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 04d87f3..20de681 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/FloatTech/ZeroBot-Plugin-Playground +module github.com/ltou14/ZeroBot-Plugin-Playground go 1.20 From 5a937405c8f608c8cd8c6eb24d478b58b5a547c2 Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:32:35 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B5=9B=E5=8D=9A?= =?UTF-8?q?=E7=8C=AB=E7=8C=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/cybercat/catdata.go | 131 +++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 43 deletions(-) diff --git a/plugin/cybercat/catdata.go b/plugin/cybercat/catdata.go index 3bd8fad..7a8f339 100644 --- a/plugin/cybercat/catdata.go +++ b/plugin/cybercat/catdata.go @@ -1,6 +1,6 @@ // Package cybercat 云养猫 package cybercat - +import "errors" import ( "fmt" "os" @@ -65,44 +65,85 @@ type catInfo struct { } func (inf *catInfo) avatar(gid int64) string { - cache := path.Join(engine.DataFolder(), "cache") - imgname := fmt.Sprintf("%d_%d", inf.User, gid) - imgfile := filepath.Join(cache, inf.Type+imgname+".png") - aimgfile := filepath.Join(file.BOTPATH, imgfile) + // 构建缓存文件路径 + cache := path.Join(engine.DataFolder(), "cache") + imgname := fmt.Sprintf("%d_%d", inf.User, gid) + imgfile := filepath.Join(cache, inf.Type+imgname+".png") + aimgfile := filepath.Join(file.BOTPATH, imgfile) - if _, err := os.Stat(cache); os.IsNotExist(err) { - err := os.MkdirAll(cache, 0755) - if err != nil { - fmt.Println("Error creating cache directory:", err) - return err.Error() - } - } - if file.IsNotExist(aimgfile) { - breed := inf.Type - data, err := web.GetData(apiURL + "search?has_breeds=" + breed) - if err != nil { - fmt.Println("Error fetching avatar URL:", err) - return err.Error() // 返回错误信息 - } - imgurl := gjson.ParseBytes(data).Get("0.url").String() - imgdata, err := web.GetData(imgurl) - if err != nil { - return "错误:未能解析图片URL" - } - var f *os.File - f, err = os.Create(aimgfile) // 使用 aimgfile 作为文件路径 - if err != nil { - fmt.Println("Error creating file:", err) - return err.Error() // 返回错误信息 - } - defer f.Close() - _, err = f.Write(imgdata) // 写入图片数据 - if err != nil { - fmt.Println("Error writing file:", err) - return err.Error() // 返回错误信息 - } - } - return "file:///" + aimgfile // 返回文件协议的完整路径 + // 确保缓存目录存在 + _ = os.MkdirAll(cache, 0755) + + // 1. 如果本地已有缓存文件,直接返回 + if file.IsExist(aimgfile) { + return "file:///" + aimgfile + } + + // 2. 优先使用已有的 Picurl(例如用户上传的猫娘图片) + if inf.Picurl != "" { + if err := downloadAndSave(inf.Picurl, aimgfile); err == nil { + return "file:///" + aimgfile + } + // 下载失败,继续尝试通过品种获取 + } + + // 3. 通过品种ID获取图片 + breedID, ok := typeZH2Breeds[inf.Type] + if ok { + // 构建请求URL(使用 breed_ids 参数) + url := apiURL + "search?breed_ids=" + breedID + "&limit=1" + // 建议添加 API 密钥(从配置读取) + if apiKey := getCatAPIKey(); apiKey != "" { + url += "&api_key=" + apiKey + } + + data, err := web.GetData(url) + if err == nil { + imgURL := gjson.ParseBytes(data).Get("0.url").String() + if imgURL != "" { + if err := downloadAndSave(imgURL, aimgfile); err == nil { + // 保存 URL 到数据库供下次使用 + inf.Picurl = imgURL + go func() { + gidStr := "group" + strconv.FormatInt(gid, 10) + _ = catdata.insert(gidStr, inf) // 异步更新,忽略错误 + }() + return "file:///" + aimgfile + } + } + } + } + + // 4. 后备方案:随机猫图 + _, _, _, url, err := suineko() + if err == nil && url != "" { + if err := downloadAndSave(url, aimgfile); err == nil { + return "file:///" + aimgfile + } + } + + // 5. 最终后备:透明PNG(避免报错) + return "base64://iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" +} + +// downloadAndSave 下载图片并保存到本地 +func downloadAndSave(url, filepath string) error { + data, err := web.GetData(url) + if err != nil { + return err + } + f, err := os.Create(filepath) + if err != nil { + return err + } + defer f.Close() + _, err = f.Write(data) + return err +} + +// getCatAPIKey 从环境变量或配置获取API密钥(需自行实现) +func getCatAPIKey() string { + return "live_jjmlzq8FSiuFko40Utf43EfniNWYY1MtBaCej1Fy2YRDW9nMEmtgJwOMiZzs6fXc" // 替换为真实密钥 } var ( @@ -176,11 +217,15 @@ func suineko() (typeName, temperament, description, url string, err error) { } func getPicByBreed(catBreed string) (url string, err error) { - data, err := web.GetData(apiURL + "search?breed_ids=" + catBreed) - if err != nil { - return - } - return gjson.ParseBytes(data).Get("0.url").String(), nil + data, err := web.GetData(apiURL + "search?breed_ids=" + catBreed) + if err != nil { + return + } + url = gjson.ParseBytes(data).Get("0.url").String() + if url == "" { + err = errors.New("no image found") + } + return } func (sql *catdb) insert(gid string, dbInfo *catInfo) error { From 0f166a6419baa1cb2fe392f922f8daa87ee8c23b Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 20:08:34 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B5=9B=E5=8D=9A?= =?UTF-8?q?=E7=8C=AB=E7=8C=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/cybercat/catdata.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/cybercat/catdata.go b/plugin/cybercat/catdata.go index 7a8f339..3cd77f0 100644 --- a/plugin/cybercat/catdata.go +++ b/plugin/cybercat/catdata.go @@ -8,6 +8,7 @@ import ( "path/filepath" "sync" "time" + "strconv" fcext "github.com/FloatTech/floatbox/ctxext" "github.com/FloatTech/floatbox/file" From 485192fa5405c832d33e84e045775cde0d67ea17 Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:34:24 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B5=9B=E5=8D=9A?= =?UTF-8?q?=E7=8C=AB=E7=8C=AB=E4=B8=8D=E8=83=BD=E6=98=BE=E7=A4=BA=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/cybercat/catdata.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/cybercat/catdata.go b/plugin/cybercat/catdata.go index 3cd77f0..425e838 100644 --- a/plugin/cybercat/catdata.go +++ b/plugin/cybercat/catdata.go @@ -8,7 +8,7 @@ import ( "path/filepath" "sync" "time" - "strconv" + "strconv" fcext "github.com/FloatTech/floatbox/ctxext" "github.com/FloatTech/floatbox/file" @@ -93,7 +93,7 @@ func (inf *catInfo) avatar(gid int64) string { if ok { // 构建请求URL(使用 breed_ids 参数) url := apiURL + "search?breed_ids=" + breedID + "&limit=1" - // 建议添加 API 密钥(从配置读取) + // 添加 API 密钥 if apiKey := getCatAPIKey(); apiKey != "" { url += "&api_key=" + apiKey } @@ -142,9 +142,9 @@ func downloadAndSave(url, filepath string) error { return err } -// getCatAPIKey 从环境变量或配置获取API密钥(需自行实现) +// getCatAPIKey API密钥 func getCatAPIKey() string { - return "live_jjmlzq8FSiuFko40Utf43EfniNWYY1MtBaCej1Fy2YRDW9nMEmtgJwOMiZzs6fXc" // 替换为真实密钥 + return "live_jjmlzq8FSiuFko40Utf43EfniNWYY1MtBaCej1Fy2YRDW9nMEmtgJwOMiZzs6fXc" // 替换为真实免费密钥 } var ( From a65b82ac7335a92a7516f626440365eb16536055 Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:45:32 +0800 Subject: [PATCH 5/7] =?UTF-8?q?Change=20module=20path=20from=20ltou14=20to?= =?UTF-8?q?=20FloatTech=E6=8A=8Amodule=E4=BF=AE=E6=94=B9=E5=9B=9E=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 20de681..04d87f3 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/ltou14/ZeroBot-Plugin-Playground +module github.com/FloatTech/ZeroBot-Plugin-Playground go 1.20 From 0bc5af52bfa5067b8e445294d7a7ddbf247ad926 Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:37:01 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=A0=87=E6=B3=A8=E8=BF=9E=E7=BB=AD?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=BA=86=E4=B8=89=E4=B8=AA=E7=A9=BA=E7=99=BD?= =?UTF-8?q?=E6=A0=87=E8=AF=86=E7=AC=A6=EF=BC=88=5F=EF=BC=89=E5=BF=BD?= =?UTF-8?q?=E7=95=A5=20suineko()=20=E5=87=BD=E6=95=B0=E7=9A=84=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E8=BF=94=E5=9B=9E=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/cybercat/catdata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/cybercat/catdata.go b/plugin/cybercat/catdata.go index 425e838..679420c 100644 --- a/plugin/cybercat/catdata.go +++ b/plugin/cybercat/catdata.go @@ -116,7 +116,7 @@ func (inf *catInfo) avatar(gid int64) string { } // 4. 后备方案:随机猫图 - _, _, _, url, err := suineko() + _, _, _, url, err := suineko()//nolint:dogsled if err == nil && url != "" { if err := downloadAndSave(url, aimgfile); err == nil { return "file:///" + aimgfile From cb3a1f13b1512e10e7dd33f9e61418de765eca7f Mon Sep 17 00:00:00 2001 From: ltou14 <95116148+ltou14@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:37:27 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=B0=86suineko=E5=8F=82=E6=95=B0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E7=BB=93=E6=9E=84=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/cybercat/catdata.go | 103 ++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/plugin/cybercat/catdata.go b/plugin/cybercat/catdata.go index 679420c..5cc2478 100644 --- a/plugin/cybercat/catdata.go +++ b/plugin/cybercat/catdata.go @@ -51,6 +51,14 @@ type catdb struct { sql.Sqlite } +type breedInfo struct { + TypeName string + Temperament string + Description string + ImageURL string + Err error +} + type catInfo struct { User int64 // 主人 Name string // 喵喵名称 @@ -116,12 +124,12 @@ func (inf *catInfo) avatar(gid int64) string { } // 4. 后备方案:随机猫图 - _, _, _, url, err := suineko()//nolint:dogsled - if err == nil && url != "" { - if err := downloadAndSave(url, aimgfile); err == nil { - return "file:///" + aimgfile - } - } + result := suineko() + if result.Err == nil && result.ImageURL != "" { + if err := downloadAndSave(result.ImageURL, aimgfile); err == nil { + return "file:///" + aimgfile + } + } // 5. 最终后备:透明PNG(避免报错) return "base64://iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" @@ -177,44 +185,55 @@ var ( ) func init() { - engine.OnRegex(`^吸(.*猫)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) { - typeOfcat := ctx.State["regex_matched"].([]string)[1] - if typeOfcat == "猫" { - typeName, temperament, description, url, err := suineko() - if err != nil { - ctx.SendChain(message.Text("[ERROR]: ", err)) - return - } - ctx.SendChain(message.Image(url), message.Text("品种: ", typeName, - "\n气质:\n", temperament, "\n描述:\n", description)) - return - } - breeds, ok := typeZH2Breeds[typeOfcat] - if !ok { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("没有相关该品种的猫图")) - return - } - picurl, err := getPicByBreed(breeds) - if err != nil { - ctx.SendChain(message.Text("[ERROR]: ", err)) - return - } - ctx.SendChain(message.Text("品种: ", typeOfcat), message.Image(picurl)) - }) + engine.OnRegex(`^吸(.*猫)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) { + typeOfcat := ctx.State["regex_matched"].([]string)[1] + if typeOfcat == "猫" { + result := suineko() + if result.Err != nil { + ctx.SendChain(message.Text("[ERROR]: ", result.Err)) + return + } + ctx.SendChain( + message.Image(result.ImageURL), + message.Text("品种: ", result.TypeName, + "\n气质:\n", result.Temperament, + "\n描述:\n", result.Description), + ) + return + } + breeds, ok := typeZH2Breeds[typeOfcat] + if !ok { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("没有相关该品种的猫图")) + return + } + picurl, err := getPicByBreed(breeds) + if err != nil { + ctx.SendChain(message.Text("[ERROR]: ", err)) + return + } + ctx.SendChain(message.Text("品种: ", typeOfcat), message.Image(picurl)) + }) } -func suineko() (typeName, temperament, description, url string, err error) { - data, err := web.GetData(apiURL + "search?has_breeds=1") - if err != nil { - return - } - picID := gjson.ParseBytes(data).Get("0.id").String() - picdata, err := web.GetData(apiURL + picID) - if err != nil { - return - } - name := gjson.ParseBytes(picdata).Get("breeds.0.name").String() - return typeEN2ZH[name], gjson.ParseBytes(picdata).Get("breeds.0.temperament").String(), gjson.ParseBytes(picdata).Get("breeds.0.description").String(), gjson.ParseBytes(picdata).Get("url").String(), nil + +func suineko() breedInfo { + data, err := web.GetData(apiURL + "search?has_breeds=1") + if err != nil { + return breedInfo{Err: err} + } + picID := gjson.ParseBytes(data).Get("0.id").String() + picdata, err := web.GetData(apiURL + picID) + if err != nil { + return breedInfo{Err: err} + } + name := gjson.ParseBytes(picdata).Get("breeds.0.name").String() + return breedInfo{ + TypeName: typeEN2ZH[name], + Temperament: gjson.ParseBytes(picdata).Get("breeds.0.temperament").String(), + Description: gjson.ParseBytes(picdata).Get("breeds.0.description").String(), + ImageURL: gjson.ParseBytes(picdata).Get("url").String(), + Err: nil, + } } func getPicByBreed(catBreed string) (url string, err error) {