Compare commits

..

84 Commits

Author SHA1 Message Date
昔音幻离
62a57fa61d
chore: update gopsutil to v4 (#1244)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-12-16 10:58:21 +08:00
himawari
0142050d6a
fix(aichat): gpt 修改提示词 (#1242)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-11-26 13:06:33 +08:00
源文雨
9cfad308b0 fix: boot panic on rsshub
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-11-24 17:51:56 +08:00
源文雨
28a8ee945c chore: update go.sum 2025-11-24 17:46:33 +08:00
github-actions[bot]
2154faec2c
chore: bump deps (#1240)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-11-13 00:13:59 +08:00
莫思潋
577b3f3f30
chore: update deps (#1241)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-11-09 17:57:01 +08:00
源文雨
99c9cc3de6 feat(aichat): add tests for storage
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-10-24 00:54:36 +08:00
源文雨
216d99c05d feat: drop unsafe -checklinkname 2025-10-24 00:28:47 +08:00
宇~
8101c02ca8
fix: 启动脚本 (#1236)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-10-08 19:41:16 +08:00
github-actions[bot]
da81875f8b
chore: bump deps (#1235)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-07 13:22:19 +08:00
github-actions[bot]
dd1a0ae478
chore: bump deps (#1234)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-07 12:39:39 +08:00
himawari
aafac8d6fa
feat: 添加 rsshub (#1232) 2025-10-07 12:39:16 +08:00
源文雨
a74bcb869a chore: update deps 2025-10-07 12:36:40 +08:00
github-actions[bot]
584882282f
chore: bump deps (#1233)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-03 23:41:32 +08:00
源文雨
05345e4c13 fix(wordcount): jieba panic
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-10-02 16:42:59 +08:00
源文雨
b8a57b80f2 doc: add go generate main.go in README 2025-10-02 16:34:02 +08:00
源文雨
177fdbae68 optimize: drop gse in order to reduce mem cons. 2025-10-02 16:32:48 +08:00
Kajiekazz
fef48e405a
fix(dailynews): update to new API (#1230)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-10-01 01:05:31 +08:00
源文雨
2d1603d65a fix: goreleaser 2025-10-01 01:04:28 +08:00
源文雨
73c7bbda1a doc: update compile instructions 2025-10-01 00:53:29 +08:00
源文雨
558c3ee482 fix: make lint happy 2025-10-01 00:40:15 +08:00
源文雨
bc20d95bd1 fix: make lint&ci happy 2025-10-01 00:35:55 +08:00
源文雨
883adc621c fix: make lint&ci happy 2025-10-01 00:33:19 +08:00
源文雨
7be1f2342b fix: make lint&ci happy 2025-10-01 00:30:24 +08:00
源文雨
4481ea4861 fix: make lint&ci happy 2025-10-01 00:25:44 +08:00
源文雨
4aace203cf fix: make lint&ci happy 2025-10-01 00:21:11 +08:00
源文雨
324a0022a7 fix: make lint&ci happy 2025-10-01 00:17:25 +08:00
源文雨
8825514fb2 fix: make lint&ci happy 2025-10-01 00:16:07 +08:00
github-actions[bot]
d2e6c9780f
chore: bump deps (#1231)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-01 00:03:48 +08:00
源文雨
06b8b518f8 fix: make lint&ci happy 2025-10-01 00:03:23 +08:00
源文雨
aa67d09ee1 feat(all): update to go1.24+ 2025-09-30 23:55:08 +08:00
github-actions[bot]
724e48f3e8
chore: bump deps (#1228)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-30 17:07:07 +08:00
源文雨
57c95178d8 chore: make lint happy
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-09-27 01:23:31 +08:00
源文雨
1e2d425cf4 optimize(bilibili): separate packages 2025-09-27 01:02:53 +08:00
源文雨
c22e4b543c chore: make lint happy
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-09-27 00:21:02 +08:00
源文雨
4434a617ed fix(aichat): mis setting 2025-09-27 00:05:04 +08:00
源文雨
d6eb3ba28c feat(aichat): agent add more trigger conds 2025-09-26 23:57:59 +08:00
源文雨
d0f4d296d9 feat(aichat): fill missing print 2025-09-26 23:55:01 +08:00
源文雨
13aaaba8f3 fix(aichat): rate print error 2025-09-26 23:52:16 +08:00
源文雨
3302d8d295 feat(aichat): agent support fallback to normal chat 2025-09-26 23:50:44 +08:00
方柳煜
dd328afae8
fix: wifegame (#1225) 2025-09-26 23:11:10 +08:00
源文雨
d304cda7f0 fix(aichat): terminus
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-26 01:37:23 +08:00
源文雨
109395a6af fix(aichat): terminus
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-26 00:48:28 +08:00
源文雨
f7c0f4df98 feat(aichat): add terminus 2025-09-26 00:37:44 +08:00
源文雨
43cc90b724 feat(aichat): add handling resp 2025-09-26 00:13:04 +08:00
莫思潋
7bd1653cb5
feat(wife): 增加作品名&猜老婆 (#1208)
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-24 16:38:33 +00:00
源文雨
6c4c6a3b8b chore: make lint happy 2025-09-25 00:36:01 +08:00
源文雨
72e0e796c4 chore: update deps 2025-09-25 00:23:29 +08:00
源文雨
3c41c18d27 feat(aichat): agent 支持识图 2025-09-25 00:20:07 +08:00
源文雨
7640f0cfac chore: update deps
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-24 00:24:04 +08:00
源文雨
73eef961b5 fix(aichat): agent group send
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-22 23:55:40 +08:00
源文雨
8e87be262c fix(aichat): agent group send 2025-09-22 23:06:46 +08:00
源文雨
8811df5968 feat(aichat): add perm check for cross-group
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-22 22:51:04 +08:00
源文雨
f09f15937c chore: update deps 2025-09-22 22:46:18 +08:00
源文雨
49983ab451 feat(aichat): add agent mode
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-21 23:18:39 +08:00
源文雨
4dd5189a3c chore: update deps
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-21 15:25:54 +08:00
Kajiekazz
b9250ab82d
doc: update zb version tag (#1206)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-09-16 21:49:34 +08:00
莫思潋
641495b579
chore: update wife data (#1207) 2025-09-16 21:44:15 +08:00
源文雨
e6a4dfcdf2 fix(aichat): adapt to 百炼
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-09-10 22:51:44 +08:00
源文雨
6b505d050a 🔖 v1.9.9
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-10 10:41:07 +08:00
github-actions[bot]
fc9a21d2d1
Changes by create-pull-request action (#1199)
* chore: bump deps

* Change Go version in go.mod

Updated Go version from 1.23.0 to 1.20 and removed toolchain specification.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
2025-09-10 10:39:51 +08:00
github-actions[bot]
e84e44476a
Changes by create-pull-request action (#1198)
* chore: bump deps

* Change Go version in go.mod

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
2025-09-10 10:39:15 +08:00
宇~
b012df4c23
feat(niuniu): 添加可自定义购买商品数量,调整商品单价 (#1189) 2025-09-10 10:33:21 +08:00
源文雨
08e02ab730 fix(aichat): adapt to 百炼 2025-09-10 10:32:30 +08:00
himawari
fb090839d6
feat(crypter): 添加语音 (#1197)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-09-03 17:07:09 +08:00
莫思潋
ac2d53352c
feat(bilibiliparse): B站视频解析 视频上传开关 (#1196)
Some checks are pending
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
* add control for getVideoDownload

* fix: typo
2025-09-03 13:02:12 +08:00
github-actions[bot]
35292a69fc
chore(lint): 改进代码样式 (#1192)
Some checks are pending
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-02 13:13:22 +08:00
Kajiekazz
cd16a755d7
doc: update README.md (#1193) 2025-09-02 13:12:13 +08:00
Kajiekazz
1e7b2d3335
feat: 添加插件 crypter (#1191)
Some checks are pending
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2025-09-01 22:42:42 +08:00
himawari
20d49ccf15
feat(aichat): 添加/gpt命令,直接聊天 (#1190)
*  添加大模型聊天,便于使用版本的

* 🐛 减少重复关键词

* 🎨 优化换行符

*  添加转换函数

*  添加lint优化

* 🎨 按字符切片

* 🎨 修改lint
2025-09-01 22:38:15 +08:00
github-actions[bot]
1f66f47ce6
chore: bump deps (#1188)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-25 11:08:05 +08:00
himawari
34f3b9ba2a
feat(aiimage&aichat): add new plugin & summary of group chat (#1187)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-08-22 22:37:35 +08:00
Dodoj
2fa7868838
fix(gif): branch名称导致的404问题 (#1186)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-08-12 00:18:32 +08:00
Dodoj
b6ddda1d51
fix(kfccrazythursday): API解析 (#1184)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-07-25 10:31:33 +09:00
himawari
a1621f34a0
optimize(antiabuse): 添加违禁词解释 (#1183)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-07-23 21:24:00 +09:00
github-actions[bot]
21aa3bc49f
chore: bump deps (#1182)
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-20 14:33:29 +09:00
himawari
617d4f50a4
feat: airecord (#1180)
Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
2025-07-20 14:31:06 +09:00
himawari
cb0ffa0c17
feat(music): 龙珠聚合搜索 (#1179)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
* 🐛 修改听歌问题

*  添加龙珠聚合搜索

* 🎨 优化聚合搜索

* 🐛 一定能点出歌

* 🎨 删除调试
2025-07-05 18:05:28 +09:00
宇~
0615993297
fix: 修复注销牛牛无法进行累加收费的问题&&优化代码 (#1178)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
* fix:修复注销牛牛无法进行累加收费的问题

* 修改牛牛商店的循环条件为商品变量的长度
2025-07-02 14:49:59 +09:00
Rinai
1c0d91424a
fix: 修复 niuniu 插件 bug,修改标点,添加部分注释 (#1177)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2025-06-27 17:49:50 +09:00
github-actions[bot]
c94ee365ce
chore: bump deps (#1175)
Some checks failed
打包最新版为 Docker Image / build docker (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-15 17:04:45 +09:00
github-actions[bot]
19e5e6636f
chore: bump deps (#1173)
Some checks failed
打包最新版为 Docker Image / build docker (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-15 02:03:33 +09:00
github-actions[bot]
cac3a4be81
chore(lint): 改进代码样式 (#1174)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-15 02:03:23 +09:00
源文雨
beada7f4da chore: update deps 2025-06-15 02:01:23 +09:00
77 changed files with 3716 additions and 2107 deletions

View File

@ -18,10 +18,12 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@master uses: actions/setup-go@master
with: with:
go-version: "1.20" go-version: "1.25"
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@master uses: actions/checkout@master
with:
fetch-depth: 0
- name: gomod2nix update - name: gomod2nix update
run: | run: |

View File

@ -1,42 +0,0 @@
name: 打包最新版为 Docker Image
on: [push]
jobs:
docker-builder:
name: build docker
runs-on: ubuntu-23.04
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@master
- run: sudo apt-get install -y qemu-user-static
- name: Set up nix
uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
sandbox = true
- name: Speed Up nix
uses: DeterminateSystems/magic-nix-cache-action@main
- name: build docker
run: |
mkdir output/
# https://discourse.nixos.org/t/nix-github-actions-aarch64/11034
nix build .#packages.aarch64-linux.docker_builder -o aarch64-linux.docker --print-out-paths --option system aarch64-linux --extra-platforms aarch64-linux
cp $(readlink aarch64-linux.docker) ./output/aarch64-linux.docker.tar.gz
nix build .#packages.x86_64-linux.docker_builder -o x86_64-linux.docker --print-out-paths --option system x86_64-linux --extra-platforms x86_64-linux
cp $(readlink x86_64-linux.docker) ./output/x86_64-linux.docker.tar.gz
# gomod2nix did not provide this
# nix build .#packages.i686-linux.docker_builder -o i686-linux.docker --print-out-paths --option system i686-linux --extra-platforms i686-linux
# cp $(readlink i686-linux.docker) ./output/i686-linux.docker.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@master
if: ${{ !github.head_ref }}
with:
path: output/

View File

@ -27,10 +27,12 @@ jobs:
fail-fast: true fail-fast: true
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
with:
fetch-depth: 0
- name: Setup Go environment - name: Setup Go environment
uses: actions/setup-go@master uses: actions/setup-go@master
with: with:
go-version: '1.20' go-version: '1.25'
- name: Cache downloaded module - name: Cache downloaded module
uses: actions/cache@master uses: actions/cache@master
continue-on-error: true continue-on-error: true
@ -45,6 +47,7 @@ jobs:
GOARCH: ${{ matrix.goarch }} GOARCH: ${{ matrix.goarch }}
IS_PR: ${{ !!github.head_ref }} IS_PR: ${{ !!github.head_ref }}
run: | run: |
GOOS= GOARCH= go generate ./...
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
if $IS_PR ; then echo $PR_PROMPT; fi if $IS_PR ; then echo $PR_PROMPT; fi
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX" export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"

View File

@ -26,15 +26,18 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@master uses: actions/setup-go@master
with: with:
go-version: '1.20' go-version: '1.24'
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Tidy Modules - name: Tidy Modules
run: go mod tidy run: |
go mod tidy
go generate main.go
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@master uses: golangci/golangci-lint-action@master

View File

@ -8,13 +8,17 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@master uses: actions/setup-go@master
with: with:
go-version: '1.20' go-version: '1.24'
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@master uses: actions/checkout@master
with:
fetch-depth: 0
- name: Tidy Modules - name: Tidy Modules
run: go mod tidy run: |
go mod tidy
go generate main.go
- name: Run Lint - name: Run Lint
uses: golangci/golangci-lint-action@master uses: golangci/golangci-lint-action@master

View File

@ -16,7 +16,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@master uses: actions/setup-go@master
with: with:
go-version: '1.20' go-version: '1.25'
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@master uses: goreleaser/goreleaser-action@master

View File

@ -56,7 +56,7 @@ run:
deadline: 5m deadline: 5m
issues-exit-code: 1 issues-exit-code: 1
tests: false tests: false
go: '1.20' go: '1.24'
# output configuration options # output configuration options
output: output:
@ -64,12 +64,12 @@ output:
- format: "colored-line-number" - format: "colored-line-number"
print-issued-lines: true print-issued-lines: true
print-linter-name: true print-linter-name: true
uniq-by-line: true
issues: issues:
# Fix found issues (if it's supported by the linter) # Fix found issues (if it's supported by the linter)
fix: true fix: true
exclude-use-default: false exclude-use-default: false
uniq-by-line: true
exclude: exclude:
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Seek|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check" - "Error return value of .((os.)?std(out|err)..*|.*Close|.*Seek|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
- 'identifier ".*" contain non-ASCII character: U\+.*' - 'identifier ".*" contain non-ASCII character: U\+.*'

View File

@ -4,6 +4,7 @@ env:
before: before:
hooks: hooks:
- go mod tidy - go mod tidy
- go generate ./...
- go install github.com/tc-hib/go-winres@latest - go install github.com/tc-hib/go-winres@latest
- go-winres make - go-winres make
builds: builds:

147
README.md
View File

@ -20,7 +20,7 @@
[![go](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin?style=flat-square&logo=go)](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin) [![go](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin?style=flat-square&logo=go)](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
[![onebot](https://img.shields.io/badge/onebot-v11-black?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAxQTFRF////29vbr6+vAAAAk1hCcwAAAAR0Uk5T////AEAqqfQAAAKcSURBVHja7NrbctswDATQXfD//zlpO7FlmwAWIOnOtNaTM5JwDMa8E+PNFz7g3waJ24fviyDPgfhz8fHP39cBcBL9KoJbQUxjA2iYqHL3FAnvzhL4GtVNUcoSZe6eSHizBcK5LL7dBr2AUZlev1ARRHCljzRALIEog6H3U6bCIyqIZdAT0eBuJYaGiJaHSjmkYIZd+qSGWAQnIaz2OArVnX6vrItQvbhZJtVGB5qX9wKqCMkb9W7aexfCO/rwQRBzsDIsYx4AOz0nhAtWu7bqkEQBO0Pr+Ftjt5fFCUEbm0Sbgdu8WSgJ5NgH2iu46R/o1UcBXJsFusWF/QUaz3RwJMEgngfaGGdSxJkE/Yg4lOBryBiMwvAhZrVMUUvwqU7F05b5WLaUIN4M4hRocQQRnEedgsn7TZB3UCpRrIJwQfqvGwsg18EnI2uSVNC8t+0QmMXogvbPg/xk+Mnw/6kW/rraUlvqgmFreAA09xW5t0AFlHrQZ3CsgvZm0FbHNKyBmheBKIF2cCA8A600aHPmFtRB1XvMsJAiza7LpPog0UJwccKdzw8rdf8MyN2ePYF896LC5hTzdZqxb6VNXInaupARLDNBWgI8spq4T0Qb5H4vWfPmHo8OyB1ito+AysNNz0oglj1U955sjUN9d41LnrX2D/u7eRwxyOaOpfyevCWbTgDEoilsOnu7zsKhjRCsnD/QzhdkYLBLXjiK4f3UWmcx2M7PO21CKVTH84638NTplt6JIQH0ZwCNuiWAfvuLhdrcOYPVO9eW3A67l7hZtgaY9GZo9AFc6cryjoeFBIWeU+npnk/nLE0OxCHL1eQsc1IciehjpJv5mqCsjeopaH6r15/MrxNnVhu7tmcslay2gO2Z1QfcfX0JMACG41/u0RrI9QAAAABJRU5ErkJggg==)](https://t.me/zerobotplugin) [![onebot](https://img.shields.io/badge/onebot-v11-black?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAxQTFRF////29vbr6+vAAAAk1hCcwAAAAR0Uk5T////AEAqqfQAAAKcSURBVHja7NrbctswDATQXfD//zlpO7FlmwAWIOnOtNaTM5JwDMa8E+PNFz7g3waJ24fviyDPgfhz8fHP39cBcBL9KoJbQUxjA2iYqHL3FAnvzhL4GtVNUcoSZe6eSHizBcK5LL7dBr2AUZlev1ARRHCljzRALIEog6H3U6bCIyqIZdAT0eBuJYaGiJaHSjmkYIZd+qSGWAQnIaz2OArVnX6vrItQvbhZJtVGB5qX9wKqCMkb9W7aexfCO/rwQRBzsDIsYx4AOz0nhAtWu7bqkEQBO0Pr+Ftjt5fFCUEbm0Sbgdu8WSgJ5NgH2iu46R/o1UcBXJsFusWF/QUaz3RwJMEgngfaGGdSxJkE/Yg4lOBryBiMwvAhZrVMUUvwqU7F05b5WLaUIN4M4hRocQQRnEedgsn7TZB3UCpRrIJwQfqvGwsg18EnI2uSVNC8t+0QmMXogvbPg/xk+Mnw/6kW/rraUlvqgmFreAA09xW5t0AFlHrQZ3CsgvZm0FbHNKyBmheBKIF2cCA8A600aHPmFtRB1XvMsJAiza7LpPog0UJwccKdzw8rdf8MyN2ePYF896LC5hTzdZqxb6VNXInaupARLDNBWgI8spq4T0Qb5H4vWfPmHo8OyB1ito+AysNNz0oglj1U955sjUN9d41LnrX2D/u7eRwxyOaOpfyevCWbTgDEoilsOnu7zsKhjRCsnD/QzhdkYLBLXjiK4f3UWmcx2M7PO21CKVTH84638NTplt6JIQH0ZwCNuiWAfvuLhdrcOYPVO9eW3A67l7hZtgaY9GZo9AFc6cryjoeFBIWeU+npnk/nLE0OxCHL1eQsc1IciehjpJv5mqCsjeopaH6r15/MrxNnVhu7tmcslay2gO2Z1QfcfX0JMACG41/u0RrI9QAAAABJRU5ErkJggg==)](https://t.me/zerobotplugin)
[![zerobot](https://img.shields.io/badge/zerobot-v1.8.0-black?style=flat-square&logo=go)](https://github.com/wdvxdr1123/ZeroBot) [![zerobot](https://img.shields.io/badge/zerobot-v1.8.1-black?style=flat-square&logo=go)](https://github.com/wdvxdr1123/ZeroBot)
@ -192,6 +192,18 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
- [x] 早安 | 晚安 - [x] 早安 | 晚安
</details>
<details>
<summary>违禁词检测</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/antiabuse"
`
- [x] 添加违禁词
- [x] 删除违禁词
- [x] 查看违禁词
</details> </details>
<details> <details>
<summary>ATRI</summary> <summary>ATRI</summary>
@ -256,6 +268,8 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
- [x] 赞我 - [x] 赞我
- [x] 群签到
- [x] [开启 | 关闭]入群验证 - [x] [开启 | 关闭]入群验证
- [x] [开启 | 关闭]gist加群自动审批 - [x] [开启 | 关闭]gist加群自动审批
@ -276,6 +290,20 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
- 设置欢迎语可选添加参数说明:{at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名 - 设置欢迎语可选添加参数说明:{at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名
</details>
<details>
<summary>群应用AI声聊</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/airecord"`
- [x] 设置AI语音群号1048452984(tips机器人任意所在群聊即可)
- [x] 设置AI语音模型
- [x] 查看AI语音配置
- [x] 发送AI语音xxx
</details> </details>
<details> <details>
<summary>定时指令触发器</summary> <summary>定时指令触发器</summary>
@ -384,6 +412,18 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 设置默认限速为每 m [分钟 | 秒] n 次触发 - [x] 设置默认限速为每 m [分钟 | 秒] n 次触发
</details>
<details>
<summary>aiimage</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage"`
- [x] 设置AI画图密钥xxx
- [x] 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations
- [x] 设置AI画图模型名Kwai-Kolors/Kolors
- [x] 查看AI画图配置
- [x] AI画图 [描述]
</details> </details>
<details> <details>
<summary>AIWife</summary> <summary>AIWife</summary>
@ -531,7 +571,7 @@ print("run[CQ:image,file="+j["img"]+"]")
<details> <details>
<summary>b站动态、专栏、视频、直播解析</summary> <summary>b站动态、专栏、视频、直播解析</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"` `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibiliparse"`
- [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245 - [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245
@ -539,7 +579,7 @@ print("run[CQ:image,file="+j["img"]+"]")
<details> <details>
<summary>b站动态、直播推送,需要配合job一起使用</summary> <summary>b站动态、直播推送,需要配合job一起使用</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"` `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibilipush"`
- [x] 添加b站订阅[uid|name] - [x] 添加b站订阅[uid|name]
@ -605,6 +645,17 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 磕cp大老师 雪乃 - [x] 磕cp大老师 雪乃
</details>
<details>
<summary>奇怪语言加解密</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/crypter"`
- [x] 齁语加密 [文本] 或 h加密 [文本]
- [x] 齁语解密 [密文] 或 h解密 [密文]
- [x] fumo加密 [文本]
- [x] fumo解密 [文本]
</details> </details>
<details> <details>
<summary>今日早报</summary> <summary>今日早报</summary>
@ -1027,6 +1078,10 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 酷狗点歌[xxx] - [x] 酷狗点歌[xxx]
- [x] qq点歌[xxx]
- [x] 咪咕点歌[xxx]
</details> </details>
<details> <details>
<summary>本地涩图</summary> <summary>本地涩图</summary>
@ -1229,6 +1284,17 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 打劫[对方Q号|@对方QQ] - [x] 打劫[对方Q号|@对方QQ]
</details>
<details>
<summary>RSSHub</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub"`
- [x] 添加rsshub订阅-/bookfere/weekly
- [x] 删除rsshub订阅-/bookfere/weekly
- [x] 查看rsshub订阅列表
- [x] rsshub同步 (使用job执行定时任务------记录在"@every 10m"触发的指令)
</details> </details>
<details> <details>
<summary>在线代码运行</summary> <summary>在线代码运行</summary>
@ -1407,50 +1473,6 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 每日特惠 - [x] 每日特惠
</details> </details>
<details>
<summary>百度文心AI</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI"`
基于百度文心API的一些功能
key申请链接https://wenxin.baidu.com/moduleApi/key
- [x] 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]
- [x] 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]
“为10086设置画图key 123 456”“为群10010设置画图key 789 101”
文心key和画图key的API key 可以是相同的只是文心key日限为200画图日限为50以此作区别。
- [x] 文心作文 (x字的)[作文题目]
- [x] 文心提案 (x字的)[文案标题]
- [x] 文心摘要 (x字的)[文章内容]
- [x] 文心小说 (x字的)[小说上文]
- [x] 文心对联 [上联]
- [x] 文心问答 [问题]
- [x] 文心补全 [带“_”的填空题]
- [x] 文心自定义 [prompt]
- [x] [bot名称]画几张[图片描述]的[图片类型][图片尺寸]
指令示例:
- 文心作文 我的椛椛机器人
- 文心作文 300字的我的椛椛机器人
- 椛椛帮我画几张金凤凰背景绚烂高饱和古风仙境高清4K古风的油画方图
</details>
<details> <details>
<summary>抽老婆</summary> <summary>抽老婆</summary>
@ -1464,7 +1486,7 @@ print("run[CQ:image,file="+j["img"]+"]")
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"` `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"`
- [x] 热词 [群号] [消息数目]|热词 123456 1000 - [x] 热词 [消息数目]|热词 1000
</details> </details>
<details> <details>
@ -1494,21 +1516,21 @@ print("run[CQ:image,file="+j["img"]+"]")
</details> </details>
<details> <details>
<summary>一些游戏王插件</summary> <summary>游戏王白鸽API卡查</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo"` `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygocdb"`
##### 白鸽API卡查
###### `"github.com/FloatTech/ZeroBot-Plugin/plugin/ygo/ygocdb.go"`
- [x] /ydp [xxx] - [x] /ydp [xxx]
- [x] /yds [xxx] - [x] /yds [xxx]
- [x] /ydb [xxx] - [x] /ydb [xxx]
- 注:[xxx]为搜索内容;p:返回一张图片;s:返回一张效果描述;b:高级搜索 - 注:[xxx]为搜索内容;p:返回一张图片;s:返回一张效果描述;b:高级搜索
##### 集换社卡价查询 </details>
<details>
<summary>游戏王集换社卡价查询</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygotrade"`
###### `"github.com/FloatTech/ZeroBot-Plugin/plugin/ygo/ygotrade.go"`
- [x] 查卡价 [卡名] - [x] 查卡价 [卡名]
- [x] 查卡价 [卡名] -r [稀有度 稀有度 ...] - [x] 查卡价 [卡名] -r [稀有度 稀有度 ...]
- [x] 查卡店 [卡名] - [x] 查卡店 [卡名]
@ -1578,11 +1600,12 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 设置AI聊天触发概率10 - [x] 设置AI聊天触发概率10
- [x] 设置AI聊天温度80 - [x] 设置AI聊天温度80
- [x] 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI] - [x] 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI]
- [x] 设置AI聊天(不)使用Agent模式
- [x] 设置AI聊天(不)支持系统提示词 - [x] 设置AI聊天(不)支持系统提示词
- [x] 设置AI聊天接口地址https://xxx - [x] 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions
- [x] 设置AI聊天密钥xxx - [x] 设置AI聊天(识图|Agent)密钥xxx
- [x] 设置AI聊天模型名xxx - [x] 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B
- [x] 查看AI聊天系统提示词 - [x] 查看AI聊天系统提示词
- [x] 重置AI聊天系统提示词 - [x] 重置AI聊天系统提示词
- [x] 设置AI聊天系统提示词xxx - [x] 设置AI聊天系统提示词xxx
@ -1590,6 +1613,11 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 设置AI聊天(不)响应AT - [x] 设置AI聊天(不)响应AT
- [x] 设置AI聊天最大长度4096 - [x] 设置AI聊天最大长度4096
- [x] 设置AI聊天TopP 0.9 - [x] 设置AI聊天TopP 0.9
- [x] 设置AI聊天(不)以AI语音输出
- [x] 查看AI聊天配置
- [x] 重置AI聊天
- [x] 群聊总结 [消息数目]|群聊总结 1000
- [x] /gpt [内容](使用大模型聊天)
</details> </details>
<details> <details>
@ -1657,6 +1685,7 @@ go version
go env -w GOPROXY=https://goproxy.cn,direct go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=auto go env -w GO111MODULE=auto
go mod tidy go mod tidy
go generate main.go
``` ```
3. 编辑 main.go 文件,内容按需修改 3. 编辑 main.go 文件,内容按需修改

164
abineundo/main.go Normal file
View File

@ -0,0 +1,164 @@
// Package abineundo provides an explicit "from the beginning" (Latin: "ab ineundō")
// initialization anchor.
//
// Name origin:
//
// Latin phrase "ab ineundō" meaning "from which is to be begun".
//
// Purpose:
//
// Place this package at the very top of top-level main.go so its init (present
// or future) executes before other plugin packages, filling in a predictable
// plugin priority.
//
// Typical usage:
//
// import (
// _ "github.com/your/module/abineundo" // priority anchor
// // ... other imports ...
// )
//
// A blank identifier import preserves ordering side-effects without expanding the
// exported API surface.
//
// (No further code is required here; the package's presence alone defines ordering semantics.)
package abineundo
import (
"bufio"
_ "embed"
"regexp"
"strings"
"github.com/FloatTech/zbputils/control"
"github.com/sirupsen/logrus"
)
//go:embed ref/main/main.go
var maincode string
//go:embed ref/custom/register.go
var customcode string
const (
statusnone = iota
statushigh
statushighend
statusmid
statusmidend
statuslow
statuslowend
)
var (
priore = regexp.MustCompile(`^\t// -{28}(高|中|低)优先级区-{28} //$`)
mainpluginre = regexp.MustCompile(`^\t_ "github\.com/FloatTech/ZeroBot-Plugin/plugin/(\w+)"\s+// `)
custpluginre = regexp.MustCompile(`^\t_ "github\.com/FloatTech/ZeroBot-Plugin/custom/plugin/(\w+)"\s+// `)
)
func init() {
highprios := make([]string, 0, 64)
midprios := make([]string, 0, 64)
lowprios := make([]string, 0, 64)
status := statusnone
scanner := bufio.NewScanner(strings.NewReader(maincode))
for scanner.Scan() {
line := scanner.Text()
prioword := ""
match := priore.FindStringSubmatch(line)
if len(match) > 1 {
prioword = match[1]
}
switch prioword {
case "高":
switch status {
case statusnone:
status = statushigh
case statushigh:
status = statushighend
default:
panic("unexpected")
}
case "中":
switch status {
case statushighend:
status = statusmid
case statusmid:
status = statusmidend
default:
panic("unexpected")
}
case "低":
switch status {
case statusmidend:
status = statuslow
case statuslow:
status = statuslowend
default:
panic("unexpected")
}
default:
switch status {
case statusnone: // 还未开始匹配
continue
case statuslowend: // 匹配已结束
break
default: // 继续匹配插件
}
}
// 在对应优先级区域内匹配插件
if matches := mainpluginre.FindStringSubmatch(line); len(matches) > 1 {
name := matches[1]
switch status {
case statushigh:
highprios = append(highprios, name)
case statusmid:
midprios = append(midprios, name)
case statuslow:
lowprios = append(lowprios, name)
default: // 在不该匹配到插件的区域匹配到
panic("unexpected")
}
}
}
custprios := make([]string, 0, 64)
scanner = bufio.NewScanner(strings.NewReader(customcode))
for scanner.Scan() {
line := scanner.Text()
if matches := custpluginre.FindStringSubmatch(line); len(matches) > 1 {
custprios = append(custprios, matches[1])
}
}
// 生成最终插件优先级表
m := make(map[string]uint64, 4*(len(highprios)+len(midprios)+len(lowprios)+len(custprios)))
i := 0
for _, name := range highprios {
m[name] = (uint64(i) + 1) * 10
logrus.Debugln("[ab] set high plugin", name, "prio to", m[name])
i++
}
for _, name := range custprios {
m[name] = (uint64(i) + 1) * 10
logrus.Debugln("[ab] set cust plugin", name, "prio to", m[name])
i++
}
for _, name := range midprios {
m[name] = (uint64(i) + 1) * 10
logrus.Debugln("[ab] set mid plugin", name, "prio to", m[name])
i++
}
for _, name := range lowprios {
m[name] = (uint64(i) + 1) * 10
logrus.Debugln("[ab] set low plugin", name, "prio to", m[name])
i++
}
control.LoadCustomPriority(m)
}

2
abineundo/ref/custom/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
!.gitignore
*

54
abineundo/ref/main.go Normal file
View File

@ -0,0 +1,54 @@
// Package main generate necessary files that needed for compiling
package main
import (
"flag"
"io"
"os"
"path"
)
func main() {
root := flag.String("r", "", "project root dir")
flag.Parse()
fi, err := os.Open(path.Join(*root, "main.go"))
if err != nil {
panic(err)
}
fo, err := os.Create(path.Join(*root, "abineundo/ref/main/main.go"))
if err != nil {
panic(err)
}
_, err = io.Copy(fo, fi)
if err != nil {
panic(err)
}
fi.Close()
fo.Close()
regf := path.Join(*root, "custom/register.go")
tgtf := path.Join(*root, "abineundo/ref/custom/register.go")
if _, err := os.Stat(regf); err != nil {
if os.IsNotExist(err) {
_ = os.WriteFile(tgtf, []byte("// Package custom ...\npackage custom\n"), 0644)
return
}
panic(err)
}
fi, err = os.Open(regf)
if err != nil {
panic(err)
}
fo, err = os.Create(tgtf)
if err != nil {
panic(err)
}
_, err = io.Copy(fo, fi)
if err != nil {
panic(err)
}
fi.Close()
fo.Close()
}

2
abineundo/ref/main/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
!.gitignore
*

View File

@ -38,12 +38,18 @@ func setConsoleTitle(title string) (err error) {
} }
func init() { func init() {
debugMode := os.Getenv("DEBUG_MODE") == "1"
stdin := windows.Handle(os.Stdin.Fd()) stdin := windows.Handle(os.Stdin.Fd())
var mode uint32 var mode uint32
err := windows.GetConsoleMode(stdin, &mode) err := windows.GetConsoleMode(stdin, &mode)
if err != nil { if err != nil {
panic(err) if debugMode {
logrus.Warnf("调试模式下忽略控制台模式获取失败: %v", err)
return // 调试模式下直接返回,跳过后续配置
} else {
panic(err) // 非调试模式下 panic
}
} }
mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式 mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式

2
data

@ -1 +1 @@
Subproject commit 4f751a1cda692b5b8cb909ce1376a3a0ea0d57cc Subproject commit 1b0abcd3fe4943fa3298885cf0311e8d94a02c0b

99
go.mod
View File

@ -1,36 +1,36 @@
module github.com/FloatTech/ZeroBot-Plugin module github.com/FloatTech/ZeroBot-Plugin
go 1.20 go 1.24.2
require ( require (
github.com/Baidu-AIP/golang-sdk v1.1.1 github.com/Baidu-AIP/golang-sdk v1.1.1
github.com/FloatTech/AnimeAPI v1.7.1-0.20250530055006-50f5c7587c5b github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80 github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31
github.com/FloatTech/gg v1.1.3 github.com/FloatTech/gg v1.1.3
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
github.com/FloatTech/rendercard v0.2.0 github.com/FloatTech/rendercard v0.2.0
github.com/FloatTech/sqlite v1.7.1 github.com/FloatTech/sqlite v1.7.2
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
github.com/FloatTech/zbpctrl v1.7.0 github.com/FloatTech/zbpctrl v1.7.0
github.com/FloatTech/zbputils v1.7.2-0.20250601113004-1bee2a7cd4b6 github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438
github.com/Tnze/go-mc v1.20.2 github.com/Tnze/go-mc v1.20.2
github.com/antchfx/htmlquery v1.3.4 github.com/antchfx/htmlquery v1.3.4
github.com/corona10/goimagehash v1.1.0 github.com/corona10/goimagehash v1.1.0
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3 github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/fumiama/ahsai v0.1.0 github.com/fumiama/ahsai v0.1.1
github.com/fumiama/cron v1.3.0 github.com/fumiama/cron v1.3.0
github.com/fumiama/deepinfra v0.0.0-20250601112706-0175c95164c1 github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa
github.com/fumiama/go-base16384 v1.7.0 github.com/fumiama/go-base16384 v1.7.0
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8
github.com/fumiama/go-registry v0.2.7 github.com/fumiama/go-registry v0.2.7
github.com/fumiama/gotracemoe v0.0.3 github.com/fumiama/gotracemoe v0.0.3
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4 github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4
github.com/fumiama/terasu v0.0.0-20241027183601-987ab91031ce github.com/fumiama/terasu v1.0.1
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6 github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6
github.com/go-ego/gse v0.80.3
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/jinzhu/gorm v1.9.16 github.com/jinzhu/gorm v1.9.16
@ -38,63 +38,68 @@ require (
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5
github.com/lithammer/fuzzysearch v1.1.8 github.com/lithammer/fuzzysearch v1.1.8
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5
github.com/mmcdole/gofeed v1.3.0
github.com/mroth/weightedrand v1.0.0 github.com/mroth/weightedrand v1.0.0
github.com/notnil/chess v1.9.0 github.com/notnil/chess v1.10.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/shirou/gopsutil/v3 v3.24.5 github.com/shirou/gopsutil/v4 v4.25.11
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/tidwall/gjson v1.18.0 github.com/tidwall/gjson v1.18.0
github.com/wcharczuk/go-chart/v2 v2.1.2 github.com/wcharczuk/go-chart/v2 v2.1.2
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250330133859-27c25d9412b5 github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282
gitlab.com/gomidi/midi/v2 v2.1.7 gitlab.com/gomidi/midi/v2 v2.3.16
golang.org/x/image v0.24.0 golang.org/x/image v0.32.0
golang.org/x/sys v0.30.0 golang.org/x/sys v0.38.0
golang.org/x/text v0.22.0 golang.org/x/text v0.30.0
gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
github.com/PuerkitoBio/goquery v1.10.3 // indirect
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca // indirect github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
github.com/antchfx/xpath v1.3.3 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/antchfx/xpath v1.3.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/oto/v3 v3.4.0 // indirect
github.com/ebitengine/purego v0.9.1 // indirect
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect
github.com/faiface/beep v1.1.0 // indirect
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
github.com/fumiama/gofastTEA v0.0.10 // indirect github.com/fumiama/gofastTEA v0.1.3 // indirect
github.com/fumiama/imgsz v0.0.2 // indirect github.com/fumiama/imgsz v0.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.0.4 // indirect github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/gabriel-vasile/mimetype v1.4.10 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/hajimehoshi/oto v0.7.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jfreymuth/oggvorbis v1.0.1 // indirect github.com/gopxl/beep/v2 v2.1.1 // indirect
github.com/jfreymuth/vorbis v1.0.0 // indirect github.com/jfreymuth/oggvorbis v1.0.5 // indirect
github.com/jfreymuth/vorbis v1.0.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/mmcdole/goxpp v1.1.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pkumza/numcn v1.0.0 // indirect github.com/pkumza/numcn v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/tetratelabs/wazero v1.9.0 // indirect
github.com/tetratelabs/wazero v1.5.0 // indirect github.com/tidwall/match v1.2.0 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.11.0 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/vcaesar/cedar v0.20.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394 // indirect golang.org/x/net v0.46.0 // indirect
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
golang.org/x/net v0.33.0 // indirect modernc.org/libc v1.66.10 // indirect
modernc.org/libc v1.61.0 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.11.0 // indirect
modernc.org/memory v1.8.0 // indirect modernc.org/sqlite v1.39.1 // indirect
modernc.org/sqlite v1.33.1 // indirect
) )
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.29.10-simp replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.29.10-simp

252
go.sum
View File

@ -1,43 +1,50 @@
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw= github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y= github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250530055006-50f5c7587c5b h1:H/1xpchTGmdoHqrszH4gjafCyHIhsGSFryAkBNsu8OI= github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c h1:fmvlRUzwoK6KdoRSW+XeTQ9myKHimd0pV6GbmRJLNRo=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250530055006-50f5c7587c5b/go.mod h1:XXG1eBJf+eeWacQx5azsQKL5Gg7jDYTFyyZGIa/56js= github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c/go.mod h1:cuDd67B23xmICSmFBhWzXN51blod2BlM1liN9Ux0pSc=
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80 h1:lFD1pd8NkYCrw0QpTX/T5pJ67I7AL5eGxQ4v0r9f81Q= github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31 h1:2K+/M64ixD1Pg5hr00Nbxr7GoWQOgahvpmp1pAMnrYc=
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80/go.mod h1:IWoFFqu+0FeaHHQdddyiTRL5z7gJME6qHC96qh0R2sc= github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31/go.mod h1:kf+Ywc2lk8PLdg3RX0vrUmFLPO6k+23MFmt4GviV8C0=
github.com/FloatTech/gg v1.1.3 h1:+GlL02lTKsxJQr4WCuNwVxC1/eBZrCvypCIBtxuOFb4= github.com/FloatTech/gg v1.1.3 h1:+GlL02lTKsxJQr4WCuNwVxC1/eBZrCvypCIBtxuOFb4=
github.com/FloatTech/gg v1.1.3/go.mod h1:/9oLP54CMfq4r+71XL26uaFTJ1uL1boAyX67680/1HE= github.com/FloatTech/gg v1.1.3/go.mod h1:/9oLP54CMfq4r+71XL26uaFTJ1uL1boAyX67680/1HE=
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef h1:CJbK/2FRwPuZpeb6M4sWK2d7oXDnBEGhpkQuQrgc91A= github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef h1:CJbK/2FRwPuZpeb6M4sWK2d7oXDnBEGhpkQuQrgc91A=
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs= github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
github.com/FloatTech/rendercard v0.2.0 h1:PBTZ2gCEy/dAEGSfWecrGTrWDYpiBJD1dVzNDDaOxh4= github.com/FloatTech/rendercard v0.2.0 h1:PBTZ2gCEy/dAEGSfWecrGTrWDYpiBJD1dVzNDDaOxh4=
github.com/FloatTech/rendercard v0.2.0/go.mod h1:Sbojcy1t3NfFz7/WicZRmR/uKFxNMYkKF8qHx69dxY0= github.com/FloatTech/rendercard v0.2.0/go.mod h1:Sbojcy1t3NfFz7/WicZRmR/uKFxNMYkKF8qHx69dxY0=
github.com/FloatTech/sqlite v1.7.1 h1:XKUY0+MNaRmvEIgRv7QLbl7PFVpUfQ72+XQg+no2Vq0= github.com/FloatTech/sqlite v1.7.2 h1:b8COegNLSzofzOyARsVwSbz9OOzWEa8IElsTlx1TBLw=
github.com/FloatTech/sqlite v1.7.1/go.mod h1:/4tzfCGhrZnnjC1U8vcfwGQeF6eR649fhOsS3+Le0+s= github.com/FloatTech/sqlite v1.7.2/go.mod h1:/4tzfCGhrZnnjC1U8vcfwGQeF6eR649fhOsS3+Le0+s=
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 h1:snfw7FNFym1eNnLrQ/VCf80LiQo9C7jHgrunZDwiRcY= github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9DBy01APXKB68PmobhxOyaJI7lY=
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs= github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo= github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo=
github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE= github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
github.com/FloatTech/zbputils v1.7.2-0.20250601113004-1bee2a7cd4b6 h1:85LGKvgkWMZU065WOIEVaaeHDNYK01CwdNr/m+jzTKw= github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913 h1:uGexKAPL26sAWGemyHbfkjYyzFItMsbI8EREBLSZ/sU=
github.com/FloatTech/zbputils v1.7.2-0.20250601113004-1bee2a7cd4b6/go.mod h1:ArZ0fMAcmPEIXOqDmfzbSx+oYH8sssApQnbCu694iS8= github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913/go.mod h1:mNvv0+wCou042n/3QkK23WmbayNctT5wgkKC3A6nbmM=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU= github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU=
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w= github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 h1:bBmmB7he0iVN4m5mcehfheeRUEer/Avo4ujnxI3uCqs= github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438 h1:I0bdwHZ+2DY45b39xPoTD2u+Z8zhvBuu9aZfjMZeiZM=
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5/go.mod h1:0UcFaCkhp6vZw6l5Dpq0Dp673CoF9GdvA8lTfst0GiU= github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438/go.mod h1:GO+9i5UYB4BuZEel6BfGx7O1u3ggwgZWUnGxPATUoTE=
github.com/Tnze/go-mc v1.20.2 h1:arHCE/WxLCxY73C/4ZNLdOymRYtdwoXE05ohB7HVN6Q= github.com/Tnze/go-mc v1.20.2 h1:arHCE/WxLCxY73C/4ZNLdOymRYtdwoXE05ohB7HVN6Q=
github.com/Tnze/go-mc v1.20.2/go.mod h1:geoRj2HsXSkB3FJBuhr7wCzXegRlzWsVXd7h7jiJ6aQ= github.com/Tnze/go-mc v1.20.2/go.mod h1:geoRj2HsXSkB3FJBuhr7wCzXegRlzWsVXd7h7jiJ6aQ=
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew= github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4= github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca h1:kWzLcty5V2rzOqJM7Tp/MfSX0RMSI1x4IOLApEefYxA= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/antchfx/htmlquery v1.3.4 h1:Isd0srPkni2iNTWCwVj/72t7uCphFeor5Q8nCzj1jdQ= github.com/antchfx/htmlquery v1.3.4 h1:Isd0srPkni2iNTWCwVj/72t7uCphFeor5Q8nCzj1jdQ=
github.com/antchfx/htmlquery v1.3.4/go.mod h1:K9os0BwIEmLAvTqaNSua8tXLWRWZpocZIH73OzWQbwM= github.com/antchfx/htmlquery v1.3.4/go.mod h1:K9os0BwIEmLAvTqaNSua8tXLWRWZpocZIH73OzWQbwM=
github.com/antchfx/xpath v1.3.3 h1:tmuPQa1Uye0Ym1Zn65vxPgfltWb/Lxu2jeqIGteJSRs=
github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antchfx/xpath v1.3.5 h1:PqbXLC3TkfeZyakF5eeh3NTWEbYl4VHNVeufANzDbKQ=
github.com/antchfx/xpath v1.3.5/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI= github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI=
github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -49,77 +56,77 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/oto/v3 v3.4.0 h1:br0PgASsEWaoWn38b2Goe7m1GKFYfNgnsjSd5Gg+/bQ=
github.com/ebitengine/oto/v3 v3.4.0/go.mod h1:IOleLVD0m+CMak3mRVwsYY8vTctQgOM0iiL6S7Ar7eI=
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU= github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM= github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c= github.com/fumiama/ahsai v0.1.1 h1:/t5tdKRim0TK6YwgNFQfqtDOW7Y2tFBsmdUWt3JK+C0=
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4= github.com/fumiama/ahsai v0.1.1/go.mod h1:rBhHLgN2bygcqLpBi+XQa8B8Afn4UkPHQ5vvQibdbDQ=
github.com/fumiama/ahsai v0.1.0 h1:LXD61Kaj6kJHa3AEGsLIfKNzcgaVxg7JB72OR4yNNZ4=
github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk=
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo= github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY= github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
github.com/fumiama/deepinfra v0.0.0-20250601112706-0175c95164c1 h1:qE3l/y4Y1gMD2NokQ5Nw4NIUjL8ZwYLPIHOExQNu4hM= github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa h1:UMMNejpPp8dn92GPaVSZ2XKNSgp7+CVneOkZfExUilk=
github.com/fumiama/deepinfra v0.0.0-20250601112706-0175c95164c1/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY= github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa/go.mod h1:uqsWK/GM9OvKV0pXZOQB63rWugBbiXInY8E1JoRKhkg=
github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA= github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8 h1:aXk5IVXvPy2IfajL6gH+V/6ZOVV1BBVKjnFISLvyw60=
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8/go.mod h1:oH8DGDpRPjUAu8Fd/K+RxsB+z0Yis+BHeJAh+ZkO5EM=
github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs= github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs=
github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs= github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs=
github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o= github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o=
github.com/fumiama/go-simple-protobuf v0.2.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4= github.com/fumiama/go-simple-protobuf v0.2.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ= github.com/fumiama/gofastTEA v0.1.3 h1:fxOi2D66knV6QN170hb59YiqxPhjlgizvBw+o0OjxUA=
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk= github.com/fumiama/gofastTEA v0.1.3/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc= github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40= github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak= github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4= github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E=
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ= github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ=
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80= github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA= github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA=
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE= github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 h1:j9o0XVvdAeLwrBYMnh0SerrMc9CgNU6AGszbsvFzoc0=
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5/go.mod h1:FOjdw7KdCbK2eH3gRPhwFNCoXKpu9sN5vPH4El/8e0c=
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4 h1:zN9e09TYKXI1mNkuS6YbH+Sn+4k5tBir+ovhZZcRYAs= github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4 h1:zN9e09TYKXI1mNkuS6YbH+Sn+4k5tBir+ovhZZcRYAs=
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4/go.mod h1:iZf1H/Jcw5gjOOFb4C5nlweJtViWc7uwUxRCe14pbYk= github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4/go.mod h1:iZf1H/Jcw5gjOOFb4C5nlweJtViWc7uwUxRCe14pbYk=
github.com/fumiama/sqlite3 v1.29.10-simp h1:c5y3uKyU0q9t0/SyfynzYyuslQ5zP+5CD8e0yYY554A= github.com/fumiama/sqlite3 v1.29.10-simp h1:c5y3uKyU0q9t0/SyfynzYyuslQ5zP+5CD8e0yYY554A=
github.com/fumiama/sqlite3 v1.29.10-simp/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA= github.com/fumiama/sqlite3 v1.29.10-simp/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
github.com/fumiama/terasu v0.0.0-20241027183601-987ab91031ce h1:T6iDDU16rFyxV/FwfJJR6qcgkIlXJEIFlUTSmTD1h6s= github.com/fumiama/terasu v1.0.1 h1:WdP12r8xhRTyeCGWBtZx0QP0Eg5S3obJyS5MQVbBilE=
github.com/fumiama/terasu v0.0.0-20241027183601-987ab91031ce/go.mod h1:UVx8YP1jKKL1Cj+uy+OnQRM2Ih6U36Mqy9GSf7jabsI= github.com/fumiama/terasu v1.0.1/go.mod h1:ksDiLG3X7RM+B9XW2qvP+v8PU8hv+xhN5vdJdLoBWX4=
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6 h1:LtDgr628eji8jRpjPCxsk7ibjcfi97QieZVCTjxLCBw= github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6 h1:LtDgr628eji8jRpjPCxsk7ibjcfi97QieZVCTjxLCBw=
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg= github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
github.com/gabriel-vasile/mimetype v1.0.4 h1:uBejfH8l3/2f+5vjl1e4xIaSyNEhRBZ5N/ij7ohpNd8=
github.com/gabriel-vasile/mimetype v1.0.4/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= github.com/gabriel-vasile/mimetype v1.0.4/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
github.com/go-ego/gse v0.80.3 h1:YNFkjMhlhQnUeuoFcUEd1ivh6SOB764rT8GDsEbDiEg=
github.com/go-ego/gse v0.80.3/go.mod h1:Gt3A9Ry1Eso2Kza4MRaiZ7f2DTAvActmETY46Lxg0gU=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= github.com/gopxl/beep/v2 v2.1.1/go.mod h1:ZAm9TGQ9lvpoiFLd4zf5B1IuyxZhgRACMId1XJbaW0E=
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk= github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ=
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos= github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
github.com/jfreymuth/oggvorbis v1.0.1 h1:NT0eXBgE2WHzu6RT/6zcb2H10Kxj6Fm3PccT0LE6bqw=
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
github.com/jfreymuth/vorbis v1.0.0 h1:SmDf783s82lIjGZi8EGUUaS7YxPHgRj4ZXW/h7rUi7U=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@ -128,8 +135,11 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM= github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg= github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 h1:BXnB1Gz4y/zwQh+ZFNy7rgd+ZfMOrwRr4uZSHEI+ieY= github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 h1:BXnB1Gz4y/zwQh+ZFNy7rgd+ZfMOrwRr4uZSHEI+ieY=
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc= github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
@ -140,105 +150,107 @@ github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d h1:hTRDIpJ1FjS9ULJuEzu69n
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc= github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc=
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 h1:wnbHIeP1UX8ClYEWKGnw66PfYvReCHu9G5lXSte3Sqc= github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 h1:wnbHIeP1UX8ClYEWKGnw66PfYvReCHu9G5lXSte3Sqc=
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo= github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU= github.com/mmcdole/gofeed v1.3.0 h1:5yn+HeqlcvjMeAI4gu6T+crm7d0anY85+M+v6fIFNG4=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA= github.com/mmcdole/gofeed v1.3.0/go.mod h1:9TGv2LcJhdXePDzxiuMnukhV2/zb6VtnZt1mS+SjkLE=
github.com/mmcdole/goxpp v1.1.1 h1:RGIX+D6iQRIunGHrKqnA2+700XMCnNv0bAOOv5MUhx8=
github.com/mmcdole/goxpp v1.1.1/go.mod h1:v+25+lT2ViuQ7mVxcncQ8ch1URund48oH+jhjiwEgS8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E= github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE= github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/notnil/chess v1.9.0 h1:YMxR5kUVjtwcuFptGU0/3q7eG3MSHQNbg0VUekvRKV0= github.com/notnil/chess v1.10.0 h1:RR3MgS9G6zZmJ+VPTJolyxdaIgxoUPyUUY+2iaw35G0=
github.com/notnil/chess v1.9.0/go.mod h1:cRuJUIBFq9Xki05TWHJxHYkC+fFpq45IWwk94DdlCrA= github.com/notnil/chess v1.10.0/go.mod h1:cRuJUIBFq9Xki05TWHJxHYkC+fFpq45IWwk94DdlCrA=
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw=
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE= github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE=
github.com/pkumza/numcn v1.0.0/go.mod h1:QSeH+al9dWCd8di5HZM/ZqHqhZmUKfph572e9Ev/ETc= github.com/pkumza/numcn v1.0.0/go.mod h1:QSeH+al9dWCd8di5HZM/ZqHqhZmUKfph572e9Ev/ETc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=
github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/vcaesar/cedar v0.20.2 h1:TDx7AdZhilKcfE1WvdToTJf5VrC/FXcUOW+KY1upLZ4= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/vcaesar/cedar v0.20.2/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E= github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ= github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250330133859-27c25d9412b5 h1:HsMcBsVpYuQv+W8pjX5WdwYROrFQP9c5Pbf4x4adDus= github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282 h1:YctW/t88sQ0H8cJ69PWULU6xWfh8kNsX/XgCpW2OPHw=
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250330133859-27c25d9412b5/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M= github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282/go.mod h1:trueIIVRywKJa3ov4QphzVvzYzgCNrlXdf9JvPJOFW8=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
gitlab.com/gomidi/midi/v2 v2.1.7 h1:lIjVXH+bnGG04j/kUVOFILt0BQvBeGz8Kyz0l6aM830= gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
gitlab.com/gomidi/midi/v2 v2.1.7/go.mod h1:Cj6K9VH5GhYvPgL2JddxHBmZiP3nxKxB5XyTxiXvL9U= gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394 h1:bFYqOIMdeiCEdzPJkLiOoMDzW/v3tjW4AA/RmUZYsL8= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg=
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
@ -246,39 +258,41 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -298,31 +312,43 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk= modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs= modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

View File

@ -5,11 +5,11 @@ schema = 3
version = "v1.1.1" version = "v1.1.1"
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo=" hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
[mod."github.com/FloatTech/AnimeAPI"] [mod."github.com/FloatTech/AnimeAPI"]
version = "v1.7.1-0.20250530055006-50f5c7587c5b" version = "v1.7.1-0.20250926171956-ba37dfebfc4a"
hash = "sha256-xDXPwphMS26J02q/ysQy3CJPK5B9c7uoqwFt1xFIF5Q=" hash = "sha256-wtr9hgHSPsD5NqSmI3Lo8RVWE+cNMIUGo2bcsKTN8Gg="
[mod."github.com/FloatTech/floatbox"] [mod."github.com/FloatTech/floatbox"]
version = "v0.0.0-20250513111443-adba80e84e80" version = "v0.0.0-20251002074805-f95cbc7edb31"
hash = "sha256-Zt9zkUa3qqldrSttAq66YLPZPxrnkOR2MaU7oapIWEE=" hash = "sha256-c50unGhF0JVPHN8geZM/YYQKgGqJgCtVksh4Ij1Pg+4="
[mod."github.com/FloatTech/gg"] [mod."github.com/FloatTech/gg"]
version = "v1.1.3" version = "v1.1.3"
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo=" hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
@ -20,23 +20,26 @@ schema = 3
version = "v0.2.0" version = "v0.2.0"
hash = "sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs=" hash = "sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs="
[mod."github.com/FloatTech/sqlite"] [mod."github.com/FloatTech/sqlite"]
version = "v1.7.1" version = "v1.7.2"
hash = "sha256-1x8xH5fFDlLts8YfzgO3vLF45Q7Ah+mYI6Wn8JG/qE0=" hash = "sha256-R9QaP5FQwtWpHdbCoNX/rYOS/CgkIeRdFB9cwJ4n/JM="
[mod."github.com/FloatTech/ttl"] [mod."github.com/FloatTech/ttl"]
version = "v0.0.0-20240716161252-965925764562" version = "v0.0.0-20250224045156-012b1463287d"
hash = "sha256-/XjfdVXEzYgeM+OYuyy76tf13lO91vCcwpjWgkRGteU=" hash = "sha256-C5xBt0roPgahradCOTgkhL+j5bvoSXmGwdqcu0aSczc="
[mod."github.com/FloatTech/zbpctrl"] [mod."github.com/FloatTech/zbpctrl"]
version = "v1.7.0" version = "v1.7.0"
hash = "sha256-HDDnE0oktWJH1tkxuQwUUbeJhmVwY5fyc/vR72D2mkU=" hash = "sha256-HDDnE0oktWJH1tkxuQwUUbeJhmVwY5fyc/vR72D2mkU="
[mod."github.com/FloatTech/zbputils"] [mod."github.com/FloatTech/zbputils"]
version = "v1.7.2-0.20250601113004-1bee2a7cd4b6" version = "v1.7.2-0.20251002080916-b554b7039913"
hash = "sha256-pNL591h1gGP60wKEuvvF3DoshbaphoLze7Pa7gDA9bQ=" hash = "sha256-9z7c79uuFl2LKaCgW1gQN5lmMjgKIcKrakcBlb3zJ90="
[mod."github.com/PuerkitoBio/goquery"]
version = "v1.10.3"
hash = "sha256-Mth7nYm/MtcOhPMbHj7gXF+Mot7eDUBVN570RitGR/c="
[mod."github.com/RomiChan/syncx"] [mod."github.com/RomiChan/syncx"]
version = "v0.0.0-20240418144900-b7402ffdebc7" version = "v0.0.0-20240418144900-b7402ffdebc7"
hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4=" hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4="
[mod."github.com/RomiChan/websocket"] [mod."github.com/RomiChan/websocket"]
version = "v1.4.3-0.20220227141055-9b2c6168c9c5" version = "v1.4.3-0.20251002072000-d3eb41798438"
hash = "sha256-Adx+gvqB+CCoUXx7ebIaBDjVkav+wS5qZPmaqcApBWA=" hash = "sha256-vLu9Va+9AbOIdh1LEetz5JlJK0P2IXKsYRvCdAO8tYw="
[mod."github.com/Tnze/go-mc"] [mod."github.com/Tnze/go-mc"]
version = "v1.20.2" version = "v1.20.2"
hash = "sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI=" hash = "sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI="
@ -44,14 +47,17 @@ schema = 3
version = "v0.0.0-20170805034717-80a9c64b256d" version = "v0.0.0-20170805034717-80a9c64b256d"
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0=" hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
[mod."github.com/ajstarks/svgo"] [mod."github.com/ajstarks/svgo"]
version = "v0.0.0-20200320125537-f189e35d30ca" version = "v0.0.0-20211024235047-1546f124cd8b"
hash = "sha256-ALeRuEJN9jHjGb4wNKJcxC59vVx8Tj7hHikEGkaZZ0s=" hash = "sha256-sPwt5sImKFk949TzUeYEF2UiJDqHxXFJKRL2Y7JWJ6Y="
[mod."github.com/andybalholm/cascadia"]
version = "v1.3.3"
hash = "sha256-jv7ZshpSd7FZzKKN6hqlUgiR8C3y85zNIS/hq7g76Ho="
[mod."github.com/antchfx/htmlquery"] [mod."github.com/antchfx/htmlquery"]
version = "v1.3.4" version = "v1.3.4"
hash = "sha256-nrtIgRgdOvo0iIQyrhHOFKOmoT8e2gduUsct3f5zDNA=" hash = "sha256-nrtIgRgdOvo0iIQyrhHOFKOmoT8e2gduUsct3f5zDNA="
[mod."github.com/antchfx/xpath"] [mod."github.com/antchfx/xpath"]
version = "v1.3.3" version = "v1.3.5"
hash = "sha256-Ent9bgBTjKS8/61LKrIu/JcBI/Qsv6EEIojwsMjCgdY=" hash = "sha256-AVM0rR81hgVAI0QVzlz4WijFUjByf6Zew3ZwuikKw2Q="
[mod."github.com/corona10/goimagehash"] [mod."github.com/corona10/goimagehash"]
version = "v1.1.0" version = "v1.1.0"
hash = "sha256-HyS8nc7kUNnDaVBDzJ9Ym4pRs83YB4M2vHSRwfm6mr4=" hash = "sha256-HyS8nc7kUNnDaVBDzJ9Ym4pRs83YB4M2vHSRwfm6mr4="
@ -64,24 +70,30 @@ schema = 3
[mod."github.com/dustin/go-humanize"] [mod."github.com/dustin/go-humanize"]
version = "v1.0.1" version = "v1.0.1"
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc=" hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
[mod."github.com/ebitengine/oto/v3"]
version = "v3.4.0"
hash = "sha256-8JU4iu+2pUKWVWMpEe8EAZ8FVo3MZdILu82vVVmDSVY="
[mod."github.com/ebitengine/purego"]
version = "v0.9.0"
hash = "sha256-jSlhGjhuYf15zHy7shSKR1rQN1sRyH5zXAzWqy+huHY="
[mod."github.com/ericpauley/go-quantize"] [mod."github.com/ericpauley/go-quantize"]
version = "v0.0.0-20200331213906-ae555eb2afa4" version = "v0.0.0-20200331213906-ae555eb2afa4"
hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs=" hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs="
[mod."github.com/faiface/beep"]
version = "v1.1.0"
hash = "sha256-66qAbnJjUjhXofxlGCa6G1+vjQcSTyN/POCZvYzHaQo="
[mod."github.com/fumiama/ahsai"] [mod."github.com/fumiama/ahsai"]
version = "v0.1.0" version = "v0.1.1"
hash = "sha256-lSoos+SFjALcL0ZYPsbOb8wntwn2fcubvSsz0YKgL9c=" hash = "sha256-knYw0R5fhjE/asc/TwlGJDzVr+Oaj8sH7kr7x6Mqs3E="
[mod."github.com/fumiama/cron"] [mod."github.com/fumiama/cron"]
version = "v1.3.0" version = "v1.3.0"
hash = "sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k=" hash = "sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k="
[mod."github.com/fumiama/deepinfra"] [mod."github.com/fumiama/deepinfra"]
version = "v0.0.0-20250601112706-0175c95164c1" version = "v0.0.0-20250924162107-cf156d49a0fa"
hash = "sha256-/8Hufq5n84QHOgS0igYQWo1zxjOBBbrqad2wQfKHBhY=" hash = "sha256-D0lgA7jBDLE8v9ePDiWwH439eB5+cDlj2fKRAc0wUms="
[mod."github.com/fumiama/go-base16384"] [mod."github.com/fumiama/go-base16384"]
version = "v1.7.0" version = "v1.7.0"
hash = "sha256-vTAsBBYe2ISzb2Nba5E96unodZSkhMcqo6hbwR01nz8=" hash = "sha256-vTAsBBYe2ISzb2Nba5E96unodZSkhMcqo6hbwR01nz8="
[mod."github.com/fumiama/go-onebot-agent"]
version = "v0.0.0-20250926145606-37ebfa6131c8"
hash = "sha256-oq1SSyddsXhsFvSHFhqSEAF9SH03b2jI0KvGbsFPXYQ="
[mod."github.com/fumiama/go-registry"] [mod."github.com/fumiama/go-registry"]
version = "v0.2.7" version = "v0.2.7"
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA=" hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
@ -89,53 +101,53 @@ schema = 3
version = "v0.2.0" version = "v0.2.0"
hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw=" hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw="
[mod."github.com/fumiama/gofastTEA"] [mod."github.com/fumiama/gofastTEA"]
version = "v0.0.10" version = "v0.1.3"
hash = "sha256-FOCbkXoS8s/K54yZbhX5pmaN/ouELnCHZoNS8a90VAg=" hash = "sha256-/Qu57mkkFt7aFufhlkMYPgrWj5XCGbuM28EHDD8w4XY="
[mod."github.com/fumiama/gotracemoe"] [mod."github.com/fumiama/gotracemoe"]
version = "v0.0.3" version = "v0.0.3"
hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ=" hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ="
[mod."github.com/fumiama/imgsz"] [mod."github.com/fumiama/imgsz"]
version = "v0.0.2" version = "v0.0.4"
hash = "sha256-eYUjP1TKWUrsY++rzg4rezOvmvmjADZFBizIIDHnZtY=" hash = "sha256-rrGx+v41OEl0ATwL6u5TNcpfkCQbj3jFNnGiQUNu2qs="
[mod."github.com/fumiama/jieba"] [mod."github.com/fumiama/jieba"]
version = "v0.0.0-20221203025406-36c17a10b565" version = "v0.0.0-20221203025406-36c17a10b565"
hash = "sha256-DvDx1pdldkdaSszrbadM/VwqT9TTSmWl6G6a+ysXYEM=" 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"] [mod."github.com/fumiama/slowdo"]
version = "v0.0.0-20241001074058-27c4fe5259a4" version = "v0.0.0-20241001074058-27c4fe5259a4"
hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY=" hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY="
[mod."github.com/fumiama/terasu"] [mod."github.com/fumiama/terasu"]
version = "v0.0.0-20241027183601-987ab91031ce" version = "v1.0.1"
hash = "sha256-WiG5BD1Icwq61KpqkQdf6dl64jEhaDJb2zAQROqXwvc=" hash = "sha256-7pe0ByxkmqWeYsxWNwa8urfv6lK1cEPrW1b5l86eM1Y="
[mod."github.com/fumiama/unibase2n"] [mod."github.com/fumiama/unibase2n"]
version = "v0.0.0-20240530074540-ec743fd5a6d6" version = "v0.0.0-20240530074540-ec743fd5a6d6"
hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw=" hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw="
[mod."github.com/gabriel-vasile/mimetype"] [mod."github.com/gabriel-vasile/mimetype"]
version = "v1.0.4" version = "v1.4.10"
hash = "sha256-5hl9zBo3nkPt8dZfcLoOix8lAKLm3qIkWhopoS4V34E=" hash = "sha256-ha8NJOAWcmEfQaybfNxyUupt0+zlWxoAKLjCacew43s="
[mod."github.com/go-ego/gse"]
version = "v0.80.3"
hash = "sha256-uxTQN4cxE/ZReZqjlIEQ3WYD9w2Ec37LRHQftJXsSZQ="
[mod."github.com/go-ole/go-ole"] [mod."github.com/go-ole/go-ole"]
version = "v1.2.6" version = "v1.3.0"
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs=" hash = "sha256-tF8t3VcV71jQ4jbPL91BwR59AKDpUAFV1waIKzkXJu8="
[mod."github.com/golang/freetype"] [mod."github.com/golang/freetype"]
version = "v0.0.0-20170609003504-e2365dfdc4a0" version = "v0.0.0-20170609003504-e2365dfdc4a0"
hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA=" hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA="
[mod."github.com/golang/groupcache"] [mod."github.com/golang/groupcache"]
version = "v0.0.0-20210331224755-41bb18bfe9da" version = "v0.0.0-20241129210726-2c02b8208cf8"
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0=" hash = "sha256-AdLZ3dJLe/yduoNvZiXugZxNfmwJjNQyQGsIdzYzH74="
[mod."github.com/google/uuid"] [mod."github.com/google/uuid"]
version = "v1.6.0" version = "v1.6.0"
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw=" hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
[mod."github.com/hajimehoshi/oto"] [mod."github.com/gopxl/beep/v2"]
version = "v0.7.1" version = "v2.1.1"
hash = "sha256-eRgbEbsziY5F0oI7wAe29FepZG7uGmq2M4deouDHcXI=" hash = "sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU="
[mod."github.com/jfreymuth/oggvorbis"] [mod."github.com/jfreymuth/oggvorbis"]
version = "v1.0.1" version = "v1.0.5"
hash = "sha256-DpkiTLxAA/iCoiylpNRvMzvaDWtK+U4UMJYNnnCmJMU=" hash = "sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0="
[mod."github.com/jfreymuth/vorbis"] [mod."github.com/jfreymuth/vorbis"]
version = "v1.0.0" version = "v1.0.2"
hash = "sha256-6kTol+g3NnZ3MazD786fvraw7ydUf0RWNBzHpzgN9Jk=" hash = "sha256-gVS+/PZ5pDnswpTQNZILcrx5ZNq9ShXd6vXn7Jabes4="
[mod."github.com/jinzhu/gorm"] [mod."github.com/jinzhu/gorm"]
version = "v1.9.16" version = "v1.9.16"
hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc=" hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc="
@ -145,6 +157,9 @@ schema = 3
[mod."github.com/jozsefsallai/gophersauce"] [mod."github.com/jozsefsallai/gophersauce"]
version = "v1.0.1" version = "v1.0.1"
hash = "sha256-29DsfnGmK51DPunR/leRBKCcokN/yLoB7S2HxCsqtgY=" 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"] [mod."github.com/kanrichan/resvg-go"]
version = "v0.0.2-0.20231001163256-63db194ca9f5" version = "v0.0.2-0.20231001163256-63db194ca9f5"
hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds=" hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds="
@ -161,23 +176,35 @@ schema = 3
version = "v0.0.0-20231231122217-0372e1059ca5" version = "v0.0.0-20231231122217-0372e1059ca5"
hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8=" hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8="
[mod."github.com/lufia/plan9stats"] [mod."github.com/lufia/plan9stats"]
version = "v0.0.0-20211012122336-39d0f177ccd0" version = "v0.0.0-20251013123823-9fd1530e3ec3"
hash = "sha256-thb+rkDx5IeWMgw5/5jgu5gZ+6RjJAUXeMgSkJHhRlA=" hash = "sha256-N760qPHHaMcxICyA3Ap/b/3exi40AStu7458VPvC9GI="
[mod."github.com/mattn/go-isatty"] [mod."github.com/mattn/go-isatty"]
version = "v0.0.20" version = "v0.0.20"
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ=" 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"
hash = "sha256-LtZDUtflL06HnDuQiCS6cpoF3VPk+gmABkYXBvdQOz0="
[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"] [mod."github.com/mroth/weightedrand"]
version = "v1.0.0" version = "v1.0.0"
hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c=" hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c="
[mod."github.com/ncruces/go-strftime"] [mod."github.com/ncruces/go-strftime"]
version = "v0.1.9" version = "v1.0.0"
hash = "sha256-T0iw+UEckzueWHT88PkTnZZixyKCEa+DTLzIiiohuWY=" hash = "sha256-GYIwYDONuv/yTE0AEugCHQbtV3oiBaco93xUNYFcVBQ="
[mod."github.com/nfnt/resize"] [mod."github.com/nfnt/resize"]
version = "v0.0.0-20180221191011-83c6a9932646" version = "v0.0.0-20180221191011-83c6a9932646"
hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA=" hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA="
[mod."github.com/notnil/chess"] [mod."github.com/notnil/chess"]
version = "v1.9.0" version = "v1.10.0"
hash = "sha256-2bHp/H5hBE/hPMT1HLOBqMaCZ/DYWJMDri26O9Yzoms=" hash = "sha256-hsUOS4rVuMW+UCPJzhsZh3PHCi1Lol12BwKujcICayo="
[mod."github.com/pbnjay/memory"] [mod."github.com/pbnjay/memory"]
version = "v0.0.0-20210728143218-7b4eea64cf58" version = "v0.0.0-20210728143218-7b4eea64cf58"
hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA=" hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA="
@ -188,8 +215,8 @@ schema = 3
version = "v1.0.0" version = "v1.0.0"
hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg=" hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg="
[mod."github.com/power-devops/perfstat"] [mod."github.com/power-devops/perfstat"]
version = "v0.0.0-20210106213030-5aafc221ea8c" version = "v0.0.0-20240221224432-82ca36839d55"
hash = "sha256-ywykDYuqcMt0TvZOz1l9Z6Z2JMTYQw8cP2fT8AtpmX4=" hash = "sha256-ujzuJ1ttQgjHQJEij4O/2+I8DZaUVZQCQgA4ysfqulI="
[mod."github.com/remyoudompheng/bigfft"] [mod."github.com/remyoudompheng/bigfft"]
version = "v0.0.0-20230129092748-24d4a6f8daec" version = "v0.0.0-20230129092748-24d4a6f8daec"
hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM=" hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM="
@ -197,62 +224,53 @@ schema = 3
version = "v3.24.5" version = "v3.24.5"
hash = "sha256-tc+t1u7gf5A+Bd956dYeM8pGbxs9ezQHqKAKfLQLpuQ=" hash = "sha256-tc+t1u7gf5A+Bd956dYeM8pGbxs9ezQHqKAKfLQLpuQ="
[mod."github.com/shoenig/go-m1cpu"] [mod."github.com/shoenig/go-m1cpu"]
version = "v0.1.6" version = "v0.1.7"
hash = "sha256-hT+JP30BBllsXosK/lo89HV/uxxPLsUyO3dRaDiLnCg=" hash = "sha256-kIKIE9uxHOniFHGgMgtypYB/OPI8VSQxFUHXehlpuYY="
[mod."github.com/sirupsen/logrus"] [mod."github.com/sirupsen/logrus"]
version = "v1.9.3" version = "v1.9.3"
hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms=" hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms="
[mod."github.com/tetratelabs/wazero"] [mod."github.com/tetratelabs/wazero"]
version = "v1.5.0" version = "v1.9.0"
hash = "sha256-fGdJM4LJrZA9jxHuYVo4EUQ3I1k0IVG3QQCBCgZkeZI=" hash = "sha256-b8D0cDMuDgyjvJ6LFY8REdcL95BIjM27SeOEQWfB0+0="
[mod."github.com/tidwall/gjson"] [mod."github.com/tidwall/gjson"]
version = "v1.18.0" version = "v1.18.0"
hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I=" hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I="
[mod."github.com/tidwall/match"] [mod."github.com/tidwall/match"]
version = "v1.1.1"
hash = "sha256-M2klhPId3Q3T3VGkSbOkYl/2nLHnsG+yMbXkPkyrRdg="
[mod."github.com/tidwall/pretty"]
version = "v1.2.0" version = "v1.2.0"
hash = "sha256-esRQGsn2Ee/CiySlwyuOICSLdqUkH4P7u8qXszos8Yc=" hash = "sha256-O2wTU0SmNIEEOxfncl2BW2czgWeIW5vqR6+A7dtNtXI="
[mod."github.com/tidwall/pretty"]
version = "v1.2.1"
hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8="
[mod."github.com/tklauser/go-sysconf"] [mod."github.com/tklauser/go-sysconf"]
version = "v0.3.12" version = "v0.3.15"
hash = "sha256-91VBZNb3L2TZkEETF1AE4wnraLoGxKeofUbC5ZiWVHk=" hash = "sha256-Twh9dD/mfNb7Qr5p/KmaK5Xi25VJwj5jESZeJr0qeUc="
[mod."github.com/tklauser/numcpus"] [mod."github.com/tklauser/numcpus"]
version = "v0.6.1" version = "v0.10.0"
hash = "sha256-8eFcw4YI0w6+GPhU5xMMQjiio94q/O5PpNO3QsvXve0=" hash = "sha256-NWg68H2Y6MijtlscPaZlLQwgPthEwLV+WpRT01m6kkI="
[mod."github.com/vcaesar/cedar"]
version = "v0.20.2"
hash = "sha256-3WblBdkR9AZcvZCKSteBV5kdhahiFHG2dbLWfwrVkwM="
[mod."github.com/wcharczuk/go-chart/v2"] [mod."github.com/wcharczuk/go-chart/v2"]
version = "v2.1.2" version = "v2.1.2"
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM=" hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="
[mod."github.com/wdvxdr1123/ZeroBot"] [mod."github.com/wdvxdr1123/ZeroBot"]
version = "v1.8.2-0.20250330133859-27c25d9412b5" version = "v1.8.2-0.20251002074418-56567b7fc282"
hash = "sha256-gT3uFTg5E0Th3r1M1vLzr0QtOjbMusqEjD/ckoBdDFc=" hash = "sha256-KaoqopWcXqiRhGYNaA3UqYtXf27yMuBEj/bvqOWxaC4="
[mod."github.com/yusufpapurcu/wmi"] [mod."github.com/yusufpapurcu/wmi"]
version = "v1.2.4" version = "v1.2.4"
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA=" hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="
[mod."gitlab.com/gomidi/midi/v2"] [mod."gitlab.com/gomidi/midi/v2"]
version = "v2.1.7" version = "v2.3.16"
hash = "sha256-fbgxSMCk7PVII3sNEKuGWbN56fy3eM564Xb+lnYTxRQ=" hash = "sha256-o+6UtQH+TRSQlcX8J53esAA/b2c9e7BY7gcO5iSeOy0="
[mod."golang.org/x/exp/shiny"]
version = "v0.0.0-20250305212735-054e65f0b394"
hash = "sha256-+xzaSlgRHFa+sGnQG90/72vcJMhletsob/L+KG24P/A="
[mod."golang.org/x/image"] [mod."golang.org/x/image"]
version = "v0.24.0" version = "v0.32.0"
hash = "sha256-nhcznNf4ePM7d0Jy2Si0dpMt7KQfRF5Y5QzMpwFCAVg=" hash = "sha256-a5C5nG4IKFkqM/EXjt29wzjrkYEFLKlg5C0aBnXnlZw="
[mod."golang.org/x/mobile"]
version = "v0.0.0-20231127183840-76ac6878050a"
hash = "sha256-GdXSvrqQiJX6pOqc2Yr8gG0ZWysEE81YRl5qkt3JCMA="
[mod."golang.org/x/net"] [mod."golang.org/x/net"]
version = "v0.33.0" version = "v0.46.0"
hash = "sha256-9swkU9vp6IflUUqAzK+y8PytSmrKLuryidP3RmRfe0w=" hash = "sha256-GkAUXwqEJZF2t5dmxJVEE+t58EDzO24KtihqHqsrZH0="
[mod."golang.org/x/sys"] [mod."golang.org/x/sys"]
version = "v0.30.0" version = "v0.37.0"
hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8=" hash = "sha256-5aT0xP02sW1o9sfJHtWoGGNVYDdwb9FyiX/n6RAlzPo="
[mod."golang.org/x/text"] [mod."golang.org/x/text"]
version = "v0.22.0" version = "v0.30.0"
hash = "sha256-kUwLNFk9K/YuWmO5/u2IshrmhT2CCuk+mAShSlTTeZo=" hash = "sha256-VPT1Y2zzgdk+Q3Gx8hdwKdxbVh0/Zn/HwDpILCW3ZNA="
[mod."gopkg.in/yaml.v3"] [mod."gopkg.in/yaml.v3"]
version = "v3.0.1" version = "v3.0.1"
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
@ -261,11 +279,11 @@ schema = 3
hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w=" hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w="
replaced = "github.com/fumiama/libc" replaced = "github.com/fumiama/libc"
[mod."modernc.org/mathutil"] [mod."modernc.org/mathutil"]
version = "v1.6.0" version = "v1.7.1"
hash = "sha256-lfuEiS1odd2TWrTylnaGihSJ9myqKs3FLdpvd7PqTnE=" hash = "sha256-COZ5rF2GhQVR1r6a0DanJ8qwQ94JSKdQxTMWrDzE0Cc="
[mod."modernc.org/memory"] [mod."modernc.org/memory"]
version = "v1.8.0" version = "v1.11.0"
hash = "sha256-ucvPr73zg8LjvU+bcoIPKTgwgcon3U9VhKrLEMH81xg=" hash = "sha256-MkybF8vvrxXS5j7O8w3skwTo0aMo1yjWS0K440rYcHM="
[mod."modernc.org/sqlite"] [mod."modernc.org/sqlite"]
version = "v1.29.10-simp" version = "v1.29.10-simp"
hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE=" hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE="

View File

@ -3,13 +3,13 @@
package banner package banner
// Version ... // Version ...
var Version = "v1.9.8" var Version = "v1.10.0"
// Copyright ... // Copyright ...
var Copyright = "© 2020 - 2025 FloatTech" var Copyright = "© 2020 - 2025 FloatTech"
// Banner ... // Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" + var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - 2025-06-01 18:52:48 +0900 JST\n" + "* Version " + Version + " - 2025-09-30 23:45:28 +0800 CST\n" +
"* Copyright " + Copyright + ". All Rights Reserved.\n" + "* Copyright " + Copyright + ". All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin" "* Project: https://github.com/FloatTech/ZeroBot-Plugin"

View File

@ -27,7 +27,7 @@ var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin" "* Project: https://github.com/FloatTech/ZeroBot-Plugin"
` `
const timeformat = `2006-01-02 15:04:05 +0900 JST` const timeformat = `2006-01-02 15:04:05 +0800 CST`
func main() { func main() {
f, err := os.Create("banner/banner.go") f, err := os.Create("banner/banner.go")

View File

@ -1,5 +0,0 @@
//go:build go1.21
package kanban
const Error int = "请使用小于1.21版本的Go"

15
main.go
View File

@ -1,6 +1,8 @@
// Package main ZeroBot-Plugin main file // Package main ZeroBot-Plugin main file
package main package main
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/abineundo/ref -r .
import ( import (
"encoding/json" "encoding/json"
"flag" "flag"
@ -12,8 +14,8 @@ import (
"strings" "strings"
"time" "time"
_ "github.com/FloatTech/ZeroBot-Plugin/abineundo" // 设置插件优先级
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性 _ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner "github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- // // ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
@ -38,6 +40,8 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleepmanage" // 统计睡眠时间 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleepmanage" // 统计睡眠时间
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/airecord" // 群应用AI声聊
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/atri" // ATRI词库 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/atri" // ATRI词库
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/manager" // 群管 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/manager" // 群管
@ -65,6 +69,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/custom" // 自定义插件合集 _ "github.com/FloatTech/ZeroBot-Plugin/custom" // 自定义插件合集
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage" // AI画图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace" // AnimeTrace 动画/Galgame识别 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace" // AnimeTrace 动画/Galgame识别
@ -74,6 +79,8 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibiliparse" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibilipush" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bookreview" // 哀伤雪刃吧推书记录 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bookreview" // 哀伤雪刃吧推书记录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chess" // 国际象棋 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/chess" // 国际象棋
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
@ -81,6 +88,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/crypter" // 奇怪语言加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
@ -128,6 +136,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery" // 打劫群友的ATRI币 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery" // 打劫群友的ATRI币
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub" // RSSHub订阅姬
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
@ -142,11 +151,11 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinvilg" // 百度文心AI画图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordcount" // 聊天热词 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordcount" // 聊天热词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygocdb" // 游戏王白鸽API卡查
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygotrade" // 游戏王集换社卡价查询
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/yujn" // 遇见API _ "github.com/FloatTech/ZeroBot-Plugin/plugin/yujn" // 遇见API

View File

@ -1,6 +1,8 @@
package aichat package aichat
import ( import (
"errors"
"fmt"
"strconv" "strconv"
"strings" "strings"
@ -13,19 +15,99 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
var cfg = newconfig() var (
cfg = newconfig()
)
var (
apitypes = map[string]uint8{
"OpenAI": 0,
"OLLaMA": 1,
"GenAI": 2,
}
apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"}
)
// ModelType 支持打印 string 并生产 protocal
type ModelType int
func newModelType(typ string) (ModelType, error) {
t, ok := apitypes[typ]
if !ok {
return 0, errors.New("未知类型 " + typ)
}
return ModelType(t), nil
}
func (mt ModelType) String() string {
return apilist[mt]
}
func (mt ModelType) protocol(modn string, temp float32, topp float32, maxn uint) (mod model.Protocol, err error) {
switch cfg.Type {
case 0:
mod = model.NewOpenAI(
modn, cfg.Separator,
temp, topp, maxn,
)
case 1:
mod = model.NewOLLaMA(
modn, cfg.Separator,
temp, topp, maxn,
)
case 2:
mod = model.NewGenAI(
modn,
temp, topp, maxn,
)
default:
err = errors.New("unsupported model type " + strconv.Itoa(int(cfg.Type)))
}
return
}
// ModelBool 支持打印成 "是/否"
type ModelBool bool
func (mb ModelBool) String() string {
if mb {
return "是"
}
return "否"
}
// ModelKey 支持隐藏密钥
type ModelKey string
func (mk ModelKey) String() string {
if len(mk) == 0 {
return "未设置"
}
if len(mk) <= 4 {
return "****"
}
key := string(mk)
return key[:2] + strings.Repeat("*", len(key)-4) + key[len(key)-2:]
}
type config struct { type config struct {
ModelName string ModelName string
Type int ImageModelName string
AgentModelName string
Type ModelType
ImageType ModelType
AgentType ModelType
MaxN uint MaxN uint
TopP float32 TopP float32
SystemP string SystemP string
API string API string
Key string ImageAPI string
AgentAPI string
Key ModelKey
ImageKey ModelKey
AgentKey ModelKey
Separator string Separator string
NoReplyAT bool NoSystemP ModelBool
NoSystemP bool
} }
func newconfig() config { func newconfig() config {
@ -36,10 +118,50 @@ func newconfig() config {
} }
} }
func (c *config) String() string {
topp, maxn := c.mparams()
sb := strings.Builder{}
sb.WriteString(fmt.Sprintf("• 模型名:%s\n", c.ModelName))
sb.WriteString(fmt.Sprintf("• 图像模型名:%s\n", c.ImageModelName))
sb.WriteString(fmt.Sprintf("• Agent模型名%s\n", c.AgentModelName))
sb.WriteString(fmt.Sprintf("• 接口类型:%v\n", c.Type))
sb.WriteString(fmt.Sprintf("• 图像接口类型:%v\n", c.ImageType))
sb.WriteString(fmt.Sprintf("• Agent接口类型%v\n", c.AgentType))
sb.WriteString(fmt.Sprintf("• 最大长度:%d\n", maxn))
sb.WriteString(fmt.Sprintf("• TopP%.1f\n", topp))
sb.WriteString(fmt.Sprintf("• 系统提示词:%s\n", c.SystemP))
sb.WriteString(fmt.Sprintf("• 接口地址:%s\n", c.API))
sb.WriteString(fmt.Sprintf("• 图像接口地址:%s\n", c.ImageAPI))
sb.WriteString(fmt.Sprintf("• Agent接口地址%s\n", c.AgentAPI))
sb.WriteString(fmt.Sprintf("• 密钥:%v\n", c.Key))
sb.WriteString(fmt.Sprintf("• 图像密钥:%v\n", c.ImageKey))
sb.WriteString(fmt.Sprintf("• Agent密钥%v\n", c.AgentKey))
sb.WriteString(fmt.Sprintf("• 分隔符:%s\n", c.Separator))
sb.WriteString(fmt.Sprintf("• 支持系统提示词:%v\n", !c.NoSystemP))
return sb.String()
}
func (c *config) isvalid() bool { func (c *config) isvalid() bool {
return c.ModelName != "" && c.API != "" && c.Key != "" return c.ModelName != "" && c.API != "" && c.Key != ""
} }
// 获取全局模型参数TopP和最大长度
func (c *config) mparams() (topp float32, maxn uint) {
// 处理TopP参数
topp = c.TopP
if topp == 0 {
topp = 0.9
}
// 处理最大长度参数
maxn = c.MaxN
if maxn == 0 {
maxn = 4096
}
return topp, maxn
}
func ensureconfig(ctx *zero.Ctx) bool { func ensureconfig(ctx *zero.Ctx) bool {
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok { if !ok {
@ -57,7 +179,7 @@ func ensureconfig(ctx *zero.Ctx) bool {
return true return true
} }
func newextrasetstr(ptr *string) func(ctx *zero.Ctx) { func newextrasetstr[T ~string](ptr *T) func(ctx *zero.Ctx) {
return func(ctx *zero.Ctx) { return func(ctx *zero.Ctx) {
args := strings.TrimSpace(ctx.State["args"].(string)) args := strings.TrimSpace(ctx.State["args"].(string))
if args == "" { if args == "" {
@ -69,7 +191,7 @@ func newextrasetstr(ptr *string) func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("ERROR: no such plugin")) ctx.SendChain(message.Text("ERROR: no such plugin"))
return return
} }
*ptr = args *ptr = T(args)
err := c.SetExtra(&cfg) err := c.SetExtra(&cfg)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: set extra err: ", err)) ctx.SendChain(message.Text("ERROR: set extra err: ", err))
@ -79,7 +201,7 @@ func newextrasetstr(ptr *string) func(ctx *zero.Ctx) {
} }
} }
func newextrasetbool(ptr *bool) func(ctx *zero.Ctx) { func newextrasetbool[T ~bool](ptr *T) func(ctx *zero.Ctx) {
return func(ctx *zero.Ctx) { return func(ctx *zero.Ctx) {
args := ctx.State["regex_matched"].([]string) args := ctx.State["regex_matched"].([]string)
isno := args[1] == "不" isno := args[1] == "不"
@ -88,7 +210,7 @@ func newextrasetbool(ptr *bool) func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("ERROR: no such plugin")) ctx.SendChain(message.Text("ERROR: no such plugin"))
return return
} }
*ptr = isno *ptr = T(isno)
err := c.SetExtra(&cfg) err := c.SetExtra(&cfg)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: set extra err: ", err)) ctx.SendChain(message.Text("ERROR: set extra err: ", err))
@ -151,3 +273,30 @@ func newextrasetfloat32(ptr *float32) func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("成功")) ctx.SendChain(message.Text("成功"))
} }
} }
func newextrasetmodeltype(ptr *ModelType) func(ctx *zero.Ctx) {
return func(ctx *zero.Ctx) {
args := strings.TrimSpace(ctx.State["args"].(string))
if args == "" {
ctx.SendChain(message.Text("ERROR: empty args"))
return
}
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
ctx.SendChain(message.Text("ERROR: no such plugin"))
return
}
typ, err := newModelType(args)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
*ptr = typ
err = c.SetExtra(&cfg)
if err != nil {
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
return
}
ctx.SendChain(message.Text("成功"))
}
}

View File

@ -1,22 +1,29 @@
// Package aichat OpenAI聊天 // Package aichat OpenAI聊天和群聊总结
package aichat package aichat
import ( import (
"encoding/json"
"math/rand" "math/rand"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/fumiama/deepinfra" "github.com/fumiama/deepinfra"
"github.com/fumiama/deepinfra/model" "github.com/fumiama/deepinfra/model"
goba "github.com/fumiama/go-onebot-agent"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/AnimeAPI/airecord"
"github.com/FloatTech/floatbox/process" "github.com/FloatTech/floatbox/process"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/chat" "github.com/FloatTech/zbputils/chat"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
) )
var ( var (
@ -27,44 +34,62 @@ var (
Brief: "OpenAI聊天", Brief: "OpenAI聊天",
Help: "- 设置AI聊天触发概率10\n" + Help: "- 设置AI聊天触发概率10\n" +
"- 设置AI聊天温度80\n" + "- 设置AI聊天温度80\n" +
"- 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI]\n" + "- 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI]\n" +
"- 设置AI聊天(不)使用Agent模式\n" +
"- 设置AI聊天(不)支持系统提示词\n" + "- 设置AI聊天(不)支持系统提示词\n" +
"- 设置AI聊天接口地址https://xxx\n" + "- 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions\n" +
"- 设置AI聊天密钥xxx\n" + "- 设置AI聊天(识图|Agent)密钥xxx\n" +
"- 设置AI聊天模型名xxx\n" + "- 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B\n" +
"- 查看AI聊天系统提示词\n" + "- 查看AI聊天系统提示词\n" +
"- 重置AI聊天系统提示词\n" + "- 重置AI聊天系统提示词\n" +
"- 设置AI聊天系统提示词xxx\n" + "- 设置AI聊天系统提示词xxx\n" +
"- 设置AI聊天分隔符</think>(留空则清除)\n" + "- 设置AI聊天分隔符</think>(留空则清除)\n" +
"- 设置AI聊天(不)响应AT\n" + "- 设置AI聊天(不)响应AT\n" +
"- 设置AI聊天最大长度4096\n" + "- 设置AI聊天最大长度4096\n" +
"- 设置AI聊天TopP 0.9", "- 设置AI聊天TopP 0.9\n" +
"- 设置AI聊天(不)以AI语音输出\n" +
"- 查看AI聊天配置\n" +
"- 重置AI聊天\n" +
"- 群聊总结 [消息数目]|群聊总结 1000\n" +
"- /gpt [内容] (使用大模型聊天)\n",
PrivateDataFolder: "aichat", PrivateDataFolder: "aichat",
}) }).ApplySingle(single.New(
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
if ctx.Event.GroupID == 0 {
return -ctx.Event.UserID
}
return ctx.Event.GroupID
}),
// no post option, silently quit
))
) )
var apitypes = map[string]uint8{ var (
"OpenAI": 0, limit = ctxext.NewLimiterManager(time.Second*30, 1)
"OLLaMA": 1, )
"GenAI": 2,
}
func init() { func init() {
en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool { en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
stor, err := newstorage(ctx, gid)
if err != nil {
logrus.Warnln("ERROR: ", err)
return false
}
ctx.State["__aichat_stor__"] = stor
return ctx.ExtractPlainText() != "" && return ctx.ExtractPlainText() != "" &&
(!cfg.NoReplyAT || (cfg.NoReplyAT && !ctx.Event.IsToMe)) (!stor.noreplyat() || (stor.noreplyat() && !ctx.Event.IsToMe))
}).SetBlock(false).Handle(func(ctx *zero.Ctx) { }).SetBlock(false).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID gid := ctx.Event.GroupID
if gid == 0 { if gid == 0 {
gid = -ctx.Event.UserID gid = -ctx.Event.UserID
} }
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) stor := ctx.State["__aichat_stor__"].(storage)
if !ok { rate := stor.rate()
return
}
rate := c.GetData(gid)
temp := (rate >> 8) & 0xff
rate &= 0xff
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) { if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
return return
} }
@ -75,47 +100,66 @@ func init() {
logrus.Warnln("ERROR: get extra err: empty key") logrus.Warnln("ERROR: get extra err: empty key")
return return
} }
temperature := stor.temp()
topp, maxn := cfg.mparams()
if temp <= 0 { if !stor.noagent() && cfg.AgentAPI != "" && cfg.AgentModelName != "" {
temp = 70 // default setting x := deepinfra.NewAPI(cfg.AgentAPI, string(cfg.AgentKey))
} mod, err := cfg.Type.protocol(cfg.AgentModelName, temperature, topp, maxn)
if temp > 100 { if err != nil {
temp = 100 logrus.Warnln("ERROR: ", err)
}
x := deepinfra.NewAPI(cfg.API, cfg.Key)
var mod model.Protocol
maxn := cfg.MaxN
if maxn == 0 {
maxn = 4096
}
topp := cfg.TopP
if topp == 0 {
topp = 0.9
}
switch cfg.Type {
case 0:
mod = model.NewOpenAI(
cfg.ModelName, cfg.Separator,
float32(temp)/100, topp, maxn,
)
case 1:
mod = model.NewOLLaMA(
cfg.ModelName, cfg.Separator,
float32(temp)/100, topp, maxn,
)
case 2:
mod = model.NewGenAI(
cfg.ModelName,
float32(temp)/100, topp, maxn,
)
default:
logrus.Warnln("[aichat] unsupported AI type", cfg.Type)
return return
} }
role := goba.PermRoleUser
if zero.AdminPermission(ctx) {
role = goba.PermRoleAdmin
if zero.SuperUserPermission(ctx) {
role = goba.PermRoleOwner
}
}
ag := chat.AgentOf(ctx.Event.SelfID)
if cfg.ImageAPI != "" && !ag.CanViewImage() {
mod, err := cfg.ImageType.protocol(cfg.ImageModelName, temperature, topp, maxn)
if err != nil {
logrus.Warnln("ERROR: ", err)
return
}
ag.SetViewImageAPI(deepinfra.NewAPI(cfg.ImageAPI, string(cfg.ImageKey)), mod)
}
ctx.NoTimeout()
hasresp := false
for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role)
if len(reqs) == 0 {
break
}
hasresp = true
for _, req := range reqs {
resp := ctx.CallAction(req.Action, req.Params)
logrus.Infoln("[aichat] agent get resp:", reqs)
ag.AddResponse(gid, &goba.APIResponse{
Status: resp.Status,
Data: json.RawMessage(resp.Data.Raw),
Message: resp.Message,
Wording: resp.Wording,
RetCode: resp.RetCode,
})
}
}
if hasresp {
ag.AddTerminus(gid)
return
}
// no response, fall back to normal chat
}
data, err := x.Request(chat.Ask(mod, gid, cfg.SystemP, cfg.NoSystemP)) x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
mod, err := cfg.Type.protocol(cfg.ModelName, temperature, topp, maxn)
if err != nil {
logrus.Warnln("ERROR: ", err)
return
}
data, err := x.Request(chat.GetChatContext(mod, gid, cfg.SystemP, bool(cfg.NoSystemP)))
if err != nil { if err != nil {
logrus.Warnln("[aichat] post err:", err) logrus.Warnln("[aichat] post err:", err)
return return
@ -123,7 +167,7 @@ func init() {
txt := chat.Sanitize(strings.Trim(data, "\n  ")) txt := chat.Sanitize(strings.Trim(data, "\n  "))
if len(txt) > 0 { if len(txt) > 0 {
chat.Reply(gid, txt) chat.AddChatReply(gid, txt)
nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))] nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))]
txt = strings.ReplaceAll(txt, "{name}", ctx.CardOrNickName(ctx.Event.UserID)) txt = strings.ReplaceAll(txt, "{name}", ctx.CardOrNickName(ctx.Event.UserID))
txt = strings.ReplaceAll(txt, "{me}", nick) txt = strings.ReplaceAll(txt, "{me}", nick)
@ -135,111 +179,53 @@ func init() {
if t == "" { if t == "" {
continue continue
} }
logrus.Infoln("[aichat] 回复内容:", t)
recCfg := airecord.GetConfig()
record := ""
if !stor.norecord() {
record = ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, t)
}
if record != "" {
ctx.SendChain(message.Record(record))
} else {
if id != nil { if id != nil {
id = ctx.SendChain(message.Reply(id), message.Text(t)) id = ctx.SendChain(message.Reply(id), message.Text(t))
} else { } else {
id = ctx.SendChain(message.Text(t)) id = ctx.SendChain(message.Text(t))
} }
}
process.SleepAbout1sTo2s() process.SleepAbout1sTo2s()
} }
} }
}) })
en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).
args := strings.TrimSpace(ctx.State["args"].(string)) Handle(ctxext.NewStorageSaveBitmapHandler(bitmaprate, 0, 100))
if args == "" { en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).
ctx.SendChain(message.Text("ERROR: empty args")) Handle(ctxext.NewStorageSaveBitmapHandler(bitmaptemp, 0, 100))
return en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
} Handle(newextrasetmodeltype(&cfg.Type))
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) en.OnPrefix("设置AI聊天识图接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
if !ok { Handle(newextrasetmodeltype(&cfg.ImageType))
ctx.SendChain(message.Text("ERROR: no such plugin")) en.OnPrefix("设置AI聊天Agent接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
return Handle(newextrasetmodeltype(&cfg.AgentType))
}
r, err := strconv.Atoi(args)
if err != nil {
ctx.SendChain(message.Text("ERROR: parse rate err: ", err))
return
}
if r > 100 {
r = 100
} else if r < 0 {
r = 0
}
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
val := c.GetData(gid) & (^0xff)
err = c.SetData(gid, val|int64(r&0xff))
if err != nil {
ctx.SendChain(message.Text("ERROR: set data err: ", err))
return
}
ctx.SendChain(message.Text("成功"))
})
en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
args := strings.TrimSpace(ctx.State["args"].(string))
if args == "" {
ctx.SendChain(message.Text("ERROR: empty args"))
return
}
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
ctx.SendChain(message.Text("ERROR: no such plugin"))
return
}
r, err := strconv.Atoi(args)
if err != nil {
ctx.SendChain(message.Text("ERROR: parse rate err: ", err))
return
}
if r > 100 {
r = 100
} else if r < 0 {
r = 0
}
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
val := c.GetData(gid) & (^0xff00)
err = c.SetData(gid, val|(int64(r&0xff)<<8))
if err != nil {
ctx.SendChain(message.Text("ERROR: set data err: ", err))
return
}
ctx.SendChain(message.Text("成功"))
})
en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
args := strings.TrimSpace(ctx.State["args"].(string))
if args == "" {
ctx.SendChain(message.Text("ERROR: empty args"))
return
}
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
ctx.SendChain(message.Text("ERROR: no such plugin"))
return
}
typ, ok := apitypes[args]
if !ok {
ctx.SendChain(message.Text("ERROR: 未知类型 ", args))
return
}
cfg.Type = int(typ)
err := c.SetExtra(&cfg)
if err != nil {
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
return
}
ctx.SendChain(message.Text("成功"))
})
en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.API)) Handle(newextrasetstr(&cfg.API))
en.OnPrefix("设置AI聊天识图接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.ImageAPI))
en.OnPrefix("设置AI聊天Agent接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.AgentAPI))
en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.Key)) Handle(newextrasetstr(&cfg.Key))
en.OnPrefix("设置AI聊天识图密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.ImageKey))
en.OnPrefix("设置AI聊天Agent密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.AgentKey))
en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.ModelName)) Handle(newextrasetstr(&cfg.ModelName))
en.OnPrefix("设置AI聊天识图模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.ImageModelName))
en.OnPrefix("设置AI聊天Agent模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.AgentModelName))
en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.SystemP)) Handle(newextrasetstr(&cfg.SystemP))
en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
@ -262,11 +248,240 @@ func init() {
en.OnPrefix("设置AI聊天分隔符", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天分隔符", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetstr(&cfg.Separator)) Handle(newextrasetstr(&cfg.Separator))
en.OnRegex("^设置AI聊天(不)?响应AT$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnRegex("^设置AI聊天(不)?响应AT$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetbool(&cfg.NoReplyAT)) Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrat))
en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetbool(&cfg.NoSystemP)) Handle(newextrasetbool(&cfg.NoSystemP))
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", ensureconfig, zero.SuperUserPermission).SetBlock(true).
Handle(ctxext.NewStorageSaveBoolHandler(bitmapnagt))
en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetuint(&cfg.MaxN)) Handle(newextrasetuint(&cfg.MaxN))
en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(newextrasetfloat32(&cfg.TopP)) Handle(newextrasetfloat32(&cfg.TopP))
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", ensureconfig, zero.AdminPermission).SetBlock(true).
Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrec))
en.OnFullMatch("查看AI聊天配置", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
stor, err := newstorage(ctx, gid)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(
message.Text(
"【当前AI聊天本群配置】\n",
"• 触发概率:", int(stor.rate()), "\n",
"• 温度:", stor.temp(), "\n",
"• 以AI语音输出", ModelBool(!stor.norecord()), "\n",
"• 使用Agent", ModelBool(!stor.noagent()), "\n",
"• 响应@", ModelBool(!stor.noreplyat()), "\n",
),
message.Text("【当前AI聊天全局配置】\n", &cfg),
)
})
en.OnFullMatch("重置AI聊天", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
chat.ResetChat()
ctx.SendChain(message.Text("成功"))
})
// 添加群聊总结功能
en.OnRegex(`^群聊总结\s?(\d*)$`, ensureconfig, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(limit.LimitByGroup).Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("少女思考中..."))
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
if p > 1000 {
p = 1000
}
if p == 0 {
p = 200
}
group := ctx.GetGroupInfo(gid, false)
if group.MemberCount == 0 {
ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获取总结"))
return
}
var messages []string
h := ctx.GetGroupMessageHistory(gid, 0, p, false)
h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool {
nickname := msgObj.Get("sender.nickname").Str
text := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText())
if text != "" {
messages = append(messages, nickname+": "+text)
}
return true
})
if len(messages) == 0 {
ctx.SendChain(message.Text("ERROR: 历史消息为空或者无法获得历史消息"))
return
}
// 构造总结请求提示 (使用通用版省流提示词)
// 使用反引号定义多行字符串,更清晰
promptTemplate := `请对以下群聊对话进行极简总结
要求
1. 剔除客套与废话直击主题
2. 使用 Markdown 列表格式
3. 按以下结构输出
- 🎯 核心议题(一句话概括)
- 💡 关键观点/结论(提取3-5个重点)
- 下一步/待办(如果有明确谁做什么)
群聊对话内容如下
`
summaryPrompt := promptTemplate + strings.Join(messages, "\n")
stor, err := newstorage(ctx, gid)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 调用大模型API进行总结
summary, err := llmchat(summaryPrompt, stor.temp())
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
var b strings.Builder
b.WriteString("群 ")
b.WriteString(group.Name)
b.WriteByte('(')
b.WriteString(strconv.FormatInt(gid, 10))
b.WriteString(") 的 ")
b.WriteString(strconv.FormatInt(p, 10))
b.WriteString(" 条消息总结:\n\n")
b.WriteString(summary)
// 分割总结内容为多段按1000字符长度切割
summaryText := b.String()
msg := make(message.Message, 0)
for len(summaryText) > 0 {
if len(summaryText) <= 1000 {
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(summaryText)))
break
}
// 查找1000字符内的最后一个换行符尽量在换行处分割
chunk := summaryText[:1000]
lastNewline := strings.LastIndex(chunk, "\n")
if lastNewline > 0 {
chunk = summaryText[:lastNewline+1]
}
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(chunk)))
summaryText = summaryText[len(chunk):]
}
if len(msg) > 0 {
ctx.Send(msg)
}
})
// 添加 /gpt 命令处理(同时支持回复消息和直接使用)
en.OnKeyword("/gpt", ensureconfig).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
text := ctx.MessageString()
var query string
var replyContent string
// 检查是否是回复消息 (使用MessageElement检查而不是CQ码)
for _, elem := range ctx.Event.Message {
if elem.Type == "reply" {
// 提取被回复的消息ID
replyIDStr := elem.Data["id"]
replyID, err := strconv.ParseInt(replyIDStr, 10, 64)
if err == nil {
// 获取被回复的消息内容
replyMsg := ctx.GetMessage(replyID)
if replyMsg.Elements != nil {
replyContent = replyMsg.Elements.ExtractPlainText()
}
}
break // 找到回复元素后退出循环
}
}
// 提取 /gpt 后面的内容
parts := strings.SplitN(text, "/gpt", 2)
var gContent string
if len(parts) > 1 {
gContent = strings.TrimSpace(parts[1])
}
// 组合内容:优先使用回复内容,如果同时有/gpt内容则拼接
switch {
case replyContent != "" && gContent != "":
query = replyContent + "\n" + gContent
case replyContent != "":
query = replyContent
case gContent != "":
query = gContent
default:
return
}
stor, err := newstorage(ctx, gid)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 调用大模型API进行聊天
reply, err := llmchat(query, stor.temp())
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 分割总结内容为多段按1000字符长度切割
msg := make(message.Message, 0)
for len(reply) > 0 {
if len(reply) <= 1000 {
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(reply)))
break
}
// 查找1000字符内的最后一个换行符尽量在换行处分割
chunk := reply[:1000]
lastNewline := strings.LastIndex(chunk, "\n")
if lastNewline > 0 {
chunk = reply[:lastNewline+1]
}
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(chunk)))
reply = reply[len(chunk):]
}
if len(msg) > 0 {
ctx.Send(msg)
}
})
}
// llmchat 调用大模型API包装
func llmchat(prompt string, temp float32) (string, error) {
topp, maxn := cfg.mparams()
x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
mod, err := cfg.Type.protocol(cfg.ModelName, temp, topp, maxn)
if err != nil {
return "", nil
}
data, err := x.Request(mod.User(model.NewContentText(prompt)))
if err != nil {
return "", err
}
return strings.TrimSpace(data), nil
} }

