mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-03-01 18:40:26 +00:00
Compare commits
11 Commits
create-pul
...
v1.10.19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
992204d588 | ||
|
|
41425ad839 | ||
|
|
e0fa3ba0b3 | ||
|
|
82dc709f3b | ||
|
|
15c9fb3e27 | ||
|
|
41292ba1e6 | ||
|
|
e5b70d7fe6 | ||
|
|
9cb3a5019f | ||
|
|
d5729b4e27 | ||
|
|
7f4830d50f | ||
|
|
39d319bf70 |
12
README.md
12
README.md
@@ -655,6 +655,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 齁语解密 [密文] 或 h解密 [密文]
|
||||
- [x] fumo加密 [文本]
|
||||
- [x] fumo解密 [文本]
|
||||
- [x] qq加密 [文本]
|
||||
- [x] qq解密 [密文]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -845,6 +847,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 下载歌单[网易云歌单链接/ID]到[歌单名称]
|
||||
- [x] 解除绑定 [歌单名称]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜成语</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/handou"`
|
||||
|
||||
- [x] 个人猜成语
|
||||
|
||||
- [x] 团队猜成语
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一言</summary>
|
||||
|
||||
2
data
2
data
Submodule data updated: 74e3bf5dc8...7f6c3a00d2
2
go.mod
2
go.mod
@@ -12,7 +12,7 @@ require (
|
||||
github.com/FloatTech/sqlite v1.7.2
|
||||
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
|
||||
github.com/FloatTech/zbpctrl v1.7.1
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260131163621-618685d53380
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260219154206-c4c0a7e0fb03
|
||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
||||
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438
|
||||
github.com/Tnze/go-mc v1.20.2
|
||||
|
||||
4
go.sum
4
go.sum
@@ -16,8 +16,8 @@ github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9
|
||||
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.7.1 h1:0yPEmCForhyMbnhTckmjDUFFDZgQp1RjO2bVF4ZVqOs=
|
||||
github.com/FloatTech/zbpctrl v1.7.1/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260131163621-618685d53380 h1:M/rYDnNv3zvF6ZOSzxlgYZdNOmmJPR6BrEBlJGknn2A=
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260131163621-618685d53380/go.mod h1:W2kaR/A5oUtEb7DnveXCc0T374VjI+f3KmOWH9FE5vU=
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260219154206-c4c0a7e0fb03 h1:rA9ybZ611JzclcfvlR049nakH29DdScfpOGsjzg92lA=
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20260219154206-c4c0a7e0fb03/go.mod h1:W2kaR/A5oUtEb7DnveXCc0T374VjI+f3KmOWH9FE5vU=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
||||
|
||||
668
gomod2nix.toml
668
gomod2nix.toml
@@ -1,290 +1,384 @@
|
||||
schema = 3
|
||||
|
||||
[mod]
|
||||
[mod."github.com/Baidu-AIP/golang-sdk"]
|
||||
version = "v1.1.1"
|
||||
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
|
||||
[mod."github.com/FloatTech/AnimeAPI"]
|
||||
version = "v1.7.1-0.20251028071248-0c948e3db65c"
|
||||
hash = "sha256-EkC8QYgmXElKGM8GzcQ4r/c+lM1ysJOccfoeqhMtAvs="
|
||||
[mod."github.com/FloatTech/floatbox"]
|
||||
version = "v0.0.0-20251002074805-f95cbc7edb31"
|
||||
hash = "sha256-c50unGhF0JVPHN8geZM/YYQKgGqJgCtVksh4Ij1Pg+4="
|
||||
[mod."github.com/FloatTech/gg"]
|
||||
version = "v1.1.3"
|
||||
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
|
||||
[mod."github.com/FloatTech/imgfactory"]
|
||||
version = "v0.2.2-0.20230413152719-e101cc3606ef"
|
||||
hash = "sha256-2okFyPQSYIxrc8hxICsbjEM9xq25a3I2A4wmDIYFCg8="
|
||||
[mod."github.com/FloatTech/rendercard"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs="
|
||||
[mod."github.com/FloatTech/sqlite"]
|
||||
version = "v1.7.2"
|
||||
hash = "sha256-R9QaP5FQwtWpHdbCoNX/rYOS/CgkIeRdFB9cwJ4n/JM="
|
||||
[mod."github.com/FloatTech/ttl"]
|
||||
version = "v0.0.0-20250224045156-012b1463287d"
|
||||
hash = "sha256-C5xBt0roPgahradCOTgkhL+j5bvoSXmGwdqcu0aSczc="
|
||||
[mod."github.com/FloatTech/zbpctrl"]
|
||||
version = "v1.7.1"
|
||||
hash = "sha256-wkeiaUTpPVbpH7fcXeoLtG+aGIMJbvoc/9sbi2IXK0I="
|
||||
[mod."github.com/FloatTech/zbputils"]
|
||||
version = "v1.7.2-0.20260131163621-618685d53380"
|
||||
hash = "sha256-/t4FpFcbT3OGGi8gU/rs/JuOG7RHoXWNaELxDBZUI3U="
|
||||
[mod."github.com/PuerkitoBio/goquery"]
|
||||
version = "v1.8.0"
|
||||
hash = "sha256-I3QaPWATvBOL/F26fIiYWKS13yBUYo+9o3tcsGIu8tY="
|
||||
[mod."github.com/RomiChan/syncx"]
|
||||
version = "v0.0.0-20240418144900-b7402ffdebc7"
|
||||
hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4="
|
||||
[mod."github.com/RomiChan/websocket"]
|
||||
version = "v1.4.3-0.20251002072000-d3eb41798438"
|
||||
hash = "sha256-vLu9Va+9AbOIdh1LEetz5JlJK0P2IXKsYRvCdAO8tYw="
|
||||
[mod."github.com/Tnze/go-mc"]
|
||||
version = "v1.20.2"
|
||||
hash = "sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI="
|
||||
[mod."github.com/adamzy/cedar-go"]
|
||||
version = "v0.0.0-20170805034717-80a9c64b256d"
|
||||
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
||||
[mod."github.com/ajstarks/svgo"]
|
||||
version = "v0.0.0-20200320125537-f189e35d30ca"
|
||||
hash = "sha256-ALeRuEJN9jHjGb4wNKJcxC59vVx8Tj7hHikEGkaZZ0s="
|
||||
[mod."github.com/andybalholm/cascadia"]
|
||||
version = "v1.3.1"
|
||||
hash = "sha256-M0u22DXSeXUaYtl1KoW1qWL46niFpycFkraCEQ/luYA="
|
||||
[mod."github.com/antchfx/htmlquery"]
|
||||
version = "v1.3.5"
|
||||
hash = "sha256-AyfSTQY2eiNPhTS/FVgaBlSzPOObSaluhSee8Gvc8ho="
|
||||
[mod."github.com/antchfx/xpath"]
|
||||
version = "v1.3.5"
|
||||
hash = "sha256-AVM0rR81hgVAI0QVzlz4WijFUjByf6Zew3ZwuikKw2Q="
|
||||
[mod."github.com/corona10/goimagehash"]
|
||||
version = "v1.1.1-0.20240121134706-d8115886f360"
|
||||
hash = "sha256-/corDVYILmy/DMWtgM1D1MK6I7pejA5JNfaxeojwkkA="
|
||||
[mod."github.com/davidscholberg/go-durationfmt"]
|
||||
version = "v0.0.0-20170122144659-64843a2083d3"
|
||||
hash = "sha256-0rdbpBf3AAjMpxvVEGFb2ImgB2i7vdEhIwCyqJs1iHE="
|
||||
[mod."github.com/disintegration/imaging"]
|
||||
version = "v1.6.2"
|
||||
hash = "sha256-pSeMTPvSkxlthh65LjNYYhPLvCZDkBgVgAGYWW0Aguo="
|
||||
[mod."github.com/dustin/go-humanize"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
|
||||
[mod."github.com/ebitengine/oto/v3"]
|
||||
version = "v3.3.2"
|
||||
hash = "sha256-TPu3qvJscLZbjwIqC3jj0T1md0mX3lQxcC8GAk7kB1w="
|
||||
[mod."github.com/ebitengine/purego"]
|
||||
version = "v0.9.1"
|
||||
hash = "sha256-iVfU8vaJ7IPa92dUeHeuW+yKvUbe59F/eV7GlDRIAcE="
|
||||
[mod."github.com/ericpauley/go-quantize"]
|
||||
version = "v0.0.0-20200331213906-ae555eb2afa4"
|
||||
hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs="
|
||||
[mod."github.com/fumiama/ahsai"]
|
||||
version = "v0.1.1"
|
||||
hash = "sha256-knYw0R5fhjE/asc/TwlGJDzVr+Oaj8sH7kr7x6Mqs3E="
|
||||
[mod."github.com/fumiama/cron"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k="
|
||||
[mod."github.com/fumiama/deepinfra"]
|
||||
version = "v0.0.0-20251221163610-e98ee3ba437a"
|
||||
hash = "sha256-XubewUDOLaN7fgv9E8PAfP7DtADdLm+M2sgSn5OE6eQ="
|
||||
[mod."github.com/fumiama/go-base16384"]
|
||||
version = "v1.7.1"
|
||||
hash = "sha256-Fd1QaeYx+3q4C3XQXlPFnDmKPsoZH6837fN/7rn8i9s="
|
||||
[mod."github.com/fumiama/go-onebot-agent"]
|
||||
version = "v0.0.0-20260128132028-05e6b4809f0a"
|
||||
hash = "sha256-ratY7o52v0KuxgZC4wqHNXdgGXzliEecs8egE3SBLeo="
|
||||
[mod."github.com/fumiama/go-registry"]
|
||||
version = "v0.2.7"
|
||||
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
|
||||
[mod."github.com/fumiama/go-simple-protobuf"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw="
|
||||
[mod."github.com/fumiama/gofastTEA"]
|
||||
version = "v0.1.3"
|
||||
hash = "sha256-/Qu57mkkFt7aFufhlkMYPgrWj5XCGbuM28EHDD8w4XY="
|
||||
[mod."github.com/fumiama/gotracemoe"]
|
||||
version = "v0.0.3"
|
||||
hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ="
|
||||
[mod."github.com/fumiama/imgsz"]
|
||||
version = "v0.0.4"
|
||||
hash = "sha256-rrGx+v41OEl0ATwL6u5TNcpfkCQbj3jFNnGiQUNu2qs="
|
||||
[mod."github.com/fumiama/jieba"]
|
||||
version = "v0.0.0-20221203025406-36c17a10b565"
|
||||
hash = "sha256-DvDx1pdldkdaSszrbadM/VwqT9TTSmWl6G6a+ysXYEM="
|
||||
[mod."github.com/fumiama/orbyte"]
|
||||
version = "v0.0.0-20251002065953-3bb358367eb5"
|
||||
hash = "sha256-mRQwhR0v922UXlJ7lXo/osv21K8kZDaHx3DsBCjmzoo="
|
||||
[mod."github.com/fumiama/slowdo"]
|
||||
version = "v0.0.0-20241001074058-27c4fe5259a4"
|
||||
hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY="
|
||||
[mod."github.com/fumiama/terasu"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-tYHvvfJT1/R4koqGFPjdU211Dcez2XWuvpRke/tFfQ8="
|
||||
[mod."github.com/fumiama/unibase2n"]
|
||||
version = "v0.0.0-20240530074540-ec743fd5a6d6"
|
||||
hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw="
|
||||
[mod."github.com/gabriel-vasile/mimetype"]
|
||||
version = "v1.4.12"
|
||||
hash = "sha256-vY2g58yUrkT//8fttRKhS9rbg89YSae/BzOARS5uH30="
|
||||
[mod."github.com/go-ole/go-ole"]
|
||||
version = "v1.2.6"
|
||||
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
|
||||
[mod."github.com/golang/freetype"]
|
||||
version = "v0.0.0-20170609003504-e2365dfdc4a0"
|
||||
hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA="
|
||||
[mod."github.com/golang/groupcache"]
|
||||
version = "v0.0.0-20210331224755-41bb18bfe9da"
|
||||
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0="
|
||||
[mod."github.com/google/uuid"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||
[mod."github.com/gopxl/beep/v2"]
|
||||
version = "v2.1.1"
|
||||
hash = "sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU="
|
||||
[mod."github.com/guohuiyuan/music-lib"]
|
||||
version = "v1.0.2-0.20260121020416-53f6cb24629d"
|
||||
hash = "sha256-juVJ/nh6zA5Gu5+dRzIx8tElXLscRQYwY9vLvVKh078="
|
||||
[mod."github.com/jfreymuth/oggvorbis"]
|
||||
version = "v1.0.5"
|
||||
hash = "sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0="
|
||||
[mod."github.com/jfreymuth/vorbis"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-gVS+/PZ5pDnswpTQNZILcrx5ZNq9ShXd6vXn7Jabes4="
|
||||
[mod."github.com/jinzhu/gorm"]
|
||||
version = "v1.9.16"
|
||||
hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc="
|
||||
[mod."github.com/jinzhu/inflection"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-3h3pHib5MaCXKyKLIMyQnSptDJ16kPjCOQPoEBoQsZg="
|
||||
[mod."github.com/jozsefsallai/gophersauce"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-29DsfnGmK51DPunR/leRBKCcokN/yLoB7S2HxCsqtgY="
|
||||
[mod."github.com/json-iterator/go"]
|
||||
version = "v1.1.12"
|
||||
hash = "sha256-To8A0h+lbfZ/6zM+2PpRpY3+L6725OPC66lffq6fUoM="
|
||||
[mod."github.com/kanrichan/resvg-go"]
|
||||
version = "v0.0.2-0.20231001163256-63db194ca9f5"
|
||||
hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds="
|
||||
[mod."github.com/lithammer/fuzzysearch"]
|
||||
version = "v1.1.8"
|
||||
hash = "sha256-aMMRcrlUc9CBiiNkcnWWn4hfNMNyVhrAt67kvP4D4Do="
|
||||
[mod."github.com/liuzl/cedar-go"]
|
||||
version = "v0.0.0-20170805034717-80a9c64b256d"
|
||||
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
||||
[mod."github.com/liuzl/da"]
|
||||
version = "v0.0.0-20180704015230-14771aad5b1d"
|
||||
hash = "sha256-J43kwDFmB6LzDhS3Ig/4ddZUTXz1cKztbTA3hILScs8="
|
||||
[mod."github.com/liuzl/gocc"]
|
||||
version = "v0.0.0-20231231122217-0372e1059ca5"
|
||||
hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8="
|
||||
[mod."github.com/lufia/plan9stats"]
|
||||
version = "v0.0.0-20211012122336-39d0f177ccd0"
|
||||
hash = "sha256-thb+rkDx5IeWMgw5/5jgu5gZ+6RjJAUXeMgSkJHhRlA="
|
||||
[mod."github.com/mattn/go-isatty"]
|
||||
version = "v0.0.20"
|
||||
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
|
||||
[mod."github.com/mmcdole/gofeed"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-GHpqGZvNg+3RSIkVKXrWg6/e8dJD8Y5v2Sx6MzmRlQ0="
|
||||
[mod."github.com/mmcdole/goxpp"]
|
||||
version = "v1.1.1-0.20240225020742-a0c311522b23"
|
||||
hash = "sha256-2pGg+LxHHQn2lwQBvc7EtrpMwZbZF7qepglzhS3TfW4="
|
||||
[mod."github.com/modern-go/concurrent"]
|
||||
version = "v0.0.0-20180306012644-bacd9c7ef1dd"
|
||||
hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo="
|
||||
[mod."github.com/modern-go/reflect2"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU="
|
||||
[mod."github.com/mroth/weightedrand"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c="
|
||||
[mod."github.com/ncruces/go-strftime"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-GYIwYDONuv/yTE0AEugCHQbtV3oiBaco93xUNYFcVBQ="
|
||||
[mod."github.com/nfnt/resize"]
|
||||
version = "v0.0.0-20180221191011-83c6a9932646"
|
||||
hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA="
|
||||
[mod."github.com/notnil/chess"]
|
||||
version = "v1.10.0"
|
||||
hash = "sha256-hsUOS4rVuMW+UCPJzhsZh3PHCi1Lol12BwKujcICayo="
|
||||
[mod."github.com/pbnjay/memory"]
|
||||
version = "v0.0.0-20210728143218-7b4eea64cf58"
|
||||
hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA="
|
||||
[mod."github.com/pkg/errors"]
|
||||
version = "v0.9.1"
|
||||
hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw="
|
||||
[mod."github.com/pkumza/numcn"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg="
|
||||
[mod."github.com/power-devops/perfstat"]
|
||||
version = "v0.0.0-20240221224432-82ca36839d55"
|
||||
hash = "sha256-ujzuJ1ttQgjHQJEij4O/2+I8DZaUVZQCQgA4ysfqulI="
|
||||
[mod."github.com/remyoudompheng/bigfft"]
|
||||
version = "v0.0.0-20230129092748-24d4a6f8daec"
|
||||
hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM="
|
||||
[mod."github.com/shirou/gopsutil/v4"]
|
||||
version = "v4.25.12"
|
||||
hash = "sha256-gzk9GW4+tXUWmxAVD3by/k4D/+l++TvajRVTkQJvwmM="
|
||||
[mod."github.com/sirupsen/logrus"]
|
||||
version = "v1.9.4"
|
||||
hash = "sha256-ltRvmtM3XTCAFwY0IesfRqYIivyXPPuvkFjL4ARh1wg="
|
||||
[mod."github.com/tetratelabs/wazero"]
|
||||
version = "v1.5.0"
|
||||
hash = "sha256-fGdJM4LJrZA9jxHuYVo4EUQ3I1k0IVG3QQCBCgZkeZI="
|
||||
[mod."github.com/tidwall/gjson"]
|
||||
version = "v1.18.0"
|
||||
hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I="
|
||||
[mod."github.com/tidwall/match"]
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-O2wTU0SmNIEEOxfncl2BW2czgWeIW5vqR6+A7dtNtXI="
|
||||
[mod."github.com/tidwall/pretty"]
|
||||
version = "v1.2.1"
|
||||
hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8="
|
||||
[mod."github.com/tklauser/go-sysconf"]
|
||||
version = "v0.3.16"
|
||||
hash = "sha256-hNVbsk0G+M9bLtHNywPD0nCW0z/9pM4jQV53nnDo/MY="
|
||||
[mod."github.com/tklauser/numcpus"]
|
||||
version = "v0.11.0"
|
||||
hash = "sha256-ObydGqAvRiHwVfO2ytmL28pRHyuCWYWwjH4hWdgI/Vs="
|
||||
[mod."github.com/wcharczuk/go-chart/v2"]
|
||||
version = "v2.1.2"
|
||||
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="
|
||||
[mod."github.com/wdvxdr1123/ZeroBot"]
|
||||
version = "v1.8.3-0.20260117102541-393033a35adb"
|
||||
hash = "sha256-Yz2OTU05kDZOHX8J04jX5Jg5ya9rwqsH0TySSBhMOp0="
|
||||
[mod."github.com/yusufpapurcu/wmi"]
|
||||
version = "v1.2.4"
|
||||
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="
|
||||
[mod."gitlab.com/gomidi/midi/v2"]
|
||||
version = "v2.3.18"
|
||||
hash = "sha256-lkU9M+h56+Ai/bpQDST3Su71dhjp1Vk2S7/okrELo7s="
|
||||
[mod."golang.org/x/image"]
|
||||
version = "v0.34.0"
|
||||
hash = "sha256-7V1bDhd++dCw11DCXOAUb5f1Hj51EfS0DZ03pq0V/p0="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.48.0"
|
||||
hash = "sha256-oZpddsiJwWCH3Aipa+XXpy7G/xHY5fEagUSok7T0bXE="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.39.0"
|
||||
hash = "sha256-dxTBu/JAWUkPbjFIXXRFdhQWyn+YyEpIC+tWqGo0Y6U="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.32.0"
|
||||
hash = "sha256-9PXtWBKKY9rG4AgjSP4N+I1DhepXhy8SF/vWSIDIoWs="
|
||||
[mod."gopkg.in/yaml.v3"]
|
||||
version = "v3.0.1"
|
||||
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
||||
[mod."modernc.org/libc"]
|
||||
version = "v0.0.0-20240530081950-6f6d8586b5c5"
|
||||
hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w="
|
||||
replaced = "github.com/fumiama/libc"
|
||||
[mod."modernc.org/mathutil"]
|
||||
version = "v1.7.1"
|
||||
hash = "sha256-COZ5rF2GhQVR1r6a0DanJ8qwQ94JSKdQxTMWrDzE0Cc="
|
||||
[mod."modernc.org/memory"]
|
||||
version = "v1.11.0"
|
||||
hash = "sha256-MkybF8vvrxXS5j7O8w3skwTo0aMo1yjWS0K440rYcHM="
|
||||
[mod."modernc.org/sqlite"]
|
||||
version = "v1.29.10-simp"
|
||||
hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE="
|
||||
replaced = "github.com/fumiama/sqlite3"
|
||||
[mod.'github.com/Baidu-AIP/golang-sdk']
|
||||
version = 'v1.1.1'
|
||||
hash = 'sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo='
|
||||
|
||||
[mod.'github.com/FloatTech/AnimeAPI']
|
||||
version = 'v1.7.1-0.20251028071248-0c948e3db65c'
|
||||
hash = 'sha256-EkC8QYgmXElKGM8GzcQ4r/c+lM1ysJOccfoeqhMtAvs='
|
||||
|
||||
[mod.'github.com/FloatTech/floatbox']
|
||||
version = 'v0.0.0-20251002074805-f95cbc7edb31'
|
||||
hash = 'sha256-c50unGhF0JVPHN8geZM/YYQKgGqJgCtVksh4Ij1Pg+4='
|
||||
|
||||
[mod.'github.com/FloatTech/gg']
|
||||
version = 'v1.1.3'
|
||||
hash = 'sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo='
|
||||
|
||||
[mod.'github.com/FloatTech/imgfactory']
|
||||
version = 'v0.2.2-0.20230413152719-e101cc3606ef'
|
||||
hash = 'sha256-2okFyPQSYIxrc8hxICsbjEM9xq25a3I2A4wmDIYFCg8='
|
||||
|
||||
[mod.'github.com/FloatTech/rendercard']
|
||||
version = 'v0.2.0'
|
||||
hash = 'sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs='
|
||||
|
||||
[mod.'github.com/FloatTech/sqlite']
|
||||
version = 'v1.7.2'
|
||||
hash = 'sha256-R9QaP5FQwtWpHdbCoNX/rYOS/CgkIeRdFB9cwJ4n/JM='
|
||||
|
||||
[mod.'github.com/FloatTech/ttl']
|
||||
version = 'v0.0.0-20250224045156-012b1463287d'
|
||||
hash = 'sha256-C5xBt0roPgahradCOTgkhL+j5bvoSXmGwdqcu0aSczc='
|
||||
|
||||
[mod.'github.com/FloatTech/zbpctrl']
|
||||
version = 'v1.7.1'
|
||||
hash = 'sha256-wkeiaUTpPVbpH7fcXeoLtG+aGIMJbvoc/9sbi2IXK0I='
|
||||
|
||||
[mod.'github.com/FloatTech/zbputils']
|
||||
version = 'v1.7.2-0.20260219154206-c4c0a7e0fb03'
|
||||
hash = 'sha256-I4Qcfm9dTth+AVP7HJ/RMLNa3ff+bKJwJzsHT2RMipA='
|
||||
|
||||
[mod.'github.com/PuerkitoBio/goquery']
|
||||
version = 'v1.8.0'
|
||||
hash = 'sha256-I3QaPWATvBOL/F26fIiYWKS13yBUYo+9o3tcsGIu8tY='
|
||||
|
||||
[mod.'github.com/RomiChan/syncx']
|
||||
version = 'v0.0.0-20240418144900-b7402ffdebc7'
|
||||
hash = 'sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4='
|
||||
|
||||
[mod.'github.com/RomiChan/websocket']
|
||||
version = 'v1.4.3-0.20251002072000-d3eb41798438'
|
||||
hash = 'sha256-vLu9Va+9AbOIdh1LEetz5JlJK0P2IXKsYRvCdAO8tYw='
|
||||
|
||||
[mod.'github.com/Tnze/go-mc']
|
||||
version = 'v1.20.2'
|
||||
hash = 'sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI='
|
||||
|
||||
[mod.'github.com/adamzy/cedar-go']
|
||||
version = 'v0.0.0-20170805034717-80a9c64b256d'
|
||||
hash = 'sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0='
|
||||
|
||||
[mod.'github.com/ajstarks/svgo']
|
||||
version = 'v0.0.0-20200320125537-f189e35d30ca'
|
||||
hash = 'sha256-ALeRuEJN9jHjGb4wNKJcxC59vVx8Tj7hHikEGkaZZ0s='
|
||||
|
||||
[mod.'github.com/andybalholm/cascadia']
|
||||
version = 'v1.3.1'
|
||||
hash = 'sha256-M0u22DXSeXUaYtl1KoW1qWL46niFpycFkraCEQ/luYA='
|
||||
|
||||
[mod.'github.com/antchfx/htmlquery']
|
||||
version = 'v1.3.5'
|
||||
hash = 'sha256-AyfSTQY2eiNPhTS/FVgaBlSzPOObSaluhSee8Gvc8ho='
|
||||
|
||||
[mod.'github.com/antchfx/xpath']
|
||||
version = 'v1.3.5'
|
||||
hash = 'sha256-AVM0rR81hgVAI0QVzlz4WijFUjByf6Zew3ZwuikKw2Q='
|
||||
|
||||
[mod.'github.com/corona10/goimagehash']
|
||||
version = 'v1.1.1-0.20240121134706-d8115886f360'
|
||||
hash = 'sha256-/corDVYILmy/DMWtgM1D1MK6I7pejA5JNfaxeojwkkA='
|
||||
|
||||
[mod.'github.com/davidscholberg/go-durationfmt']
|
||||
version = 'v0.0.0-20170122144659-64843a2083d3'
|
||||
hash = 'sha256-0rdbpBf3AAjMpxvVEGFb2ImgB2i7vdEhIwCyqJs1iHE='
|
||||
|
||||
[mod.'github.com/disintegration/imaging']
|
||||
version = 'v1.6.2'
|
||||
hash = 'sha256-pSeMTPvSkxlthh65LjNYYhPLvCZDkBgVgAGYWW0Aguo='
|
||||
|
||||
[mod.'github.com/dustin/go-humanize']
|
||||
version = 'v1.0.1'
|
||||
hash = 'sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc='
|
||||
|
||||
[mod.'github.com/ebitengine/oto/v3']
|
||||
version = 'v3.3.2'
|
||||
hash = 'sha256-TPu3qvJscLZbjwIqC3jj0T1md0mX3lQxcC8GAk7kB1w='
|
||||
|
||||
[mod.'github.com/ebitengine/purego']
|
||||
version = 'v0.9.1'
|
||||
hash = 'sha256-iVfU8vaJ7IPa92dUeHeuW+yKvUbe59F/eV7GlDRIAcE='
|
||||
|
||||
[mod.'github.com/ericpauley/go-quantize']
|
||||
version = 'v0.0.0-20200331213906-ae555eb2afa4'
|
||||
hash = 'sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs='
|
||||
|
||||
[mod.'github.com/fumiama/ahsai']
|
||||
version = 'v0.1.1'
|
||||
hash = 'sha256-knYw0R5fhjE/asc/TwlGJDzVr+Oaj8sH7kr7x6Mqs3E='
|
||||
|
||||
[mod.'github.com/fumiama/cron']
|
||||
version = 'v1.3.0'
|
||||
hash = 'sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k='
|
||||
|
||||
[mod.'github.com/fumiama/deepinfra']
|
||||
version = 'v0.0.0-20251221163610-e98ee3ba437a'
|
||||
hash = 'sha256-XubewUDOLaN7fgv9E8PAfP7DtADdLm+M2sgSn5OE6eQ='
|
||||
|
||||
[mod.'github.com/fumiama/go-base16384']
|
||||
version = 'v1.7.1'
|
||||
hash = 'sha256-Fd1QaeYx+3q4C3XQXlPFnDmKPsoZH6837fN/7rn8i9s='
|
||||
|
||||
[mod.'github.com/fumiama/go-onebot-agent']
|
||||
version = 'v0.0.0-20260128132028-05e6b4809f0a'
|
||||
hash = 'sha256-ratY7o52v0KuxgZC4wqHNXdgGXzliEecs8egE3SBLeo='
|
||||
|
||||
[mod.'github.com/fumiama/go-registry']
|
||||
version = 'v0.2.7'
|
||||
hash = 'sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA='
|
||||
|
||||
[mod.'github.com/fumiama/go-simple-protobuf']
|
||||
version = 'v0.2.0'
|
||||
hash = 'sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw='
|
||||
|
||||
[mod.'github.com/fumiama/gofastTEA']
|
||||
version = 'v0.1.3'
|
||||
hash = 'sha256-/Qu57mkkFt7aFufhlkMYPgrWj5XCGbuM28EHDD8w4XY='
|
||||
|
||||
[mod.'github.com/fumiama/gotracemoe']
|
||||
version = 'v0.0.3'
|
||||
hash = 'sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ='
|
||||
|
||||
[mod.'github.com/fumiama/imgsz']
|
||||
version = 'v0.0.4'
|
||||
hash = 'sha256-rrGx+v41OEl0ATwL6u5TNcpfkCQbj3jFNnGiQUNu2qs='
|
||||
|
||||
[mod.'github.com/fumiama/jieba']
|
||||
version = 'v0.0.0-20221203025406-36c17a10b565'
|
||||
hash = 'sha256-DvDx1pdldkdaSszrbadM/VwqT9TTSmWl6G6a+ysXYEM='
|
||||
|
||||
[mod.'github.com/fumiama/orbyte']
|
||||
version = 'v0.0.0-20251002065953-3bb358367eb5'
|
||||
hash = 'sha256-mRQwhR0v922UXlJ7lXo/osv21K8kZDaHx3DsBCjmzoo='
|
||||
|
||||
[mod.'github.com/fumiama/slowdo']
|
||||
version = 'v0.0.0-20241001074058-27c4fe5259a4'
|
||||
hash = 'sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY='
|
||||
|
||||
[mod.'github.com/fumiama/terasu']
|
||||
version = 'v1.0.2'
|
||||
hash = 'sha256-tYHvvfJT1/R4koqGFPjdU211Dcez2XWuvpRke/tFfQ8='
|
||||
|
||||
[mod.'github.com/fumiama/unibase2n']
|
||||
version = 'v0.0.0-20240530074540-ec743fd5a6d6'
|
||||
hash = 'sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw='
|
||||
|
||||
[mod.'github.com/gabriel-vasile/mimetype']
|
||||
version = 'v1.4.12'
|
||||
hash = 'sha256-vY2g58yUrkT//8fttRKhS9rbg89YSae/BzOARS5uH30='
|
||||
|
||||
[mod.'github.com/go-ole/go-ole']
|
||||
version = 'v1.2.6'
|
||||
hash = 'sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs='
|
||||
|
||||
[mod.'github.com/golang/freetype']
|
||||
version = 'v0.0.0-20170609003504-e2365dfdc4a0'
|
||||
hash = 'sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA='
|
||||
|
||||
[mod.'github.com/golang/groupcache']
|
||||
version = 'v0.0.0-20210331224755-41bb18bfe9da'
|
||||
hash = 'sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0='
|
||||
|
||||
[mod.'github.com/google/uuid']
|
||||
version = 'v1.6.0'
|
||||
hash = 'sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw='
|
||||
|
||||
[mod.'github.com/gopxl/beep/v2']
|
||||
version = 'v2.1.1'
|
||||
hash = 'sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU='
|
||||
|
||||
[mod.'github.com/guohuiyuan/music-lib']
|
||||
version = 'v1.0.2-0.20260121020416-53f6cb24629d'
|
||||
hash = 'sha256-juVJ/nh6zA5Gu5+dRzIx8tElXLscRQYwY9vLvVKh078='
|
||||
|
||||
[mod.'github.com/jfreymuth/oggvorbis']
|
||||
version = 'v1.0.5'
|
||||
hash = 'sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0='
|
||||
|
||||
[mod.'github.com/jfreymuth/vorbis']
|
||||
version = 'v1.0.2'
|
||||
hash = 'sha256-gVS+/PZ5pDnswpTQNZILcrx5ZNq9ShXd6vXn7Jabes4='
|
||||
|
||||
[mod.'github.com/jinzhu/gorm']
|
||||
version = 'v1.9.16'
|
||||
hash = 'sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc='
|
||||
|
||||
[mod.'github.com/jinzhu/inflection']
|
||||
version = 'v1.0.0'
|
||||
hash = 'sha256-3h3pHib5MaCXKyKLIMyQnSptDJ16kPjCOQPoEBoQsZg='
|
||||
|
||||
[mod.'github.com/jozsefsallai/gophersauce']
|
||||
version = 'v1.0.1'
|
||||
hash = 'sha256-29DsfnGmK51DPunR/leRBKCcokN/yLoB7S2HxCsqtgY='
|
||||
|
||||
[mod.'github.com/json-iterator/go']
|
||||
version = 'v1.1.12'
|
||||
hash = 'sha256-To8A0h+lbfZ/6zM+2PpRpY3+L6725OPC66lffq6fUoM='
|
||||
|
||||
[mod.'github.com/kanrichan/resvg-go']
|
||||
version = 'v0.0.2-0.20231001163256-63db194ca9f5'
|
||||
hash = 'sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds='
|
||||
|
||||
[mod.'github.com/lithammer/fuzzysearch']
|
||||
version = 'v1.1.8'
|
||||
hash = 'sha256-aMMRcrlUc9CBiiNkcnWWn4hfNMNyVhrAt67kvP4D4Do='
|
||||
|
||||
[mod.'github.com/liuzl/cedar-go']
|
||||
version = 'v0.0.0-20170805034717-80a9c64b256d'
|
||||
hash = 'sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0='
|
||||
|
||||
[mod.'github.com/liuzl/da']
|
||||
version = 'v0.0.0-20180704015230-14771aad5b1d'
|
||||
hash = 'sha256-J43kwDFmB6LzDhS3Ig/4ddZUTXz1cKztbTA3hILScs8='
|
||||
|
||||
[mod.'github.com/liuzl/gocc']
|
||||
version = 'v0.0.0-20231231122217-0372e1059ca5'
|
||||
hash = 'sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8='
|
||||
|
||||
[mod.'github.com/lufia/plan9stats']
|
||||
version = 'v0.0.0-20211012122336-39d0f177ccd0'
|
||||
hash = 'sha256-thb+rkDx5IeWMgw5/5jgu5gZ+6RjJAUXeMgSkJHhRlA='
|
||||
|
||||
[mod.'github.com/mattn/go-isatty']
|
||||
version = 'v0.0.20'
|
||||
hash = 'sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ='
|
||||
|
||||
[mod.'github.com/mmcdole/gofeed']
|
||||
version = 'v1.3.0'
|
||||
hash = 'sha256-GHpqGZvNg+3RSIkVKXrWg6/e8dJD8Y5v2Sx6MzmRlQ0='
|
||||
|
||||
[mod.'github.com/mmcdole/goxpp']
|
||||
version = 'v1.1.1-0.20240225020742-a0c311522b23'
|
||||
hash = 'sha256-2pGg+LxHHQn2lwQBvc7EtrpMwZbZF7qepglzhS3TfW4='
|
||||
|
||||
[mod.'github.com/modern-go/concurrent']
|
||||
version = 'v0.0.0-20180306012644-bacd9c7ef1dd'
|
||||
hash = 'sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo='
|
||||
|
||||
[mod.'github.com/modern-go/reflect2']
|
||||
version = 'v1.0.2'
|
||||
hash = 'sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU='
|
||||
|
||||
[mod.'github.com/mroth/weightedrand']
|
||||
version = 'v1.0.0'
|
||||
hash = 'sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c='
|
||||
|
||||
[mod.'github.com/ncruces/go-strftime']
|
||||
version = 'v1.0.0'
|
||||
hash = 'sha256-GYIwYDONuv/yTE0AEugCHQbtV3oiBaco93xUNYFcVBQ='
|
||||
|
||||
[mod.'github.com/nfnt/resize']
|
||||
version = 'v0.0.0-20180221191011-83c6a9932646'
|
||||
hash = 'sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA='
|
||||
|
||||
[mod.'github.com/notnil/chess']
|
||||
version = 'v1.10.0'
|
||||
hash = 'sha256-hsUOS4rVuMW+UCPJzhsZh3PHCi1Lol12BwKujcICayo='
|
||||
|
||||
[mod.'github.com/pbnjay/memory']
|
||||
version = 'v0.0.0-20210728143218-7b4eea64cf58'
|
||||
hash = 'sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA='
|
||||
|
||||
[mod.'github.com/pkg/errors']
|
||||
version = 'v0.9.1'
|
||||
hash = 'sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw='
|
||||
|
||||
[mod.'github.com/pkumza/numcn']
|
||||
version = 'v1.0.0'
|
||||
hash = 'sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg='
|
||||
|
||||
[mod.'github.com/power-devops/perfstat']
|
||||
version = 'v0.0.0-20240221224432-82ca36839d55'
|
||||
hash = 'sha256-ujzuJ1ttQgjHQJEij4O/2+I8DZaUVZQCQgA4ysfqulI='
|
||||
|
||||
[mod.'github.com/remyoudompheng/bigfft']
|
||||
version = 'v0.0.0-20230129092748-24d4a6f8daec'
|
||||
hash = 'sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM='
|
||||
|
||||
[mod.'github.com/shirou/gopsutil/v4']
|
||||
version = 'v4.25.12'
|
||||
hash = 'sha256-gzk9GW4+tXUWmxAVD3by/k4D/+l++TvajRVTkQJvwmM='
|
||||
|
||||
[mod.'github.com/sirupsen/logrus']
|
||||
version = 'v1.9.4'
|
||||
hash = 'sha256-ltRvmtM3XTCAFwY0IesfRqYIivyXPPuvkFjL4ARh1wg='
|
||||
|
||||
[mod.'github.com/tetratelabs/wazero']
|
||||
version = 'v1.5.0'
|
||||
hash = 'sha256-fGdJM4LJrZA9jxHuYVo4EUQ3I1k0IVG3QQCBCgZkeZI='
|
||||
|
||||
[mod.'github.com/tidwall/gjson']
|
||||
version = 'v1.18.0'
|
||||
hash = 'sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I='
|
||||
|
||||
[mod.'github.com/tidwall/match']
|
||||
version = 'v1.2.0'
|
||||
hash = 'sha256-O2wTU0SmNIEEOxfncl2BW2czgWeIW5vqR6+A7dtNtXI='
|
||||
|
||||
[mod.'github.com/tidwall/pretty']
|
||||
version = 'v1.2.1'
|
||||
hash = 'sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8='
|
||||
|
||||
[mod.'github.com/tklauser/go-sysconf']
|
||||
version = 'v0.3.16'
|
||||
hash = 'sha256-hNVbsk0G+M9bLtHNywPD0nCW0z/9pM4jQV53nnDo/MY='
|
||||
|
||||
[mod.'github.com/tklauser/numcpus']
|
||||
version = 'v0.11.0'
|
||||
hash = 'sha256-ObydGqAvRiHwVfO2ytmL28pRHyuCWYWwjH4hWdgI/Vs='
|
||||
|
||||
[mod.'github.com/wcharczuk/go-chart/v2']
|
||||
version = 'v2.1.2'
|
||||
hash = 'sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM='
|
||||
|
||||
[mod.'github.com/wdvxdr1123/ZeroBot']
|
||||
version = 'v1.8.3-0.20260117102541-393033a35adb'
|
||||
hash = 'sha256-Yz2OTU05kDZOHX8J04jX5Jg5ya9rwqsH0TySSBhMOp0='
|
||||
|
||||
[mod.'github.com/yusufpapurcu/wmi']
|
||||
version = 'v1.2.4'
|
||||
hash = 'sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA='
|
||||
|
||||
[mod.'gitlab.com/gomidi/midi/v2']
|
||||
version = 'v2.3.18'
|
||||
hash = 'sha256-lkU9M+h56+Ai/bpQDST3Su71dhjp1Vk2S7/okrELo7s='
|
||||
|
||||
[mod.'golang.org/x/image']
|
||||
version = 'v0.34.0'
|
||||
hash = 'sha256-7V1bDhd++dCw11DCXOAUb5f1Hj51EfS0DZ03pq0V/p0='
|
||||
|
||||
[mod.'golang.org/x/net']
|
||||
version = 'v0.48.0'
|
||||
hash = 'sha256-oZpddsiJwWCH3Aipa+XXpy7G/xHY5fEagUSok7T0bXE='
|
||||
|
||||
[mod.'golang.org/x/sys']
|
||||
version = 'v0.39.0'
|
||||
hash = 'sha256-dxTBu/JAWUkPbjFIXXRFdhQWyn+YyEpIC+tWqGo0Y6U='
|
||||
|
||||
[mod.'golang.org/x/text']
|
||||
version = 'v0.32.0'
|
||||
hash = 'sha256-9PXtWBKKY9rG4AgjSP4N+I1DhepXhy8SF/vWSIDIoWs='
|
||||
|
||||
[mod.'gopkg.in/yaml.v3']
|
||||
version = 'v3.0.1'
|
||||
hash = 'sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU='
|
||||
|
||||
[mod.'modernc.org/libc']
|
||||
version = 'v0.0.0-20240530081950-6f6d8586b5c5'
|
||||
hash = 'sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w='
|
||||
replaced = 'github.com/fumiama/libc'
|
||||
|
||||
[mod.'modernc.org/mathutil']
|
||||
version = 'v1.7.1'
|
||||
hash = 'sha256-COZ5rF2GhQVR1r6a0DanJ8qwQ94JSKdQxTMWrDzE0Cc='
|
||||
|
||||
[mod.'modernc.org/memory']
|
||||
version = 'v1.11.0'
|
||||
hash = 'sha256-MkybF8vvrxXS5j7O8w3skwTo0aMo1yjWS0K440rYcHM='
|
||||
|
||||
[mod.'modernc.org/sqlite']
|
||||
version = 'v1.29.10-simp'
|
||||
hash = 'sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE='
|
||||
replaced = 'github.com/fumiama/sqlite3'
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
package banner
|
||||
|
||||
// Version ...
|
||||
var Version = "v1.10.16"
|
||||
var Version = "v1.10.19"
|
||||
|
||||
// Copyright ...
|
||||
var Copyright = "© 2020 - 2026 FloatTech"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - 2026-01-17 21:00:49 +0800 CST\n" +
|
||||
"* Version " + Version + " - 2026-02-19 23:44:59 +0800 CST\n" +
|
||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
|
||||
1
main.go
1
main.go
@@ -104,6 +104,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/handou" // 猜成语
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hitokoto" // 一言
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
|
||||
|
||||
@@ -2,18 +2,104 @@
|
||||
package crypter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/airecord"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var faceTagRe = regexp.MustCompile(`\{\{face:(\d+)\}\}`)
|
||||
|
||||
func parseID(v interface{}) int64 {
|
||||
n, _ := strconv.ParseInt(fmt.Sprint(v), 10, 64)
|
||||
return n
|
||||
}
|
||||
|
||||
func serializeMsg(segs message.Message) string {
|
||||
var sb strings.Builder
|
||||
for _, seg := range segs {
|
||||
switch seg.Type {
|
||||
case "text":
|
||||
sb.WriteString(seg.Data["text"])
|
||||
case "face":
|
||||
fmt.Fprintf(&sb, "{{face:%v}}", seg.Data["id"])
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func deserializeMsg(s string) message.Message {
|
||||
var msg message.Message
|
||||
parts := faceTagRe.Split(s, -1)
|
||||
matches := faceTagRe.FindAllStringSubmatch(s, -1)
|
||||
for i, part := range parts {
|
||||
if part != "" {
|
||||
msg = append(msg, message.Text(part))
|
||||
}
|
||||
if i < len(matches) {
|
||||
id, _ := strconv.Atoi(matches[i][1])
|
||||
msg = append(msg, message.Face(id))
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func getInput(ctx *zero.Ctx, cmds ...string) string {
|
||||
full := serializeMsg(ctx.Event.Message)
|
||||
for _, cmd := range cmds {
|
||||
if idx := strings.Index(full, cmd); idx >= 0 {
|
||||
return strings.TrimSpace(full[idx+len(cmd):])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getReplyContent(ctx *zero.Ctx) string {
|
||||
for _, seg := range ctx.Event.Message {
|
||||
if seg.Type == "reply" {
|
||||
if msgID := parseID(seg.Data["id"]); msgID > 0 {
|
||||
if msg := ctx.GetMessage(msgID); msg.Elements != nil {
|
||||
return serializeMsg(msg.Elements)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getReplyFaceIDs(ctx *zero.Ctx) []int {
|
||||
for _, seg := range ctx.Event.Message {
|
||||
if seg.Type == "reply" {
|
||||
if msgID := parseID(seg.Data["id"]); msgID > 0 {
|
||||
return extractFaceIDs(ctx.GetMessage(msgID).Elements)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractFaceIDs(segs message.Message) []int {
|
||||
var ids []int
|
||||
for _, seg := range segs {
|
||||
if seg.Type == "face" {
|
||||
if id := int(parseID(seg.Data["id"])); id > 0 {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// hou
|
||||
func houEncryptHandler(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[1]
|
||||
text := getInput(ctx, "h加密", "齁语加密")
|
||||
result := encodeHou(text)
|
||||
recCfg := airecord.GetConfig()
|
||||
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result)
|
||||
if record != "" {
|
||||
if record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result); record != "" {
|
||||
ctx.SendChain(message.Record(record))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(result))
|
||||
@@ -21,20 +107,52 @@ func houEncryptHandler(ctx *zero.Ctx) {
|
||||
}
|
||||
|
||||
func houDecryptHandler(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[1]
|
||||
result := decodeHou(text)
|
||||
ctx.SendChain(message.Text(result))
|
||||
text := getInput(ctx, "h解密", "齁语解密")
|
||||
if text == "" {
|
||||
text = getReplyContent(ctx)
|
||||
}
|
||||
if text == "" {
|
||||
ctx.SendChain(message.Text("请输入密文或回复加密消息"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(deserializeMsg(decodeHou(text))...)
|
||||
}
|
||||
|
||||
// fumo
|
||||
func fumoEncryptHandler(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[1]
|
||||
result := encryptFumo(text)
|
||||
ctx.SendChain(message.Text(result))
|
||||
ctx.SendChain(message.Text(encryptFumo(getInput(ctx, "fumo加密"))))
|
||||
}
|
||||
|
||||
func fumoDecryptHandler(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[1]
|
||||
result := decryptFumo(text)
|
||||
ctx.SendChain(message.Text(result))
|
||||
text := getInput(ctx, "fumo解密")
|
||||
if text == "" {
|
||||
text = getReplyContent(ctx)
|
||||
}
|
||||
if text == "" {
|
||||
ctx.SendChain(message.Text("请输入密文或回复加密消息"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(deserializeMsg(decryptFumo(text))...)
|
||||
}
|
||||
|
||||
// qq表情
|
||||
func qqEmojiEncryptHandler(ctx *zero.Ctx) {
|
||||
text := getInput(ctx, "qq加密")
|
||||
if text == "" {
|
||||
ctx.SendChain(message.Text("请输入要加密的文本"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(encodeQQEmoji(text)...)
|
||||
}
|
||||
|
||||
func qqEmojiDecryptHandler(ctx *zero.Ctx) {
|
||||
faceIDs := extractFaceIDs(ctx.Event.Message)
|
||||
if len(faceIDs) == 0 {
|
||||
faceIDs = getReplyFaceIDs(ctx)
|
||||
}
|
||||
if len(faceIDs) == 0 {
|
||||
ctx.SendChain(message.Text("请回复QQ表情加密消息进行解密"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(deserializeMsg(decodeQQEmoji(faceIDs))...)
|
||||
}
|
||||
|
||||
@@ -17,15 +17,25 @@ func init() {
|
||||
"- 齁语解密 [密文] 或 h解密 [密文]\n\n" +
|
||||
"- Fumo语加解密:\n" +
|
||||
"- fumo加密 [文本]\n" +
|
||||
"- fumo解密 [密文]\n\n",
|
||||
"- fumo解密 [密文]\n\n" +
|
||||
"- QQ表情加解密:\n" +
|
||||
"- qq加密 [文本]\n" +
|
||||
"- qq解密 [密文]\n\n" +
|
||||
"注意:QQ表情解密建议使用回复,尽量不要复制粘贴\n\n",
|
||||
PublicDataFolder: "Crypter",
|
||||
})
|
||||
|
||||
re := `(?:\[CQ:reply,id=-?\d+\])?`
|
||||
|
||||
// hou
|
||||
engine.OnRegex(`^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
|
||||
engine.OnRegex(`^(?:齁语解密|h解密)\s*(.+)$`).SetBlock(true).Handle(houDecryptHandler)
|
||||
engine.OnRegex(re + `^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
|
||||
engine.OnRegex(re + `(?:齁语解密|h解密)\s*(.*)$`).SetBlock(true).Handle(houDecryptHandler)
|
||||
|
||||
// Fumo
|
||||
engine.OnRegex(`^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
|
||||
engine.OnRegex(`^fumo解密\s*(.+)$`).SetBlock(true).Handle(fumoDecryptHandler)
|
||||
engine.OnRegex(re + `^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
|
||||
engine.OnRegex(re + `fumo解密\s*(.*)$`).SetBlock(true).Handle(fumoDecryptHandler)
|
||||
|
||||
// QQ表情
|
||||
engine.OnRegex(re + `^qq加密\s*(.+)$`).SetBlock(true).Handle(qqEmojiEncryptHandler)
|
||||
engine.OnRegex(re + `qq解密`).SetBlock(true).Handle(qqEmojiDecryptHandler)
|
||||
}
|
||||
|
||||
66
plugin/crypter/qqemoji.go
Normal file
66
plugin/crypter/qqemoji.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Package crypter QQ表情加解密
|
||||
package crypter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
emojiZeroID = 297
|
||||
emojiOneID = 424
|
||||
)
|
||||
|
||||
func encodeQQEmoji(text string) message.Message {
|
||||
if text == "" {
|
||||
return message.Message{message.Text("请输入要加密的文本")}
|
||||
}
|
||||
|
||||
var bin strings.Builder
|
||||
for _, b := range []byte(text) {
|
||||
fmt.Fprintf(&bin, "%08b", b)
|
||||
}
|
||||
|
||||
s := bin.String()
|
||||
msg := make(message.Message, 0, len(s))
|
||||
for _, bit := range s {
|
||||
if bit == '0' {
|
||||
msg = append(msg, message.Face(emojiZeroID))
|
||||
} else {
|
||||
msg = append(msg, message.Face(emojiOneID))
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func decodeQQEmoji(faceIDs []int) string {
|
||||
var bin strings.Builder
|
||||
for _, id := range faceIDs {
|
||||
if id == emojiZeroID {
|
||||
bin.WriteByte('0')
|
||||
} else if id == emojiOneID {
|
||||
bin.WriteByte('1')
|
||||
}
|
||||
}
|
||||
binary := bin.String()
|
||||
if len(binary) == 0 || len(binary)%8 != 0 {
|
||||
return "QQ表情密文格式错误"
|
||||
}
|
||||
|
||||
data := make([]byte, len(binary)/8)
|
||||
for i := range data {
|
||||
for j := 0; j < 8; j++ {
|
||||
if binary[i*8+j] == '1' {
|
||||
data[i] |= 1 << (7 - j)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !utf8.Valid(data) {
|
||||
return "QQ表情解密失败:结果不是有效文本"
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
182
plugin/handou/baiAPI.go
Normal file
182
plugin/handou/baiAPI.go
Normal file
@@ -0,0 +1,182 @@
|
||||
// Package handou 猜成语
|
||||
package handou
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type baiduAPIData struct {
|
||||
Errno int `json:"errno"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
Data struct {
|
||||
IdiomVersion int `json:"idiomVersion"`
|
||||
Name string `json:"name"`
|
||||
Sid string `json:"sid"`
|
||||
Type string `json:"type"`
|
||||
LessonInfo any `json:"lessonInfo"`
|
||||
RelationInfo struct {
|
||||
RelationName string `json:"relationName"`
|
||||
RelationList []struct {
|
||||
Name string `json:"name"`
|
||||
Imgs []string `json:"imgs"`
|
||||
} `json:"relationList"`
|
||||
} `json:"relationInfo"`
|
||||
Imgs []string `json:"imgs"`
|
||||
Definition []struct {
|
||||
Pinyin string `json:"pinyin"`
|
||||
Voice string `json:"voice"`
|
||||
Definition []string `json:"definition"`
|
||||
DetailDefinition any `json:"detailDefinition"`
|
||||
} `json:"definition"`
|
||||
DefinitionInfo struct {
|
||||
Definition string `json:"definition"`
|
||||
SimilarDefinition string `json:"similarDefinition"`
|
||||
AncientDefinition string `json:"ancientDefinition"`
|
||||
ModernDefinition string `json:"modernDefinition"`
|
||||
DetailMeans []struct {
|
||||
Word string `json:"word"`
|
||||
Definition string `json:"definition"`
|
||||
} `json:"detailMeans"`
|
||||
UsageTips any `json:"usageTips"`
|
||||
Yicuodian any `json:"yicuodian"`
|
||||
Baobian string `json:"baobian"`
|
||||
WordFormation string `json:"wordFormation"`
|
||||
} `json:"definitionInfo"`
|
||||
Liju []struct {
|
||||
Name string `json:"name"`
|
||||
ShowName string `json:"showName"`
|
||||
} `json:"liju"`
|
||||
Source string `json:"source"`
|
||||
Story any `json:"story"`
|
||||
Antonym []struct {
|
||||
Name string `json:"name"`
|
||||
IsClick bool `json:"isClick"`
|
||||
} `json:"antonym"`
|
||||
Synonym []string `json:"synonym"`
|
||||
Synonyms []struct {
|
||||
Name string `json:"name"`
|
||||
IsClick bool `json:"isClick"`
|
||||
} `json:"synonyms"`
|
||||
Tongyiyixing []struct {
|
||||
Name string `json:"name"`
|
||||
IsClick bool `json:"isClick"`
|
||||
} `json:"tongyiyixing"`
|
||||
ChuChu []struct {
|
||||
SourceChapter string `json:"sourceChapter"`
|
||||
Source string `json:"source"`
|
||||
Dynasty string `json:"dynasty"`
|
||||
CiteOriginalText string `json:"citeOriginalText"`
|
||||
Author string `json:"author"`
|
||||
} `json:"chuChu"`
|
||||
YinZheng []struct {
|
||||
SourceChapter string `json:"sourceChapter"`
|
||||
Source string `json:"source"`
|
||||
Dynasty string `json:"dynasty"`
|
||||
CiteOriginalText string `json:"citeOriginalText"`
|
||||
Author string `json:"author"`
|
||||
} `json:"yinZheng"`
|
||||
PictureList []any `json:"pictureList"`
|
||||
LessonTerms struct {
|
||||
TermList any `json:"termList"`
|
||||
HasTerms int `json:"hasTerms"`
|
||||
} `json:"lessonTerms"`
|
||||
LessonTermsNew struct {
|
||||
TermList any `json:"termList"`
|
||||
HasTerms int `json:"hasTerms"`
|
||||
} `json:"lessonTermsNew"`
|
||||
Baobian string `json:"baobian"`
|
||||
Structure string `json:"structure"`
|
||||
Pinyin string `json:"pinyin"`
|
||||
Voice string `json:"voice"`
|
||||
ZuowenQuery string `json:"zuowen_query"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func geiAPIdata(s string) (*idiomJSON, error) {
|
||||
url := "https://hanyuapp.baidu.com/dictapp/swan/termdetail?wd=" + url.QueryEscape(s) + "&client=pc&source_tag=2&lesson_from=xiaodu"
|
||||
logrus.Debugln(url)
|
||||
data, err := web.GetData(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiData baiduAPIData
|
||||
err = json.Unmarshal(data, &apiData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if apiData.Data.Name == "" {
|
||||
return nil, errors.New("未找到该成语")
|
||||
}
|
||||
derivation := ""
|
||||
for _, v := range apiData.Data.ChuChu {
|
||||
if derivation != "" {
|
||||
derivation += "\n"
|
||||
}
|
||||
derivation += v.Dynasty + "·" + v.Author + " " + v.Source + ":" + v.CiteOriginalText
|
||||
}
|
||||
|
||||
explanation := apiData.Data.DefinitionInfo.Definition + apiData.Data.DefinitionInfo.ModernDefinition
|
||||
if derivation == "" && explanation == "" {
|
||||
return nil, errors.New("无法获取成语词源和解释")
|
||||
}
|
||||
synonyms := make([]string, len(apiData.Data.Synonyms))
|
||||
for i, synonym := range apiData.Data.Synonyms {
|
||||
synonyms[i] = synonym.Name
|
||||
}
|
||||
for i, synonym := range apiData.Data.Synonym {
|
||||
if !slices.Contains(synonyms, synonym) {
|
||||
synonyms[i] = synonym
|
||||
}
|
||||
}
|
||||
liju := ""
|
||||
if len(apiData.Data.Liju) > 0 {
|
||||
liju = apiData.Data.Liju[0].Name
|
||||
}
|
||||
|
||||
// 生成字符切片
|
||||
chars := make([]string, 0, len(s))
|
||||
for _, r := range s {
|
||||
chars = append(chars, string(r))
|
||||
}
|
||||
// 分割拼音
|
||||
pinyinSlice := strings.Split(apiData.Data.Pinyin, " ")
|
||||
if len(pinyinSlice) != len(chars) {
|
||||
pinyinSlice = strings.Split(apiData.Data.Definition[0].Pinyin, " ")
|
||||
}
|
||||
|
||||
newIdiom := idiomJSON{
|
||||
Word: apiData.Data.Name,
|
||||
Chars: chars,
|
||||
Pinyin: pinyinSlice,
|
||||
Baobian: apiData.Data.Baobian,
|
||||
Explanation: explanation,
|
||||
Derivation: derivation,
|
||||
Example: liju,
|
||||
Abbreviation: apiData.Data.Structure,
|
||||
Synonyms: synonyms,
|
||||
}
|
||||
return &newIdiom, nil
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
func saveIdiomJSON() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
f, err := os.Create(idiomFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return json.NewEncoder(f).Encode(&idiomInfoMap)
|
||||
}
|
||||
676
plugin/handou/game.go
Normal file
676
plugin/handou/game.go
Normal file
@@ -0,0 +1,676 @@
|
||||
// Package handou 猜成语
|
||||
package handou
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/gg"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type idiomJSON struct {
|
||||
Word string `json:"word"` // 成语
|
||||
Chars []string `json:"chars"` // 成语
|
||||
Pinyin []string `json:"pinyin"` // 拼音
|
||||
Baobian string `json:"baobian"` // 褒贬义
|
||||
Explanation string `json:"explanation"` // 解释
|
||||
Derivation string `json:"derivation"` // 词源
|
||||
Example string `json:"example"` // 例句
|
||||
Abbreviation string `json:"abbreviation"` // 结构
|
||||
Synonyms []string `json:"synonyms"` // 近义词
|
||||
}
|
||||
|
||||
const (
|
||||
kong = rune(' ')
|
||||
pinFontSize = 45.0
|
||||
hanFontSize = 150.0
|
||||
)
|
||||
|
||||
const (
|
||||
match = iota
|
||||
exist
|
||||
notexist
|
||||
blockmatch
|
||||
blockexist
|
||||
)
|
||||
|
||||
var colors = [...]color.RGBA{
|
||||
{0, 153, 0, 255},
|
||||
{255, 128, 0, 255},
|
||||
{123, 123, 123, 255},
|
||||
{125, 166, 108, 255},
|
||||
{199, 183, 96, 255},
|
||||
}
|
||||
|
||||
var (
|
||||
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "猜成语",
|
||||
Help: "- 个人猜成语\n" +
|
||||
"- 团队猜成语\n",
|
||||
PublicDataFolder: "Handou",
|
||||
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||
userHabitsFile = file.BOTPATH + "/" + en.DataFolder() + "userHabits.json"
|
||||
idiomFilePath = file.BOTPATH + "/" + en.DataFolder() + "idiom.json"
|
||||
initialized = fcext.DoOnceOnSuccess(
|
||||
func(ctx *zero.Ctx) bool {
|
||||
idiomFile, err := en.GetLazyData("idiom.json", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 下载字典时发生错误.\n", err))
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(idiomFile, &idiomInfoMap)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 解析字典时发生错误.\n", err))
|
||||
return false
|
||||
}
|
||||
habitsIdiomKeys = make([]string, 0, len(idiomInfoMap))
|
||||
for k := range idiomInfoMap {
|
||||
habitsIdiomKeys = append(habitsIdiomKeys, k)
|
||||
}
|
||||
// 构建用户习惯库(全局高频N-gram)
|
||||
err = initUserHabits()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 构建用户习惯库时发生错误.\n", err))
|
||||
return false
|
||||
}
|
||||
// 下载字体
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 加载字体时发生错误.\n", err))
|
||||
return false
|
||||
}
|
||||
pinyinFont = data
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
pinyinFont []byte
|
||||
idiomInfoMap = make(map[string]idiomJSON)
|
||||
habitsIdiomKeys = make([]string, 0)
|
||||
|
||||
errHadGuessed = errors.New("had guessed")
|
||||
errLengthNotEnough = errors.New("length not enough")
|
||||
errUnknownWord = errors.New("unknown word")
|
||||
errTimesRunOut = errors.New("times run out")
|
||||
)
|
||||
|
||||
func init() {
|
||||
en.OnRegex(`^猜成语热门(汉字|成语)$`, zero.OnlyGroup, initialized).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
if ctx.State["regex_matched"].([]string)[1] == "汉字" {
|
||||
topChars := getTopCharacters(10)
|
||||
ctx.SendChain(message.Text("热门汉字:\n", strings.Join(topChars, "\n")))
|
||||
} else {
|
||||
topIdioms := getTopIdioms(10)
|
||||
ctx.SendChain(message.Text("热门成语:\n", strings.Join(topIdioms, "\n")))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^(个人|团队)猜成语$`, zero.OnlyGroup, initialized).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
target := poolIdiom()
|
||||
idiomData := idiomInfoMap[target]
|
||||
game := newHandouGame(idiomData)
|
||||
_, img, _ := game("")
|
||||
anser := anserOutString(idiomData)
|
||||
worldLength := len(idiomData.Chars)
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
message.Text("你有", 7, "次机会猜出", worldLength, "字成语\n首字拼音为:", idiomData.Pinyin[0]),
|
||||
),
|
||||
)
|
||||
var next *zero.FutureEvent
|
||||
if ctx.State["regex_matched"].([]string)[1] == "个人" {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([\p{Han},,]){%d}$`, worldLength)),
|
||||
zero.OnlyGroup, ctx.CheckSession())
|
||||
} else {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([\p{Han},,]){%d}$`, worldLength)),
|
||||
zero.OnlyGroup, zero.CheckGroup(ctx.Event.GroupID))
|
||||
}
|
||||
var err error
|
||||
var win bool
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
tick := time.NewTimer(105 * time.Second)
|
||||
after := time.NewTimer(120 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
ctx.SendChain(message.Text("猜成语,你还有15s作答时间"))
|
||||
case <-after.C:
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("猜成语超时,游戏结束...\n答案是: ", anser),
|
||||
),
|
||||
)
|
||||
return
|
||||
case c := <-recv:
|
||||
tick.Reset(105 * time.Second)
|
||||
after.Reset(120 * time.Second)
|
||||
err = updateHabits(c.Event.Message.String())
|
||||
if err != nil {
|
||||
logrus.Warn("更新用户习惯库时发生错误: ", err)
|
||||
}
|
||||
win, img, err = game(c.Event.Message.String())
|
||||
switch {
|
||||
case win:
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
message.Text("太棒了,你猜出来了!\n答案是: ", anser),
|
||||
),
|
||||
)
|
||||
return
|
||||
case err == errTimesRunOut:
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
message.Text("游戏结束...\n答案是: ", anser),
|
||||
),
|
||||
)
|
||||
return
|
||||
case err == errLengthNotEnough:
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("成语长度错误"),
|
||||
),
|
||||
)
|
||||
case err == errHadGuessed:
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("该成语已经猜过了"),
|
||||
),
|
||||
)
|
||||
case err == errUnknownWord:
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("你确定存在这样的成语吗?"),
|
||||
),
|
||||
)
|
||||
default:
|
||||
if img != nil {
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("回答错误。"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func poolIdiom() string {
|
||||
prioritizedData := prioritizeData(habitsIdiomKeys)
|
||||
if len(prioritizedData) > 0 {
|
||||
return prioritizedData[rand.Intn(len(prioritizedData))]
|
||||
}
|
||||
// 如果没有优先级数据,则随机选择一个成语
|
||||
keys := make([]string, 0, len(idiomInfoMap))
|
||||
for k := range idiomInfoMap {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys[rand.Intn(len(keys))]
|
||||
}
|
||||
|
||||
func newHandouGame(target idiomJSON) func(string) (bool, []byte, error) {
|
||||
var (
|
||||
class = len(target.Chars)
|
||||
words = target.Word
|
||||
chars = target.Chars
|
||||
pinyin = target.Pinyin
|
||||
|
||||
tickTruePinyin = make([]string, class)
|
||||
tickExistChars = make([]string, class)
|
||||
tickExistPinyin = make([]string, 0, class)
|
||||
|
||||
record = make([]string, 0, 7)
|
||||
)
|
||||
// 初始化 tick, 第一个是已知的拼音
|
||||
for i := range class {
|
||||
if i == 0 {
|
||||
tickTruePinyin[i] = pinyin[0]
|
||||
} else {
|
||||
tickTruePinyin[i] = ""
|
||||
}
|
||||
tickExistChars[i] = "?"
|
||||
}
|
||||
|
||||
return func(s string) (win bool, data []byte, err error) {
|
||||
answer := []rune(s)
|
||||
var answerData idiomJSON
|
||||
|
||||
if s != "" {
|
||||
if words == s {
|
||||
win = true
|
||||
}
|
||||
|
||||
if len(answer) != len(chars) {
|
||||
err = errLengthNotEnough
|
||||
return
|
||||
}
|
||||
if slices.Contains(record, s) {
|
||||
err = errHadGuessed
|
||||
return
|
||||
}
|
||||
|
||||
answerInfo, ok := idiomInfoMap[s]
|
||||
if !ok {
|
||||
newIdiom, err1 := geiAPIdata(s)
|
||||
if err1 != nil {
|
||||
logrus.Debugln("通过API获取成语信息时发生错误: ", err1)
|
||||
err = errUnknownWord
|
||||
return
|
||||
}
|
||||
logrus.Debugln("通过API获取成语信息: ", newIdiom.Word)
|
||||
if newIdiom.Word != "" {
|
||||
idiomInfoMap[newIdiom.Word] = *newIdiom
|
||||
go func() { _ = saveIdiomJSON() }()
|
||||
}
|
||||
if newIdiom.Word != s {
|
||||
err = errUnknownWord
|
||||
return
|
||||
}
|
||||
answerData = *newIdiom
|
||||
} else {
|
||||
answerData = answerInfo
|
||||
}
|
||||
if len(record) >= 6 || win {
|
||||
// 结束了显示答案
|
||||
tickTruePinyin = target.Pinyin
|
||||
tickExistChars = target.Chars
|
||||
} else {
|
||||
// 处理汉字匹配逻辑
|
||||
for i := range class {
|
||||
char := answerData.Chars[i]
|
||||
if char == chars[i] {
|
||||
tickExistChars[i] = char
|
||||
} else {
|
||||
tickExistChars[i] = "?"
|
||||
}
|
||||
}
|
||||
|
||||
// 确保 tickExistPinyin 有足够的长度
|
||||
if len(tickExistPinyin) < class {
|
||||
for i := len(tickExistPinyin); i < class; i++ {
|
||||
tickExistPinyin = append(tickExistPinyin, "")
|
||||
}
|
||||
}
|
||||
|
||||
// 处理拼音匹配逻辑
|
||||
minPinyinLen := min(len(pinyin), len(answerData.Pinyin))
|
||||
for i := range minPinyinLen {
|
||||
pyChar := pinyin[i]
|
||||
answerPinyinChar := []rune(pyChar)
|
||||
tickTruePinyinChar := make([]rune, len(answerPinyinChar))
|
||||
tickExistPinyinChar := []rune(tickExistPinyin[i])
|
||||
|
||||
if tickTruePinyin[i] != "" {
|
||||
copy(tickTruePinyinChar, []rune(tickTruePinyin[i]))
|
||||
} else {
|
||||
for k := range answerPinyinChar {
|
||||
tickTruePinyinChar[k] = kong
|
||||
}
|
||||
}
|
||||
|
||||
PinyinChar := answerData.Pinyin[i]
|
||||
for j, c := range []rune(PinyinChar) {
|
||||
if c == kong {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case j < len(answerPinyinChar) && c == answerPinyinChar[j]:
|
||||
tickTruePinyinChar[j] = c
|
||||
case slices.Contains(answerPinyinChar, c):
|
||||
// 如果字符存在但位置不对,添加到 tickExistPinyinChar
|
||||
if !slices.Contains(tickExistPinyinChar, c) {
|
||||
tickExistPinyinChar = append(tickExistPinyinChar, c)
|
||||
}
|
||||
default:
|
||||
if j < len(tickTruePinyinChar) {
|
||||
tickTruePinyinChar[j] = kong
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理提示逻辑,将非匹配位置设为下划线
|
||||
matchIndex := -1
|
||||
for j, v := range tickTruePinyinChar {
|
||||
if v != kong && v != '_' {
|
||||
matchIndex = j
|
||||
}
|
||||
}
|
||||
for j := range tickTruePinyinChar {
|
||||
if j > matchIndex {
|
||||
break
|
||||
}
|
||||
if tickTruePinyinChar[j] == kong {
|
||||
tickTruePinyinChar[j] = '_'
|
||||
}
|
||||
}
|
||||
// 更新提示拼音
|
||||
tickTruePinyin[i] = string(tickTruePinyinChar)
|
||||
tickExistPinyin[i] = string(tickExistPinyinChar)
|
||||
}
|
||||
if len(record) >= 2 {
|
||||
tickTruePinyin[0] = pinyin[0]
|
||||
tickExistChars[0] = chars[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 准备绘制数据
|
||||
existPinyin := make([]string, 0, class)
|
||||
for _, v := range tickExistPinyin {
|
||||
if v != "" {
|
||||
v = "?" + v
|
||||
}
|
||||
existPinyin = append(existPinyin, v)
|
||||
}
|
||||
tickIdiom := idiomJSON{
|
||||
Chars: tickExistChars,
|
||||
Pinyin: tickTruePinyin,
|
||||
}
|
||||
|
||||
// 确保所有切片长度一致
|
||||
if len(tickIdiom.Chars) < class {
|
||||
// 如果答案字符数不足,用问号填充
|
||||
for i := len(tickIdiom.Chars); i < class; i++ {
|
||||
tickIdiom.Chars = append(tickIdiom.Chars, "?")
|
||||
}
|
||||
}
|
||||
if len(tickIdiom.Pinyin) < class {
|
||||
// 如果答案拼音数不足,用空字符串填充
|
||||
for i := len(tickIdiom.Pinyin); i < class; i++ {
|
||||
tickIdiom.Pinyin = append(tickIdiom.Pinyin, "")
|
||||
}
|
||||
}
|
||||
|
||||
if s == "" {
|
||||
answerData = tickIdiom
|
||||
}
|
||||
|
||||
var (
|
||||
tickImage image.Image
|
||||
answerImage image.Image
|
||||
imgHistery = make([]image.Image, 0)
|
||||
hisH = 0
|
||||
wg = &sync.WaitGroup{}
|
||||
)
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
tickImage = drawHanBlock(hanFontSize/2, pinFontSize/2, tickIdiom, target, existPinyin...)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
answerImage = drawHanBlock(hanFontSize, pinFontSize, answerData, target)
|
||||
}()
|
||||
if len(record) > 0 {
|
||||
wg.Add(len(record))
|
||||
for i, v := range record {
|
||||
imgHistery = append(imgHistery, nil)
|
||||
go func(i int, v string) {
|
||||
defer wg.Done()
|
||||
idiom, ok := idiomInfoMap[v]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
hisImage := drawHanBlock(hanFontSize/3, pinFontSize/3, idiom, target)
|
||||
imgHistery[i] = hisImage
|
||||
if i == 0 {
|
||||
hisH = hisImage.Bounds().Dy()
|
||||
}
|
||||
}(i, v)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// 记录猜过的成语
|
||||
if s != "" && !win {
|
||||
record = append(record, s)
|
||||
}
|
||||
|
||||
if tickImage == nil || answerImage == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tickW, tickH := tickImage.Bounds().Dx(), tickImage.Bounds().Dy()
|
||||
answerW, answerH := answerImage.Bounds().Dx(), answerImage.Bounds().Dy()
|
||||
|
||||
ctx := gg.NewContext(1, 1)
|
||||
_ = ctx.ParseFontFace(pinyinFont, pinFontSize/2)
|
||||
wordH, _ := ctx.MeasureString("M")
|
||||
|
||||
ctxWidth := max(tickW, answerW)
|
||||
ctxHeight := tickH + answerH + int(wordH) + hisH*(len(imgHistery)+1)/2
|
||||
|
||||
ctx = gg.NewContext(ctxWidth, ctxHeight)
|
||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||
ctx.Clear()
|
||||
|
||||
ctx.SetColor(color.RGBA{0, 0, 0, 255})
|
||||
_ = ctx.ParseFontFace(pinyinFont, hanFontSize/2)
|
||||
ctx.DrawStringAnchored("题目:", float64(ctxWidth-tickW)/4, float64(tickH)/2, 0.5, 0.5)
|
||||
|
||||
ctx.DrawImageAnchored(tickImage, ctxWidth/2, tickH/2, 0.5, 0.5)
|
||||
ctx.DrawImageAnchored(answerImage, ctxWidth/2, tickH+int(wordH)+answerH/2, 0.5, 0.5)
|
||||
|
||||
k := 0
|
||||
for i, v := range imgHistery {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
x := ctxWidth / 4
|
||||
y := tickH + int(wordH) + answerH + hisH*k
|
||||
|
||||
if i%2 == 1 {
|
||||
x = ctxWidth * 3 / 4
|
||||
y = tickH + int(wordH) + answerH + hisH*k
|
||||
k++
|
||||
}
|
||||
ctx.DrawImageAnchored(v, x, y+hisH/2, 0.5, 0.5)
|
||||
}
|
||||
|
||||
data, err = imgfactory.ToBytes(ctx.Image())
|
||||
if len(record) >= cap(record) {
|
||||
err = errTimesRunOut
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// drawHanBlock 绘制汉字方块,支持多行显示(6字以上时分成两行)
|
||||
func drawHanBlock(hanFontSize, pinFontSize float64, idiom, target idiomJSON, exitPinyin ...string) image.Image {
|
||||
class := len(target.Chars)
|
||||
|
||||
// 确保切片长度一致
|
||||
if len(idiom.Chars) < class {
|
||||
temp := make([]string, class)
|
||||
copy(temp, idiom.Chars)
|
||||
for i := len(idiom.Chars); i < class; i++ {
|
||||
temp[i] = "?"
|
||||
}
|
||||
idiom.Chars = temp
|
||||
}
|
||||
if len(idiom.Pinyin) < class {
|
||||
temp := make([]string, class)
|
||||
copy(temp, idiom.Pinyin)
|
||||
for i := len(idiom.Pinyin); i < class; i++ {
|
||||
temp[i] = ""
|
||||
}
|
||||
idiom.Pinyin = temp
|
||||
}
|
||||
|
||||
chars := idiom.Chars
|
||||
pinyin := idiom.Pinyin
|
||||
|
||||
// 确定行数和每行字数
|
||||
rows := 1
|
||||
charsPerRow := class
|
||||
if class > 6 {
|
||||
rows = 2
|
||||
charsPerRow = (class + 1) / 2
|
||||
}
|
||||
|
||||
ctx := gg.NewContext(1, 1)
|
||||
_ = ctx.ParseFontFace(pinyinFont, pinFontSize)
|
||||
pinWidth, pinHeight := ctx.MeasureString("w")
|
||||
_ = ctx.ParseFontFace(pinyinFont, hanFontSize)
|
||||
hanWidth, hanHeight := ctx.MeasureString("拼")
|
||||
|
||||
space := int(pinHeight / 2)
|
||||
blockPinWidth := int(pinWidth*6) + space
|
||||
boxPadding := math.Min(math.Abs(float64(blockPinWidth)-hanWidth)/2, hanHeight*0.3)
|
||||
|
||||
// 计算总宽度和高度
|
||||
width := space + charsPerRow*blockPinWidth + space
|
||||
height := space + rows*(int(pinHeight+hanHeight+boxPadding*2)+space*2) + space
|
||||
if len(exitPinyin) > 0 {
|
||||
height = space + rows*(int(pinHeight+hanHeight+boxPadding*2+pinHeight)+space*2) + space
|
||||
}
|
||||
|
||||
ctx = gg.NewContext(width, height)
|
||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||
ctx.Clear()
|
||||
|
||||
for i := range class {
|
||||
// 边界检查
|
||||
if i >= len(chars) || i >= len(pinyin) || i >= len(target.Pinyin) || i >= len(target.Chars) {
|
||||
break
|
||||
}
|
||||
|
||||
// 计算当前字符在哪一行哪一列
|
||||
idiomRows := 0
|
||||
col := i
|
||||
if rows > 1 {
|
||||
idiomRows = i / charsPerRow
|
||||
col = i % charsPerRow
|
||||
}
|
||||
|
||||
x := float64(space + col*blockPinWidth)
|
||||
// 如果上一层字数是奇数就额外移位
|
||||
if idiomRows%2 == 1 {
|
||||
x += float64(blockPinWidth) / 2
|
||||
}
|
||||
y := float64(idiomRows*(int(pinHeight+hanHeight+boxPadding*2)+space*2) + space)
|
||||
if len(exitPinyin) > 0 {
|
||||
y = float64(idiomRows*(int(pinHeight+hanHeight+boxPadding*2+pinHeight)+space*2) + space)
|
||||
}
|
||||
|
||||
// 绘制拼音
|
||||
_ = ctx.ParseFontFace(pinyinFont, pinFontSize)
|
||||
if i < len(pinyin) {
|
||||
targetPinyinByte := []rune(target.Pinyin[i])
|
||||
pinyinByte := []rune(pinyin[i])
|
||||
|
||||
// 取两者中的最大长度
|
||||
pinTotalWidth := pinWidth * float64(len(pinyinByte))
|
||||
pinX := x + float64(blockPinWidth)/2 - pinTotalWidth/2
|
||||
pinY := y + pinHeight/2
|
||||
|
||||
for k, ch := range pinyinByte {
|
||||
ctx.SetColor(colors[notexist])
|
||||
for m, c := range targetPinyinByte {
|
||||
if k == m && ch == c {
|
||||
ctx.SetColor(colors[match])
|
||||
break
|
||||
} else if ch == c {
|
||||
ctx.SetColor(colors[exist])
|
||||
}
|
||||
}
|
||||
ctx.DrawStringAnchored(string(ch), pinX+pinWidth*float64(k)+pinWidth/2, pinY, 0.5, 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制汉字方框
|
||||
boxX := x + boxPadding
|
||||
boxY := y + pinHeight + float64(space)
|
||||
boxWidth := float64(blockPinWidth) - boxPadding*2
|
||||
boxHeight := float64(hanHeight) + boxPadding*2
|
||||
ctx.DrawRectangle(boxX, boxY, boxWidth, boxHeight)
|
||||
|
||||
// 设置方框颜色
|
||||
char := chars[i]
|
||||
switch {
|
||||
case char == target.Chars[i]:
|
||||
ctx.SetColor(colors[blockmatch])
|
||||
case char != "" && strings.Contains(target.Word, char):
|
||||
ctx.SetColor(colors[blockexist])
|
||||
default:
|
||||
ctx.SetColor(colors[notexist])
|
||||
}
|
||||
ctx.Fill()
|
||||
|
||||
// 绘制汉字
|
||||
_ = ctx.ParseFontFace(pinyinFont, hanFontSize)
|
||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||
hanX := boxX + boxWidth/2
|
||||
hanY := boxY + boxHeight/2
|
||||
ctx.DrawStringAnchored(char, hanX, hanY, 0.5, 0.5)
|
||||
|
||||
// 绘制题目的拼音提示
|
||||
ctx.SetColor(colors[exist])
|
||||
_ = ctx.ParseFontFace(pinyinFont, pinFontSize)
|
||||
if len(exitPinyin) > i && exitPinyin[i] != "" {
|
||||
tickY := boxY + boxHeight + float64(space) + pinHeight/2
|
||||
ctx.DrawStringAnchored(exitPinyin[i], hanX, tickY, 0.5, 0.5)
|
||||
}
|
||||
}
|
||||
return ctx.Image()
|
||||
}
|
||||
|
||||
func anserOutString(s idiomJSON) string {
|
||||
msg := s.Word
|
||||
if s.Baobian != "" && s.Baobian != "-" {
|
||||
msg += "\n" + s.Baobian + "词"
|
||||
}
|
||||
if s.Derivation != "" && s.Derivation != "-" {
|
||||
msg += "\n词源:\n" + s.Derivation
|
||||
} else {
|
||||
msg += "\n词源:无"
|
||||
}
|
||||
if s.Explanation != "" && s.Explanation != "-" {
|
||||
msg += "\n解释:\n" + s.Explanation
|
||||
} else {
|
||||
msg += "\n解释:无"
|
||||
}
|
||||
if len(s.Synonyms) > 0 {
|
||||
msg += "\n近义词:\n" + strings.Join(s.Synonyms, ",")
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
351
plugin/handou/habits.go
Normal file
351
plugin/handou/habits.go
Normal file
@@ -0,0 +1,351 @@
|
||||
// Package handou 猜成语
|
||||
package handou
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// UserHabits 用户习惯
|
||||
type UserHabits struct {
|
||||
mu sync.RWMutex
|
||||
habits map[string]int // 单字频率
|
||||
bigrams map[string]int // 二元组频率
|
||||
idioms map[string]int // 成语出现频率
|
||||
totalWords int // 总字数
|
||||
totalIdioms int // 总成语数
|
||||
lastUpdate time.Time // 最后更新时间
|
||||
}
|
||||
|
||||
var userHabits *UserHabits
|
||||
|
||||
// 初始化用户习惯
|
||||
func initUserHabits() error {
|
||||
userHabits = &UserHabits{
|
||||
habits: make(map[string]int),
|
||||
bigrams: make(map[string]int),
|
||||
idioms: make(map[string]int),
|
||||
}
|
||||
|
||||
if file.IsNotExist(userHabitsFile) {
|
||||
f, err := os.Create(userHabitsFile)
|
||||
if err != nil {
|
||||
return errors.New("创建用户习惯库时发生错误: " + err.Error())
|
||||
}
|
||||
_ = f.Close()
|
||||
return saveHabits()
|
||||
}
|
||||
|
||||
// 读取现有习惯数据
|
||||
habitsFile, err := os.ReadFile(userHabitsFile)
|
||||
if err != nil {
|
||||
return errors.New("读取用户习惯库时发生错误: " + err.Error())
|
||||
}
|
||||
|
||||
var savedData struct {
|
||||
Habits map[string]int `json:"habits"`
|
||||
Bigrams map[string]int `json:"bigrams"`
|
||||
Idioms map[string]int `json:"idioms"`
|
||||
TotalWords int `json:"total_words"`
|
||||
TotalIdioms int `json:"total_idioms"`
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(habitsFile, &savedData); err != nil {
|
||||
// 如果是旧格式,尝试兼容
|
||||
var oldHabits map[string]int
|
||||
if err := json.Unmarshal(habitsFile, &oldHabits); err == nil {
|
||||
savedData.Habits = oldHabits
|
||||
// 从旧数据重新计算统计信息
|
||||
for _, count := range oldHabits {
|
||||
savedData.TotalWords += count
|
||||
}
|
||||
} else {
|
||||
return errors.New("解析用户习惯库时发生错误: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
userHabits.mu.Lock()
|
||||
defer userHabits.mu.Unlock()
|
||||
|
||||
userHabits.habits = savedData.Habits
|
||||
userHabits.bigrams = savedData.Bigrams
|
||||
userHabits.idioms = savedData.Idioms
|
||||
userHabits.totalWords = savedData.TotalWords
|
||||
userHabits.totalIdioms = savedData.TotalIdioms
|
||||
userHabits.lastUpdate = savedData.LastUpdate
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 保存习惯数据
|
||||
func saveHabits() error {
|
||||
userHabits.mu.RLock()
|
||||
defer userHabits.mu.RUnlock()
|
||||
|
||||
data := struct {
|
||||
Habits map[string]int `json:"habits"`
|
||||
Bigrams map[string]int `json:"bigrams"`
|
||||
Idioms map[string]int `json:"idioms"`
|
||||
TotalWords int `json:"total_words"`
|
||||
TotalIdioms int `json:"total_idioms"`
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
}{
|
||||
Habits: userHabits.habits,
|
||||
Bigrams: userHabits.bigrams,
|
||||
Idioms: userHabits.idioms,
|
||||
TotalWords: userHabits.totalWords,
|
||||
TotalIdioms: userHabits.totalIdioms,
|
||||
LastUpdate: time.Now(),
|
||||
}
|
||||
|
||||
f, err := os.Create(userHabitsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
encoder := json.NewEncoder(f)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(data)
|
||||
}
|
||||
|
||||
// 更新用户习惯(累加频率)
|
||||
func updateHabits(input string) error {
|
||||
if userHabits == nil {
|
||||
if err := initUserHabits(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
userHabits.mu.Lock()
|
||||
defer userHabits.mu.Unlock()
|
||||
|
||||
// 统计单字和二元组
|
||||
chars := []rune(input)
|
||||
userHabits.totalWords += len(chars)
|
||||
|
||||
// 更新单字频率
|
||||
for _, char := range chars {
|
||||
charStr := string(char)
|
||||
userHabits.habits[charStr]++
|
||||
}
|
||||
|
||||
// 仅当成语存在时,更新成语相关频率
|
||||
if slices.Contains(habitsIdiomKeys, input) {
|
||||
// 更新二元组频率(N=2的gram)
|
||||
for i := 0; i < len(chars)-1; i++ {
|
||||
bigram := string(chars[i]) + string(chars[i+1])
|
||||
userHabits.bigrams[bigram]++
|
||||
}
|
||||
// 更新成语频率
|
||||
userHabits.idioms[input]++
|
||||
userHabits.totalIdioms++
|
||||
}
|
||||
|
||||
// 异步保存到文件
|
||||
go func() {
|
||||
if err := saveHabits(); err != nil {
|
||||
logrus.Debugln("保存用户习惯时发生错误: ", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 计算成语的优先级分数
|
||||
func calculatePriorityScore(idiom string) float64 {
|
||||
if userHabits == nil || userHabits.totalWords == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
userHabits.mu.RLock()
|
||||
defer userHabits.mu.RUnlock()
|
||||
|
||||
chars := []rune(idiom)
|
||||
charsLenght := len(chars)
|
||||
|
||||
// 1. 基于单字频率的分数
|
||||
charsScore := 0.0
|
||||
for _, char := range chars {
|
||||
charStr := string(char)
|
||||
if count, exists := userHabits.habits[charStr]; exists {
|
||||
// 使用TF-IDF思想:频率越高,权重越高,但通过总字数归一化
|
||||
tf := float64(count*10) / float64(userHabits.totalWords)
|
||||
// score += tf * 100
|
||||
charsScore += 100 / (1 + 10*math.Abs(tf-5)) // 规避一直是最热门的汉字
|
||||
}
|
||||
}
|
||||
charsScore = charsScore / float64(charsLenght) * 60 / 100
|
||||
|
||||
// 2. 基于二元组频率的分数(词序的重要性)
|
||||
bigramScore := 0.0
|
||||
for i := 0; i < charsLenght-1; i++ {
|
||||
bigram := string(chars[i]) + string(chars[i+1])
|
||||
if count, exists := userHabits.bigrams[bigram]; exists {
|
||||
tf := float64(count*10) / float64(userHabits.totalWords)
|
||||
// score += tf * 150 // 二元组比单字更重要
|
||||
bigramScore += 100 / (1 + 2*math.Abs(tf-5)) // 规避一直是最热门的词组
|
||||
}
|
||||
}
|
||||
bigramScore = bigramScore / float64(charsLenght-1) * 40 / 100
|
||||
|
||||
// 3. 基于成语本身的频率(降低常见成语的优先级,增加多样性)
|
||||
penaltyScore := 0.0
|
||||
if idiomCount, exists := userHabits.idioms[idiom]; exists {
|
||||
// 出现次数越多,优先级越低(避免总是出现相同的成语)
|
||||
penalty := float64(idiomCount) / float64(userHabits.totalIdioms) * 100
|
||||
penaltyScore -= penalty
|
||||
}
|
||||
|
||||
// 4. 考虑成语长度, 让长成语也有机会被选中
|
||||
idiomScore := 0.0
|
||||
if rand.Intn(100) < 60 {
|
||||
idiomScore = 20 / (1 + 1*math.Abs(float64(charsLenght)-4))
|
||||
} else {
|
||||
count := 2.0 + float64(rand.Intn(18))
|
||||
idiomScore = 100 / (1 + 1*math.Abs(float64(charsLenght)-count))
|
||||
}
|
||||
|
||||
finalScore := charsScore + bigramScore + penaltyScore + idiomScore
|
||||
|
||||
return finalScore
|
||||
}
|
||||
|
||||
// 优先抽取数据
|
||||
func prioritizeData(data []string) []string {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
// 计算每个成语的优先级分数
|
||||
idiomScores := make([]struct {
|
||||
idiom string
|
||||
score float64
|
||||
}, len(data))
|
||||
|
||||
for i, idiom := range data {
|
||||
idiomScores[i] = struct {
|
||||
idiom string
|
||||
score float64
|
||||
}{
|
||||
idiom: idiom,
|
||||
score: calculatePriorityScore(idiom),
|
||||
}
|
||||
}
|
||||
|
||||
// 按分数排序(从高到低)
|
||||
slices.SortFunc(idiomScores, func(a, b struct {
|
||||
idiom string
|
||||
score float64
|
||||
}) int {
|
||||
if a.score > b.score {
|
||||
return -1
|
||||
} else if a.score < b.score {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
// 排除的前1/3的数量, 去除分数太高的成语
|
||||
excludeCount := int(float64(len(idiomScores)) * 0.333)
|
||||
if excludeCount < 1 && len(idiomScores) > 1 {
|
||||
excludeCount = 1
|
||||
}
|
||||
startIndex := excludeCount
|
||||
if startIndex >= len(idiomScores) {
|
||||
startIndex = 0
|
||||
}
|
||||
|
||||
// 选择接下来前10个作为优先数据
|
||||
limit := min(len(idiomScores)-startIndex, 10)
|
||||
|
||||
prioritized := make([]string, limit)
|
||||
for i := range limit {
|
||||
prioritized[i] = idiomScores[startIndex+i].idiom
|
||||
logrus.Debugf("成语 '%s' 分数=%.2f",
|
||||
idiomScores[startIndex+i].idiom, idiomScores[startIndex+i].score)
|
||||
}
|
||||
|
||||
return prioritized
|
||||
}
|
||||
|
||||
// 获取热门汉字(用于调试或展示)
|
||||
func getTopCharacters(limit int) []string {
|
||||
if userHabits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
userHabits.mu.RLock()
|
||||
defer userHabits.mu.RUnlock()
|
||||
|
||||
type charFreq struct {
|
||||
char string
|
||||
count int
|
||||
}
|
||||
|
||||
chars := make([]charFreq, 0, len(userHabits.habits))
|
||||
for char, count := range userHabits.habits {
|
||||
chars = append(chars, charFreq{char, count})
|
||||
}
|
||||
|
||||
slices.SortFunc(chars, func(a, b charFreq) int {
|
||||
return b.count - a.count
|
||||
})
|
||||
|
||||
if len(chars) > limit {
|
||||
chars = chars[:limit]
|
||||
}
|
||||
|
||||
result := make([]string, len(chars))
|
||||
for i, cf := range chars {
|
||||
result[i] = fmt.Sprintf("%s:%d", cf.char, cf.count)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 获取热门成语(用于调试或展示)
|
||||
func getTopIdioms(limit int) []string {
|
||||
if userHabits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
userHabits.mu.RLock()
|
||||
defer userHabits.mu.RUnlock()
|
||||
|
||||
type idiomFreq struct {
|
||||
idiom string
|
||||
count int
|
||||
}
|
||||
|
||||
idioms := make([]idiomFreq, 0, len(userHabits.idioms))
|
||||
for char, count := range userHabits.idioms {
|
||||
idioms = append(idioms, idiomFreq{char, count})
|
||||
}
|
||||
|
||||
slices.SortFunc(idioms, func(a, b idiomFreq) int {
|
||||
return b.count - a.count
|
||||
})
|
||||
|
||||
if len(idioms) > limit {
|
||||
idioms = idioms[:limit]
|
||||
}
|
||||
|
||||
result := make([]string, len(idioms))
|
||||
for i, cf := range idioms {
|
||||
result[i] = fmt.Sprintf("%s:%d", cf.idiom, cf.count)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
"0409": {
|
||||
"identity": {
|
||||
"name": "ZeroBot-Plugin",
|
||||
"version": "1.10.16.2369"
|
||||
"version": "1.10.19.2387"
|
||||
},
|
||||
"description": "",
|
||||
"minimum-os": "vista",
|
||||
@@ -36,23 +36,23 @@
|
||||
"#1": {
|
||||
"0000": {
|
||||
"fixed": {
|
||||
"file_version": "1.10.16.2369",
|
||||
"product_version": "v1.10.16",
|
||||
"timestamp": "2026-01-17T21:01:01+08:00"
|
||||
"file_version": "1.10.19.2387",
|
||||
"product_version": "v1.10.19",
|
||||
"timestamp": "2026-02-19T23:45:11+08:00"
|
||||
},
|
||||
"info": {
|
||||
"0409": {
|
||||
"Comments": "OneBot plugins based on ZeroBot",
|
||||
"CompanyName": "FloatTech",
|
||||
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
"FileVersion": "1.10.16.2369",
|
||||
"FileVersion": "1.10.19.2387",
|
||||
"InternalName": "",
|
||||
"LegalCopyright": "© 2020 - 2026 FloatTech. All Rights Reserved.",
|
||||
"LegalTrademarks": "",
|
||||
"OriginalFilename": "ZBP.EXE",
|
||||
"PrivateBuild": "",
|
||||
"ProductName": "ZeroBot-Plugin",
|
||||
"ProductVersion": "v1.10.16",
|
||||
"ProductVersion": "v1.10.19",
|
||||
"SpecialBuild": ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user