mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-08 16:10:25 +00:00
Compare commits
80 Commits
v1.7.0-bet
...
v1.7.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0357405cdf | ||
|
|
7f264964c2 | ||
|
|
c8dcdbb0b2 | ||
|
|
ebcd3cdef2 | ||
|
|
eb43f84d34 | ||
|
|
5931e03c00 | ||
|
|
aaf659f6d4 | ||
|
|
f4add826ff | ||
|
|
0d8157e2f8 | ||
|
|
283667cfe5 | ||
|
|
6403614fa8 | ||
|
|
bdcb833217 | ||
|
|
278d7e0cf9 | ||
|
|
821f8d4949 | ||
|
|
436838d2f8 | ||
|
|
30301f1aba | ||
|
|
df1d71b9b2 | ||
|
|
0315718ab7 | ||
|
|
971c179227 | ||
|
|
1c0270fda0 | ||
|
|
5463945b6c | ||
|
|
8eb058fb26 | ||
|
|
33e5b0286f | ||
|
|
296fd60cd7 | ||
|
|
667c9fbcca | ||
|
|
3d8d0ad107 | ||
|
|
f35a89e401 | ||
|
|
c5c63d0b64 | ||
|
|
3e15754031 | ||
|
|
c1e37b293c | ||
|
|
8edc3f6de6 | ||
|
|
416cb3f2b8 | ||
|
|
8050f12d51 | ||
|
|
292fc311d6 | ||
|
|
28cb0491f7 | ||
|
|
1bad611018 | ||
|
|
d49224fd50 | ||
|
|
2324837052 | ||
|
|
35f8458d67 | ||
|
|
8a6b7f65c7 | ||
|
|
7b1d2b7eaa | ||
|
|
7ced79c6bb | ||
|
|
e224bf9252 | ||
|
|
2b1caafa16 | ||
|
|
c1702c5d5e | ||
|
|
5c8ead8b1d | ||
|
|
635eb9832a | ||
|
|
f1e49dc02e | ||
|
|
573c942a9d | ||
|
|
e8b61b39f0 | ||
|
|
ed26d31326 | ||
|
|
76dbf5a4b6 | ||
|
|
f1ea658c7d | ||
|
|
2964986ee5 | ||
|
|
52ef28cd6a | ||
|
|
df4c0438a2 | ||
|
|
864f92a728 | ||
|
|
6ea50cf8b7 | ||
|
|
d66dd9b7fa | ||
|
|
4a15326977 | ||
|
|
b4a1f93993 | ||
|
|
0c8dfb3f9c | ||
|
|
1aa11879dc | ||
|
|
14c596be1f | ||
|
|
309afecadd | ||
|
|
f465e78460 | ||
|
|
aa5c324592 | ||
|
|
1a0575af64 | ||
|
|
587d3967ef | ||
|
|
d693f988bb | ||
|
|
500dcaa9ed | ||
|
|
1376803b07 | ||
|
|
68386910c4 | ||
|
|
1734f1f7d4 | ||
|
|
86b87c2b4e | ||
|
|
e9eb4c5602 | ||
|
|
6474b36ccd | ||
|
|
107149892c | ||
|
|
f1dba97922 | ||
|
|
bc3c4303be |
@@ -18,7 +18,7 @@ linters:
|
||||
fast: false
|
||||
enable:
|
||||
- bodyclose
|
||||
- depguard
|
||||
#- depguard
|
||||
- dogsled
|
||||
- errcheck
|
||||
- exportloopref
|
||||
|
||||
141
README.md
141
README.md
@@ -17,7 +17,7 @@
|
||||
|
||||
[](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
|
||||
[](https://t.me/zerobotplugin)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
[](https://raw.githubusercontent.com/FloatTech/ZeroBot-Plugin/master/LICENSE)
|
||||
[](https://jq.qq.com/?_wv=1027&k=QMb7x1mM)
|
||||
[](https://t.me/zerobotplugin)
|
||||
@@ -42,9 +42,10 @@
|
||||
## 命令行参数
|
||||
> `[]`代表是可选参数
|
||||
```bash
|
||||
zerobot [-h] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
```
|
||||
- **-h**: 显示帮助
|
||||
- **-m**: 不自动标记消息为已读
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-t token**: 设置`AccessToken`,默认为空
|
||||
- **-u url**: 设置`Url`,默认为`ws://127.0.0.1:6700`
|
||||
@@ -62,27 +63,17 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s
|
||||
默认配置文件格式如下。当选择从配置文件加载时,将忽略相应命令行参数。
|
||||
```json
|
||||
{
|
||||
"zero": {
|
||||
"nickname": [
|
||||
"椛椛",
|
||||
"ATRI",
|
||||
"atri",
|
||||
"亚托莉",
|
||||
"アトリ"
|
||||
],
|
||||
"command_prefix": "/",
|
||||
"super_users": [],
|
||||
"ring_len": 4096,
|
||||
"latency": 233000000,
|
||||
"max_process_time": 240000000000
|
||||
},
|
||||
"ws": [
|
||||
{
|
||||
"Url": "ws://127.0.0.1:6700",
|
||||
"AccessToken": ""
|
||||
}
|
||||
],
|
||||
"wss": null
|
||||
"zero": {
|
||||
"nickname": ["椛椛", "ATRI", "atri", "亚托莉", "アトリ"],
|
||||
"command_prefix": "/",
|
||||
"super_users": [],
|
||||
"ring_len": 4096,
|
||||
"latency": 233000000,
|
||||
"max_process_time": 240000000000,
|
||||
"mark_message": true
|
||||
},
|
||||
"ws": [{ "Url": "ws://127.0.0.1:6700", "AccessToken": "" }],
|
||||
"wss": null
|
||||
}
|
||||
```
|
||||
|
||||
@@ -436,11 +427,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度一下</summary>
|
||||
<summary>百科</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu"`
|
||||
|
||||
- [x] 百度下[xxx]
|
||||
- [x] 百度/百科/维基/wiki[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -559,7 +550,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] b站推送列表
|
||||
|
||||
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 10s"触发的指令)
|
||||
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 5m"触发的指令)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -571,14 +562,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 随机书评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>打断复读</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat"`
|
||||
|
||||
- [x] (打断三次以上的复读)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>藏头诗</summary>
|
||||
@@ -659,6 +642,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 教你一篇小作文[作文]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>程序员做饭指南</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/dish"`
|
||||
|
||||
- [x] 怎么做 | 烹饪[菜名]
|
||||
|
||||
- [x] 随机菜谱 | 随便做点菜
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>多功能抽签</summary>
|
||||
@@ -727,7 +720,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/font"`
|
||||
|
||||
- [x] (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体])渲染文字xxx
|
||||
- [x] (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|粗苹方体|未来荧黑体|Gugi体|八丸体|Impact体|猫啃体|苹方体])渲染(抖动)文字xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>每日运势</summary>
|
||||
@@ -1247,6 +1241,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 签到
|
||||
- [x] 获得签到背景[@xxx] | 获得签到背景
|
||||
- [x] 设置签到预设(0~3)
|
||||
- [x] 查看等级排名
|
||||
- 注:跨群排行
|
||||
- [x] 查看我的钱包
|
||||
@@ -1279,10 +1274,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 卖萌[@xxx]
|
||||
|
||||
- [x] 抽老婆[@xxx]
|
||||
- [x] 今日老婆[@xxx]
|
||||
|
||||
- [x] 黄油角色[@xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>steam</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/steam"`
|
||||
|
||||
- [x] steam[添加|删除]订阅xxxxx
|
||||
|
||||
- [x] steam查询订阅
|
||||
|
||||
- [x] steam绑定 api key xxxxxxx
|
||||
|
||||
- [x] 查看apikey
|
||||
|
||||
- [x] 拉取steam订阅 (使用job执行定时任务------记录在"@every 1m"触发的指令)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>抽塔罗牌</summary>
|
||||
@@ -1366,7 +1377,17 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 来份网易云热评
|
||||
|
||||
</details>
|
||||
</details>
|
||||
<details>
|
||||
<summary>据意查句</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes"`
|
||||
|
||||
- [x] 据意查句 大海
|
||||
|
||||
- [x] 登录据意查句
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>星际战甲</summary>
|
||||
|
||||
@@ -1443,19 +1464,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>月幕galgame图</summary>
|
||||
<summary>抽老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife"`
|
||||
|
||||
- [x] 随机galCG
|
||||
|
||||
- [x] 随机gal表情包
|
||||
|
||||
- [x] galCG[xxx]
|
||||
|
||||
- [x] gal表情包[xxx]
|
||||
|
||||
- [x] 更新gal
|
||||
- [x] 抽老婆
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1504,14 +1517,19 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>词典匹配回复</summary>
|
||||
<summary>月幕galgame图</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal"`
|
||||
|
||||
- [x] 切换[kimo|傲娇|可爱]词库
|
||||
- [x] 设置词库触发概率0.x (0<x<9)
|
||||
- [x] 随机galCG
|
||||
|
||||
- 注:由于占用资源较大,默认注释。
|
||||
- [x] 随机gal表情包
|
||||
|
||||
- [x] galCG[xxx]
|
||||
|
||||
- [x] gal表情包[xxx]
|
||||
|
||||
- [x] 更新gal
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1550,6 +1568,23 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 设置 ChatGPT api key xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>词典匹配回复</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||
|
||||
- [x] 切换[kimo|傲娇|可爱]词库
|
||||
- [x] 设置词库触发概率0.x (0<x<9)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>打断复读</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat"`
|
||||
|
||||
- [x] (打断三次以上的复读)
|
||||
|
||||
</details>
|
||||
|
||||
## 三种使用方法,推荐第一种
|
||||
|
||||
@@ -79,7 +79,7 @@ func init() {
|
||||
logrus.Warnln("VT100设置失败, 将以无色模式输出")
|
||||
}
|
||||
|
||||
err = setConsoleTitle("ZeroBot-Blugin " + banner.Version + " " + banner.Copyright)
|
||||
err = setConsoleTitle("ZeroBot-Plugin " + banner.Version + " " + banner.Copyright)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
2
data
2
data
Submodule data updated: b9848c9a4e...9cab8a7bae
16
go.mod
16
go.mod
@@ -4,15 +4,15 @@ go 1.20
|
||||
|
||||
require (
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230316111643-46d40c9d80e3
|
||||
github.com/FloatTech/floatbox v0.0.0-20230316111222-7ffde57284cc
|
||||
github.com/FloatTech/gg v1.1.2
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230315152233-49741fc994f9
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230724165034-a3cf504fab92
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9
|
||||
github.com/FloatTech/sqlite v1.5.7
|
||||
github.com/FloatTech/sqlite v1.6.2
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230316111555-2d1ec958de04
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230514154630-b74e6fcca380
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230728081122-94d4d957f3bf
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
@@ -37,7 +37,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.4
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25
|
||||
golang.org/x/image v0.3.0
|
||||
golang.org/x/sys v0.4.0
|
||||
|
||||
32
go.sum
32
go.sum
@@ -2,24 +2,24 @@ github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhv
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230316111643-46d40c9d80e3 h1:SyXS1YXrRuzO3YVCZB/5gSX7vaFbSMwzN+RXLNNKq5M=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230316111643-46d40c9d80e3/go.mod h1:h+22XrJTgcn0m4aM3o1pYo5G0+Mv4v7wW5xvZQ4LabY=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230316111222-7ffde57284cc h1:1yentlIEJImE0rla5xE7o73ZW37eS/byFhPEwx9WYEs=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230316111222-7ffde57284cc/go.mod h1:FwQm6wk+b4wuW54KCKn3zccMX47Q5apnHD/Yakzv0fI=
|
||||
github.com/FloatTech/gg v1.1.2 h1:YolgOYg3uDHc1+g0bLtt6QuRA/pvLn+b9IBCIhOOX88=
|
||||
github.com/FloatTech/gg v1.1.2/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI=
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230315152233-49741fc994f9 h1:IzZLuM/fgKclyMaU/Qb1qlLdGrs2FTietkqOWhh07Gw=
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230315152233-49741fc994f9/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230724165034-a3cf504fab92 h1:B4IaLEhnXdr7oqszneri6ykdHggL2GvPUueBB5WxYVQ=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230724165034-a3cf504fab92/go.mod h1:fWJ5hx1ggDmLyLldO53Go97zc1JpWnDpsC5qeTOcaVw=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944 h1:/eQoMa6Aj3coF5F7yhzZe1+SzX6SItul7MW8//pl18o=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944/go.mod h1:FwQm6wk+b4wuW54KCKn3zccMX47Q5apnHD/Yakzv0fI=
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08 h1:dPLeoiTVSBlgls+66EB/UJ2e38BaASmBN5nANaycSBU=
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI=
|
||||
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/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 h1:hffajvmQFfP68U6wUwHemPuuwCUoss+SEFfoLYwbGwE=
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9/go.mod h1:NBFPhWae4hqVMeG8ELBBnUQkKce3nDjkljVn6PdiUNs=
|
||||
github.com/FloatTech/sqlite v1.5.7 h1:Bvo4LSojcZ6dVtbHrkqvt6z4v8e+sj0G5PSUIvdawsk=
|
||||
github.com/FloatTech/sqlite v1.5.7/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||
github.com/FloatTech/sqlite v1.6.2 h1:FytbExjpvYalZxxITtmSenHiPGLPUvlz47LY/P0SCCw=
|
||||
github.com/FloatTech/sqlite v1.6.2/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3 h1:mCVrTvS2LMNaI2bNA1Gu/B4F5MnfGaTaJClgR6+rhdA=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3/go.mod h1:IagyEhY38VcbbQgVRzAM9f9mhaUn90rM5BTPfudtl1g=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230316111555-2d1ec958de04 h1:ovL+7SAPTBCXy6XNRSdJhNvHtbueWCwEb/jtztmizAc=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230316111555-2d1ec958de04/go.mod h1:jUmX4WBgGRcfjGeIobmVao10AHmXtL3gT00qLbx3/yo=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230514154630-b74e6fcca380 h1:qmwoT8xVaND01aCdwy+5/j6z490nehQWZAVyTBN8ahU=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230514154630-b74e6fcca380/go.mod h1:gkGC1C1eEUd/Ld/ja68zas5j2ZktIZCdnj2FMaM+Au0=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230728081122-94d4d957f3bf h1:PwH9aMnmN+m204cVIqUrI3e7nsdQi/IGW012Fjzb1bs=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230728081122-94d4d957f3bf/go.mod h1:JRnGR7EGeEQgxOs+c0rZAhrS9Es2BTcGHdIDHXIPRzQ=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||
@@ -203,8 +203,8 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11 h1:44Wr6CsCtWlFensK5IhuVCWkosdRw0rA8SygVD8DgoI=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11/go.mod h1:y29UIOy0RD3P+0meDNIWRhcJF3jtWPN9xP9hgt/AJAU=
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.4 h1:+148rELpf/FCDW2EuvKqpb9bNKcwKRtoh16s2sIb5SE=
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.4/go.mod h1:y29UIOy0RD3P+0meDNIWRhcJF3jtWPN9xP9hgt/AJAU=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
package banner
|
||||
|
||||
// Version ...
|
||||
var Version = "v1.7.0-beta5"
|
||||
var Version = "v1.7.2"
|
||||
|
||||
// Copyright ...
|
||||
var Copyright = "© 2020 - 2023 FloatTech"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - 2023-03-16 19:22:03 +0800 CST\n" +
|
||||
"* Version " + Version + " - 2023-07-28 13:58:50 +0800 CST\n" +
|
||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
|
||||
30
main.go
30
main.go
@@ -82,6 +82,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dish" // 程序员做饭指南
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress" // 女装
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
|
||||
@@ -131,6 +132,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime" // 来份涩图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shadiao" // 沙雕app
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shindan" // 测定
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/steam" // steam相关
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tarot" // 抽塔罗牌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||
@@ -140,15 +142,16 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic" // vtb点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf" // 鬼东西
|
||||
|
||||
// ^^^^ //
|
||||
@@ -173,6 +176,8 @@ import (
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_reply" // 人工智能回复
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat" // 打断复读
|
||||
|
||||
// ^^^^ //
|
||||
@@ -226,6 +231,7 @@ func init() {
|
||||
late := flag.Uint("l", 233, "Response latency (ms).")
|
||||
rsz := flag.Uint("r", 4096, "Receiving buffer ring size.")
|
||||
maxpt := flag.Uint("x", 4, "Max process time (min).")
|
||||
markmsg := flag.Bool("m", false, "Don't mark message as read automatically")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@@ -233,13 +239,12 @@ func init() {
|
||||
fmt.Println("Usage:")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
} else {
|
||||
if *d && !*w {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
if *w {
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
}
|
||||
if *d && !*w {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
if *w {
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
|
||||
for _, s := range flag.Args() {
|
||||
@@ -254,6 +259,9 @@ func init() {
|
||||
// sus = append(sus, 12345678)
|
||||
// sus = append(sus, 87654321)
|
||||
|
||||
// 启用 webui
|
||||
// go webctrl.RunGui(*g)
|
||||
|
||||
if *runcfg != "" {
|
||||
f, err := os.Open(*runcfg)
|
||||
if err != nil {
|
||||
@@ -283,6 +291,7 @@ func init() {
|
||||
RingLen: *rsz,
|
||||
Latency: time.Duration(*late) * time.Millisecond,
|
||||
MaxProcessTime: time.Duration(*maxpt) * time.Minute,
|
||||
MarkMessage: !*markmsg,
|
||||
Driver: []zero.Driver{config.W[0]},
|
||||
}
|
||||
|
||||
@@ -299,9 +308,6 @@ func init() {
|
||||
logrus.Infoln("[main] 配置文件已保存到", *save)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 启用 webui
|
||||
// go webctrl.RunGui(*g)
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -309,7 +315,7 @@ func main() {
|
||||
rand.Seed(time.Now().UnixNano()) //nolint: staticcheck
|
||||
}
|
||||
// 帮助
|
||||
zero.OnFullMatchGroup([]string{"/help", ".help", "菜单"}, zero.OnlyToMe).SetBlock(true).
|
||||
zero.OnFullMatchGroup([]string{"help", "/help", ".help", "菜单"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(banner.Banner, "\n管理发送\"/服务列表\"查看 bot 功能\n发送\"/用法name\"查看功能用法"))
|
||||
})
|
||||
|
||||
@@ -187,7 +187,13 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
back = imgfactory.Size(back, int(bw*cw/bw), int(bh*cw/bw)).Image()
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
|
||||
var blurback image.Image
|
||||
bwg := &sync.WaitGroup{}
|
||||
bwg.Add(1)
|
||||
go func() {
|
||||
defer bwg.Done()
|
||||
blurback = imaging.Blur(canvas.Image(), 8)
|
||||
}()
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(5)
|
||||
|
||||
@@ -200,8 +206,8 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
titlecard := gg.NewContext(cardw, titlecardh)
|
||||
|
||||
titlecard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70)
|
||||
bwg.Wait()
|
||||
titlecard.DrawImage(blurback, -70, -70)
|
||||
|
||||
titlecard.DrawRoundedRectangle(1, 1, float64(titlecard.W()-1*2), float64(titlecardh-1*2), 16)
|
||||
titlecard.SetLineWidth(3)
|
||||
@@ -253,8 +259,8 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
basiccard := gg.NewContext(cardw, basiccardh)
|
||||
|
||||
basiccard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40)
|
||||
bwg.Wait()
|
||||
basiccard.DrawImage(blurback, -70, -70-titlecardh-40)
|
||||
|
||||
basiccard.DrawRoundedRectangle(1, 1, float64(basiccard.W()-1*2), float64(basiccardh-1*2), 16)
|
||||
basiccard.SetLineWidth(3)
|
||||
@@ -317,7 +323,8 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
diskcard := gg.NewContext(cardw, diskcardh)
|
||||
diskcard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40-basiccardh-40)
|
||||
bwg.Wait()
|
||||
diskcard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40)
|
||||
|
||||
diskcard.DrawRoundedRectangle(1, 1, float64(diskcard.W()-1*2), float64(diskcardh-1*2), 16)
|
||||
diskcard.SetLineWidth(3)
|
||||
@@ -335,6 +342,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
if dslen == 1 {
|
||||
diskcard.SetRGBA255(192, 192, 192, 255)
|
||||
diskcard.DrawRoundedRectangle(40, 40, float64(diskcard.W())-40-100, 50, 12)
|
||||
diskcard.ClipPreserve()
|
||||
diskcard.Fill()
|
||||
|
||||
switch {
|
||||
@@ -348,7 +356,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
|
||||
diskcard.DrawRoundedRectangle(40, 40, (float64(diskcard.W())-40-100)*diskstate[0].precent*0.01, 50, 12)
|
||||
diskcard.Fill()
|
||||
|
||||
diskcard.ResetClip()
|
||||
diskcard.SetRGBA255(30, 30, 30, 255)
|
||||
|
||||
fw, _ := diskcard.MeasureString(diskstate[0].name)
|
||||
@@ -392,8 +400,8 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
moreinfocard := gg.NewContext(cardw, moreinfocardh)
|
||||
|
||||
moreinfocard.DrawImage(imaging.Blur(canvas.Image(), 8), -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
||||
bwg.Wait()
|
||||
moreinfocard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
||||
|
||||
moreinfocard.DrawRoundedRectangle(1, 1, float64(moreinfocard.W()-1*2), float64(moreinfocard.H()-1*2), 16)
|
||||
moreinfocard.SetLineWidth(3)
|
||||
@@ -430,7 +438,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40), float64(cardw), float64(basiccardh), 16)
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40), float64(cardw), float64(basiccardh), 16)
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40), float64(cardw), float64(diskcardh), 16)
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40+diskcardh+40), float64(cardw), float64(moreinfocardh), 16)
|
||||
shadow.Stroke()
|
||||
|
||||
@@ -2,58 +2,75 @@ package aireply
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/RomiChan/syncx"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/aireply"
|
||||
"github.com/FloatTech/AnimeAPI/tts"
|
||||
"github.com/FloatTech/AnimeAPI/tts/baidutts"
|
||||
"github.com/FloatTech/AnimeAPI/tts/genshin"
|
||||
"github.com/FloatTech/AnimeAPI/tts/mockingbird"
|
||||
"github.com/FloatTech/AnimeAPI/tts/ttscn"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
)
|
||||
|
||||
// 数据结构: [4 bits] [4 bits] [8 bits] [8 bits]
|
||||
// [拟声鸟模式] [百度模式] [tts模式] [回复模式]
|
||||
// [ttscn模式] [百度模式] [tts模式] [回复模式]
|
||||
|
||||
// defaultttsindexkey
|
||||
// 数据结构: [4 bits] [4 bits] [8 bits]
|
||||
// [拟声鸟模式] [百度模式] [tts模式]
|
||||
// [ttscn模式] [百度模式] [tts模式]
|
||||
|
||||
// [tts模式]: 0~63 genshin 64 baidu 65 mockingbird
|
||||
// [tts模式]: 0~63 genshin 64 baidu 65 ttscn
|
||||
|
||||
const (
|
||||
lastgsttsindex = 63 + iota
|
||||
baiduttsindex
|
||||
mockingbirdttsindex
|
||||
ttscnttsindex
|
||||
)
|
||||
|
||||
// extrattsname is the tts other than genshin vits
|
||||
var extrattsname = []string{"百度", "拟声鸟"}
|
||||
var extrattsname = []string{"百度", "TTSCN"}
|
||||
|
||||
const (
|
||||
defaultttsindexkey = -2905
|
||||
gsapikeyextragrp = -1
|
||||
chatgptapikeyextragrp = -2
|
||||
)
|
||||
|
||||
type replymode struct {
|
||||
APIKey string // APIKey is for chatgpt
|
||||
replyModes []string `json:"-"`
|
||||
var ttscnspeakers = [...]string{
|
||||
"晓晓(女 - 年轻人)",
|
||||
"云扬(男 - 年轻人)",
|
||||
"晓辰(女 - 年轻人 - 抖音热门)",
|
||||
"晓涵(女 - 年轻人)",
|
||||
"晓墨(女 - 年轻人)",
|
||||
"晓秋(女 - 中年人)",
|
||||
"晓睿(女 - 老年)",
|
||||
"晓双(女 - 儿童)",
|
||||
"晓萱(女 - 年轻人)",
|
||||
"晓颜(女 - 年轻人)",
|
||||
"晓悠(女 - 儿童)",
|
||||
"云希(男 - 年轻人 - 抖音热门)",
|
||||
"云野(男 - 中年人)",
|
||||
"晓梦(女 - 年轻人)",
|
||||
"晓伊(女 - 儿童)",
|
||||
"晓甄(女 - 年轻人)",
|
||||
}
|
||||
|
||||
func (r *replymode) setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
const defaultttsindexkey = -2905
|
||||
|
||||
var (
|
||||
原 = newapikeystore("./data/tts/o.txt")
|
||||
ཆཏ = newapikeystore("./data/tts/c.txt")
|
||||
百 = newapikeystore("./data/tts/b.txt")
|
||||
)
|
||||
|
||||
type replymode []string
|
||||
|
||||
func (r replymode) setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var ok bool
|
||||
var index int64
|
||||
for i, s := range r.replyModes {
|
||||
for i, s := range r {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
@@ -70,7 +87,7 @@ func (r *replymode) setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
return m.SetData(gid, (m.GetData(index)&^0xff)|(index&0xff))
|
||||
}
|
||||
|
||||
func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
func (r replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
@@ -83,7 +100,7 @@ func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
case 1:
|
||||
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
|
||||
case 2:
|
||||
k := r.getAPIKey(ctx)
|
||||
k := ཆཏ.k
|
||||
if k != "" {
|
||||
return aireply.NewChatGPT(aireply.ChatGPTURL, k)
|
||||
}
|
||||
@@ -93,21 +110,6 @@ func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
|
||||
func (r *replymode) getAPIKey(ctx *zero.Ctx) string {
|
||||
if r.APIKey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(chatgptapikeyextragrp, &r)
|
||||
logrus.Debugln("[tts] get api key:", r.APIKey)
|
||||
}
|
||||
return r.APIKey
|
||||
}
|
||||
|
||||
func (r *replymode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
r.APIKey = key
|
||||
_ = m.Manager.Response(chatgptapikeyextragrp)
|
||||
return m.Manager.SetExtra(chatgptapikeyextragrp, r)
|
||||
}
|
||||
|
||||
var ttsins = func() map[string]tts.TTS {
|
||||
m := make(map[string]tts.TTS, 128)
|
||||
for _, mode := range append(genshin.SoundList[:], extrattsname...) {
|
||||
@@ -122,10 +124,7 @@ var ttsModes = func() []string {
|
||||
return s
|
||||
}()
|
||||
|
||||
type ttsmode struct {
|
||||
APIKey string // APIKey is for genshin vits
|
||||
mode syncx.Map[int64, int64] `json:"-"` // mode grp index
|
||||
}
|
||||
type ttsmode syncx.Map[int64, int64]
|
||||
|
||||
func list(list []string, num int) string {
|
||||
s := ""
|
||||
@@ -143,33 +142,17 @@ func list(list []string, num int) string {
|
||||
func newttsmode() *ttsmode {
|
||||
t := &ttsmode{}
|
||||
m, ok := control.Lookup("tts")
|
||||
t.mode = syncx.Map[int64, int64]{}
|
||||
t.mode.Store(defaultttsindexkey, 0)
|
||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, 0)
|
||||
if ok {
|
||||
index := m.GetData(defaultttsindexkey)
|
||||
msk := index & 0xff
|
||||
if msk >= 0 && (msk < int64(len(genshin.SoundList)) || msk == baiduttsindex || msk == mockingbirdttsindex) {
|
||||
t.mode.Store(defaultttsindexkey, index)
|
||||
if msk >= 0 && (msk < int64(len(genshin.SoundList)) || msk == baiduttsindex || msk == ttscnttsindex) {
|
||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string {
|
||||
if t.APIKey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(gsapikeyextragrp, &t)
|
||||
logrus.Debugln("[tts] get api key:", t.APIKey)
|
||||
}
|
||||
return url.QueryEscape(t.APIKey)
|
||||
}
|
||||
|
||||
func (t *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
t.APIKey = key
|
||||
_ = m.Manager.Response(gsapikeyextragrp)
|
||||
return m.Manager.SetExtra(gsapikeyextragrp, t)
|
||||
}
|
||||
|
||||
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt int) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
@@ -191,13 +174,13 @@ func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case extrattsname[1]:
|
||||
index = mockingbirdttsindex
|
||||
index = ttscnttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
}
|
||||
}
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
t.mode.Store(gid, index)
|
||||
(*syncx.Map[int64, int64])(t).Store(gid, index)
|
||||
return m.SetData(gid, (m.GetData(gid)&^0xffff00)|((index<<8)&0xff00)|((int64(baiduper)<<16)&0x0f0000)|((int64(mockingsynt)<<20)&0xf00000))
|
||||
}
|
||||
|
||||
@@ -206,14 +189,14 @@ func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
i, ok := t.mode.Load(gid)
|
||||
i, ok := (*syncx.Map[int64, int64])(t).Load(gid)
|
||||
if !ok {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
i = m.GetData(gid) >> 8
|
||||
}
|
||||
m := i & 0xff
|
||||
if m < 0 || (m >= int64(len(genshin.SoundList)) && m != baiduttsindex && m != mockingbirdttsindex) {
|
||||
i, _ = t.mode.Load(defaultttsindexkey)
|
||||
if m < 0 || (m >= int64(len(genshin.SoundList)) && m != baiduttsindex && m != ttscnttsindex) {
|
||||
i, _ = (*syncx.Map[int64, int64])(t).Load(defaultttsindexkey)
|
||||
m = i & 0xff
|
||||
}
|
||||
mode := ttsModes[m]
|
||||
@@ -221,17 +204,18 @@ func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
|
||||
if !ok || ins == nil {
|
||||
switch mode {
|
||||
case extrattsname[0]:
|
||||
ins = baidutts.NewBaiduTTS(int(i&0x0f00) >> 8)
|
||||
id, sec, _ := strings.Cut(百.k, ",")
|
||||
ins = baidutts.NewBaiduTTS(int(i&0x0f00)>>8, id, sec)
|
||||
case extrattsname[1]:
|
||||
var err error
|
||||
ins, err = mockingbird.NewMockingBirdTTS(int(i&0xf000) >> 12)
|
||||
ins, err = ttscn.NewTTSCN("中文(普通话,简体)", ttscnspeakers[int(i&0xf000)>>12], ttscn.KBRates[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default: // 原神
|
||||
k := t.getAPIKey(ctx)
|
||||
k := 原.k
|
||||
if k != "" {
|
||||
ins = genshin.NewGenshin(int(m), t.getAPIKey(ctx))
|
||||
ins = genshin.NewGenshin(int(m), 原.k)
|
||||
ttsins[mode] = ins
|
||||
} else {
|
||||
return nil, errors.New("no valid speaker")
|
||||
@@ -268,7 +252,7 @@ func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) er
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case extrattsname[1]:
|
||||
index = mockingbirdttsindex
|
||||
index = ttscnttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
}
|
||||
@@ -277,6 +261,6 @@ func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) er
|
||||
if !ok {
|
||||
return errors.New("[tts] service not found")
|
||||
}
|
||||
t.mode.Store(defaultttsindexkey, index)
|
||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
|
||||
return m.SetData(defaultttsindexkey, (index&0xff)|((int64(baiduper)<<8)&0x0f00)|((int64(mockingsynt)<<12)&0xf000))
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var replmd = replymode{
|
||||
replyModes: []string{"青云客", "小爱", "ChatGPT"},
|
||||
}
|
||||
var replmd = replymode([]string{"青云客", "小爱", "ChatGPT"})
|
||||
|
||||
var ttsmd = newttsmode()
|
||||
|
||||
@@ -26,11 +24,14 @@ func init() { // 插件主体
|
||||
DisableOnDefault: true,
|
||||
Brief: "人工智能语音回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n" +
|
||||
"- 设置语音模式[原神人物/百度/拟声鸟] 数字(百度/拟声鸟模式)\n" +
|
||||
"- 设置默认语音模式[原神人物/百度/拟声鸟] 数字(百度/拟声鸟模式)\n" +
|
||||
"- 设置语音模式[原神人物/百度/TTSCN] 数字(百度/TTSCN说话人)\n" +
|
||||
"- 设置默认语音模式[原神人物/百度/TTSCN] 数字(百度/TTSCN说话人)\n" +
|
||||
"- 恢复成默认语音模式\n" +
|
||||
"- 设置原神语音 api key xxxxxx (key请加开发群获得)\n" +
|
||||
"当前适用的原神人物含有以下:\n" + list(genshin.SoundList[:], 5),
|
||||
"- 设置百度语音 api id xxxxxx secret xxxxxx (请自行获得)\n" +
|
||||
"当前适用的原神人物含有以下: \n" + list(genshin.SoundList[:], 5) +
|
||||
"\n当前适用的TTSCN人物含有以下(以数字顺序代表): \n" + list(ttscnspeakers[:], 5),
|
||||
PrivateDataFolder: "tts",
|
||||
})
|
||||
|
||||
enr := control.Register("aireply", &ctrl.Options[*zero.Ctx]{
|
||||
@@ -65,7 +66,7 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
enr.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := replmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
|
||||
err := ཆཏ.set(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -103,7 +104,7 @@ func init() { // 插件主体
|
||||
}
|
||||
})
|
||||
|
||||
ent.OnRegex(`^设置语音模式\s*([\S\D]*)\s*(\d*)$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
ent.OnRegex(`^设置语音模式\s*([\S\D]*)\s+(\d*)$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
num := ctx.State["regex_matched"].([]string)[2]
|
||||
n := 0
|
||||
@@ -146,7 +147,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
||||
})
|
||||
|
||||
ent.OnRegex(`^设置默认语音模式\s*([\S\D]*)\s*(\d*)$`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
ent.OnRegex(`^设置默认语音模式\s*([\S\D]*)\s+(\d*)$`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
num := ctx.State["regex_matched"].([]string)[2]
|
||||
n := 0
|
||||
@@ -183,7 +184,16 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
ent.OnRegex(`^设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := ttsmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
|
||||
err := 原.set(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("设置成功"))
|
||||
})
|
||||
|
||||
ent.OnRegex(`^设置百度语音\s*api\s*id\s*(.*)\s*secret\s*(.*)\s*$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := 百.set(ctx.State["regex_matched"].([]string)[1] + "," + ctx.State["regex_matched"].([]string)[2])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
29
plugin/ai_reply/model.go
Normal file
29
plugin/ai_reply/model.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
type apikeystore struct {
|
||||
k string
|
||||
p string
|
||||
}
|
||||
|
||||
func newapikeystore(p string) (s apikeystore) {
|
||||
s.p = p
|
||||
if file.IsExist(p) {
|
||||
data, err := os.ReadFile(p)
|
||||
if err == nil {
|
||||
s.k = binary.BytesToString(data)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *apikeystore) set(k string) error {
|
||||
s.k = k
|
||||
return os.WriteFile(s.p, binary.StringToBytes(k), 0644)
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func init() {
|
||||
if err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.DoBlock(uid); err == nil {
|
||||
t := time.Now().Unix()
|
||||
cache.Set(uid, struct{}{})
|
||||
ctx.SetGroupBan(gid, uid, int64(bandur.Minutes()))
|
||||
ctx.SetThisGroupBan(uid, int64(bandur.Minutes()))
|
||||
ctx.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur))
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
|
||||
@@ -40,7 +40,7 @@ func randText(text ...string) message.MessageSegment {
|
||||
}
|
||||
|
||||
// isAtriSleeping 凌晨0点到6点,ATRI 在睡觉,不回应任何请求
|
||||
func isAtriSleeping(ctx *zero.Ctx) bool {
|
||||
func isAtriSleeping(*zero.Ctx) bool {
|
||||
if now := time.Now().Hour(); now >= 1 && now < 6 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,27 +1,60 @@
|
||||
// Package baidu 百度一下
|
||||
// Package baidu 百度百科
|
||||
package baidu
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
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"
|
||||
)
|
||||
|
||||
func init() {
|
||||
control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "不会百度吗",
|
||||
Help: "- 百度下[xxx]",
|
||||
}).OnPrefix("百度下").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
txt := ctx.State["args"].(string)
|
||||
if txt != "" {
|
||||
ctx.SendChain(message.Text("https://buhuibaidu.me/?s=" + url.QueryEscape(txt)))
|
||||
}
|
||||
})
|
||||
const (
|
||||
duURL = "https://api.a20safe.com/api.php?api=21&key=%s&text=%s" // api地址
|
||||
wikiURL = "https://api.a20safe.com/api.php?api=23&key=%s&text=%s"
|
||||
key = "7d06a110e9e20a684e02934549db1d3d"
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data []struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "百科\n" +
|
||||
"- 百度/百科/维基/wiki[关键字]",
|
||||
})
|
||||
en.OnRegex(`^(百度|维基|百科|wiki)\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
var es []byte
|
||||
var err error
|
||||
switch ctx.State["regex_matched"].([]string)[1] {
|
||||
case "百度", "百科":
|
||||
es, err = web.GetData(fmt.Sprintf(duURL, key, ctx.State["regex_matched"].([]string)[2])) // 将网站返回结果赋值
|
||||
case "wiki", "维基":
|
||||
es, err = web.GetData(fmt.Sprintf(wikiURL, key, ctx.State["regex_matched"].([]string)[2])) // 将网站返回结果赋值
|
||||
}
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var r result // r数组
|
||||
err = json.Unmarshal(es, &r) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
if r.Code == 0 && len(r.Data) > 0 {
|
||||
ctx.SendChain(message.Text(r.Data[0].Content)) // 输出提取后的结果
|
||||
} else {
|
||||
ctx.SendChain(message.Text("API访问错误"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (bdres *baiduRes) audit(ctx *zero.Ctx, configpath string) {
|
||||
bantime = group.BANTime * 60
|
||||
}
|
||||
// 执行禁言
|
||||
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
|
||||
ctx.SetThisGroupBan(ctx.Event.UserID, bantime)
|
||||
}
|
||||
// 查看是否开启撤回提示
|
||||
if group.DMRemind {
|
||||
|
||||
@@ -56,7 +56,7 @@ func init() {
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 查弹幕 [xxx]\n" +
|
||||
"- 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0;\n" +
|
||||
"- 更新vup" +
|
||||
"- 更新vup\n" +
|
||||
"Tips: (412就是拦截的意思,建议私聊把cookie设全)\n",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
db.DBPath = engine.DataFolder() + "bookreview.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("bookreview.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
err := db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -26,7 +26,7 @@ func init() {
|
||||
db.DBPath = en.DataFolder() + "cxh.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = en.GetLazyData("cxh.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
err := db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
db.DBPath = engine.DataFolder() + "cp.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("cp.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
err := db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -29,7 +29,7 @@ func init() {
|
||||
}
|
||||
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image(picURL))
|
||||
|
||||
@@ -27,7 +27,7 @@ func LoadText(dbfile string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
115
plugin/dish/dish.go
Normal file
115
plugin/dish/dish.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// Package dish 程序员做饭指南zbp版,数据来源Anduin2017/HowToCook
|
||||
package dish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type dish struct {
|
||||
ID uint32 `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Materials string `db:"materials"`
|
||||
Steps string `db:"steps"`
|
||||
}
|
||||
|
||||
var (
|
||||
db = &sql.Sqlite{}
|
||||
initialized = false
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("dish", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "程序员做饭指南",
|
||||
Help: "-怎么做[xxx]|烹饪[xxx]|随机菜谱|随便做点菜",
|
||||
PublicDataFolder: "Dish",
|
||||
})
|
||||
|
||||
db.DBPath = en.DataFolder() + "dishes.db"
|
||||
|
||||
if _, err := en.GetLazyData("dishes.db", true); err != nil {
|
||||
logrus.Warnln("[dish]获取菜谱数据库文件失败")
|
||||
} else if err = db.Open(time.Hour); err != nil {
|
||||
logrus.Warnln("[dish]连接菜谱数据库失败")
|
||||
} else if err = db.Create("dish", &dish{}); err != nil {
|
||||
logrus.Warnln("[dish]同步菜谱数据表失败")
|
||||
} else if count, err := db.Count("dish"); err != nil {
|
||||
logrus.Warnln("[dish]统计菜谱数据失败")
|
||||
} else {
|
||||
logrus.Infoln("[dish]加载", count, "条菜谱")
|
||||
initialized = true
|
||||
}
|
||||
|
||||
if !initialized {
|
||||
logrus.Warnln("[dish]插件未能成功初始化")
|
||||
}
|
||||
|
||||
en.OnPrefixGroup([]string{"怎么做", "烹饪"}).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
if !initialized {
|
||||
ctx.SendChain(message.Text("客官,本店暂未开业"))
|
||||
return
|
||||
}
|
||||
|
||||
name := ctx.NickName()
|
||||
dishName := ctx.State["args"].(string)
|
||||
|
||||
if dishName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(dishName, "'") ||
|
||||
strings.Contains(dishName, "\"") ||
|
||||
strings.Contains(dishName, "\\") ||
|
||||
strings.Contains(dishName, ";") {
|
||||
return
|
||||
}
|
||||
|
||||
var d dish
|
||||
if err := db.Find("dish", &d, fmt.Sprintf("WHERE name like %%%s%%", dishName)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
||||
"已为客官%s找到%s的做法辣!\n"+
|
||||
"原材料:%s\n"+
|
||||
"步骤:\n"+
|
||||
"%s",
|
||||
name, dishName, d.Materials, d.Steps),
|
||||
))
|
||||
})
|
||||
|
||||
en.OnPrefixGroup([]string{"随机菜谱", "随便做点菜"}).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
if !initialized {
|
||||
ctx.SendChain(message.Text("客官,本店暂未开业"))
|
||||
return
|
||||
}
|
||||
|
||||
name := ctx.NickName()
|
||||
var d dish
|
||||
if err := db.Pick("dish", &d); err != nil {
|
||||
ctx.SendChain(message.Text("小店好像出错了,暂时端不出菜来惹"))
|
||||
logrus.Warnln("[dish]随机菜谱请求出错:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
||||
"已为客官%s送上%s的做法:\n"+
|
||||
"原材料:%s\n"+
|
||||
"步骤:\n"+
|
||||
"%s",
|
||||
name, d.Name, d.Materials, d.Steps),
|
||||
))
|
||||
})
|
||||
}
|
||||
@@ -53,9 +53,10 @@ var (
|
||||
|
||||
func init() {
|
||||
en.OnFullMatchGroup([]string{"抽签列表", "刷新抽签列表"}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
lotsList, err := getList() // 刷新列表
|
||||
var err error
|
||||
lotsList, err = getList() // 刷新列表
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
messageText := &strings.Builder{}
|
||||
@@ -67,7 +68,7 @@ func init() {
|
||||
}
|
||||
textPic, err := text.RenderToBase64(messageText.String(), text.BoldFontFile, 400, 50)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + helper.BytesToString(textPic)))
|
||||
@@ -82,7 +83,7 @@ func init() {
|
||||
if fileInfo.lotsType == "folder" {
|
||||
picPath, err := randFile(lotsType, 3)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("file:///"+picPath))
|
||||
@@ -90,13 +91,13 @@ func init() {
|
||||
}
|
||||
lotsImg, err := randGif(lotsType + "." + fileInfo.lotsType)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 生成图片
|
||||
data, err := imgfactory.ToBytes(lotsImg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.ImageBytes(data))
|
||||
@@ -129,13 +130,13 @@ func init() {
|
||||
}
|
||||
im, err := gif.DecodeAll(bytes.NewReader(gifdata))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
fileName := datapath + "/" + lotsName + ".gif"
|
||||
err = file.DownloadTo(picURL, fileName)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
lotsList[lotsName] = info{
|
||||
@@ -158,7 +159,7 @@ func init() {
|
||||
}
|
||||
err := os.Remove(datapath + lotsName + "." + fileInfo.lotsType)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
delete(lotsList, lotsName)
|
||||
@@ -244,10 +245,10 @@ func randGif(gifName string) (image.Image, error) {
|
||||
return nil, err
|
||||
}
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.Size(firstImg, firstImg.Bounds().Max.X, firstImg.Bounds().Max.Y).InsertUpC(v, 0, 0, firstImg.Bounds().Max.X/2, firstImg.Bounds().Max.Y/2).Clone().Image(),err
|
||||
return imgfactory.Size(firstImg, firstImg.Bounds().Dx(), firstImg.Bounds().Dy()).InsertUpC(v, 0, 0, firstImg.Bounds().Dx()/2, firstImg.Bounds().Dy()/2).Clone().Image(),err
|
||||
/*/
|
||||
// 如果gif图片出现信息缺失请使用上面注释掉的代码,把下面注释了(上面代码部分图存在bug)
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.NewFactoryBG(v.Rect.Max.X, v.Rect.Max.Y, color.NRGBA{0, 0, 0, 255}).InsertUp(v, 0, 0, 0, 0).Clone().Image(), err
|
||||
return imgfactory.NewFactoryBG(v.Rect.Dx(), v.Rect.Dy(), color.NRGBA{0, 0, 0, 255}).InsertUp(v, 0, 0, 0, 0).Clone().Image(), err
|
||||
// */
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func init() {
|
||||
PrivateDataFolder: "driftbottle",
|
||||
})
|
||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
||||
err := seaSide.Open(time.Hour * 24)
|
||||
err := seaSide.Open(time.Hour)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ func init() {
|
||||
userid := ctx.Event.UserID
|
||||
username := ctx.CardOrNickName(userid)
|
||||
data := (storage)(c.GetData(-su))
|
||||
groupname := ctx.GetThisGroupInfo(true).Name
|
||||
groupid := ctx.Event.GroupID
|
||||
groupname := ctx.GetGroupInfo(groupid, true).Name
|
||||
logrus.Info("[event]收到来自[", username, "](", userid, ")的群聊邀请,群:[", groupname, "](", groupid, ")")
|
||||
if data.isinviteon() || (!data.ismasteroff() && zero.SuperUserPermission(ctx)) {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "invite", true, "")
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
package font
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/gif"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -15,10 +25,10 @@ func init() {
|
||||
control.Register("font", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "渲染任意文字到图片",
|
||||
Help: "- (用[字体])渲染文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体]",
|
||||
}).OnRegex(`^(用.+)?渲染文字([\s\S]+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
Help: "- (用[字体])渲染(抖动)文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|粗苹方体|未来荧黑体|Gugi体|八丸体|Impact体|猫啃体|苹方体]",
|
||||
}).OnRegex(`^(用.+)?渲染(抖动)?文字([\s\S]+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
fnt := ctx.State["regex_matched"].([]string)[1]
|
||||
txt := ctx.State["regex_matched"].([]string)[2]
|
||||
txt := ctx.State["regex_matched"].([]string)[3]
|
||||
switch fnt {
|
||||
case "用终末体":
|
||||
fnt = text.SyumatuFontFile
|
||||
@@ -30,16 +40,73 @@ func init() {
|
||||
fnt = text.SakuraFontFile
|
||||
case "用Consolas体":
|
||||
fnt = text.ConsolasFontFile
|
||||
case "用粗苹方体":
|
||||
fnt = text.BoldFontFile
|
||||
case "用未来荧黑体":
|
||||
fnt = text.GlowSansFontFile
|
||||
case "用Gugi体":
|
||||
fnt = text.GugiRegularFontFile
|
||||
case "用八丸体":
|
||||
fnt = text.HachiMaruPopRegularFontFile
|
||||
case "用Impact体":
|
||||
fnt = text.ImpactFontFile
|
||||
case "用猫啃体":
|
||||
fnt = text.MaokenFontFile
|
||||
case "用苹方体":
|
||||
fallthrough
|
||||
default:
|
||||
fnt = text.FontFile
|
||||
}
|
||||
b, err := text.RenderToBase64(txt, fnt, 400, 20)
|
||||
if ctx.State["regex_matched"].([]string)[2] == "" {
|
||||
b, err := text.RenderToBase64(txt, fnt, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
return
|
||||
}
|
||||
nilx, nily := 1.0, 8.0
|
||||
s := []*image.NRGBA{}
|
||||
strlist := strings.Split(txt, "\n")
|
||||
data, err := file.GetLazyData(fnt, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
// 获得画布预计
|
||||
testcov := gg.NewContext(1, 1)
|
||||
if err = testcov.ParseFontFace(data, 30); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 取最长段
|
||||
txt = ""
|
||||
for _, v := range strlist {
|
||||
if len([]rune(v)) > len([]rune(txt)) {
|
||||
txt = v
|
||||
}
|
||||
}
|
||||
w, h := testcov.MeasureString(txt)
|
||||
for i := 0; i < 10; i++ {
|
||||
cov := gg.NewContext(int(w+float64(len([]rune(txt)))*nilx)+40, int(h+nily)*len(strlist)+30)
|
||||
cov.SetRGB(1, 1, 1)
|
||||
cov.Clear()
|
||||
if err = cov.ParseFontFace(data, 30); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
cov.SetColor(color.NRGBA{R: 0, G: 0, B: 0, A: 127})
|
||||
for k, v := range strlist {
|
||||
for kk, vv := range []rune(v) {
|
||||
x, y := cov.MeasureString(string([]rune(v)[:kk]))
|
||||
cov.DrawString(string(vv), x+float64(rand.Intn(5))+10+nilx, y+float64(rand.Intn(5))+15+float64(k)*(y+nily))
|
||||
}
|
||||
}
|
||||
s = append(s, imgfactory.Size(cov.Image(), 0, 0).Image())
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_ = gif.EncodeAll(&buf, imgfactory.MergeGif(5, s))
|
||||
ctx.SendChain(message.ImageBytes(buf.Bytes()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -19,7 +19,7 @@ func mo(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "摸.gif"
|
||||
// name := cc.usrdir + "摸.gif"
|
||||
c := dlrange("mo", 5, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -44,7 +44,8 @@ func mo(cc *context, value ...string) (string, error) {
|
||||
imgs[3].InsertBottom(tou, 85, 75, 27, 37).Image(),
|
||||
imgs[4].InsertBottom(tou, 90, 70, 22, 42).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, mo))
|
||||
g := imgfactory.MergeGif(1, mo)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// cuo 搓
|
||||
@@ -53,7 +54,7 @@ func cuo(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "搓.gif"
|
||||
// name := cc.usrdir + "搓.gif"
|
||||
c := dlrange("cuo", 5, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -82,7 +83,8 @@ func cuo(cc *context, value ...string) (string, error) {
|
||||
imgs[3].InsertBottomC(m3.Image(), 0, 0, 75, 130).Image(),
|
||||
imgs[4].InsertBottomC(m4.Image(), 0, 0, 75, 130).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(5, cuo))
|
||||
g := imgfactory.MergeGif(5, cuo)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// qiao 敲
|
||||
@@ -91,7 +93,7 @@ func qiao(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "敲.gif"
|
||||
// name := cc.usrdir + "敲.gif"
|
||||
c := dlrange("qiao", 2, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -113,7 +115,8 @@ func qiao(cc *context, value ...string) (string, error) {
|
||||
imgs[0].InsertUp(tou, 40, 33, 57, 52).Image(),
|
||||
imgs[1].InsertUp(tou, 38, 36, 58, 50).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, qiao))
|
||||
g := imgfactory.MergeGif(1, qiao)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// chi 吃
|
||||
@@ -122,7 +125,7 @@ func chi(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "吃.gif"
|
||||
// name := cc.usrdir + "吃.gif"
|
||||
c := dlrange("chi", 3, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -145,7 +148,8 @@ func chi(cc *context, value ...string) (string, error) {
|
||||
imgs[1].InsertBottom(tou, 0, 0, 1, 38).Image(),
|
||||
imgs[2].InsertBottom(tou, 0, 0, 1, 38).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, chi))
|
||||
g := imgfactory.MergeGif(1, chi)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// ceng 蹭
|
||||
@@ -154,7 +158,7 @@ func ceng(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "蹭.gif"
|
||||
// name := cc.usrdir + "蹭.gif"
|
||||
c := dlrange("ceng", 6, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -184,7 +188,8 @@ func ceng(cc *context, value ...string) (string, error) {
|
||||
imgs[4].InsertUp(tou, 75, 77, 56, 110).InsertUp(imgfactory.Rotate(tou2, -66, 132, 80).Image(), 0, 0, 78, 40).Image(),
|
||||
imgs[5].InsertUp(tou, 75, 77, 62, 102).InsertUp(tou2, 71, 100, 110, 94).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, ceng))
|
||||
g := imgfactory.MergeGif(8, ceng)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// ken 啃
|
||||
@@ -193,7 +198,7 @@ func ken(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "啃.gif"
|
||||
// name := cc.usrdir + "啃.gif"
|
||||
c := dlrange("ken", 16, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -229,7 +234,8 @@ func ken(cc *context, value ...string) (string, error) {
|
||||
imgs[14].Image(),
|
||||
imgs[15].Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ken))
|
||||
g := imgfactory.MergeGif(7, ken)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// pai 拍
|
||||
@@ -238,7 +244,7 @@ func pai(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "拍.gif"
|
||||
// name := cc.usrdir + "拍.gif"
|
||||
c := dlrange("pai", 2, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -260,7 +266,8 @@ func pai(cc *context, value ...string) (string, error) {
|
||||
imgs[0].InsertUp(tou, 0, 0, 1, 47).Image(),
|
||||
imgs[1].InsertUp(tou, 0, 0, 1, 67).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, pai))
|
||||
g := imgfactory.MergeGif(1, pai)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// xqe 冲
|
||||
@@ -269,7 +276,7 @@ func xqe(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "冲.gif"
|
||||
// name := cc.usrdir + "冲.gif"
|
||||
c := dlrange("xqe", 2, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -291,7 +298,8 @@ func xqe(cc *context, value ...string) (string, error) {
|
||||
imgs[0].InsertUp(tou, 30, 30, 15, 53).Image(),
|
||||
imgs[1].InsertUp(tou, 30, 30, 40, 53).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, chong))
|
||||
g := imgfactory.MergeGif(1, chong)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// diu 丢
|
||||
@@ -300,7 +308,7 @@ func diu(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "丢.gif"
|
||||
// name := cc.usrdir + "丢.gif"
|
||||
c := dlrange("diu", 8, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -328,7 +336,8 @@ func diu(cc *context, value ...string) (string, error) {
|
||||
imgs[6].InsertUp(tou, 35, 35, 259, 31).Image(),
|
||||
imgs[7].InsertUp(tou, 175, 175, -50, 220).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, diu))
|
||||
g := imgfactory.MergeGif(7, diu)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// kiss 亲
|
||||
@@ -338,7 +347,7 @@ func kiss(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 13
|
||||
name := cc.usrdir + "Kiss.gif"
|
||||
// name := cc.usrdir + "Kiss.gif"
|
||||
c := dlrange("kiss", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -367,7 +376,8 @@ func kiss(cc *context, value ...string) (string, error) {
|
||||
kiss[i] = imgs[i].InsertUp(tou, 50, 50, userLocs[i][0], userLocs[i][1]).
|
||||
InsertUp(tou2, 40, 40, selfLocs[i][0], selfLocs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, kiss))
|
||||
g := imgfactory.MergeGif(7, kiss)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// garbage 垃圾 垃圾桶
|
||||
@@ -377,7 +387,7 @@ func garbage(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 25
|
||||
name := cc.usrdir + "Garbage.gif"
|
||||
// name := cc.usrdir + "Garbage.gif"
|
||||
c := dlrange("garbage", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -400,7 +410,8 @@ func garbage(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
garbage[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, garbage))
|
||||
g := imgfactory.MergeGif(7, garbage)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// thump 捶
|
||||
@@ -410,7 +421,7 @@ func thump(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 4
|
||||
name := cc.usrdir + "Thump.gif"
|
||||
// name := cc.usrdir + "Thump.gif"
|
||||
c := dlrange("thump", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -433,7 +444,8 @@ func thump(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
thump[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, thump))
|
||||
g := imgfactory.MergeGif(7, thump)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// jiujiu 啾啾
|
||||
@@ -443,7 +455,7 @@ func jiujiu(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 8
|
||||
name := cc.usrdir + "Jiujiu.gif"
|
||||
// name := cc.usrdir + "Jiujiu.gif"
|
||||
c := dlrange("jiujiu", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -465,7 +477,8 @@ func jiujiu(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
jiujiu[i] = imgs[i].InsertBottom(im.Image(), 0, 0, 0, 0).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, jiujiu))
|
||||
g := imgfactory.MergeGif(7, jiujiu)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// knock 2敲
|
||||
@@ -475,7 +488,7 @@ func knock(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 8
|
||||
name := cc.usrdir + "Knock.gif"
|
||||
// name := cc.usrdir + "Knock.gif"
|
||||
c := dlrange("knock", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -498,7 +511,8 @@ func knock(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
knock[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, knock))
|
||||
g := imgfactory.MergeGif(7, knock)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// 听音乐 listenMusic
|
||||
@@ -508,7 +522,7 @@ func listenMusic(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 1
|
||||
name := cc.usrdir + "ListenMusic.gif"
|
||||
// name := cc.usrdir + "ListenMusic.gif"
|
||||
c := dlrange("listen_music", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -530,7 +544,8 @@ func listenMusic(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < 36; i++ {
|
||||
listenmusic[i] = imgs[0].InsertBottomC(imgfactory.Rotate(face, float64(-i*10), 215, 215).Image(), 0, 0, 207, 207).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, listenmusic))
|
||||
g := imgfactory.MergeGif(7, listenmusic)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// loveYou 永远爱你
|
||||
@@ -540,7 +555,7 @@ func loveYou(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 2
|
||||
name := cc.usrdir + "LoveYou.gif"
|
||||
// name := cc.usrdir + "LoveYou.gif"
|
||||
c := dlrange("love_you", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -563,7 +578,8 @@ func loveYou(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
loveyou[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, loveyou))
|
||||
g := imgfactory.MergeGif(7, loveyou)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// pat 2拍
|
||||
@@ -573,7 +589,7 @@ func pat(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 10
|
||||
name := cc.usrdir + "Pat.gif"
|
||||
// name := cc.usrdir + "Pat.gif"
|
||||
c := dlrange("pat", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -605,7 +621,8 @@ func pat(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < len(pat); i++ {
|
||||
pat[i] = p[seq[i]]
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, pat))
|
||||
g := imgfactory.MergeGif(7, pat)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// jackUp 顶
|
||||
@@ -615,7 +632,7 @@ func jackUp(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 23
|
||||
name := cc.usrdir + "JackUp.gif"
|
||||
// name := cc.usrdir + "JackUp.gif"
|
||||
c := dlrange("play", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -648,7 +665,8 @@ func jackUp(cc *context, value ...string) (string, error) {
|
||||
play = append(play, p[0:8]...)
|
||||
play = append(play, p[12:18]...)
|
||||
play = append(play, p[18:23]...)
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, play))
|
||||
g := imgfactory.MergeGif(7, play)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// pound 捣
|
||||
@@ -658,7 +676,7 @@ func pound(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 8
|
||||
name := cc.usrdir + "Pound.gif"
|
||||
// name := cc.usrdir + "Pound.gif"
|
||||
c := dlrange("pound", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -681,7 +699,8 @@ func pound(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
pound[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, pound))
|
||||
g := imgfactory.MergeGif(7, pound)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// punch 打拳
|
||||
@@ -691,7 +710,7 @@ func punch(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 13
|
||||
name := cc.usrdir + "Punch.gif"
|
||||
// name := cc.usrdir + "Punch.gif"
|
||||
c := dlrange("punch", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -714,7 +733,8 @@ func punch(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
punch[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]-15).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, punch))
|
||||
g := imgfactory.MergeGif(7, punch)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// roll 滚
|
||||
@@ -724,7 +744,7 @@ func roll(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 8
|
||||
name := cc.usrdir + "roll.gif"
|
||||
// name := cc.usrdir + "roll.gif"
|
||||
c := dlrange("roll", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -747,7 +767,8 @@ func roll(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
roll[i] = imgs[i].InsertBottomC(imgfactory.Rotate(im.Image(), float64(locs[i][2]), 0, 0).Image(), 0, 0, locs[i][0]+105, locs[i][1]+105).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, roll))
|
||||
g := imgfactory.MergeGif(7, roll)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// suck 吸 嗦
|
||||
@@ -757,7 +778,7 @@ func suck(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 12
|
||||
name := cc.usrdir + "Suck.gif"
|
||||
// name := cc.usrdir + "Suck.gif"
|
||||
c := dlrange("suck", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -780,7 +801,8 @@ func suck(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
suck[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, suck))
|
||||
g := imgfactory.MergeGif(7, suck)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// hammer 锤
|
||||
@@ -790,7 +812,7 @@ func hammer(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 7
|
||||
name := cc.usrdir + "Hammer.gif"
|
||||
// name := cc.usrdir + "Hammer.gif"
|
||||
c := dlrange("hammer", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -813,7 +835,8 @@ func hammer(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
hammer[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, hammer))
|
||||
g := imgfactory.MergeGif(7, hammer)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// tightly 紧贴 紧紧贴着
|
||||
@@ -823,7 +846,7 @@ func tightly(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 20
|
||||
name := cc.usrdir + "Tightly.gif"
|
||||
// name := cc.usrdir + "Tightly.gif"
|
||||
c := dlrange("tightly", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -846,13 +869,14 @@ func tightly(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
tightly[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, tightly))
|
||||
g := imgfactory.MergeGif(7, tightly)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// turn 转
|
||||
func turn(cc *context, value ...string) (string, error) {
|
||||
_ = value
|
||||
name := cc.usrdir + "Turn.gif"
|
||||
// name := cc.usrdir + "Turn.gif"
|
||||
face, err := cc.getLogo(0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -865,7 +889,8 @@ func turn(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < 36; i++ {
|
||||
turn[i] = imgfactory.Size(canvas.Image(), 0, 0).InsertUpC(imgfactory.Rotate(face, float64(10*i), 250, 250).Image(), 0, 0, 125, 125).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, turn))
|
||||
g := imgfactory.MergeGif(7, turn)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// taiguan 抬棺
|
||||
@@ -874,7 +899,7 @@ func taiguan(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "taiguan.gif"
|
||||
// name := cc.usrdir + "taiguan.gif"
|
||||
c := dlrange("taiguan", 20, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -914,7 +939,8 @@ func taiguan(cc *context, value ...string) (string, error) {
|
||||
imgs[18].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[19].InsertUp(tou, 85, 85, 175, 65).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, taiguan))
|
||||
g := imgfactory.MergeGif(7, taiguan)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// zou 揍
|
||||
@@ -923,7 +949,7 @@ func zou(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "zou.gif"
|
||||
// name := cc.usrdir + "zou.gif"
|
||||
c := dlrange("zou", 3, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -950,7 +976,8 @@ func zou(cc *context, value ...string) (string, error) {
|
||||
imgs[1].InsertUp(tou, 40, 40, 98, 138).InsertUp(tou2, 55, 55, 101, 45).Image(),
|
||||
imgs[2].InsertUp(tou, 40, 40, 89, 140).InsertUp(tou2, 55, 55, 99, 40).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, zou))
|
||||
g := imgfactory.MergeGif(8, zou)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// ci 吞
|
||||
@@ -959,7 +986,7 @@ func ci(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "ci.gif"
|
||||
// name := cc.usrdir + "ci.gif"
|
||||
c := dlrange("ci", 26, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1005,7 +1032,8 @@ func ci(cc *context, value ...string) (string, error) {
|
||||
imgs[24].Image(),
|
||||
imgs[25].Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ci))
|
||||
g := imgfactory.MergeGif(7, ci)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// worship 膜拜
|
||||
@@ -1014,7 +1042,7 @@ func worship(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "worship.gif"
|
||||
// name := cc.usrdir + "worship.gif"
|
||||
c := dlrange("worship", 9, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -1043,7 +1071,8 @@ func worship(cc *context, value ...string) (string, error) {
|
||||
imgs[7].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[8].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, worship))
|
||||
g := imgfactory.MergeGif(7, worship)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// 2ceng 2蹭
|
||||
@@ -1052,7 +1081,7 @@ func ceng2(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "ceng2.gif"
|
||||
// name := cc.usrdir + "ceng2.gif"
|
||||
c := dlrange("ceng2", 4, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1076,7 +1105,8 @@ func ceng2(cc *context, value ...string) (string, error) {
|
||||
imgs[2].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
imgs[3].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ceng2))
|
||||
g := imgfactory.MergeGif(7, ceng2)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// dun 炖
|
||||
@@ -1085,7 +1115,7 @@ func dun(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "dun.gif"
|
||||
// name := cc.usrdir + "dun.gif"
|
||||
c := dlrange("dun", 5, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1110,7 +1140,8 @@ func dun(cc *context, value ...string) (string, error) {
|
||||
imgs[3].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
imgs[4].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, dun))
|
||||
g := imgfactory.MergeGif(7, dun)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// push 滚高清重置版 过渡
|
||||
@@ -1120,7 +1151,7 @@ func push(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 16
|
||||
name := cc.usrdir + "push.gif"
|
||||
// name := cc.usrdir + "push.gif"
|
||||
c := dlrange("push", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -1142,7 +1173,8 @@ func push(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
push[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-22*i), 280, 280).Image(), 0, 0, 523, 291).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, push))
|
||||
g := imgfactory.MergeGif(7, push)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// peng 砰
|
||||
@@ -1151,7 +1183,7 @@ func peng(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "peng.gif"
|
||||
// name := cc.usrdir + "peng.gif"
|
||||
c := dlrange("peng", 25, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1200,7 +1232,8 @@ func peng(cc *context, value ...string) (string, error) {
|
||||
imgs[23].InsertUp(m4.Image(), 0, 0, 89, 159).Image(),
|
||||
imgs[24].InsertUp(m4.Image(), 0, 0, 86, 160).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, peng))
|
||||
g := imgfactory.MergeGif(8, peng)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// klee 可莉吃
|
||||
@@ -1210,7 +1243,7 @@ func klee(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 31
|
||||
name := cc.usrdir + "klee.gif"
|
||||
// name := cc.usrdir + "klee.gif"
|
||||
c := dlrange("klee", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -1233,7 +1266,8 @@ func klee(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
klee[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, klee))
|
||||
g := imgfactory.MergeGif(7, klee)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// hutaoken 胡桃啃
|
||||
@@ -1242,7 +1276,7 @@ func hutaoken(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "hutaoken.gif"
|
||||
// name := cc.usrdir + "hutaoken.gif"
|
||||
c := dlrange("hutaoken", 2, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1264,7 +1298,8 @@ func hutaoken(cc *context, value ...string) (string, error) {
|
||||
imgs[0].InsertBottom(tou, 98, 101, 108, 234).Image(),
|
||||
imgs[1].InsertBottom(tou, 96, 100, 108, 237).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, hutaoken))
|
||||
g := imgfactory.MergeGif(8, hutaoken)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// lick 2舔
|
||||
@@ -1273,7 +1308,7 @@ func lick(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "lick.gif"
|
||||
// name := cc.usrdir + "lick.gif"
|
||||
c := dlrange("lick", 2, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1295,7 +1330,8 @@ func lick(cc *context, value ...string) (string, error) {
|
||||
imgs[0].InsertUp(tou, 44, 44, 10, 138).Image(),
|
||||
imgs[1].InsertUp(tou, 44, 44, 10, 138).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, lick))
|
||||
g := imgfactory.MergeGif(8, lick)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// tiqiu 踢球
|
||||
@@ -1305,7 +1341,7 @@ func tiqiu(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 15
|
||||
name := cc.usrdir + "tiqiu.gif"
|
||||
// name := cc.usrdir + "tiqiu.gif"
|
||||
c := dlrange("tiqiu", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -1328,7 +1364,8 @@ func tiqiu(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
tiqiu[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-24*i), 0, 0).Image(), 0, 0, locs[i][0]+38, locs[i][1]+38).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, tiqiu))
|
||||
g := imgfactory.MergeGif(7, tiqiu)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// cai 踩
|
||||
@@ -1337,7 +1374,7 @@ func cai(cc *context, value ...string) (string, error) {
|
||||
var wg sync.WaitGroup
|
||||
var errwg error
|
||||
var m sync.Mutex
|
||||
name := cc.usrdir + "cai.gif"
|
||||
// name := cc.usrdir + "cai.gif"
|
||||
c := dlrange("cai", 5, &wg, func(e error) {
|
||||
m.Lock()
|
||||
errwg = e
|
||||
@@ -1363,7 +1400,8 @@ func cai(cc *context, value ...string) (string, error) {
|
||||
imgs[3].InsertBottom(tou, 85, 76, 52, 203).Image(),
|
||||
imgs[4].InsertBottom(tou, 88, 82, 49, 198).Image(),
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, cai))
|
||||
g := imgfactory.MergeGif(7, cai)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// whir 2转
|
||||
@@ -1373,7 +1411,7 @@ func whirl(cc *context, value ...string) (string, error) {
|
||||
var err error
|
||||
var m sync.Mutex
|
||||
piclen := 15
|
||||
name := cc.usrdir + "whirl.gif"
|
||||
// name := cc.usrdir + "whirl.gif"
|
||||
c := dlrange("whirl", piclen, &wg, func(e error) {
|
||||
m.Lock()
|
||||
err = e
|
||||
@@ -1395,7 +1433,8 @@ func whirl(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < piclen; i++ {
|
||||
whirl[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-24*i), 145, 145).Image(), 0, 0, 115, 89).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, whirl))
|
||||
g := imgfactory.MergeGif(7, whirl)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
// always 一直
|
||||
@@ -1403,8 +1442,8 @@ func alwaysDoGif(cc *context, value ...string) (string, error) {
|
||||
_ = value
|
||||
var err error
|
||||
var face []*imgfactory.Factory
|
||||
name := cc.usrdir + "AlwaysDo.gif"
|
||||
face, err = imgfactory.LoadAllFrames(cc.headimgsdir[0], 500, 500)
|
||||
// name := cc.usrdir + "AlwaysDo.gif"
|
||||
face, err = imgfactory.LoadAllTrueFrames(cc.headimgsdir[0], 500, 500)
|
||||
if err != nil {
|
||||
// 载入失败尝试载入第一帧
|
||||
face = nil
|
||||
@@ -1438,11 +1477,12 @@ func alwaysDoGif(cc *context, value ...string) (string, error) {
|
||||
canvas := gg.NewContext(500, 600)
|
||||
canvas.DrawImage(f.Image(), 0, 0)
|
||||
canvas.SetColor(color.Black)
|
||||
// _ = canvas.ParseFontFace(data, 40)
|
||||
_ = canvas.ParseFontFace(data, 40)
|
||||
canvas.DrawString(arg, 280-l, 560)
|
||||
canvas.DrawImage(imgfactory.Size(f.Image(), 90, 90).Image(), 280, 505)
|
||||
canvas.DrawString("吗", 370, 560)
|
||||
turn[i] = imgfactory.Size(canvas.Image(), 0, 0).Image()
|
||||
}
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, turn))
|
||||
g := imgfactory.MergeGif(8, turn)
|
||||
return imgfactory.GIF2Base64(g)
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ func getlist(pathOfMusic string) (list []listinfo, err error) {
|
||||
|
||||
// 遍历群文件
|
||||
func getFileURLbyFileName(ctx *zero.Ctx, fileName string) (fileSearchName, fileURL string) {
|
||||
filesOfGroup := ctx.GetThisGroupRootFiles(ctx.Event.GroupID)
|
||||
filesOfGroup := ctx.GetThisGroupRootFiles()
|
||||
files := filesOfGroup.Get("files").Array()
|
||||
folders := filesOfGroup.Get("folders").Array()
|
||||
// 遍历当前目录的文件名
|
||||
|
||||
@@ -33,7 +33,7 @@ func init() {
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "pics.db"
|
||||
_, _ = engine.GetLazyData("pics.db", false)
|
||||
err := db.Open(time.Hour * 24)
|
||||
err := db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
jiami1 = "http://ovooa.com/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.com/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
jiami1 = "http://ovooa.caonm.net/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.caonm.net/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -73,7 +73,7 @@ func init() { // 插件主体
|
||||
|
||||
go func() {
|
||||
db.DBPath = engine.DataFolder() + "config.db"
|
||||
err := db.Open(time.Hour * 24)
|
||||
err := db.Open(time.Hour)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -95,13 +95,11 @@ func init() { // 插件主体
|
||||
// 升为管理
|
||||
engine.OnRegex(`^升为管理.*?(\d+)`, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupAdmin(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupAdmin(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
true,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被升为管理的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
nickname := ctx.GetThisGroupMemberInfo( // 被升为管理的人的昵称
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
@@ -110,13 +108,11 @@ func init() { // 插件主体
|
||||
// 取消管理
|
||||
engine.OnRegex(`^取消管理.*?(\d+)`, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupAdmin(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupAdmin(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
false,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被取消管理的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
nickname := ctx.GetThisGroupMemberInfo( // 被取消管理的人的昵称
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
@@ -125,13 +121,11 @@ func init() { // 插件主体
|
||||
// 踢出群聊
|
||||
engine.OnRegex(`^踢出群聊.*?(\d+)`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupKick(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupKick(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
false,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被踢出群聊的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
nickname := ctx.GetThisGroupMemberInfo( // 被踢出群聊的人的昵称
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
@@ -148,19 +142,13 @@ func init() { // 插件主体
|
||||
// 开启全体禁言
|
||||
engine.OnRegex(`^开启全员禁言$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupWholeBan(
|
||||
ctx.Event.GroupID,
|
||||
true,
|
||||
)
|
||||
ctx.SetThisGroupWholeBan(true)
|
||||
ctx.SendChain(message.Text("全员自闭开始~"))
|
||||
})
|
||||
// 解除全员禁言
|
||||
engine.OnRegex(`^解除全员禁言$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupWholeBan(
|
||||
ctx.Event.GroupID,
|
||||
false,
|
||||
)
|
||||
ctx.SetThisGroupWholeBan(false)
|
||||
ctx.SendChain(message.Text("全员自闭结束~"))
|
||||
})
|
||||
// 禁言
|
||||
@@ -180,8 +168,7 @@ func init() { // 插件主体
|
||||
if duration >= 43200 {
|
||||
duration = 43199 // qq禁言最大时长为一个月
|
||||
}
|
||||
ctx.SetGroupBan(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupBan(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要禁言的人的qq
|
||||
duration*60, // 要禁言的时间(分钟)
|
||||
)
|
||||
@@ -190,8 +177,7 @@ func init() { // 插件主体
|
||||
// 解除禁言
|
||||
engine.OnRegex(`^解除禁言.*?(\d+)`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupBan(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupBan(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要解除禁言的人的qq
|
||||
0,
|
||||
)
|
||||
@@ -214,8 +200,7 @@ func init() { // 插件主体
|
||||
if duration >= 43200 {
|
||||
duration = 43199 // qq禁言最大时长为一个月
|
||||
}
|
||||
ctx.SetGroupBan(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupBan(
|
||||
ctx.Event.UserID,
|
||||
duration*60, // 要自闭的时间(分钟)
|
||||
)
|
||||
@@ -228,8 +213,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("名字太长啦!"))
|
||||
return
|
||||
}
|
||||
ctx.SetGroupCard(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupCard(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被修改群名片的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群名片
|
||||
)
|
||||
@@ -246,8 +230,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("头衔太长啦!"))
|
||||
return
|
||||
}
|
||||
ctx.SetGroupSpecialTitle(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupSpecialTitle(
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被修改群头衔的人
|
||||
sptitle, // 修改成的群头衔
|
||||
)
|
||||
@@ -264,8 +247,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("头衔太长啦!"))
|
||||
return
|
||||
}
|
||||
ctx.SetGroupSpecialTitle(
|
||||
ctx.Event.GroupID,
|
||||
ctx.SetThisGroupSpecialTitle(
|
||||
ctx.Event.UserID, // 被修改群头衔的人
|
||||
sptitle, // 修改成的群头衔
|
||||
)
|
||||
@@ -445,7 +427,7 @@ func init() { // 插件主体
|
||||
case <-time.After(time.Minute):
|
||||
cancel()
|
||||
ctx.SendChain(message.Text("拜拜啦~"))
|
||||
ctx.SetGroupKick(ctx.Event.GroupID, uid, false)
|
||||
ctx.SetThisGroupKick(uid, false)
|
||||
case <-recv:
|
||||
cancel()
|
||||
ctx.SendChain(message.Text("答对啦~"))
|
||||
@@ -594,7 +576,7 @@ func init() { // 插件主体
|
||||
if ok {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", true, "")
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SetGroupCard(ctx.Event.GroupID, ctx.Event.UserID, ghun)
|
||||
ctx.SetThisGroupCard(ctx.Event.UserID, ghun)
|
||||
} else {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", false, reason)
|
||||
}
|
||||
@@ -618,7 +600,7 @@ func init() { // 插件主体
|
||||
}
|
||||
})
|
||||
engine.OnCommand("精华列表", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
list := ctx.GetGroupEssenceMessageList(ctx.Event.GroupID).Array()
|
||||
list := ctx.GetThisGroupEssenceMessageList().Array()
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("本群精华列表:"))}
|
||||
n := len(list)
|
||||
if n > 30 {
|
||||
@@ -675,7 +657,7 @@ func welcometocq(ctx *zero.Ctx, welcome string) string {
|
||||
at := "[CQ:at,qq=" + uid + "]" // at用户
|
||||
avatar := "[CQ:image,file=" + "http://q4.qlogo.cn/g?b=qq&nk=" + uid + "&s=640]" // 用户头像
|
||||
gid := strconv.FormatInt(ctx.Event.GroupID, 10) // 群id
|
||||
groupname := ctx.GetGroupInfo(ctx.Event.GroupID, true).Name // 群名
|
||||
groupname := ctx.GetThisGroupInfo(true).Name // 群名
|
||||
cqstring := strings.ReplaceAll(welcome, "{at}", at)
|
||||
cqstring = strings.ReplaceAll(cqstring, "{nickname}", nickname)
|
||||
cqstring = strings.ReplaceAll(cqstring, "{avatar}", avatar)
|
||||
|
||||
@@ -25,6 +25,8 @@ var speakers = map[string]uint{
|
||||
"派蒙": 0, "凯亚": 1, "安柏": 2, "丽莎": 3, "琴": 4, "香菱": 5, "枫原万叶": 6, "迪卢克": 7, "温迪": 8, "可莉": 9, "早柚": 10, "托马": 11, "芭芭拉": 12, "优菈": 13, "云堇": 14, "钟离": 15, "魈": 16, "凝光": 17, "雷电将军": 18, "北斗": 19, "甘雨": 20, "七七": 21, "刻晴": 22, "神里绫华": 23, "戴因斯雷布": 24, "雷泽": 25, "神里绫人": 26, "罗莎莉亚": 27, "阿贝多": 28, "八重神子": 29, "宵宫": 30, "荒泷一斗": 31, "九条裟罗": 32, "夜兰": 33, "珊瑚宫心海": 34, "五郎": 35, "散兵": 36, "女士": 37, "达达利亚": 38, "莫娜": 39, "班尼特": 40, "申鹤": 41, "行秋": 42, "烟绯": 43, "久岐忍": 44, "辛焱": 45, "砂糖": 46, "胡桃": 47, "重云": 48, "菲谢尔": 49, "诺艾尔": 50, "迪奥娜": 51, "鹿野院平藏": 52,
|
||||
}
|
||||
|
||||
var 原 = newapikeystore("./data/tts/o.txt")
|
||||
|
||||
func init() {
|
||||
en := control.Register("moegoe", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
@@ -47,21 +49,11 @@ func init() {
|
||||
})
|
||||
en.OnRegex("^让(派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if 原.k == "" {
|
||||
return
|
||||
}
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
c, ok := control.Lookup("tts")
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("ERROR: plugin tts not found"))
|
||||
return
|
||||
}
|
||||
var key struct {
|
||||
APIKey string
|
||||
}
|
||||
err := c.Manager.GetExtra(-1, &key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(genshin.CNAPI, id, url.QueryEscape(text), url.QueryEscape(key.APIKey))))
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(genshin.CNAPI, id, url.QueryEscape(text), url.QueryEscape(原.k))))
|
||||
})
|
||||
}
|
||||
|
||||
24
plugin/moegoe/model.go
Normal file
24
plugin/moegoe/model.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package moegoe
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
type apikeystore struct {
|
||||
k string
|
||||
p string
|
||||
}
|
||||
|
||||
func newapikeystore(p string) (s apikeystore) {
|
||||
s.p = p
|
||||
if file.IsExist(p) {
|
||||
data, err := os.ReadFile(p)
|
||||
if err == nil {
|
||||
s.k = binary.BytesToString(data)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (n *nsetu) scanall(path string) error {
|
||||
root := os.DirFS(path)
|
||||
_ = n.db.Close()
|
||||
_ = os.Remove(n.db.DBPath)
|
||||
err := n.db.Open(time.Hour * 24)
|
||||
err := n.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func init() {
|
||||
logrus.Infoln("[nsetu] set setu dir to", setupath)
|
||||
}
|
||||
}
|
||||
err := ns.db.Open(time.Hour * 24)
|
||||
err := ns.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/antchfx/htmlquery"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -42,12 +43,14 @@ const (
|
||||
var (
|
||||
cachePath string
|
||||
// apikey 由账号和密码拼接而成, 例: zerobot,123456
|
||||
apikey string
|
||||
apikey string
|
||||
apikeymu sync.Mutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("novel", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Extra: control.ExtraFromString("novel"),
|
||||
Brief: "铅笔小说网搜索",
|
||||
Help: "- 小说[xxx]\n" +
|
||||
"- 设置小说配置 zerobot 123456\n" +
|
||||
@@ -290,16 +293,19 @@ func download(id string, cookie string) (downloadHTML string, err error) {
|
||||
}
|
||||
|
||||
func getAPIKey(ctx *zero.Ctx) string {
|
||||
apikeymu.Lock()
|
||||
defer apikeymu.Unlock()
|
||||
if apikey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(-1, &apikey)
|
||||
_ = m.GetExtra(&apikey)
|
||||
logrus.Debugln("[novel] get api key:", apikey)
|
||||
}
|
||||
return apikey
|
||||
}
|
||||
|
||||
func setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
apikeymu.Lock()
|
||||
defer apikeymu.Unlock()
|
||||
apikey = key
|
||||
_ = m.Manager.Response(-1)
|
||||
return m.Manager.SetExtra(-1, apikey)
|
||||
return m.SetExtra(apikey)
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -82,7 +82,7 @@ var (
|
||||
))
|
||||
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
民政局.db.DBPath = engine.DataFolder() + "结婚登记表.db"
|
||||
err := 民政局.db.Open(time.Hour * 24)
|
||||
err := 民政局.db.Open(time.Hour)
|
||||
if err == nil {
|
||||
// 创建群配置表
|
||||
err = 民政局.db.Create("updateinfo", &updateinfo{})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package quan
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -11,13 +11,18 @@ import (
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
const (
|
||||
quan = "http://tc.tfkapi.top/API/qqqz.php?qq=%v" // api
|
||||
quan = "http://tfapi.top/API/qqqz.php?type=json&qq=" // api
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Qz string `json:"qz"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.Register("quan", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
@@ -31,28 +36,25 @@ func init() { // 主函数
|
||||
if str == "" { // user
|
||||
str = strconv.FormatInt(ctx.Event.UserID, 10)
|
||||
}
|
||||
es, err := web.GetData(fmt.Sprintf(quan, str)) // 将网站返回结果赋值
|
||||
es, err := web.GetData(quan + str) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
ctx.SendChain(message.Text("出现错误捏: ", err))
|
||||
return
|
||||
}
|
||||
if len(helper.BytesToString(es)) <= 24 {
|
||||
ctx.SendChain(message.Text("网站维护中")) // 输出结果
|
||||
return
|
||||
}
|
||||
f := helper.BytesToString(es)[24:]
|
||||
_, err = strconv.Atoi(f)
|
||||
var data result
|
||||
err = json.Unmarshal(es, &data)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("网站维护中")) // 输出结果
|
||||
ctx.SendChain(message.Text("解析json错误: ", err))
|
||||
return
|
||||
}
|
||||
var msg strings.Builder
|
||||
msg.WriteString("查询账号:")
|
||||
msg.WriteString("查询账号: ")
|
||||
msg.WriteString(str)
|
||||
msg.WriteString("\n")
|
||||
msg.WriteString("查询状态:成功\n")
|
||||
msg.WriteString("您的权重为:")
|
||||
msg.WriteString(f)
|
||||
msg.WriteString("查询状态: ")
|
||||
msg.WriteString(data.Msg)
|
||||
msg.WriteString("\n您的权重为: ")
|
||||
msg.WriteString(data.Qz)
|
||||
ctx.SendChain(message.Text(msg.String())) // 输出结果
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var ro = runoob.NewRunOOB("b6365362a90ac2ac7098ba52c13e352b")
|
||||
var ro = runoob.NewRunOOB("066417defb80d038228de76ec581a50a")
|
||||
|
||||
func init() {
|
||||
control.Register("runcode", &ctrl.Options[*zero.Ctx]{
|
||||
@@ -59,7 +59,7 @@ func init() {
|
||||
} else {
|
||||
// 运行成功
|
||||
output = cutTooLong(strings.Trim(output, "\n"))
|
||||
if israw {
|
||||
if israw && zero.AdminPermission(ctx) {
|
||||
ctx.SendChain(message.Text(output))
|
||||
} else {
|
||||
ctx.SendChain(
|
||||
|
||||
@@ -162,27 +162,27 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("请私聊发送 设置 saucenao api key [apikey] 以启用 saucenao 搜图 (方括号不需要输入), key 请前往 https://saucenao.com/user.php?page=search-api 获取"))
|
||||
}
|
||||
// ascii2d 搜索
|
||||
if result, err := ascii2d.ASCII2d(pic); err != nil {
|
||||
result, err := ascii2d.ASCII2d(pic)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
continue
|
||||
} else {
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("ascii2d搜图结果"))}
|
||||
for i := 0; i < len(result) && i < 5; i++ {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image(result[i].Thumb),
|
||||
message.Text(fmt.Sprintf(
|
||||
"标题: %s\n图源: %s\n画师: %s\n画师链接: %s\n图片链接: %s",
|
||||
result[i].Name,
|
||||
result[i].Type,
|
||||
result[i].AuthNm,
|
||||
result[i].Author,
|
||||
result[i].Link,
|
||||
))),
|
||||
)
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
}
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("ascii2d搜图结果"))}
|
||||
for i := 0; i < len(result) && i < 5; i++ {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image(result[i].Thumb),
|
||||
message.Text(fmt.Sprintf(
|
||||
"标题: %s\n图源: %s\n画师: %s\n画师链接: %s\n图片链接: %s",
|
||||
result[i].Name,
|
||||
result[i].Type,
|
||||
result[i].AuthNm,
|
||||
result[i].Author,
|
||||
result[i].Link,
|
||||
))),
|
||||
)
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
492
plugin/score/draw.go
Normal file
492
plugin/score/draw.go
Normal file
@@ -0,0 +1,492 @@
|
||||
// Package score 签到
|
||||
package score
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/rendercard"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/disintegration/imaging"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
type scoredrawer func(a *scdata) (image.Image, error)
|
||||
|
||||
func drawScore16(a *scdata) (image.Image, error) {
|
||||
// 绘图
|
||||
getAvatar, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
imgDX := back.Bounds().Dx()
|
||||
imgDY := back.Bounds().Dy()
|
||||
canvas := gg.NewContext(imgDX, imgDY)
|
||||
// draw Aero Style
|
||||
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
|
||||
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
|
||||
// aero draw image.
|
||||
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
|
||||
// SideLine
|
||||
aeroStyle.SetLineWidth(3)
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 100)
|
||||
aeroStyle.StrokePreserve()
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 140)
|
||||
// fill
|
||||
aeroStyle.Fill()
|
||||
// draw background
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
// Aero style combine
|
||||
canvas.DrawImage(aeroStyle.Image(), 100, 100)
|
||||
canvas.Fill()
|
||||
hourWord := getHourWord(time.Now())
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 200, 200)
|
||||
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
|
||||
// draw info(name,coin,etc)
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 50); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// draw head
|
||||
canvas.DrawStringWrapped(a.nickname, 350, 180, 0.5, 0.5, 0.5, 0.5, gg.AlignLeft)
|
||||
canvas.Fill()
|
||||
// main draw
|
||||
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), 350, 350, 0, 0)
|
||||
canvas.DrawStringAnchored("当前ATRI币:"+strconv.Itoa(a.score), 350, 400, 0, 0)
|
||||
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(a.level)), 350, 450, 0, 0)
|
||||
// draw Info(Time,etc.)
|
||||
getTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
|
||||
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
|
||||
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
canvas.Fill()
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
// Gradient
|
||||
grad := gg.NewLinearGradient(20, 320, 400, 20)
|
||||
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
|
||||
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
|
||||
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
|
||||
canvas.SetStrokeStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
// level array with rectangle work.
|
||||
gradLineLength := float64(imgDX-120) - 120
|
||||
renderLine := (float64(a.level) / float64(nextrankScore)) * gradLineLength
|
||||
canvas.MoveTo(120, float64(imgDY)-102)
|
||||
canvas.LineTo(120+renderLine, float64(imgDY)-102)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
|
||||
func drawScore15(a *scdata) (image.Image, error) {
|
||||
// 绘图
|
||||
_, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7))
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
canvas.Clear()
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
monthWord := time.Now().Format("01/02")
|
||||
hourWord := getHourWord(time.Now())
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, float64(back.Bounds().Size().X)*0.1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2)
|
||||
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2)
|
||||
_, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.FontFile, float64(back.Bounds().Size().X)*0.04); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawString(a.nickname+fmt.Sprintf(" ATRI币+%d", a.inc), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
|
||||
canvas.DrawString("当前ATRI币:"+strconv.FormatInt(int64(a.score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4)
|
||||
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(a.rank), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(150, 150, 150)
|
||||
canvas.Fill()
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(a.level)/float64(nextrankScore), float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(102, 102, 102)
|
||||
canvas.Fill()
|
||||
canvas.DrawString(fmt.Sprintf("%d/%d", a.level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
|
||||
func drawScore17(a *scdata) (image.Image, error) {
|
||||
getAvatar, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
imgDX := back.Bounds().Dx()
|
||||
imgDY := back.Bounds().Dy()
|
||||
canvas := gg.NewContext(imgDX, imgDY)
|
||||
|
||||
// draw background
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
|
||||
// Create smaller Aero Style boxes
|
||||
createAeroBox := func(x, y, width, height float64) {
|
||||
aeroStyle := gg.NewContext(int(width), int(height))
|
||||
aeroStyle.DrawRoundedRectangle(0, 0, width, height, 8)
|
||||
aeroStyle.SetLineWidth(2)
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 100)
|
||||
aeroStyle.StrokePreserve()
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 140)
|
||||
aeroStyle.Fill()
|
||||
canvas.DrawImage(aeroStyle.Image(), int(x), int(y))
|
||||
}
|
||||
|
||||
// draw aero boxes for text
|
||||
createAeroBox(20, float64(imgDY-120), 280, 100) // left bottom
|
||||
createAeroBox(float64(imgDX-272), float64(imgDY-60), 252, 40) // right bottom
|
||||
|
||||
// draw info(name, coin, etc)
|
||||
hourWord := getHourWord(time.Now())
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
data, err := file.GetLazyData(text.MaokenFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 24); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getNameLengthWidth, _ := canvas.MeasureString(a.nickname)
|
||||
// draw aero box
|
||||
if getNameLengthWidth > 140 {
|
||||
createAeroBox(20, 40, 140+getNameLengthWidth, 100) // left top
|
||||
} else {
|
||||
createAeroBox(20, 40, 280, 100) // left top
|
||||
}
|
||||
|
||||
// draw avatar
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 100, 100)
|
||||
canvas.DrawImage(avatarf.Circle(0).Image(), 30, 20)
|
||||
|
||||
canvas.DrawString(a.nickname, 140, 80)
|
||||
canvas.DrawStringAnchored(hourWord, 140, 120, 0, 0)
|
||||
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), 40, float64(imgDY-90), 0, 0)
|
||||
canvas.DrawStringAnchored("当前ATRI币:"+strconv.Itoa(a.score), 40, float64(imgDY-60), 0, 0)
|
||||
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(a.level)), 40, float64(imgDY-30), 0, 0)
|
||||
|
||||
// Draw Info(Time, etc.)
|
||||
getTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
canvas.DrawStringAnchored(getTime, float64(imgDX)-146, float64(imgDY)-40, 0.5, 0.5) // time
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, 190, float64(imgDY-30), 0, 0) // time
|
||||
|
||||
// Draw Zerobot-Plugin information
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
|
||||
func drawScore17b2(a *scdata) (img image.Image, err error) {
|
||||
fontdata, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
getAvatar, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bx, by := float64(back.Bounds().Dx()), float64(back.Bounds().Dy())
|
||||
|
||||
sc := 1280 / bx
|
||||
|
||||
colors := gg.TakeColor(back, 3)
|
||||
|
||||
canvas := gg.NewContext(1280, 1280*int(by)/int(bx))
|
||||
|
||||
cw, ch := float64(canvas.W()), float64(canvas.H())
|
||||
|
||||
sch := ch * 6 / 10
|
||||
|
||||
var blurback, scbackimg, backshadowimg, avatarimg, avatarbackimg, avatarshadowimg, whitetext, blacktext image.Image
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(8)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
scback := gg.NewContext(canvas.W(), canvas.H())
|
||||
scback.ScaleAbout(sc, sc, cw/2, ch/2)
|
||||
scback.DrawImageAnchored(back, canvas.W()/2, canvas.H()/2, 0.5, 0.5)
|
||||
scback.Identity()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
blurback = imaging.Blur(scback.Image(), 20)
|
||||
}()
|
||||
|
||||
scbackimg = rendercard.Fillet(scback.Image(), 12)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
pureblack := gg.NewContext(canvas.W(), canvas.H())
|
||||
pureblack.SetRGBA255(0, 0, 0, 255)
|
||||
pureblack.Clear()
|
||||
|
||||
shadow := gg.NewContext(canvas.W(), canvas.H())
|
||||
shadow.ScaleAbout(0.6, 0.6, cw-cw/3, ch/2)
|
||||
shadow.DrawImageAnchored(pureblack.Image(), canvas.W()-canvas.W()/3, canvas.H()/2, 0.5, 0.5)
|
||||
shadow.Identity()
|
||||
|
||||
backshadowimg = imaging.Blur(shadow.Image(), 8)
|
||||
}()
|
||||
|
||||
aw, ah := (ch-sch)/2/2/2*3, (ch-sch)/2/2/2*3
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
isc := (ch - sch) / 2 / 2 / 2 * 3 / float64(avatar.Bounds().Dy())
|
||||
|
||||
scavatar := gg.NewContext(int(aw), int(ah))
|
||||
|
||||
scavatar.ScaleAbout(isc, isc, aw/2, ah/2)
|
||||
scavatar.DrawImageAnchored(avatar, scavatar.W()/2, scavatar.H()/2, 0.5, 0.5)
|
||||
scavatar.Identity()
|
||||
|
||||
avatarimg = rendercard.Fillet(scavatar.Image(), 8)
|
||||
}()
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
namew, _ := canvas.MeasureString(a.nickname)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
avatarshadowimg = imaging.Blur(customrectangle(cw, ch, aw, ah, namew, color.Black), 8)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
avatarbackimg = customrectangle(cw, ch, aw, ah, namew, colors[0])
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
whitetext, err = customtext(a, fontdata, cw, ch, aw, color.White)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
blacktext, err = customtext(a, fontdata, cw, ch, aw, color.Black)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
if scbackimg == nil || backshadowimg == nil || avatarimg == nil || avatarbackimg == nil || avatarshadowimg == nil || whitetext == nil || blacktext == nil {
|
||||
err = errors.New("图片渲染失败")
|
||||
return
|
||||
}
|
||||
|
||||
canvas.DrawImageAnchored(blurback, canvas.W()/2, canvas.H()/2, 0.5, 0.5)
|
||||
|
||||
canvas.DrawImage(backshadowimg, 0, 0)
|
||||
|
||||
canvas.ScaleAbout(0.6, 0.6, cw-cw/3, ch/2)
|
||||
canvas.DrawImageAnchored(scbackimg, canvas.W()-canvas.W()/3, canvas.H()/2, 0.5, 0.5)
|
||||
canvas.Identity()
|
||||
|
||||
canvas.DrawImage(avatarshadowimg, 0, 0)
|
||||
canvas.DrawImage(avatarbackimg, 0, 0)
|
||||
canvas.DrawImageAnchored(avatarimg, int((ch-sch)/2/2), int((ch-sch)/2/2), 0.5, 0.5)
|
||||
|
||||
canvas.DrawImage(blacktext, 2, 2)
|
||||
canvas.DrawImage(whitetext, 0, 0)
|
||||
|
||||
img = canvas.Image()
|
||||
return
|
||||
}
|
||||
|
||||
func customrectangle(cw, ch, aw, ah, namew float64, rtgcolor color.Color) (img image.Image) {
|
||||
canvas := gg.NewContext(int(cw), int(ch))
|
||||
sch := ch * 6 / 10
|
||||
canvas.DrawRoundedRectangle((ch-sch)/2/2-aw/2-aw/40, (ch-sch)/2/2-aw/2-ah/40, aw+aw/40*2, ah+ah/40*2, 8)
|
||||
canvas.SetColor(rtgcolor)
|
||||
canvas.Fill()
|
||||
canvas.DrawRoundedRectangle((ch-sch)/2/2, (ch-sch)/2/2-ah/4, aw/2+aw/40*5+namew, ah/2, 8)
|
||||
canvas.Fill()
|
||||
|
||||
img = canvas.Image()
|
||||
return
|
||||
}
|
||||
|
||||
func customtext(a *scdata, fontdata []byte, cw, ch, aw float64, textcolor color.Color) (img image.Image, err error) {
|
||||
canvas := gg.NewContext(int(cw), int(ch))
|
||||
canvas.SetColor(textcolor)
|
||||
scw, sch := cw*6/10, ch*6/10
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
canvas.DrawStringAnchored(a.nickname, (ch-sch)/2/2+aw/2+aw/40*2, (ch-sch)/2/2, 0, 0.5)
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/3*2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
canvas.DrawStringAnchored(time.Now().Format("2006/01/02"), cw-cw/6, ch/2-sch/2-canvas.FontHeight(), 0.5, 0.5)
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nextrankScore := 0
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
|
||||
|
||||
canvas.DrawStringAnchored("Level "+strconv.Itoa(a.rank), cw/3*2-scw/2, ch/2+sch/2+canvas.FontHeight(), 0, 0.5)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, cw/3*2+scw/2, ch/2+sch/2+canvas.FontHeight(), 1, 0.5)
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/2/3)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
canvas.DrawStringAnchored("Create By ZeroBot-Plugin "+banner.Version, 0+4, ch, 0, -0.5)
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/5*3)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tempfh := canvas.FontHeight()
|
||||
|
||||
canvas.DrawStringAnchored(getHourWord(time.Now()), ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4, 0, 0.5)
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/5)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4+tempfh, 0, 0.5)
|
||||
canvas.DrawStringAnchored("EXP + 1", ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4+tempfh+canvas.FontHeight(), 0, 1)
|
||||
|
||||
err = canvas.ParseFontFace(fontdata, (ch-sch)/2/4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
canvas.DrawStringAnchored("你有 "+strconv.Itoa(a.score)+" 枚ATRI币", ((cw-scw)-(cw/3-scw/2))/8, (ch-sch)/2+sch/4*3, 0, 0.5)
|
||||
|
||||
img = canvas.Image()
|
||||
return
|
||||
}
|
||||
@@ -122,3 +122,14 @@ func (sdb *scoredb) GetScoreRankByTopN(n int) (st []scoretable, err error) {
|
||||
err = db.Model(&scoretable{}).Order("score desc").Limit(n).Find(&st).Error
|
||||
return
|
||||
}
|
||||
|
||||
type scdata struct {
|
||||
drawedfile string
|
||||
picfile string
|
||||
uid int64
|
||||
nickname string
|
||||
inc int // 增加币
|
||||
score int // 钱包
|
||||
level int
|
||||
rank int
|
||||
}
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
// Package score 签到,答题得分
|
||||
// Package score 签到
|
||||
package score
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/AnimeAPI/wallet"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
@@ -45,200 +38,146 @@ var (
|
||||
engine = control.Register("score", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "签到",
|
||||
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
|
||||
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 设置签到预设(0~3)\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
|
||||
PrivateDataFolder: "score",
|
||||
})
|
||||
styles = []scoredrawer{
|
||||
drawScore15,
|
||||
drawScore16,
|
||||
drawScore17,
|
||||
drawScore17b2,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
go func() {
|
||||
_ = os.RemoveAll(cachePath)
|
||||
err := os.MkdirAll(cachePath, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
ok := file.IsExist(cachePath)
|
||||
if !ok {
|
||||
err := os.MkdirAll(cachePath, 0777)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(cachePath)
|
||||
if err == nil {
|
||||
for _, f := range files {
|
||||
if !strings.Contains(f.Name(), time.Now().Format("20060102")) {
|
||||
_ = os.Remove(cachePath + f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
sdb = initialize(engine.DataFolder() + "score.db")
|
||||
}()
|
||||
engine.OnFullMatch("签到").Limit(ctxext.LimitByUser).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
uid := ctx.Event.UserID
|
||||
now := time.Now()
|
||||
today := now.Format("20060102")
|
||||
// 签到图片
|
||||
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
|
||||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
|
||||
// 获取签到时间
|
||||
si := sdb.GetSignInByUID(uid)
|
||||
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
|
||||
switch {
|
||||
case si.Count >= signinMax && siUpdateTimeStr == today:
|
||||
// 如果签到时间是今天
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
}
|
||||
return
|
||||
case siUpdateTimeStr != today:
|
||||
// 如果是跨天签到就清数据
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
// 更新签到次数
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
|
||||
engine.OnRegex(`^签到\s?(\d*)$`).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
// 选择key
|
||||
key := ctx.State["regex_matched"].([]string)[1]
|
||||
gid := ctx.Event.GroupID
|
||||
if gid < 0 {
|
||||
// 个人用户设为负数
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
k := uint8(0)
|
||||
if key == "" {
|
||||
k = uint8(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).GetData(gid))
|
||||
} else {
|
||||
kn, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新经验
|
||||
level := sdb.GetScoreByUID(uid).Score + 1
|
||||
if level > SCOREMAX {
|
||||
level = SCOREMAX
|
||||
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
|
||||
k = uint8(kn)
|
||||
}
|
||||
if int(k) >= len(styles) {
|
||||
ctx.SendChain(message.Text("ERROR: 未找到签到设定: ", key))
|
||||
return
|
||||
}
|
||||
uid := ctx.Event.UserID
|
||||
today := time.Now().Format("20060102")
|
||||
// 签到图片
|
||||
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
|
||||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
|
||||
// 获取签到时间
|
||||
si := sdb.GetSignInByUID(uid)
|
||||
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
|
||||
switch {
|
||||
case si.Count >= signinMax && siUpdateTimeStr == today:
|
||||
// 如果签到时间是今天
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
}
|
||||
err = sdb.InsertOrUpdateScoreByUID(uid, level)
|
||||
return
|
||||
case siUpdateTimeStr != today:
|
||||
// 如果是跨天签到就清数据
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新钱包
|
||||
rank := getrank(level)
|
||||
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
|
||||
}
|
||||
// 更新签到次数
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新经验
|
||||
level := sdb.GetScoreByUID(uid).Score + 1
|
||||
if level > SCOREMAX {
|
||||
level = SCOREMAX
|
||||
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
|
||||
}
|
||||
err = sdb.InsertOrUpdateScoreByUID(uid, level)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新钱包
|
||||
rank := getrank(level)
|
||||
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
|
||||
go func() {
|
||||
err = wallet.InsertWalletOf(uid, add)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
score := wallet.GetWalletOf(uid)
|
||||
// 绘图
|
||||
getAvatar, err := initPic(picFile, uid)
|
||||
}()
|
||||
alldata := &scdata{
|
||||
drawedfile: drawedFile,
|
||||
picfile: picFile,
|
||||
uid: uid,
|
||||
nickname: ctx.CardOrNickName(uid),
|
||||
inc: add,
|
||||
score: wallet.GetWalletOf(uid),
|
||||
level: level,
|
||||
rank: rank,
|
||||
}
|
||||
drawimage, err := styles[k](alldata)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// done.
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
data, err := imgfactory.ToBytes(drawimage)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back, err := gg.LoadImage(picFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
imgDX := back.Bounds().Dx()
|
||||
imgDY := back.Bounds().Dy()
|
||||
canvas := gg.NewContext(imgDX, imgDY)
|
||||
// draw Aero Style
|
||||
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
|
||||
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
|
||||
// aero draw image.
|
||||
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
|
||||
// SideLine
|
||||
aeroStyle.SetLineWidth(3)
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 100)
|
||||
aeroStyle.StrokePreserve()
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 140)
|
||||
// fill
|
||||
aeroStyle.Fill()
|
||||
// draw background
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
// Aero style combine
|
||||
canvas.DrawImage(aeroStyle.Image(), 100, 100)
|
||||
canvas.Fill()
|
||||
hourWord := getHourWord(now)
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 200, 200)
|
||||
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
|
||||
// draw info(name,coin,etc)
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 50); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// draw head
|
||||
nickName := ctx.CardOrNickName(uid)
|
||||
canvas.DrawString(nickName, 350, 180)
|
||||
canvas.Fill()
|
||||
// main draw
|
||||
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(add), 350, 350, 0, 0)
|
||||
canvas.DrawStringAnchored("当前ATRI币:"+strconv.Itoa(score), 350, 400, 0, 0)
|
||||
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(level)), 350, 450, 0, 0)
|
||||
// draw Info(Time,etc.)
|
||||
getTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
|
||||
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
var nextrankScore int
|
||||
if rank < 10 {
|
||||
nextrankScore = rankArray[rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(level) + "/" + strconv.Itoa(nextrankScore)
|
||||
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
canvas.Fill()
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
// Gradient
|
||||
grad := gg.NewLinearGradient(20, 320, 400, 20)
|
||||
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
|
||||
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
|
||||
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
|
||||
canvas.SetStrokeStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
// level array with rectangle work.
|
||||
gradLineLength := float64(imgDX-120) - 120
|
||||
renderLine := (float64(level) / float64(nextrankScore)) * gradLineLength
|
||||
canvas.MoveTo(120, float64(imgDY)-102)
|
||||
canvas.LineTo(120+renderLine, float64(imgDY)-102)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
// done.
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
data, err := imgfactory.ToBytes(canvas.Image())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
return
|
||||
}
|
||||
_, err = imgfactory.WriteTo(canvas.Image(), f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
return
|
||||
}
|
||||
_, err = imgfactory.WriteTo(drawimage, f)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
engine.OnPrefix("获得签到背景", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -254,7 +193,9 @@ func init() {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请先签到!"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile))
|
||||
if id := ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 消息发送失败, 账号可能被风控"))
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch("查看等级排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -328,6 +269,29 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
engine.OnRegex(`^设置签到预设\s*(\d+)$`, zero.SuperUserPermission).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
key := ctx.State["regex_matched"].([]string)[1]
|
||||
kn, err := strconv.Atoi(key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
k := uint8(kn)
|
||||
if int(k) >= len(styles) {
|
||||
ctx.SendChain(message.Text("ERROR: 未找到签到设定: ", key))
|
||||
return
|
||||
}
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
err = ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).SetData(gid, int64(k))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("设置成功"))
|
||||
})
|
||||
}
|
||||
|
||||
func getHourWord(t time.Time) string {
|
||||
@@ -360,21 +324,21 @@ func getrank(count int) int {
|
||||
}
|
||||
|
||||
func initPic(picFile string, uid int64) (avatar []byte, err error) {
|
||||
if file.IsExist(picFile) {
|
||||
return nil, nil
|
||||
}
|
||||
defer process.SleepAbout1sTo2s()
|
||||
avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if file.IsExist(picFile) {
|
||||
return
|
||||
}
|
||||
url, err := bilibili.GetRealURL(backgroundURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
return avatar, os.WriteFile(picFile, data, 0644)
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func init() { // 插件主体
|
||||
// 如果数据库不存在则下载
|
||||
pool.db.DBPath = engine.DataFolder() + "SetuTime.db"
|
||||
_, _ = engine.GetLazyData("SetuTime.db", false)
|
||||
err := pool.db.Open(time.Hour * 24)
|
||||
err := pool.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
@@ -236,10 +236,7 @@ func (p *imgpool) add(ctx *zero.Ctx, imgtype string, id int64) error {
|
||||
return err
|
||||
}
|
||||
// 添加插画到对应的数据库table
|
||||
if err := p.db.Insert(imgtype, illust); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return p.db.Insert(imgtype, illust)
|
||||
}
|
||||
|
||||
func (p *imgpool) remove(imgtype string, id int64) error {
|
||||
|
||||
@@ -20,13 +20,13 @@ func init() {
|
||||
Help: "- 今天是什么少女[@xxx]\n" +
|
||||
"- 异世界转生[@xxx]\n" +
|
||||
"- 卖萌[@xxx]\n" +
|
||||
"- 抽老婆[@xxx]\n" +
|
||||
"- 今日老婆[@xxx]\n" +
|
||||
"- 黄油角色[@xxx]",
|
||||
})
|
||||
engine.OnPrefix("异世界转生", number(587874)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
engine.OnPrefix("今天是什么少女", number(162207)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
engine.OnPrefix("卖萌", number(360578)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handletxt)
|
||||
engine.OnPrefix("抽老婆", number(1075116)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlecq)
|
||||
engine.OnPrefix("今日老婆", number(1075116)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlecq)
|
||||
engine.OnPrefix("黄油角色", number(1115465)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
}
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ func timeDuration(time time.Duration) (hour, minute, second int64) {
|
||||
}
|
||||
|
||||
// 只统计6点到12点的早安
|
||||
func isMorning(ctx *zero.Ctx) bool {
|
||||
func isMorning(*zero.Ctx) bool {
|
||||
now := time.Now().Hour()
|
||||
return now >= 6 && now <= 12
|
||||
}
|
||||
|
||||
// 只统计21点到凌晨3点的晚安
|
||||
func isEvening(ctx *zero.Ctx) bool {
|
||||
func isEvening(*zero.Ctx) bool {
|
||||
now := time.Now().Hour()
|
||||
return now >= 21 || now <= 3
|
||||
}
|
||||
|
||||
142
plugin/steam/listenter.go
Normal file
142
plugin/steam/listenter.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package steam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
// ----------------------- 远程调用 ----------------------
|
||||
const (
|
||||
apiurl = "https://api.steampowered.com/" // steam API 调用地址
|
||||
statusurl = "ISteamUser/GetPlayerSummaries/v2/?key=%+v&steamids=%+v" // 根据用户steamID获取用户状态
|
||||
)
|
||||
|
||||
var (
|
||||
apiKey string
|
||||
apiKeyMu sync.Mutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine.OnRegex(`^steam绑定\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
apiKeyMu.Lock()
|
||||
defer apiKeyMu.Unlock()
|
||||
apiKey = ctx.State["regex_matched"].([]string)[1]
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
err := m.SetExtra(apiKey)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 保存apikey失败!"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("保存apikey成功!"))
|
||||
})
|
||||
engine.OnFullMatch("查看apikey", zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
apiKeyMu.Lock()
|
||||
defer apiKeyMu.Unlock()
|
||||
ctx.SendChain(message.Text("apikey为: ", apiKey))
|
||||
})
|
||||
engine.OnFullMatch("拉取steam订阅", getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
// 获取所有处于监听状态的用户信息
|
||||
infos, err := database.findAll()
|
||||
if err != nil {
|
||||
// 挂了就给管理员发消息
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(infos) == 0 {
|
||||
return
|
||||
}
|
||||
// 收集这波用户的streamId,然后查当前的状态,并建立信息映射表
|
||||
streamIds := make([]string, len(infos))
|
||||
localPlayerMap := make(map[int64]*player)
|
||||
for i := 0; i < len(infos); i++ {
|
||||
streamIds[i] = strconv.FormatInt(infos[i].SteamID, 10)
|
||||
localPlayerMap[infos[i].SteamID] = infos[i]
|
||||
}
|
||||
// 将所有用户状态查一遍
|
||||
playerStatus, err := getPlayerStatus(streamIds...)
|
||||
if err != nil {
|
||||
// 出错就发消息
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 遍历返回的信息做对比,假如信息有变化则发消息
|
||||
now := time.Now()
|
||||
msg := make(message.Message, 0, len(playerStatus))
|
||||
for _, playerInfo := range playerStatus {
|
||||
msg = msg[:0]
|
||||
localInfo := localPlayerMap[playerInfo.SteamID]
|
||||
// 排除不需要处理的情况
|
||||
if localInfo.GameID == 0 && playerInfo.GameID == 0 {
|
||||
continue
|
||||
}
|
||||
// 打开游戏
|
||||
if localInfo.GameID == 0 && playerInfo.GameID != 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "正在玩", playerInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = now.Unix()
|
||||
}
|
||||
// 更换游戏
|
||||
if localInfo.GameID != 0 && playerInfo.GameID != localInfo.GameID && playerInfo.GameID != 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 丢下了", localInfo.GameExtraInfo, ", 转头去玩", playerInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = now.Unix()
|
||||
}
|
||||
// 关闭游戏
|
||||
if playerInfo.GameID != localInfo.GameID && playerInfo.GameID == 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 关掉了", localInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = 0
|
||||
}
|
||||
if len(msg) != 0 {
|
||||
groups := strings.Split(localInfo.Target, ",")
|
||||
for _, groupString := range groups {
|
||||
group, err := strconv.ParseInt(groupString, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nOTHER: SteamID ", localInfo.SteamID))
|
||||
continue
|
||||
}
|
||||
ctx.SendGroupMessage(group, msg)
|
||||
}
|
||||
}
|
||||
// 更新数据
|
||||
localInfo.GameID = playerInfo.GameID
|
||||
localInfo.GameExtraInfo = playerInfo.GameExtraInfo
|
||||
if err = database.update(localInfo); err != nil {
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据失败\nOTHER: SteamID ", localInfo.SteamID))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// getPlayerStatus 获取用户状态
|
||||
func getPlayerStatus(streamIds ...string) ([]*player, error) {
|
||||
players := make([]*player, 0)
|
||||
// 拼接请求地址
|
||||
apiKeyMu.Lock()
|
||||
url := fmt.Sprintf(apiurl+statusurl, apiKey, strings.Join(streamIds, ","))
|
||||
apiKeyMu.Unlock()
|
||||
// 拉取并解析数据
|
||||
data, err := web.GetData(url)
|
||||
if err != nil {
|
||||
return players, err
|
||||
}
|
||||
dataStr := binary.BytesToString(data)
|
||||
index := gjson.Get(dataStr, "response.players.#").Uint()
|
||||
for i := uint64(0); i < index; i++ {
|
||||
players = append(players, &player{
|
||||
SteamID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.steamid", i)).Int(),
|
||||
PersonaName: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.personaname", i)).String(),
|
||||
GameID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameid", i)).Int(),
|
||||
GameExtraInfo: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameextrainfo", i)).String(),
|
||||
})
|
||||
}
|
||||
return players, nil
|
||||
}
|
||||
159
plugin/steam/steam.go
Normal file
159
plugin/steam/steam.go
Normal file
@@ -0,0 +1,159 @@
|
||||
// Package steam 获取steam用户状态
|
||||
package steam
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
engine = control.Register("steam", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Extra: control.ExtraFromString("steam"),
|
||||
Brief: "steam相关插件",
|
||||
Help: "- steam添加订阅 xxxxxxx (可输入需要绑定的 steamid)\n" +
|
||||
"- steam删除订阅 xxxxxxx (删除你创建的对于 steamid 的绑定)\n" +
|
||||
"- steam查询订阅 (查询本群内所有的绑定对象)\n" +
|
||||
"-----------------------\n" +
|
||||
"- steam绑定 api key xxxxxxx (密钥在steam网站申请, 申请地址: https://steamcommunity.com/dev/apikey)\n" +
|
||||
"- 查看apikey (查询已经绑定的密钥)\n" +
|
||||
"- 拉取steam订阅 (使用插件定时任务开始)\n" +
|
||||
"-----------------------\n" +
|
||||
"Tips: steamID在用户资料页的链接上面, 形如7656119820673xxxx\n" +
|
||||
"需要先私聊绑定apikey, 订阅用户之后使用job插件设置定时, 例: \n" +
|
||||
"记录在\"@every 1m\"触发的指令\n" +
|
||||
"拉取steam订阅",
|
||||
PrivateDataFolder: "steam",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 创建绑定流程
|
||||
engine.OnRegex(`^steam添加订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
steamidstr := ctx.State["regex_matched"].([]string)[1]
|
||||
steamID := math.Str2Int64(steamidstr)
|
||||
// 获取用户状态
|
||||
playerStatus, err := getPlayerStatus(steamidstr)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败, 获取用户信息错误"))
|
||||
return
|
||||
}
|
||||
if len(playerStatus) == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 需要添加的用户不存在, 请检查id或url"))
|
||||
return
|
||||
}
|
||||
playerData := playerStatus[0]
|
||||
// 判断用户是否已经初始化:若未初始化,通过用户的steamID获取当前状态并初始化;若已经初始化则更新用户信息
|
||||
info, err := database.find(steamID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
// 处理数据
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
if info.Target == "" {
|
||||
info = player{
|
||||
SteamID: steamID,
|
||||
PersonaName: playerData.PersonaName,
|
||||
Target: groupID,
|
||||
GameID: playerData.GameID,
|
||||
GameExtraInfo: playerData.GameExtraInfo,
|
||||
LastUpdate: time.Now().Unix(),
|
||||
}
|
||||
} else if !strings.Contains(info.Target, groupID) {
|
||||
info.Target = strings.Join([]string{info.Target, groupID}, ",")
|
||||
}
|
||||
// 更新数据库
|
||||
if err = database.update(&info); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据库失败"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("添加成功"))
|
||||
})
|
||||
// 删除绑定流程
|
||||
engine.OnRegex(`^steam删除订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
steamID := math.Str2Int64(ctx.State["regex_matched"].([]string)[1])
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
// 判断是否已经绑定该steamID,若已绑定就将群列表从推送群列表钟去除
|
||||
info, err := database.findWithGroupID(steamID, groupID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
if info.SteamID == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 所需要删除的用户不存在。"))
|
||||
return
|
||||
}
|
||||
// 从绑定列表中剔除需要删除的对象
|
||||
targets := strings.Split(info.Target, ",")
|
||||
newTargets := make([]string, 0)
|
||||
for _, target := range targets {
|
||||
if target == groupID {
|
||||
continue
|
||||
}
|
||||
newTargets = append(newTargets, target)
|
||||
}
|
||||
if len(newTargets) == 0 {
|
||||
if err = database.del(steamID); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
info.Target = strings.Join(newTargets, ",")
|
||||
if err = database.update(&info); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("删除成功"))
|
||||
})
|
||||
// 查询当前群绑定信息
|
||||
engine.OnFullMatch("steam查询订阅", zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群信息
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
// 获取所有绑定信息
|
||||
infos, err := database.findAll()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 查询订阅失败, 数据库错误"))
|
||||
return
|
||||
}
|
||||
if len(infos) == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 还未订阅过用户关系!"))
|
||||
return
|
||||
}
|
||||
// 遍历所有信息,如果包含该群就收集对应的steamID
|
||||
var sb strings.Builder
|
||||
head := " 查询steam订阅成功, 该群订阅的用户有: \n"
|
||||
sb.WriteString(head)
|
||||
for _, info := range infos {
|
||||
if strings.Contains(info.Target, groupID) {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(info.PersonaName)
|
||||
sb.WriteString(":")
|
||||
sb.WriteString(strconv.FormatInt(info.SteamID, 10))
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
}
|
||||
if sb.String() == head {
|
||||
ctx.SendChain(message.Text("查询成功,该群暂时还没有被绑定的用户!"))
|
||||
return
|
||||
}
|
||||
// 组装并返回结果
|
||||
data, err := text.RenderToBase64(sb.String(), text.FontFile, 400, 18)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(data)))
|
||||
})
|
||||
}
|
||||
106
plugin/steam/store.go
Normal file
106
plugin/steam/store.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package steam
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
database streamDB
|
||||
// 开启并检查数据库链接
|
||||
getDB = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
database.db.DBPath = engine.DataFolder() + "steam.db"
|
||||
err := database.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
if err = database.db.Create(tableListenPlayer, &player{}); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
// 校验密钥是否初始化
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
apiKeyMu.Lock()
|
||||
defer apiKeyMu.Unlock()
|
||||
_ = m.GetExtra(&apiKey)
|
||||
if apiKey == "" {
|
||||
ctx.SendChain(message.Text("ERROR: 未设置steam apikey"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
|
||||
// streamDB 继承方法的存储结构
|
||||
type streamDB struct {
|
||||
sync.RWMutex
|
||||
db sql.Sqlite
|
||||
}
|
||||
|
||||
const (
|
||||
// tableListenPlayer 存储查询用户信息
|
||||
tableListenPlayer = "listen_player"
|
||||
)
|
||||
|
||||
// player 用户状态存储结构体
|
||||
type player struct {
|
||||
SteamID int64 `json:"steam_id"` // 绑定用户标识ID
|
||||
PersonaName string `json:"persona_name"` // 用户昵称
|
||||
Target string `json:"target"` // 信息推送群组
|
||||
GameID int64 `json:"game_id"` // 游戏ID
|
||||
GameExtraInfo string `json:"game_extra_info"` // 游戏信息
|
||||
LastUpdate int64 `json:"last_update"` // 更新时间
|
||||
}
|
||||
|
||||
// update 如果主键不存在则插入一条新的数据,如果主键存在直接复写
|
||||
func (sdb *streamDB) update(dbInfo *player) error {
|
||||
sdb.Lock()
|
||||
defer sdb.Unlock()
|
||||
return sdb.db.Insert(tableListenPlayer, dbInfo)
|
||||
}
|
||||
|
||||
// find 根据主键查信息
|
||||
func (sdb *streamDB) find(steamID int64) (dbInfo player, err error) {
|
||||
sdb.Lock()
|
||||
defer sdb.Unlock()
|
||||
condition := "where steam_id = " + strconv.FormatInt(steamID, 10)
|
||||
err = sdb.db.Find(tableListenPlayer, &dbInfo, condition)
|
||||
if err == sql.ErrNullResult { // 规避没有该用户数据的报错
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// findWithGroupID 根据用户steamID和groupID查询信息
|
||||
func (sdb *streamDB) findWithGroupID(steamID int64, groupID string) (dbInfo player, err error) {
|
||||
sdb.Lock()
|
||||
defer sdb.Unlock()
|
||||
condition := "where steam_id = " + strconv.FormatInt(steamID, 10) + " AND target LIKE '%" + groupID + "%'"
|
||||
err = sdb.db.Find(tableListenPlayer, &dbInfo, condition)
|
||||
if err == sql.ErrNullResult { // 规避没有该用户数据的报错
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// findAll 查询所有库信息
|
||||
func (sdb *streamDB) findAll() (dbInfos []*player, err error) {
|
||||
sdb.Lock()
|
||||
defer sdb.Unlock()
|
||||
return sql.FindAll[player](&sdb.db, tableListenPlayer, "")
|
||||
}
|
||||
|
||||
// del 删除指定数据
|
||||
func (sdb *streamDB) del(steamID int64) error {
|
||||
sdb.Lock()
|
||||
defer sdb.Unlock()
|
||||
return sdb.db.Del(tableListenPlayer, "where steam_id = "+strconv.FormatInt(steamID, 10))
|
||||
}
|
||||
@@ -5,10 +5,17 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/fumiama/jieba"
|
||||
@@ -22,10 +29,33 @@ func init() {
|
||||
engine := control.Register("thesaurus", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "词典匹配回复",
|
||||
Help: "- 切换[kimo|傲娇|可爱]词库\n- 设置词库触发概率0.x (0<x<9)",
|
||||
Help: "- 切换[kimo|傲娇|可爱|🦙]词库\n- 设置词库触发概率0.x (0<x<9)",
|
||||
PublicDataFolder: "Chat",
|
||||
})
|
||||
engine.OnRegex(`^切换(kimo|傲娇|可爱)词库$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
alpacafolder := engine.DataFolder() + "alpaca/"
|
||||
err := os.MkdirAll(alpacafolder, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
alpacapifile := alpacafolder + "api.txt"
|
||||
alpacapiurl := ""
|
||||
if file.IsExist(alpacapifile) {
|
||||
data, err := os.ReadFile(alpacapifile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
alpacapiurl = binary.BytesToString(data)
|
||||
}
|
||||
alpacatokenfile := alpacafolder + "token.txt"
|
||||
alpacatoken := ""
|
||||
if file.IsExist(alpacatokenfile) {
|
||||
data, err := os.ReadFile(alpacatokenfile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
alpacatoken = binary.BytesToString(data)
|
||||
}
|
||||
engine.OnRegex(`^切换(kimo|傲娇|可爱|🦙)词库$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("ERROR: 找不到 manager"))
|
||||
@@ -44,6 +74,8 @@ func init() {
|
||||
t = tDERE
|
||||
case "可爱":
|
||||
t = tKAWA
|
||||
case "🦙":
|
||||
t = tALPACA
|
||||
}
|
||||
err := c.SetData(gid, (d&^3)|t)
|
||||
if err != nil {
|
||||
@@ -76,6 +108,24 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
engine.OnRegex(`^设置🦙API地址\s*(http.*)\s*$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
alpacapiurl = ctx.State["regex_matched"].([]string)[1]
|
||||
err := os.WriteFile(alpacapifile, binary.StringToBytes(alpacapiurl), 0644)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
engine.OnRegex(`^设置🦙token\s*([0-9a-f]{112})\s*$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
alpacatoken = ctx.State["regex_matched"].([]string)[1]
|
||||
err := os.WriteFile(alpacatokenfile, binary.StringToBytes(alpacatoken), 0644)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
go func() {
|
||||
data, err := engine.GetLazyData("dict.txt", false)
|
||||
if err != nil {
|
||||
@@ -128,6 +178,57 @@ func init() {
|
||||
engine.OnMessage(canmatch(tKAWA), match(chatListK, seg)).
|
||||
SetBlock(false).
|
||||
Handle(randreply(sm.K))
|
||||
engine.OnMessage(canmatch(tALPACA), func(ctx *zero.Ctx) bool {
|
||||
return alpacapiurl != "" && alpacatoken != ""
|
||||
}).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
msg := ctx.ExtractPlainText()
|
||||
if msg != "" {
|
||||
data, err := web.RequestDataWithHeaders(http.DefaultClient, alpacapiurl+"/reply", "POST",
|
||||
func(r *http.Request) error {
|
||||
r.Header.Set("Authorization", alpacatoken)
|
||||
return nil
|
||||
}, bytes.NewReader(binary.NewWriterF(func(writer *binary.Writer) {
|
||||
_ = json.NewEncoder(writer).Encode(&[]alpacamsg{{
|
||||
Name: ctx.CardOrNickName(ctx.Event.UserID),
|
||||
Message: msg,
|
||||
}})
|
||||
})))
|
||||
if err != nil {
|
||||
logrus.Warnln("[chat] 🦙 err:", err)
|
||||
return
|
||||
}
|
||||
type reply struct {
|
||||
ID int
|
||||
Msg string
|
||||
}
|
||||
m := reply{}
|
||||
err = json.Unmarshal(data, &m)
|
||||
if err != nil {
|
||||
logrus.Warnln("[chat] 🦙 unmarshal err:", err)
|
||||
return
|
||||
}
|
||||
for i := 0; i < 60; i++ {
|
||||
time.Sleep(time.Second * 4)
|
||||
data, err := web.RequestDataWithHeaders(http.DefaultClient, alpacapiurl+"/get?id="+strconv.Itoa(m.ID), "GET",
|
||||
func(r *http.Request) error {
|
||||
r.Header.Set("Authorization", alpacatoken)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal(data, &m)
|
||||
if err != nil {
|
||||
logrus.Warnln("[chat] 🦙 unmarshal err:", err)
|
||||
return
|
||||
}
|
||||
if len(m.Msg) > 0 {
|
||||
ctx.Send(message.Text(m.Msg))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -138,18 +239,21 @@ type simai struct {
|
||||
K map[string][]string `yaml:"可爱"`
|
||||
}
|
||||
|
||||
type alpacamsg struct {
|
||||
Name string
|
||||
Message string
|
||||
}
|
||||
|
||||
const (
|
||||
tKIMO = iota
|
||||
tDERE
|
||||
tKAWA
|
||||
tALPACA
|
||||
)
|
||||
|
||||
func match(l []string, seg *jieba.Segmenter) zero.Rule {
|
||||
return func(ctx *zero.Ctx) bool {
|
||||
if zero.FullMatchRule(l...)(ctx) {
|
||||
return true
|
||||
}
|
||||
return ctxext.JiebaFullMatch(seg, func(ctx *zero.Ctx) string {
|
||||
return ctxext.JiebaSimilarity(0.66, seg, func(ctx *zero.Ctx) string {
|
||||
return ctx.ExtractPlainText()
|
||||
}, l...)(ctx)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
err = db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
203
plugin/wantquotes/wantquotes.go
Normal file
203
plugin/wantquotes/wantquotes.go
Normal file
@@ -0,0 +1,203 @@
|
||||
// Package wantquotes 据意查句
|
||||
package wantquotes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
wantquotesURL = "https://wantquotes.net"
|
||||
getQrcode = "/api/get_qrcode/"
|
||||
showqrcode = "https://mp.weixin.qq.com/cgi-bin/showqrcode"
|
||||
loginCheck = "/api/login_check/"
|
||||
semantic = "/api/semantic/"
|
||||
semanticURL = wantquotesURL + semantic + "?query=%s&type=%s&unionid=%s&secret=%s"
|
||||
)
|
||||
|
||||
var (
|
||||
typeList = [...]string{"现", "现-名言", "现-佳句", "现-佳句-文学", "现-佳句-诗歌", "现-佳句-其他", "现-网络", "现-台词", "现-台词-影视剧", "现-台词-动漫", "现-台词-综艺",
|
||||
"古", "谚", "谚-谚语", "谚-俗语", "谚-惯用语", "歇"}
|
||||
)
|
||||
|
||||
type getQrcodeRsp struct {
|
||||
Ticket string `json:"ticket"`
|
||||
SceneID string `json:"scene_id"`
|
||||
}
|
||||
|
||||
type loginCheckRsp struct {
|
||||
Login int `json:"login"`
|
||||
Secret string `json:"secret"`
|
||||
Unionid string `json:"unionid"`
|
||||
}
|
||||
|
||||
type semanticRsp struct {
|
||||
Quotes []Quotes `json:"quotes"`
|
||||
TopSim float64 `json:"top_sim"`
|
||||
}
|
||||
|
||||
// Quotes 名句结构体
|
||||
type Quotes struct {
|
||||
Quote string `json:"quote"`
|
||||
SourceType string `json:"source_type"`
|
||||
Author string `json:"author"`
|
||||
Work string `json:"work"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
engine := control.Register("wantquotes", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Extra: control.ExtraFromString("wantquotes"),
|
||||
Brief: "据意查句",
|
||||
Help: "- 据意查句 大海 (需登录据意查句)\n" +
|
||||
"- 登录据意查句",
|
||||
PrivateDataFolder: "wantquotes",
|
||||
})
|
||||
|
||||
// 开启
|
||||
engine.OnRegex(`^据意查句\s?(.{1,25})$`, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
quotesType := ctx.State["quotesType"].(string)
|
||||
var key string
|
||||
manager := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
err := manager.GetExtra(&key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
logrus.Debugln("[wantquotes] get api key:", key)
|
||||
unionid, secret, _ := strings.Cut(key, "|")
|
||||
apiURL := fmt.Sprintf(semanticURL, url.QueryEscape(keyword), url.QueryEscape(quotesType), url.QueryEscape(unionid), url.QueryEscape(secret))
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), apiURL, "GET", wantquotesURL, web.RandUA(), nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var rsp semanticRsp
|
||||
err = json.Unmarshal(data, &rsp)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
m := make(message.Message, 0, len(rsp.Quotes))
|
||||
text := strings.Builder{}
|
||||
for _, v := range rsp.Quotes {
|
||||
text.WriteString(v.Quote)
|
||||
text.WriteString("\n—— ")
|
||||
text.WriteString(v.Author)
|
||||
text.WriteString(" 《")
|
||||
text.WriteString(v.Work)
|
||||
text.WriteString("》")
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
|
||||
text.Reset()
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch(`登录据意查句`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
getQrcodeData, err := web.RequestDataWith(web.NewDefaultClient(), wantquotesURL+getQrcode, "GET", wantquotesURL, web.RandUA(), nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var qrRsp getQrcodeRsp
|
||||
err = json.Unmarshal(getQrcodeData, &qrRsp)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
showQrcodeData, err := web.RequestDataWith(web.NewDefaultClient(), showqrcode+"?ticket="+qrRsp.Ticket, "GET", "", web.RandUA(), nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("WantQuotes\n微信扫码登录\n首次登录需关注公众号"))
|
||||
ctx.SendChain(message.ImageBytes(showQrcodeData))
|
||||
|
||||
ticker := time.NewTicker(2 * time.Second) // 创建每秒触发一次的定时器
|
||||
defer ticker.Stop()
|
||||
count := 0
|
||||
for range ticker.C {
|
||||
count++
|
||||
if count == 60 {
|
||||
ctx.SendChain(message.Text("据意查句登录超时,请重新登录"))
|
||||
return
|
||||
}
|
||||
loginCheckData, err := web.RequestDataWith(web.NewDefaultClient(), wantquotesURL+loginCheck+"?scene_id="+qrRsp.SceneID, "GET", "", web.RandUA(), nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var lcr loginCheckRsp
|
||||
err = json.Unmarshal(loginCheckData, &lcr)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if lcr.Login == 1 {
|
||||
manager := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
err := manager.SetExtra(lcr.Unionid + "|" + lcr.Secret)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("据意查句登录成功"))
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getPara(ctx *zero.Ctx) bool {
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
tex := strings.Builder{}
|
||||
tex.WriteString("请下列选择查询名句的类型\n")
|
||||
for i, v := range typeList {
|
||||
tex.WriteString(strconv.Itoa(i))
|
||||
tex.WriteString(". ")
|
||||
tex.WriteString(v)
|
||||
tex.WriteString("\n")
|
||||
}
|
||||
base64Str, err := text.RenderToBase64(tex.String(), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("图片生成错误了, ", zero.BotConfig.NickName[0], "帮你选择查询名句类型"))
|
||||
ctx.State["quotesType"] = typeList[0]
|
||||
return true
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(base64Str)))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10):
|
||||
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询名句类型"))
|
||||
ctx.State["quotesType"] = typeList[0]
|
||||
return true
|
||||
case c := <-recv:
|
||||
msg := c.Event.Message.ExtractPlainText()
|
||||
num, _ := strconv.Atoi(msg)
|
||||
if num < 0 || num >= len(typeList) {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
ctx.State["quotesType"] = typeList[num]
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package warframeapi
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -30,7 +31,11 @@ func newwfapi() (w wfapi, err error) {
|
||||
// 获取Warframe市场的售价表,并进行排序,cn_name为物品中文名称,onlyMaxRank表示只取最高等级的物品,返回物品售价表,物品信息,物品英文
|
||||
func getitemsorder(cnName string, onlyMaxRank bool) (od orders, it *itemsInSet, n string, err error) {
|
||||
var wfapiio wfAPIItemsOrders
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{}, fmt.Sprintf("https://api.warframe.market/v1/items/%s/orders?include=item", cnName), "GET", func(request *http.Request) error {
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
},
|
||||
}}, fmt.Sprintf("https://api.warframe.market/v1/items/%s/orders?include=item", cnName), "GET", func(request *http.Request) error {
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("Platform", "pc")
|
||||
return nil
|
||||
@@ -87,7 +92,11 @@ var (
|
||||
func newwm() (*wmdata, error) {
|
||||
var itemapi wfAPIItem // WarFrame市场的数据实例
|
||||
var wd wmdata
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{}, wfitemurl, "GET", func(request *http.Request) error {
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
},
|
||||
}}, wfitemurl, "GET", func(request *http.Request) error {
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("Language", "zh-hans")
|
||||
return nil
|
||||
|
||||
@@ -81,6 +81,9 @@ func (w *world) refresh(api *wfapi) {
|
||||
|
||||
w.w[2].NextTime = api.CambionCycle.Expiry.Local()
|
||||
w.w[2].IsDay = api.CambionCycle.Active == "fass"
|
||||
for _, t := range w.w {
|
||||
t.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// 游戏时间更新
|
||||
|
||||
@@ -100,7 +100,7 @@ func init() { // 插件主体
|
||||
))
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
vilginfo.db.DBPath = engine.DataFolder() + "ernieVilg.db"
|
||||
err := vilginfo.db.Open(time.Hour * 24)
|
||||
err := vilginfo.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return false
|
||||
@@ -302,7 +302,7 @@ func init() { // 插件主体
|
||||
))
|
||||
getmodeldb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
modelinfo.db.DBPath = engine.DataFolder() + "ernieModel.db"
|
||||
err := modelinfo.db.Open(time.Hour * 24)
|
||||
err := modelinfo.db.Open(time.Hour)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return false
|
||||
|
||||
65
plugin/wife/main.go
Normal file
65
plugin/wife/main.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Package wife 抽老婆
|
||||
package wife
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("wife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "- 抽老婆",
|
||||
Brief: "从老婆库抽每日老婆",
|
||||
PublicDataFolder: "Wife",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
|
||||
cards := []string{}
|
||||
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
|
||||
func(ctx *zero.Ctx) bool {
|
||||
data, err := engine.GetLazyData("wife.json", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(data, &cards)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Infof("[wife]加载%d个老婆", len(cards))
|
||||
return true
|
||||
},
|
||||
)).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
|
||||
data, err := engine.GetLazyData("wives/"+card, true)
|
||||
card, _, _ = strings.Cut(card, ".")
|
||||
if err != nil {
|
||||
ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"),
|
||||
)
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒"),
|
||||
message.ImageBytes(data),
|
||||
); id.ID() == 0 {
|
||||
ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func init() {
|
||||
var secondname string
|
||||
if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" {
|
||||
qq, _ := strconv.ParseInt(ctx.Event.Message[1].Data["qq"], 10, 64)
|
||||
secondname = ctx.GetGroupMemberInfo(ctx.Event.GroupID, qq, false).Get("nickname").Str
|
||||
secondname = ctx.GetThisGroupMemberInfo(qq, false).Get("nickname").Str
|
||||
}
|
||||
name = ctx.Event.Sender.NickName
|
||||
var text string
|
||||
|
||||
@@ -89,7 +89,7 @@ func main() {
|
||||
commitcnt := strings.Builder{}
|
||||
commitcnt.WriteString(banner.Version[1:i])
|
||||
commitcnt.WriteByte('.')
|
||||
commitcntcmd := exec.Command("git", "rev-list", "--count", "master")
|
||||
commitcntcmd := exec.Command("git", "rev-list", "--count", "HEAD")
|
||||
commitcntcmd.Stdout = &commitcnt
|
||||
err = commitcntcmd.Run()
|
||||
if err != nil {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"0409": {
|
||||
"identity": {
|
||||
"name": "ZeroBot-Plugin",
|
||||
"version": "1.7.0.1749"
|
||||
"version": "1.7.2.1831"
|
||||
},
|
||||
"description": "",
|
||||
"minimum-os": "vista",
|
||||
@@ -36,23 +36,23 @@
|
||||
"#1": {
|
||||
"0000": {
|
||||
"fixed": {
|
||||
"file_version": "1.7.0.1749",
|
||||
"product_version": "v1.7.0-beta5",
|
||||
"timestamp": "2023-03-16T19:22:18+08:00"
|
||||
"file_version": "1.7.2.1831",
|
||||
"product_version": "v1.7.2",
|
||||
"timestamp": "2023-07-28T13:59:16+08:00"
|
||||
},
|
||||
"info": {
|
||||
"0409": {
|
||||
"Comments": "OneBot plugins based on ZeroBot",
|
||||
"CompanyName": "FloatTech",
|
||||
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
"FileVersion": "1.7.0.1749",
|
||||
"FileVersion": "1.7.2.1831",
|
||||
"InternalName": "",
|
||||
"LegalCopyright": "© 2020 - 2023 FloatTech. All Rights Reserved.",
|
||||
"LegalTrademarks": "",
|
||||
"OriginalFilename": "ZBP.EXE",
|
||||
"PrivateBuild": "",
|
||||
"ProductName": "ZeroBot-Plugin",
|
||||
"ProductVersion": "v1.7.0-beta5",
|
||||
"ProductVersion": "v1.7.2",
|
||||
"SpecialBuild": ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user