49
plugin/aichat/storage.go Normal file
View File

@ -0,0 +1,49 @@
package aichat
import (
"github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot"
)
const (
bitmaprate = 0x0000ff
bitmaptemp = 0x00ff00
bitmapnagt = 0x010000
bitmapnrec = 0x020000
bitmapnrat = 0x040000
)
type storage ctxext.Storage
func newstorage(ctx *zero.Ctx, gid int64) (storage, error) {
s, err := ctxext.NewStorage(ctx, gid)
return storage(s), err
}
func (s storage) rate() uint8 {
return uint8((ctxext.Storage)(s).Get(bitmaprate))
}
func (s storage) temp() float32 {
temp := int8((ctxext.Storage)(s).Get(bitmaptemp))
// 处理温度参数
if temp <= 0 {
temp = 70 // default setting
}
if temp > 100 {
temp = 100
}
return float32(temp) / 100
}
func (s storage) noagent() bool {
return (ctxext.Storage)(s).GetBool(bitmapnagt)
}
func (s storage) norecord() bool {
return (ctxext.Storage)(s).GetBool(bitmapnrec)
}
func (s storage) noreplyat() bool {
return (ctxext.Storage)(s).GetBool(bitmapnrat)
}

View File

@ -0,0 +1,149 @@
package aichat
import (
"testing"
"github.com/FloatTech/zbputils/ctxext"
)
func TestStorage_rate(t *testing.T) {
s := storage(ctxext.Storage(0))
// 测试默认值
if rate := s.rate(); rate != 0 {
t.Errorf("default rate() = %v, want 0", rate)
}
// 设置值并测试
s = storage((ctxext.Storage)(s).Set(int64(100), bitmaprate))
if rate := s.rate(); rate != 100 {
t.Errorf("rate() after set = %v, want 100", rate)
}
}
func TestStorage_temp(t *testing.T) {
s := storage(ctxext.Storage(0))
tests := []struct {
name string
setValue int64
expected float32
}{
{"default temp (0)", 0, 0.70}, // 默认值 70/100
{"valid temp 50", 50, 0.50}, // 50/100 = 0.50
{"valid temp 80", 80, 0.80}, // 80/100 = 0.80
{"max temp 100", 100, 1.00}, // 100/100 = 1.00
{"over max temp", 127, 1.00}, // 限制为 100/100 = 1.00
{"negative temp", -10, 0.70}, // 默认值 70/100
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s = storage((ctxext.Storage)(s).Set(tt.setValue, bitmaptemp))
result := s.temp()
if result != tt.expected {
t.Errorf("temp() = %v, want %v", result, tt.expected)
}
})
}
}
func TestStorage_noagent(t *testing.T) {
s := storage(ctxext.Storage(0))
// 测试默认值
if noagent := s.noagent(); noagent != false {
t.Errorf("default noagent() = %v, want false", noagent)
}
// 设置为 true 并测试
s = storage((ctxext.Storage)(s).Set(1, bitmapnagt))
if noagent := s.noagent(); noagent != true {
t.Errorf("noagent() after set true = %v, want true", noagent)
}
}
func TestStorage_norecord(t *testing.T) {
s := storage(ctxext.Storage(0))
// 测试默认值
if norecord := s.norecord(); norecord != false {
t.Errorf("default norecord() = %v, want false", norecord)
}
// 设置为 true 并测试
s = storage((ctxext.Storage)(s).Set(1, bitmapnrec))
if norecord := s.norecord(); norecord != true {
t.Errorf("norecord() after set true = %v, want true", norecord)
}
}
func TestStorage_noreplyat(t *testing.T) {
s := storage(ctxext.Storage(0))
// 测试默认值
if noreplyat := s.noreplyat(); noreplyat != false {
t.Errorf("default noreplyat() = %v, want false", noreplyat)
}
// 设置为 true 并测试
s = storage((ctxext.Storage)(s).Set(1, bitmapnrat))
if noreplyat := s.noreplyat(); noreplyat != true {
t.Errorf("noreplyat() after set true = %v, want true", noreplyat)
}
}
func TestStorage_Integration(t *testing.T) {
s := storage(ctxext.Storage(0))
// 设置各种值
s = storage((ctxext.Storage)(s).Set(int64(75), bitmaprate))
s = storage((ctxext.Storage)(s).Set(int64(85), bitmaptemp))
s = storage((ctxext.Storage)(s).Set(1, bitmapnagt))
s = storage((ctxext.Storage)(s).Set(0, bitmapnrec))
s = storage((ctxext.Storage)(s).Set(1, bitmapnrat))
// 验证所有方法
if rate := s.rate(); rate != 75 {
t.Errorf("rate() = %v, want 75", rate)
}
if temp := s.temp(); temp != 0.85 {
t.Errorf("temp() = %v, want 0.85", temp)
}
if noagent := s.noagent(); !noagent {
t.Errorf("noagent() = %v, want true", noagent)
}
if norecord := s.norecord(); norecord {
t.Errorf("norecord() = %v, want false", norecord)
}
if noreplyat := s.noreplyat(); !noreplyat {
t.Errorf("noreplyat() = %v, want true", noreplyat)
}
}
func BenchmarkStorage_rate(b *testing.B) {
s := storage(ctxext.Storage(0))
s = storage((ctxext.Storage)(s).Set(int64(100), bitmaprate))
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.rate()
}
}
func BenchmarkStorage_temp(b *testing.B) {
s := storage(ctxext.Storage(0))
s = storage((ctxext.Storage)(s).Set(int64(80), bitmaptemp))
b.ResetTimer()
for i := 0; i < b.N; i++ {
s.temp()
}
}

View File

@ -25,10 +25,10 @@ import (
"github.com/FloatTech/zbputils/ctxext" "github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/img/text" "github.com/FloatTech/zbputils/img/text"
"github.com/disintegration/imaging" "github.com/disintegration/imaging"
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v4/host"
"github.com/shirou/gopsutil/v3/mem" "github.com/shirou/gopsutil/v4/mem"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/text/cases" "golang.org/x/text/cases"
"golang.org/x/text/language" "golang.org/x/text/language"

56
plugin/aiimage/config.go Normal file
View File

@ -0,0 +1,56 @@
// Package aiimage 提供AI画图功能配置
package aiimage
import (
"fmt"
"strings"
"sync"
sql "github.com/FloatTech/sqlite"
)
// storage 管理画图配置存储
type storage struct {
sync.RWMutex
db sql.Sqlite
}
// imageConfig 存储AI画图配置信息
type imageConfig struct {
ID int64 `db:"id"` // 主键ID
APIKey string `db:"apiKey"` // API密钥
APIURL string `db:"apiUrl"` // API地址
ModelName string `db:"modelName"` // 画图模型名称
}
// getConfig 获取当前配置
func (sdb *storage) getConfig() imageConfig {
sdb.RLock()
defer sdb.RUnlock()
cfg := imageConfig{}
_ = sdb.db.Find("config", &cfg, "WHERE id = 1")
return cfg
}
// setConfig 设置AI画图配置
func (sdb *storage) setConfig(apiKey, apiURL, modelName string) error {
sdb.Lock()
defer sdb.Unlock()
return sdb.db.Insert("config", &imageConfig{
ID: 1,
APIKey: apiKey,
APIURL: apiURL,
ModelName: modelName,
})
}
// PrintConfig 返回格式化后的配置信息
func (sdb *storage) PrintConfig() string {
cfg := sdb.getConfig()
var builder strings.Builder
builder.WriteString("当前AI画图配置:\n")
builder.WriteString(fmt.Sprintf("• 密钥: %s\n", cfg.APIKey))
builder.WriteString(fmt.Sprintf("• 接口地址: %s\n", cfg.APIURL))
builder.WriteString(fmt.Sprintf("• 模型名: %s\n", cfg.ModelName))
return builder.String()
}

171
plugin/aiimage/main.go Normal file
View File

@ -0,0 +1,171 @@
// Package aiimage AI画图
package aiimage
import (
"bytes"
"encoding/json"
"net/http"
"strings"
"time"
fcext "github.com/FloatTech/floatbox/ctxext"
"github.com/FloatTech/floatbox/web"
sql "github.com/FloatTech/sqlite"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
)
func init() {
var sdb = &storage{}
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Extra: control.ExtraFromString("aiimage"),
Brief: "AI画图",
Help: "- 设置AI画图密钥xxx\n" +
"- 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations\n" +
"- 设置AI画图模型名Kwai-Kolors/Kolors\n" +
"- 查看AI画图配置\n" +
"- AI画图 [描述]",
PrivateDataFolder: "aiimage",
})
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
sdb.db = sql.New(en.DataFolder() + "aiimage.db")
err := sdb.db.Open(time.Hour)
if err == nil {
// 创建配置表
err = sdb.db.Create("config", &imageConfig{})
if err != nil {
ctx.SendChain(message.Text("[ERROR]:", err))
return false
}
return true
}
ctx.SendChain(message.Text("[ERROR]:", err))
return false
})
en.OnPrefix("设置AI画图密钥", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
apiKey := strings.TrimSpace(ctx.State["args"].(string))
cfg := sdb.getConfig()
err := sdb.setConfig(apiKey, cfg.APIURL, cfg.ModelName)
if err != nil {
ctx.SendChain(message.Text("ERROR: 设置API密钥失败: ", err))
return
}
ctx.SendChain(message.Text("成功设置API密钥"))
})
en.OnPrefix("设置AI画图接口地址", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
apiURL := strings.TrimSpace(ctx.State["args"].(string))
cfg := sdb.getConfig()
err := sdb.setConfig(cfg.APIKey, apiURL, cfg.ModelName)
if err != nil {
ctx.SendChain(message.Text("ERROR: 设置API地址失败: ", err))
return
}
ctx.SendChain(message.Text("成功设置API地址"))
})
en.OnPrefix("设置AI画图模型名", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
modelName := strings.TrimSpace(ctx.State["args"].(string))
cfg := sdb.getConfig()
err := sdb.setConfig(cfg.APIKey, cfg.APIURL, modelName)
if err != nil {
ctx.SendChain(message.Text("ERROR: 设置模型失败: ", err))
return
}
ctx.SendChain(message.Text("成功设置模型: ", modelName))
})
en.OnFullMatch("查看AI画图配置", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(sdb.PrintConfig()))
})
en.OnPrefix("AI画图", getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("少女思考中..."))
prompt := strings.TrimSpace(ctx.State["args"].(string))
if prompt == "" {
ctx.SendChain(message.Text("请输入图片描述"))
return
}
cfg := sdb.getConfig()
if cfg.APIKey == "" || cfg.APIURL == "" || cfg.ModelName == "" {
ctx.SendChain(message.Text("请先配置API密钥、地址和模型"))
return
}
// 准备请求数据
reqBytes, _ := json.Marshal(map[string]interface{}{
"model": cfg.ModelName,
"prompt": prompt,
"image_size": "1024x1024",
"batch_size": 4,
"num_inference_steps": 20,
"guidance_scale": 7.5,
})
// 发送API请求
data, err := web.RequestDataWithHeaders(
web.NewDefaultClient(),
cfg.APIURL,
"POST",
func(req *http.Request) error {
req.Header.Set("Authorization", "Bearer "+cfg.APIKey)
req.Header.Set("Content-Type", "application/json")
return nil
},
bytes.NewReader(reqBytes),
)
if err != nil {
ctx.SendChain(message.Text("API请求失败: ", err))
return
}
// 解析API响应
jsonData := gjson.ParseBytes(data)
images := jsonData.Get("images")
if !images.Exists() {
images = jsonData.Get("data")
if !images.Exists() {
ctx.SendChain(message.Text("未获取到图片URL"))
return
}
}
// 发送生成的图片和相关信息
inferenceTime := jsonData.Get("timings.inference").Float()
seed := jsonData.Get("seed").Int()
msg := make(message.Message, 0, 1)
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text("图片生成成功!\n",
"提示词: ", prompt, "\n",
"模型: ", cfg.ModelName, "\n",
"推理时间: ", inferenceTime, "秒\n",
"种子: ", seed)))
// 添加所有图片
images.ForEach(func(_, value gjson.Result) bool {
url := value.Get("url").String()
if url != "" {
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Image(url)))
}
return true
})
if len(msg) > 0 {
ctx.Send(msg)
}
})
}

134
plugin/airecord/record.go Normal file
View File

@ -0,0 +1,134 @@
// Package airecord 群应用AI声聊
package airecord
import (
"strconv"
"strings"
"time"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/AnimeAPI/airecord"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
)
func init() {
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Extra: control.ExtraFromString("airecord"),
Brief: "群应用AI声聊",
Help: "- 设置AI语音群号1048452984(tips机器人任意所在群聊即可)\n" +
"- 设置AI语音模型\n" +
"- 查看AI语音配置\n" +
"- 发送AI语音xxx",
PrivateDataFolder: "airecord",
})
en.OnPrefix("设置AI语音群号", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
u := strings.TrimSpace(ctx.State["args"].(string))
num, err := strconv.ParseInt(u, 10, 64)
if err != nil {
ctx.SendChain(message.Text("ERROR: parse gid err: ", err))
return
}
err = airecord.SetCustomGID(num)
if err != nil {
ctx.SendChain(message.Text("ERROR: set gid err: ", err))
return
}
ctx.SendChain(message.Text("设置AI语音群号为", num))
})
en.OnFullMatch("设置AI语音模型", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
recv, cancel := next.Repeat()
defer cancel()
jsonData := ctx.GetAICharacters(0, 1)
// 转换为字符串数组
var names []string
// 初始化两个映射表
nameToID := make(map[string]string)
nameToURL := make(map[string]string)
characters := jsonData.Get("#.characters")
// 遍历每个角色对象
characters.ForEach(func(_, group gjson.Result) bool {
group.ForEach(func(_, character gjson.Result) bool {
// 提取当前角色的三个字段
name := character.Get("character_name").String()
names = append(names, name)
// 存入映射表(重复名称会覆盖,保留最后出现的条目)
nameToID[name] = character.Get("character_id").String()
nameToURL[name] = character.Get("preview_url").String()
return true // 继续遍历
})
return true // 继续遍历
})
var builder strings.Builder
// 写入开头文本
builder.WriteString("请选择语音模型序号:\n")
// 遍历names数组拼接序号和名称
for i, v := range names {
// 将数字转换为字符串不依赖fmt
numStr := strconv.Itoa(i)
// 拼接格式:"序号. 名称\n"
builder.WriteString(numStr)
builder.WriteString(". ")
builder.WriteString(v)
builder.WriteString("\n")
}
// 获取最终字符串
ctx.SendChain(message.Text(builder.String()))
for {
select {
case <-time.After(time.Second * 120):
ctx.SendChain(message.Text("设置AI语音模型指令过期"))
return
case ct := <-recv:
msg := ct.Event.Message.ExtractPlainText()
num, err := strconv.Atoi(msg)
if err != nil {
ctx.SendChain(message.Text("请输入数字!"))
continue
}
if num < 0 || num >= len(names) {
ctx.SendChain(message.Text("序号非法!"))
continue
}
err = airecord.SetRecordModel(names[num], nameToID[names[num]])
if err != nil {
ctx.SendChain(message.Text("ERROR: set model err: ", err))
continue
}
ctx.SendChain(message.Text("已选择语音模型: ", names[num]))
ctx.SendChain(message.Record(nameToURL[names[num]]))
return
}
}
})
en.OnFullMatch("查看AI语音配置", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(airecord.PrintRecordConfig()))
})
en.OnPrefix("发送AI语音", zero.UserOrGrpAdmin).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
u := strings.TrimSpace(ctx.State["args"].(string))
recCfg := airecord.GetConfig()
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, u)
if record == "" {
id := ctx.SendGroupAIRecord(recCfg.ModelID, ctx.Event.GroupID, u)
if id == "" {
ctx.SendChain(message.Text("ERROR: get record err: empty record"))
return
}
}
ctx.SendChain(message.Record(record))
})
}

View File

@ -23,7 +23,7 @@ import (
) )
func init() { func init() {
engine := control.Register("animetrace", &ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "AnimeTrace 动画/Galgame识别插件", Brief: "AnimeTrace 动画/Galgame识别插件",
Help: "- Gal识图\n- 动漫识图\n- 动漫识图 2\n- 动漫识图 [模型名]\n- Gal识图 [模型名]", Help: "- Gal识图\n- 动漫识图\n- 动漫识图 2\n- 动漫识图 [模型名]\n- Gal识图 [模型名]",

View File

@ -17,7 +17,12 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
const bandur time.Duration = time.Minute * 10 const (
bandur time.Duration = time.Minute * 2
add = "添加违禁词"
del = "删除违禁词"
list = "查看违禁词"
)
var ( var (
managers *ctrl.Manager[*zero.Ctx] // managers lazy load managers *ctrl.Manager[*zero.Ctx] // managers lazy load
@ -41,7 +46,7 @@ func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "违禁词检测", Brief: "违禁词检测",
Help: "- /[添加|删除|查看]违禁词", Help: "- [添加|删除|查看]违禁词",
PrivateDataFolder: "anti_abuse", PrivateDataFolder: "anti_abuse",
}) })
@ -56,10 +61,14 @@ func init() {
return true return true
}) })
engine.OnMessage(onceRule, zero.OnlyGroup, func(ctx *zero.Ctx) bool { notAntiabuse := func(ctx *zero.Ctx) bool {
if !ctx.Event.IsToMe { if zero.PrefixRule(add)(ctx) || zero.PrefixRule(del)(ctx) || zero.PrefixRule(list)(ctx) {
return false
}
return true return true
} }
engine.OnMessage(onceRule, notAntiabuse, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
uid := ctx.Event.UserID uid := ctx.Event.UserID
gid := ctx.Event.GroupID gid := ctx.Event.GroupID
msg := strings.ReplaceAll(ctx.MessageString(), "\n", "") msg := strings.ReplaceAll(ctx.MessageString(), "\n", "")
@ -70,7 +79,8 @@ func init() {
if err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.DoBlock(uid); err == nil { if err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.DoBlock(uid); err == nil {
t := time.Now().Unix() t := time.Now().Unix()
cache.Set(uid, struct{}{}) cache.Set(uid, struct{}{})
ctx.SetThisGroupBan(uid, int64(bandur.Minutes())) ctx.SetThisGroupBan(uid, int64(bandur.Seconds()))
ctx.DeleteMessage(ctx.Event.MessageID)
ctx.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur)) ctx.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur))
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
@ -92,9 +102,9 @@ func init() {
return true return true
}) })
engine.OnCommand("添加违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle( engine.OnPrefix(add, zero.OnlyGroup, zero.AdminPermission, onceRule).SetBlock(true).Handle(
func(ctx *zero.Ctx) { func(ctx *zero.Ctx) {
args := ctx.State["args"].(string) args := strings.TrimSpace(ctx.State["args"].(string))
if err := db.insertWord(ctx.Event.GroupID, args); err != nil { if err := db.insertWord(ctx.Event.GroupID, args); err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
} else { } else {
@ -102,9 +112,9 @@ func init() {
} }
}) })
engine.OnCommand("删除违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle( engine.OnPrefix(del, zero.OnlyGroup, zero.AdminPermission, onceRule).SetBlock(true).Handle(
func(ctx *zero.Ctx) { func(ctx *zero.Ctx) {
args := ctx.State["args"].(string) args := strings.TrimSpace(ctx.State["args"].(string))
if err := db.deleteWord(ctx.Event.GroupID, args); err != nil { if err := db.deleteWord(ctx.Event.GroupID, args); err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
} else { } else {
@ -112,7 +122,7 @@ func init() {
} }
}) })
engine.OnCommand("查看违禁词", zero.OnlyGroup, onceRule).Handle( engine.OnPrefix(list, zero.OnlyGroup, onceRule).SetBlock(true).Handle(
func(ctx *zero.Ctx) { func(ctx *zero.Ctx) {
b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20) b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20)
if err != nil { if err != nil {

View File

@ -11,7 +11,6 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"regexp"
"sort" "sort"
"strconv" "strconv"
"time" "time"
@ -31,7 +30,6 @@ import (
) )
var ( var (
re = regexp.MustCompile(`^\d+$`)
danmakuTypeMap = map[int64]string{ danmakuTypeMap = map[int64]string{
0: "普通消息", 0: "普通消息",
1: "礼物", 1: "礼物",
@ -73,7 +71,7 @@ func init() {
} }
return true return true
}) })
engine.OnRegex(`^>user info\s?(.{1,25})$`, getPara).SetBlock(true). engine.OnRegex(`^>user info\s?(.{1,25})$`, bz.RequireUser(cfg)).SetBlock(true).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
id := ctx.State["uid"].(string) id := ctx.State["uid"].(string)
card, err := bz.GetMemberCard(id) card, err := bz.GetMemberCard(id)
@ -91,7 +89,7 @@ func init() {
)) ))
}) })
engine.OnRegex(`^>vup info\s?(.{1,25})$`, getPara).SetBlock(true). engine.OnRegex(`^>vup info\s?(.{1,25})$`, bz.RequireUser(cfg)).SetBlock(true).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
id := ctx.State["uid"].(string) id := ctx.State["uid"].(string)
// 获取详情 // 获取详情
@ -114,7 +112,7 @@ func init() {
)) ))
}) })
engine.OnRegex(`^查成分\s?(.{1,25})$`, getPara, getdb).SetBlock(true). engine.OnRegex(`^查成分\s?(.{1,25})$`, bz.RequireUser(cfg), getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
id := ctx.State["uid"].(string) id := ctx.State["uid"].(string)
today := time.Now().Format("20060102") today := time.Now().Format("20060102")
@ -134,7 +132,7 @@ func init() {
return return
} }
vupLen := len(vups) vupLen := len(vups)
medals, err := bz.GetMedalWall(cfg, id) medals, err := cfg.GetMedalWall(id)
sort.Sort(bz.MedalSorter(medals)) sort.Sort(bz.MedalSorter(medals))
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
@ -275,7 +273,7 @@ func init() {
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile)) ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
}) })
engine.OnRegex(`^查弹幕\s?(\S{1,25})\s?(\d*)$`, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { engine.OnRegex(`^查弹幕\s?(\S{1,25})\s?(\d*)$`, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
id := ctx.State["uid"].(string) id := ctx.State["uid"].(string)
pagenum := ctx.State["regex_matched"].([]string)[2] pagenum := ctx.State["regex_matched"].([]string)[2]
if pagenum == "" { if pagenum == "" {
@ -582,51 +580,3 @@ func int2rbg(t int64) (int64, int64, int64) {
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2]) b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
return r, g, b return r, g, b
} }
func getPara(ctx *zero.Ctx) bool {
keyword := ctx.State["regex_matched"].([]string)[1]
if !re.MatchString(keyword) {
searchRes, err := bz.SearchUser(cfg, keyword)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
return true
}
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
recv, cancel := next.Repeat()
defer cancel()
ctx.SendChain(message.Text("输入为纯数字, 请选择查询uid还是用户名, 输入对应序号:\n0. 查询uid\n1. 查询用户名"))
for {
select {
case <-time.After(time.Second * 10):
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询uid"))
ctx.State["uid"] = keyword
return true
case c := <-recv:
msg := c.Event.Message.ExtractPlainText()
num, err := strconv.Atoi(msg)
if err != nil {
ctx.SendChain(message.Text("请输入数字!"))
continue
}
if num < 0 || num > 1 {
ctx.SendChain(message.Text("序号非法!"))
continue
}
if num == 0 {
ctx.State["uid"] = keyword
return true
} else if num == 1 {
searchRes, err := bz.SearchUser(cfg, keyword)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
return true
}
}
}
}

View File

@ -1,342 +0,0 @@
package bilibili
import (
"encoding/json"
"fmt"
"time"
bz "github.com/FloatTech/AnimeAPI/bilibili"
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/web"
"github.com/wdvxdr1123/ZeroBot/message"
)
var (
msgType = map[int]string{
1: "转发了动态",
2: "有图营业",
4: "无图营业",
8: "投稿了视频",
16: "投稿了短视频",
64: "投稿了文章",
256: "投稿了音频",
2048: "发布了简报",
4200: "发布了直播",
4308: "发布了直播",
}
)
// dynamicCard2msg 处理DynCard
func dynamicCard2msg(dynamicCard *bz.DynamicCard) (msg []message.Segment, err error) {
var (
card bz.Card
vote bz.Vote
cType int
)
msg = make([]message.Segment, 0, 16)
// 初始化结构体
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
if err != nil {
return
}
if dynamicCard.Extension.Vote != "" {
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
if err != nil {
return
}
}
cType = dynamicCard.Desc.Type
// 生成消息
switch cType {
case 1:
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
card.Item.Content, "\n",
"转发的内容: \n"))
var originMsg []message.Segment
var co bz.Card
co, err = bz.LoadCardDetail(card.Origin)
if err != nil {
return
}
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
if err != nil {
return
}
msg = append(msg, originMsg...)
case 2:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Description))
for i := 0; i < len(card.Item.Pictures); i++ {
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
}
case 4:
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Content, "\n"))
if dynamicCard.Extension.Vote != "" {
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
for i := 0; i < len(vote.Options); i++ {
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
if vote.Options[i].ImgURL != "" {
msg = append(msg, message.Image(vote.Options[i].ImgURL))
}
}
}
case 8:
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Pic))
msg = append(msg, message.Text(card.Desc, "\n",
card.ShareSubtitle, "\n",
"视频链接: ", card.ShortLink, "\n"))
case 16:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Description))
msg = append(msg, message.Image(card.Item.Cover.Default))
case 64:
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title, "\n",
card.Summary))
for i := 0; i < len(card.ImageUrls); i++ {
msg = append(msg, message.Image(card.ImageUrls[i]))
}
if card.ID != 0 {
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
}
case 256:
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Cover))
msg = append(msg, message.Text(card.Intro, "\n"))
if card.ID != 0 {
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
}
case 2048:
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
card.Vest.Content, "\n",
card.Sketch.Title, "\n",
card.Sketch.DescText, "\n"))
msg = append(msg, message.Image(card.Sketch.CoverURL))
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
case 4308:
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
}
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
"房间号: ", card.LivePlayInfo.RoomID, "\n",
"分区: ", card.LivePlayInfo.ParentAreaName))
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
}
if card.LivePlayInfo.LiveStatus == 0 {
msg = append(msg, message.Text("未开播 \n"))
} else {
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
}
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
default:
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
}
if dynamicCard.Desc.DynamicIDStr != "" {
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
}
return
}
// card2msg cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
func card2msg(dynamicCard *bz.DynamicCard, card *bz.Card, cType int) (msg []message.Segment, err error) {
var (
vote bz.Vote
)
msg = make([]message.Segment, 0, 16)
// 生成消息
switch cType {
case 1:
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
card.Item.Content, "\n",
"转发的内容: \n"))
var originMsg []message.Segment
var co bz.Card
co, err = bz.LoadCardDetail(card.Origin)
if err != nil {
return
}
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
if err != nil {
return
}
msg = append(msg, originMsg...)
case 2:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Description))
for i := 0; i < len(card.Item.Pictures); i++ {
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
}
case 4:
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Content, "\n"))
if dynamicCard.Extension.Vote != "" {
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
for i := 0; i < len(vote.Options); i++ {
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
if vote.Options[i].ImgURL != "" {
msg = append(msg, message.Image(vote.Options[i].ImgURL))
}
}
}
case 8:
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Pic))
msg = append(msg, message.Text(card.Desc, "\n",
card.ShareSubtitle, "\n",
"视频链接: ", card.ShortLink, "\n"))
case 16:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Item.Description))
msg = append(msg, message.Image(card.Item.Cover.Default))
case 64:
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title, "\n",
card.Summary))
for i := 0; i < len(card.ImageUrls); i++ {
msg = append(msg, message.Image(card.ImageUrls[i]))
}
if card.ID != 0 {
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
}
case 256:
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Cover))
msg = append(msg, message.Text(card.Intro, "\n"))
if card.ID != 0 {
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
}
case 2048:
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
card.Vest.Content, "\n",
card.Sketch.Title, "\n",
card.Sketch.DescText, "\n"))
msg = append(msg, message.Image(card.Sketch.CoverURL))
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
case 4308:
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
}
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
"房间号: ", card.LivePlayInfo.RoomID, "\n",
"分区: ", card.LivePlayInfo.ParentAreaName))
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
}
if card.LivePlayInfo.LiveStatus == 0 {
msg = append(msg, message.Text("未开播 \n"))
} else {
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
}
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
default:
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
}
if dynamicCard.Desc.DynamicIDStr != "" {
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
}
return
}
// dynamicDetail 用动态id查动态信息
func dynamicDetail(cookiecfg *bz.CookieConfig, dynamicIDStr string) (msg []message.Segment, err error) {
dyc, err := bz.GetDynamicDetail(cookiecfg, dynamicIDStr)
if err != nil {
return
}
return dynamicCard2msg(&dyc)
}
// articleCard2msg 专栏转消息
func articleCard2msg(card bz.Card, defaultID string) (msg []message.Segment) {
msg = make([]message.Segment, 0, 16)
for i := 0; i < len(card.OriginImageUrls); i++ {
msg = append(msg, message.Image(card.OriginImageUrls[i]))
}
msg = append(msg, message.Text("\n", card.Title, "\n", "UP主: ", card.AuthorName, "\n",
"阅读: ", bz.HumanNum(card.Stats.View), " 评论: ", bz.HumanNum(card.Stats.Reply), "\n",
bz.CVURL, defaultID))
return
}
// liveCard2msg 直播卡片转消息
func liveCard2msg(card bz.RoomCard) (msg []message.Segment) {
msg = make([]message.Segment, 0, 16)
msg = append(msg, message.Image(card.RoomInfo.Keyframe))
msg = append(msg, message.Text("\n", card.RoomInfo.Title, "\n",
"主播: ", card.AnchorInfo.BaseInfo.Uname, "\n",
"房间号: ", card.RoomInfo.RoomID, "\n"))
if card.RoomInfo.ShortID != 0 {
msg = append(msg, message.Text("短号: ", card.RoomInfo.ShortID, "\n"))
}
msg = append(msg, message.Text("分区: ", card.RoomInfo.ParentAreaName))
if card.RoomInfo.ParentAreaName != card.RoomInfo.AreaName {
msg = append(msg, message.Text("-", card.RoomInfo.AreaName))
}
if card.RoomInfo.LiveStatus == 0 {
msg = append(msg, message.Text("未开播 \n"))
} else {
msg = append(msg, message.Text("直播中 ", bz.HumanNum(card.RoomInfo.Online), "人气\n"))
}
if card.RoomInfo.ShortID != 0 {
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.ShortID))
} else {
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.RoomID))
}
return
}
// videoCard2msg 视频卡片转消息
func videoCard2msg(card bz.Card) (msg []message.Segment, err error) {
var (
mCard bz.MemberCard
onlineTotal bz.OnlineTotal
)
msg = make([]message.Segment, 0, 16)
mCard, err = bz.GetMemberCard(card.Owner.Mid)
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
if card.Rights.IsCooperation == 1 {
for i := 0; i < len(card.Staff); i++ {
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", bz.HumanNum(card.Staff[i].Follower), "\n"))
}
} else {
if err != nil {
msg = append(msg, message.Text("UP主: ", card.Owner.Name, "\n"))
} else {
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", bz.HumanNum(mCard.Fans), "\n"))
}
}
msg = append(msg, message.Image(card.Pic))
data, err := web.GetData(fmt.Sprintf(bz.OnlineTotalURL, card.BvID, card.CID))
if err != nil {
return
}
err = json.Unmarshal(data, &onlineTotal)
if err != nil {
return
}
msg = append(msg, message.Text("👀播放: ", bz.HumanNum(card.Stat.View), " 💬弹幕: ", bz.HumanNum(card.Stat.Danmaku),
"\n👍点赞: ", bz.HumanNum(card.Stat.Like), " 💰投币: ", bz.HumanNum(card.Stat.Coin),
"\n📁收藏: ", bz.HumanNum(card.Stat.Favorite), " 🔗分享: ", bz.HumanNum(card.Stat.Share),
"\n📝简介: ", card.Desc,
"\n🏄 总共 ", onlineTotal.Data.Total, " 人在观看,", onlineTotal.Data.Count, " 人在网页端观看\n",
bz.VURL, card.BvID, "\n\n"))
return
}

View File

@ -1,55 +0,0 @@
package bilibili
import (
"testing"
bz "github.com/FloatTech/AnimeAPI/bilibili"
)
func TestArticleInfo(t *testing.T) {
card, err := bz.GetArticleInfo("17279244")
if err != nil {
t.Fatal(err)
}
t.Log(articleCard2msg(card, "17279244"))
}
func TestMemberCard(t *testing.T) {
card, err := bz.GetMemberCard(2)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v\n", card)
}
func TestVideoInfo(t *testing.T) {
card, err := bz.GetVideoInfo("10007")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = bz.GetVideoInfo("BV1xx411c7mD")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = bz.GetVideoInfo("bv1xx411c7mD")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = bz.GetVideoInfo("BV1mF411j7iU")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
}
func TestLiveRoomInfo(t *testing.T) {
card, err := bz.GetLiveRoomInfo("83171")
if err != nil {
t.Fatal(err)
}
t.Log(liveCard2msg(card))
}

View File

@ -1,5 +1,5 @@
// Package bilibili bilibili卡片解析 // Package bilibiliparse bilibili卡片解析
package bilibili package bilibiliparse
import ( import (
"bytes" "bytes"
@ -24,9 +24,12 @@ import (
) )
const ( const (
enableHex = 0x10 enableVideoSummary = int64(0x10)
unableHex = 0x7fffffff_fffffffd disableVideoSummary = ^enableVideoSummary
enableVideoDownload = int64(0x20)
disableVideoDownload = ^enableVideoDownload
bilibiliparseReferer = "https://www.bilibili.com" bilibiliparseReferer = "https://www.bilibili.com"
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
) )
var ( var (
@ -40,11 +43,12 @@ var (
searchArticleRe = regexp.MustCompile(searchArticle) searchArticleRe = regexp.MustCompile(searchArticle)
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom) searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
cachePath string cachePath string
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
) )
// 插件主体 // 插件主体
func init() { func init() {
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{ en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "b站链接解析", Brief: "b站链接解析",
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ", Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
@ -92,9 +96,9 @@ func init() {
data := c.GetData(ctx.Event.GroupID) data := c.GetData(ctx.Event.GroupID)
switch option { switch option {
case "开启", "打开", "启用": case "开启", "打开", "启用":
data |= enableHex data |= enableVideoSummary
case "关闭", "关掉", "禁用": case "关闭", "关掉", "禁用":
data &= unableHex data &= disableVideoSummary
default: default:
return return
} }
@ -105,6 +109,35 @@ func init() {
} }
ctx.SendChain(message.Text("已", option, "视频总结")) ctx.SendChain(message.Text("已", option, "视频总结"))
}) })
en.OnRegex(`^(开启|打开|启用|关闭|关掉|禁用)视频上传$`, zero.AdminPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
if gid <= 0 {
// 个人用户设为负数
gid = -ctx.Event.UserID
}
option := ctx.State["regex_matched"].([]string)[1]
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
ctx.SendChain(message.Text("找不到服务!"))
return
}
data := c.GetData(ctx.Event.GroupID)
switch option {
case "开启", "打开", "启用":
data |= enableVideoDownload
case "关闭", "关掉", "禁用":
data &= disableVideoDownload
default:
return
}
err := c.SetData(gid, data)
if err != nil {
ctx.SendChain(message.Text("出错啦: ", err))
return
}
ctx.SendChain(message.Text("已", option, "视频上传"))
})
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo) en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic) en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle) en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
@ -121,13 +154,13 @@ func handleVideo(ctx *zero.Ctx) {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
msg, err := videoCard2msg(card) msg, err := card.ToVideoMessage()
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if ok && c.GetData(ctx.Event.GroupID)&enableHex == enableHex { if ok && c.GetData(ctx.Event.GroupID)&enableVideoSummary == enableVideoSummary {
summaryMsg, err := getVideoSummary(cfg, card) summaryMsg, err := getVideoSummary(cfg, card)
if err != nil { if err != nil {
msg = append(msg, message.Text("ERROR: ", err)) msg = append(msg, message.Text("ERROR: ", err))
@ -136,6 +169,7 @@ func handleVideo(ctx *zero.Ctx) {
} }
} }
ctx.SendChain(msg...) ctx.SendChain(msg...)
if ok && c.GetData(ctx.Event.GroupID)&enableVideoDownload == enableVideoDownload {
downLoadMsg, err := getVideoDownload(cfg, card, cachePath) downLoadMsg, err := getVideoDownload(cfg, card, cachePath)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
@ -143,9 +177,10 @@ func handleVideo(ctx *zero.Ctx) {
} }
ctx.SendChain(downLoadMsg...) ctx.SendChain(downLoadMsg...)
} }
}
func handleDynamic(ctx *zero.Ctx) { func handleDynamic(ctx *zero.Ctx) {
msg, err := dynamicDetail(cfg, ctx.State["regex_matched"].([]string)[2]) msg, err := cfg.GetDetailMessage(ctx.State["regex_matched"].([]string)[2])
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
@ -159,16 +194,21 @@ func handleArticle(ctx *zero.Ctx) {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
ctx.SendChain(articleCard2msg(card, ctx.State["regex_matched"].([]string)[1])...) ctx.SendChain(card.ToArticleMessage(ctx.State["regex_matched"].([]string)[1])...)
} }
func handleLive(ctx *zero.Ctx) { func handleLive(ctx *zero.Ctx) {
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1]) cookie, err := cfg.Load()
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
ctx.SendChain(liveCard2msg(card)...) card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1], cookie)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(card.ToMessage()...)
} }
// getVideoSummary AI视频总结 // getVideoSummary AI视频总结

View File

@ -1,5 +1,5 @@
// Package bilibili b站推送 // Package bilibilipush b站推送
package bilibili package bilibilipush
import ( import (
"bytes" "bytes"
@ -34,10 +34,11 @@ var (
lastTime = map[int64]int64{} lastTime = map[int64]int64{}
liveStatus = map[int64]int{} liveStatus = map[int64]int{}
upMap = map[int64]string{} upMap = map[int64]string{}
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
) )
func init() { func init() {
en := control.Register("bilibilipush", &ctrl.Options[*zero.Ctx]{ en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "b站推送", Brief: "b站推送",
Help: "- 添加b站订阅[uid|name]\n" + Help: "- 添加b站订阅[uid|name]\n" +
@ -75,7 +76,7 @@ func init() {
ctx.SendChain(message.Text("已关闭艾特全体Oo")) ctx.SendChain(message.Text("已关闭艾特全体Oo"))
}) })
en.OnRegex(`^添加[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnRegex(`^添加[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64) buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
name, err := getName(buid, cfg) name, err := getName(buid, cfg)
if err != nil || name == "" { if err != nil || name == "" {
@ -93,7 +94,7 @@ func init() {
ctx.SendChain(message.Text("已添加" + name + "的订阅")) ctx.SendChain(message.Text("已添加" + name + "的订阅"))
}) })
en.OnRegex(`^取消[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnRegex(`^取消[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64) buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
name, err := getName(buid, cfg) name, err := getName(buid, cfg)
if err != nil { if err != nil {
@ -110,7 +111,7 @@ func init() {
} }
ctx.SendChain(message.Text("已取消" + name + "的订阅")) ctx.SendChain(message.Text("已取消" + name + "的订阅"))
}) })
en.OnRegex(`^取消[B|b]站动态订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnRegex(`^取消[B|b]站动态订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64) buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
name, err := getName(buid, cfg) name, err := getName(buid, cfg)
if err != nil { if err != nil {
@ -127,7 +128,7 @@ func init() {
} }
ctx.SendChain(message.Text("已取消" + name + "的动态订阅")) ctx.SendChain(message.Text("已取消" + name + "的动态订阅"))
}) })
en.OnRegex(`^取消[B|b]站直播订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnRegex(`^取消[B|b]站直播订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64) buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
gid := ctx.Event.GroupID gid := ctx.Event.GroupID
if gid == 0 { if gid == 0 {
@ -333,7 +334,7 @@ func sendDynamic(ctx *zero.Ctx) error {
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err) err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
return err return err
} }
msg, err := dynamicCard2msg(&dc) msg, err := dc.ToMessage()
if err != nil { if err != nil {
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err) err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
return err return err

View File

@ -1,4 +1,4 @@
package bilibili package bilibilipush
import ( import (
"encoding/json" "encoding/json"

View File

@ -43,8 +43,15 @@ func init() {
}) })
engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
param := ctx.State["args"].(string)
var uid int64
if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" {
uid, _ = strconv.ParseInt(ctx.Event.Message[1].Data["qq"], 10, 64)
} else if param == "" {
uid = ctx.Event.UserID
}
name := ctx.NickName() name := ctx.NickName()
todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, ctx.Event.UserID) todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, uid)
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒发了%d条消息总计水了%d分%d秒发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage))) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒发了%d条消息总计水了%d分%d秒发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage)))
}) })
engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true). engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).

View File

@ -13,7 +13,6 @@ import (
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext" "github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
@ -35,16 +34,7 @@ var (
Brief: "国际象棋", Brief: "国际象棋",
Help: helpString, Help: helpString,
PrivateDataFolder: "chess", PrivateDataFolder: "chess",
}).ApplySingle(single.New( }).ApplySingle(ctxext.GroupSingle)
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("有操作正在执行, 请稍后再试..."),
),
)
}),
))
) )
func init() { func init() {

95
plugin/crypter/fumo.go Normal file
View File

@ -0,0 +1,95 @@
// Package crypter Fumo语
package crypter
import (
"encoding/base64"
"fmt"
"regexp"
"strings"
)
// Base64字符表
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
// Fumo语字符表 - 使用各种fumo变体来表示base64字符
var fumoChars = []string{
"fumo-", "Fumo-", "fUmo-", "fuMo-", "fumO-", "FUmo-", "FuMo-", "FumO-",
"fUMo-", "fUmO-", "fuMO-", "FUMo-", "FUmO-", "fUMO-", "FUMO-", "fumo.",
"Fumo.", "fUmo.", "fuMo.", "fumO.", "FUmo.", "FuMo.", "FumO.", "fUMo.",
"fUmO.", "fuMO.", "FUMo.", "FUmO.", "fUMO.", "FUMO.", "fumo,", "Fumo,",
"fUmo,", "fuMo,", "fumO,", "FUmo,", "FuMo,", "FumO,", "fUMo,", "fUmO,",
"fuMO,", "FUMo,", "FuMO,", "fUMO,", "FUMO,", "fumo+", "Fumo+", "fUmo+",
"fuMo+", "fumO+", "FUmo+", "FuMo+", "FumO+", "fUMo+", "fUmO+", "fuMO+",
"FUMo+", "FUmO+", "fUMO+", "FUMO+", "fumo|", "Fumo|", "fUmo|", "fuMo|",
"fumO|", "FUmo|", "FuMo|", "FumO|", "fUMo|", "fUmO|", "fuMO|", "fumo/",
"Fumo/", "fUmo/",
}
// Base64 2 Fumo
// 创建编码映射表
var encodeMap = make(map[byte]string)
// 创建解码映射表
var decodeMap = make(map[string]byte)
func init() {
for i := 0; i < 64 && i < len(fumoChars); i++ {
base64Char := base64Chars[i]
fumoChar := fumoChars[i]
encodeMap[base64Char] = fumoChar
decodeMap[fumoChar] = base64Char
}
}
// 加密
func encryptFumo(text string) string {
if text == "" {
return "请输入要加密的文本"
}
textBytes := []byte(text)
base64String := base64.StdEncoding.EncodeToString(textBytes)
base64Body := strings.TrimRight(base64String, "=")
paddingCount := len(base64String) - len(base64Body)
var fumoBody strings.Builder
for _, char := range base64Body {
if fumoChar, exists := encodeMap[byte(char)]; exists {
fumoBody.WriteString(fumoChar)
} else {
return fmt.Sprintf("Fumo加密失败: 未知字符 %c", char)
}
}
result := fumoBody.String() + strings.Repeat("=", paddingCount)
return result
}
// 解密
func decryptFumo(fumoText string) string {
if fumoText == "" {
return "请输入要解密的Fumo语密文"
}
fumoBody := strings.TrimRight(fumoText, "=")
paddingCount := len(fumoText) - len(fumoBody)
fumoPattern := regexp.MustCompile(`(\w+[-.,+|/])`)
fumoWords := fumoPattern.FindAllString(fumoBody, -1)
reconstructed := strings.Join(fumoWords, "")
if reconstructed != fumoBody {
return "Fumo解密失败: 包含无效的Fumo字符或格式错误"
}
var base64Body strings.Builder
for _, fumoWord := range fumoWords {
if base64Char, exists := decodeMap[fumoWord]; exists {
base64Body.WriteByte(base64Char)
} else {
return fmt.Sprintf("Fumo解密失败: 包含无效的Fumo字符 %s", fumoWord)
}
}
base64String := base64Body.String() + strings.Repeat("=", paddingCount)
decodedBytes, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
return fmt.Sprintf("Fumo解密失败: Base64解码错误 %v", err)
}
originalText := string(decodedBytes)
return originalText
}

View File

@ -0,0 +1,42 @@
// Package crypter 处理函数
package crypter
import (
"github.com/FloatTech/AnimeAPI/airecord"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
// hou
func houEncryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := encodeHou(text)
logrus.Infoln("[crypter] 回复内容:", result)
recCfg := airecord.GetConfig()
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result)
if record != "" {
ctx.SendChain(message.Record(record))
} else {
ctx.SendChain(message.Text(result))
}
}
func houDecryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := decodeHou(text)
ctx.SendChain(message.Text(result))
}
// fumo
func fumoEncryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := encryptFumo(text)
ctx.SendChain(message.Text(result))
}
func fumoDecryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := decryptFumo(text)
ctx.SendChain(message.Text(result))
}

88
plugin/crypter/hou.go Normal file
View File

@ -0,0 +1,88 @@
// Package crypter 齁语加解密
package crypter
import (
"strings"
)
// 齁语密码表
var houCodebook = []string{
"齁", "哦", "噢", "喔", "咕", "咿", "嗯", "啊",
"", "哈", "", "唔", "哼", "❤", "呃", "呼",
}
// 索引: 0 1 2 3 4 5 6 7
// 8 9 10 11 12 13 14 15
// 创建映射表
var houCodebookMap = make(map[string]int)
// 初始化映射表
func init() {
for idx, ch := range houCodebook {
houCodebookMap[ch] = idx
}
}
func encodeHou(text string) string {
if text == "" {
return "请输入要加密的文本"
}
var encoded strings.Builder
textBytes := []byte(text)
for _, b := range textBytes {
high := (b >> 4) & 0x0F
low := b & 0x0F
encoded.WriteString(houCodebook[high])
encoded.WriteString(houCodebook[low])
}
return encoded.String()
}
func decodeHou(code string) string {
if code == "" {
return "请输入要解密的齁语密文"
}
// 过滤出有效的齁语字符
var validChars []string
for _, r := range code {
charStr := string(r)
if _, exists := houCodebookMap[charStr]; exists {
validChars = append(validChars, charStr)
}
}
if len(validChars)%2 != 0 {
return "齁语密文长度错误,无法解密"
}
// 解密过程
var byteList []byte
for i := 0; i < len(validChars); i += 2 {
highIdx, highExists := houCodebookMap[validChars[i]]
lowIdx, lowExists := houCodebookMap[validChars[i+1]]
if !highExists || !lowExists {
return "齁语密文包含无效字符"
}
originalByte := byte((highIdx << 4) | lowIdx)
byteList = append(byteList, originalByte)
}
result := string(byteList)
if !isValidUTF8(result) {
return "齁语解密失败,结果不是有效的文本"
}
return result
}
// 检查字符串是否为有效的UTF-8编码
func isValidUTF8(s string) bool {
// Go的string类型默认就是UTF-8如果转换没有出错说明是有效的
return len(s) > 0 || s == ""
}

31
plugin/crypter/main.go Normal file
View File

@ -0,0 +1,31 @@
// Package crypter 奇怪语言加解密
package crypter
import (
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
zero "github.com/wdvxdr1123/ZeroBot"
)
func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "奇怪语言加解密",
Help: "多种语言加解密插件\n" +
"- 齁语加解密:\n" +
"- 齁语加密 [文本] 或 h加密 [文本]\n" +
"- 齁语解密 [密文] 或 h解密 [密文]\n\n" +
"- Fumo语加解密:\n" +
"- fumo加密 [文本]\n" +
"- fumo解密 [密文]\n\n",
PublicDataFolder: "Crypter",
})
// hou
engine.OnRegex(`^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
engine.OnRegex(`^(?:齁语解密|h解密)\s*(.+)$`).SetBlock(true).Handle(houDecryptHandler)
// Fumo
engine.OnRegex(`^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
engine.OnRegex(`^fumo解密\s*(.+)$`).SetBlock(true).Handle(fumoDecryptHandler)
}

View File

@ -2,16 +2,14 @@
package dailynews package dailynews
import ( import (
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/web" "github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
const api = "http://dwz.2xb.cn/zaob" const api = "https://uapis.cn/api/v1/daily/news-image"
func init() { func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
@ -28,7 +26,6 @@ func init() {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String() ctx.SendChain(message.ImageBytes(data))
ctx.SendChain(message.Image(picURL))
}) })
} }

View File

@ -20,7 +20,7 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
defer wg.Done() defer wg.Done()
target := datapath + `materials/` + name target := datapath + `materials/` + name
if file.IsNotExist(target) { if file.IsNotExist(target) {
data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/main/` + name) data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/master/` + name)
if err != nil { if err != nil {
_ = os.Remove(target) _ = os.Remove(target)
exit(err) exit(err)
@ -48,7 +48,7 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
func dlblock(name string) (string, error) { func dlblock(name string) (string, error) {
target := datapath + `materials/` + name target := datapath + `materials/` + name
if file.IsNotExist(target) { if file.IsNotExist(target) {
data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/main/` + name) data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/master/` + name)
if err != nil { if err != nil {
_ = os.Remove(target) _ = os.Remove(target)
return "", err return "", err

View File

@ -15,7 +15,6 @@ import (
"github.com/FloatTech/zbputils/ctxext" "github.com/FloatTech/zbputils/ctxext"
"github.com/pkg/errors" "github.com/pkg/errors"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
// 图片输出 // 图片输出
@ -65,17 +64,7 @@ var (
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" + "- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
"- 解除绑定 [歌单名称]", "- 解除绑定 [歌单名称]",
PrivateDataFolder: "guessmusic", PrivateDataFolder: "guessmusic",
}).ApplySingle(single.New( }).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Break()
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("已经有正在进行的游戏..."),
),
)
}),
))
// 用于存放歌曲三个片段的缓存文件夹 // 用于存放歌曲三个片段的缓存文件夹
cachePath = engine.DataFolder() + "cache/" cachePath = engine.DataFolder() + "cache/"
// 用于存放用户的配置 // 用于存放用户的配置

View File

@ -2,8 +2,6 @@
package kfccrazythursday package kfccrazythursday
import ( import (
"encoding/json"
"github.com/FloatTech/floatbox/web" "github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
@ -15,12 +13,6 @@ const (
crazyURL = "https://api.pearktrue.cn/api/kfc/" crazyURL = "https://api.pearktrue.cn/api/kfc/"
) )
type crazyResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Text string `json:"text"`
}
func init() { func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
@ -34,17 +26,7 @@ func init() {
return return
} }
var resp crazyResponse // 根据来源API修改返回方式到直接输出文本
if err := json.Unmarshal(data, &resp); err != nil { ctx.SendChain(message.Text(string(data)))
ctx.SendChain(message.Text("JSON解析失败: ", err))
return
}
if resp.Code != 200 {
ctx.SendChain(message.Text("API返回错误: ", resp.Msg))
return
}
ctx.SendChain(message.Text(resp.Text))
}) })
} }

View File

@ -50,6 +50,7 @@ const (
"- 列出所有提醒\n" + "- 列出所有提醒\n" +
"- 翻牌\n" + "- 翻牌\n" +
"- 赞我\n" + "- 赞我\n" +
"- 群签到\n" +
"- 对信息回复: 回应表情 [表情]\n" + "- 对信息回复: 回应表情 [表情]\n" +
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" + "- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" +
"- 测试欢迎语\n" + "- 测试欢迎语\n" +
@ -405,6 +406,12 @@ func init() { // 插件主体
ctx.SendLike(ctx.Event.UserID, 10) ctx.SendLike(ctx.Event.UserID, 10)
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("给你赞了10下哦记得回我~")) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("给你赞了10下哦记得回我~"))
}) })
// 群签到
engine.OnFullMatch("群签到", zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) {
ctx.SetGroupSign(ctx.Event.GroupID)
ctx.SendChain(message.Text("群签到成功,可在手机端输入框中的打卡查看"))
})
facere := regexp.MustCompile(`\[CQ:face,id=(\d+)\]`) facere := regexp.MustCompile(`\[CQ:face,id=(\d+)\]`)
// 给消息回应表情 // 给消息回应表情
engine.OnRegex(`^\[CQ:reply,id=(-?\d+)\].*回应表情\s*(.+)\s*$`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true). engine.OnRegex(`^\[CQ:reply,id=(-?\d+)\].*回应表情\s*(.+)\s*$`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).

View File

@ -21,6 +21,10 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
var (
longZhuURL = "https://www.hhlqilongzhu.cn/api/joox/juhe_music.php?msg=%v"
)
func init() { func init() {
control.AutoRegister(&ctrl.Options[*zero.Ctx]{ control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
@ -29,7 +33,8 @@ func init() {
"- 网易点歌[xxx]\n" + "- 网易点歌[xxx]\n" +
"- 酷我点歌[xxx]\n" + "- 酷我点歌[xxx]\n" +
"- 酷狗点歌[xxx]\n" + "- 酷狗点歌[xxx]\n" +
"- 咪咕点歌[xxx]", "- 咪咕点歌[xxx]\n" +
"- qq点歌[xxx]\n",
}).OnRegex(`^(.{0,2})点歌\s?(.{1,25})$`).SetBlock(true).Limit(ctxext.LimitByUser). }).OnRegex(`^(.{0,2})点歌\s?(.{1,25})$`).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
// switch 平台 // switch 平台
@ -42,12 +47,37 @@ func init() {
ctx.SendChain(kugou(ctx.State["regex_matched"].([]string)[2])) ctx.SendChain(kugou(ctx.State["regex_matched"].([]string)[2]))
case "网易": case "网易":
ctx.SendChain(cloud163(ctx.State["regex_matched"].([]string)[2])) ctx.SendChain(cloud163(ctx.State["regex_matched"].([]string)[2]))
default: // 默认 QQ音乐 case "qq":
ctx.SendChain(qqmusic(ctx.State["regex_matched"].([]string)[2])) ctx.SendChain(qqmusic(ctx.State["regex_matched"].([]string)[2]))
default: // 默认聚合点歌
ctx.SendChain(longzhu(ctx.State["regex_matched"].([]string)[2]))
} }
}) })
} }
// longzhu 聚合平台
func longzhu(keyword string) message.Segment {
data, _ := web.GetData(fmt.Sprintf(longZhuURL, url.QueryEscape(keyword)))
// 假设 data 是包含整个 JSON 数组的字节切片
results := gjson.ParseBytes(data).Array()
for _, result := range results {
if strings.Contains(strings.ToLower(result.Get("title").String()), strings.ToLower(keyword)) {
if musicURL := result.Get("full_track").String(); musicURL != "" {
return message.Record(musicURL)
}
}
}
results = gjson.GetBytes(data, "#.full_track").Array()
if len(results) > 0 {
if musicURL := results[0].String(); musicURL != "" {
return message.Record(musicURL)
}
}
return message.Text("点歌失败, 找不到 ", keyword, " 的相关结果")
}
// migu 返回咪咕音乐卡片 // migu 返回咪咕音乐卡片
func migu(keyword string) message.Segment { func migu(keyword string) message.Segment {
headers := http.Header{ headers := http.Header{

View File

@ -2,9 +2,11 @@
package niuniu package niuniu
import ( import (
"errors"
"fmt" "fmt"
"math/rand" "math/rand"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/FloatTech/AnimeAPI/niu" "github.com/FloatTech/AnimeAPI/niu"
@ -18,12 +20,6 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
type lastLength struct {
TimeLimit time.Time
Count int
Length float64
}
var ( var (
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{ en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
@ -47,8 +43,8 @@ var (
}) })
dajiaoLimiter = rate.NewManager[string](time.Second*90, 1) dajiaoLimiter = rate.NewManager[string](time.Second*90, 1)
jjLimiter = rate.NewManager[string](time.Second*150, 1) jjLimiter = rate.NewManager[string](time.Second*150, 1)
jjCount = syncx.Map[string, *lastLength]{} jjCount = syncx.Map[string, *niu.PKRecord]{}
register = syncx.Map[string, *lastLength]{} register = syncx.Map[string, *niu.PKRecord]{}
) )
func init() { func init() {
@ -65,7 +61,7 @@ func init() {
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛拍卖行有以下牛牛"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛拍卖行有以下牛牛")))
for _, info := range auction { for _, info := range auction {
msg := fmt.Sprintf("商品序号: %d\n牛牛原所属: %d\n牛牛价格: %d%s\n牛牛大小: %.2fcm", msg := fmt.Sprintf("商品序号: %d\n牛牛原所属: %d\n牛牛价格: %d%s\n牛牛大小: %.2fcm",
info.ID+1, info.UserID, info.Money, wallet.GetWalletName(), info.Length) info.ID, info.UserID, info.Money, wallet.GetWalletName(), info.Length)
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(msg))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(msg)))
} }
if id := ctx.Send(messages).ID(); id == 0 { if id := ctx.Send(messages).ID(); id == 0 {
@ -81,7 +77,7 @@ func init() {
for { for {
select { select {
case <-timer.C: case <-timer.C:
ctx.SendChain(message.At(uid), message.Text(" 超时,已自动取消")) ctx.SendChain(message.At(uid), message.Text(" 超时已自动取消"))
return return
case r := <-recv: case r := <-recv:
answer = r.Event.Message.String() answer = r.Event.Message.String()
@ -90,7 +86,6 @@ func init() {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
n--
msg, err := niu.Auction(gid, uid, n) msg, err := niu.Auction(gid, uid, n)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR:", err)) ctx.SendChain(message.Text("ERROR:", err))
@ -104,11 +99,21 @@ func init() {
en.OnFullMatch("出售牛牛", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnFullMatch("出售牛牛", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID gid := ctx.Event.GroupID
uid := ctx.Event.UserID uid := ctx.Event.UserID
key := fmt.Sprintf("%d_%d", gid, uid)
sell, err := niu.Sell(gid, uid) sell, err := niu.Sell(gid, uid)
if err != nil { if errors.Is(err, niu.ErrCanceled) || errors.Is(err, niu.ErrNoNiuNiu) {
ctx.SendChain(message.Text(err))
jjCount.Delete(key)
return
} else if err != nil {
ctx.SendChain(message.Text("ERROR:", err)) ctx.SendChain(message.Text("ERROR:", err))
return return
} }
// 数据库操作成功之后,及时删除残留的缓存
if _, ok := jjCount.Load(key); ok {
jjCount.Delete(key)
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(sell)) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(sell))
}) })
en.OnFullMatch("牛牛背包", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { en.OnFullMatch("牛牛背包", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
@ -135,29 +140,33 @@ func init() {
cost int cost int
scope string scope string
description string description string
count int
}{ }{
1: {"伟哥", 300, "打胶", "可以让你打胶每次都增长", 5}, 1: {"伟哥", 100, "打胶", "可以让你打胶每次都增长"},
2: {"媚药", 300, "打胶", "可以让你打胶每次都减少", 5}, 2: {"媚药", 100, "打胶", "可以让你打胶每次都减少"},
3: {"击剑神器", 500, "jj", "可以让你每次击剑都立于不败之地", 2}, 3: {"击剑神器", 300, "jj", "可以让你每次击剑都立于不败之地"},
4: {"击剑神稽", 500, "jj", "可以让你每次击剑都失败", 2}, 4: {"击剑神稽", 300, "jj", "可以让你每次击剑都失败"},
} }
var messages message.Message var messages message.Message
messages = append(messages, ctxext.FakeSenderForwardNode(ctx,
message.Text("输入对应序号进行购买商品"),
message.Text(
"使用说明:\n"+
"商品id-商品数量\n"+
"如想购买10个伟哥\n"+
"即:1-10")))
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛商店当前售卖的物品如下"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛商店当前售卖的物品如下")))
for id := range propMap { for id := 1; id <= len(propMap); id++ {
product := propMap[id] product := propMap[id]
productInfo := fmt.Sprintf("商品%d\n商品名: %s\n商品价格: %dATRI币\n商品作用域: %s\n商品描述: %s\n使用次数:%d", productInfo := fmt.Sprintf("商品%d\n商品名: %s\n商品价格: %dATRI币\n商品作用域: %s\n商品描述: %s",
id, product.name, product.cost, product.scope, product.description, product.count) id, product.name, product.cost, product.scope, product.description)
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(productInfo))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(productInfo)))
} }
if id := ctx.Send(messages).ID(); id == 0 { if id := ctx.Send(messages).ID(); id == 0 {
ctx.Send(message.Text("发送商店失败")) ctx.Send(message.Text("发送商店失败"))
return return
} }
recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(\d+)-(\d+)$`)).Repeat()
ctx.SendChain(message.Text("输入对应序号进行购买商品"))
recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(\d+)$`)).Repeat()
defer cancel() defer cancel()
timer := time.NewTimer(120 * time.Second) timer := time.NewTimer(120 * time.Second)
answer := "" answer := ""
@ -165,17 +174,17 @@ func init() {
for { for {
select { select {
case <-timer.C: case <-timer.C:
ctx.SendChain(message.At(uid), message.Text(" 超时,已自动取消")) ctx.SendChain(message.At(uid), message.Text(" 超时已自动取消"))
return return
case r := <-recv: case r := <-recv:
answer = r.Event.Message.String() answer = r.Event.Message.String()
n, err := strconv.Atoi(answer)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if err = niu.Store(gid, uid, n); err != nil { // 解析输入的商品ID和数量
parts := strings.Split(answer, "-")
productID, _ := strconv.Atoi(parts[0])
quantity, _ := strconv.Atoi(parts[1])
if err := niu.Store(gid, uid, productID, quantity); err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
@ -196,16 +205,16 @@ func init() {
} }
if time.Since(last.TimeLimit) > time.Hour { if time.Since(last.TimeLimit) > time.Hour {
ctx.SendChain(message.Text("时间已经过期了,牛牛已被收回!")) ctx.SendChain(message.Text("时间已经过期了牛牛已被收回!"))
jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid)) jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid))
return return
} }
if last.Count < 4 { if last.Count < 4 {
ctx.SendChain(message.Text("你还没有被厥够4次呢,不能赎牛牛")) ctx.SendChain(message.Text("你还没有被厥够4次呢不能赎牛牛"))
return return
} }
ctx.SendChain(message.Text("再次确认一下哦,这次赎牛牛,牛牛长度将会变成", last.Length, "cm\n还需要嘛【是|否】")) ctx.SendChain(message.Text("再次确认一下哦这次赎牛牛,牛牛长度将会变成", last.Length, "cm\n还需要嘛【是|否】"))
recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(是|否)$`)).Repeat() recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(是|否)$`)).Repeat()
defer cancel() defer cancel()
timer := time.NewTimer(2 * time.Minute) timer := time.NewTimer(2 * time.Minute)
@ -222,11 +231,11 @@ func init() {
return return
} }
if err := niu.Redeem(gid, uid, last.Length); err == nil { if err := niu.Redeem(gid, uid, *last); err != nil {
ctx.SendChain(message.Text("ERROR:", err)) ctx.SendChain(message.Text("ERROR:", err))
return return
} }
// 成功赎回,删除残留的缓存。
jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid)) jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid))
ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("恭喜你!成功赎回牛牛,当前长度为:%.2fcm", last.Length))) ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("恭喜你!成功赎回牛牛,当前长度为:%.2fcm", last.Length)))
@ -332,7 +341,7 @@ func init() {
} }
uid := ctx.Event.UserID uid := ctx.Event.UserID
gid := ctx.Event.GroupID gid := ctx.Event.GroupID
msg, length, err := niu.JJ(gid, uid, adduser, patternParsed[0].Text()[1]) msg, length, niuID, err := niu.JJ(gid, uid, adduser, patternParsed[0].Text()[1])
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
jjLimiter.Delete(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID)) jjLimiter.Delete(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
@ -341,22 +350,27 @@ func init() {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg)) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg))
j := fmt.Sprintf("%d_%d", gid, adduser) j := fmt.Sprintf("%d_%d", gid, adduser)
count, ok := jjCount.Load(j) count, ok := jjCount.Load(j)
var c lastLength var c niu.PKRecord
// 按照最后一次被 jj 时的时间计算超过60分钟则重置 // 按照最后一次被 jj 时的时间计算超过60分钟则重置
if !ok { if !ok {
c = lastLength{ // 第一次被 jj
c = niu.PKRecord{
NiuID: niuID,
TimeLimit: time.Now(), TimeLimit: time.Now(),
Count: 1, Count: 1,
Length: length, Length: length,
} }
} else { } else {
c = lastLength{ c = niu.PKRecord{
NiuID: niuID,
TimeLimit: time.Now(), TimeLimit: time.Now(),
Count: count.Count + 1, Count: count.Count + 1,
Length: count.Length, Length: count.Length,
} }
// 超时了,重置
if time.Since(c.TimeLimit) > time.Hour { if time.Since(c.TimeLimit) > time.Hour {
c = lastLength{ c = niu.PKRecord{
NiuID: niuID,
TimeLimit: time.Now(), TimeLimit: time.Now(),
Count: 1, Count: 1,
Length: length, Length: length,
@ -372,6 +386,9 @@ func init() {
))) )))
if c.Count >= 4 { if c.Count >= 4 {
if c.Count == 6 {
return
}
id := ctx.SendPrivateMessage(adduser, id := ctx.SendPrivateMessage(adduser,
message.Text(fmt.Sprintf("你在%d群里已经被厥冒烟了快去群里赎回你原本的牛牛!\n发送:`赎牛牛`即可!", gid))) message.Text(fmt.Sprintf("你在%d群里已经被厥冒烟了快去群里赎回你原本的牛牛!\n发送:`赎牛牛`即可!", gid)))
if id == 0 { if id == 0 {
@ -386,8 +403,8 @@ func init() {
key := fmt.Sprintf("%d_%d", gid, uid) key := fmt.Sprintf("%d_%d", gid, uid)
data, ok := register.Load(key) data, ok := register.Load(key)
switch { switch {
case !ok || time.Since(data.TimeLimit) > time.Hour*12: case !ok || time.Since(data.TimeLimit) > time.Hour*24:
data = &lastLength{ data = &niu.PKRecord{
TimeLimit: time.Now(), TimeLimit: time.Now(),
Count: 1, Count: 1,
} }
@ -396,6 +413,7 @@ func init() {
ctx.SendChain(message.Text("你的钱不够你注销牛牛了,这次注销需要", data.Count*50, wallet.GetWalletName())) ctx.SendChain(message.Text("你的钱不够你注销牛牛了,这次注销需要", data.Count*50, wallet.GetWalletName()))
return return
} }
data.Count++
} }
register.Store(key, data) register.Store(key, data)
msg, err := niu.Cancel(gid, uid) msg, err := niu.Cancel(gid, uid)

View File

@ -3,7 +3,6 @@ package nsfw
import ( import (
"github.com/FloatTech/AnimeAPI/nsfw" "github.com/FloatTech/AnimeAPI/nsfw"
"github.com/FloatTech/floatbox/process"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext" "github.com/FloatTech/zbputils/ctxext"
@ -11,8 +10,6 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
const hso = "https://gchat.qpic.cn/gchatpic_new//--4234EDEC5F147A4C319A41149D7E0EA9/0"
func init() { func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
@ -33,23 +30,6 @@ func init() {
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(judge(p)))) ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(judge(p))))
} }
}) })
control.Register("nsfwauto", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: true,
Brief: "nsfw图片自动识别",
Help: "- 当图片属于非 neutral 类别时自动发送评价",
}).OnMessage(zero.HasPicture).SetBlock(false).
Handle(func(ctx *zero.Ctx) {
url := ctx.State["image_url"].([]string)
if len(url) > 0 {
process.SleepAbout1sTo2s()
p, err := nsfw.Classify(url[0])
if err != nil {
return
}
process.SleepAbout1sTo2s()
autojudge(ctx, p)
}
})
} }
func judge(p *nsfw.Picture) string { func judge(p *nsfw.Picture) string {
@ -73,31 +53,3 @@ func judge(p *nsfw.Picture) string {
} }
return c return c
} }
func autojudge(ctx *zero.Ctx, p *nsfw.Picture) {
if p.Neutral > 0.3 {
return
}
c := ""
if p.Drawings > 0.3 {
c = "二次元"
} else {
c = "三次元"
}
i := 0
if p.Hentai > 0.3 {
c += " hentai"
i++
}
if p.Porn > 0.3 {
c += " porn"
i++
}
if p.Sexy > 0.3 {
c += " hso"
i++
}
if i > 0 {
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(c, "\n"), message.Image(hso)))
}
}

61
plugin/nsfwauto/main.go Normal file
View File

@ -0,0 +1,61 @@
// Package nsfwauto 图片合规性审查的自动版本
package nsfwauto
import (
"github.com/FloatTech/AnimeAPI/nsfw"
"github.com/FloatTech/floatbox/process"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const hso = "https://gchat.qpic.cn/gchatpic_new//--4234EDEC5F147A4C319A41149D7E0EA9/0"
func init() {
control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: true,
Brief: "nsfw图片自动识别",
Help: "- 当图片属于非 neutral 类别时自动发送评价",
}).OnMessage(zero.HasPicture).SetBlock(false).
Handle(func(ctx *zero.Ctx) {
url := ctx.State["image_url"].([]string)
if len(url) > 0 {
process.SleepAbout1sTo2s()
p, err := nsfw.Classify(url[0])
if err != nil {
return
}
process.SleepAbout1sTo2s()
autojudge(ctx, p)
}
})
}
func autojudge(ctx *zero.Ctx, p *nsfw.Picture) {
if p.Neutral > 0.3 {
return
}
c := ""
if p.Drawings > 0.3 {
c = "二次元"
} else {
c = "三次元"
}
i := 0
if p.Hentai > 0.3 {
c += " hentai"
i++
}
if p.Porn > 0.3 {
c += " porn"
i++
}
if p.Sexy > 0.3 {
c += " hso"
i++
}
if i > 0 {
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(c, "\n"), message.Image(hso)))
}
}

View File

@ -17,7 +17,7 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
// 反并发 // 反并发
"github.com/wdvxdr1123/ZeroBot/extension/single"
// 数据库 // 数据库
sql "github.com/FloatTech/sqlite" sql "github.com/FloatTech/sqlite"
// 画图 // 画图
@ -67,16 +67,7 @@ var (
"\"娶群友\"&\"(娶|嫁)@对方QQ\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" + "\"娶群友\"&\"(娶|嫁)@对方QQ\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" +
"\nTips: 群老婆列表过0点刷新", "\nTips: 群老婆列表过0点刷新",
PrivateDataFolder: "qqwife", PrivateDataFolder: "qqwife",
}).ApplySingle(single.New( }).ApplySingle(ctxext.NewGroupSingle("别着急,民政局门口排长队了!"))
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("别着急,民政局门口排长队了!"),
),
)
}),
))
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
民政局.db = sql.New(engine.DataFolder() + "结婚登记表.db") 民政局.db = sql.New(engine.DataFolder() + "结婚登记表.db")
err := 民政局.db.Open(time.Hour) err := 民政局.db.Open(time.Hour)

View File

@ -11,7 +11,6 @@ import (
sql "github.com/FloatTech/sqlite" sql "github.com/FloatTech/sqlite"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/FloatTech/AnimeAPI/wallet" "github.com/FloatTech/AnimeAPI/wallet"
"github.com/FloatTech/floatbox/math" "github.com/FloatTech/floatbox/math"
@ -45,16 +44,7 @@ func init() {
"7. 每日可打劫或被打劫一次\n" + "7. 每日可打劫或被打劫一次\n" +
"8. 打劫失败不计入次数\n", "8. 打劫失败不计入次数\n",
PrivateDataFolder: "robbery", PrivateDataFolder: "robbery",
}).ApplySingle(single.New( }).ApplySingle(ctxext.NewGroupSingle("别着急,警察局门口排长队了!"))
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("别着急,警察局门口排长队了!"),
),
)
}),
))
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
police.db = sql.New(engine.DataFolder() + "robbery.db") police.db = sql.New(engine.DataFolder() + "robbery.db")
err := police.db.Open(time.Hour) err := police.db.Open(time.Hour)

134
plugin/rsshub/domain/job.go Normal file
View File

@ -0,0 +1,134 @@
// Package domain rsshub领域逻辑
package domain
import (
"context"
"github.com/mmcdole/gofeed"
"github.com/sirupsen/logrus"
)
// syncRss 同步所有频道
// 返回:更新的频道&订阅信息 map[int64]*RssClientView
// 1. 获取所有频道
// 2. 遍历所有频道,检查频道是否更新
// 3. 如果更新,获取更新的内容,但是返回的数据
func (repo *RssDomain) syncRss(ctx context.Context) (updated map[int64]*RssClientView, err error) {
updated = make(map[int64]*RssClientView)
// 获取所有频道
sources, err := repo.storage.GetSources(ctx)
if err != nil {
return
}
// 遍历所有源获取每个channel对应的rss内容
rssView := make([]*RssClientView, len(sources))
for i, channel := range sources {
var feed *gofeed.Feed
// 从site获取rss内容
feed, err = repo.rssHubClient.FetchFeed(channel.RssHubFeedPath)
// 如果获取失败,则跳过
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] fetch path(%+v) error: %v", channel.RssHubFeedPath, err)
continue
}
rv := convertFeedToRssView(0, channel.RssHubFeedPath, feed)
rssView[i] = rv
}
// 检查频道是否更新
for _, cv := range rssView {
if cv == nil {
continue
}
var needUpdate bool
needUpdate, err = repo.checkSourceNeedUpdate(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] checkSourceNeedUpdate error: %v", err)
err = nil
continue
}
// 保存
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %+v, need update(real): %v", cv.Source, needUpdate)
// 如果需要更新更新channel 和 content
if needUpdate {
err = repo.storage.UpsertSource(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert source error: %v", err)
}
}
var updateChannelView = &RssClientView{Source: cv.Source, Contents: []*RssContent{}}
err = repo.processContentsUpdate(ctx, cv, updateChannelView)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] processContentsUpdate error: %v", err)
continue
}
if len(updateChannelView.Contents) == 0 {
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, no new content", cv.Source.RssHubFeedPath)
continue
}
updateChannelView.Sort()
updated[updateChannelView.Source.ID] = updateChannelView
logrus.WithContext(ctx).Debugf("[rsshub syncRss] cv %s, new contents: %v", cv.Source.RssHubFeedPath, len(updateChannelView.Contents))
}
return
}
// checkSourceNeedUpdate 检查频道是否需要更新
func (repo *RssDomain) checkSourceNeedUpdate(ctx context.Context, source *RssSource) (needUpdate bool, err error) {
var sourceInDB *RssSource
sourceInDB, err = repo.storage.GetSourceByRssHubFeedLink(ctx, source.RssHubFeedPath)
if err != nil {
return
}
if sourceInDB == nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] source not found: %v", source.RssHubFeedPath)
return
}
source.ID = sourceInDB.ID
// 检查是否需要更新到db
if sourceInDB.IfNeedUpdate(source) {
needUpdate = true
}
return
}
// processContentsUpdate 处理内容(s)更新
func (repo *RssDomain) processContentsUpdate(ctx context.Context, cv *RssClientView, updateChannelView *RssClientView) error {
var err error
for _, content := range cv.Contents {
if content == nil {
continue
}
content.RssSourceID = cv.Source.ID
var existed bool
existed, err = repo.processContentItemUpdate(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
err = nil
continue
}
if !existed {
updateChannelView.Contents = append(updateChannelView.Contents, content)
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, add new content: %v", cv.Source.RssHubFeedPath, content.Title)
}
}
return err
}
// processContentItemUpdate 处理单个内容更新
func (repo *RssDomain) processContentItemUpdate(ctx context.Context, content *RssContent) (existed bool, err error) {
existed, err = repo.storage.IsContentHashIDExist(ctx, content.HashID)
if err != nil {
return
}
// 不需要更新&不需要发送
if existed {
return
}
// 保存
err = repo.storage.UpsertContent(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
return
}
return
}

View File

@ -0,0 +1,118 @@
package domain
import (
"encoding/hex"
"hash/fnv"
"sort"
"time"
)
// ======== RSS ========[START]
func genHashForFeedItem(link, guid string) string {
h := fnv.New32()
// 分三次写入数据link、分隔符、guid
_, _ = h.Write([]byte(link))
_, _ = h.Write([]byte("||"))
_, _ = h.Write([]byte(guid))
encoded := hex.EncodeToString(h.Sum(nil))
return encoded
}
// RssClientView 频道视图
type RssClientView struct {
Source *RssSource
Contents []*RssContent
}
// ======== RSS ========[END]
// ======== DB ========[START]
const (
tableNameRssSource = "rss_source"
tableNameRssContent = "rss_content"
tableNameRssSubscribe = "rss_subscribe"
)
// RssSource RSS频道
type RssSource struct {
// Id 自增id
ID int64 `gorm:"column:id;primary_key;AUTO_INCREMENT"`
// RssHubFeedPath 频道路由 用于区分rss_hub 不同的频道 例如: `/bangumi/tv/calendar/today`
RssHubFeedPath string `gorm:"column:rss_hub_feed_path;not null;unique;" json:"rss_hub_feed_path"`
// Title 频道标题
Title string `gorm:"column:title" json:"title"`
// ChannelDesc 频道描述
ChannelDesc string `gorm:"column:channel_desc" json:"channel_desc"`
// ImageURL 频道图片
ImageURL string `gorm:"column:image_url" json:"image_url"`
// Link 频道链接
Link string `gorm:"column:link" json:"link"`
// UpdatedParsed RSS页面更新时间
UpdatedParsed time.Time `gorm:"column:updated_parsed" json:"updated_parsed"`
// Mtime update time
Mtime time.Time `gorm:"column:mtime;default:current_timestamp;" json:"mtime"`
}
// TableName ...
func (RssSource) TableName() string {
return tableNameRssSource
}
// IfNeedUpdate ...
func (r RssSource) IfNeedUpdate(cmp *RssSource) bool {
if r.Link != cmp.Link {
return false
}
return r.UpdatedParsed.Unix() < cmp.UpdatedParsed.Unix()
}
// RssContent 订阅的RSS频道的推送信息
type RssContent struct {
// Id 自增id
ID int64 `gorm:"column:id;primary_key;AUTO_INCREMENT"`
HashID string `gorm:"column:hash_id;unique" json:"hash_id"`
RssSourceID int64 `gorm:"column:rss_source_id;not null" json:"rss_source_id"`
Title string `gorm:"column:title" json:"title"`
Description string `gorm:"column:description" json:"description"`
Link string `gorm:"column:link" json:"link"`
Date time.Time `gorm:"column:date" json:"date"`
Author string `gorm:"column:author" json:"author"`
Thumbnail string `gorm:"column:thumbnail" json:"thumbnail"`
Content string `gorm:"column:content" json:"content"`
// Mtime update time
Mtime time.Time `gorm:"column:mtime;default:current_timestamp;" json:"mtime"`
}
// TableName ...
func (RssContent) TableName() string {
return tableNameRssContent
}
// Sort ... order by Date desc
func (r *RssClientView) Sort() {
sort.Slice(r.Contents, func(i, j int) bool {
return r.Contents[i].Date.Unix() > r.Contents[j].Date.Unix()
})
}
// RssSubscribe 订阅关系表:群组-RSS频道
type RssSubscribe struct {
// Id 自增id
ID int64 `gorm:"column:id;primary_key;AUTO_INCREMENT"`
// 订阅群组
GroupID int64 `gorm:"column:group_id;not null;uniqueIndex:uk_sid_gid"`
// 订阅频道
RssSourceID int64 `gorm:"column:rss_source_id;not null;uniqueIndex:uk_sid_gid"`
// Mtime update time
Mtime time.Time `gorm:"column:mtime;default:current_timestamp;" json:"mtime"`
}
// TableName ...
func (RssSubscribe) TableName() string {
return tableNameRssSubscribe
}
// ======== DB ========[END]

View File

@ -0,0 +1,101 @@
package domain
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"time"
"github.com/FloatTech/floatbox/web"
"github.com/mmcdole/gofeed"
"github.com/sirupsen/logrus"
)
var (
// RSSHubMirrors RSSHub镜像站地址列表第一个为默认地址
rssHubMirrors = []string{
"https://rsshub.rssforever.com",
"https://rss.injahow.cn",
}
)
// RssHubClient rss hub client (http)
type RssHubClient struct {
*http.Client
}
// FetchFeed 获取rss feed信息
func (c *RssHubClient) FetchFeed(path string) (feed *gofeed.Feed, err error) {
var data []byte
// 遍历 rssHubMirrors直到获取成功
for _, mirror := range rssHubMirrors {
data, err = web.RequestDataWith(c.Client, mirror+path, "GET", "", web.RandUA(), nil)
if err == nil && len(data) > 0 {
break
}
}
if err != nil {
logrus.Errorf("[rsshub FetchFeed] fetch feed error: %v", err)
return nil, err
}
if len(data) == 0 {
logrus.Errorf("[rsshub FetchFeed] fetch feed error: data is empty")
return nil, errors.New("feed data is empty")
}
feed, err = gofeed.NewParser().Parse(bytes.NewBuffer(data))
if err != nil {
return
}
return
}
func convertFeedToRssView(channelID int64, cPath string, feed *gofeed.Feed) (view *RssClientView) {
var imgURL string
if feed.Image != nil {
imgURL = feed.Image.URL
}
view = &RssClientView{
Source: &RssSource{
ID: channelID,
RssHubFeedPath: cPath,
Title: feed.Title,
ChannelDesc: feed.Description,
ImageURL: imgURL,
Link: feed.Link,
UpdatedParsed: *(feed.UpdatedParsed),
Mtime: time.Now(),
},
// 不用定长后面可能会过滤一些元素再append
Contents: []*RssContent{},
}
// convert feed items to rss content
for _, item := range feed.Items {
if item.Link == "" || item.Title == "" {
continue
}
var thumbnail string
if item.Image != nil {
thumbnail = item.Image.URL
}
var publishedParsed = item.PublishedParsed
if publishedParsed == nil {
publishedParsed = &time.Time{}
}
aus, _ := json.Marshal(item.Authors)
view.Contents = append(view.Contents, &RssContent{
ID: 0,
HashID: genHashForFeedItem(item.Link, item.GUID),
RssSourceID: channelID,
Title: item.Title,
Description: item.Description,
Link: item.Link,
Date: *publishedParsed,
Author: string(aus),
Thumbnail: thumbnail,
Content: item.Content,
Mtime: time.Now(),
})
}
return
}

View File

@ -0,0 +1,178 @@
package domain
import (
"context"
"errors"
"net/http"
"os"
"time"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
)
// RssDomain RssRepo定义
type RssDomain struct {
storage *repoStorage
rssHubClient *RssHubClient
}
// NewRssDomain 新建RssDomain调用方保证单例模式
func NewRssDomain(dbPath string) (*RssDomain, error) {
return newRssDomain(dbPath)
}
func newRssDomain(dbPath string) (*RssDomain, error) {
if _, err := os.Stat(dbPath); err != nil || os.IsNotExist(err) {
// 生成文件
f, err := os.Create(dbPath)
if err != nil {
return nil, err
}
defer f.Close()
}
orm, err := gorm.Open("sqlite3", dbPath)
if err != nil {
logrus.Errorf("[rsshub NewRssDomain] open db error: %v", err)
panic(err)
}
repo := &RssDomain{
storage: &repoStorage{orm: orm},
rssHubClient: &RssHubClient{Client: http.DefaultClient},
}
err = repo.storage.initDB()
if err != nil {
logrus.Errorf("[rsshub NewRssDomain] open db error: %v", err)
panic(err)
}
return repo, nil
}
// Subscribe QQ群订阅Rss频道
func (repo *RssDomain) Subscribe(ctx context.Context, gid int64, feedPath string) (
rv *RssClientView, isChannelExisted, isSubExisted bool, err error) {
// 验证
feed, err := repo.rssHubClient.FetchFeed(feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] add source error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] try get source success: %v", len(feed.Title))
// 新建source结构体
rv = convertFeedToRssView(0, feedPath, feed)
feedChannel, err := repo.storage.GetSourceByRssHubFeedLink(ctx, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query source by feedPath error: %v", err)
return
}
// 如果已经存在
if feedChannel != nil {
logrus.WithContext(ctx).Warningf("[rsshub Subscribe] source existed: %v", feedChannel)
isChannelExisted = true
} else {
// 不存在的情况,要把更新时间置空,保证下一次同步时能够更新
rv.Source.UpdatedParsed = time.Time{}
}
// 保存
err = repo.storage.UpsertSource(ctx, rv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] save source error: %v", err)
return
}
logrus.Infof("[rsshub Subscribe] save/update source success %v", rv.Source.ID)
// 添加群号到订阅
subscribe, err := repo.storage.GetSubscribeByID(ctx, gid, rv.Source.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query subscribe error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] query subscribe success: %v", subscribe)
// 如果已经存在,直接返回
if subscribe != nil {
isSubExisted = true
logrus.WithContext(ctx).Infof("[rsshub Subscribe] subscribe existed: %v", subscribe)
return
}
// 如果不存在,保存
err = repo.storage.CreateSubscribe(ctx, gid, rv.Source.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] save subscribe error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] success: %v", len(rv.Contents))
return
}
// Unsubscribe 群组取消订阅
func (repo *RssDomain) Unsubscribe(ctx context.Context, gid int64, feedPath string) (err error) {
existedSubscribes, ifExisted, err := repo.storage.GetIfExistedSubscribe(ctx, gid, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query sub by route error: %v", err)
return errors.New("数据库错误")
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] query source by route success: %v", existedSubscribes)
// 如果不存在订阅关系,直接返回
if !ifExisted || existedSubscribes == nil {
logrus.WithContext(ctx).Infof("[rsshub Subscribe] source existed: %v", ifExisted)
return errors.New("频道不存在")
}
err = repo.storage.DeleteSubscribe(ctx, existedSubscribes.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] delete source error: %v", err)
return errors.New("删除失败")
}
// 查询是否还有群订阅这个频道
subscribesNeedsToDel, err := repo.storage.GetSubscribesBySource(ctx, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query source by route error: %v", err)
return
}
// 没有群订阅的时候,把频道删除
if len(subscribesNeedsToDel) == 0 {
err = repo.storage.DeleteSource(ctx, existedSubscribes.RssSourceID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] delete source error: %v", err)
return errors.New("清除频道信息失败")
}
}
return
}
// GetSubscribedChannelsByGroupID 获取群对应的订阅的频道信息
func (repo *RssDomain) GetSubscribedChannelsByGroupID(ctx context.Context, gid int64) ([]*RssClientView, error) {
channels, err := repo.storage.GetSubscribedChannelsByGroupID(ctx, gid)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub GetSubscribedChannelsByGroupID] GetSubscribedChannelsByGroupID error: %v", err)
return nil, err
}
rv := make([]*RssClientView, len(channels))
logrus.WithContext(ctx).Infof("[rsshub GetSubscribedChannelsByGroupID] query subscribe success: %v", len(channels))
for i, cn := range channels {
rv[i] = &RssClientView{
Source: cn,
}
}
return rv, nil
}
// Sync 同步任务按照群组订阅情况做好map切片
func (repo *RssDomain) Sync(ctx context.Context) (groupView map[int64][]*RssClientView, err error) {
groupView = make(map[int64][]*RssClientView)
// 获取所有Rss频道
// 获取所有频道
updatedViews, err := repo.syncRss(ctx)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Sync] sync rss feed error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Sync] updated channels: %v", len(updatedViews))
subscribes, err := repo.storage.GetSubscribes(ctx)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Sync] get subscribes error: %v", err)
return
}
for _, subscribe := range subscribes {
groupView[subscribe.GroupID] = append(groupView[subscribe.GroupID], updatedViews[subscribe.RssSourceID])
}
return
}

View File

@ -0,0 +1,105 @@
package domain
import (
"context"
"encoding/json"
"testing"
)
func TestNewRssDomain(t *testing.T) {
dm, err := newRssDomain("rsshub.db")
if err != nil {
t.Fatal(err)
return
}
if dm == nil {
t.Fatal("domain is nil")
}
}
//var testRssHubChannelUrl = "https://rsshub.rssforever.com/bangumi/tv/calendar/today"
var dm, _ = newRssDomain("rsshub.db")
func TestSub(t *testing.T) {
testCases := []struct {
name string
feedLink string
gid int64
}{
{
name: "test1",
feedLink: "/bangumi/tv/calendar/today",
gid: 99,
},
{
name: "test2",
feedLink: "/go-weekly",
gid: 99,
},
{
name: "test3",
feedLink: "/go-weekly",
gid: 123,
},
{
name: "test3",
feedLink: "/go-weekly",
gid: 321,
},
{
name: "test3",
feedLink: "/go-weekly",
gid: 4123,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
channel, ifExisted, ifSub, err := dm.Subscribe(ctx, tc.gid, tc.feedLink)
if err != nil {
t.Fatal(err)
return
}
t.Logf("[TEST] add sub res: %+v,%+v,%+v\n", channel, ifExisted, ifSub)
res, ext, err := dm.storage.GetIfExistedSubscribe(ctx, tc.gid, tc.feedLink)
if err != nil {
t.Fatal(err)
return
}
t.Logf("[TEST] if exist: %+v,%+v", res, ext)
channels, err := dm.GetSubscribedChannelsByGroupID(ctx, 2)
if err != nil {
t.Fatal(err)
return
}
t.Logf("[TEST] 2 channels: %+v", channels)
// del
//err = dm.Unsubscribe(ctx, tc.gid, tc.feedLink)
//if err != nil {
// t.Fatal(err)
// return
//}
//res, ext, err = dm.storage.GetIfExistedSubscribe(ctx, tc.gid, tc.feedLink)
//if err != nil {
// t.Fatal(err)
// return
//}
//t.Logf("[TEST] after del: %+v,%+v", res, ext)
//if res != nil || ext {
// t.Fatal("delete failed")
//}
})
}
}
func Test_SyncFeed(t *testing.T) {
feed, err := dm.Sync(context.Background())
if err != nil {
t.Fatal(err)
return
}
rs, _ := json.Marshal(feed)
t.Logf("[Test] feed: %+v", string(rs))
}

View File

@ -0,0 +1,271 @@
package domain
import (
"context"
"errors"
"fmt"
"time"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
)
// repoStorage db struct for rss
type repoStorage struct {
orm *gorm.DB
}
// initDB ...
func (s *repoStorage) initDB() (err error) {
err = s.orm.AutoMigrate(&RssSource{}, &RssContent{}, &RssSubscribe{}).Error
if err != nil {
logrus.Errorf("[rsshub initDB] error: %v", err)
return err
}
return nil
// s.orm.LogMode(true)
}
// GetSubscribesBySource Impl
func (s *repoStorage) GetSubscribesBySource(ctx context.Context, feedPath string) ([]*RssSubscribe, error) {
logrus.WithContext(ctx).Infof("[rsshub GetSubscribesBySource] feedPath: %s", feedPath)
rs := make([]*RssSubscribe, 0)
err := s.orm.Model(&RssSubscribe{}).Joins(fmt.Sprintf("%s left join %s on %s.rss_source_id=%s.id", tableNameRssSubscribe, tableNameRssSource, tableNameRssSubscribe, tableNameRssSource)).
Where("rss_source.rss_hub_feed_path = ?", feedPath).Select("rss_subscribe.*").Find(&rs).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub GetSubscribesBySource] error: %v", err)
return nil, err
}
return rs, nil
}
// GetIfExistedSubscribe Impl
func (s *repoStorage) GetIfExistedSubscribe(ctx context.Context, gid int64, feedPath string) (*RssSubscribe, bool, error) {
rs := RssSubscribe{}
err := s.orm.Table(tableNameRssSubscribe).
Select("rss_subscribe.id, rss_subscribe.group_id, rss_subscribe.rss_source_id, rss_subscribe.mtime").
Joins(fmt.Sprintf("INNER JOIN %s ON %s.rss_source_id=%s.id",
tableNameRssSource, tableNameRssSubscribe, tableNameRssSource)).
Where("rss_source.rss_hub_feed_path = ? AND rss_subscribe.group_id = ?", feedPath, gid).Scan(&rs).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
logrus.WithContext(ctx).Errorf("[rsshub GetIfExistedSubscribe] error: %v", err)
return nil, false, err
}
if rs.ID == 0 {
return nil, false, nil
}
return &rs, true, nil
}
// ==================== RepoSource ==================== [Start]
// UpsertSource Impl
func (s *repoStorage) UpsertSource(ctx context.Context, source *RssSource) (err error) {
// Update columns to default value on `id` conflict
querySource := &RssSource{RssHubFeedPath: source.RssHubFeedPath}
err = s.orm.First(querySource, "rss_hub_feed_path = ?", querySource.RssHubFeedPath).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = s.orm.Create(source).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] add source error: %v", err)
return
}
}
return
}
source.ID = querySource.ID
logrus.WithContext(ctx).Infof("[rsshub] update source: %+v", source.UpdatedParsed)
err = s.orm.Model(&source).Where(&RssSource{ID: source.ID}).
Updates(&RssSource{
Title: source.Title,
ChannelDesc: source.ChannelDesc,
ImageURL: source.ImageURL,
Link: source.Link,
UpdatedParsed: source.UpdatedParsed,
Mtime: time.Now(),
}).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] update source error: %v", err)
return
}
logrus.Println("[rsshub] add source success: ", source.ID)
return nil
}
// GetSources Impl
func (s *repoStorage) GetSources(ctx context.Context) (sources []RssSource, err error) {
sources = []RssSource{}
err = s.orm.Find(&sources, "id > 0").Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("source not found")
}
logrus.WithContext(ctx).Errorf("[rsshub] get sources error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub] get sources success: %d", len(sources))
return
}
// GetSourceByRssHubFeedLink Impl
func (s *repoStorage) GetSourceByRssHubFeedLink(ctx context.Context, rssHubFeedLink string) (source *RssSource, err error) {
source = &RssSource{RssHubFeedPath: rssHubFeedLink}
err = s.orm.Take(source, source).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] get source error: %v", err)
return
}
return
}
// DeleteSource Impl
func (s *repoStorage) DeleteSource(ctx context.Context, fID int64) (err error) {
err = s.orm.Delete(&RssSource{}, "id = ?", fID).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSource: %v", err)
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("source not found")
}
return
}
return nil
}
// ==================== RepoSource ==================== [End]
// ==================== RepoContent ==================== [Start]
// UpsertContent Impl
func (s *repoStorage) UpsertContent(ctx context.Context, content *RssContent) (err error) {
// check params
if content == nil {
err = errors.New("content is nil")
return
}
// check params.RssHubFeedPath and params.HashID
if content.RssSourceID < 0 || content.HashID == "" || content.Title == "" {
err = errors.New("content.RssSourceID or content.HashID or content.Title is empty")
return
}
err = s.orm.Create(content).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.UpsertContent: %v", err)
return
}
return
}
// DeleteSourceContents Impl
func (s *repoStorage) DeleteSourceContents(ctx context.Context, channelID int64) (rows int64, err error) {
err = s.orm.Delete(&RssSubscribe{}).Where(&RssSubscribe{RssSourceID: channelID}).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSourceContents: %v", err)
return
}
return
}
// IsContentHashIDExist Impl
func (s *repoStorage) IsContentHashIDExist(ctx context.Context, hashID string) (bool, error) {
wanted := &RssContent{HashID: hashID}
err := s.orm.Take(wanted, wanted).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.IsContentHashIDExist: %v", err)
return false, err
}
return true, nil
}
// ==================== RepoContent ==================== [End]
// ==================== RepoSubscribe ==================== [Start]
// CreateSubscribe Impl
func (s *repoStorage) CreateSubscribe(ctx context.Context, gid, rssSourceID int64) (err error) {
// check subscribe
if rssSourceID < 0 || gid == 0 {
err = errors.New("gid or rssSourceID is empty")
return
}
err = s.orm.Create(&RssSubscribe{GroupID: gid, RssSourceID: rssSourceID}).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.CreateSubscribe: %v", err)
return
}
return
}
// DeleteSubscribe Impl
func (s *repoStorage) DeleteSubscribe(ctx context.Context, subscribeID int64) (err error) {
err = s.orm.Delete(&RssSubscribe{}, "id = ?", subscribeID).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSubscribe error: %v", err)
return
}
return
}
// GetSubscribeByID Impl
func (s *repoStorage) GetSubscribeByID(ctx context.Context, gid int64, subscribeID int64) (res *RssSubscribe, err error) {
res = &RssSubscribe{}
err = s.orm.First(res, &RssSubscribe{GroupID: gid, RssSourceID: subscribeID}).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribeByID: %v", err)
return nil, err
}
return
}
// GetSubscribedChannelsByGroupID Impl
func (s *repoStorage) GetSubscribedChannelsByGroupID(ctx context.Context, gid int64) (res []*RssSource, err error) {
res = make([]*RssSource, 0)
err = s.orm.Model(&RssSource{}).
Joins(fmt.Sprintf("join %s on rss_source_id=%s.id", tableNameRssSubscribe, tableNameRssSource)).Where("rss_subscribe.group_id = ?", gid).
Select("rss_source.*").
Find(&res).
Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = nil
return
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribedChannelsByGroupID: %v", err)
return
}
return
}
// GetSubscribes Impl
func (s *repoStorage) GetSubscribes(ctx context.Context) (res []*RssSubscribe, err error) {
res = make([]*RssSubscribe, 0)
err = s.orm.Find(&res).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
err = nil
return
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribes: %v", err)
return
}
return
}
// ==================== RepoSubscribe ==================== [End]

152
plugin/rsshub/main.go Normal file
View File

@ -0,0 +1,152 @@
// Package rsshub rss_hub订阅插件
package rsshub
import (
"context"
"fmt"
"regexp"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
zbpCtxExt "github.com/FloatTech/zbputils/ctxext"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub/domain"
)
// 初始化 repo
var (
rssRepo *domain.RssDomain
initErr error
regexpForSQL = regexp.MustCompile(`[\^<>\[\]%&\*\(\)\{\}\|\=]|(union\s+select|update\s+|delete\s+|drop\s+|truncate\s+|insert\s+|exec\s+|declare\s+)`)
)
var (
// 注册插件
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
// 默认不启动
DisableOnDefault: false,
Brief: "rsshub订阅姬",
// 详细帮助
Help: "rsshub订阅姬desu~ \n" +
"支持的详细订阅列表文档可见:\n" +
"https://rsshub.netlify.app/zh/ \n" +
"- 添加rsshub订阅-/bookfere/weekly \n" +
"- 删除rsshub订阅-/bookfere/weekly \n" +
"- 查看rsshub订阅列表 \n" +
"- rsshub同步 \n" +
"Tips: 定时刷新rsshub订阅信息需要配合job一起使用, 全局只需要设置一个, 无视响应状态推送, 下为例子\n" +
"记录在\"@every 10m\"触发的指令)\n" +
"rsshub同步",
// 插件数据存储路径
PrivateDataFolder: "rsshub",
OnEnable: func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("rsshub订阅姬现在启动了哦"))
},
OnDisable: func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("rsshub订阅姬现在关闭了哦"))
},
}).ApplySingle(zbpCtxExt.DefaultSingle)
)
// init 命令路由
func init() {
rssRepo, initErr = domain.NewRssDomain(engine.DataFolder() + "rsshub.db")
if initErr != nil {
logrus.Errorln("rsshub订阅姬初始化失败", initErr)
panic(initErr)
}
engine.OnFullMatch("rsshub同步", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
// 群组-频道推送视图 map[群组]推送内容数组
groupToFeedsMap, err := rssRepo.Sync(context.Background())
if err != nil {
logrus.Errorln("rsshub同步失败", err)
ctx.SendPrivateMessage(zero.BotConfig.SuperUsers[0], message.Text("rsshub同步失败", err))
return
}
// 没有更新的[群组-频道推送视图]则不推送
if len(groupToFeedsMap) == 0 {
logrus.Info("rsshub未发现更新")
return
}
sendRssUpdateMsg(ctx, groupToFeedsMap)
})
// 添加订阅
engine.OnPrefix("添加rsshub订阅-", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
routeStr := ctx.State["args"].(string)
input := regexpForSQL.ReplaceAllString(routeStr, "")
logrus.Debugf("添加rsshub订阅raw(%s), replaced(%s)", routeStr, input)
rv, _, isSubExisted, err := rssRepo.Subscribe(context.Background(), ctx.Event.GroupID, input)
if err != nil {
ctx.SendChain(message.Text("rsshub订阅姬添加失败", err.Error()))
return
}
if isSubExisted {
ctx.SendChain(message.Text("rsshub订阅姬已存在更新成功"))
} else {
ctx.SendChain(message.Text("rsshub订阅姬添加成功\n", rv.Source.Title))
}
// 添加成功,发送订阅源快照
msg, err := newRssDetailsMsg(ctx, rv)
if len(msg) == 0 || err != nil {
ctx.SendPrivateMessage(zero.BotConfig.SuperUsers[0], message.Text("rsshub推送错误", err))
return
}
if id := ctx.Send(msg).ID(); id == 0 {
ctx.SendChain(message.Text("ERROR: 发送订阅源快照失败,可能被风控了"))
}
})
engine.OnPrefix("删除rsshub订阅-", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
routeStr := ctx.State["args"].(string)
input := regexpForSQL.ReplaceAllString(routeStr, "")
logrus.Debugf("删除rsshub订阅raw(%s), replaced(%s)", routeStr, input)
err := rssRepo.Unsubscribe(context.Background(), ctx.Event.GroupID, input)
if err != nil {
ctx.SendChain(message.Text("rsshub订阅姬删除失败 ", err.Error()))
return
}
ctx.SendChain(message.Text(fmt.Sprintf("rsshub订阅姬删除%s成功", input)))
})
engine.OnFullMatch("查看rsshub订阅列表", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
rv, err := rssRepo.GetSubscribedChannelsByGroupID(context.Background(), ctx.Event.GroupID)
if err != nil {
ctx.SendChain(message.Text("rsshub订阅姬查询失败 ", err.Error()))
return
}
// 添加成功,发送订阅源信息
msg, err := newRssSourcesMsg(ctx, rv)
if err != nil {
ctx.SendChain(message.Text("rsshub订阅姬查询失败 ", err.Error()))
return
}
if len(msg) == 0 {
ctx.SendChain(message.Text("ん? 没有订阅的频道哦~"))
return
}
ctx.SendChain(msg...)
})
}
// sendRssUpdateMsg 发送Rss更新消息
func sendRssUpdateMsg(ctx *zero.Ctx, groupToFeedsMap map[int64][]*domain.RssClientView) {
for groupID, views := range groupToFeedsMap {
logrus.Infof("rsshub插件在群 %d 触发推送检查", groupID)
for _, view := range views {
if view == nil || len(view.Contents) == 0 {
continue
}
msg, err := newRssDetailsMsg(ctx, view)
if len(msg) == 0 || err != nil {
ctx.SendPrivateMessage(zero.BotConfig.SuperUsers[0], message.Text(rssHubPushErrMsg, err))
continue
}
logrus.Infof("rsshub插件在群 %d 开始推送 %s", groupID, view.Source.Title)
ctx.SendGroupMessage(groupID, message.Text(fmt.Sprintf("%s\n该rsshub频道下有更新了哦~", view.Source.Title)))
if res := ctx.SendGroupForwardMessage(groupID, msg); !res.Exists() {
ctx.SendPrivateMessage(zero.BotConfig.SuperUsers[0], message.Text(rssHubPushErrMsg))
}
}
}
}

100
plugin/rsshub/view.go Normal file
View File

@ -0,0 +1,100 @@
package rsshub
import (
"fmt"
"time"
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/zbputils/img/text"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub/domain"
)
const (
rssHubPushErrMsg = "RssHub推送错误"
)
// formatRssViewToMessagesSlice 格式化RssClientView为消息切片
func formatRssViewToMessagesSlice(view *domain.RssClientView) ([]message.Message, error) {
// 取前20条
cts := view.Contents
if len(cts) > 20 {
cts = cts[:20]
}
// 2n+1条消息
fv := make([]message.Message, len(cts)*2+1)
// 订阅源头图
toastPic, err := text.RenderToBase64(fmt.Sprintf("%s\n\n\n%s\n\n\n更新时间:%v\n\n\n",
view.Source.Title, view.Source.Link, view.Source.UpdatedParsed.Local().Format(time.DateTime)),
text.SakuraFontFile, 1200, 40)
if err != nil {
return nil, err
}
fv[0] = message.Message{message.Image("base64://" + binary.BytesToString(toastPic))}
// 元素信息
for idx, item := range cts {
contentStr := fmt.Sprintf("%s\n\n\n", item.Title)
// Date为空时不显示
if !item.Date.IsZero() {
contentStr += fmt.Sprintf("更新时间:\n%v\n", item.Date.Local().Format(time.DateTime))
}
var content []byte
content, err = text.RenderToBase64(contentStr, text.SakuraFontFile, 1200, 40)
if err != nil {
logrus.WithError(err).Error("RssHub订阅姬渲染图片失败")
continue
}
itemMessagePic := message.Message{message.Image("base64://" + binary.BytesToString(content))}
fv[2*idx+1] = itemMessagePic
fv[2*idx+2] = message.Message{message.Text(item.Link)}
}
return fv, nil
}
// newRssSourcesMsg Rss订阅源列表
func newRssSourcesMsg(ctx *zero.Ctx, view []*domain.RssClientView) (message.Message, error) {
var msgSlice []message.Message
// 生成消息
for _, v := range view {
if v == nil {
continue
}
item, err := formatRssViewToMessagesSlice(v)
if err != nil {
return nil, err
}
msgSlice = append(msgSlice, item...)
}
// 伪造一个发送者为RssHub订阅姬的消息节点
msg := make(message.Message, len(msgSlice))
for i, item := range msgSlice {
msg[i] = fakeSenderForwardNode(ctx.Event.SelfID, item...)
}
return msg, nil
}
// newRssDetailsMsg Rss订阅源详情包含文章信息列表
func newRssDetailsMsg(ctx *zero.Ctx, view *domain.RssClientView) (message.Message, error) {
// 生成消息
msgSlice, err := formatRssViewToMessagesSlice(view)
if err != nil {
return nil, err
}
// 伪造一个发送者为RssHub订阅姬的消息节点
msg := make(message.Message, len(msgSlice))
for i, item := range msgSlice {
msg[i] = fakeSenderForwardNode(ctx.Event.SelfID, item...)
}
return msg, nil
}
// fakeSenderForwardNode 伪造一个发送者为RssHub订阅姬的消息节点
func fakeSenderForwardNode(userID int64, msgs ...message.Segment) message.Segment {
return message.CustomNode(
"RssHub订阅姬",
userID,
msgs)
}

View File

@ -2,6 +2,7 @@ package score
import ( import (
"os" "os"
"sync"
"time" "time"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
@ -11,7 +12,10 @@ import (
var sdb *scoredb var sdb *scoredb
// scoredb 分数数据库 // scoredb 分数数据库
type scoredb gorm.DB type scoredb struct {
db *gorm.DB
scoremu sync.Mutex
}
// scoretable 分数结构体 // scoretable 分数结构体
type scoretable struct { type scoretable struct {
@ -52,25 +56,31 @@ func initialize(dbpath string) *scoredb {
panic(err) panic(err)
} }
gdb.AutoMigrate(&scoretable{}).AutoMigrate(&signintable{}) gdb.AutoMigrate(&scoretable{}).AutoMigrate(&signintable{})
return (*scoredb)(gdb) return &scoredb{
db: gdb,
}
} }
// Close ... // Close ...
func (sdb *scoredb) Close() error { func (sdb *scoredb) Close() error {
db := (*gorm.DB)(sdb) db := sdb.db
return db.Close() return db.Close()
} }
// GetScoreByUID 取得分数 // GetScoreByUID 取得分数
func (sdb *scoredb) GetScoreByUID(uid int64) (s scoretable) { func (sdb *scoredb) GetScoreByUID(uid int64) (s scoretable) {
db := (*gorm.DB)(sdb) sdb.scoremu.Lock()
defer sdb.scoremu.Unlock()
db := sdb.db
db.Model(&scoretable{}).FirstOrCreate(&s, "uid = ? ", uid) db.Model(&scoretable{}).FirstOrCreate(&s, "uid = ? ", uid)
return s return s
} }
// InsertOrUpdateScoreByUID 插入或更新分数 // InsertOrUpdateScoreByUID 插入或更新分数
func (sdb *scoredb) InsertOrUpdateScoreByUID(uid int64, score int) (err error) { func (sdb *scoredb) InsertOrUpdateScoreByUID(uid int64, score int) (err error) {
db := (*gorm.DB)(sdb) sdb.scoremu.Lock()
defer sdb.scoremu.Unlock()
db := sdb.db
s := scoretable{ s := scoretable{
UID: uid, UID: uid,
Score: score, Score: score,
@ -91,14 +101,18 @@ func (sdb *scoredb) InsertOrUpdateScoreByUID(uid int64, score int) (err error) {
// GetSignInByUID 取得签到次数 // GetSignInByUID 取得签到次数
func (sdb *scoredb) GetSignInByUID(uid int64) (si signintable) { func (sdb *scoredb) GetSignInByUID(uid int64) (si signintable) {
db := (*gorm.DB)(sdb) sdb.scoremu.Lock()
defer sdb.scoremu.Unlock()
db := sdb.db
db.Model(&signintable{}).FirstOrCreate(&si, "uid = ? ", uid) db.Model(&signintable{}).FirstOrCreate(&si, "uid = ? ", uid)
return si return si
} }
// InsertOrUpdateSignInCountByUID 插入或更新签到次数 // InsertOrUpdateSignInCountByUID 插入或更新签到次数
func (sdb *scoredb) InsertOrUpdateSignInCountByUID(uid int64, count int) (err error) { func (sdb *scoredb) InsertOrUpdateSignInCountByUID(uid int64, count int) (err error) {
db := (*gorm.DB)(sdb) sdb.scoremu.Lock()
defer sdb.scoremu.Unlock()
db := sdb.db
si := signintable{ si := signintable{
UID: uid, UID: uid,
Count: count, Count: count,
@ -118,7 +132,9 @@ func (sdb *scoredb) InsertOrUpdateSignInCountByUID(uid int64, count int) (err er
} }
func (sdb *scoredb) GetScoreRankByTopN(n int) (st []scoretable, err error) { func (sdb *scoredb) GetScoreRankByTopN(n int) (st []scoretable, err error) {
db := (*gorm.DB)(sdb) sdb.scoremu.Lock()
defer sdb.scoremu.Unlock()
db := sdb.db
err = db.Model(&scoretable{}).Order("score desc").Limit(n).Find(&st).Error err = db.Model(&scoretable{}).Order("score desc").Limit(n).Find(&st).Error
return return
} }

View File

@ -2,19 +2,10 @@
package thesaurus package thesaurus
import ( import (
"math/rand"
"strings"
"github.com/go-ego/gse"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/AnimeAPI/kimoi" "github.com/FloatTech/AnimeAPI/kimoi"
"github.com/FloatTech/floatbox/ctxext"
"github.com/FloatTech/floatbox/process"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
) )
@ -23,62 +14,9 @@ func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "词典匹配回复, 仅@触发", Brief: "词典匹配回复, 仅@触发",
Help: "- 切换[kimo|傲娇|可爱]词库",
PublicDataFolder: "Chat", PublicDataFolder: "Chat",
}) })
engine.OnRegex(`^切换(kimo|傲娇|可爱)词库$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { engine.OnMessage(zero.OnlyToMe, canmatch()).
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
ctx.SendChain(message.Text("ERROR: 找不到 manager"))
return
}
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
d := c.GetData(gid)
t := int64(0)
switch ctx.State["regex_matched"].([]string)[1] {
case "kimo":
t = tKIMO
case "傲娇":
t = tDERE
case "可爱":
t = tKAWA
}
err := c.SetData(gid, (d&^3)|t)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("成功!"))
})
go func() {
var seg gse.Segmenter
err := seg.LoadDictEmbed()
if err != nil {
panic(err)
}
smd, err := engine.GetLazyData("simai.yml", false)
if err != nil {
panic(err)
}
sm := simai{D: make(map[string][]string, 8192), K: make(map[string][]string, 16384)}
err = yaml.Unmarshal(smd, &sm)
if err != nil {
panic(err)
}
chatListD := make([]string, 0, len(sm.D))
for k := range sm.D {
chatListD = append(chatListD, k)
}
chatListK := make([]string, 0, len(sm.K))
for k := range sm.K {
chatListK = append(chatListK, k)
}
logrus.Infoln("[thesaurus]加载", len(chatListD), "条傲娇词库", len(chatListK), "条可爱词库")
engine.OnMessage(zero.OnlyToMe, canmatch(tKIMO)).
SetBlock(false).Handle(func(ctx *zero.Ctx) { SetBlock(false).Handle(func(ctx *zero.Ctx) {
msg := ctx.ExtractPlainText() msg := ctx.ExtractPlainText()
r, err := kimoi.Chat(msg) r, err := kimoi.Chat(msg)
@ -98,68 +36,13 @@ func init() {
ctx.SendChain(message.Text(r.Reply)) ctx.SendChain(message.Text(r.Reply))
} }
}) })
engine.OnMessage(zero.OnlyToMe, canmatch(tDERE), match(chatListD, &seg)).
SetBlock(false).
Handle(randreply(sm.D))
engine.OnMessage(zero.OnlyToMe, canmatch(tKAWA), match(chatListK, &seg)).
SetBlock(false).
Handle(randreply(sm.K))
}()
} }
type simai struct { func canmatch() zero.Rule {
D map[string][]string `yaml:"傲娇"`
K map[string][]string `yaml:"可爱"`
}
const (
tKIMO = iota
tDERE
tKAWA
)
func match(l []string, seg *gse.Segmenter) zero.Rule {
return func(ctx *zero.Ctx) bool {
return ctxext.JiebaSimilarity(0.66, seg, func(ctx *zero.Ctx) string {
return ctx.ExtractPlainText()
}, l...)(ctx)
}
}
func canmatch(typ int64) zero.Rule {
return func(ctx *zero.Ctx) bool { return func(ctx *zero.Ctx) bool {
if zero.HasPicture(ctx) { if zero.HasPicture(ctx) {
return false return false
} }
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) return ctx.ExtractPlainText() != ""
if !ok {
return false
}
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
d := c.GetData(gid)
return ctx.ExtractPlainText() != "" && d&3 == typ
}
}
func randreply(m map[string][]string) zero.Handler {
return func(ctx *zero.Ctx) {
ctx.Block()
key := ctx.State["matched"].(string)
val := m[key]
nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))]
text := val[rand.Intn(len(val))]
text = strings.ReplaceAll(text, "{name}", ctx.CardOrNickName(ctx.Event.UserID))
text = strings.ReplaceAll(text, "{me}", nick)
id := ctx.Event.MessageID
for _, t := range strings.Split(text, "{segment}") {
if t == "" {
continue
}
process.SleepAbout1sTo2s()
id = ctx.SendChain(message.Reply(id), message.Text(t))
}
} }
} }

View File

@ -1,670 +0,0 @@
// Package wenxin 百度文心AI
package wenxin
import (
"errors"
"strconv"
"strings"
"sync"
"time"
fcext "github.com/FloatTech/floatbox/ctxext"
"github.com/FloatTech/floatbox/process"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message"
// 数据库
sql "github.com/FloatTech/sqlite"
// 百度文心大模型
model "github.com/FloatTech/AnimeAPI/wenxinAI/erniemodle"
// 百度文心AI画图API
wenxin "github.com/FloatTech/AnimeAPI/wenxinAI/ernievilg"
)
const (
serviceErr = "[wenxinvilg]ERROR:\n"
modelErr = "[wenxinmodel]ERROR:\n"
)
type keydb struct {
sync.RWMutex
db sql.Sqlite
}
// db内容
type apikey struct {
ID int64 // 群号
APIKey string // API Key
SecretKey string // Secret Key
Token string // AccessToken
Updatetime int64 // token的有效时间
MaxLimit int // 总使用次数
DayLimit int // 当天的使用次数
Lasttime string // 记录使用的时间,用于刷新使用次数
}
var (
name = "椛椛"
limit int
vilginfo keydb
modelinfo keydb
dtype = [...]string{
"古风", "油画", "水彩画", "卡通画", "二次元", "浮世绘", "蒸汽波艺术", "low poly", "像素风格", "概念艺术", "未来主义", "赛博朋克", "写实风格", "洛丽塔风格", "巴洛克风格", "超现实主义",
}
)
func init() { // 插件主体
go func() {
process.GlobalInitMutex.Lock()
defer process.GlobalInitMutex.Unlock()
name = zero.BotConfig.NickName[0]
}()
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "文心AI画图",
Help: "基于百度文心的免费AI画图插件,\n因为是免费的,图片质量你懂的。\n" +
"key申请链接:https://wenxin.baidu.com/moduleApi/key\n" +
"key和erniemodel插件的key相同。\n" +
"注意:每个apikey每日上限50次,总上限500次请求。次数超过了请自行更新apikey\n" +
"- 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]\n" +
"例:\n为自己设置画图key 123 456\n为10086设置画图key 123 456\n为群10010设置画图key 789 101\n" +
"- [bot名称]画几张[图片描述]的[图片类型][图片尺寸]\n" +
"————————————————————\n" +
"图片描述指南:\n图片主体细节词(请用逗号连接)\n官方prompt指南:https://wenxin.baidu.com/wenxin/docs#Ol7ece95m\n" +
"————————————————————\n" +
"图片类型当前支持:" + strings.Join(dtype[:], "、") +
"\n————————————————————\n" +
"图片尺寸当前只支持:方图/长图/横图\n" +
"————————————————————\n" +
"指令示例:\n" +
name + "帮我画几张金凤凰背景绚烂高饱和古风仙境高清4K古风的油画方图",
PrivateDataFolder: "wenxinAI",
}).ApplySingle(single.New(
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Break()
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text(zero.BotConfig.NickName[0], "正在给别人画图,请不要打扰哦"),
),
)
}),
))
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
vilginfo.db = sql.New(engine.DataFolder() + "ernieVilg.db")
err := vilginfo.db.Open(time.Hour)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return false
}
return true
})
// 画图
engine.OnRegex(`画几张(.*[^的$])的(.*[^\s$])(方图|长图|横图)$`, zero.OnlyToMe, getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
uid := -ctx.Event.UserID
gid := ctx.Event.GroupID
// 获取个人和群的key
userinfo, err1 := vilginfo.checkGroup(uid, "vilg")
info, err2 := vilginfo.checkGroup(gid, "vilg")
switch {
// 如果是个人请求且报错
case gid == 0 && err1 != nil:
ctx.SendChain(message.Text(serviceErr, err1))
return
// 如果群报错而个人没有,就切换成个人的
case err2 != nil && err1 == nil:
gid = uid
info = userinfo
// 如果都报错就以群为优先级
case err1 != nil && err2 != nil:
ctx.SendChain(message.Text(serviceErr, err2))
return
}
// 判断使用次数
check := false
switch {
// 群和个人都没有次数了
case info.DayLimit == 0 && userinfo.DayLimit == 0:
ctx.SendChain(message.Text("我已经画了", limit, "张了!我累了!不画不画,就不画!"))
return
// 个人还有次数的话
case info.DayLimit == 0 && userinfo.DayLimit != 0:
check = true
}
switch {
// 群和个人都没有总次数了
case info.MaxLimit == 0 && userinfo.MaxLimit == 0:
ctx.SendChain(message.Text("设置的key使用次数超过了限额请更换key。"))
return
// 个人还有总次数的话
case info.MaxLimit == 0 && userinfo.MaxLimit != 0:
check = true
}
if check { // 如果只有个人有次数就切换回个人key
gid = uid
info = userinfo
}
// 创建任务
keyword := ctx.State["regex_matched"].([]string)[1]
if len([]rune(keyword)) >= 64 { // 描述不能超过64个字
ctx.SendChain(message.Text("要求太多了啦!减少点!"))
return
}
picType := ctx.State["regex_matched"].([]string)[2]
chooseSize := ctx.State["regex_matched"].([]string)[3]
wtime := 3
picSize := "1024*1024"
switch chooseSize {
case "长图":
wtime = 5
picSize = "1024*1536"
case "横图":
wtime = 5
picSize = "1536*1024"
}
taskID, err := wenxin.BuildWork(info.Token, keyword, picType, picSize)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return
}
if taskID < 1 {
ctx.SendChain(message.Text("要求太复杂力!想不出来..."))
return
}
// 开始画图
ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "知道了,我可能需要", time.Duration(wtime*10)*time.Second, "左右才能画好哦,请等待..."))
i := 0
for range time.NewTicker(10 * time.Second).C {
// 等待 wtime * 10秒
i++
if i <= wtime {
continue
}
/*
if i > 60{// 十分钟还不出图就放弃
ctx.SendChain(message.Text("呜呜呜,要求太复杂力!画不出来..."))
return
}
// 获取结果*/
picURL, status, err := wenxin.GetPic(info.Token, taskID)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return
}
if status == "0" {
lastTime := time.Duration(i * 10 * int(time.Second))
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("我画好了!\n本次绘画用了", lastTime))}
for _, imginfo := range picURL {
msg = append(msg,
ctxext.FakeSenderForwardNode(ctx,
message.Image(imginfo.Image)))
}
if id := ctx.Send(msg).ID(); id == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
}
break
}
}
err = vilginfo.update(gid, 1)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
}
process.SleepAbout1sTo2s()
ctx.SendChain(message.Text("累死了,今天我最多只能画", info.DayLimit-1, "张图哦"))
})
engine.OnRegex(`^为(群)?(自己|本群|\d+)设置画图key\s(.*[^\s$])\s(.+)$`, getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
mode := ctx.State["regex_matched"].([]string)[1]
user := ctx.State["regex_matched"].([]string)[2]
aKey := ctx.State["regex_matched"].([]string)[3]
sKey := ctx.State["regex_matched"].([]string)[4]
dbID := -ctx.Event.UserID // 默认给自己
switch {
case mode != "": // 指定群的话
gid, err := strconv.ParseInt(user, 10, 64)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return
}
dbID = gid
case user == "本群": // 用于本群
gid := ctx.Event.GroupID
if gid == 0 {
ctx.SendChain(message.Text(serviceErr, "请指定群聊,或者使用指令;\n为群xxx设置AI画图key xxx xxx"))
return
}
dbID = gid
case user != "自己": // 给别人开key
uid, err := strconv.ParseInt(user, 10, 64)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return
}
dbID = -uid
}
err := vilginfo.insert(dbID, "vilg", aKey, sKey)
if err != nil {
ctx.SendChain(message.Text(serviceErr, err))
return
}
ctx.SendChain(message.Text("成功!"))
})
/*********************************************************/
en := control.Register("wenxinmodel", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "文心AI文本处理",
Help: "基于百度文心AI的API文本处理\n" +
"key申请链接:https://wenxin.baidu.com/moduleApi/key\n" +
"key和ernievilg插件的key相同。\n" +
"注意:每个apikey每日上限200条,总上限2000条。次数超过了请自行更新apikey\n" +
"- 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]\n" +
"例:\n为自己设置文心key 123 456\n为10086设置文心key 123 456\n为群10010设置文心key 789 101\n" +
"————————————————————\n" +
"- 文心作文 (x字的)[作文题目]\n" +
"————————————————————\n" +
"- 文心提案 (x字的)[文案标题]\n" +
"————————————————————\n" +
"- 文心摘要 (x字的)[文章内容]\n" +
"————————————————————\n" +
"- 文心小说 (x字的)[小说上文]\n" +
"————————————————————\n" +
"- 文心对联 [上联]\n" +
"————————————————————\n" +
"- 文心问答 [问题]\n" +
"————————————————————\n" +
"- 文心补全 [带“_”的填空题]\n" +
"————————————————————\n" +
"- 文心自定义 [prompt]\n\n" +
"prompt: [问题描述] [问题类型]:[题目] [解答类型]:[解题必带内容]\n" +
"指令示例:\n" +
"文心自定义 请写出下面这道题的解题过程。\\n题目:养殖场养鸭376只,养鸡的只数比鸭多258只,这个养殖场一共养鸭和鸡多少只?\\n解\n\n" +
"文心自定义 1+1=?\n" +
"文心自定义 歌曲名:大风车转啊转\\n歌词",
}).ApplySingle(single.New(
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Break()
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text(zero.BotConfig.NickName[0], "正在给别人编辑,请不要打扰哦"),
),
)
}),
))
getmodeldb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
modelinfo.db = sql.New(engine.DataFolder() + "ernieModel.db")
err := modelinfo.db.Open(time.Hour)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return false
}
return true
})
en.OnRegex(`^为(群)?(自己|本群|\d+)设置文心key\s(.*[^\s$])\s(.+)$`, getmodeldb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
mode := ctx.State["regex_matched"].([]string)[1]
user := ctx.State["regex_matched"].([]string)[2]
aKey := ctx.State["regex_matched"].([]string)[3]
sKey := ctx.State["regex_matched"].([]string)[4]
dbID := -ctx.Event.UserID // 默认给自己
switch {
case mode != "": // 指定群的话
gid, err := strconv.ParseInt(user, 10, 64)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
dbID = gid
case user == "本群": // 用于本群
gid := ctx.Event.GroupID
if gid == 0 {
ctx.SendChain(message.Text(modelErr, "请指定群聊,或者使用指令;\n为群xxx设置AI画图key xxx xxx"))
return
}
dbID = gid
case user != "自己": // 给别人开key
uid, err := strconv.ParseInt(user, 10, 64)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
dbID = -uid
}
err := modelinfo.insert(dbID, "model", aKey, sKey)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
ctx.SendChain(message.Text("成功!"))
})
var erniemodel = map[string]int{
"作文": 1,
"提案": 2,
"摘要": 3,
"对联": 4,
"问答": 5,
"小说": 6,
"补全": 7,
"自定义": 8}
var erniePrompt = map[string]string{
"作文": "zuowen",
"提案": "adtext",
"摘要": "Summarization",
"对联": "couplet",
"问答": "Dialogue",
"小说": "novel",
"补全": "cloze"}
en.OnRegex(`^文心(作文|提案|摘要|小说)\s?((\d+)字的)?(.*)$`, getmodeldb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
uid := -ctx.Event.UserID
gid := ctx.Event.GroupID
// 获取个人和群的key
userinfo, err1 := modelinfo.checkGroup(uid, "model")
info, err2 := modelinfo.checkGroup(gid, "model")
switch {
// 如果是个人请求且报错
case gid == 0 && err1 != nil:
ctx.SendChain(message.Text(modelErr, err1))
return
// 如果群报错而个人没有,就切换成个人的
case err2 != nil && err1 == nil:
gid = uid
info = userinfo
// 如果都报错就以群为优先级
case err1 != nil && err2 != nil:
ctx.SendChain(message.Text(modelErr, err2))
return
}
// 判断使用次数
check := false
switch {
// 群和个人都没有次数了
case info.DayLimit == 0 && userinfo.DayLimit == 0:
ctx.SendChain(message.Text("今日请求次数已到200次了,明天在玩吧"))
return
// 个人还有次数的话
case info.DayLimit == 0 && userinfo.DayLimit != 0:
check = true
}
switch {
// 群和个人都没有总次数了
case info.MaxLimit == 0 && userinfo.MaxLimit == 0:
ctx.SendChain(message.Text("设置的key使用次数超过了限额,请更换key。"))
return
// 个人还有总次数的话
case info.MaxLimit == 0 && userinfo.MaxLimit != 0:
check = true
}
if check { // 如果只有个人有次数就切换回个人key
gid = uid
info = userinfo
}
// 调用API
modelStr := ctx.State["regex_matched"].([]string)[1]
mun := ctx.State["regex_matched"].([]string)[3]
minlen := 1
maxlen := 128
if mun != "" {
maxNum, err := strconv.Atoi(mun)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
minlen = maxNum
if maxNum > 128 {
maxlen = maxNum
}
}
keyword := ctx.State["regex_matched"].([]string)[4]
if len([]rune(keyword)) >= 1000 { // 描述不能超过1000
ctx.SendChain(message.Text("是你写作文还是我写?减少点!"))
return
}
result, err := model.GetResult(info.Token, erniemodel[modelStr], keyword, minlen, maxlen, erniePrompt[modelStr])
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
if id := ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(keyword, "", result))); id.ID() == 0 {
ctx.SendChain(message.Text("ERROR: 请求超时!"))
}
err = modelinfo.update(gid, 1)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
}
})
en.OnRegex(`^文心(对联|问答|补全|自定义)\s?(.*)$`, getmodeldb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
uid := -ctx.Event.UserID
gid := ctx.Event.GroupID
// 获取个人和群的key
userinfo, err1 := modelinfo.checkGroup(uid, "model")
info, err2 := modelinfo.checkGroup(gid, "model")
switch {
// 如果是个人请求且报错
case gid == 0 && err1 != nil:
ctx.SendChain(message.Text(modelErr, err1))
return
// 如果群报错而个人没有,就切换成个人的
case err2 != nil && err1 == nil:
gid = uid
info = userinfo
// 如果都报错就以群为优先级
case err1 != nil && err2 != nil:
ctx.SendChain(message.Text(modelErr, err2))
return
}
// 判断使用次数
check := false
switch {
// 群和个人都没有次数了
case info.DayLimit == 0 && userinfo.DayLimit == 0:
ctx.SendChain(message.Text("今日请求次数已到200次了,明天在玩吧"))
return
// 个人还有次数的话
case info.DayLimit == 0 && userinfo.DayLimit != 0:
check = true
}
switch {
// 群和个人都没有总次数了
case info.MaxLimit == 0 && userinfo.MaxLimit == 0:
ctx.SendChain(message.Text("设置的key使用次数超过了限额,请更换key。"))
return
// 个人还有总次数的话
case info.MaxLimit == 0 && userinfo.MaxLimit != 0:
check = true
}
if check { // 如果只有个人有次数就切换回个人key
gid = uid
info = userinfo
}
// 创建任务
modelStr := ctx.State["regex_matched"].([]string)[1]
keyword := ctx.State["regex_matched"].([]string)[2]
if len([]rune(keyword)) >= 1000 { // 描述不能超过1000
ctx.SendChain(message.Text("你在写作文吗?减少点!"))
return
}
result, err := model.GetResult(info.Token, erniemodel[modelStr], keyword, 1, 128, erniePrompt[modelStr])
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
return
}
if id := ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(result))); id.ID() == 0 {
ctx.SendChain(message.Text("ERROR: 请求超时!"))
}
err = modelinfo.update(gid, 1)
if err != nil {
ctx.SendChain(message.Text(modelErr, err))
}
})
}
// 登记group的key
func (sql *keydb) insert(gid int64, model, akey, skey string) error {
sql.Lock()
defer sql.Unlock()
// 给db文件创建表格(没有才创建)表格名称groupinfo表格结构apikey
err := sql.db.Create("groupinfo", &apikey{})
if err != nil {
return err
}
// 获取group信息
groupinfo := apikey{} // 用于暂存数据
err = sql.db.Find("groupinfo", &groupinfo, "WHERE ID = ?", gid)
if err != nil {
// 如果该group没有注册过
err = sql.db.Find("groupinfo", &groupinfo, "WHERE APIKey = ? and SecretKey = ?", akey, skey)
if err == nil {
// 如果key存在过将当前的数据迁移过去
groupinfo.ID = gid
} else {
groupinfo = apikey{
ID: gid,
APIKey: akey,
SecretKey: skey,
}
switch model {
case "vilg":
groupinfo.MaxLimit = 500
case "model":
groupinfo.MaxLimit = 2000
}
}
return sql.db.Insert("groupinfo", &groupinfo)
}
// 进行更新
groupinfo.APIKey = akey
groupinfo.SecretKey = skey
groupinfo.Token = ""
groupinfo.Updatetime = 0
switch model {
case "vilg":
groupinfo.MaxLimit = 500
case "model":
groupinfo.MaxLimit = 2000
}
return sql.db.Insert("groupinfo", &groupinfo)
}
// 获取group信息
func (sql *keydb) checkGroup(gid int64, model string) (groupinfo apikey, err error) {
sql.Lock()
defer sql.Unlock()
// 给db文件创建表格(没有才创建)表格名称groupinfo表格结构apikey
err = sql.db.Create("groupinfo", &apikey{})
if err != nil {
return
}
switch model {
case "vilg":
limit = 50
model = "画图"
case "model":
limit = 200
model = "文心"
}
// 先判断该群是否已经设置过key了
if ok := sql.db.CanFind("groupinfo", "WHERE ID = ?", gid); !ok {
if gid > 0 {
err = errors.New("该群没有设置过apikey请前往https://wenxin.baidu.com/moduleApi/key获取key值后发送指令:\n为本群设置" + model + "key [API Key] [Secret Key]\n或\n为自己设置" + model + "key [API Key] [Secret Key]")
} else {
err = errors.New("你没有设置过apikey请前往https://wenxin.baidu.com/moduleApi/key获取key值后发送指令:\n为自己设置" + model + "key [API Key] [Secret Key]")
}
return
}
// 获取group信息
err = sql.db.Find("groupinfo", &groupinfo, "WHERE ID = ?", gid)
if err != nil {
return
}
// 如果隔天使用刷新次数
if time.Now().Format("2006/01/02") != groupinfo.Lasttime {
groupinfo.DayLimit = limit
groupinfo.Lasttime = time.Now().Format("2006/01/02")
}
if err = sql.db.Insert("groupinfo", &groupinfo); err != nil {
return
}
// 如果token有效期过期
if time.Since(time.Unix(groupinfo.Updatetime, 0)).Hours() > 24 || groupinfo.Token == "" {
token, err1 := wenxin.GetToken(groupinfo.APIKey, groupinfo.SecretKey)
if err1 != nil {
err = err1
return
}
groupinfo.Token = token
groupinfo.Updatetime = time.Now().Unix()
err = sql.db.Insert("groupinfo", &groupinfo)
if err == nil {
// 更新相同key的他人次数
otherinfo := apikey{}
var groups []int64 // 将相同的key的ID暂存
// 无视没有找到相同的key的err
_ = sql.db.FindFor("groupinfo", &otherinfo, "WHERE ID <> ? AND APIKey = ? AND SecretKey = ?", func() error {
groups = append(groups, otherinfo.ID)
return nil
}, gid, groupinfo.APIKey, groupinfo.SecretKey)
if len(groups) != 0 { // 如果有相同的key就更新
for _, group := range groups {
err = sql.db.Find("groupinfo", &otherinfo, "WHERE ID = ?", group)
if err == nil {
otherinfo.Token = groupinfo.Token
otherinfo.Updatetime = groupinfo.Updatetime
err = sql.db.Insert("groupinfo", &otherinfo)
}
}
}
}
}
return
}
// 记录次数(-sub)
func (sql *keydb) update(gid int64, sub int) error {
sql.Lock()
defer sql.Unlock()
// 给db文件创建表格(没有才创建)表格名称groupinfo表格结构apikey
err := sql.db.Create("groupinfo", &apikey{})
if err != nil {
return err
}
groupinfo := apikey{} // 用于暂存数据
// 获取group信息
err = sql.db.Find("groupinfo", &groupinfo, "WHERE ID = ?", gid)
if err != nil {
return err
}
groupinfo.MaxLimit -= sub
groupinfo.DayLimit -= sub
err = sql.db.Insert("groupinfo", &groupinfo)
if err != nil {
return err
}
// 更新相同key的他人次数
otherinfo := apikey{}
var groups []int64 // 将相同的key的ID暂存
// 无视没有找到相同的key的err
_ = sql.db.FindFor("groupinfo", &otherinfo, "WHERE ID <> ? AND APIKey = ? AND SecretKey = ?", func() error {
groups = append(groups, otherinfo.ID)
return nil
}, gid, groupinfo.APIKey, groupinfo.SecretKey)
if len(groups) != 0 { // 如果有相同的key就更新
for _, group := range groups {
err = sql.db.Find("groupinfo", &otherinfo, "WHERE ID = ?", group)
if err == nil {
otherinfo.MaxLimit = groupinfo.MaxLimit
otherinfo.DayLimit = groupinfo.DayLimit
otherinfo.Lasttime = groupinfo.Lasttime
err = sql.db.Insert("groupinfo", &otherinfo)
}
}
}
return err
}

View File

@ -3,8 +3,9 @@ package wife
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"strings" "regexp"
fcext "github.com/FloatTech/floatbox/ctxext" fcext "github.com/FloatTech/floatbox/ctxext"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
@ -15,16 +16,16 @@ import (
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
func init() { var (
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ cards = []string{}
re = regexp.MustCompile(`^\[(.*?)\](.*)\..*$`)
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Help: "- 抽老婆", Help: "- 抽老婆",
Brief: "从老婆库抽每日老婆", Brief: "从老婆库抽每日老婆",
PublicDataFolder: "Wife", PublicDataFolder: "Wife",
}).ApplySingle(ctxext.DefaultSingle) }).ApplySingle(ctxext.DefaultSingle)
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755) getJSON = fcext.DoOnceOnSuccess(
cards := []string{}
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
func(ctx *zero.Ctx) bool { func(ctx *zero.Ctx) bool {
data, err := engine.GetLazyData("wife.json", true) data, err := engine.GetLazyData("wife.json", true)
if err != nil { if err != nil {
@ -39,26 +40,45 @@ func init() {
logrus.Infof("[wife]加载%d个老婆", len(cards)) logrus.Infof("[wife]加载%d个老婆", len(cards))
return true return true
}, },
)).SetBlock(true). )
)
func card2name(card string) (string, string) {
match := re.FindStringSubmatch(card)
if len(match) >= 3 {
return match[1], match[2]
}
return "", ""
}
func init() {
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
engine.OnFullMatch("抽老婆", getJSON).SetBlock(true).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))] card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
data, err := engine.GetLazyData("wives/"+card, true) data, err := engine.GetLazyData("wives/"+card, true)
card, _, _ = strings.Cut(card, ".") var msgText string
work, name := card2name(card)
if work != "" && name != "" {
msgText = fmt.Sprintf("今天的二次元老婆是~来自【%s】的【%s】哒", work, name)
} else {
msgText = fmt.Sprintf("今天的二次元老婆是~【%s】哒", card)
}
if err != nil { if err != nil {
ctx.SendChain( ctx.SendChain(
message.At(ctx.Event.UserID), message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"), message.Text(msgText, "\n【图片下载失败: ", err, "】"),
) )
return return
} }
if id := ctx.SendChain( if id := ctx.SendChain(
message.At(ctx.Event.UserID), message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒"), message.Text(msgText),
message.ImageBytes(data), message.ImageBytes(data),
); id.ID() == 0 { ); id.ID() == 0 {
ctx.SendChain( ctx.SendChain(
message.At(ctx.Event.UserID), message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"), message.Text(msgText, "\n【图片发送失败, 多半是被夹了,请联系维护者】"),
) )
} }
}) })

157
plugin/wife/wifegame.go Normal file
View File

@ -0,0 +1,157 @@
// Package wife 抽老婆
package wife
import (
"bytes"
"image"
"image/color"
"math/rand"
"strings"
"time"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
zbmath "github.com/FloatTech/floatbox/math"
"github.com/FloatTech/imgfactory"
)
var (
sizeList = []int{0, 3, 5, 8}
enguess = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Help: "- 猜老婆",
Brief: "从老婆库猜老婆",
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
)
func init() {
enguess.OnFullMatch("猜老婆", getJSON).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
class := 3
card := cards[rand.Intn(len(cards))]
pic, err := engine.GetLazyData("wives/"+card, true)
if err != nil {
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
return
}
work, name := card2name(card)
name = strings.ToLower(name)
img, _, err := image.Decode(bytes.NewReader(pic))
if err != nil {
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
return
}
dst := imgfactory.Size(img, img.Bounds().Dx(), img.Bounds().Dy())
q, err := mosaic(dst, class)
if err != nil {
ctx.SendChain(
message.Reply(ctx.Event.MessageID),
message.Text("[猜老婆]图片生成失败:\n", err),
)
return
}
if id := ctx.SendChain(
message.ImageBytes(q),
); id.ID() != 0 {
ctx.SendChain(message.Text("请回答该二次元角色名字\n以“xxx酱”格式回答\n发送“跳过”结束猜题"))
}
var next *zero.FutureEvent
if ctx.Event.GroupID == 0 {
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(·)?[^酱]+酱|^跳过$`), ctx.CheckSession())
} else {
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(·)?[^酱]+酱|^跳过$`), zero.CheckGroup(ctx.Event.GroupID))
}
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.ImageBytes(pic),
message.Text("[猜老婆]倒计时结束,游戏结束...\n角色是:\n", name, "\n出自《", work, "》\n"),
),
)
return
case c := <-recv:
// tick.Reset(105 * time.Second)
// after.Reset(120 * time.Second)
msg := strings.ReplaceAll(c.Event.Message.String(), "酱", "")
if msg == "" {
continue
}
if msg == "跳过" {
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
message.Text("已跳过猜题\n角色是:\n", name, "\n出自《", work, "》\n"),
message.ImageBytes(pic))); msgID.ID() == 0 {
ctx.SendChain(message.Text("太棒了,你猜对了!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
}
return
}
class--
if strings.Contains(name, strings.ToLower(msg)) {
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
message.Text("太棒了,你猜对了!\n角色是:\n", name, "\n出自《", work, "》\n"),
message.ImageBytes(pic))); msgID.ID() == 0 {
ctx.SendChain(message.Text("太棒了,你猜对了!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
}
return
}
if class < 1 {
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
message.Text("很遗憾,次数到了,游戏结束!\n角色是:\n", name, "\n出自《", work, "》\n"),
message.ImageBytes(pic))); msgID.ID() == 0 {
ctx.SendChain(message.Text("很遗憾,次数到了,游戏结束!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
}
return
}
q, err = mosaic(dst, class)
if err != nil {
ctx.SendChain(
message.Text("回答错误,你还有", class, "次机会\n请继续作答\n(提示:", work, ")"),
)
continue
}
msg = ""
if class == 2 {
msg = "(提示:" + work + ")\n"
}
ctx.SendChain(
message.Text("回答错误,你还有", class, "次机会\n", msg, "请继续作答(难度降低)\n"),
message.ImageBytes(q),
)
continue
}
}
})
}
// 马赛克生成
func mosaic(dst *imgfactory.Factory, level int) ([]byte, error) {
b := dst.Image().Bounds()
p := imgfactory.NewFactoryBG(dst.W(), dst.H(), color.NRGBA{255, 255, 255, 255})
markSize := zbmath.Max(b.Max.X, b.Max.Y) * sizeList[level] / 200
for yOfMarknum := 0; yOfMarknum <= zbmath.Ceil(b.Max.Y, markSize); yOfMarknum++ {
for xOfMarknum := 0; xOfMarknum <= zbmath.Ceil(b.Max.X, markSize); xOfMarknum++ {
a := dst.Image().At(xOfMarknum*markSize+markSize/2, yOfMarknum*markSize+markSize/2)
cc := color.NRGBAModel.Convert(a).(color.NRGBA)
for y := 0; y < markSize; y++ {
for x := 0; x < markSize; x++ {
xOfPic := xOfMarknum*markSize + x
yOfPic := yOfMarknum*markSize + y
p.Image().Set(xOfPic, yOfPic, cc)
}
}
}
}
return imgfactory.ToBytes(p.Blur(3).Image())
}

View File

@ -2,16 +2,16 @@
package wordcount package wordcount
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/go-ego/gse" "github.com/fumiama/jieba"
"github.com/golang/freetype" "github.com/golang/freetype"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@ -27,31 +27,32 @@ import (
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
"github.com/wdvxdr1123/ZeroBot/utils/helper"
) )
var ( var (
re = regexp.MustCompile(`^[一-龥]+$`) re = regexp.MustCompile(`^[一-龥]+$`)
stopwords []string stopwords []string
seg gse.Segmenter
) )
func init() { func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "聊天热词", Brief: "聊天热词",
Help: "- 热词 [群号] [消息数目]|热词 123456 1000", Help: "- 热词 [消息数目]|热词 1000",
PublicDataFolder: "WordCount", PublicDataFolder: "WordCount",
}) })
cachePath := engine.DataFolder() + "cache/" cachePath := engine.DataFolder() + "cache/"
// 读取gse内置中文词典 dat, err := file.GetLazyData("data/Chat/dict.txt", control.Md5File, true)
err := seg.LoadDictEmbed() if err != nil {
panic(err)
}
seg, err := jieba.LoadDictionary(bytes.NewReader(dat))
if err != nil { if err != nil {
panic(err) panic(err)
} }
_ = os.RemoveAll(cachePath) _ = os.RemoveAll(cachePath)
_ = os.MkdirAll(cachePath, 0755) _ = os.MkdirAll(cachePath, 0755)
engine.OnRegex(`^热词\s?(\d*)\s?(\d*)$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { engine.OnRegex(`^热词\s?(\d*)$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
_, err := engine.GetLazyData("stopwords.txt", false) _, err := engine.GetLazyData("stopwords.txt", false)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR: ", err)) ctx.SendChain(message.Text("ERROR: ", err))
@ -85,17 +86,14 @@ func init() {
} }
ctx.SendChain(message.Text("少女祈祷中...")) ctx.SendChain(message.Text("少女祈祷中..."))
gid, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64)
if p > 10000 { if p > 10000 {
p = 10000 p = 10000
} }
if p == 0 { if p == 0 {
p = 1000 p = 1000
} }
if gid == 0 { gid := ctx.Event.GroupID
gid = ctx.Event.GroupID
}
group := ctx.GetGroupInfo(gid, false) group := ctx.GetGroupInfo(gid, false)
if group.MemberCount == 0 { if group.MemberCount == 0 {
ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获得热词呢")) ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获得热词呢"))
@ -108,44 +106,21 @@ func init() {
return return
} }
messageMap := make(map[string]int, 256) messageMap := make(map[string]int, 256)
msghists := make(chan *gjson.Result, 256) h := ctx.GetGroupMessageHistory(gid, 0, p, false)
go func() { h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool {
h := ctx.GetLatestGroupMessageHistory(gid) tex := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText())
messageSeq := h.Get("messages.0.message_seq").Int() if tex != "" {
msghists <- &h words := seg.Cut(tex, true)
for i := 1; i < int(p/20) && messageSeq != 0; i++ {
h := ctx.GetGroupMessageHistory(gid, messageSeq)
msghists <- &h
messageSeq = h.Get("messages.0.message_seq").Int()
}
close(msghists)
}()
var wg sync.WaitGroup
var mapmu sync.Mutex
for h := range msghists {
wg.Add(1)
go func(h *gjson.Result) {
for _, v := range h.Get("messages.#.message").Array() {
tex := strings.TrimSpace(message.ParseMessageFromString(v.Str).ExtractPlainText())
if tex == "" {
continue
}
segments := seg.Segment(helper.StringToBytes(tex))
words := gse.ToSlice(segments, true)
for _, word := range words { for _, word := range words {
word = strings.TrimSpace(word) word = strings.TrimSpace(word)
i := sort.SearchStrings(stopwords, word) i := sort.SearchStrings(stopwords, word)
if re.MatchString(word) && (i >= len(stopwords) || stopwords[i] != word) { if re.MatchString(word) && (i >= len(stopwords) || stopwords[i] != word) {
mapmu.Lock()
messageMap[word]++ messageMap[word]++
mapmu.Unlock()
} }
} }
} }
wg.Done() return true
}(h) })
}
wg.Wait()
wc := rankByWordCount(messageMap) wc := rankByWordCount(messageMap)
if len(wc) > 20 { if len(wc) > 20 {

View File

@ -22,7 +22,6 @@ import (
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext" "github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
@ -69,16 +68,7 @@ func init() {
"- 团队六阶猜单词\n" + "- 团队六阶猜单词\n" +
"- 团队七阶猜单词", "- 团队七阶猜单词",
PublicDataFolder: "Wordle", PublicDataFolder: "Wordle",
}).ApplySingle(single.New( }).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("已经有正在进行的游戏..."),
),
)
}),
))
en.OnRegex(`^(个人|团队)(五阶|六阶|七阶)?猜单词$`, zero.OnlyGroup, fcext.DoOnceOnSuccess( en.OnRegex(`^(个人|团队)(五阶|六阶|七阶)?猜单词$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(
func(ctx *zero.Ctx) bool { func(ctx *zero.Ctx) bool {

View File

@ -1,14 +1,13 @@
// Package ygo 一些关于ygo的插件 // Package ygocdb 游戏王卡查插件
package ygo package ygocdb
import ( import (
"encoding/json"
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"encoding/json"
"github.com/FloatTech/floatbox/web" "github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
control "github.com/FloatTech/zbputils/control" control "github.com/FloatTech/zbputils/control"
@ -39,7 +38,7 @@ type searchResult struct {
} }
func init() { func init() {
en := control.Register("ygocdb", &ctrl.Options[*zero.Ctx]{ en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "游戏王百鸽API", // 本插件基于游戏王百鸽API"https://www.ygo-sem.cn/" Brief: "游戏王百鸽API", // 本插件基于游戏王百鸽API"https://www.ygo-sem.cn/"
Help: "- /ydp [xxx]\n" + Help: "- /ydp [xxx]\n" +

View File

@ -1,5 +1,5 @@
// Package ygo 一些关于ygo的插件 // Package ygotrade 游戏王卡价查询插件
package ygo package ygotrade
import ( import (
"encoding/json" "encoding/json"
@ -46,7 +46,7 @@ type tradeInfo struct {
} }
func init() { func init() {
engine := control.Register("ygotrade", &ctrl.Options[*zero.Ctx]{ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Brief: "游戏王卡价查询", // 本插件基于集换社API Brief: "游戏王卡价查询", // 本插件基于集换社API
Help: "- 查卡价 [卡名]\n- 查卡价 [卡名] -r [稀有度 稀有度 ...]\n- 查卡店 [卡名]\n- 查卡店 [卡名] -r [稀有度]", Help: "- 查卡价 [卡名]\n- 查卡价 [卡名] -r [稀有度 稀有度 ...]\n- 查卡店 [卡名]\n- 查卡店 [卡名] -r [稀有度]",

View File

@ -72,7 +72,7 @@ func init() {
func sendYmgal(y ymgal, ctx *zero.Ctx) { func sendYmgal(y ymgal, ctx *zero.Ctx) {
if y.PictureList == "" { if y.PictureList == "" {
ctx.SendChain(message.Text(zero.BotConfig.NickName[0] + "暂时没有这样的图呢")) ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "暂时没有这样的图呢"))
return return
} }
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text(y.Title))} m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text(y.Title))}

View File

@ -3,5 +3,6 @@ go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=auto go env -w GO111MODULE=auto
go mod tidy go mod tidy
::go build -ldflags="-s -w" -o ZeroBot-Plugin.exe ::go build -ldflags="-s -w" -o ZeroBot-Plugin.exe
go run main.go go generate main.go
go run -ldflags "-s -w" main.go
pause pause

3
run.sh
View File

@ -3,4 +3,5 @@ go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=auto go env -w GO111MODULE=auto
go mod tidy go mod tidy
#go build -ldflags="-s -w" -o ZeroBot-Plugin #go build -ldflags="-s -w" -o ZeroBot-Plugin
go run main.go go generate main.go
go run -ldflags "-s -w" main.go

View File

@ -12,7 +12,7 @@
"0409": { "0409": {
"identity": { "identity": {
"name": "ZeroBot-Plugin", "name": "ZeroBot-Plugin",
"version": "1.9.8.2223" "version": "1.10.0.2279"
}, },
"description": "", "description": "",
"minimum-os": "vista", "minimum-os": "vista",
@ -36,23 +36,23 @@
"#1": { "#1": {
"0000": { "0000": {
"fixed": { "fixed": {
"file_version": "1.9.8.2223", "file_version": "1.10.0.2279",
"product_version": "v1.9.8", "product_version": "v1.10.0",
"timestamp": "2025-06-01T18:52:57+08:00" "timestamp": "2025-09-30T23:54:09+08:00"
}, },
"info": { "info": {
"0409": { "0409": {
"Comments": "OneBot plugins based on ZeroBot", "Comments": "OneBot plugins based on ZeroBot",
"CompanyName": "FloatTech", "CompanyName": "FloatTech",
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin", "FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
"FileVersion": "1.9.8.2223", "FileVersion": "1.10.0.2279",
"InternalName": "", "InternalName": "",
"LegalCopyright": "© 2020 - 2025 FloatTech. All Rights Reserved.", "LegalCopyright": "© 2020 - 2025 FloatTech. All Rights Reserved.",
"LegalTrademarks": "", "LegalTrademarks": "",
"OriginalFilename": "ZBP.EXE", "OriginalFilename": "ZBP.EXE",
"PrivateBuild": "", "PrivateBuild": "",
"ProductName": "ZeroBot-Plugin", "ProductName": "ZeroBot-Plugin",
"ProductVersion": "v1.9.8", "ProductVersion": "v1.10.0",
"SpecialBuild": "" "SpecialBuild": ""
} }
} }