mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-07 07:40:21 +00:00
Compare commits
212 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f5fb2d87 | ||
|
|
8674c14754 | ||
|
|
6c2fc1b4c2 | ||
|
|
5d94980e7c | ||
|
|
9bed71a99f | ||
|
|
6faa2b65e2 | ||
|
|
98812b103e | ||
|
|
deb655de36 | ||
|
|
8d1c18cb4a | ||
|
|
88824126f7 | ||
|
|
68a9ecf995 | ||
|
|
57404b2dcd | ||
|
|
29705c63c9 | ||
|
|
5a854d9715 | ||
|
|
eb1cbeae3f | ||
|
|
b6246cfee6 | ||
|
|
0619000f9a | ||
|
|
01361781c8 | ||
|
|
3c03a308b3 | ||
|
|
7895e48420 | ||
|
|
ba15713b99 | ||
|
|
bd98fa3aed | ||
|
|
fce75a9475 | ||
|
|
7616d5759f | ||
|
|
ea2c81a9c7 | ||
|
|
37cff9ff31 | ||
|
|
b8d3d6af9b | ||
|
|
fdf90a72cc | ||
|
|
ba0c05a774 | ||
|
|
3250ec14ac | ||
|
|
ce2f390361 | ||
|
|
71434232fe | ||
|
|
852629fa2e | ||
|
|
f10676d16d | ||
|
|
d43ea7df1d | ||
|
|
21712c6299 | ||
|
|
2fc47a38fa | ||
|
|
cbb4408668 | ||
|
|
a0df41b859 | ||
|
|
494c1b33b4 | ||
|
|
2034d91912 | ||
|
|
235ced0b78 | ||
|
|
3339b6a16f | ||
|
|
c08e3dfe4a | ||
|
|
894cf41d37 | ||
|
|
55aa869b1a | ||
|
|
42b18619c3 | ||
|
|
b0c57dfec5 | ||
|
|
bdbcf2a5f8 | ||
|
|
7807e68519 | ||
|
|
4cd81cb2e9 | ||
|
|
dc34a33346 | ||
|
|
2922854f96 | ||
|
|
29c85442ff | ||
|
|
048cbf51ca | ||
|
|
467dd2ea65 | ||
|
|
aef678be5c | ||
|
|
77f7567b29 | ||
|
|
c3c0685d3a | ||
|
|
c4c3f79c8c | ||
|
|
9cb54a34da | ||
|
|
519ae62760 | ||
|
|
6971da1abc | ||
|
|
5f3054d344 | ||
|
|
5b586a7402 | ||
|
|
f2ff66ec1d | ||
|
|
92b9bab76a | ||
|
|
4609985b79 | ||
|
|
6cf14fc7dd | ||
|
|
053363f781 | ||
|
|
e319bd61f1 | ||
|
|
baad83172f | ||
|
|
4b288a59b9 | ||
|
|
a2ada0b67e | ||
|
|
97fea6a93a | ||
|
|
145a9fb0b1 | ||
|
|
202d5e41a1 | ||
|
|
a64bead5e6 | ||
|
|
f9b84f8cb1 | ||
|
|
76e0c13f89 | ||
|
|
f9319c2a27 | ||
|
|
295c50a0ae | ||
|
|
942f5abbe4 | ||
|
|
965df40476 | ||
|
|
11f7f07009 | ||
|
|
76cd2afbd3 | ||
|
|
00d07cb7af | ||
|
|
3234c18718 | ||
|
|
d48285c450 | ||
|
|
98ea387254 | ||
|
|
fb80ff3b74 | ||
|
|
41e0cf8424 | ||
|
|
1bcd321477 | ||
|
|
b0482ee84b | ||
|
|
404f4041a9 | ||
|
|
f6d6375667 | ||
|
|
04acf4af49 | ||
|
|
df6957cfb6 | ||
|
|
d3ab1e1560 | ||
|
|
598a255e34 | ||
|
|
b4418fda55 | ||
|
|
3f26dde791 | ||
|
|
14d81411b1 | ||
|
|
4b667835f9 | ||
|
|
002f971882 | ||
|
|
99a8fcd73a | ||
|
|
3705da38b7 | ||
|
|
32afee62c5 | ||
|
|
a5ecb4bf7d | ||
|
|
1a424ebcd0 | ||
|
|
6a44331edd | ||
|
|
4e78f43649 | ||
|
|
ca7ac08808 | ||
|
|
3351450d88 | ||
|
|
fa82bdec79 | ||
|
|
0860a105ed | ||
|
|
b834307178 | ||
|
|
fafe24f1e4 | ||
|
|
6f1ec04ac8 | ||
|
|
263278d71d | ||
|
|
9ee5b044b4 | ||
|
|
21bfa14b55 | ||
|
|
0e2d717aa6 | ||
|
|
f5d2bd78b9 | ||
|
|
ef9f764fa0 | ||
|
|
3cfe1a6960 | ||
|
|
9387a48b5b | ||
|
|
3812150669 | ||
|
|
4ca100b0bf | ||
|
|
43dee54678 | ||
|
|
14786a94bf | ||
|
|
98a652f440 | ||
|
|
a004ed8064 | ||
|
|
37b0edde38 | ||
|
|
fd9f19562f | ||
|
|
acb7b42ded | ||
|
|
f1e4a523ce | ||
|
|
676ea312a3 | ||
|
|
6acd930455 | ||
|
|
340db0c644 | ||
|
|
f3d66b6abb | ||
|
|
6b8ae2e864 | ||
|
|
664cb2f2f9 | ||
|
|
486292434e | ||
|
|
e5f186ace1 | ||
|
|
0c637d4c8e | ||
|
|
0943023a19 | ||
|
|
941d6d2884 | ||
|
|
169af4ccce | ||
|
|
6f1d0f8c02 | ||
|
|
dd970b9a91 | ||
|
|
b997cb650e | ||
|
|
dd3ccf1d2f | ||
|
|
52a7977461 | ||
|
|
70713c0719 | ||
|
|
b4d6e1ef04 | ||
|
|
5295701541 | ||
|
|
43b9cea801 | ||
|
|
926d48af81 | ||
|
|
962c48ca36 | ||
|
|
03fc569f87 | ||
|
|
e5b712ff39 | ||
|
|
c7f7d0409e | ||
|
|
e4ec7ea5bb | ||
|
|
4bf734778b | ||
|
|
461325c8ca | ||
|
|
efa2ec6aac | ||
|
|
eb8be40f77 | ||
|
|
ae7e3c9c89 | ||
|
|
4d68cc9fce | ||
|
|
0226e2739a | ||
|
|
caa163a879 | ||
|
|
0e29010897 | ||
|
|
e9a8b99f4f | ||
|
|
27c637ba66 | ||
|
|
305db3395c | ||
|
|
3da37f0a3e | ||
|
|
c30c9192f4 | ||
|
|
ceb3df513d | ||
|
|
83372c4209 | ||
|
|
20d5e014b7 | ||
|
|
1c9a7eb158 | ||
|
|
31555cbf2f | ||
|
|
4a1d4644ed | ||
|
|
9182d214af | ||
|
|
45e3383031 | ||
|
|
fc91b69b55 | ||
|
|
13b6614dc2 | ||
|
|
fec5e4d73f | ||
|
|
585add29fc | ||
|
|
1e48e59cb7 | ||
|
|
41911af09a | ||
|
|
37b95e9559 | ||
|
|
a7901745e8 | ||
|
|
da9f085a50 | ||
|
|
192c2a8bd6 | ||
|
|
e6c00e9b68 | ||
|
|
1faa5aa5d8 | ||
|
|
7e7191536a | ||
|
|
16ff1975ff | ||
|
|
b32c86863e | ||
|
|
d9b361f765 | ||
|
|
5b2810e6c5 | ||
|
|
15a5b347e8 | ||
|
|
477ffa825b | ||
|
|
84363b1513 | ||
|
|
01bf6f049b | ||
|
|
a8d93de000 | ||
|
|
2da5de3743 | ||
|
|
bf6bac7be6 | ||
|
|
394d2e4a08 | ||
|
|
0dd447e270 |
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
- name: Cache downloaded module
|
||||
uses: actions/cache@master
|
||||
with:
|
||||
|
||||
2
.github/workflows/pull.yml
vendored
2
.github/workflows/pull.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
|
||||
11
.github/workflows/push.yml
vendored
11
.github/workflows/push.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
@@ -17,12 +17,3 @@ jobs:
|
||||
uses: golangci/golangci-lint-action@master
|
||||
with:
|
||||
version: latest
|
||||
args: --issues-exit-code=0
|
||||
- name: Commit back
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git config --local user.name 'github-actions[bot]'
|
||||
git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
git add --all
|
||||
git commit -m "🎨 改进代码样式"
|
||||
git push
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.18'
|
||||
go-version: '1.19'
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@master
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,4 +5,5 @@ plugins/*.dll
|
||||
.vscode
|
||||
go-zero*
|
||||
nohup.out
|
||||
zerobot
|
||||
zerobot
|
||||
ZeroBot-Plugin*
|
||||
|
||||
@@ -62,7 +62,7 @@ run:
|
||||
tests: false
|
||||
skip-dirs:
|
||||
- order
|
||||
go: '1.18'
|
||||
go: '1.19'
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
|
||||
559
README.md
559
README.md
@@ -26,7 +26,9 @@
|
||||
| [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp) | [MiraiGo](https://github.com/Mrs4s/MiraiGo) | Mrs4s |
|
||||
| [yyuueexxiinngg/cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) | [Mirai](https://github.com/mamoe/mirai) | yyuueexxiinngg |
|
||||
| [takayama-lily/onebot](https://github.com/takayama-lily/onebot) | [OICQ](https://github.com/takayama-lily/oicq) | takayama |
|
||||
|
||||
|
||||
[](https://seladb.github.io/StarTrack-js/#/preload?r=FloatTech,ZeroBot-Plugin)
|
||||
|
||||
</div>
|
||||
|
||||
> 如果您不知道什么是 [OneBot](https://github.com/howmanybots/onebot) 或不希望运行多个程序,还可以直接前往 [gocqzbp](https://github.com/FloatTech/gocqzbp) 的 [Release](https://github.com/FloatTech/gocqzbp/releases) 页面下载单一可执行文件或前往 [Packages](https://github.com/FloatTech/gocqzbp/pkgs/container/gocqzbp) 页面使用`docker`,运行后按提示登录即可。
|
||||
@@ -36,16 +38,19 @@
|
||||
## 命令行参数
|
||||
> `[]`代表是可选参数
|
||||
```bash
|
||||
zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname] [-p prefix] [-d|w] [qq1 qq2 qq3 ...] [&]
|
||||
zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
```
|
||||
- **-c config.json**: 从`config.json`加载`bot`配置
|
||||
- **-h**: 显示帮助
|
||||
- **-s config.json**: 保存现在`bot`配置到`config.json`
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-t token**: 设置`AccessToken`,默认为空
|
||||
- **-u url**: 设置`Url`,默认为`ws://127.0.0.1:6700`
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-p prefix**: 设置命令前缀,默认为`/`
|
||||
- **-d|w**: 开启 debug | warning 级别及以上日志输出
|
||||
- **-c config.json**: 从`config.json`加载`bot`配置
|
||||
- **-s config.json**: 保存现在`bot`配置到`config.json`
|
||||
- **-l latency**: 全局处理延时 (ms)
|
||||
- **-r ringlen**: 接收消息环缓冲区大小
|
||||
- **-x max process time**: 最大处理时间 (min)
|
||||
- **qqs**: superusers 的 qq 号
|
||||
- **&**: 驻留在后台,必须放在最后,仅`Linux`下有效
|
||||
|
||||
@@ -61,7 +66,10 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
"アトリ"
|
||||
],
|
||||
"command_prefix": "/",
|
||||
"super_users": []
|
||||
"super_users": [],
|
||||
"ring_len": 4096,
|
||||
"latency": 233000000,
|
||||
"max_process_time": 240000000000
|
||||
},
|
||||
"ws": [
|
||||
{
|
||||
@@ -80,6 +88,14 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
<details>
|
||||
<summary>插件控制</summary>
|
||||
|
||||
- [x] /响应 (在发送的群/用户开始工作)
|
||||
|
||||
- [x] /沉默 (在发送的群/用户停止工作)
|
||||
|
||||
- [x] /全局响应 (在所有位置开始工作,无视单独的沉默)
|
||||
|
||||
- [x] /全局沉默 (在所有本应沉默的位置停止工作,显式指定启用的位置不受影响)
|
||||
|
||||
- [x] /启用 xxx (在发送的群/用户启用xxx)
|
||||
|
||||
- [x] /禁用 xxx (在发送的群/用户禁用xxx)
|
||||
@@ -114,7 +130,7 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
<details>
|
||||
<summary>动态加载插件</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin-Dynamic/dyloader`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin-Dynamic/dyloader"`
|
||||
|
||||
- 本功能需要`cgo`,故已分离出主线。详见[ZeroBot-Plugin-Dynamic](https://github.com/FloatTech/ZeroBot-Plugin-Dynamic)
|
||||
|
||||
@@ -142,7 +158,7 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
<details>
|
||||
<summary>睡眠管理</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin/plugin/sleep_manage`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleep_manage"`
|
||||
|
||||
- [x] 早安 | 晚安
|
||||
|
||||
@@ -212,6 +228,12 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
|
||||
- [x] [开启 | 关闭]gist加群自动审批
|
||||
|
||||
- [x] 对信息回复:[设置 | 取消]精华
|
||||
|
||||
- [x] 取消精华 [信息ID]
|
||||
|
||||
- [x] /精华列表
|
||||
|
||||
- [ ] 同意好友请求
|
||||
|
||||
- [ ] 撤回[@xxx] [xxx]
|
||||
@@ -242,7 +264,7 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
|
||||
- [x] 取消以"完全匹配关键词"触发的(代表我执行的)指令
|
||||
|
||||
- [x] 记录在"cron"触发的指令
|
||||
- [x] 记录在"cron"触发的(别名xxx的)指令
|
||||
|
||||
- [x] 取消在"cron"触发的指令
|
||||
|
||||
@@ -321,7 +343,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
</details>
|
||||
|
||||
### *中优先级*
|
||||
<details>
|
||||
<summary>ahsai tts</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai"`
|
||||
|
||||
- [x] 使[ 伊織弓鶴 | 紲星あかり | 結月ゆかり | 京町セイカ |東北きりたん | 東北イタコ | ついなちゃん標準語 | ついなちゃん関西弁 | 音街ウナ | 琴葉茜 | 吉田くん | 民安ともえ | 桜乃そら | 月読アイ | 琴葉葵 | 東北ずん子 | 月読ショウタ | 水奈瀬コウ ]说(日语)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>AIfalse</summary>
|
||||
|
||||
@@ -331,6 +360,30 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 设置默认限速为每 m [分钟 | 秒] n 次触发
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>ai绘图</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint"`
|
||||
|
||||
- [x] [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx
|
||||
|
||||
- [x] [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] xxx
|
||||
|
||||
- [x] [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]
|
||||
|
||||
- [x] 设置ai绘图配置 [server] [token]
|
||||
|
||||
- [x] 设置ai绘图撤回时间90s
|
||||
|
||||
- [x] 查看ai绘图配置
|
||||
|
||||
例: 设置ai绘图配置 http://91.216.169.75:5010 abc
|
||||
|
||||
参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010
|
||||
|
||||
通过 http://91.217.139.190:5010/token 获取token
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>AIWife</summary>
|
||||
@@ -339,6 +392,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] waifu | 随机waifu(从[100000个AI生成的waifu](https://www.thiswaifudoesnotexist.net/)中随机一位)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>支付宝到账语音</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice"`
|
||||
|
||||
- [x] 支付宝到账 1
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>base16384加解密</summary>
|
||||
@@ -361,6 +422,79 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 百度下[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度内容审核</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit"`
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] 配置BDAKey [API Key] [Secret Key]
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] [开启|关闭]内容审核
|
||||
|
||||
- [x] [开启|关闭]撤回提示
|
||||
|
||||
- [x] [开启|关闭]详细提示
|
||||
|
||||
- [x] [开启|关闭]撤回禁言
|
||||
|
||||
- [x] [开启|关闭]禁言累加
|
||||
|
||||
- [x] [开启|关闭]文本检测
|
||||
|
||||
- [x] [开启|关闭]图像检测
|
||||
|
||||
- [x] 设置最大禁言时间[分钟,默认:60,最大43200]
|
||||
|
||||
- [x] 设置每次累加时间[分钟,默认:1]
|
||||
|
||||
- [x] 设置撤回禁言时间[分钟,默认:1]
|
||||
|
||||
- [x] 查看检测类型
|
||||
|
||||
- [x] 查看检测配置
|
||||
|
||||
- [x] 测试文本检测[文本内容]
|
||||
|
||||
- [x] 测试图像检测[图片]
|
||||
|
||||
- [x] 设置检测类型[类型编号]
|
||||
|
||||
- [x] 设置不检测类型[类型编号]
|
||||
|
||||
检测类型编号列表:[1:违禁违规|2:文本色情|3:敏感信息|4:恶意推广|5:低俗辱骂|6:恶意推广-联系方式|7:恶意推广-软文推广]
|
||||
</details>
|
||||
<details>
|
||||
<summary>base64卦加解密</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua"`
|
||||
|
||||
- [x] 六十四卦加密xxx
|
||||
|
||||
- [x] 六十四卦解密xxx
|
||||
|
||||
- [x] 六十四卦用yyy加密xxx
|
||||
|
||||
- [x] 六十四卦用yyy解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>base天城文加解密</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro"`
|
||||
|
||||
- [x] 天城文加密xxx
|
||||
|
||||
- [x] 天城文解密xxx
|
||||
|
||||
- [x] 天城文用yyy加密xxx
|
||||
|
||||
- [x] 天城文用yyy解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>bilibili</summary>
|
||||
@@ -373,17 +507,39 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 查成分 [xxx]
|
||||
|
||||
- [x] 设置b站cookie SESSDATA=82da790d,1663822823,06ecf\*31
|
||||
- [x] 查弹幕 [xxx] 2 (最后一个参数是页码)
|
||||
|
||||
- [x] 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0; (最好把cookie设全)
|
||||
|
||||
获取Cookie可以使用[这个工具](https://github.com/XiaoMiku01/login_bili_go)
|
||||
|
||||
- [x] 更新vup
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>b站视频链接解析</summary>
|
||||
<summary>b站动态、专栏、视频、直播解析</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_parse"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
||||
|
||||
- [x] https://www.bilibili.com/video/BV1xx411c7BF | https://www.bilibili.com/video/av1605 | https://b23.tv/I8uzWCA | https://www.bilibili.com/video/bv1xx411c7BF
|
||||
- [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>b站动态、直播推送,需要配合job一起使用</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
||||
|
||||
- [x] 添加b站订阅[uid|name]
|
||||
|
||||
- [x] 取消b站订阅[uid|name]
|
||||
|
||||
- [x] 取消b站动态订阅[uid|name]
|
||||
|
||||
- [x] 取消b站直播订阅[uid|name]
|
||||
|
||||
- [x] b站推送列表
|
||||
|
||||
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 10s"触发的指令)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -395,6 +551,14 @@ 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>
|
||||
@@ -421,6 +585,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 抽象翻译[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>英文字符翻转</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev"`
|
||||
|
||||
- [x] 翻转 I love you
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>coser</summary>
|
||||
@@ -443,7 +615,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<summary>DeepDanbooru二次元图标签识别</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru"`
|
||||
|
||||
- [x] 鉴赏图片[图片]
|
||||
|
||||
@@ -459,37 +631,15 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 教你一篇小作文[作文]
|
||||
|
||||
- [x] [回复]查重
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>漂流瓶</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle"`
|
||||
|
||||
- [x] (在群xxx)丢漂流瓶(到频道xxx) [消息]
|
||||
- [x] @Bot pick (随机捞一个漂流瓶)
|
||||
|
||||
- [x] (从频道xxx)捡漂流瓶
|
||||
|
||||
- [x] @BOT 创建频道 xxx
|
||||
|
||||
- [x] 跳入(频道)海中
|
||||
|
||||
- [x] 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一群一天一夫一妻制群老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife"`
|
||||
|
||||
- [x] 娶群友
|
||||
|
||||
- [x] (娶|嫁)[@对方QQ]
|
||||
|
||||
- [x] 当[对方Q号|@对方QQ]的小三
|
||||
|
||||
- [x] 群老婆列表
|
||||
- [x] @Bot throw xxx (投递内容xxx,支持图片文字,投递内容需要大于10个字符或者带有图片)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -507,6 +657,18 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] xxx疫情
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>好友申请及群聊邀请事件处理</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/event"`
|
||||
|
||||
- [x] [开启|关闭]自动同意[申请|邀请|主人]
|
||||
|
||||
- [x] [同意|拒绝][申请|邀请][flag]
|
||||
|
||||
- flag跟随事件一起发送, 默认同意主人的事件
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>渲染任意文字到图片</summary>
|
||||
@@ -518,7 +680,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<summary>每日运势</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin/plugin/fortune`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune"`
|
||||
|
||||
- [x] 运势 | 抽签
|
||||
|
||||
@@ -536,7 +698,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<summary>原神抽卡</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin/plugin/genshin`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/genshin"`
|
||||
|
||||
- [x] 切换原神卡池
|
||||
|
||||
@@ -566,6 +728,52 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] >github -p [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜歌</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic"`
|
||||
|
||||
- 猜歌插件(该插件依赖ffmpeg)
|
||||
|
||||
- 因为API不可抗因素,更改为了本地猜歌,但仍支持歌曲下载(VIP歌曲无法下载,黑胶可以)
|
||||
|
||||
- [x] 设置猜歌歌库路径 [绝对路径]
|
||||
|
||||
- [x] 猜歌[开启/关闭][歌单/歌词]自动下载
|
||||
|
||||
- 现只有歌词指令有效
|
||||
|
||||
- [ ] 添加歌单 [网易云歌单链接/ID] [歌单名称]
|
||||
|
||||
- [x] 下载歌曲 [歌曲名称/网易云歌曲ID] [歌单名称]
|
||||
|
||||
- [x] 删除歌单 [网易云歌单ID/歌单名称]
|
||||
|
||||
- 注:删除网易云歌单ID仅只是解除绑定,删除歌单名称是将本地数据全部删除!
|
||||
|
||||
- [x] 设置猜歌默认歌单 [歌单名称]
|
||||
|
||||
- [x] 歌单列表
|
||||
|
||||
- [x] [个人/团队]猜歌
|
||||
|
||||
- 注:默认歌库为歌单列表第一个,如果设置了默认歌单变为指定的歌单
|
||||
|
||||
- 可在“[个人/团队]猜歌指令”后面添加[-歌单名称]进行指定歌单猜歌
|
||||
|
||||
- 猜歌内容必须以[-]开头才会识别
|
||||
|
||||
- 本地歌曲命名规则为:\n歌名 - 歌手 - 其他(歌曲出处之类)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>黑丝</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi"`
|
||||
|
||||
- [x] 来点黑丝/白丝/jk/巨乳/足控/网红
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>炉石</summary>
|
||||
@@ -614,6 +822,38 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新[屌|弔|吊]图
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>兽语加密(嗷呜~)</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami"`
|
||||
|
||||
- [x] 兽语加密xxx
|
||||
|
||||
- [x] 兽语解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>小鸡词典</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jikipedia"`
|
||||
|
||||
- [x] [查梗|小鸡词典][梗]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>日语听力学习材料</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom"`
|
||||
|
||||
- [x] 随机日语听力
|
||||
|
||||
- [x] 随机日语歌曲
|
||||
|
||||
- [x] 日语听力 xxx
|
||||
|
||||
- [x] 日语歌曲 xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>绝绝子</summary>
|
||||
@@ -628,7 +868,9 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon"`
|
||||
|
||||
- [x] 来份萝莉
|
||||
- [x] 随机图片
|
||||
|
||||
- [x] 随机图片 萝莉|少女
|
||||
|
||||
- [x] 设置随机图片地址[http...]
|
||||
|
||||
@@ -638,6 +880,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
来份萝莉
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>MagicPrompt-Stable-Diffusion吟唱提示</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt"`
|
||||
|
||||
- [x] 吟唱提示[xxxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>简易midi音乐制作</summary>
|
||||
@@ -650,12 +900,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 团队听音练习
|
||||
|
||||
- [x] *.mid (解析上传的mid文件)
|
||||
- [x] *.mid (midi 转 txt)
|
||||
|
||||
- [x] 注: 该插件需要安装timidity,安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh
|
||||
- [x] midi制作*.txt (txt 转 midi)
|
||||
|
||||
- [x] 设置音色40 (0~127)
|
||||
|
||||
- [x] 注: 该插件需要安装timidity, linux安装脚本可参考 https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh, windows安装脚本可参考 https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat?inline=false, windows需要管理员模式运行
|
||||
|
||||
- [x] 符号说明: C5是中央C,后面不写数字,默认接5,Cb6<1,b代表降调,#代表升调,6比5高八度,<1代表音长×2,<3代表音长×8,<-1代表音长×0.5,<-3代表音长×0.125,R是休止符
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>日韩 VITS 模型拟声</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe"`
|
||||
|
||||
- [x] 让[宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海]说(日语)
|
||||
|
||||
- [x] 让[수아|미미르|아린|연화|유화|선배]说(韩语)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>摸鱼</summary>
|
||||
@@ -742,6 +1006,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] ?? [缩写]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>日语语法学习</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo"`
|
||||
|
||||
- [x] 日语语法 [xxx] (使用tag随机)
|
||||
|
||||
- [x] 搜索日语语法 [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>小说</summary>
|
||||
@@ -764,12 +1038,49 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<summary>浅草寺求签</summary>
|
||||
|
||||
`import _ github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji"`
|
||||
|
||||
- [x] 求签 | 占卜
|
||||
|
||||
- [x] 解签
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一群一天一夫一妻制群老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife"`
|
||||
|
||||
- 引入好感度系统,好感度越高,自由恋爱成功率越高
|
||||
|
||||
- [x] 设置CD为xx小时
|
||||
|
||||
- [x] [允许|禁止]自由恋爱
|
||||
|
||||
- [x] [允许|禁止]牛头人
|
||||
|
||||
- [x] 娶群友
|
||||
|
||||
- [x] [娶|嫁][@对方QQ]
|
||||
|
||||
- [x] 当[对方Q号|@对方QQ]的小三
|
||||
|
||||
- [x] 做媒 @攻方QQ @受方QQ
|
||||
|
||||
- [x] 买礼物给[对方Q号|@对方QQ]
|
||||
|
||||
- [x] 群老婆列表
|
||||
|
||||
- [x] 重置花名册
|
||||
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Real-CUGAN清晰术</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan"`
|
||||
|
||||
- [x] 清晰术(双重吟唱|三重吟唱|四重吟唱)(强力术式|中等术式|弱术式|不变式|原式)[图片]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>投胎</summary>
|
||||
@@ -786,11 +1097,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode"`
|
||||
|
||||
- [x] > runcode [language] help
|
||||
- [x] >runcode [language] help
|
||||
|
||||
- [x] > runcode [language] [code block]
|
||||
- [x] >runcode [language] [code block]
|
||||
|
||||
- [x] > runcoderaw [language] [code block]
|
||||
- [x] >runcoderaw [language] [code block]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -802,6 +1113,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 搜图[P站图片ID]
|
||||
|
||||
- [x] 设置 saucenao api key [apikey]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>叔叔的AI二次元图片放大</summary>
|
||||
@@ -818,6 +1131,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 签到
|
||||
- [x] 获得签到背景[@xxx] | 获得签到背景
|
||||
- [x] 查看等级排名
|
||||
- 注:跨群排行
|
||||
- [x] 查看我的钱包
|
||||
- [x] 查看钱包排名
|
||||
- 注:本群排行,若群人数太多不建议使用该功能!!!
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -855,9 +1173,18 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tarot"`
|
||||
|
||||
- [x] 抽塔罗牌
|
||||
- [x] 抽n张塔罗牌
|
||||
- [x] 抽[塔罗牌|大阿卡纳|小阿卡纳]
|
||||
- [x] 抽n张[塔罗牌|大阿卡纳|小阿卡纳]
|
||||
- [x] 解塔罗牌[牌名]
|
||||
- [x] [塔罗|大阿卡纳|小阿卡纳|混合]牌阵[圣三角|时间之流|四要素|五牌阵|吉普赛十字|马蹄|六芒星]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>舔狗日记</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
|
||||
- [x] 舔狗日记
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -867,16 +1194,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 搜番 | 搜索番剧[图片]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜单词</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle"`
|
||||
|
||||
- [x] 个人猜单词
|
||||
|
||||
- [x] 团队猜单词
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>翻译</summary>
|
||||
@@ -885,6 +1202,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] >TL 你好
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vits猫雷</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru"`
|
||||
|
||||
- [x] 让猫雷说[xxxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vtb语录</summary>
|
||||
@@ -905,6 +1230,64 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 来份网易云热评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>天气/拼音查询-名言</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben"`
|
||||
|
||||
- [x] xx天气
|
||||
|
||||
- [x] xx拼音
|
||||
|
||||
- [x] 每日情话/一言/鸡汤
|
||||
|
||||
- [x] 绕口令
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度文心AI</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI"`
|
||||
|
||||
基于百度文心API的一些功能
|
||||
|
||||
key申请链接:https://wenxin.baidu.com/moduleApi/key
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]
|
||||
|
||||
例:“为10086设置画图key 123 456”;“为群10010设置画图key 789 101”
|
||||
|
||||
文心key和画图key的API key 可以是相同的,只是文心key日限为200,画图日限为50,以此作区别。
|
||||
|
||||
- [x] 文心作文 (x字的)[作文题目]
|
||||
|
||||
- [x] 文心提案 (x字的)[文案标题]
|
||||
|
||||
- [x] 文心摘要 (x字的)[文章内容]
|
||||
|
||||
- [x] 文心小说 (x字的)[小说上文]
|
||||
|
||||
- [x] 文心对联 [上联]
|
||||
|
||||
- [x] 文心问答 [问题]
|
||||
|
||||
- [x] 文心补全 [带“_”的填空题]
|
||||
|
||||
- [x] 文心自定义 [prompt]
|
||||
|
||||
- [x] [bot名称]画几张[图片描述]的[图片类型][图片尺寸]
|
||||
|
||||
指令示例:
|
||||
|
||||
- 文心作文 我的椛椛机器人
|
||||
|
||||
- 文心作文 300字的我的椛椛机器人
|
||||
|
||||
- 椛椛帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>月幕galgame图</summary>
|
||||
@@ -921,31 +1304,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新gal
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>早报</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/zaobao"`
|
||||
|
||||
- api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用
|
||||
|
||||
- [x] /启用 zaobao
|
||||
|
||||
- [x] /禁用 zaobao
|
||||
|
||||
```
|
||||
记录在"00 9 * * *"触发的指令
|
||||
今日早报
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>舔狗日记</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
|
||||
- [x] 舔狗日记
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>聊天热词</summary>
|
||||
@@ -954,6 +1312,20 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 热词 [群号] [消息数目]|热词 123456 1000
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜单词</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle"`
|
||||
|
||||
- [x] 个人猜单词
|
||||
|
||||
- [x] 团队猜单词
|
||||
|
||||
- [x] 团队六阶猜单词
|
||||
|
||||
- [x] 团队七阶猜单词
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>鬼东西</summary>
|
||||
@@ -966,24 +1338,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- 注:由于需要科学,默认注释。
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>b站推送</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_push"`
|
||||
|
||||
- [x] 添加b站订阅[uid]
|
||||
|
||||
- [x] 取消b站订阅[uid]
|
||||
|
||||
- [x] 取消b站动态订阅[uid]
|
||||
|
||||
- [x] 取消b站直播订阅[uid]
|
||||
|
||||
- [x] b站推送列表
|
||||
|
||||
- 注:由于需要安装Chrome,默认注释,具体看[这里](https://www.yuque.com/xiangrikuidezhongzi/zerobot/qrwxth)
|
||||
|
||||
</details>
|
||||
|
||||
### *低优先级*
|
||||
@@ -1006,7 +1360,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] @Bot 任意文本(任意一句话回复)
|
||||
|
||||
- [x] 设置回复模式[青云客 | 小爱]
|
||||
|
||||
</details>
|
||||
|
||||
## 三种使用方法,推荐第一种
|
||||
|
||||
13
config.go
13
config.go
@@ -1,13 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/driver"
|
||||
)
|
||||
|
||||
type zbpcfg struct {
|
||||
Z zero.Config `json:"zero"`
|
||||
W []*driver.WSClient `json:"ws"`
|
||||
}
|
||||
|
||||
var config zbpcfg
|
||||
2
data
2
data
Submodule data updated: 5ce4b48c12...7bc1828db5
79
go.mod
79
go.mod
@@ -1,58 +1,66 @@
|
||||
module github.com/FloatTech/ZeroBot-Plugin
|
||||
|
||||
go 1.18
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/FloatTech/AnimeAPI v1.4.1-0.20220613042537-0adf8c5616ec
|
||||
github.com/FloatTech/sqlite v0.3.2
|
||||
github.com/FloatTech/zbpctrl v1.4.1-0.20220610074608-425160596f27
|
||||
github.com/FloatTech/zbputils v1.4.1-0.20220613042833-33e22060e8d9
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/Coloured-glaze/gg v1.3.4
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9
|
||||
github.com/FloatTech/sqlite v0.5.0
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.5.2
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
github.com/corona10/goimagehash v1.0.3
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/fumiama/ahsai v0.1.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
github.com/fumiama/go-base16384 v1.5.3
|
||||
github.com/fumiama/go-registry v0.1.6
|
||||
github.com/fumiama/gofastTEA v0.0.10
|
||||
github.com/fumiama/go-base16384 v1.6.1
|
||||
github.com/fumiama/go-registry v0.2.1
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/sqlite3 v1.14.6
|
||||
github.com/fumiama/unibase2n v0.0.0-20221003115227-e7db987de949
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/jozsefsallai/gophersauce v1.0.1
|
||||
github.com/lucas-clemente/quic-go v0.27.2
|
||||
github.com/lucas-clemente/quic-go v0.29.0
|
||||
github.com/mroth/weightedrand v0.4.1
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkumza/numcn v1.0.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.3
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
github.com/shirou/gopsutil/v3 v3.22.8
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/tidwall/gjson v1.14.3
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220610070647-9eeffcb277ee
|
||||
gitlab.com/gomidi/midi v1.23.7
|
||||
gitlab.com/gomidi/midi/v2 v2.0.17
|
||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c // indirect
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc // indirect
|
||||
github.com/antchfx/xpath v1.2.1 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/disintegration/imaging v1.6.2 // indirect
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect
|
||||
github.com/faiface/beep v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 // indirect
|
||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hajimehoshi/oto v0.7.1 // indirect
|
||||
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
|
||||
github.com/jfreymuth/vorbis v1.0.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
@@ -63,15 +71,18 @@ require (
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
|
||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741 // indirect
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.1 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
modernc.org/libc v1.16.8 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
modernc.org/memory v1.1.1 // indirect
|
||||
modernc.org/libc v1.19.0 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
)
|
||||
|
||||
358
go.sum
358
go.sum
@@ -1,41 +1,34 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/FloatTech/AnimeAPI v1.4.1-0.20220613042537-0adf8c5616ec h1:Hl/BxaQoQFEJUIGmdhR0NyBvZChb7qkfCrF916bNxnI=
|
||||
github.com/FloatTech/AnimeAPI v1.4.1-0.20220613042537-0adf8c5616ec/go.mod h1:MrCZ7P6WvF0JWHMeedAx6fVm5BP1s6/RUy0r0Jvqrds=
|
||||
github.com/FloatTech/sqlite v0.3.2 h1:iTg2ZKnzjjZAdlSN3hXmpCBn15odc4Ud484OoM3yXGA=
|
||||
github.com/FloatTech/sqlite v0.3.2/go.mod h1:VFtLofV5qxw5eBneZRbWwD451SLSm50o9J3J43iB1iw=
|
||||
github.com/FloatTech/zbpctrl v1.4.1-0.20220610074608-425160596f27 h1:C+D30vpxfgbJetTFXWAHzuU8GydbFb/A8Kv6E3PdRS4=
|
||||
github.com/FloatTech/zbpctrl v1.4.1-0.20220610074608-425160596f27/go.mod h1:5FDkrlVaQCxUfeqH7XJPTfej0q+y9fzImhvZI4ofu9Y=
|
||||
github.com/FloatTech/zbputils v1.4.1-0.20220613042833-33e22060e8d9 h1:IeUs08sUqdR/g8DfxPNTSBfsE1g0OtmffLNgKzbrVZ4=
|
||||
github.com/FloatTech/zbputils v1.4.1-0.20220613042833-33e22060e8d9/go.mod h1:A9AeVHZsv5chyw8p4fDI0cHnEOfMpmsTLoLWqUT7TO4=
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Coloured-glaze/gg v1.3.4 h1:l31zIF/HaVwkzjrj+A56RGQoSKyKuR1IWtIrqXGFStI=
|
||||
github.com/Coloured-glaze/gg v1.3.4/go.mod h1:Ih5NLNNDHOy3RJbB0EPqGTreIzq/H02TGThIagh8HJg=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051 h1:NEW8HzBNybMXAV0NrDpMF31n/e9BFGvNiGkDPGSkouc=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051/go.mod h1:Z+Q4kIPNo/OX4RWw6WGQOQcaNsbkv/wPmPDw8p4aQIY=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9 h1:HYJ7lwaqaOKmbYooPUMWxMhXRTp+JItoyeqa320ARD4=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9/go.mod h1:w+ND28mRaJvxUJ6pRXS6i4cLzutpXsWyroutCzBdL78=
|
||||
github.com/FloatTech/sqlite v0.5.0 h1:U7J5Omc534PqmH6csfu+ypCo3DS8L91l5lTsxUu3b/U=
|
||||
github.com/FloatTech/sqlite v0.5.0/go.mod h1:i33d92OtR8jcp5fBUvQtospf27+MkfUxnGwnZ95E/dA=
|
||||
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.2 h1:5ap0t2KgROpfTVHqMd9vHKXLeLmRFGI3ZrTPASgFP6s=
|
||||
github.com/FloatTech/zbpctrl v1.5.2/go.mod h1:BVPivMDJCBImPSdwgizb6sqb7rcDaRE65ZjfgthoC7g=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24 h1:6d9o83ZFI3LSPf4isDUmShiaU9CXqqggFwKFuof2Ghs=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24/go.mod h1:KDPJDu4KHeB4Gdyt8sqR5+QnIsIDW6XXsFfT1kD7okw=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c h1:cNPOdTNiVwxLpROLjXCgbIPvdkE+BwvxDvgmdYmWx6Q=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c/go.mod h1:KqZzu7slNKROh3TSYEH/IUMG6f4M+1qubZ5e52QypsE=
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc h1:AAx50/fb/xS4lvsdQg+bFbGvqSDhyV1MF+p2PLCamZ0=
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc/go.mod h1:OMmITAib6POA37xCichWM0aRnoVpSMZO1rB/G01wrr0=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antchfx/htmlquery v1.2.5 h1:1lXnx46/1wtv1E/kzmH8vrfMuUKYgkdDBA9pIdMJnk4=
|
||||
github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61ci2oOsOQVw=
|
||||
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
|
||||
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/corona10/goimagehash v1.0.3 h1:NZM518aKLmoNluluhfHGxT3LGOnrojrxhGn63DR/CZA=
|
||||
github.com/corona10/goimagehash v1.0.3/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
|
||||
github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI=
|
||||
github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
|
||||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -48,86 +41,79 @@ github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+Jl
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
|
||||
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fumiama/ahsai v0.1.0 h1:LXD61Kaj6kJHa3AEGsLIfKNzcgaVxg7JB72OR4yNNZ4=
|
||||
github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk=
|
||||
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
||||
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
||||
github.com/fumiama/go-base16384 v1.5.3 h1:IUZUlm2ajJB1nEJzauP6yD5IeJoVHyBEkzKJf9O82zs=
|
||||
github.com/fumiama/go-base16384 v1.5.3/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.1.6 h1:Ee/tXCCIR/xt8celhbbw0W/xDMdhAXLwy2YFBB/LWFk=
|
||||
github.com/fumiama/go-registry v0.1.6/go.mod h1:dIUVbiOgfk9oZcsgwDvNLC72i+ctibVukSXR/9bLviI=
|
||||
github.com/fumiama/go-base16384 v1.6.1 h1:4yb4JgmBJDnQtq3XGXXdLrVwEnRpjhMUt4eAcsNeA30=
|
||||
github.com/fumiama/go-base16384 v1.6.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.2.1 h1:PCu4d1OIYkLmoSufyxov3QXRul4lXrAfXfK1pVS2wrQ=
|
||||
github.com/fumiama/go-registry v0.2.1/go.mod h1:GP45kejHuDLFxcWdksrt75r5rHBqYwtfeUl3JzGWxfQ=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 h1:rLzJgNqB6LHNDVMl81yyNt6ZKziWtVfu+ioF0edlEVw=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
|
||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
||||
github.com/fumiama/sqlite3 v1.14.6 h1:+e+iygyiDXQJVi7xeXIviBvR7hAc5y20WA9hRwfKn10=
|
||||
github.com/fumiama/sqlite3 v1.14.6/go.mod h1:Xx9a2/OtHuy9pBjow0N+bE/RhNeZ7zZz5xh25vqbA5A=
|
||||
github.com/fumiama/unibase2n v0.0.0-20221003115227-e7db987de949 h1:VAzR8aoS2SCEBmRF9rqCPyXgXoP8mZ1viNL4mLWUg0Q=
|
||||
github.com/fumiama/unibase2n v0.0.0-20221003115227-e7db987de949/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 h1:uBejfH8l3/2f+5vjl1e4xIaSyNEhRBZ5N/ij7ohpNd8=
|
||||
github.com/gabriel-vasile/mimetype v1.0.4/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
||||
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
|
||||
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
|
||||
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
|
||||
github.com/jfreymuth/oggvorbis v1.0.1 h1:NT0eXBgE2WHzu6RT/6zcb2H10Kxj6Fm3PccT0LE6bqw=
|
||||
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
|
||||
github.com/jfreymuth/vorbis v1.0.0 h1:SmDf783s82lIjGZi8EGUUaS7YxPHgRj4ZXW/h7rUi7U=
|
||||
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
@@ -136,43 +122,30 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
|
||||
github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lucas-clemente/quic-go v0.27.2 h1:zsMwwniyybb8B/UDNXRSYee7WpQJVOcjQEGgpw2ikXs=
|
||||
github.com/lucas-clemente/quic-go v0.27.2/go.mod h1:vXgO/11FBSKM+js1NxoaQ/bPtVFYfB7uxhfHXyMhl1A=
|
||||
github.com/lucas-clemente/quic-go v0.29.0 h1:Vw0mGTfmWqGzh4jx/kMymsIkFK6rErFVmg+t9RLrnZE=
|
||||
github.com/lucas-clemente/quic-go v0.29.0/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||
github.com/mroth/weightedrand v0.4.1 h1:rHcbUBopmi/3x4nnrvwGJBhX9d0vk+KgoLUZeDP6YyI=
|
||||
github.com/mroth/weightedrand v0.4.1/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -181,66 +154,35 @@ github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE=
|
||||
github.com/pkumza/numcn v1.0.0/go.mod h1:QSeH+al9dWCd8di5HZM/ZqHqhZmUKfph572e9Ev/ETc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.22.3 h1:UebRzEomgMpv61e3hgD1tGooqX5trFbdU/ehphbHd00=
|
||||
github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8 h1:a4s3hXogo5mE2PfdfJIonDbstO/P+9JszdfhAHSzD9Y=
|
||||
github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
|
||||
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
@@ -249,53 +191,52 @@ github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03O
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
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.5.2-0.20220610070647-9eeffcb277ee h1:b2f+KLhZv+BCMQZuwMJvhKQOrz5YXzOduHC3G1DjQR0=
|
||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220610070647-9eeffcb277ee/go.mod h1:LJ+VOf523i3IrykuLK53UEeWqnAclRL5d2wGT4sS4Zk=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3 h1:Xf+rM8fR9Etc7ydcGHuqCk0ulAAn7Oa7nD9Zy/qZ6Pk=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3/go.mod h1:shG/ruauisKaVcov4amrFJtkeDl7nl+Q00IXB2PqFsc=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/gomidi/midi v1.23.7 h1:I6qKoIk9s9dcX+pNf0jC+tziCzJFn82bMpuntRkLeik=
|
||||
gitlab.com/gomidi/midi v1.23.7/go.mod h1:3ohtNOhqoSakkuLG/Li1OI6I3J1c2LErnJF5o/VBq1c=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.17 h1:kf16wNwFFOskl0trvarOwMuZUQICdIGn37LP9QqIRuo=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.17/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25 h1:dkzVBqbaFHjyWwP71MrQNX7IeRUIDonddmHbPpO/Ucg=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741 h1:b7y8iQCnzOE0NhgpMj2yHw17Us+lhXxFbdzKlTpqm5I=
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd h1:9NbNcTg//wfC5JskFW4Z3sqwVnjmJKHxLAol1bW2qgw=
|
||||
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f h1:kgfVkAEEQXXQ0qc6dH7n6y37NAYmTFmz0YRwrRjgxKw=
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -305,34 +246,23 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -341,86 +271,55 @@ golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
|
||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
@@ -438,9 +337,6 @@ modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g
|
||||
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.35.22/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
|
||||
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
||||
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
|
||||
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
|
||||
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
|
||||
modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
|
||||
modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
|
||||
@@ -482,11 +378,8 @@ modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi
|
||||
modernc.org/ccgo/v3 v3.15.9/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
|
||||
modernc.org/ccgo/v3 v3.15.10/go.mod h1:wQKxoFn0ynxMuCLfFD09c8XPUCc8obfchoVR9Cn0fI8=
|
||||
modernc.org/ccgo/v3 v3.15.12/go.mod h1:VFePOWoCd8uDGRJpq/zfJ29D0EVzMSyID8LCMWYbX6I=
|
||||
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
|
||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
|
||||
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
|
||||
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
|
||||
@@ -529,21 +422,18 @@ modernc.org/libc v1.14.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
|
||||
modernc.org/libc v1.14.2/go.mod h1:MX1GBLnRLNdvmK9azU9LCxZ5lMyhrbEMK8rG3X/Fe34=
|
||||
modernc.org/libc v1.14.3/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ=
|
||||
modernc.org/libc v1.14.5/go.mod h1:2PJHINagVxO4QW/5OQdRrvMYo+bm5ClpUFfyXCYl9ak=
|
||||
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
|
||||
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
|
||||
modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o=
|
||||
modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
|
||||
modernc.org/libc v1.19.0 h1:bXyVhGQg6KIClTr8FMVIDPl7jtbcs7aS5WP7vLDaxPs=
|
||||
modernc.org/libc v1.19.0/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0=
|
||||
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
||||
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
|
||||
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
|
||||
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
|
||||
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
|
||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
||||
@@ -2,21 +2,17 @@ package kanban
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fumiama/go-registry"
|
||||
)
|
||||
|
||||
var (
|
||||
info = [...]string{
|
||||
"* OneBot + ZeroBot + Golang",
|
||||
"* Version 1.4.1 - 2022-06-16 13:31:06 +0800 CST",
|
||||
"* Copyright © 2020 - 2022 FloatTech. All Rights Reserved.",
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
}
|
||||
// Banner ...
|
||||
Banner = strings.Join(info[:], "\n")
|
||||
reg = registry.NewRegReader("reilia.fumiama.top:32664", "fumiama")
|
||||
Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version 1.5.2 - 2022-11-09 15:15:01 +0800 CST\n" +
|
||||
"* Copyright © 2020 - 2022 FloatTech. All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
reg = registry.NewRegReader("reilia.fumiama.top:32664", "fumiama")
|
||||
)
|
||||
|
||||
// PrintBanner ...
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
// Package kanban 打印版本信息
|
||||
package kanban
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
|
||||
func init() {
|
||||
PrintBanner()
|
||||
once.Do(PrintBanner)
|
||||
}
|
||||
|
||||
168
main.go
168
main.go
@@ -1,3 +1,4 @@
|
||||
// Package main ZeroBot-Plugin main file
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -25,6 +26,8 @@ import (
|
||||
// vvvvvvvvvvvvvv //
|
||||
// vvvv //
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/antiabuse" // 违禁词
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chat" // 基础词库
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleep_manage" // 统计睡眠时间
|
||||
@@ -55,68 +58,85 @@ import (
|
||||
// vvvvvvvvvvvvvv //
|
||||
// vvvv //
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_false" // 服务器监控
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // 查询b站用户信息
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_parse" // b站视频链接解析
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/book_review" // 哀伤雪刃吧推书记录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi" // 藏头诗
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chouxianghua" // 说抽象话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/epidemic" // 城市疫情查询
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/funny" // 笑话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/genshin" // 原神抽卡
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu_calendar" // 摸鱼人日历
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativesetu" // 本地涩图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife" // 本地老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nbnhhsh" // 拼音首字母缩写释义工具
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale" // 叔叔的AI二次元图片放大
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
|
||||
_ "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/tarot" // 抽塔罗牌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtb_quotation" // vtb语录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/zaobao" // 早报
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_false" // 服务器监控
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint" // ai绘图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/book_review" // 哀伤雪刃吧推书记录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi" // 藏头诗
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chouxianghua" // 说抽象话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/epidemic" // 城市疫情查询
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/event" // 好友申请群聊邀请事件处理
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/funny" // 笑话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/genshin" // 原神抽卡
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi" // 黑丝
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami" // 兽语加密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jikipedia" // 小鸡词典
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom" // 日语听力学习材料
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe" // 日韩 VITS 模型拟声
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu_calendar" // 摸鱼人日历
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativesetu" // 本地涩图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife" // 本地老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nbnhhsh" // 拼音首字母缩写释义工具
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo" // 日语语法学习
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale" // 叔叔的AI二次元图片放大
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
|
||||
_ "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/tarot" // 抽塔罗牌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtb_quotation" // vtb语录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf" // 鬼东西
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_push" // b站推送
|
||||
|
||||
// ^^^^ //
|
||||
// ^^^^^^^^^^^^^^ //
|
||||
@@ -140,6 +160,8 @@ import (
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_reply" // 人工智能回复
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat" // 打断复读
|
||||
|
||||
// ^^^^ //
|
||||
// ^^^^^^^^^^^^^^ //
|
||||
// ^^^^^^^低优先级区^^^^^^^ //
|
||||
@@ -152,7 +174,7 @@ import (
|
||||
// //
|
||||
// //
|
||||
// -----------------------以下为内置依赖,勿动------------------------ //
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/driver"
|
||||
@@ -160,6 +182,13 @@ import (
|
||||
// -----------------------以上为内置依赖,勿动------------------------ //
|
||||
)
|
||||
|
||||
type zbpcfg struct {
|
||||
Z zero.Config `json:"zero"`
|
||||
W []*driver.WSClient `json:"ws"`
|
||||
}
|
||||
|
||||
var config zbpcfg
|
||||
|
||||
func init() {
|
||||
sus := make([]int64, 0, 16)
|
||||
// 解析命令行参数
|
||||
@@ -175,11 +204,13 @@ func init() {
|
||||
prefix := flag.String("p", "/", "Set command prefix.")
|
||||
runcfg := flag.String("c", "", "Run from config file.")
|
||||
save := flag.String("s", "", "Save default config to file and exit.")
|
||||
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).")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *h {
|
||||
kanban.PrintBanner()
|
||||
fmt.Println("Usage:")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
@@ -225,10 +256,13 @@ func init() {
|
||||
|
||||
config.W = []*driver.WSClient{driver.NewWebSocketClient(*url, *token)}
|
||||
config.Z = zero.Config{
|
||||
NickName: append([]string{*adana}, "ATRI", "atri", "亚托莉", "アトリ"),
|
||||
CommandPrefix: *prefix,
|
||||
SuperUsers: sus,
|
||||
Driver: []zero.Driver{config.W[0]},
|
||||
NickName: append([]string{*adana}, "ATRI", "atri", "亚托莉", "アトリ"),
|
||||
CommandPrefix: *prefix,
|
||||
SuperUsers: sus,
|
||||
RingLen: *rsz,
|
||||
Latency: time.Duration(*late) * time.Millisecond,
|
||||
MaxProcessTime: time.Duration(*maxpt) * time.Minute,
|
||||
Driver: []zero.Driver{config.W[0]},
|
||||
}
|
||||
|
||||
if *save != "" {
|
||||
@@ -257,5 +291,5 @@ func main() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(kanban.Kanban()))
|
||||
})
|
||||
zero.RunAndBlock(config.Z, process.GlobalInitMutex.Unlock)
|
||||
zero.RunAndBlock(&config.Z, process.GlobalInitMutex.Unlock)
|
||||
}
|
||||
|
||||
97
plugin/ahsai/ahsai.go
Normal file
97
plugin/ahsai/ahsai.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Package ahsai AH Soft フリーテキスト音声合成 demo API
|
||||
package ahsai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
ahsaitts "github.com/fumiama/ahsai"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
namelist = [...]string{"伊織弓鶴", "紲星あかり", "結月ゆかり", "京町セイカ", "東北きりたん", "東北イタコ", "ついなちゃん標準語", "ついなちゃん関西弁", "音街ウナ", "琴葉茜", "吉田くん", "民安ともえ", "桜乃そら", "月読アイ", "琴葉葵", "東北ずん子", "月読ショウタ", "水奈瀬コウ"}
|
||||
namesort = func() []string {
|
||||
nl := namelist[:]
|
||||
sort.Strings(nl)
|
||||
return nl
|
||||
}()
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("ahsai", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "フリーテキスト音声合成",
|
||||
Help: "- 使[伊織弓鶴|紲星あかり|結月ゆかり|京町セイカ|東北きりたん|東北イタコ|ついなちゃん標準語|ついなちゃん関西弁|音街ウナ|琴葉茜|吉田くん|民安ともえ|桜乃そら|月読アイ|琴葉葵|東北ずん子|月読ショウタ|水奈瀬コウ]说(日语)\n",
|
||||
PrivateDataFolder: "ahsai",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
_ = os.RemoveAll(cachePath)
|
||||
_ = os.MkdirAll(cachePath, 0755)
|
||||
engine.OnRegex("^使(.{0,10})说([A-Za-z\\s\\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d\\pP]+)$", selectName).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
uid := ctx.Event.UserID
|
||||
today := time.Now().Format("20060102150405")
|
||||
ahsaiFile := cachePath + strconv.FormatInt(uid, 10) + today + "ahsai.wav"
|
||||
s := ahsaitts.NewSpeaker()
|
||||
err := s.SetName(ctx.State["ahsainame"].(string))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
u, err := s.Speak(ctx.State["ahsaitext"].(string))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = ahsaitts.SaveOggToFile(u, ahsaiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + ahsaiFile))
|
||||
})
|
||||
}
|
||||
|
||||
func selectName(ctx *zero.Ctx) bool {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
ctx.State["ahsaitext"] = regexMatched[2]
|
||||
name := regexMatched[1]
|
||||
index := sort.SearchStrings(namesort, name)
|
||||
if index < len(namelist) && namesort[index] == name {
|
||||
ctx.State["ahsainame"] = name
|
||||
return true
|
||||
}
|
||||
speaktext := ""
|
||||
for i, v := range namelist {
|
||||
speaktext += fmt.Sprintf("%d. %s\n", i, v)
|
||||
}
|
||||
ctx.SendChain(message.Text("输入的音源为空, 请输入音源序号\n", speaktext))
|
||||
next, cancel := zero.NewFutureEvent("message", 999, false, ctx.CheckSession(), zero.RegexRule(`\d{0,2}`)).Repeat()
|
||||
defer cancel()
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10):
|
||||
ctx.State["ahsainame"] = namelist[rand.Intn(len(namelist))]
|
||||
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择", ctx.State["ahsainame"]))
|
||||
return true
|
||||
case c := <-next:
|
||||
msg := c.Event.Message.ExtractPlainText()
|
||||
num, _ := strconv.Atoi(msg)
|
||||
if num < 0 || num >= len(namelist) {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
ctx.State["ahsainame"] = namelist[num]
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("aifalse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "AIfalse\n" +
|
||||
"- 查询计算机当前活跃度: [检查身体 | 自检 | 启动自检 | 系统状态]\n" +
|
||||
Brief: "自检, 全局限速",
|
||||
Help: "- 查询计算机当前活跃度: [检查身体 | 自检 | 启动自检 | 系统状态]\n" +
|
||||
"- 设置默认限速为每 m [分钟 | 秒] n 次触发",
|
||||
})
|
||||
c, ok := control.Lookup("aifalse")
|
||||
@@ -50,34 +50,34 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("ERROR:no such plugin"))
|
||||
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||
return
|
||||
}
|
||||
m, err := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if ctx.State["regex_matched"].([]string)[2] == "分钟" {
|
||||
m *= 60
|
||||
}
|
||||
if m >= 65536 || m <= 0 {
|
||||
ctx.SendChain(message.Text("ERROR:interval too big"))
|
||||
ctx.SendChain(message.Text("ERROR: interval too big"))
|
||||
return
|
||||
}
|
||||
n, err := strconv.ParseInt(ctx.State["regex_matched"].([]string)[3], 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if n >= 65536 || n <= 0 {
|
||||
ctx.SendChain(message.Text("ERROR:burst too big"))
|
||||
ctx.SendChain(message.Text("ERROR: burst too big"))
|
||||
return
|
||||
}
|
||||
ctxext.SetDefaultLimiterManagerParam(time.Duration(m)*time.Second, int(n))
|
||||
err = c.SetData(0, (m&0xffff)|((n<<16)&0xffff0000))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("设置默认限速为每", m, "秒触发", n, "次"))
|
||||
|
||||
@@ -1,181 +1,238 @@
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/pkumza/numcn"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/aireply"
|
||||
"github.com/FloatTech/AnimeAPI/tts"
|
||||
"github.com/FloatTech/AnimeAPI/tts/baidutts"
|
||||
"github.com/FloatTech/AnimeAPI/tts/mockingbird"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
)
|
||||
|
||||
const ttsServiceName = "tts"
|
||||
const (
|
||||
cnapi = "https://genshin.azurewebsites.net/api/speak?format=mp3&id=%d&text=%s"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile(`(\-|\+)?\d+(\.\d+)?`)
|
||||
|
||||
type ttsInstances struct {
|
||||
sync.RWMutex
|
||||
m map[string]tts.TTS
|
||||
l []string
|
||||
// 每个角色的测试文案
|
||||
var testRecord = map[string]string{
|
||||
"派蒙": "哎,又是看不懂的东西。我完全不知道这些奇怪的问题和实验,能得到什么结果…",
|
||||
"凯亚": "真是个急性子啊你。",
|
||||
"安柏": "最初的鸟儿是不会飞翔的,飞翔是它们勇敢跃入峡谷的奖励。",
|
||||
"丽莎": "嗨,小可爱,你是新来的助理吗?",
|
||||
"琴": "蒲公英骑士,琴,申请入队。",
|
||||
"香菱": "我是来自璃月的厨师香菱,最擅长的是做各种捞…捞,料理…哎呀,练了那么多次,还是会紧张,嘿。",
|
||||
"枫原万叶": "飘摇风雨中,带刀归来赤脚行。",
|
||||
"迪卢克": "在黎明来临之前,总要有人照亮黑暗。",
|
||||
"温迪": "若你困于无风之地,我将为你奏响高天之歌。",
|
||||
"可莉": "西风骑士团,火花骑士,可莉,前来报到!…呃—后面该说什么词来着?可莉背不下来啦...",
|
||||
"早柚": "终末番,早柚,参上。 呼——",
|
||||
"托马": "初次见面,异乡的旅人,你的名字我可是早就听说了。只要你不嫌弃,我托马,从今天起就是你的朋友了。",
|
||||
"芭芭拉": "芭芭拉,闪耀登场~治疗就交给我吧,不会让你失望的!",
|
||||
"优菈": "沉沦是很容易的一件事,但我仍想冻住这股潮流。",
|
||||
"云堇": "曲高未必人不识,自有知音和清词。",
|
||||
"钟离": "人间归离复归离,借一浮生逃浮生。",
|
||||
"魈": "三眼五显仙人,魈,听召,前来守护",
|
||||
"凝光": "就算古玩价值连城,给人的快乐,也只有刚拥有的一瞬",
|
||||
"雷电将军": "浮世千百年来风景依旧,人之在世却如白露与泡影。",
|
||||
"北斗": "不知道如何向前的话,总之先迈出第一步,后面的道路就会自然而然地展开了。",
|
||||
"甘雨": "这项工作,该划掉了。",
|
||||
"七七": "椰羊的奶,好喝!比一般的羊奶,好喝!",
|
||||
"刻晴": "劳逸结合是不错,但也别放松过头。",
|
||||
"神里绫华": "若知是梦何须醒,不比真如一相会。",
|
||||
"雷泽": "你是朋友。我和你一起狩猎。",
|
||||
"神里绫人": "此前听绫华屡次提起阁下,不料公务繁忙,直至今日才有机会相见。",
|
||||
"罗莎莉亚": "哪怕如今你已经走上截然不同的道路,也不要否认从前的自己,从前的每一个你都是你脚下的基石,不要害怕过去,不要畏惧与它抗衡。",
|
||||
"阿贝多": "用自己的双脚丈量土地,将未知变为知识。",
|
||||
"八重神子": "我的神明,就托付给你了。",
|
||||
"宵宫": "即使只是片刻的火花,也能在仰望黑夜的人心中留下久久不灭的美丽光芒。",
|
||||
"荒泷一斗": "更好地活下去,绝不该靠牺牲同类换取,应该是,一起更好地活着,才对。",
|
||||
"九条裟罗": "想要留住雪花。但在手心里,它只会融化的更快。",
|
||||
"夜兰": "线人来信了,嗯,看来又出现了新的变数。",
|
||||
"珊瑚宫心海": "成为了现任人神巫女之后,我也慢慢习惯了这样的生活,更重要的是我也因此和你相遇了,不是吗?",
|
||||
"五郎": "海祇岛反抗军大将,五郎,前来助阵!",
|
||||
"达达利亚": "许下的诺言就好好遵守,做错了事情就承担责任,这才是家人应有的样子吧。",
|
||||
"莫娜": "正是因为无法更改,无可违逆,只能接受,命运才会被称之为命运。",
|
||||
"班尼特": "只要有大家在,伤口就不会痛!",
|
||||
"申鹤": "不知道你是喜欢人间的灯火,还是山林的月光?",
|
||||
"行秋": "有时明月无人夜,独向昭潭制恶龙。",
|
||||
"烟绯": "律法即是约束,也是工具。",
|
||||
"久岐忍": "有麻烦事要处理的话,直接告诉我就好,我来摆平。",
|
||||
"辛焱": "马上就要演出了,你也一起来嗨吗?",
|
||||
"砂糖": "我是砂糖,炼金术的…研究员。",
|
||||
"胡桃": "阴阳有序,命运无常,死亡难以预测,却也有它的规矩。",
|
||||
"重云": "我名重云,家族久居璃月,世代以驱邪除魔为业。",
|
||||
"菲谢尔": "我即断罪之皇女,真名为菲谢尔。应命运的召唤降临在此间——哎?你也是,异世界的旅人吗…?",
|
||||
"诺艾尔": "我是诺艾尔,西风骑士团的女仆,从今天起会陪你一起去冒险。",
|
||||
"迪奥娜": "猫尾酒馆的招牌调酒师,迪奥娜,我的出场费可是很贵的。",
|
||||
"鹿野院平藏": "我叫鹿野院平藏,是天领奉行里破案最多最快的侦探……",
|
||||
}
|
||||
|
||||
func (t *ttsInstances) List() []string {
|
||||
t.RLock()
|
||||
cl := make([]string, len(t.l))
|
||||
_ = copy(cl, t.l)
|
||||
t.RUnlock()
|
||||
return cl
|
||||
}
|
||||
|
||||
func init() {
|
||||
t := &ttsInstances{
|
||||
m: map[string]tts.TTS{
|
||||
"百度女声": baidutts.NewBaiduTTS(0),
|
||||
"百度男声": baidutts.NewBaiduTTS(1),
|
||||
"百度度逍遥": baidutts.NewBaiduTTS(3),
|
||||
"百度度丫丫": baidutts.NewBaiduTTS(4),
|
||||
"拟声鸟阿梓": nil,
|
||||
"拟声鸟文静": nil,
|
||||
"拟声鸟药水哥": nil,
|
||||
},
|
||||
l: []string{"拟声鸟阿梓", "拟声鸟文静", "拟声鸟药水哥", "百度女声", "百度男声", "百度度逍遥", "百度度丫丫"},
|
||||
var (
|
||||
re = regexp.MustCompile(`(\-|\+)?\d+(\.\d+)?`)
|
||||
soundList = [...]string{
|
||||
"派蒙", "凯亚", "安柏", "丽莎", "琴",
|
||||
"香菱", "枫原万叶", "迪卢克", "温迪", "可莉",
|
||||
"早柚", "托马", "芭芭拉", "优菈", "云堇",
|
||||
"钟离", "魈", "凝光", "雷电将军", "北斗",
|
||||
"甘雨", "七七", "刻晴", "神里绫华", "雷泽",
|
||||
"神里绫人", "罗莎莉亚", "阿贝多", "八重神子", "宵宫",
|
||||
"荒泷一斗", "九条裟罗", "夜兰", "珊瑚宫心海", "五郎",
|
||||
"达达利亚", "莫娜", "班尼特", "申鹤", "行秋",
|
||||
"烟绯", "久岐忍", "辛焱", "砂糖", "胡桃",
|
||||
"重云", "菲谢尔", "诺艾尔", "迪奥娜", "鹿野院平藏",
|
||||
}
|
||||
engine := control.Register(ttsServiceName, &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "语音回复(包括拟声鸟和百度)\n" +
|
||||
"- @Bot 任意文本(任意一句话回复)\n" +
|
||||
"- 设置语音模式[拟声鸟阿梓 | 拟声鸟文静 | 拟声鸟药水哥 | 百度女声 | 百度男声| 百度度逍遥 | 百度度丫丫]\n" +
|
||||
"- 设置默认语音模式[拟声鸟阿梓 | 拟声鸟文静 | 拟声鸟药水哥 | 百度女声 | 百度男声| 百度度逍遥 | 百度度丫丫]\n",
|
||||
})
|
||||
engine.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msg := ctx.ExtractPlainText()
|
||||
r := aireply.NewAIReply(getReplyMode(ctx))
|
||||
tts, err := t.new(t.getSoundMode(ctx))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
var reply string
|
||||
if tts != nil {
|
||||
rec, err := tts.Speak(ctx.Event.UserID, func() string {
|
||||
reply = r.TalkPlain(msg, zero.BotConfig.NickName[0])
|
||||
reply = re.ReplaceAllStringFunc(reply, func(s string) string {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
log.Errorln("[tts]:", err)
|
||||
return s
|
||||
}
|
||||
return numcn.EncodeFromFloat64(f)
|
||||
})
|
||||
log.Debugln("[tts]:", reply)
|
||||
return reply
|
||||
})
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Record(rec))
|
||||
} else {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^设置语音模式(.*)$`, ctxext.ValueInList(func(ctx *zero.Ctx) string { return ctx.State["regex_matched"].([]string)[1] }, t)).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
err := t.setSoundMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前模式为", param))
|
||||
})
|
||||
engine.OnRegex(`^设置默认语音模式(.*)$`, ctxext.ValueInList(func(ctx *zero.Ctx) string { return ctx.State["regex_matched"].([]string)[1] }, t)).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
t.setDefaultSoundMode(param)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,默认模式为", param))
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
// new 语音简单工厂
|
||||
func (t *ttsInstances) new(name string) (ts tts.TTS, err error) {
|
||||
t.RLock()
|
||||
ts = t.m[name]
|
||||
t.RUnlock()
|
||||
if ts == nil {
|
||||
switch name {
|
||||
case "拟声鸟阿梓":
|
||||
t.Lock()
|
||||
ts, err = mockingbird.NewMockingBirdTTS(0)
|
||||
t.Unlock()
|
||||
case "拟声鸟文静":
|
||||
t.Lock()
|
||||
ts, err = mockingbird.NewMockingBirdTTS(1)
|
||||
t.Unlock()
|
||||
case "拟声鸟药水哥":
|
||||
t.Lock()
|
||||
ts, err = mockingbird.NewMockingBirdTTS(2)
|
||||
t.Unlock()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *ttsInstances) setSoundMode(ctx *zero.Ctx, name string) error {
|
||||
/*************************************************************
|
||||
*******************************AIreply************************
|
||||
*************************************************************/
|
||||
func setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var ok bool
|
||||
var index int64
|
||||
t.RLock()
|
||||
for i, s := range t.l {
|
||||
for i, s := range replyModes {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
t.RUnlock()
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such mode")
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such plugin")
|
||||
}
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func (t *ttsInstances) getSoundMode(ctx *zero.Ctx) (name string) {
|
||||
func getReplyMode(ctx *zero.Ctx) (name string) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
index := m.GetData(gid)
|
||||
if int(index) < len(t.l) {
|
||||
return t.l[index]
|
||||
if int(index) < len(replyModes) {
|
||||
return replyModes[index]
|
||||
}
|
||||
}
|
||||
return "拟声鸟阿梓"
|
||||
return "青云客"
|
||||
}
|
||||
|
||||
func (t *ttsInstances) setDefaultSoundMode(name string) {
|
||||
var index int
|
||||
t.RLock()
|
||||
for _, s := range t.l {
|
||||
/*************************************************************
|
||||
***********************tts************************************
|
||||
*************************************************************/
|
||||
type ttsmode struct {
|
||||
sync.RWMutex
|
||||
mode map[int64]int64
|
||||
}
|
||||
|
||||
func list(list []string, num int) string {
|
||||
s := ""
|
||||
for i, value := range list {
|
||||
s += value
|
||||
if (i+1)%num == 0 {
|
||||
s += "\n"
|
||||
} else {
|
||||
s += " | "
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func newttsmode() *ttsmode {
|
||||
tts := &ttsmode{}
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m, ok := control.Lookup("tts")
|
||||
tts.mode = make(map[int64]int64, 2*len(soundList))
|
||||
tts.mode[-2905] = 1
|
||||
if ok {
|
||||
index := m.GetData(-2905)
|
||||
if index > 0 && index < int64(len(soundList)) {
|
||||
tts.mode[-2905] = index
|
||||
}
|
||||
}
|
||||
return tts
|
||||
}
|
||||
|
||||
func (tts *ttsmode) setSoundMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var index int64
|
||||
for i, s := range soundList {
|
||||
if s == name {
|
||||
index = int64(i + 1)
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
t.RUnlock()
|
||||
t.Lock()
|
||||
t.l[0], t.l[index] = t.l[index], t.l[0]
|
||||
t.Unlock()
|
||||
if index == 0 {
|
||||
return errors.New("不支持设置语音人物" + name)
|
||||
}
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
tts.mode[gid] = index
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func (tts *ttsmode) getSoundMode(ctx *zero.Ctx) int64 {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
i, ok := tts.mode[gid]
|
||||
if !ok {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
i = m.GetData(gid)
|
||||
}
|
||||
if i <= 0 || i >= int64(len(soundList)) {
|
||||
i = tts.mode[-2905]
|
||||
}
|
||||
return i - 1
|
||||
}
|
||||
|
||||
func (tts *ttsmode) resetSoundMode(ctx *zero.Ctx) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
tts.mode[gid] = 0
|
||||
return m.SetData(gid, 0) // 重置数据
|
||||
}
|
||||
|
||||
func (tts *ttsmode) setDefaultSoundMode(name string) error {
|
||||
var index int64
|
||||
for i, s := range soundList {
|
||||
if s == name {
|
||||
index = int64(i + 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == 0 {
|
||||
return errors.New("不支持设置语音人物" + name)
|
||||
}
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m, ok := control.Lookup("tts")
|
||||
if !ok {
|
||||
return errors.New("[tts] service not found")
|
||||
}
|
||||
tts.mode[-2905] = index
|
||||
return m.SetData(-2905, index)
|
||||
}
|
||||
|
||||
@@ -2,31 +2,43 @@
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/aireply"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/pkumza/numcn"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
replyServiceName = "aireply"
|
||||
)
|
||||
|
||||
var replyModes = [...]string{"青云客", "小爱"}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register(replyServiceName, &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "人工智能回复\n" +
|
||||
"- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客 | 小爱]\n- ",
|
||||
enOftts := control.Register("tts", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Brief: "人工智能语音回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n" +
|
||||
"- 设置语音模式[原神人物]\n" +
|
||||
"- 设置默认语音模式[原神人物]\n" +
|
||||
"- 恢复成默认语音模式\n" +
|
||||
"当前适用的原神人物含有以下:\n" + list(soundList[:], 5),
|
||||
})
|
||||
// 回复 @和包括名字
|
||||
engine.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
tts := newttsmode()
|
||||
enOfreply := control.Register("aireply", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "人工智能回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]",
|
||||
})
|
||||
/*************************************************************
|
||||
*******************************AIreply************************
|
||||
*************************************************************/
|
||||
enOfreply.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
aireply := aireply.NewAIReply(getReplyMode(ctx))
|
||||
reply := message.ParseMessageFromString(aireply.Talk(ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
|
||||
@@ -39,53 +51,95 @@ func init() { // 插件主体
|
||||
}
|
||||
ctx.Send(reply)
|
||||
})
|
||||
engine.OnPrefix(`设置回复模式`).SetBlock(true).
|
||||
enOfreply.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
err := setReplyMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
/*************************************************************
|
||||
***********************tts************************************
|
||||
*************************************************************/
|
||||
enOftts.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
err := setReplyMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
msg := ctx.ExtractPlainText()
|
||||
// 获取回复模式
|
||||
r := aireply.NewAIReply(getReplyMode(ctx))
|
||||
// 获取回复的文本
|
||||
reply := r.TalkPlain(msg, zero.BotConfig.NickName[0])
|
||||
// 获取语音
|
||||
index := tts.getSoundMode(ctx)
|
||||
record := message.Record(fmt.Sprintf(cnapi, index, url.QueryEscape(
|
||||
// 将数字转文字
|
||||
re.ReplaceAllStringFunc(reply, func(s string) string {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
log.Errorln("[tts]:", err)
|
||||
return s
|
||||
}
|
||||
return numcn.EncodeFromFloat64(f)
|
||||
}),
|
||||
))).Add("cache", 0)
|
||||
// 发送语音
|
||||
if ID := ctx.SendChain(record); ID.ID() == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
}
|
||||
|
||||
func 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 replyModes {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
break
|
||||
enOftts.OnRegex(`^设置语音模式(.*)$`, zero.AdminPermission, func(ctx *zero.Ctx) bool {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
if _, ok := testRecord[param]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("no such mode")
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such plugin")
|
||||
}
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func getReplyMode(ctx *zero.Ctx) (name string) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
index := m.GetData(gid)
|
||||
if int(index) < len(replyModes) {
|
||||
return replyModes[index]
|
||||
return true
|
||||
}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
// 保存设置
|
||||
err := tts.setSoundMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
return "青云客"
|
||||
// 设置验证
|
||||
i := tts.getSoundMode(ctx)
|
||||
if _, ok := testRecord[soundList[i]]; !ok {
|
||||
ctx.SendChain(message.Text("配置的语音人物数据丢失!请重新设置语音人物。"))
|
||||
return
|
||||
}
|
||||
record := message.Record(fmt.Sprintf(cnapi, i, url.QueryEscape(testRecord[soundList[i]]))).Add("cache", 0)
|
||||
if ID := ctx.SendChain(record); ID.ID() == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置失败!无法发送测试语音,请重试。"))
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
||||
})
|
||||
enOftts.OnRegex(`^设置默认语音模式(.*)$`, zero.SuperUserPermission, func(ctx *zero.Ctx) bool {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
if _, ok := testRecord[param]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
// 保存设置
|
||||
err := tts.setDefaultSoundMode(param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
||||
})
|
||||
enOftts.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := tts.resetSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
// 设置验证
|
||||
index := tts.getSoundMode(ctx)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", soundList[index]))
|
||||
})
|
||||
}
|
||||
|
||||
271
plugin/aipaint/aipaint.go
Normal file
271
plugin/aipaint/aipaint.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// Package aipaint ai绘图
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
datapath string
|
||||
predictRe = regexp.MustCompile(`{"steps".+?}`)
|
||||
// 参考host http://91.217.139.190:5010 http://91.216.169.75:5010
|
||||
aipaintTxt2ImgURL = "/got_image?token=%v&tags=%v"
|
||||
aipaintImg2ImgURL = "/got_image2image?token=%v&tags=%v"
|
||||
cfg = newServerConfig("data/aipaint/config.json")
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Steps int `json:"steps"`
|
||||
Sampler string `json:"sampler"`
|
||||
Seed int `json:"seed"`
|
||||
Strength float64 `json:"strength"`
|
||||
Noise float64 `json:"noise"`
|
||||
Scale float64 `json:"scale"`
|
||||
Uc string `json:"uc"`
|
||||
}
|
||||
|
||||
func (r *result) String() string {
|
||||
return fmt.Sprintf("steps: %v\nsampler: %v\nseed: %v\nstrength: %v\nnoise: %v\nscale: %v\nuc: %v\n", r.Steps, r.Sampler, r.Seed, r.Strength, r.Noise, r.Scale, r.Uc)
|
||||
}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("aipaint", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "ai绘图",
|
||||
Help: "- [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx\n" +
|
||||
"- [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] [prompt]\n" +
|
||||
"- [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]\n" +
|
||||
"- 设置ai绘图配置 [server] [token]\n" +
|
||||
"- 设置ai绘图撤回时间90s\n" +
|
||||
"- 查看ai绘图配置\n" +
|
||||
"例: 设置ai绘图配置 http://91.217.139.190:5010 abc\n" +
|
||||
"参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010\n" +
|
||||
"通过 http://91.217.139.190:5010/token 获取token\n" +
|
||||
"[prompt]参数如下\n" +
|
||||
"tags:tag词条\nntags:ntag词条\nshape:[Portrait|Landscape|Square]\nscale:[6:20]\nseed:种子\n" +
|
||||
"参数与参数内容用:连接,每个参数之间用回车分割",
|
||||
PrivateDataFolder: "aipaint",
|
||||
})
|
||||
datapath = file.BOTPATH + "/" + engine.DataFolder()
|
||||
engine.OnPrefixGroup([]string{`ai绘图`, `生成色图`, `生成涩图`, `ai画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
args := ctx.State["args"].(string)
|
||||
data, err := web.GetData(cfg.BaseURL + fmt.Sprintf(aipaintTxt2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20")))))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^(以图绘图|以图生图|以图画图)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
c := newContext(ctx.Event.UserID)
|
||||
list := ctx.State["regex_matched"].([]string)
|
||||
err = c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
args := strings.TrimSuffix(strings.TrimPrefix(list[0], list[1]), list[2])
|
||||
if args == "" {
|
||||
ctx.SendChain(message.Text("ERROR: 以图绘图必须添加tag"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
postURL := cfg.BaseURL + fmt.Sprintf(aipaintImg2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20"))))
|
||||
|
||||
f, err := os.Open(c.headimgsdir[0])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
imageShape := ""
|
||||
switch {
|
||||
case img.Bounds().Dx() > img.Bounds().Dy():
|
||||
imageShape = "Landscape"
|
||||
case img.Bounds().Dx() == img.Bounds().Dy():
|
||||
imageShape = "Square"
|
||||
default:
|
||||
imageShape = "Portrait"
|
||||
}
|
||||
|
||||
// 图片转base64
|
||||
base64Bytes, err := writer.ToBase64(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := web.PostData(postURL+"&shape="+imageShape, "text/plain", bytes.NewReader(base64Bytes))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnPrefixGroup([]string{`ai高级绘图`, `高级生成色图`, `高级生成涩图`, `ai高级画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tags := make(map[string]string)
|
||||
args := strings.Split(ctx.State["args"].(string), "\n")
|
||||
if len(args) < 1 {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的参数"))
|
||||
return
|
||||
}
|
||||
for _, info := range args {
|
||||
value := strings.Split(info, ":")
|
||||
if len(value) > 1 {
|
||||
if value[0] == "R18" && value[1] == "1" {
|
||||
value[1] = "0"
|
||||
ctx.SendChain(message.Text("不准涩涩! 已将R18设置为0. "))
|
||||
}
|
||||
tags[value[0]] = strings.Join(value[1:], ":")
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
apiurl := "/got_image?token=" + cfg.Token
|
||||
if _, ok := tags["tags"]; ok {
|
||||
apiurl += "&tags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["tags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["ntags"]; ok {
|
||||
apiurl += "&ntags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["ntags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["R18"]; ok {
|
||||
apiurl += "&R18=" + url.QueryEscape(strings.TrimSpace(tags["R18"]))
|
||||
}
|
||||
if _, ok := tags["shape"]; ok {
|
||||
apiurl += "&shape=" + url.QueryEscape(strings.TrimSpace(tags["shape"]))
|
||||
}
|
||||
if _, ok := tags["scale"]; ok {
|
||||
apiurl += "&scale=" + url.QueryEscape(strings.TrimSpace(tags["scale"]))
|
||||
}
|
||||
if _, ok := tags["seed"]; ok {
|
||||
apiurl += "&seed=" + url.QueryEscape(strings.TrimSpace(tags["seed"]))
|
||||
}
|
||||
data, err := web.GetData(cfg.BaseURL + apiurl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(regexMatched[1], regexMatched[2], cfg.Interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("成功设置\nbase_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图撤回时间(\d{1,3})s$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
interval, err := strconv.Atoi(regexMatched[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(cfg.BaseURL, cfg.Token, interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("成功设置\nbase_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
engine.OnFullMatch(`查看ai绘图配置`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("base_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
}
|
||||
|
||||
func sendAiImg(ctx *zero.Ctx, data []byte, interval int) {
|
||||
var loadData string
|
||||
if predictRe.MatchString(binary.BytesToString(data)) {
|
||||
loadData = predictRe.FindStringSubmatch(binary.BytesToString(data))[0]
|
||||
}
|
||||
var r result
|
||||
if loadData != "" {
|
||||
err := json.Unmarshal(binary.StringToBytes(loadData), &r)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
r.Uc, err = url.QueryUnescape(r.Uc)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
encodeStr := base64.StdEncoding.EncodeToString(data)
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+encodeStr))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(r.String())))
|
||||
if mid := ctx.Send(m); mid.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
} else if interval > 0 {
|
||||
go func(i message.MessageID) {
|
||||
time.Sleep(time.Duration(interval) * time.Second)
|
||||
ctx.DeleteMessage(i)
|
||||
}(mid)
|
||||
}
|
||||
}
|
||||
56
plugin/aipaint/config.go
Normal file
56
plugin/aipaint/config.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
// 配置结构体
|
||||
type serverConfig struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
Token string `json:"token"`
|
||||
Interval int `json:"interval"`
|
||||
file string
|
||||
}
|
||||
|
||||
func newServerConfig(file string) *serverConfig {
|
||||
return &serverConfig{
|
||||
file: file,
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) update(baseURL, token string, interval int) (err error) {
|
||||
if baseURL != "" {
|
||||
cfg.BaseURL = baseURL
|
||||
}
|
||||
if token != "" {
|
||||
cfg.Token = token
|
||||
}
|
||||
cfg.Interval = interval
|
||||
reader, err := os.Create(cfg.file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
return json.NewEncoder(reader).Encode(cfg)
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) load() (err error) {
|
||||
if cfg.BaseURL != "" && cfg.Token != "" && cfg.Interval != 0 {
|
||||
return
|
||||
}
|
||||
if file.IsNotExist(cfg.file) {
|
||||
err = errors.New("no server config")
|
||||
return
|
||||
}
|
||||
reader, err := os.Open(cfg.file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
err = json.NewDecoder(reader).Decode(cfg)
|
||||
return
|
||||
}
|
||||
39
plugin/aipaint/context.go
Normal file
39
plugin/aipaint/context.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
type context struct {
|
||||
usrdir string
|
||||
headimgsdir []string
|
||||
}
|
||||
|
||||
func newContext(user int64) *context {
|
||||
c := new(context)
|
||||
c.usrdir = datapath + "users/" + strconv.FormatInt(user, 10) + `/`
|
||||
_ = os.MkdirAll(c.usrdir, 0755)
|
||||
c.headimgsdir = make([]string, 2)
|
||||
c.headimgsdir[0] = c.usrdir + "0.gif"
|
||||
c.headimgsdir[1] = c.usrdir + "1.gif"
|
||||
return c
|
||||
}
|
||||
|
||||
func (cc *context) prepareLogos(s ...string) error {
|
||||
for i, v := range s {
|
||||
_, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.usrdir+strconv.Itoa(i)+".gif", true)
|
||||
} else {
|
||||
err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.usrdir+strconv.Itoa(i)+".gif", true)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -19,8 +19,8 @@ const (
|
||||
func init() { // 插件主体
|
||||
control.Register("aiwife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "AIWife\n" +
|
||||
"- waifu | 随机waifu",
|
||||
Brief: "ai随机生成老婆",
|
||||
Help: "- waifu | 随机waifu",
|
||||
}).ApplySingle(ctxext.DefaultSingle).OnFullMatchGroup([]string{"waifu", "随机waifu"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
miku := rand.Intn(100000) + 1
|
||||
|
||||
32
plugin/alipayvoice/alipayvoice.go
Normal file
32
plugin/alipayvoice/alipayvoice.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Package alipayvoice 支付宝到账语音
|
||||
package alipayvoice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
alipayvoiceURL = "https://mm.cqu.cc/share/zhifubaodaozhang/mp3/%v.mp3"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("alipayvoice", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "支付宝到账语音",
|
||||
Help: "- 支付宝到账 1",
|
||||
PrivateDataFolder: "alipayvoice",
|
||||
})
|
||||
|
||||
// 开启
|
||||
engine.OnPrefix(`支付宝到账`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(alipayvoiceURL, strings.TrimSpace(args))))
|
||||
})
|
||||
}
|
||||
124
plugin/antiabuse/anti.go
Normal file
124
plugin/antiabuse/anti.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// Package antiabuse defines antiabuse plugin ,support abuse words check and add/remove abuse words
|
||||
package antiabuse
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/ttl"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const bandur time.Duration = time.Minute * 10
|
||||
|
||||
var (
|
||||
managers *ctrl.Manager[*zero.Ctx] // managers lazy load
|
||||
cache = ttl.NewCacheOn(bandur, [4]func(int64, struct{}){nil, nil, onDel, nil})
|
||||
db *antidb
|
||||
)
|
||||
|
||||
func onDel(uid int64, _ struct{}) {
|
||||
if managers == nil {
|
||||
return
|
||||
}
|
||||
if err := managers.DoUnblock(uid); err != nil {
|
||||
logrus.Errorln("[antiabuse.onDel] unblock:", err)
|
||||
}
|
||||
if err := db.Del("__bantime__", "WHERE id="+strconv.FormatInt(uid, 10)); err != nil {
|
||||
logrus.Errorln("[antiabuse.onDel] db:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
engine := control.Register("antiabuse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "违禁词检测",
|
||||
Help: "- /[添加|删除|查看]违禁词",
|
||||
PrivateDataFolder: "anti_abuse",
|
||||
})
|
||||
|
||||
onceRule := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
managers = ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager
|
||||
var err error
|
||||
db, err = newantidb(engine.DataFolder() + "anti_abuse.db")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnMessage(onceRule, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||
if !ctx.Event.IsToMe {
|
||||
return true
|
||||
}
|
||||
uid := ctx.Event.UserID
|
||||
gid := ctx.Event.GroupID
|
||||
msg := strings.ReplaceAll(ctx.MessageString(), "\n", "")
|
||||
msg = strings.ReplaceAll(msg, "\r", "")
|
||||
msg = strings.ReplaceAll(msg, "\t", "")
|
||||
msg = strings.ReplaceAll(msg, ";", "")
|
||||
if db.isInAntiList(gid, msg) {
|
||||
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.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur))
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
err := db.Create("__bantime__", nilbt)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Insert("__bantime__", &banTime{ID: uid, Time: t})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
ctx.SendChain(message.Text("ERROR: block user: ", err))
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnCommand("添加违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle(
|
||||
func(ctx *zero.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
if err := db.insertWord(ctx.Event.GroupID, args); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("成功"))
|
||||
}
|
||||
})
|
||||
|
||||
engine.OnCommand("删除违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle(
|
||||
func(ctx *zero.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
if err := db.deleteWord(ctx.Event.GroupID, args); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("成功"))
|
||||
}
|
||||
})
|
||||
|
||||
engine.OnCommand("查看违禁词", zero.OnlyGroup, onceRule).Handle(
|
||||
func(ctx *zero.Ctx) {
|
||||
b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("本群违禁词有\n"), message.Image("base64://"+binary.BytesToString(b)))
|
||||
})
|
||||
}
|
||||
102
plugin/antiabuse/db.go
Normal file
102
plugin/antiabuse/db.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package antiabuse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
sqlite "github.com/FloatTech/sqlite"
|
||||
)
|
||||
|
||||
type antidb struct {
|
||||
sync.RWMutex
|
||||
sqlite.Sqlite
|
||||
}
|
||||
|
||||
type banWord struct {
|
||||
Word string `db:"word"`
|
||||
}
|
||||
|
||||
type banTime struct {
|
||||
ID int64 `db:"id"`
|
||||
Time int64 `db:"time"`
|
||||
}
|
||||
|
||||
var (
|
||||
nilban = &banWord{}
|
||||
nilbt = &banTime{}
|
||||
)
|
||||
|
||||
func newantidb(path string) (*antidb, error) {
|
||||
db := &antidb{Sqlite: sqlite.Sqlite{DBPath: path}}
|
||||
err := db.Open(bandur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = db.FindFor("__bantime__", nilbt, "", func() error {
|
||||
t := time.Unix(nilbt.Time, 0)
|
||||
ttl := time.Until(t.Add(bandur))
|
||||
if ttl < time.Minute {
|
||||
_ = managers.DoUnblock(nilbt.ID)
|
||||
return nil
|
||||
}
|
||||
cache.Set(nilbt.ID, struct{}{})
|
||||
cache.Touch(nilbt.ID, -time.Since(t))
|
||||
return nil
|
||||
})
|
||||
_ = db.Del("__bantime__", "WHERE time<="+strconv.FormatInt(time.Now().Add(time.Minute-bandur).Unix(), 10))
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (db *antidb) isInAntiList(gid int64, msg string) bool {
|
||||
grp := strconv.FormatInt(gid, 36)
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
return db.CanFind(grp, "WHERE instr('"+msg+"', word)>0")
|
||||
}
|
||||
|
||||
func (db *antidb) insertWord(gid int64, word string) error {
|
||||
grp := strconv.FormatInt(gid, 36)
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
err := db.Create(grp, nilban)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Insert(grp, &banWord{Word: word})
|
||||
}
|
||||
|
||||
func (db *antidb) deleteWord(gid int64, word string) error {
|
||||
grp := strconv.FormatInt(gid, 36)
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
if n, _ := db.Count(grp); n == 0 {
|
||||
return errors.New("本群还没有违禁词~")
|
||||
}
|
||||
return db.Del(grp, "WHERE word='"+word+"'")
|
||||
}
|
||||
|
||||
func (db *antidb) listWords(gid int64) string {
|
||||
grp := strconv.FormatInt(gid, 36)
|
||||
word := &banWord{}
|
||||
sb := strings.Builder{}
|
||||
sb.WriteByte('[')
|
||||
i := 0
|
||||
db.RLock()
|
||||
defer db.RUnlock()
|
||||
_ = db.FindFor(grp, word, "", func() error {
|
||||
if i > 0 {
|
||||
sb.WriteString(" | ")
|
||||
}
|
||||
sb.WriteString(word.Word)
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
if sb.Len() <= 4 {
|
||||
return "[]"
|
||||
}
|
||||
sb.WriteByte(']')
|
||||
return sb.String()
|
||||
}
|
||||
@@ -12,21 +12,17 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
)
|
||||
|
||||
const (
|
||||
// 服务名
|
||||
servicename = "atri"
|
||||
// ATRI 表情的 codechina 镜像
|
||||
res = "https://gitcode.net/u011570312/zbpdata/-/raw/main/Atri/"
|
||||
)
|
||||
const res = "https://gitcode.net/u011570312/zbpdata/-/raw/main/Atri/"
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register(servicename, &ctrl.Options[*zero.Ctx]{
|
||||
engine := control.Register("atri", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "atri人格文本回复",
|
||||
Help: "本插件基于 ATRI ,为 Golang 移植版\n" +
|
||||
"- ATRI醒醒\n- ATRI睡吧\n- 萝卜子\n- 喜欢 | 爱你 | 爱 | suki | daisuki | すき | 好き | 贴贴 | 老婆 | 亲一个 | mua\n" +
|
||||
"- 草你妈 | 操你妈 | 脑瘫 | 废柴 | fw | 废物 | 战斗 | 爬 | 爪巴 | sb | SB | 傻B\n- 早安 | 早哇 | 早上好 | ohayo | 哦哈哟 | お早う | 早好 | 早 | 早早早\n" +
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
package b14coder
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/FloatTech/floatbox/crypto"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
base14 "github.com/fumiama/go-base16384"
|
||||
tea "github.com/fumiama/gofastTEA"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
@@ -16,10 +14,10 @@ import (
|
||||
func init() {
|
||||
en := control.Register("base16384", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "base16384加解密\n" +
|
||||
"- 加密xxx\n- 解密xxx\n- 用yyy加密xxx\n- 用yyy解密xxx",
|
||||
Brief: "base16384加解密",
|
||||
Help: "- 加密xxx\n- 解密xxx\n- 用yyy加密xxx\n- 用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^加密\s*(.*)`).SetBlock(true).
|
||||
en.OnRegex(`^加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := base14.EncodeString(str)
|
||||
@@ -29,7 +27,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^解密\s*([一-踀]*[㴁-㴆]?)$`).SetBlock(true).
|
||||
en.OnRegex(`^解密\s*([一-踀]+[㴁-㴆]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := base14.DecodeString(str)
|
||||
@@ -39,10 +37,10 @@ func init() {
|
||||
ctx.SendChain(message.Text("解密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^用(.*)加密\s*(.*)`).SetBlock(true).
|
||||
en.OnRegex(`^用(.+)加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := getea(key)
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := base14.UTF16BE2UTF8(base14.Encode(t.Encrypt(helper.StringToBytes(str))))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(es)))
|
||||
@@ -50,10 +48,10 @@ func init() {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^用(.*)解密\s*([一-踀]*[㴁-㴆]?)$`).SetBlock(true).
|
||||
en.OnRegex(`^用(.+)解密\s*([一-踀]+[㴁-㴆]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := getea(key)
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := base14.UTF82UTF16BE(helper.StringToBytes(str))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(t.Decrypt(base14.Decode(es)))))
|
||||
@@ -62,15 +60,3 @@ func init() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getea(key string) tea.TEA {
|
||||
kr := []rune(key)
|
||||
if len(kr) > 4 {
|
||||
kr = kr[:4]
|
||||
} else {
|
||||
for len(kr) < 4 {
|
||||
kr = append(kr, rune(4-len(kr)))
|
||||
}
|
||||
}
|
||||
return *(*tea.TEA)(*(*unsafe.Pointer)(unsafe.Pointer(&kr)))
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
func init() {
|
||||
control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "baidu\n" +
|
||||
"- 百度下[xxx]",
|
||||
Brief: "不会百度吗",
|
||||
Help: "- 百度下[xxx]",
|
||||
}).OnPrefix("百度下").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
txt := ctx.State["args"].(string)
|
||||
|
||||
502
plugin/baiduaudit/audit.go
Normal file
502
plugin/baiduaudit/audit.go
Normal file
@@ -0,0 +1,502 @@
|
||||
// Package baiduaudit 百度内容审核
|
||||
package baiduaudit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Baidu-AIP/golang-sdk/aip/censor"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
// 服务网址:https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index
|
||||
// 返回参数说明:https://cloud.baidu.com/doc/ANTIPORN/s/Nk3h6xbb2
|
||||
type baiduRes struct {
|
||||
LogID int `json:"log_id"` // 请求唯一id
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Data []auditData `json:"data"`
|
||||
ErrorCode int `json:"error_code"` // 错误提示码,失败才返回,成功不返回
|
||||
ErrorMsg string `json:"error_msg"` // 错误提示信息,失败才返回,成功不返回
|
||||
}
|
||||
|
||||
type auditData struct {
|
||||
Type int `json:"type"` // 审核主类型,11:百度官方违禁词库、12:文本反作弊、13:自定义文本黑名单、14:自定义文本白名单
|
||||
SubType int `json:"subType"` // 审核子类型,0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Msg string `json:"msg"` // 不合规项描述信息
|
||||
Hits []hit `json:"hits"`
|
||||
} // 不合规/疑似/命中白名单项详细信息。响应成功并且conclusion为疑似或不合规或命中白名单时才返回,响应失败或conclusion为合规且未命中白名单时不返回。
|
||||
|
||||
type hit struct {
|
||||
DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
|
||||
Words []string `json:"words"` // 送检文本命中词库的关键词(备注:建议参考新字段“wordHitPositions”,包含信息更丰富:关键词以及对应的位置及标签信息)
|
||||
Probability float64 `json:"probability,omitempty"` // 不合规项置信度
|
||||
} // 送检文本违规原因的详细信息
|
||||
type keyConfig struct {
|
||||
Key1 string `json:"key1"` // 百度云服务内容审核key存储
|
||||
Key2 string `json:"key2"` // 百度云服务内容审核key存储
|
||||
Groups map[int64]group `json:"groups"` // 群配置存储
|
||||
}
|
||||
|
||||
type group struct {
|
||||
Enable EnableMark // 是否启用内容审核
|
||||
TextAudit EnableMark // 文本检测
|
||||
ImageAudit EnableMark // 图像检测
|
||||
DMRemind EnableMark // 撤回提示
|
||||
MoreRemind EnableMark // 详细违规提示
|
||||
DMBAN EnableMark // 撤回后禁言
|
||||
BANTimeAddEnable EnableMark // 禁言累加
|
||||
BANTime int64 // 标准禁言时间,禁用累加,但开启禁言的的情况下采用该值
|
||||
MaxBANTimeAddRange int64 // 最大禁言时间累加范围,最高禁言时间
|
||||
BANTimeAddTime int64 // 禁言累加时间,该值是开启禁累加功能后,再次触发时,根据被禁次数X该值计算出的禁言时间
|
||||
WhiteListType [8]bool // 类型白名单,处于白名单类型的违规,不会被触发 0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
AuditHistory map[int64]auditHistory // 被封禁用户列表
|
||||
}
|
||||
|
||||
// EnableMark 启用:●,禁用:○
|
||||
type EnableMark bool
|
||||
|
||||
// String 打印启用状态
|
||||
func (em EnableMark) String() string {
|
||||
if em {
|
||||
return "开启"
|
||||
}
|
||||
return "关闭"
|
||||
}
|
||||
|
||||
type auditHistory struct {
|
||||
Count int64 `json:"key2"` // 被禁次数
|
||||
ResList []baiduRes `json:"reslist"` // 禁言原因
|
||||
}
|
||||
|
||||
var bdcli *censor.ContentCensorClient // 百度云审核服务Client
|
||||
var typetext = [8]string{
|
||||
0: "默认违禁词库",
|
||||
1: "违禁违规",
|
||||
2: "文本色情",
|
||||
3: "敏感信息",
|
||||
4: "恶意推广",
|
||||
5: "低俗辱骂",
|
||||
6: "恶意推广-联系方式",
|
||||
7: "恶意推广-软文推广",
|
||||
} // 文本类型
|
||||
|
||||
var (
|
||||
config keyConfig // 插件配置
|
||||
configinit bool // 配置初始化
|
||||
configpath string // 配置路径
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "百度内容审核",
|
||||
Help: "##该功能来自百度内容审核,需购买相关服务,并创建app##\n" +
|
||||
"- 获取BDAKey\n" +
|
||||
"- 配置BDAKey [API key] [Secret Key]\n" +
|
||||
"- 开启/关闭内容审核\n" +
|
||||
"- 开启/关闭撤回提示\n" +
|
||||
"- 开启/关闭详细提示\n" +
|
||||
"- 开启/关闭撤回禁言\n" +
|
||||
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时,再次触发按最大禁言时间计算\n" +
|
||||
"- 开启/关闭禁言累加\n" +
|
||||
"- 设置撤回禁言时间[分钟,默认:1]\n" +
|
||||
"- 设置最大禁言时间[分钟,默认:60,最大43200]\n" +
|
||||
"- 设置每次累加时间[分钟,默认:1]\n" +
|
||||
"##检测类型设置## 类型编号列表:[1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广]\n" +
|
||||
"- 查看检测类型\n" +
|
||||
"- 查看检测配置\n" +
|
||||
"- 设置检测类型[类型编号]\n" +
|
||||
"- 设置不检测类型[类型编号]\n" +
|
||||
"- 开启/关闭文本检测\n" +
|
||||
"- 开启/关闭图像检测\n" +
|
||||
"##测试功能##\n" +
|
||||
"- 测试文本检测[文本内容]\n" +
|
||||
"- 测试图像检测[图片]\n",
|
||||
PrivateDataFolder: "baiduaudit",
|
||||
})
|
||||
configpath = engine.DataFolder() + "config.json"
|
||||
loadConfig()
|
||||
if configinit {
|
||||
bdcli = censor.NewClient(config.Key1, config.Key2)
|
||||
}
|
||||
engine.OnFullMatch("获取BDAKey", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("接口key创建网址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index\n" +
|
||||
"免费8w次数领取地址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/resource/getFree"))
|
||||
})
|
||||
|
||||
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
var msgs string
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
if k1 == "类型" {
|
||||
msgs += "本群检测类型:"
|
||||
find := false
|
||||
// 遍历群检测类型名单
|
||||
for i, v := range group.WhiteListType {
|
||||
if !v {
|
||||
find = true
|
||||
msgs += fmt.Sprint("\n", i, ".", typetext[i])
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
msgs += "无"
|
||||
}
|
||||
|
||||
} else {
|
||||
// 生成配置文本
|
||||
msgs = fmt.Sprintf("本群配置:\n"+
|
||||
"内容审核:%s\n"+
|
||||
"-文本:%s\n"+
|
||||
"-图像:%s\n"+
|
||||
"撤回提示:%s\n"+
|
||||
"-详细提示:%s\n"+
|
||||
"撤回禁言:%s\n"+
|
||||
"-禁言累加:%s\n"+
|
||||
"-撤回禁言时间:%v分钟\n"+
|
||||
"-每次累加时间:%v分钟\n"+
|
||||
"-最大禁言时间:%v分钟", group.Enable, group.TextAudit, group.ImageAudit, group.DMRemind, group.MoreRemind, group.DMBAN, group.BANTimeAddEnable, group.BANTime, group.BANTimeAddTime, group.MaxBANTimeAddRange)
|
||||
}
|
||||
b, err := text.RenderToBase64(msgs, text.FontFile, 300, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
})
|
||||
engine.OnRegex("^设置(不)?检测类型([01234567])$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
inputType, _ := strconv.Atoi(k2)
|
||||
if k1 == "不" {
|
||||
group.WhiteListType[inputType] = true //不检测:则进入类型白名单
|
||||
} else {
|
||||
group.WhiteListType[inputType] = false //检测:则退出白名单
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, typetext[inputType])))
|
||||
})
|
||||
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k3 := ctx.State["regex_matched"].([]string)[3]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
time, _ := strconv.ParseInt(k1, 10, 64)
|
||||
switch k1 {
|
||||
case "最大":
|
||||
group.MaxBANTimeAddRange = time
|
||||
case "每次":
|
||||
group.BANTimeAddTime = time
|
||||
case "撤回":
|
||||
group.BANTime = time
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s禁言累加时间已设置为%s", k3, k1)))
|
||||
})
|
||||
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
isEnable := EnableMark(false)
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
if k1 == "开启" {
|
||||
isEnable = true
|
||||
}
|
||||
switch k2 {
|
||||
case "内容审核":
|
||||
group.Enable = isEnable
|
||||
case "撤回提示":
|
||||
group.DMRemind = isEnable
|
||||
case "撤回禁言":
|
||||
group.DMBAN = isEnable
|
||||
case "禁言累加":
|
||||
group.BANTimeAddEnable = isEnable
|
||||
case "详细提示":
|
||||
group.MoreRemind = isEnable
|
||||
case "文本检测":
|
||||
group.TextAudit = isEnable
|
||||
case "图像检测":
|
||||
group.ImageAudit = isEnable
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s已%s", k2, k1)))
|
||||
})
|
||||
engine.OnRegex(`^配置BDAKey\s*(.*)\s*(.*)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
bdcli = censor.NewClient(k1, k2)
|
||||
config.Key1 = k1
|
||||
config.Key2 = k2
|
||||
if bdcli != nil {
|
||||
jsonSave(config, configpath)
|
||||
ctx.SendChain(message.Text("配置成功"))
|
||||
}
|
||||
})
|
||||
engine.OnMessage().SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
group, ok := config.Groups[ctx.Event.GroupID]
|
||||
// 如果没该配置,或者审核功能未开启直接跳过
|
||||
if !ok || !bool(group.Enable) {
|
||||
return
|
||||
}
|
||||
for _, elem := range ctx.Event.Message {
|
||||
switch elem.Type {
|
||||
case "image":
|
||||
if !group.ImageAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
|
||||
case "text":
|
||||
if !group.TextAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.TextCensor(elem.Data["text"])
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnPrefix("文本检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return
|
||||
}
|
||||
args := ctx.ExtractPlainText()
|
||||
res := bdcli.TextCensor(args)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
})
|
||||
engine.OnPrefix("^图像检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var urls []string
|
||||
for _, elem := range ctx.Event.Message {
|
||||
if elem.Type == "image" {
|
||||
if elem.Data["url"] != "" {
|
||||
urls = append(urls, elem.Data["url"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(urls) == 0 {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(urls[0], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 禁言检测
|
||||
func banCheck(ctx *zero.Ctx, bdres baiduRes) {
|
||||
// 如果返回类型为2(不合规),0为合规,3为疑似
|
||||
if bdres.ConclusionType == 2 {
|
||||
// 创建消息ID
|
||||
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
// 检测群配置里的不检测类型白名单,忽略掉不检测的违规类型
|
||||
for i, b := range group.WhiteListType {
|
||||
if i == bdres.Data[0].SubType && b {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 生成回复文本
|
||||
res := buildResp(bdres, group)
|
||||
// 撤回消息
|
||||
ctx.DeleteMessage(mid)
|
||||
// 查看是否启用撤回后禁言
|
||||
if group.DMBAN {
|
||||
// 从历史违规记录中获取指定用户
|
||||
user := group.getUser(ctx.Event.UserID)
|
||||
// 用户违规次数自增
|
||||
user.Count++
|
||||
// 用户违规原因记录
|
||||
user.ResList = append(user.ResList, bdres)
|
||||
// 覆写该用户到群违规记录中
|
||||
group.AuditHistory[ctx.Event.UserID] = user
|
||||
// 覆写该群信息
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
// 保存到json
|
||||
jsonSave(config, configpath)
|
||||
var bantime int64
|
||||
// 查看是否开启禁言累加功能,并计算禁言时间
|
||||
if group.BANTimeAddEnable {
|
||||
bantime = user.Count * group.BANTimeAddTime * 60
|
||||
} else {
|
||||
bantime = group.BANTime * 60
|
||||
}
|
||||
//执行禁言
|
||||
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
|
||||
}
|
||||
//查看是否开启撤回提示
|
||||
if group.DMRemind {
|
||||
res = append(res, message.At(ctx.Event.Sender.ID))
|
||||
ctx.SendChain(res...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群配置
|
||||
func getGroup(groupID int64) group {
|
||||
g, ok := config.Groups[groupID]
|
||||
if ok {
|
||||
return g
|
||||
}
|
||||
if config.Groups == nil {
|
||||
config.Groups = make(map[int64]group)
|
||||
}
|
||||
g = group{
|
||||
TextAudit: true,
|
||||
ImageAudit: true,
|
||||
BANTime: 1,
|
||||
MaxBANTimeAddRange: 60,
|
||||
BANTimeAddTime: 1,
|
||||
WhiteListType: [8]bool{},
|
||||
AuditHistory: map[int64]auditHistory{},
|
||||
}
|
||||
config.Groups[groupID] = g
|
||||
return g
|
||||
}
|
||||
|
||||
// 从群历史违规记录中获取用户
|
||||
func (group *group) getUser(userID int64) auditHistory {
|
||||
audit, ok := group.AuditHistory[userID]
|
||||
if ok {
|
||||
return audit
|
||||
}
|
||||
// 如果没有用户,则创建一个并返回
|
||||
if group.AuditHistory == nil {
|
||||
group.AuditHistory = make(map[int64]auditHistory)
|
||||
}
|
||||
audit = auditHistory{0, []baiduRes{}}
|
||||
group.AuditHistory[userID] = audit
|
||||
return audit
|
||||
}
|
||||
|
||||
// 客户端是否初始化检测
|
||||
func clientCheck(ctx *zero.Ctx) bool {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 加载JSON配置文件
|
||||
func loadConfig() {
|
||||
if file.IsExist(configpath) {
|
||||
data, err := os.OpenFile(configpath, os.O_RDONLY, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = json.NewDecoder(data).Decode(&config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
configinit = true
|
||||
} else {
|
||||
config = keyConfig{}
|
||||
configinit = false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
func jsonSave(v keyConfig, path string) {
|
||||
jsf, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}(jsf) // 结束时关闭句柄,释放资源
|
||||
err := json.NewEncoder(jsf).Encode(v)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// JSON反序列化
|
||||
func jsonToBaiduRes(resjson string) (baiduRes, error) {
|
||||
var bdres baiduRes
|
||||
err := json.Unmarshal(binary.StringToBytes(resjson), &bdres)
|
||||
return bdres, err
|
||||
}
|
||||
|
||||
// 生成回复文本
|
||||
func buildResp(bdres baiduRes, group group) []message.MessageSegment {
|
||||
// 建立消息段
|
||||
msgs := make([]message.MessageSegment, 0, 8)
|
||||
// 生成简略审核结果回复
|
||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||
// 查看是否开启详细审核内容提示,并确定审核内容值为疑似,或者不合规
|
||||
if !group.MoreRemind {
|
||||
return msgs
|
||||
}
|
||||
// 遍历返回的不合规数据,生成详细违规内容
|
||||
for i, datum := range bdres.Data {
|
||||
msgs = append(msgs, message.Text("[", i, "]:", datum.Msg, "\n"))
|
||||
// 检查命中词条是否大于0
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
// 遍历打印命中的违规词条
|
||||
for _, hit := range datum.Hits {
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
msgs = append(msgs, message.Text("("))
|
||||
for i4, i3 := range hit.Words {
|
||||
// 检查是否是最后一个要打印的词条,如果是则不加上逗号
|
||||
if i4 != len(hit.Words)-1 {
|
||||
msgs = append(msgs, message.Text(i3, ","))
|
||||
} else {
|
||||
msgs = append(msgs, message.Text(i3))
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, message.Text(")"))
|
||||
}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
62
plugin/base64gua/main.go
Normal file
62
plugin/base64gua/main.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Package base64gua base64卦 与 tea 加解密
|
||||
package base64gua
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/crypto"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/fumiama/unibase2n"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("base64gua", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "六十四卦加解密",
|
||||
Help: "- 六十四卦加密xxx\n- 六十四卦解密xxx\n- 六十四卦用yyy加密xxx\n- 六十四卦用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^六十四卦加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := unibase2n.Base64Gua.EncodeString(str)
|
||||
if es != "" {
|
||||
ctx.SendChain(message.Text(es))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^六十四卦解密\s*([䷀-䷿]+[☰☱]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := unibase2n.Base64Gua.DecodeString(str)
|
||||
if es != "" {
|
||||
ctx.SendChain(message.Text(es))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("解密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^六十四卦用(.+)加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := unibase2n.UTF16BE2UTF8(unibase2n.Base64Gua.Encode(t.Encrypt(helper.StringToBytes(str))))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(es)))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^六十四卦用(.+)解密\s*([䷀-䷿]+[☰☱]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := unibase2n.UTF82UTF16BE(helper.StringToBytes(str))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(t.Decrypt(unibase2n.Base64Gua.Decode(es)))))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("解密失败!"))
|
||||
}
|
||||
})
|
||||
}
|
||||
62
plugin/baseamasiro/main.go
Normal file
62
plugin/baseamasiro/main.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Package baseamasiro base天城文 与 tea 加解密
|
||||
package baseamasiro
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/crypto"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/fumiama/unibase2n"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("baseamasiro", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "天城文加解密",
|
||||
Help: "- 天城文加密xxx\n- 天城文解密xxx\n- 天城文用yyy加密xxx\n- 天城文用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^天城文加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := unibase2n.BaseDevanagari.EncodeString(str)
|
||||
if es != "" {
|
||||
ctx.SendChain(message.Text(es))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^天城文解密\s*([ऀ-ॿ]+[০-৫]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es := unibase2n.BaseDevanagari.DecodeString(str)
|
||||
if es != "" {
|
||||
ctx.SendChain(message.Text(es))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("解密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^天城文用(.+)加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := unibase2n.UTF16BE2UTF8(unibase2n.BaseDevanagari.Encode(t.Encrypt(helper.StringToBytes(str))))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(es)))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("加密失败!"))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^天城文用(.+)解密\s*([ऀ-ॿ]+[০-৫]?)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
key, str := ctx.State["regex_matched"].([]string)[1], ctx.State["regex_matched"].([]string)[2]
|
||||
t := crypto.GetTEA(key)
|
||||
es, err := unibase2n.UTF82UTF16BE(helper.StringToBytes(str))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(helper.BytesToString(t.Decrypt(unibase2n.BaseDevanagari.Decode(es)))))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("解密失败!"))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
var (
|
||||
errNeedCookie = errors.New("该api需要设置b站cookie,请发送命令设置cookie,例如\"设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\"")
|
||||
)
|
||||
|
||||
type searchResult struct {
|
||||
Mid int64 `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Gender int64 `json:"gender"`
|
||||
Usign string `json:"usign"`
|
||||
Level int64 `json:"level"`
|
||||
}
|
||||
|
||||
// 搜索api:通过把触发指令传入的昵称找出uid返回
|
||||
func search(keyword string) (r []searchResult, err error) {
|
||||
searchURL := "http://api.bilibili.com/x/web-interface/search/type?search_type=bili_user&keyword=" + keyword
|
||||
data, err := web.GetData(searchURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("data.numResults").Int() == 0 {
|
||||
err = errors.New("查无此人")
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(j.Get("data.result").Raw), &r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type follower struct {
|
||||
Mid int `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Video int `json:"video"`
|
||||
Roomid int `json:"roomid"`
|
||||
Rise int `json:"rise"`
|
||||
Follower int `json:"follower"`
|
||||
GuardNum int `json:"guardNum"`
|
||||
AreaRank int `json:"areaRank"`
|
||||
}
|
||||
|
||||
// 请求api
|
||||
func fansapi(uid string) (result follower, err error) {
|
||||
fanURL := "https://api.vtbs.moe/v1/detail/" + uid
|
||||
data, err := web.GetData(fanURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &result); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func followings(uid string) (s string, err error) {
|
||||
followingURL := "https://api.bilibili.com/x/relation/same/followings?vmid=" + uid
|
||||
method := "GET"
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, followingURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := vdb.getBilibiliCookie()
|
||||
req.Header.Add("cookie", c.Value)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(body)
|
||||
s = j.Get("data.list.#.uname").Raw
|
||||
if j.Get("code").Int() == -101 {
|
||||
err = errNeedCookie
|
||||
return
|
||||
}
|
||||
if j.Get("code").Int() != 0 {
|
||||
err = errors.New(j.Get("message").String())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type userinfo struct {
|
||||
Name string `json:"name"`
|
||||
Mid string `json:"mid"`
|
||||
Face string `json:"face"`
|
||||
Fans int64 `json:"fans"`
|
||||
Regtime int64 `json:"regtime"`
|
||||
Attentions []int64 `json:"attentions"`
|
||||
}
|
||||
|
||||
type medalInfo struct {
|
||||
Mid int64 `json:"target_id"`
|
||||
MedalName string `json:"medal_name"`
|
||||
Level int64 `json:"level"`
|
||||
MedalColorStart int64 `json:"medal_color_start"`
|
||||
MedalColorEnd int64 `json:"medal_color_end"`
|
||||
MedalColorBorder int64 `json:"medal_color_border"`
|
||||
}
|
||||
type medal struct {
|
||||
Uname string `json:"target_name"`
|
||||
medalInfo `json:"medal_info"`
|
||||
}
|
||||
|
||||
type medalSlice []medal
|
||||
|
||||
func (m medalSlice) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
func (m medalSlice) Swap(i, j int) {
|
||||
m[i], m[j] = m[j], m[i]
|
||||
}
|
||||
func (m medalSlice) Less(i, j int) bool {
|
||||
return m[i].Level > m[j].Level
|
||||
}
|
||||
|
||||
// 获取详情
|
||||
func card(uid string) (result userinfo, err error) {
|
||||
cardURL := "https://account.bilibili.com/api/member/getCardByMid?mid=" + uid
|
||||
data, err := web.GetData(cardURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("card").Raw), &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获得牌子
|
||||
func medalwall(uid string) (result []medal, err error) {
|
||||
medalwallURL := "https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id=" + uid
|
||||
method := "GET"
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, medalwallURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := vdb.getBilibiliCookie()
|
||||
req.Header.Add("cookie", c.Value)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("code").Int() == -101 {
|
||||
err = errNeedCookie
|
||||
return
|
||||
}
|
||||
if j.Get("code").Int() != 0 {
|
||||
err = errors.New(j.Get("message").String())
|
||||
}
|
||||
_ = json.Unmarshal(binary.StringToBytes(j.Get("data.list").Raw), &result)
|
||||
return
|
||||
}
|
||||
618
plugin/bilibili/bilibili.go
Normal file
618
plugin/bilibili/bilibili.go
Normal file
@@ -0,0 +1,618 @@
|
||||
// Package bilibili 查询b站用户信息
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile(`^\d+$`)
|
||||
danmakuTypeMap = map[int64]string{
|
||||
0: "普通消息",
|
||||
1: "礼物",
|
||||
2: "上舰",
|
||||
3: "Superchat",
|
||||
4: "进入直播间",
|
||||
5: "标题变动",
|
||||
}
|
||||
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||
)
|
||||
|
||||
// 查成分的
|
||||
func init() {
|
||||
engine := control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站查成分查弹幕",
|
||||
Help: "- >vup info [xxx]\n" +
|
||||
"- >user info [xxx]\n" +
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 查弹幕 [xxx]\n" +
|
||||
"- 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0;\n" +
|
||||
"- 更新vup" +
|
||||
"Tips: (412就是拦截的意思,建议私聊把cookie设全)\n",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
_ = os.RemoveAll(cachePath)
|
||||
_ = os.MkdirAll(cachePath, 0755)
|
||||
var getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
var err error
|
||||
_, _ = engine.GetLazyData("bilibili.db", false)
|
||||
vdb, err = initializeVup(engine.DataFolder() + "bilibili.db")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
engine.OnRegex(`^>user info\s?(.{1,25})$`, getPara).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
card, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"uid: ", card.Mid, "\n",
|
||||
"name: ", card.Name, "\n",
|
||||
"sex: ", card.Sex, "\n",
|
||||
"sign: ", card.Sign, "\n",
|
||||
"level: ", card.LevelInfo.CurrentLevel, "\n",
|
||||
"birthday: ", card.Birthday,
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^>vup info\s?(.{1,25})$`, getPara).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
// 获取详情
|
||||
fo, err := bz.GetVtbDetail(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"b站id: ", fo.Mid, "\n",
|
||||
"名字: ", fo.Uname, "\n",
|
||||
"当前粉丝数: ", fo.Follower, "\n",
|
||||
"24h涨粉数: ", fo.Rise, "\n",
|
||||
"视频投稿数: ", fo.Video, "\n",
|
||||
"直播间id: ", fo.Roomid, "\n",
|
||||
"舰队: ", fo.GuardNum, "\n",
|
||||
"直播总排名: ", fo.AreaRank, "\n",
|
||||
"数据来源: ", "https://vtbs.moe/detail/", fo.Mid, "\n",
|
||||
"数据获取时间: ", time.Now().Format("2006-01-02 15:04:05"),
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^查成分\s?(.{1,25})$`, getPara, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
today := time.Now().Format("20060102")
|
||||
drawedFile := cachePath + id + today + "vupLike.png"
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
return
|
||||
}
|
||||
u, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
vups, err := vdb.filterVup(u.Attentions)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
vupLen := len(vups)
|
||||
medals, err := bz.GetMedalWall(cfg, id)
|
||||
sort.Sort(bz.MedalSorter(medals))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
frontVups := make([]vup, 0)
|
||||
medalMap := make(map[int64]bz.Medal)
|
||||
for _, v := range medals {
|
||||
up := vup{
|
||||
Mid: v.Mid,
|
||||
Uname: v.Uname,
|
||||
}
|
||||
frontVups = append(frontVups, up)
|
||||
medalMap[v.Mid] = v
|
||||
}
|
||||
vups = append(vups, frontVups...)
|
||||
copy(vups[len(frontVups):], vups)
|
||||
copy(vups, frontVups)
|
||||
for i := len(frontVups); i < len(vups); i++ {
|
||||
if _, ok := medalMap[vups[i].Mid]; ok {
|
||||
vups = append(vups[:i], vups[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
facePath := cachePath + id + "vupFace" + path.Ext(u.Face)
|
||||
backX := 500
|
||||
backY := 500
|
||||
var back image.Image
|
||||
if path.Ext(u.Face) != ".webp" {
|
||||
err = initFacePic(facePath, u.Face)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back, err = gg.LoadImage(facePath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
}
|
||||
if len(vups) > 50 {
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了, 只展示前50个up"))
|
||||
vups = vups[:50]
|
||||
}
|
||||
canvas := gg.NewContext(1500, int(500*(1.1+float64(len(vups))/3)))
|
||||
fontSize := 50.0
|
||||
canvas.SetColor(color.White)
|
||||
canvas.Clear()
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sl, _ := canvas.MeasureString("好")
|
||||
length, h := canvas.MeasureString(u.Mid)
|
||||
n, _ := canvas.MeasureString(u.Name)
|
||||
canvas.DrawString(u.Name, 550, 160-h)
|
||||
canvas.DrawRoundedRectangle(600+n-length*0.1, 160-h*2.5, length*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(u.Mid, 600+n, 160-h)
|
||||
canvas.DrawString(fmt.Sprintf("粉丝:%d", u.Fans), 550, 240-h)
|
||||
canvas.DrawString(fmt.Sprintf("关注:%d", len(u.Attentions)), 1000, 240-h)
|
||||
canvas.DrawString(fmt.Sprintf("管人痴成分:%.2f%%(%d/%d)", float64(vupLen)/float64(len(u.Attentions))*100, vupLen, len(u.Attentions)), 550, 320-h)
|
||||
regtime := time.Unix(u.Regtime, 0).Format("2006-01-02 15:04:05")
|
||||
canvas.DrawString("注册日期:"+regtime, 550, 400-h)
|
||||
canvas.DrawString("查询日期:"+time.Now().Format("2006-01-02"), 550, 480-h)
|
||||
for i, v := range vups {
|
||||
if i%2 == 1 {
|
||||
canvas.SetRGB255(245, 245, 245)
|
||||
canvas.DrawRectangle(0, float64(backY)*1.1+float64(i)*float64(backY)/3, float64(backX*3), float64(backY)/3)
|
||||
canvas.Fill()
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
nl, _ := canvas.MeasureString(v.Uname)
|
||||
canvas.DrawString(v.Uname, float64(backX)*0.1, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
ml, _ := canvas.MeasureString(strconv.FormatInt(v.Mid, 10))
|
||||
canvas.DrawRoundedRectangle(nl-0.1*ml+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-h*3.5, ml*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(strconv.FormatInt(v.Mid, 10), nl+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
if m, ok := medalMap[v.Mid]; ok {
|
||||
mnl, _ := canvas.MeasureString(m.MedalName)
|
||||
grad := gg.NewLinearGradient(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h, nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
r, g, b := int2rbg(m.MedalColorStart)
|
||||
grad.AddColorStop(0, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
|
||||
r, g, b = int2rbg(m.MedalColorEnd)
|
||||
grad.AddColorStop(1, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
|
||||
canvas.SetFillStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.White)
|
||||
canvas.DrawString(m.MedalName, nl+ml+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
r, g, b = int2rbg(m.MedalColorBorder)
|
||||
canvas.SetRGB255(int(r), int(g), int(b))
|
||||
canvas.DrawString(strconv.FormatInt(m.Level, 10), nl+ml+mnl+sl+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
mll, _ := canvas.MeasureString(strconv.FormatInt(m.Level, 10))
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
}
|
||||
}
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(canvas.Image(), f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^查弹幕\s?(\S{1,25})\s?(\d*)$`, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
pagenum := ctx.State["regex_matched"].([]string)[2]
|
||||
if pagenum == "" {
|
||||
pagenum = "0"
|
||||
}
|
||||
u, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var danmaku bz.Danmakusuki
|
||||
tr := &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
data, err := web.RequestDataWith(client, fmt.Sprintf(bz.DanmakuAPI, id, pagenum), "GET", "", web.RandUA())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &danmaku)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
today := time.Now().Format("20060102150415")
|
||||
drawedFile := cachePath + id + today + "vupLike.png"
|
||||
facePath := cachePath + id + "vupFace" + path.Ext(u.Face)
|
||||
backX := 500
|
||||
backY := 500
|
||||
var back image.Image
|
||||
if path.Ext(u.Face) != ".webp" {
|
||||
err = initFacePic(facePath, u.Face)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back, err = gg.LoadImage(facePath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
}
|
||||
canvas := gg.NewContext(100, 100)
|
||||
fontSize := 50.0
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
dz, h := canvas.MeasureString("好")
|
||||
danmuH := h * 2
|
||||
faceH := float64(510)
|
||||
|
||||
totalDanmuku := 0
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
totalDanmuku += len(danmaku.Data.Data[i].Danmakus) + 1
|
||||
}
|
||||
cw := 10000
|
||||
mcw := float64(2000)
|
||||
ch := 550 + len(danmaku.Data.Data)*int(faceH) + totalDanmuku*int(danmuH)
|
||||
canvas = gg.NewContext(cw, ch)
|
||||
canvas.SetColor(color.White)
|
||||
canvas.Clear()
|
||||
canvas.SetColor(color.Black)
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
facestart := 100
|
||||
fontH := h * 1.6
|
||||
startWidth := float64(700)
|
||||
startWidth2 := float64(20)
|
||||
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, facestart, 0)
|
||||
}
|
||||
length, _ := canvas.MeasureString(u.Mid)
|
||||
n, _ := canvas.MeasureString(u.Name)
|
||||
canvas.DrawString(u.Name, startWidth, 122.5)
|
||||
canvas.DrawRoundedRectangle(900+n-length*0.1, 66, length*1.2, 75, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(u.Mid, 900+n, 122.5)
|
||||
canvas.DrawString(fmt.Sprintf("粉丝:%d 关注:%d", u.Fans, u.Attention), startWidth, 222.5)
|
||||
canvas.DrawString(fmt.Sprintf("页码:[%d/%d]", danmaku.Data.PageNum, (danmaku.Data.Total-1)/5), startWidth, 322.5)
|
||||
canvas.DrawString("网页链接: "+fmt.Sprintf(bz.DanmakuURL, u.Mid), startWidth, 422.5)
|
||||
var channelStart float64
|
||||
channelStart = float64(550)
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
item := danmaku.Data.Data[i]
|
||||
facePath = cachePath + strconv.Itoa(int(item.Channel.UID)) + "vupFace" + path.Ext(item.Channel.FaceURL)
|
||||
if path.Ext(item.Channel.FaceURL) != ".webp" {
|
||||
err = initFacePic(facePath, item.Channel.FaceURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back, err = gg.LoadImage(facePath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
}
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, facestart, int(channelStart))
|
||||
}
|
||||
canvas.SetRGB255(24, 144, 255)
|
||||
canvas.DrawString("标题: "+item.Live.Title, startWidth, channelStart+fontH)
|
||||
canvas.DrawString("主播: "+item.Channel.Name, startWidth, channelStart+fontH*2)
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString("开始时间: "+time.UnixMilli(item.Live.StartDate).Format("2006-01-02 15:04:05"), startWidth, channelStart+fontH*3)
|
||||
if item.Live.IsFinish {
|
||||
canvas.DrawString("结束时间: "+time.UnixMilli(item.Live.StopDate).Format("2006-01-02 15:04:05"), startWidth, channelStart+fontH*4)
|
||||
canvas.DrawString("直播时长: "+strconv.FormatFloat(float64(item.Live.StopDate-item.Live.StartDate)/3600000.0, 'f', 1, 64)+"小时", startWidth, channelStart+fontH*5)
|
||||
} else {
|
||||
t := "结束时间:"
|
||||
l, _ := canvas.MeasureString(t)
|
||||
canvas.DrawString(t, startWidth, channelStart+fontH*4)
|
||||
|
||||
canvas.SetRGB255(0, 128, 0)
|
||||
t = "正在直播"
|
||||
canvas.DrawString(t, startWidth+l*1.1, channelStart+fontH*4)
|
||||
canvas.SetColor(color.Black)
|
||||
|
||||
canvas.DrawString("直播时长: "+strconv.FormatFloat(float64(time.Now().UnixMilli()-item.Live.StartDate)/3600000.0, 'f', 1, 64)+"小时", startWidth, channelStart+fontH*5)
|
||||
}
|
||||
canvas.DrawString("弹幕数量: "+strconv.Itoa(int(item.Live.DanmakusCount)), startWidth, channelStart+fontH*6)
|
||||
canvas.DrawString("观看次数: "+strconv.Itoa(int(item.Live.WatchCount)), startWidth, channelStart+fontH*7)
|
||||
|
||||
t := "收益:"
|
||||
l, _ := canvas.MeasureString(t)
|
||||
canvas.DrawString(t, startWidth, channelStart+fontH*8)
|
||||
|
||||
t = "¥" + strconv.Itoa(int(item.Live.TotalIncome))
|
||||
canvas.SetRGB255(255, 0, 0)
|
||||
canvas.DrawString(t, startWidth+l*1.1, channelStart+fontH*8)
|
||||
canvas.SetColor(color.Black)
|
||||
|
||||
DanmakuStart := channelStart + faceH
|
||||
for i := 0; i < len(item.Danmakus); i++ {
|
||||
moveW := startWidth2
|
||||
danmuNow := DanmakuStart + danmuH*float64(i+1)
|
||||
danItem := item.Danmakus[i]
|
||||
|
||||
t := time.UnixMilli(danItem.SendDate).Format("15:04:05")
|
||||
l, _ := canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l + dz
|
||||
|
||||
t = danItem.Name
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.SetRGB255(24, 144, 255)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
canvas.SetColor(color.Black)
|
||||
moveW += l + dz
|
||||
|
||||
switch danItem.Type {
|
||||
case 0:
|
||||
t = danItem.Message
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l + dz
|
||||
case 1:
|
||||
t = danmakuTypeMap[danItem.Type]
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.SetRGB255(255, 0, 0)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l + dz
|
||||
|
||||
t = danItem.Message
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
canvas.SetColor(color.Black)
|
||||
moveW += l + dz
|
||||
case 2, 3:
|
||||
t = danmakuTypeMap[danItem.Type]
|
||||
l, _ = canvas.MeasureString(t)
|
||||
if danItem.Type == 3 {
|
||||
canvas.SetRGB255(0, 85, 255)
|
||||
} else {
|
||||
canvas.SetRGB255(128, 0, 128)
|
||||
}
|
||||
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l + dz
|
||||
|
||||
t = danItem.Message
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l
|
||||
|
||||
t = "["
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l
|
||||
|
||||
t = "¥" + strconv.FormatFloat(danItem.Price, 'f', 1, 64)
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.SetRGB255(255, 0, 0)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
if danItem.Type == 3 {
|
||||
canvas.SetRGB255(0, 85, 255)
|
||||
} else {
|
||||
canvas.SetRGB255(128, 0, 128)
|
||||
}
|
||||
moveW += l
|
||||
|
||||
t = "]"
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
canvas.SetColor(color.Black)
|
||||
moveW += l + dz
|
||||
case 4, 5:
|
||||
t = danmakuTypeMap[danItem.Type]
|
||||
canvas.SetRGB255(0, 128, 0)
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
canvas.SetColor(color.Black)
|
||||
moveW += l + dz
|
||||
}
|
||||
if moveW > mcw {
|
||||
mcw = moveW
|
||||
}
|
||||
}
|
||||
channelStart = DanmakuStart + float64(len(item.Danmakus)+1)*danmuH
|
||||
}
|
||||
im := canvas.Image().(*image.RGBA)
|
||||
nim := im.SubImage(image.Rect(0, 0, int(mcw), ch))
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(nim)
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(nim, f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^设置b站cookie?\s+(.*)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
cookie := ctx.State["regex_matched"].([]string)[1]
|
||||
err := cfg.Set(cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置b站cookie为" + cookie))
|
||||
})
|
||||
|
||||
engine.OnFullMatch("更新vup", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
err := updateVup()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("vup已更新"))
|
||||
})
|
||||
}
|
||||
|
||||
func initFacePic(filename, faceURL string) error {
|
||||
if file.IsNotExist(filename) {
|
||||
data, err := web.GetData(faceURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(filename, data, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func int2rbg(t int64) (int64, int64, int64) {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(t))
|
||||
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
func getPara(ctx *zero.Ctx) bool {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
if !re.MatchString(keyword) {
|
||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
||||
return true
|
||||
}
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
ctx.SendChain(message.Text("输入为纯数字, 请选择查询uid还是用户名, 输入对应序号:\n0. 查询uid\n1. 查询用户名"))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10):
|
||||
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询uid"))
|
||||
ctx.State["uid"] = keyword
|
||||
return true
|
||||
case c := <-recv:
|
||||
msg := c.Event.Message.ExtractPlainText()
|
||||
num, err := strconv.Atoi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("请输入数字!"))
|
||||
continue
|
||||
}
|
||||
if num < 0 || num > 1 {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
if num == 0 {
|
||||
ctx.State["uid"] = keyword
|
||||
return true
|
||||
} else if num == 1 {
|
||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
107
plugin/bilibili/bilibili_parse.go
Normal file
107
plugin/bilibili/bilibili_parse.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Package bilibili bilibili卡片解析
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
limit = ctxext.NewLimiterManager(time.Second*10, 1)
|
||||
searchVideo = `bilibili.com\\?/video\\?/(?:av(\d+)|([bB][vV][0-9a-zA-Z]+))`
|
||||
searchDynamic = `(t.bilibili.com|m.bilibili.com\\?/dynamic)\\?/(\d+)`
|
||||
searchArticle = `bilibili.com\\?/read\\?/(?:cv|mobile\\?/)(\d+)`
|
||||
searchLiveRoom = `live.bilibili.com\\?/(\d+)`
|
||||
searchVideoRe = regexp.MustCompile(searchVideo)
|
||||
searchDynamicRe = regexp.MustCompile(searchDynamic)
|
||||
searchArticleRe = regexp.MustCompile(searchArticle)
|
||||
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
|
||||
)
|
||||
|
||||
// 插件主体
|
||||
func init() {
|
||||
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站链接解析",
|
||||
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
|
||||
})
|
||||
en.OnRegex(`((b23|acg).tv|bili2233.cn)/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
url := ctx.State["regex_matched"].([]string)[0]
|
||||
realurl, err := bz.GetRealUrl("https://" + url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case searchVideoRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchVideoRe.FindStringSubmatch(realurl)
|
||||
handleVideo(ctx)
|
||||
case searchDynamicRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchDynamicRe.FindStringSubmatch(realurl)
|
||||
handleDynamic(ctx)
|
||||
case searchArticleRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchArticleRe.FindStringSubmatch(realurl)
|
||||
handleArticle(ctx)
|
||||
case searchLiveRoomRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchLiveRoomRe.FindStringSubmatch(realurl)
|
||||
handleLive(ctx)
|
||||
}
|
||||
})
|
||||
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
|
||||
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
|
||||
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
|
||||
en.OnRegex(searchLiveRoom).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleLive)
|
||||
}
|
||||
|
||||
func handleVideo(ctx *zero.Ctx) {
|
||||
id := ctx.State["regex_matched"].([]string)[1]
|
||||
if id == "" {
|
||||
id = ctx.State["regex_matched"].([]string)[2]
|
||||
}
|
||||
card, err := bz.GetVideoInfo(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
msg, err := videoCard2msg(card)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(msg...)
|
||||
}
|
||||
|
||||
func handleDynamic(ctx *zero.Ctx) {
|
||||
msg, err := dynamicDetail(ctx.State["regex_matched"].([]string)[2])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(msg...)
|
||||
}
|
||||
|
||||
func handleArticle(ctx *zero.Ctx) {
|
||||
card, err := bz.GetArticleInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(articleCard2msg(card, ctx.State["regex_matched"].([]string)[1])...)
|
||||
}
|
||||
|
||||
func handleLive(ctx *zero.Ctx) {
|
||||
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(liveCard2msg(card)...)
|
||||
}
|
||||
@@ -3,17 +3,13 @@ package bilibili
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
_ "github.com/fumiama/sqlite3" // use sql
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
bilibiliCookie = "bilbili_cookie"
|
||||
)
|
||||
|
||||
var (
|
||||
vtbURLs = [...]string{"https://api.vtbs.moe/v1/short", "https://api.tokyo.vtbs.moe/v1/short", "https://vtbs.musedash.moe/v1/short"}
|
||||
vdb *vupdb
|
||||
@@ -32,17 +28,8 @@ func (vup) TableName() string {
|
||||
return "vup"
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Key string `gorm:"column:key;primary_key"`
|
||||
Value string `gorm:"column:value"`
|
||||
}
|
||||
|
||||
func (config) TableName() string {
|
||||
return "config"
|
||||
}
|
||||
|
||||
// initialize 初始化vtb数据库
|
||||
func initialize(dbpath string) (*vupdb, error) {
|
||||
// initializeVup 初始化vup数据库
|
||||
func initializeVup(dbpath string) (*vupdb, error) {
|
||||
if _, err := os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
@@ -55,7 +42,7 @@ func initialize(dbpath string) (*vupdb, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gdb.AutoMigrate(&vup{}).AutoMigrate(&config{})
|
||||
gdb.AutoMigrate(&vup{})
|
||||
return (*vupdb)(gdb), nil
|
||||
}
|
||||
|
||||
@@ -102,29 +89,3 @@ func updateVup() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vdb *vupdb) setBilibiliCookie(cookie string) (err error) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
c := config{
|
||||
Key: bilibiliCookie,
|
||||
Value: cookie,
|
||||
}
|
||||
if err = db.Model(&config{}).First(&c, "key = ? ", bilibiliCookie).Error; err != nil {
|
||||
// error handling...
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
err = db.Model(&config{}).Create(&c).Error
|
||||
}
|
||||
} else {
|
||||
err = db.Model(&config{}).Where("key = ? ", bilibiliCookie).Update(
|
||||
map[string]interface{}{
|
||||
"value": cookie,
|
||||
}).Error
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (vdb *vupdb) getBilibiliCookie() (c config) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
db.Model(&config{}).First(&c, "key = ?", bilibiliCookie)
|
||||
return
|
||||
}
|
||||
364
plugin/bilibili/bilibilipush.go
Normal file
364
plugin/bilibili/bilibilipush.go
Normal file
@@ -0,0 +1,364 @@
|
||||
// Package bilibili b站推送
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
const (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
referer = "https://www.bilibili.com/"
|
||||
infoURL = "https://api.bilibili.com/x/space/acc/info?mid=%v"
|
||||
)
|
||||
|
||||
// bdb bilibili推送数据库
|
||||
var bdb *bilibilipushdb
|
||||
|
||||
var (
|
||||
lastTime = map[int64]int64{}
|
||||
liveStatus = map[int64]int{}
|
||||
upMap = map[int64]string{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("bilibilipush", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站推送",
|
||||
Help: "- 添加b站订阅[uid|name]\n" +
|
||||
"- 取消b站订阅[uid|name]\n" +
|
||||
"- 取消b站动态订阅[uid|name]\n" +
|
||||
"- 取消b站直播订阅[uid|name]\n" +
|
||||
"- b站推送列表\n" +
|
||||
"Tips: 需要配合job一起使用, 全局只需要设置一个, 无视响应状态推送, 下为例子\n" +
|
||||
"记录在\"@every 5m\"触发的指令)\n" +
|
||||
"拉取b站推送",
|
||||
PrivateDataFolder: "bilibilipush",
|
||||
})
|
||||
|
||||
// 加载bilibili推送数据库
|
||||
dbpath := en.DataFolder()
|
||||
dbfile := dbpath + "push.db"
|
||||
bdb = initializePush(dbfile)
|
||||
|
||||
en.OnRegex(`^添加b站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||
name, err := getName(buid)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if err := subscribe(buid, gid); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("已添加" + name + "的订阅"))
|
||||
})
|
||||
en.OnRegex(`^取消b站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||
name, err := getName(buid)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if err := unsubscribe(buid, gid); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("已取消" + name + "的订阅"))
|
||||
})
|
||||
en.OnRegex(`^取消b站动态订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||
name, err := getName(buid)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if err := unsubscribeDynamic(buid, gid); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("已取消" + name + "的动态订阅"))
|
||||
})
|
||||
en.OnRegex(`^取消b站直播订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
name, err := getName(buid)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if err := unsubscribeLive(buid, gid); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("已取消" + name + "的直播订阅"))
|
||||
})
|
||||
en.OnFullMatch("b站推送列表", zero.UserOrGrpAdmin).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
bpl := bdb.getAllPushByGroup(gid)
|
||||
msg := "--------b站推送列表--------"
|
||||
for _, v := range bpl {
|
||||
if _, ok := upMap[v.BilibiliUID]; !ok {
|
||||
bdb.updateAllUp()
|
||||
}
|
||||
msg += fmt.Sprintf("\nuid:%-12d 动态:", v.BilibiliUID)
|
||||
if v.DynamicDisable == 0 {
|
||||
msg += "●"
|
||||
} else {
|
||||
msg += "○"
|
||||
}
|
||||
msg += " 直播:"
|
||||
if v.LiveDisable == 0 {
|
||||
msg += "●"
|
||||
} else {
|
||||
msg += "○"
|
||||
}
|
||||
msg += " up主:" + upMap[v.BilibiliUID]
|
||||
}
|
||||
data, err := text.RenderToBase64(msg, text.FontFile, 600, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
en.OnFullMatch("拉取b站推送").SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := sendDynamic(ctx)
|
||||
if err != nil {
|
||||
ctx.SendPrivateMessage(ctx.Event.UserID, message.Text("Error: bilibilipush,", err))
|
||||
}
|
||||
err = sendLive(ctx)
|
||||
if err != nil {
|
||||
ctx.SendPrivateMessage(ctx.Event.UserID, message.Text("Error: bilibilipush,", err))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 取得uid的名字
|
||||
func getName(buid int64) (name string, err error) {
|
||||
var ok bool
|
||||
if name, ok = upMap[buid]; !ok {
|
||||
var data []byte
|
||||
data, err = web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(infoURL, buid), "GET", referer, ua)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
status := int(gjson.Get(binary.BytesToString(data), "code").Int())
|
||||
if status != 0 {
|
||||
err = errors.New(gjson.Get(binary.BytesToString(data), "message").String())
|
||||
return
|
||||
}
|
||||
name = gjson.Get(binary.BytesToString(data), "data.name").String()
|
||||
bdb.insertBilibiliUp(buid, name)
|
||||
upMap[buid] = name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// subscribe 订阅
|
||||
func subscribe(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 0,
|
||||
"dynamic_disable": 0,
|
||||
}
|
||||
return bdb.insertOrUpdateLiveAndDynamic(bpMap)
|
||||
}
|
||||
|
||||
// unsubscribe 取消订阅
|
||||
func unsubscribe(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 1,
|
||||
"dynamic_disable": 1,
|
||||
}
|
||||
return bdb.insertOrUpdateLiveAndDynamic(bpMap)
|
||||
}
|
||||
|
||||
func unsubscribeDynamic(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"dynamic_disable": 1,
|
||||
}
|
||||
return bdb.insertOrUpdateLiveAndDynamic(bpMap)
|
||||
}
|
||||
|
||||
func unsubscribeLive(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 1,
|
||||
}
|
||||
return bdb.insertOrUpdateLiveAndDynamic(bpMap)
|
||||
}
|
||||
|
||||
func getUserDynamicCard(buid int64) (cardList []gjson.Result, err error) {
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(bz.SpaceHistoryURL, buid, 0), "GET", referer, ua)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cardList = gjson.Get(binary.BytesToString(data), "data.cards").Array()
|
||||
return
|
||||
}
|
||||
|
||||
func getLiveList(uids ...int64) (string, error) {
|
||||
m := make(map[string]any)
|
||||
m["uids"] = uids
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := web.PostData(bz.LiveListURL, "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return binary.BytesToString(data), nil
|
||||
}
|
||||
|
||||
func sendDynamic(ctx *zero.Ctx) error {
|
||||
uids := bdb.getAllBuidByDynamic()
|
||||
for _, buid := range uids {
|
||||
time.Sleep(2 * time.Second)
|
||||
cardList, err := getUserDynamicCard(buid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(cardList) == 0 {
|
||||
return errors.Errorf("%v的历史动态数为0", buid)
|
||||
}
|
||||
t, ok := lastTime[buid]
|
||||
// 第一次先记录时间,啥也不做
|
||||
if !ok {
|
||||
lastTime[buid] = cardList[0].Get("desc.timestamp").Int()
|
||||
return nil
|
||||
}
|
||||
for i := len(cardList) - 1; i >= 0; i-- {
|
||||
ct := cardList[i].Get("desc.timestamp").Int()
|
||||
if ct > t && ct > time.Now().Unix()-600 {
|
||||
lastTime[buid] = ct
|
||||
m, ok := control.Lookup("bilibilipush")
|
||||
if ok {
|
||||
groupList := bdb.getAllGroupByBuidAndDynamic(buid)
|
||||
dc, err := bz.LoadDynamicDetail(cardList[i].Raw)
|
||||
if err != nil {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
}
|
||||
msg, err := dynamicCard2msg(&dc)
|
||||
if err != nil {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
}
|
||||
for _, gid := range groupList {
|
||||
if m.IsEnabledIn(gid) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
switch {
|
||||
case gid > 0:
|
||||
ctx.SendGroupMessage(gid, msg)
|
||||
case gid < 0:
|
||||
ctx.SendPrivateMessage(-gid, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendLive(ctx *zero.Ctx) error {
|
||||
uids := bdb.getAllBuidByLive()
|
||||
ll, err := getLiveList(uids...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gjson.Get(ll, "data").ForEach(func(key, value gjson.Result) bool {
|
||||
newStatus := int(value.Get("live_status").Int())
|
||||
if newStatus == 2 {
|
||||
newStatus = 0
|
||||
}
|
||||
if _, ok := liveStatus[key.Int()]; !ok {
|
||||
liveStatus[key.Int()] = newStatus
|
||||
return true
|
||||
}
|
||||
oldStatus := liveStatus[key.Int()]
|
||||
if newStatus != oldStatus && newStatus == 1 {
|
||||
liveStatus[key.Int()] = newStatus
|
||||
m, ok := control.Lookup("bilibilipush")
|
||||
if ok {
|
||||
groupList := bdb.getAllGroupByBuidAndLive(key.Int())
|
||||
roomID := value.Get("short_id").Int()
|
||||
if roomID == 0 {
|
||||
roomID = value.Get("room_id").Int()
|
||||
}
|
||||
lURL := bz.LiveURL + strconv.FormatInt(roomID, 10)
|
||||
lName := value.Get("uname").String()
|
||||
lTitle := value.Get("title").String()
|
||||
lCover := value.Get("cover_from_user").String()
|
||||
if lCover == "" {
|
||||
lCover = value.Get("keyframe").String()
|
||||
}
|
||||
var msg []message.MessageSegment
|
||||
msg = append(msg, message.Text(lName+" 正在直播:\n"))
|
||||
msg = append(msg, message.Text(lTitle))
|
||||
msg = append(msg, message.Image(lCover))
|
||||
msg = append(msg, message.Text("直播链接:", lURL))
|
||||
for _, gid := range groupList {
|
||||
if m.IsEnabledIn(gid) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
switch {
|
||||
case gid > 0:
|
||||
ctx.SendGroupMessage(gid, msg)
|
||||
case gid < 0:
|
||||
ctx.SendPrivateMessage(-gid, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if newStatus != oldStatus {
|
||||
liveStatus[key.Int()] = newStatus
|
||||
}
|
||||
return true
|
||||
})
|
||||
return nil
|
||||
}
|
||||
150
plugin/bilibili/bilibilipushmodel.go
Normal file
150
plugin/bilibili/bilibilipushmodel.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
_ "github.com/fumiama/sqlite3" // import sql
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// bilibilipushdb bilibili推送数据库
|
||||
type bilibilipushdb gorm.DB
|
||||
|
||||
type bilibilipush struct {
|
||||
ID int64 `gorm:"column:id;primary_key" json:"id"`
|
||||
BilibiliUID int64 `gorm:"column:bilibili_uid;index:idx_buid_gid" json:"bilibili_uid"`
|
||||
GroupID int64 `gorm:"column:group_id;index:idx_buid_gid" json:"group_id"`
|
||||
LiveDisable int64 `gorm:"column:live_disable;default:0" json:"live_disable"`
|
||||
DynamicDisable int64 `gorm:"column:dynamic_disable;default:0" json:"dynamic_disable"`
|
||||
}
|
||||
|
||||
// TableName ...
|
||||
func (bilibilipush) TableName() string {
|
||||
return "bilibili_push"
|
||||
}
|
||||
|
||||
type bilibiliup struct {
|
||||
BilibiliUID int64 `gorm:"column:bilibili_uid;primary_key"`
|
||||
Name string `gorm:"column:name"`
|
||||
}
|
||||
|
||||
// TableName ...
|
||||
func (bilibiliup) TableName() string {
|
||||
return "bilibili_up"
|
||||
}
|
||||
|
||||
// initializePush 初始化bilibilipushdb数据库
|
||||
func initializePush(dbpath string) *bilibilipushdb {
|
||||
var err error
|
||||
if _, err = os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
gdb, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gdb.AutoMigrate(&bilibilipush{}).AutoMigrate(&bilibiliup{})
|
||||
return (*bilibilipushdb)(gdb)
|
||||
}
|
||||
|
||||
// insertOrUpdateLiveAndDynamic 插入或更新数据库
|
||||
func (bdb *bilibilipushdb) insertOrUpdateLiveAndDynamic(bpMap map[string]any) (err error) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
bp := bilibilipush{}
|
||||
data, err := json.Marshal(&bpMap)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &bp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = db.Model(&bilibilipush{}).First(&bp, "bilibili_uid = ? and group_id = ?", bp.BilibiliUID, bp.GroupID).Error; err != nil {
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
err = db.Model(&bilibilipush{}).Create(&bp).Error
|
||||
}
|
||||
} else {
|
||||
err = db.Model(&bilibilipush{}).Where("bilibili_uid = ? and group_id = ?", bp.BilibiliUID, bp.GroupID).Update(bpMap).Error
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) getAllBuidByLive() (buidList []int64) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
var bpl []bilibilipush
|
||||
db.Model(&bilibilipush{}).Find(&bpl, "live_disable = 0")
|
||||
temp := make(map[int64]bool)
|
||||
for _, v := range bpl {
|
||||
_, ok := temp[v.BilibiliUID]
|
||||
if !ok {
|
||||
buidList = append(buidList, v.BilibiliUID)
|
||||
temp[v.BilibiliUID] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) getAllBuidByDynamic() (buidList []int64) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
var bpl []bilibilipush
|
||||
db.Model(&bilibilipush{}).Find(&bpl, "dynamic_disable = 0")
|
||||
temp := make(map[int64]bool)
|
||||
for _, v := range bpl {
|
||||
_, ok := temp[v.BilibiliUID]
|
||||
if !ok {
|
||||
buidList = append(buidList, v.BilibiliUID)
|
||||
temp[v.BilibiliUID] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) getAllGroupByBuidAndLive(buid int64) (groupList []int64) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
var bpl []bilibilipush
|
||||
db.Model(&bilibilipush{}).Find(&bpl, "bilibili_uid = ? and live_disable = 0", buid)
|
||||
for _, v := range bpl {
|
||||
groupList = append(groupList, v.GroupID)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) getAllGroupByBuidAndDynamic(buid int64) (groupList []int64) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
var bpl []bilibilipush
|
||||
db.Model(&bilibilipush{}).Find(&bpl, "bilibili_uid = ? and dynamic_disable = 0", buid)
|
||||
for _, v := range bpl {
|
||||
groupList = append(groupList, v.GroupID)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) getAllPushByGroup(groupID int64) (bpl []bilibilipush) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
db.Model(&bilibilipush{}).Find(&bpl, "group_id = ? and (live_disable = 0 or dynamic_disable = 0)", groupID)
|
||||
return
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) insertBilibiliUp(buid int64, name string) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
bu := bilibiliup{
|
||||
BilibiliUID: buid,
|
||||
Name: name,
|
||||
}
|
||||
db.Model(&bilibiliup{}).Create(bu)
|
||||
}
|
||||
|
||||
func (bdb *bilibilipushdb) updateAllUp() {
|
||||
db := (*gorm.DB)(bdb)
|
||||
var bul []bilibiliup
|
||||
db.Model(&bilibiliup{}).Find(&bul)
|
||||
for _, v := range bul {
|
||||
upMap[v.BilibiliUID] = v.Name
|
||||
}
|
||||
}
|
||||
326
plugin/bilibili/card2msg.go
Normal file
326
plugin/bilibili/card2msg.go
Normal file
@@ -0,0 +1,326 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
msgType = map[int]string{
|
||||
1: "转发了动态",
|
||||
2: "有图营业",
|
||||
4: "无图营业",
|
||||
8: "投稿了视频",
|
||||
16: "投稿了短视频",
|
||||
64: "投稿了文章",
|
||||
256: "投稿了音频",
|
||||
2048: "发布了简报",
|
||||
4200: "发布了直播",
|
||||
4308: "发布了直播",
|
||||
}
|
||||
)
|
||||
|
||||
// dynamicCard2msg 处理DynCard
|
||||
func dynamicCard2msg(dynamicCard *bz.DynamicCard) (msg []message.MessageSegment, err error) {
|
||||
var (
|
||||
card bz.Card
|
||||
vote bz.Vote
|
||||
cType int
|
||||
)
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
// 初始化结构体
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
cType = dynamicCard.Desc.Type
|
||||
// 生成消息
|
||||
switch cType {
|
||||
case 1:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Item.Content, "\n",
|
||||
"转发的内容: \n"))
|
||||
var originMsg []message.MessageSegment
|
||||
var co bz.Card
|
||||
co, err = bz.LoadCardDetail(card.Origin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, originMsg...)
|
||||
case 2:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
||||
}
|
||||
case 4:
|
||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Content, "\n"))
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
||||
for i := 0; i < len(vote.Options); i++ {
|
||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
||||
if vote.Options[i].ImgURL != "" {
|
||||
msg = append(msg, message.Image(vote.Options[i].ImgURL))
|
||||
}
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text(card.Desc, "\n",
|
||||
card.ShareSubtitle, "\n",
|
||||
"视频链接: ", card.ShortLink, "\n"))
|
||||
case 16:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
||||
case 64:
|
||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title, "\n",
|
||||
card.Summary))
|
||||
for i := 0; i < len(card.ImageUrls); i++ {
|
||||
msg = append(msg, message.Image(card.ImageUrls[i]))
|
||||
}
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
||||
}
|
||||
case 256:
|
||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Cover))
|
||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
|
||||
}
|
||||
|
||||
case 2048:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Vest.Content, "\n",
|
||||
card.Sketch.Title, "\n",
|
||||
card.Sketch.DescText, "\n"))
|
||||
msg = append(msg, message.Image(card.Sketch.CoverURL))
|
||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
||||
case 4308:
|
||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
||||
}
|
||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
||||
"房间号: ", card.LivePlayInfo.RoomID, "\n",
|
||||
"分区: ", card.LivePlayInfo.ParentAreaName))
|
||||
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
|
||||
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
|
||||
}
|
||||
if card.LivePlayInfo.LiveStatus == 0 {
|
||||
msg = append(msg, message.Text("未开播 \n"))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
|
||||
default:
|
||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
||||
}
|
||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// card2msg cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
|
||||
func card2msg(dynamicCard *bz.DynamicCard, card *bz.Card, cType int) (msg []message.MessageSegment, err error) {
|
||||
var (
|
||||
vote bz.Vote
|
||||
)
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
// 生成消息
|
||||
switch cType {
|
||||
case 1:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Item.Content, "\n",
|
||||
"转发的内容: \n"))
|
||||
var originMsg []message.MessageSegment
|
||||
var co bz.Card
|
||||
co, err = bz.LoadCardDetail(card.Origin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, originMsg...)
|
||||
case 2:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
||||
}
|
||||
case 4:
|
||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Content, "\n"))
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
||||
for i := 0; i < len(vote.Options); i++ {
|
||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
||||
if vote.Options[i].ImgURL != "" {
|
||||
msg = append(msg, message.Image(vote.Options[i].ImgURL))
|
||||
}
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text(card.Desc, "\n",
|
||||
card.ShareSubtitle, "\n",
|
||||
"视频链接: ", card.ShortLink, "\n"))
|
||||
case 16:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
||||
case 64:
|
||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title, "\n",
|
||||
card.Summary))
|
||||
for i := 0; i < len(card.ImageUrls); i++ {
|
||||
msg = append(msg, message.Image(card.ImageUrls[i]))
|
||||
}
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
||||
}
|
||||
case 256:
|
||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Cover))
|
||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
|
||||
}
|
||||
|
||||
case 2048:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Vest.Content, "\n",
|
||||
card.Sketch.Title, "\n",
|
||||
card.Sketch.DescText, "\n"))
|
||||
msg = append(msg, message.Image(card.Sketch.CoverURL))
|
||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
||||
case 4308:
|
||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
||||
}
|
||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
||||
"房间号: ", card.LivePlayInfo.RoomID, "\n",
|
||||
"分区: ", card.LivePlayInfo.ParentAreaName))
|
||||
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
|
||||
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
|
||||
}
|
||||
if card.LivePlayInfo.LiveStatus == 0 {
|
||||
msg = append(msg, message.Text("未开播 \n"))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
|
||||
default:
|
||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
||||
}
|
||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// dynamicDetail 用动态id查动态信息
|
||||
func dynamicDetail(dynamicIDStr string) (msg []message.MessageSegment, err error) {
|
||||
dyc, err := bz.GetDynamicDetail(dynamicIDStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return dynamicCard2msg(&dyc)
|
||||
}
|
||||
|
||||
// articleCard2msg 专栏转消息
|
||||
func articleCard2msg(card bz.Card, defaultID string) (msg []message.MessageSegment) {
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
for i := 0; i < len(card.OriginImageUrls); i++ {
|
||||
msg = append(msg, message.Image(card.OriginImageUrls[i]))
|
||||
}
|
||||
msg = append(msg, message.Text("\n", card.Title, "\n", "UP主: ", card.AuthorName, "\n",
|
||||
"阅读: ", bz.HumanNum(card.Stats.View), " 评论: ", bz.HumanNum(card.Stats.Reply), "\n",
|
||||
bz.CVURL, defaultID))
|
||||
return
|
||||
}
|
||||
|
||||
// liveCard2msg 直播卡片转消息
|
||||
func liveCard2msg(card bz.RoomCard) (msg []message.MessageSegment) {
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
msg = append(msg, message.Image(card.RoomInfo.Keyframe))
|
||||
msg = append(msg, message.Text("\n", card.RoomInfo.Title, "\n",
|
||||
"主播: ", card.AnchorInfo.BaseInfo.Uname, "\n",
|
||||
"房间号: ", card.RoomInfo.RoomID, "\n"))
|
||||
if card.RoomInfo.ShortID != 0 {
|
||||
msg = append(msg, message.Text("短号: ", card.RoomInfo.ShortID, "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("分区: ", card.RoomInfo.ParentAreaName))
|
||||
if card.RoomInfo.ParentAreaName != card.RoomInfo.AreaName {
|
||||
msg = append(msg, message.Text("-", card.RoomInfo.AreaName))
|
||||
}
|
||||
if card.RoomInfo.LiveStatus == 0 {
|
||||
msg = append(msg, message.Text("未开播 \n"))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播中 ", bz.HumanNum(card.RoomInfo.Online), "人气\n"))
|
||||
}
|
||||
if card.RoomInfo.ShortID != 0 {
|
||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.ShortID))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.RoomID))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// videoCard2msg 视频卡片转消息
|
||||
func videoCard2msg(card bz.Card) (msg []message.MessageSegment, err error) {
|
||||
var mCard bz.MemberCard
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
mCard, err = bz.GetMemberCard(card.Owner.Mid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
|
||||
if card.Rights.IsCooperation == 1 {
|
||||
for i := 0; i < len(card.Staff); i++ {
|
||||
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", bz.HumanNum(card.Staff[i].Follower), "\n"))
|
||||
}
|
||||
} else {
|
||||
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", bz.HumanNum(mCard.Fans), "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("播放: ", bz.HumanNum(card.Stat.View), " 弹幕: ", bz.HumanNum(card.Stat.Danmaku)))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text("\n点赞: ", bz.HumanNum(card.Stat.Like), " 投币: ", bz.HumanNum(card.Stat.Coin), "\n",
|
||||
"收藏: ", bz.HumanNum(card.Stat.Favorite), " 分享: ", bz.HumanNum(card.Stat.Share), "\n",
|
||||
bz.VURL, card.BvID))
|
||||
return
|
||||
}
|
||||
84
plugin/bilibili/card2msg_test.go
Normal file
84
plugin/bilibili/card2msg_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
)
|
||||
|
||||
func TestArticleInfo(t *testing.T) {
|
||||
card, err := bz.GetArticleInfo("17279244")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(articleCard2msg(card, "17279244"))
|
||||
|
||||
}
|
||||
|
||||
func TestDynamicDetail(t *testing.T) {
|
||||
t.Log("cType = 1")
|
||||
t.Log(dynamicDetail("642279068898689029"))
|
||||
|
||||
t.Log("cType = 2")
|
||||
t.Log(dynamicDetail("642470680290394121"))
|
||||
|
||||
t.Log("cType = 2048")
|
||||
t.Log(dynamicDetail("642277677329285174"))
|
||||
|
||||
t.Log("cType = 4")
|
||||
t.Log(dynamicDetail("642154347357011968"))
|
||||
|
||||
t.Log("cType = 8")
|
||||
t.Log(dynamicDetail("675892999274627104"))
|
||||
|
||||
t.Log("cType = 4308")
|
||||
t.Log(dynamicDetail("668598718656675844"))
|
||||
|
||||
t.Log("cType = 64")
|
||||
t.Log(dynamicDetail("675966082178088963"))
|
||||
|
||||
t.Log("cType = 256")
|
||||
t.Log(dynamicDetail("599253048535707632"))
|
||||
|
||||
t.Log("cType = 4,投票类型")
|
||||
t.Log(dynamicDetail("677231070435868704"))
|
||||
}
|
||||
|
||||
func TestMemberCard(t *testing.T) {
|
||||
card, err := bz.GetMemberCard(2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%+v\n", card)
|
||||
}
|
||||
|
||||
func TestVideoInfo(t *testing.T) {
|
||||
card, err := bz.GetVideoInfo("10007")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = bz.GetVideoInfo("BV1xx411c7mD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = bz.GetVideoInfo("bv1xx411c7mD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = bz.GetVideoInfo("BV1mF411j7iU")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
}
|
||||
|
||||
func TestLiveRoomInfo(t *testing.T) {
|
||||
card, err := bz.GetLiveRoomInfo("83171")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(liveCard2msg(card))
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
// Package bilibili 查询b站用户信息
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/FloatTech/zbputils/img/writer"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/fogleman/gg"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var engine = control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "bilibili\n" +
|
||||
"- >vup info [xxx]\n" +
|
||||
"- >user info [xxx]\n" +
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\n" +
|
||||
"- 更新vup",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
var re = regexp.MustCompile(`^\d+$`)
|
||||
|
||||
// 查成分的
|
||||
func init() {
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
_ = os.RemoveAll(cachePath)
|
||||
_ = os.MkdirAll(cachePath, 0755)
|
||||
var getdb = ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
var err error
|
||||
_, _ = engine.GetLazyData("bilibili.db", false)
|
||||
vdb, err = initialize(engine.DataFolder() + "bilibili.db")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnRegex(`^>user info\s?(.{1,25})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
uidRes, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := strconv.FormatInt(uidRes[0].Mid, 10)
|
||||
follwings, err := followings(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"search: ", uidRes[0].Mid, "\n",
|
||||
"name: ", uidRes[0].Uname, "\n",
|
||||
"sex: ", []string{"", "男", "女", "未知"}[uidRes[0].Gender], "\n",
|
||||
"sign: ", uidRes[0].Usign, "\n",
|
||||
"level: ", uidRes[0].Level, "\n",
|
||||
"follow: ", follwings,
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^>vup info\s?(.{1,25})$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
res, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := strconv.FormatInt(res[0].Mid, 10)
|
||||
// 获取详情
|
||||
fo, err := fansapi(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"search: ", fo.Mid, "\n",
|
||||
"名字: ", fo.Uname, "\n",
|
||||
"当前粉丝数: ", fo.Follower, "\n",
|
||||
"24h涨粉数: ", fo.Rise, "\n",
|
||||
"视频投稿数: ", fo.Video, "\n",
|
||||
"直播间id: ", fo.Roomid, "\n",
|
||||
"舰队: ", fo.GuardNum, "\n",
|
||||
"直播总排名: ", fo.AreaRank, "\n",
|
||||
"数据来源: ", "https://vtbs.moe/detail/", fo.Mid, "\n",
|
||||
"数据获取时间: ", time.Now().Format("2006-01-02 15:04:05"),
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^查成分\s?(.{1,25})$`, getdb, getPara).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
today := time.Now().Format("20060102")
|
||||
drawedFile := cachePath + id + today + "vupLike.png"
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
return
|
||||
}
|
||||
u, err := card(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
vups, err := vdb.filterVup(u.Attentions)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
vupLen := len(vups)
|
||||
medals, err := medalwall(id)
|
||||
sort.Sort(medalSlice(medals))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
}
|
||||
frontVups := make([]vup, 0)
|
||||
medalMap := make(map[int64]medal)
|
||||
for _, v := range medals {
|
||||
up := vup{
|
||||
Mid: v.Mid,
|
||||
Uname: v.Uname,
|
||||
}
|
||||
frontVups = append(frontVups, up)
|
||||
medalMap[v.Mid] = v
|
||||
}
|
||||
vups = append(vups, frontVups...)
|
||||
copy(vups[len(frontVups):], vups)
|
||||
copy(vups, frontVups)
|
||||
for i := len(frontVups); i < len(vups); i++ {
|
||||
if _, ok := medalMap[vups[i].Mid]; ok {
|
||||
vups = append(vups[:i], vups[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
facePath := cachePath + id + "vupFace" + path.Ext(u.Face)
|
||||
backX := 500
|
||||
backY := 500
|
||||
var back image.Image
|
||||
if path.Ext(u.Face) != ".webp" {
|
||||
err = initFacePic(facePath, u.Face)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
back, err = gg.LoadImage(facePath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
}
|
||||
if len(vups) > 50 {
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了,只展示前50个up"))
|
||||
vups = vups[:50]
|
||||
}
|
||||
canvas := gg.NewContext(1500, int(500*(1.1+float64(len(vups))/3)))
|
||||
fontSize := 50.0
|
||||
canvas.SetColor(color.White)
|
||||
canvas.Clear()
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
sl, _ := canvas.MeasureString("好")
|
||||
length, h := canvas.MeasureString(u.Mid)
|
||||
n, _ := canvas.MeasureString(u.Name)
|
||||
canvas.DrawString(u.Name, 550, 160-h)
|
||||
canvas.DrawRoundedRectangle(600+n-length*0.1, 160-h*2.5, length*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(u.Mid, 600+n, 160-h)
|
||||
canvas.DrawString(fmt.Sprintf("粉丝:%d", u.Fans), 550, 240-h)
|
||||
canvas.DrawString(fmt.Sprintf("关注:%d", len(u.Attentions)), 1000, 240-h)
|
||||
canvas.DrawString(fmt.Sprintf("管人痴成分:%.2f%%(%d/%d)", float64(vupLen)/float64(len(u.Attentions))*100, vupLen, len(u.Attentions)), 550, 320-h)
|
||||
regtime := time.Unix(u.Regtime, 0).Format("2006-01-02 15:04:05")
|
||||
canvas.DrawString("注册日期:"+regtime, 550, 400-h)
|
||||
canvas.DrawString("查询日期:"+time.Now().Format("2006-01-02"), 550, 480-h)
|
||||
for i, v := range vups {
|
||||
if i%2 == 1 {
|
||||
canvas.SetRGB255(245, 245, 245)
|
||||
canvas.DrawRectangle(0, float64(backY)*1.1+float64(i)*float64(backY)/3, float64(backX*3), float64(backY)/3)
|
||||
canvas.Fill()
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
nl, _ := canvas.MeasureString(v.Uname)
|
||||
canvas.DrawString(v.Uname, float64(backX)*0.1, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
ml, _ := canvas.MeasureString(strconv.FormatInt(v.Mid, 10))
|
||||
canvas.DrawRoundedRectangle(nl-0.1*ml+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-h*3.5, ml*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(strconv.FormatInt(v.Mid, 10), nl+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
if m, ok := medalMap[v.Mid]; ok {
|
||||
mnl, _ := canvas.MeasureString(m.MedalName)
|
||||
grad := gg.NewLinearGradient(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h, nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
r, g, b := int2rbg(m.MedalColorStart)
|
||||
grad.AddColorStop(0, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
|
||||
r, g, b = int2rbg(m.MedalColorEnd)
|
||||
grad.AddColorStop(1, color.RGBA{R: uint8(r), G: uint8(g), B: uint8(b), A: 255})
|
||||
canvas.SetFillStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.White)
|
||||
canvas.DrawString(m.MedalName, nl+ml+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
r, g, b = int2rbg(m.MedalColorBorder)
|
||||
canvas.SetRGB255(int(r), int(g), int(b))
|
||||
canvas.DrawString(strconv.FormatInt(m.Level, 10), nl+ml+mnl+sl+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
mll, _ := canvas.MeasureString(strconv.FormatInt(m.Level, 10))
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
}
|
||||
}
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(canvas.Image(), f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^设置b站cookie?\s+(.{1,100})$`, zero.SuperUserPermission, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
cookie := ctx.State["regex_matched"].([]string)[1]
|
||||
err := vdb.setBilibiliCookie(cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置b站cookie为" + cookie))
|
||||
})
|
||||
|
||||
engine.OnFullMatch("更新vup", zero.SuperUserPermission, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
err := updateVup()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("vup已更新"))
|
||||
})
|
||||
}
|
||||
|
||||
func initFacePic(filename, faceURL string) error {
|
||||
if file.IsNotExist(filename) {
|
||||
data, err := web.GetData(faceURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(filename, data, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func int2rbg(t int64) (int64, int64, int64) {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(t))
|
||||
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
func getPara(ctx *zero.Ctx) bool {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
if !re.MatchString(keyword) {
|
||||
searchRes, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return false
|
||||
}
|
||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
||||
return true
|
||||
}
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
ctx.SendChain(message.Text("输入为纯数字,请选择查询uid还是用户名,输入对应序号:\n0. 查询uid\n1. 查询用户名"))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10):
|
||||
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询uid"))
|
||||
ctx.State["uid"] = keyword
|
||||
return true
|
||||
case c := <-recv:
|
||||
msg := c.Event.Message.ExtractPlainText()
|
||||
num, err := strconv.Atoi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("请输入数字!"))
|
||||
continue
|
||||
}
|
||||
if num < 0 || num > 1 {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
if num == 0 {
|
||||
ctx.State["uid"] = keyword
|
||||
return true
|
||||
} else if num == 1 {
|
||||
searchRes, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return false
|
||||
}
|
||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
// Package bilibiliparse b站视频链接解析
|
||||
package bilibiliparse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Data struct {
|
||||
Bvid string `json:"bvid"`
|
||||
Aid int `json:"aid"`
|
||||
Copyright int `json:"copyright"`
|
||||
Pic string `json:"pic"`
|
||||
Title string `json:"title"`
|
||||
Pubdate int `json:"pubdate"`
|
||||
Ctime int `json:"ctime"`
|
||||
Rights struct {
|
||||
IsCooperation int `json:"is_cooperation"`
|
||||
} `json:"rights"`
|
||||
Owner struct {
|
||||
Mid int `json:"mid"`
|
||||
Name string `json:"name"`
|
||||
} `json:"owner"`
|
||||
Stat struct {
|
||||
Aid int `json:"aid"`
|
||||
View int `json:"view"`
|
||||
Danmaku int `json:"danmaku"`
|
||||
Reply int `json:"reply"`
|
||||
Favorite int `json:"favorite"`
|
||||
Coin int `json:"coin"`
|
||||
Share int `json:"share"`
|
||||
Like int `json:"like"`
|
||||
} `json:"stat"`
|
||||
Staff []struct {
|
||||
Title string `json:"title"`
|
||||
Name string `json:"name"`
|
||||
Follower int `json:"follower"`
|
||||
} `json:"staff"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type owner struct {
|
||||
Data struct {
|
||||
Card struct {
|
||||
Fans int `json:"fans"`
|
||||
} `json:"card"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
const (
|
||||
videoapi = "https://api.bilibili.com/x/web-interface/view?"
|
||||
cardapi = "http://api.bilibili.com/x/web-interface/card?"
|
||||
origin = "https://www.bilibili.com/video/"
|
||||
)
|
||||
|
||||
var (
|
||||
reg = regexp.MustCompile(`https://www.bilibili.com/video/([0-9a-zA-Z]+)`)
|
||||
limit = ctxext.NewLimiterManager(time.Second*10, 1)
|
||||
)
|
||||
|
||||
// 插件主体
|
||||
func init() {
|
||||
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "b站视频链接解析\n" +
|
||||
"- https://www.bilibili.com/video/BV1xx411c7BF | https://www.bilibili.com/video/av1605 | https://b23.tv/I8uzWCA | https://www.bilibili.com/video/bv1xx411c7BF",
|
||||
})
|
||||
en.OnRegex(`(av[0-9]+|BV[0-9a-zA-Z]{10}){1}`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if strings.Contains(ctx.MessageString(), "[CQ:forward") {
|
||||
return
|
||||
}
|
||||
id := ctx.State["regex_matched"].([]string)[1]
|
||||
m, err := parse(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(m)
|
||||
})
|
||||
en.OnRegex(`https://www.bilibili.com/video/([0-9a-zA-Z]+)`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["regex_matched"].([]string)[1]
|
||||
m, err := parse(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(m)
|
||||
})
|
||||
en.OnRegex(`(https://b23.tv/[0-9a-zA-Z]+)`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
url := ctx.State["regex_matched"].([]string)[1]
|
||||
realurl, err := getrealurl(url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
m, err := parse(cuturl(realurl))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(m)
|
||||
})
|
||||
}
|
||||
|
||||
// parse 解析视频数据
|
||||
func parse(id string) (m message.Message, err error) {
|
||||
var vid string
|
||||
switch id[:2] {
|
||||
case "av":
|
||||
vid = "aid=" + id[2:]
|
||||
case "BV":
|
||||
vid = "bvid=" + id
|
||||
}
|
||||
data, err := web.GetData(videoapi + vid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var r result
|
||||
err = json.Unmarshal(data, &r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
m = make(message.Message, 0, 16)
|
||||
m = append(m, message.Text("标题: ", r.Data.Title, "\n"))
|
||||
if r.Data.Rights.IsCooperation == 1 {
|
||||
for i := 0; i < len(r.Data.Staff); i++ {
|
||||
m = append(m, message.Text(r.Data.Staff[i].Title, ": ", r.Data.Staff[i].Name, ", 粉丝: ", row(r.Data.Staff[i].Follower), "\n"))
|
||||
}
|
||||
} else {
|
||||
o, err := getcard(r.Data.Owner.Mid)
|
||||
if err != nil {
|
||||
return m, err
|
||||
}
|
||||
m = append(m, message.Text("UP主: ", r.Data.Owner.Name, ", 粉丝: ", row(o.Data.Card.Fans), "\n"))
|
||||
}
|
||||
m = append(m, message.Text("播放: ", row(r.Data.Stat.View), ", 弹幕: ", row(r.Data.Stat.Danmaku), "\n"),
|
||||
message.Image(r.Data.Pic),
|
||||
message.Text("\n点赞: ", row(r.Data.Stat.Like), ", 投币: ", row(r.Data.Stat.Coin), "\n收藏: ", row(r.Data.Stat.Favorite), ", 分享: ", row(r.Data.Stat.Share), "\n", origin, id))
|
||||
return
|
||||
}
|
||||
|
||||
// getrealurl 获取跳转后的链接
|
||||
func getrealurl(url string) (realurl string, err error) {
|
||||
data, err := http.Head(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
realurl = data.Request.URL.String()
|
||||
return
|
||||
}
|
||||
|
||||
// cuturl 获取aid或者bvid
|
||||
func cuturl(url string) (id string) {
|
||||
if !reg.MatchString(url) {
|
||||
return
|
||||
}
|
||||
return reg.FindStringSubmatch(url)[1]
|
||||
}
|
||||
|
||||
// getcard 获取个人信息
|
||||
func getcard(mid int) (o owner, err error) {
|
||||
data, err := web.GetData(cardapi + "mid=" + strconv.Itoa(mid))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &o)
|
||||
return
|
||||
}
|
||||
|
||||
func row(res int) string {
|
||||
if res/10000 != 0 {
|
||||
return strconv.FormatFloat(float64(res)/10000, 'f', 2, 64) + "万"
|
||||
}
|
||||
return strconv.Itoa(res)
|
||||
}
|
||||
@@ -8,37 +8,38 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("bookreview", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "哀伤雪刃推书记录\n- 书评[xxx]\n- 随机书评",
|
||||
Brief: "哀伤雪刃推书书评",
|
||||
Help: "- 书评[xxx]\n- 随机书评",
|
||||
PublicDataFolder: "BookReview",
|
||||
})
|
||||
|
||||
getdb := ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "bookreview.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("bookreview.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("bookreview", &book{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("bookreview")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
log.Infof("[bookreview]读取%d条书评", n)
|
||||
@@ -51,11 +52,11 @@ func init() {
|
||||
b := getBookReviewByKeyword(ctx.State["regex_matched"].([]string)[1])
|
||||
data, err := text.RenderToBase64(b.BookReview, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:可能被风控了"))
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -64,11 +65,11 @@ func init() {
|
||||
br := getRandomBookReview()
|
||||
data, err := text.RenderToBase64(br.BookReview, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:可能被风控了"))
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
50
plugin/breakrepeat/breakrepeat.go
Normal file
50
plugin/breakrepeat/breakrepeat.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Package breakrepeat 打断复读
|
||||
package breakrepeat
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/RomiChan/syncx"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
)
|
||||
|
||||
const throttle = 3 // 不可超过 9
|
||||
|
||||
var sm syncx.Map[int64, string]
|
||||
|
||||
func init() {
|
||||
engine := control.Register("breakrepeat", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "打断复读",
|
||||
Help: "- 打断" + strconv.Itoa(throttle) + "次以上复读\n",
|
||||
})
|
||||
engine.On("message/group", zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||
return !zero.HasPicture(ctx)
|
||||
}).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
gid := ctx.Event.GroupID
|
||||
raw := ctx.Event.RawMessage
|
||||
r, ok := sm.Load(gid)
|
||||
if !ok || len(r) <= 3 || r[3:] != raw {
|
||||
sm.Store(gid, "0: "+raw)
|
||||
return
|
||||
}
|
||||
c := int(r[0] - '0')
|
||||
if c < throttle {
|
||||
sm.Store(gid, strconv.Itoa(c+1)+": "+raw)
|
||||
return
|
||||
}
|
||||
sm.Delete(gid)
|
||||
if len(r) > 5 {
|
||||
ru := []rune(r[3:])
|
||||
rand.Shuffle(len(ru), func(i, j int) {
|
||||
ru[i], ru[j] = ru[j], ru[i]
|
||||
})
|
||||
r = string(ru)
|
||||
}
|
||||
ctx.Send(r)
|
||||
})
|
||||
}
|
||||
@@ -32,24 +32,24 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("cangtoushi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "藏头诗\n" +
|
||||
"- 藏头诗[xxx]\n- 藏尾诗[xxx]",
|
||||
Brief: "藏头诗, 藏尾诗",
|
||||
Help: "- 藏头诗[xxx]\n- 藏尾诗[xxx]",
|
||||
})
|
||||
engine.OnRegex(`藏头诗\s?([一-龥]{3,10})$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
kw := ctx.State["regex_matched"].([]string)[1]
|
||||
err := login()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := search(kw, "7", "0")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text, err := dealHTML(helper.BytesToString(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(text))
|
||||
@@ -59,17 +59,17 @@ func init() {
|
||||
kw := ctx.State["regex_matched"].([]string)[1]
|
||||
err := login()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := search(kw, "7", "2")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text, err := dealHTML(helper.BytesToString(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(text))
|
||||
|
||||
@@ -17,6 +17,7 @@ var (
|
||||
poke = rate.NewManager[int64](time.Minute*5, 8) // 戳一戳
|
||||
engine = control.Register("chat", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "基础反应, 群空调",
|
||||
Help: "chat\n- [BOT名字]\n- [戳一戳BOT]\n- 空调开\n- 空调关\n- 群温度\n- 设置温度[正整数]",
|
||||
})
|
||||
)
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("choose", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "choose\n" +
|
||||
"- 选择可口可乐还是百事可乐\n" +
|
||||
"- 选择肯德基还是麦当劳还是必胜客",
|
||||
Brief: "选择困难症帮手",
|
||||
Help: "例: 选择可口可乐还是百事可乐\n" +
|
||||
"选择肯德基还是麦当劳还是必胜客",
|
||||
})
|
||||
engine.OnPrefix("选择").SetBlock(true).Handle(handle)
|
||||
}
|
||||
|
||||
@@ -8,36 +8,37 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("chouxianghua", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "抽象话\n- 抽象翻译xxx",
|
||||
Brief: "翻译为抽象话",
|
||||
Help: "- 抽象翻译xxx",
|
||||
PublicDataFolder: "ChouXiangHua",
|
||||
})
|
||||
|
||||
en.OnRegex("^抽象翻译((\\s|[\\r\\n]|[\\p{Han}\\p{P}A-Za-z0-9])+)$",
|
||||
ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = en.DataFolder() + "cxh.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = en.GetLazyData("cxh.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("pinyin", &pinyin{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("pinyin")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Printf("[chouxianghua]读取%d条拼音", n)
|
||||
|
||||
33
plugin/chrev/init.go
Normal file
33
plugin/chrev/init.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Package chrev 英文字符反转
|
||||
package chrev
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 初始化engine
|
||||
engine := control.Register("chrev", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "英文字符翻转",
|
||||
Help: "例: 翻转 I love you",
|
||||
})
|
||||
// 处理字符翻转指令
|
||||
engine.OnRegex(`^翻转\s*([A-Za-z\s]*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 获取需要翻转的字符串
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
// 将字符顺序翻转
|
||||
tmp := strings.Builder{}
|
||||
for i := len(str) - 1; i >= 0; i-- {
|
||||
tmp.WriteRune(charMap[str[i]])
|
||||
}
|
||||
// 发送翻转后的字符串
|
||||
ctx.SendChain(message.Text(tmp.String()))
|
||||
})
|
||||
}
|
||||
59
plugin/chrev/map.go
Normal file
59
plugin/chrev/map.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package chrev
|
||||
|
||||
var charMap [256]rune
|
||||
|
||||
func init() {
|
||||
charMap[' '] = ' '
|
||||
charMap['a'] = 'ɐ'
|
||||
charMap['b'] = 'q'
|
||||
charMap['c'] = 'ɔ'
|
||||
charMap['d'] = 'p'
|
||||
charMap['e'] = 'ǝ'
|
||||
charMap['f'] = 'ɟ'
|
||||
charMap['g'] = 'ƃ'
|
||||
charMap['h'] = 'ɥ'
|
||||
charMap['i'] = 'ᴉ'
|
||||
charMap['j'] = 'ɾ'
|
||||
charMap['k'] = 'ʞ'
|
||||
charMap['l'] = 'l'
|
||||
charMap['m'] = 'ɯ'
|
||||
charMap['n'] = 'u'
|
||||
charMap['o'] = 'o'
|
||||
charMap['p'] = 'd'
|
||||
charMap['q'] = 'b'
|
||||
charMap['r'] = 'ɹ'
|
||||
charMap['s'] = 's'
|
||||
charMap['t'] = 'ʇ'
|
||||
charMap['u'] = 'n'
|
||||
charMap['v'] = 'ʌ'
|
||||
charMap['w'] = 'ʍ'
|
||||
charMap['x'] = 'x'
|
||||
charMap['y'] = 'ʎ'
|
||||
charMap['z'] = 'z'
|
||||
charMap['A'] = '∀'
|
||||
charMap['B'] = 'ᗺ'
|
||||
charMap['C'] = 'Ɔ'
|
||||
charMap['D'] = 'ᗡ'
|
||||
charMap['E'] = 'Ǝ'
|
||||
charMap['F'] = 'Ⅎ'
|
||||
charMap['G'] = '⅁'
|
||||
charMap['H'] = 'H'
|
||||
charMap['I'] = 'I'
|
||||
charMap['J'] = 'ſ'
|
||||
charMap['K'] = 'ʞ'
|
||||
charMap['L'] = '˥'
|
||||
charMap['M'] = 'W'
|
||||
charMap['N'] = 'N'
|
||||
charMap['O'] = 'O'
|
||||
charMap['P'] = 'Ԁ'
|
||||
charMap['Q'] = 'Ò'
|
||||
charMap['R'] = 'ᴚ'
|
||||
charMap['S'] = 'S'
|
||||
charMap['T'] = '⏊'
|
||||
charMap['U'] = '∩'
|
||||
charMap['V'] = 'Λ'
|
||||
charMap['W'] = 'M'
|
||||
charMap['X'] = 'X'
|
||||
charMap['Y'] = '⅄'
|
||||
charMap['Z'] = 'Z'
|
||||
}
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -25,13 +25,14 @@ var (
|
||||
func init() {
|
||||
control.Register("coser", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "三次元小姐姐\n- coser",
|
||||
}).ApplySingle(ctxext.DefaultSingle).OnFullMatch("coser", zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Brief: "三次元coser",
|
||||
Help: "- coser",
|
||||
}).ApplySingle(ctxext.DefaultSingle).OnFullMatch("coser").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), coserURL, "GET", "", ua)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := gjson.Get(helper.BytesToString(data), "data.Title").String()
|
||||
@@ -46,11 +47,8 @@ func init() {
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Image(value.String())))
|
||||
return true
|
||||
})
|
||||
|
||||
if id := ctx.SendGroupForwardMessage(
|
||||
ctx.Event.GroupID,
|
||||
m).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:可能被风控或下载图片用时过长,请耐心等待"))
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,36 +9,37 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/math"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("cpstory", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "cp短打\n- 组cp[@xxx][@xxx]\n- 磕cp大老师 雪乃",
|
||||
Brief: "cp短打", // 这里也许有更好的名字
|
||||
Help: "- 组cp[@xxx][@xxx]\n- 磕cp大老师 雪乃",
|
||||
PublicDataFolder: "CpStory",
|
||||
})
|
||||
|
||||
getdb := ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "cp.db"
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("cp.db", true)
|
||||
err := db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("cp_story", &cpstory{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("cp_story")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Printf("[cpstory]读取%d条故事", n)
|
||||
|
||||
@@ -8,10 +8,11 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,30 +23,31 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("curse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "骂人(求骂,自卫)\n- 骂我\n- 大力骂我",
|
||||
Brief: "骂人反击",
|
||||
Help: "- 骂我\n- 大力骂我",
|
||||
PublicDataFolder: "Curse",
|
||||
})
|
||||
|
||||
getdb := ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "curse.db"
|
||||
_, err := engine.GetLazyData("curse.db", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("curse", &curse{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
c, err := db.Count("curse")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Infoln("[curse]加载", c, "条骂人语录")
|
||||
|
||||
@@ -4,12 +4,13 @@ package deepdanbooru
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/danbooru"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/img/writer"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
@@ -17,9 +18,9 @@ import (
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("danbooru", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "二次元图片标签识别\n" +
|
||||
"- 鉴赏图片[图片]",
|
||||
DisableOnDefault: false,
|
||||
Brief: "二次元图片标签识别",
|
||||
Help: "- 鉴赏图片[图片]",
|
||||
PrivateDataFolder: "danbooru",
|
||||
})
|
||||
|
||||
@@ -30,9 +31,9 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
for _, url := range ctx.State["image_url"].([]string) {
|
||||
t, err := danbooru.TagURL("", url)
|
||||
t, st, err := tagurl("", url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
digest := md5.Sum(helper.StringToBytes(url))
|
||||
@@ -40,7 +41,11 @@ func init() { // 插件主体
|
||||
if file.IsNotExist(f) {
|
||||
_ = writer.SavePNG2Path(f, t)
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + f))
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("file:///"+file.BOTPATH+"/"+f))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text("tags: ", strings.Join(st.tseq, ","))))
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
118
plugin/danbooru/tag.go
Normal file
118
plugin/danbooru/tag.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package deepdanbooru
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
imgutils "github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text" // jpg png gif
|
||||
_ "golang.org/x/image/webp" // webp
|
||||
)
|
||||
|
||||
const api = "https://nsfwtag.azurewebsites.net/api/tag?limit=0.5&url="
|
||||
|
||||
type sorttags struct {
|
||||
tags map[string]float64
|
||||
tseq []string
|
||||
}
|
||||
|
||||
func newsorttags(tags map[string]float64) (s *sorttags) {
|
||||
t := make([]string, 0, len(tags))
|
||||
for k := range tags {
|
||||
t = append(t, k)
|
||||
}
|
||||
return &sorttags{tags: tags, tseq: t}
|
||||
}
|
||||
|
||||
func (s *sorttags) Len() int {
|
||||
return len(s.tags)
|
||||
}
|
||||
|
||||
func (s *sorttags) Less(i, j int) bool {
|
||||
v1 := s.tseq[i]
|
||||
v2 := s.tseq[j]
|
||||
return s.tags[v1] >= s.tags[v2]
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (s *sorttags) Swap(i, j int) {
|
||||
s.tseq[j], s.tseq[i] = s.tseq[i], s.tseq[j]
|
||||
}
|
||||
|
||||
func tagurl(name, u string) (im image.Image, st *sorttags, err error) {
|
||||
ch := make(chan []byte, 1)
|
||||
go func() {
|
||||
var data []byte
|
||||
data, err = web.GetData(u)
|
||||
ch <- data
|
||||
}()
|
||||
|
||||
data, err := web.GetData(api + url.QueryEscape(u))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tags := make(map[string]float64)
|
||||
err = json.Unmarshal(data, &tags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
longestlen := 0
|
||||
for k := range tags {
|
||||
if len(k) > longestlen {
|
||||
longestlen = len(k)
|
||||
}
|
||||
}
|
||||
longestlen++
|
||||
|
||||
st = newsorttags(tags)
|
||||
sort.Sort(st)
|
||||
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = file.GetLazyData(text.ConsolasFontFile, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data = <-ch
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
img = imgutils.Limit(img, 1280, 720)
|
||||
|
||||
canvas := gg.NewContext(img.Bounds().Size().X, img.Bounds().Size().Y+int(float64(img.Bounds().Size().X)*0.2)+len(tags)*img.Bounds().Size().X/25)
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
canvas.Clear()
|
||||
canvas.DrawImage(img, 0, 0)
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, float64(img.Bounds().Size().X)*0.1); err != nil {
|
||||
return
|
||||
}
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
canvas.DrawString(name, float64(img.Bounds().Size().X)*0.02, float64(img.Bounds().Size().Y)+float64(img.Bounds().Size().X)*0.1)
|
||||
i := float64(img.Bounds().Size().Y) + float64(img.Bounds().Size().X)*0.2
|
||||
if err = canvas.LoadFontFace(text.ConsolasFontFile, float64(img.Bounds().Size().X)*0.04); err != nil {
|
||||
return
|
||||
}
|
||||
rate := float64(img.Bounds().Size().X) * 0.04
|
||||
for _, k := range st.tseq {
|
||||
canvas.DrawString(fmt.Sprintf("* %-*s -%.3f-", longestlen, k, tags[k]), float64(img.Bounds().Size().X)*0.04, i)
|
||||
i += rate
|
||||
}
|
||||
im = canvas.Image()
|
||||
return
|
||||
}
|
||||
@@ -5,28 +5,27 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/plugin/diana/data"
|
||||
)
|
||||
|
||||
var engine = control.Register("diana", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "嘉然\n" +
|
||||
"- 小作文\n" +
|
||||
Brief: "嘉然相关", // 也许使用常用功能当Brief更好
|
||||
Help: "- 小作文\n" +
|
||||
"- 发大病\n" +
|
||||
"- 教你一篇小作文[作文]\n" +
|
||||
"- [回复]查重",
|
||||
"- 教你一篇小作文[作文]",
|
||||
PublicDataFolder: "Diana",
|
||||
})
|
||||
|
||||
func init() {
|
||||
getdb := ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
err := data.LoadText(engine.DataFolder() + "text.db")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -49,7 +48,7 @@ func init() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := data.AddText(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("记住啦!"))
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
binutils "github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
binutils "github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
// Package diana 嘉然相关
|
||||
package diana
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
)
|
||||
|
||||
// 小作文查重: 回复要查的消息 查重
|
||||
func init() {
|
||||
engine.OnMessage(func(ctx *zero.Ctx) bool {
|
||||
msg := ctx.Event.Message
|
||||
if msg[0].Type != "reply" {
|
||||
return false
|
||||
}
|
||||
for _, elem := range msg {
|
||||
if elem.Type == "text" {
|
||||
text := elem.Data["text"]
|
||||
text = strings.ReplaceAll(text, " ", "")
|
||||
text = strings.ReplaceAll(text, "\r", "")
|
||||
text = strings.ReplaceAll(text, "\n", "")
|
||||
if text == "查重" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
msg := ctx.GetMessage(message.NewMessageIDFromString(ctx.Event.Message[0].Data["id"])).Elements[0].Data["text"]
|
||||
result, err := zhiwangapi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
if result.Get("code").Int() != 0 {
|
||||
ctx.SendChain(message.Text("api返回错误:", result.Get("code").Int()))
|
||||
return
|
||||
}
|
||||
if result.Get("data.related.#").Int() == 0 {
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("枝网没搜到,查重率为0%,鉴定为原创")))
|
||||
return
|
||||
}
|
||||
related := result.Get("data.related.0.reply").Map()
|
||||
rate := result.Get("data.related.0.rate").Float()
|
||||
relatedcontent := related["content"].String()
|
||||
if len(relatedcontent) > 102 {
|
||||
relatedcontent = relatedcontent[:102] + "....."
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(
|
||||
"枝网文本复制检测报告(简洁)", "\n",
|
||||
"查重时间: ", time.Now().Format("2006-01-02 15:04:05"), "\n",
|
||||
"总文字复制比: ", math.Floor(rate*100), "%", "\n",
|
||||
"相似小作文:", "\n", relatedcontent, "\n",
|
||||
"获赞数:", related["like_num"].String(), "\n",
|
||||
result.Get("data.related.0.reply_url").String(), "\n",
|
||||
"作者: ", related["m_name"].String(), "\n",
|
||||
"发表时间: ", time.Unix(int64(related["ctime"].Float()), 0).Format("2006-01-02 15:04:05"), "\n",
|
||||
"查重结果仅作参考,请注意辨别是否为原创", "\n",
|
||||
"数据来源: https://asoulcnki.asia/",
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
func zhiwangapi(text string) (*gjson.Result, error) {
|
||||
b, cl := binary.OpenWriterF(func(w *binary.Writer) {
|
||||
w.WriteString("{\n\"text\":\"")
|
||||
w.WriteString(text)
|
||||
w.WriteString("\"\n}")
|
||||
})
|
||||
|
||||
data, err := web.PostData("https://asoulcnki.asia/v1/api/check", "application/json", bytes.NewReader(b))
|
||||
cl()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := gjson.ParseBytes(data)
|
||||
return &result, nil
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
)
|
||||
|
||||
type bottle struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64
|
||||
QQ int64 `db:"qq"` // QQ 发送者 qq
|
||||
Grp int64 `db:"grp"` // Grp 限制抽出的群 / 人(负数)
|
||||
Name string `db:"name"` // Name 发送者 昵称
|
||||
Msg string `db:"msg"` // Msg 消息,纯文本
|
||||
}
|
||||
|
||||
var sea = &sql.Sqlite{}
|
||||
var seamu sync.RWMutex
|
||||
|
||||
func newBottle(qq, grp int64, name, msg string) *bottle {
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s", qq, grp, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &bottle{ID: id, QQ: qq, Grp: grp, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (b *bottle) throw(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Insert(channel, b)
|
||||
}
|
||||
|
||||
func (b *bottle) destroy(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Del(channel, "WHERE id="+strconv.FormatInt(b.ID, 10))
|
||||
}
|
||||
|
||||
// fetchBottle grp != 0
|
||||
func fetchBottle(db *sql.Sqlite, channel string, grp int64) (*bottle, error) {
|
||||
seamu.RLock()
|
||||
defer seamu.RUnlock()
|
||||
b := new(bottle)
|
||||
return b, db.Find(channel, b, "WHERE grp=0 or grp="+strconv.FormatInt(grp, 10)+" ORDER BY RANDOM() limit 1")
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Create(channel, &bottle{})
|
||||
}
|
||||
@@ -2,132 +2,108 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type sea struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64 hashCheck.
|
||||
QQ int64 `db:"qq"` // Get current user(Who sends this)
|
||||
Name string `db:"Name"` // his or her name at that time:P
|
||||
Msg string `db:"msg"` // What he or she sent to bot?
|
||||
Grp int64 `db:"grp"` // which group sends this msg?
|
||||
Time string `db:"time"` // we need to know the current time,master>
|
||||
}
|
||||
|
||||
var seaSide = &sql.Sqlite{}
|
||||
var seaLocker sync.RWMutex
|
||||
|
||||
// We need a container to inject what we need :(
|
||||
|
||||
func init() {
|
||||
en := control.Register("driftbottle", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "漂流瓶\n- (在群xxx)丢漂流瓶(到频道xxx) [消息]\n- (从频道xxx)捡漂流瓶\n- @BOT 创建频道 xxx\n- 跳入(频道)海中\n- 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global",
|
||||
Brief: "漂流瓶",
|
||||
Help: "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
||||
PrivateDataFolder: "driftbottle",
|
||||
})
|
||||
sea.DBPath = en.DataFolder() + "sea.db"
|
||||
err := sea.Open(time.Hour * 24)
|
||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
||||
err := seaSide.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = createChannel(sea, "global")
|
||||
en.OnRegex(`^(在群\d+)?丢漂流瓶(到频道\w+)?\s+(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
channel := "global"
|
||||
msg := msgs[3]
|
||||
var err error
|
||||
if msgs[1] != "" {
|
||||
grp, err = strconv.ParseInt(msgs[1][6:], 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("群号非法!"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if msgs[2] != "" {
|
||||
channel = msgs[2][9:]
|
||||
}
|
||||
if msg == "" {
|
||||
ctx.SendChain(message.Text("消息为空!"))
|
||||
return
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel, msg)
|
||||
err = newBottle(
|
||||
ctx.Event.UserID,
|
||||
grp,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
msg,
|
||||
).throw(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你将它扔进大海,希望有人捞到吧~")))
|
||||
})
|
||||
en.OnRegex(`^(从频道\w+)?捡漂流瓶$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
if grp == 0 {
|
||||
grp = -ctx.Event.UserID
|
||||
}
|
||||
if grp == 0 {
|
||||
ctx.SendChain(message.Text("找不到对象!"))
|
||||
return
|
||||
}
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1][9:]
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel)
|
||||
b, err := fetchBottle(sea, channel, grp)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = b.destroy(sea, channel)
|
||||
wg.Done()
|
||||
}()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(
|
||||
ctx.Event.MessageID,
|
||||
message.Text("你在海边捡到了一个来自 ", b.Name, " 的漂流瓶,打开瓶子,里面有一张纸条,写着:"),
|
||||
message.Text(b.Msg),
|
||||
),
|
||||
)
|
||||
wg.Wait()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
en.OnPrefix("创建频道", zero.SuperUserPermission, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
channel := strings.TrimRight(ctx.State["args"].(string), " ")
|
||||
if channel == "" {
|
||||
ctx.SendChain(message.Text("频道名为空!"))
|
||||
return
|
||||
}
|
||||
err := createChannel(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功~")))
|
||||
})
|
||||
en.OnRegex(`^跳入(\w+)?海中$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1]
|
||||
}
|
||||
seamu.RLock()
|
||||
c, err := sea.Count(channel)
|
||||
seamu.RUnlock()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你缓缓走入大海,感受着海浪轻柔地拍打着你的小腿,膝盖……\n波浪卷着你的腰腹,你感觉有些把握不住平衡了……\n……\n你沉入海中,", c, " 个物体与你一同沉浮。\n不知何处涌来一股暗流,你失去了意识。")))
|
||||
})
|
||||
|
||||
_ = createChannel(seaSide)
|
||||
en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
be, err := fetchBottle(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERR:", err))
|
||||
}
|
||||
idstr := strconv.Itoa(int(be.ID))
|
||||
qqstr := strconv.Itoa(int(be.QQ))
|
||||
grpstr := strconv.Itoa(int(be.Grp))
|
||||
botname := zero.BotConfig.NickName[0]
|
||||
msg := message.Message{message.CustomNode(botname, ctx.Event.SelfID, botname+"试着帮你捞出来了这个~\nID:"+idstr+"\n投递人: "+be.Name+"("+qqstr+")"+"\n群号: "+grpstr+"\n时间: "+be.Time+"\n内容: \n"+be.Msg)}
|
||||
ctx.Send(msg)
|
||||
})
|
||||
|
||||
en.OnRegex(`throw.*?(.*)`, zero.OnlyToMe, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
senderFormatTime := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
|
||||
rawSenderMessage := ctx.State["regex_matched"].([]string)[1]
|
||||
rawMessageCallBack := message.UnescapeCQCodeText(rawSenderMessage)
|
||||
keyWordsNum := utf8.RuneCountInString(rawMessageCallBack)
|
||||
if keyWordsNum < 10 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("需要投递的内容过少( "))
|
||||
return
|
||||
}
|
||||
// check current needs and prepare to throw drift_bottle.
|
||||
err = globalbottle(
|
||||
ctx.Event.UserID,
|
||||
ctx.Event.GroupID,
|
||||
senderFormatTime,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
rawMessageCallBack,
|
||||
).throw(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("已经帮你丢出去了哦~")))
|
||||
})
|
||||
}
|
||||
|
||||
func globalbottle(qq, grp int64, time, name, msg string) *sea { // Check as if the User is available and collect information to store.
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s_%s", grp, qq, time, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &sea{ID: id, Grp: grp, Time: time, QQ: qq, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (be *sea) throw(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Insert("global", be)
|
||||
}
|
||||
|
||||
func fetchBottle(db *sql.Sqlite) (*sea, error) {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
be := new(sea)
|
||||
return be, db.Pick("global", be)
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Create("global", &sea{})
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ const bed = "https://www.gstatic.com/android/keyboard/emojikitchen/%d/u%x/u%x_u%
|
||||
func init() {
|
||||
control.Register("emojimix", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "合成emoji\n" +
|
||||
"- [emoji][emoji]",
|
||||
Brief: "合成emoji",
|
||||
Help: "- [emoji][emoji]",
|
||||
}).OnMessage(match).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
r := ctx.State["emojimix"].([]rune)
|
||||
|
||||
@@ -7,16 +7,13 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
)
|
||||
|
||||
const (
|
||||
servicename = "epidemic"
|
||||
txurl = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf"
|
||||
)
|
||||
const txurl = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf"
|
||||
|
||||
// result 疫情查询结果
|
||||
type result struct {
|
||||
@@ -35,8 +32,8 @@ type epidemic struct {
|
||||
type area struct {
|
||||
Name string `json:"name"`
|
||||
Today struct {
|
||||
Confirm int `json:"confirm"`
|
||||
Wzzadd interface{} `json:"wzz_add"`
|
||||
Confirm int `json:"confirm"`
|
||||
Wzzadd any `json:"wzz_add"`
|
||||
} `json:"today"`
|
||||
Total struct {
|
||||
NowConfirm int `json:"nowConfirm"`
|
||||
@@ -50,10 +47,10 @@ type area struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
engine := control.Register(servicename, &ctrl.Options[*zero.Ctx]{
|
||||
engine := control.Register("epidemic", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "城市疫情查询\n" +
|
||||
"- xxx疫情\n",
|
||||
Brief: "城市疫情查询",
|
||||
Help: "- xxx疫情\n",
|
||||
})
|
||||
engine.OnSuffix("疫情").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -64,7 +61,7 @@ func init() {
|
||||
}
|
||||
data, time, err := queryEpidemic(city)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if data == nil {
|
||||
|
||||
45
plugin/event/data.go
Normal file
45
plugin/event/data.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package event
|
||||
|
||||
type storage int64
|
||||
|
||||
// 申请
|
||||
func (s *storage) setapply(on bool) {
|
||||
if on {
|
||||
*s |= 0b001
|
||||
} else {
|
||||
*s &= 0b110
|
||||
}
|
||||
}
|
||||
|
||||
// 邀请
|
||||
func (s *storage) setinvite(on bool) {
|
||||
if on {
|
||||
*s |= 0b010
|
||||
} else {
|
||||
*s &= 0b101
|
||||
}
|
||||
}
|
||||
|
||||
// 主人
|
||||
func (s *storage) setmaster(on bool) {
|
||||
if on {
|
||||
*s |= 0b100
|
||||
} else {
|
||||
*s &= 0b011
|
||||
}
|
||||
}
|
||||
|
||||
// 申请
|
||||
func (s *storage) isapplyon() bool {
|
||||
return *s&0b001 > 0
|
||||
}
|
||||
|
||||
// 邀请
|
||||
func (s *storage) isinviteon() bool {
|
||||
return *s&0b010 > 0
|
||||
}
|
||||
|
||||
// 主人
|
||||
func (s *storage) ismasteroff() bool {
|
||||
return *s&0b100 > 0
|
||||
}
|
||||
144
plugin/event/event.go
Normal file
144
plugin/event/event.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Package event 好友申请以及群聊邀请事件处理
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
base14 "github.com/fumiama/go-base16384"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("event", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "好友申请和群聊邀请事件处理",
|
||||
Help: "- [开启|关闭]自动同意[申请|邀请|主人]\n" +
|
||||
"- [同意|拒绝][申请|邀请][flag]\n" +
|
||||
"Tips: 信息默认发送给主人列表第一位, 默认同意所有主人的事件, flag跟随事件一起发送",
|
||||
})
|
||||
engine.On("request/group/invite").SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
now := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
|
||||
flag, err := strconv.ParseInt(ctx.Event.Flag, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var buf [8]byte
|
||||
binary.BigEndian.PutUint64(buf[:], uint64(flag))
|
||||
es := base14.EncodeToString(buf[1:])
|
||||
userid := ctx.Event.UserID
|
||||
username := ctx.CardOrNickName(userid)
|
||||
data := (storage)(c.GetData(-su))
|
||||
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, "")
|
||||
ctx.SendPrivateForwardMessage(su, message.Message{message.CustomNode(username, userid,
|
||||
"已自动同意在"+now+"收到来自"+
|
||||
"\n用户:["+username+"]("+strconv.FormatInt(userid, 10)+")的群聊邀请"+
|
||||
"\n群聊:["+groupname+"]("+strconv.FormatInt(groupid, 10)+")"+
|
||||
"\nflag:"+es)})
|
||||
return
|
||||
}
|
||||
ctx.SendPrivateForwardMessage(su,
|
||||
message.Message{message.CustomNode(username, userid,
|
||||
"在"+now+"收到来自"+
|
||||
"\n用户:["+username+"]("+strconv.FormatInt(userid, 10)+")的群聊邀请"+
|
||||
"\n群聊:["+groupname+"]("+strconv.FormatInt(groupid, 10)+")"+
|
||||
"\n请在下方复制flag并在前面加上:"+
|
||||
"\n同意/拒绝邀请,来决定同意还是拒绝"),
|
||||
message.CustomNode(username, userid, es)})
|
||||
}
|
||||
})
|
||||
engine.On("request/friend").SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
now := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
|
||||
flag, err := strconv.ParseInt(ctx.Event.Flag, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var buf [8]byte
|
||||
binary.BigEndian.PutUint64(buf[:], uint64(flag))
|
||||
es := base14.EncodeToString(buf[1:])
|
||||
comment := ctx.Event.Comment
|
||||
userid := ctx.Event.UserID
|
||||
username := ctx.CardOrNickName(userid)
|
||||
data := (storage)(c.GetData(-su))
|
||||
logrus.Info("[event]收到来自[", username, "](", userid, ")的好友申请")
|
||||
if data.isapplyon() || (!data.ismasteroff() && zero.SuperUserPermission(ctx)) {
|
||||
ctx.SetFriendAddRequest(ctx.Event.Flag, true, "")
|
||||
ctx.SendPrivateForwardMessage(su, message.Message{message.CustomNode(username, userid,
|
||||
"已自动同意在"+now+"收到来自"+
|
||||
"\n用户:["+username+"]("+strconv.FormatInt(userid, 10)+")"+
|
||||
"\n的好友请求:"+comment+
|
||||
"\nflag:"+es)})
|
||||
return
|
||||
}
|
||||
ctx.SendPrivateForwardMessage(su,
|
||||
message.Message{message.CustomNode(username, userid,
|
||||
"在"+now+"收到来自"+
|
||||
"\n用户:["+username+"]("+strconv.FormatInt(userid, 10)+")"+
|
||||
"\n的好友请求:"+comment+
|
||||
"\n请在下方复制flag并在前面加上:"+
|
||||
"\n同意/拒绝申请,来决定同意还是拒绝"),
|
||||
message.CustomNode(username, userid, es)})
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^(同意|拒绝)(申请|邀请)\s*([一-踀]{4})\s*(.*)$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
cmd := ctx.State["regex_matched"].([]string)[1]
|
||||
org := ctx.State["regex_matched"].([]string)[2]
|
||||
es := ctx.State["regex_matched"].([]string)[3]
|
||||
other := ctx.State["regex_matched"].([]string)[4]
|
||||
var buf [8]byte
|
||||
copy(buf[1:], base14.DecodeFromString(es))
|
||||
flag := strconv.FormatInt(int64(binary.BigEndian.Uint64(buf[:])), 10)
|
||||
ok := cmd == "同意"
|
||||
switch org {
|
||||
case "申请":
|
||||
ctx.SetFriendAddRequest(flag, ok, other)
|
||||
ctx.SendPrivateMessage(su, message.Text("已", cmd, org))
|
||||
case "邀请":
|
||||
ctx.SetGroupAddRequest(flag, "invite", ok, other)
|
||||
ctx.SendPrivateMessage(su, message.Text("已", cmd, org))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^(开启|关闭)自动同意(申请|邀请|主人)$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
c := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
from := ctx.State["regex_matched"].([]string)[2]
|
||||
data := (storage)(c.GetData(-su))
|
||||
switch from {
|
||||
case "申请":
|
||||
data.setapply(option == "开启")
|
||||
case "邀请":
|
||||
data.setinvite(option == "开启")
|
||||
case "主人":
|
||||
data.setmaster(option == "关闭")
|
||||
}
|
||||
err := c.SetData(-su, int64(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("已设置自动同意" + from + "为" + option))
|
||||
})
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
package font
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
func init() {
|
||||
control.Register("font", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "渲染任意文字到图片\n- (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体])渲染文字xxx",
|
||||
Brief: "渲染任意文字到图片",
|
||||
Help: "- (用[字体])渲染文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体]",
|
||||
}).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]
|
||||
@@ -36,7 +37,7 @@ func init() {
|
||||
}
|
||||
b, err := text.RenderToBase64(txt, fnt, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
|
||||
@@ -11,19 +11,20 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/fogleman/gg" // 注册了 jpg png gif
|
||||
"github.com/Coloured-glaze/gg" // 注册了 jpg png gif
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/img/pool"
|
||||
"github.com/FloatTech/zbputils/img/writer"
|
||||
"github.com/FloatTech/zbputils/math"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,8 +51,8 @@ func init() {
|
||||
// 插件主体
|
||||
en := control.Register("fortune", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "每日运势: \n" +
|
||||
"- 运势 | 抽签\n" +
|
||||
Brief: "每日运势",
|
||||
Help: "- 运势 | 抽签\n" +
|
||||
"- 设置底图[车万 | DC4 | 爱因斯坦 | 星空列车 | 樱云之恋 | 富婆妹 | 李清歌 | 公主连结 | 原神 | 明日方舟 | 碧蓝航线 | 碧蓝幻想 | 战双 | 阴阳师 | 赛马娘 | 东方归言录 | 奇异恩典 | 夏日口袋 | ASoul]",
|
||||
PublicDataFolder: "Fortune",
|
||||
})
|
||||
@@ -87,21 +88,21 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Text("没有这个底图哦~"))
|
||||
})
|
||||
en.OnFullMatchGroup([]string{"运势", "抽签"}, ctxext.DoOnceOnSuccess(
|
||||
en.OnFullMatchGroup([]string{"运势", "抽签"}, fcext.DoOnceOnSuccess(
|
||||
func(ctx *zero.Ctx) bool {
|
||||
data, err := file.GetLazyData(omikujson, false)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(data, &omikujis)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
_, err = file.GetLazyData(font, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -127,19 +128,19 @@ func init() {
|
||||
zipfile := images + kind + ".zip"
|
||||
_, err := file.GetLazyData(zipfile, false)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 随机获取背景
|
||||
background, index, err := randimage(zipfile, ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 随机获取签文
|
||||
randtextindex := ctxext.RandSenderPerDayN(ctx.Event.UserID, len(omikujis))
|
||||
randtextindex := fcext.RandSenderPerDayN(ctx.Event.UserID, len(omikujis))
|
||||
title, text := omikujis[randtextindex]["title"], omikujis[randtextindex]["content"]
|
||||
digest := md5.Sum(helper.StringToBytes(zipfile + strconv.Itoa(index) + title + text))
|
||||
cachefile := cache + hex.EncodeToString(digest[:])
|
||||
@@ -154,7 +155,7 @@ func init() {
|
||||
return err
|
||||
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -171,7 +172,7 @@ func randimage(path string, ctx *zero.Ctx) (im image.Image, index int, err error
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
file := reader.File[ctxext.RandSenderPerDayN(ctx.Event.UserID, len(reader.File))]
|
||||
file := reader.File[fcext.RandSenderPerDayN(ctx.Event.UserID, len(reader.File))]
|
||||
f, err := file.Open()
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
@@ -25,31 +26,31 @@ var db = &sql.Sqlite{}
|
||||
func init() {
|
||||
en := control.Register("funny", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "讲个笑话\n" +
|
||||
"- 讲个笑话[@xxx|qq号|人名] | 夸夸[@xxx|qq号|人名] ",
|
||||
Brief: "讲个笑话",
|
||||
Help: "- 讲个笑话[@xxx|qq号|人名] | 夸夸[@xxx|qq号|人名] ",
|
||||
PublicDataFolder: "Funny",
|
||||
})
|
||||
|
||||
en.OnPrefixGroup([]string{"讲个笑话", "夸夸"}, ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
en.OnPrefixGroup([]string{"讲个笑话", "夸夸"}, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = en.DataFolder() + "jokes.db"
|
||||
_, err := en.GetLazyData("jokes.db", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("jokes", &joke{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
c, err := db.Count("jokes")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Infoln("[funny]加载", c, "个笑话")
|
||||
@@ -60,7 +61,7 @@ func init() {
|
||||
var j joke
|
||||
err := db.Pick("jokes", &j)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(strings.ReplaceAll(j.Text, "%name", name)))
|
||||
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/writer"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/golang/freetype"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@@ -36,7 +37,8 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("genshin", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "原神抽卡\n- 原神十连\n- 切换原神卡池",
|
||||
Brief: "原神模拟抽卡",
|
||||
Help: "- 原神十连\n- 切换原神卡池",
|
||||
PublicDataFolder: "Genshin",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
|
||||
@@ -62,21 +64,21 @@ func init() {
|
||||
err := c.SetData(gid, int64(store))
|
||||
if err != nil {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
})
|
||||
|
||||
engine.OnFullMatch("原神十连", ctxext.DoOnceOnSuccess(
|
||||
engine.OnFullMatch("原神十连", fcext.DoOnceOnSuccess(
|
||||
func(ctx *zero.Ctx) bool {
|
||||
zipfile := engine.DataFolder() + "Genshin.zip"
|
||||
_, err := engine.GetLazyData("Genshin.zip", false)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = parsezip(zipfile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -95,7 +97,7 @@ func init() {
|
||||
store := (storage)(c.GetData(gid))
|
||||
img, str, mode, err := randnums(10, store)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
b, cl := writer.ToBytes(img)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ZeroBot-Plugin-Gif
|
||||
[ZeroBot QQ机器人](https://github.com/wdvxdr1123/ZeroBot)插件,可以制作各种沙雕gif图
|
||||
> 素材包地址: https://gitcode.net/u011570312/imagematerials
|
||||
> 素材包地址: https://gitcode.net/anto_july/imagematerials
|
||||
|
||||
## 触发方式
|
||||
1. [指令词]+[qq号] 如:爬123456
|
||||
@@ -29,3 +29,75 @@
|
||||
- [x] 浮雕
|
||||
- [x] 打码
|
||||
- [x] 负片
|
||||
- [x] 旋转45
|
||||
- [x] 变形100 100
|
||||
- [x] 亲
|
||||
- [x] 娶|结婚申请|结婚登记
|
||||
- [x] 像只
|
||||
- [x] 阿尼亚喜欢
|
||||
- [x] 我永远喜欢|永远喜欢
|
||||
- [x] 像样的亲亲
|
||||
- [x] 国旗
|
||||
- [x] 不要靠近
|
||||
- [x] 万能表情|空白表情
|
||||
- [x] 采访
|
||||
- [x] 需要|你可能需要
|
||||
- [x] 这像画吗
|
||||
- [x] 小画家
|
||||
- [x] 完美
|
||||
- [x] 玩游戏 (应该使用透视变换)
|
||||
- [x] 出警
|
||||
- [x] 警察
|
||||
- [x] 舔|舔屏|prpr (应该使用透视变换)
|
||||
- [x] 安全感
|
||||
- [x] 精神支柱
|
||||
- [x] 想什么
|
||||
- [x] 墙纸
|
||||
- [x] 为什么at我
|
||||
- [x] 交个朋友
|
||||
- [x] 打工人|继续干活
|
||||
- [x] 兑换券
|
||||
- [ ] 捂脸 (使用了透视变换, 需要研究矩阵变换)
|
||||
- [x] 注意力涣散
|
||||
- [x] 垃圾桶|垃圾
|
||||
- [x] 锤
|
||||
- [x] 啾啾
|
||||
- [x] 2敲
|
||||
- [x] 听音乐
|
||||
- [ ] 群青 (需要mask)
|
||||
- [ ] 加载中 (需要mask)
|
||||
- [x] 永远爱你 (未加闪光)
|
||||
- [ ] 关注 (处理文字麻烦)
|
||||
- [x] 2拍
|
||||
- [x] 顶
|
||||
- [x] 捣
|
||||
- [x] 打拳 (未加闪光)
|
||||
- [ ] 复读 (处理文字麻烦)
|
||||
- [x] 滚
|
||||
- [x] 吸
|
||||
- [x] 扔
|
||||
- [x] 捶
|
||||
- [x] 紧贴
|
||||
- [ ] 膜拜 (使用了透视变换, 需要研究矩阵变换)
|
||||
- [ ] 小天使 (摆)
|
||||
- [ ] 一直 (摆)
|
||||
- [x] 转
|
||||
- [ ] 问问 (摆)
|
||||
- [ ] 典中典 (摆)
|
||||
- [ ] 震惊 (摆)
|
||||
- [ ] 哈哈镜 (摆)
|
||||
- [ ] 对称 (猎奇, 不整)
|
||||
- [x] 炖
|
||||
- [x] 2蹭
|
||||
- [x] 诶嘿
|
||||
- [x] 膜拜
|
||||
- [x] 吞
|
||||
- [x] 揍
|
||||
- [x] 给我变
|
||||
- [x] 玩一下
|
||||
- [x] 不要看
|
||||
- [x] 小天使
|
||||
- [x] 你的
|
||||
- [x] 我老婆
|
||||
- [x] 远离
|
||||
- [x] 抬棺
|
||||
|
||||
@@ -5,7 +5,8 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -18,10 +19,22 @@ type context struct {
|
||||
func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
|
||||
defer wg.Done()
|
||||
target := datapath + `materials/` + name
|
||||
var err error
|
||||
if file.IsNotExist(target) {
|
||||
err = file.DownloadTo(`https://gitcode.net/u011570312/imagematerials/-/raw/main/`+name, target, true)
|
||||
data, err := web.RequestDataWith(web.NewTLS12Client(), `https://gitcode.net/m0_60838134/imagematerials/-/raw/main/`+name, "GET", "gitcode.net", web.RandUA())
|
||||
if err != nil {
|
||||
_ = os.Remove(target)
|
||||
exit(err)
|
||||
return
|
||||
}
|
||||
f, err := os.Create(target)
|
||||
if err != nil {
|
||||
exit(err)
|
||||
return
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
_ = os.Remove(target)
|
||||
exit(err)
|
||||
return
|
||||
}
|
||||
@@ -35,8 +48,19 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
|
||||
func dlblock(name string) (string, error) {
|
||||
target := datapath + `materials/` + name
|
||||
if file.IsNotExist(target) {
|
||||
err := file.DownloadTo(`https://gitcode.net/u011570312/imagematerials/-/raw/main/`+name, target, true)
|
||||
data, err := web.RequestDataWith(web.NewTLS12Client(), `https://gitcode.net/m0_60838134/imagematerials/-/raw/main/`+name, "GET", "gitcode.net", web.RandUA())
|
||||
if err != nil {
|
||||
_ = os.Remove(target)
|
||||
return "", err
|
||||
}
|
||||
f, err := os.Create(target)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = f.Write(data)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
_ = os.Remove(target)
|
||||
return "", err
|
||||
}
|
||||
logrus.Debugln("[gif] dl", name, "to", target, "succeeded")
|
||||
@@ -73,8 +97,8 @@ func newContext(user int64) *context {
|
||||
return c
|
||||
}
|
||||
|
||||
func loadFirstFrames(paths []string, size int) (imgs []*img.ImgFactory, err error) {
|
||||
imgs = make([]*img.ImgFactory, size)
|
||||
func loadFirstFrames(paths []string, size int) (imgs []*img.Factory, err error) {
|
||||
imgs = make([]*img.Factory, size)
|
||||
for i := range imgs {
|
||||
imgs[i], err = img.LoadFirstFrame(paths[i], 0, 0)
|
||||
if err != nil {
|
||||
|
||||
1267
plugin/gif/gif.go
1267
plugin/gif/gif.go
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
)
|
||||
|
||||
|
||||
1495
plugin/gif/png.go
1495
plugin/gif/png.go
File diff suppressed because it is too large
Load Diff
@@ -2,52 +2,166 @@
|
||||
package gif
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
cmds = []string{"搓", "冲", "摸", "拍", "丢", "吃", "敲", "啃", "蹭", "爬", "撕",
|
||||
"灰度", "上翻", "下翻", "左翻", "右翻", "反色", "浮雕", "打码", "负片"}
|
||||
cmd = make([]string, 0)
|
||||
datapath string
|
||||
cmdMap = map[string]func(cc *context, args ...string) (string, error){
|
||||
"搓": cuo,
|
||||
"冲": xqe,
|
||||
"摸": mo,
|
||||
"拍": pai,
|
||||
"丢": diu,
|
||||
"吃": chi,
|
||||
"敲": qiao,
|
||||
"啃": ken,
|
||||
"蹭": ceng,
|
||||
"爬": pa,
|
||||
"撕": si,
|
||||
"灰度": grayscale,
|
||||
"上翻": flipV,
|
||||
"下翻": flipV,
|
||||
"左翻": flipH,
|
||||
"右翻": flipH,
|
||||
"反色": invert,
|
||||
"浮雕": convolve3x3,
|
||||
"打码": blur,
|
||||
"负片": invertAndGrayscale,
|
||||
"旋转": rotate,
|
||||
"变形": deformation,
|
||||
"亲": kiss,
|
||||
"结婚申请": marriage,
|
||||
"结婚登记": marriage,
|
||||
"阿尼亚喜欢": anyasuki,
|
||||
"像只": alike,
|
||||
"我永远喜欢": alwaysLike,
|
||||
"永远喜欢": alwaysLike,
|
||||
"像样的亲亲": decentKiss,
|
||||
"国旗": chinaFlag,
|
||||
"不要靠近": dontTouch,
|
||||
"万能表情": universal,
|
||||
"空白表情": universal,
|
||||
"采访": interview,
|
||||
"需要": need,
|
||||
"你可能需要": need,
|
||||
"这像画吗": paint,
|
||||
"小画家": painter,
|
||||
"完美": perfect,
|
||||
"玩游戏": playGame,
|
||||
"出警": police,
|
||||
"警察": police1,
|
||||
"舔": prpr,
|
||||
"舔屏": prpr,
|
||||
"prpr": prpr,
|
||||
"安全感": safeSense,
|
||||
"精神支柱": support,
|
||||
"想什么": thinkwhat,
|
||||
"墙纸": wallpaper,
|
||||
"为什么at我": whyatme,
|
||||
"交个朋友": makeFriend,
|
||||
"打工人": backToWork,
|
||||
"继续干活": backToWork,
|
||||
"兑换券": coupon,
|
||||
"注意力涣散": distracted,
|
||||
"垃圾桶": garbage,
|
||||
"垃圾": garbage,
|
||||
"捶": thump,
|
||||
"啾啾": jiujiu,
|
||||
"2敲": knock,
|
||||
"听音乐": listenMusic,
|
||||
"永远爱你": loveYou,
|
||||
"2拍": pat,
|
||||
"顶": jackUp,
|
||||
"捣": pound,
|
||||
"打拳": punch,
|
||||
"滚": roll,
|
||||
"吸": suck,
|
||||
"嗦": suck,
|
||||
"扔": throw,
|
||||
"锤": hammer,
|
||||
"紧贴": tightly,
|
||||
"紧紧贴着": tightly,
|
||||
"转": turn,
|
||||
"蒙蔽": mengbi,
|
||||
"踩": cai,
|
||||
"好玩": haowan,
|
||||
"2转": whirl,
|
||||
"2滚": push,
|
||||
"踢球": tiqiu,
|
||||
"2舔": lick,
|
||||
"可莉吃": klee,
|
||||
"胡桃啃": hutaoken,
|
||||
"怀": huai,
|
||||
"砰": peng,
|
||||
"你犯法了": fanfa,
|
||||
"炖": dun,
|
||||
"2蹭": ceng2,
|
||||
"诶嘿": eihei,
|
||||
"膜拜": worship,
|
||||
"吞": ci,
|
||||
"揍": zou,
|
||||
"给我变": bian,
|
||||
"玩一下": van,
|
||||
"不要看": neko,
|
||||
"小天使": xiaotianshi,
|
||||
"你的": youer,
|
||||
"我老婆": nowife,
|
||||
"远离": yuanli,
|
||||
"抬棺": taiguan,
|
||||
"一直": alwaysDoGif,
|
||||
}
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
for k := range cmdMap {
|
||||
cmd = append(cmd, k)
|
||||
}
|
||||
en := control.Register("gif", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "制图\n- " + strings.Join(cmds, "\n- "),
|
||||
DisableOnDefault: false,
|
||||
Brief: "制图",
|
||||
Help: "下为制图命令: " +
|
||||
"- 搓|-冲|-摸|-拍|-丢|-吃|-敲|-啃|-蹭|-爬|-撕|-灰度|-上翻|-下翻\n" +
|
||||
"- 左翻|-右翻|-反色|-浮雕|- 打码|- 负片|- 旋转|- 变形|- 亲\n" +
|
||||
"- 结婚申请|结婚登记|- 阿尼亚喜欢XXX|- 像只|- 我永远喜欢XXX\n" +
|
||||
"- 像样的亲亲|- 国旗|- 不要靠近|- 万能表情|-空白表情|- 采访\n" +
|
||||
"- 需要|-你可能需要|- 这像画吗|- 小画家|- 完美|- 玩游戏|- 出警\n" +
|
||||
"- 警察|- 舔|舔屏|prpr|- 安全感|- 精神支柱|- 想什么|- 墙纸\n" +
|
||||
"- 为什么at我|- 交个朋友|- 打工人|-继续干活|- 兑换券|- 炖\n" +
|
||||
"- 垃圾桶|- 垃圾|- 捶|- 啾啾|- 2敲|- 听音乐|- 永远爱你|- 2拍\n" +
|
||||
"- 顶|- 捣|- 打拳|- 滚|- 吸|- 嗦|- 扔|- 锤|- 紧贴|紧紧贴着|- 转\n" +
|
||||
"- 抬棺|- 远离|- 我老婆|- 小天使XXX|- 你的XXX|- 不要看\n" +
|
||||
"- 玩一下XXX|- 给我变|- 揍|- 吞|- 膜拜|- 诶嘿|- 2蹭|- 你犯法了\n" +
|
||||
"- 砰|- 注意力涣散|- 蒙蔽|- 踩|- 好玩|- 2转|- 踢球|- 2舔|\n" +
|
||||
"- 可莉吃|- 胡桃啃|- 怀|- 一直(支持动图)\n" +
|
||||
"例: 制图命令XXX[@用户|QQ号|图片]" +
|
||||
"Tips: XXX可以为限制长度的任何文字\n" +
|
||||
"对Bot使用为 @Bot制图命令[XXX]@Bot",
|
||||
PrivateDataFolder: "gif",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
datapath = file.BOTPATH + "/" + en.DataFolder()
|
||||
en.OnRegex(`^(` + strings.Join(cmds, "|") + `)\D*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).
|
||||
en.OnRegex(`^(` + strings.Join(cmd, "|") + `)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).
|
||||
SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
c := newContext(ctx.Event.UserID)
|
||||
list := ctx.State["regex_matched"].([]string)
|
||||
err := c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var picurl string
|
||||
if len([]rune(list[1])) == 1 {
|
||||
r := reflect.ValueOf(c).MethodByName("A" + list[1]).Call(nil)
|
||||
picurl = r[0].String()
|
||||
if !r[1].IsNil() {
|
||||
err = r[1].Interface().(error)
|
||||
}
|
||||
} else {
|
||||
picurl, err = c.other(list[1]) // "灰度", "上翻", "下翻", "左翻", "右翻", "反色", "倒放", "浮雕", "打码", "负片"
|
||||
}
|
||||
argslist := strings.Split(strings.TrimSuffix(strings.TrimPrefix(list[0], list[1]), list[2]), " ")
|
||||
picurl, err := cmdMap[list[1]](c, argslist...)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image(picurl))
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
func init() { // 插件主体
|
||||
control.Register("github", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "GitHub仓库搜索\n" +
|
||||
"- >github [xxx]\n" +
|
||||
Brief: "GitHub仓库搜索",
|
||||
Help: "- >github [xxx]\n" +
|
||||
"- >github -p [xxx]",
|
||||
}).OnRegex(`^>github\s(-.{1,10}? )?(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -35,12 +35,12 @@ func init() { // 插件主体
|
||||
}.Encode()
|
||||
body, err := netGet(api.String(), header)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
// 解析请求
|
||||
info := gjson.ParseBytes(body)
|
||||
if info.Get("total_count").Int() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:没有找到这样的仓库"))
|
||||
ctx.SendChain(message.Text("ERROR: 没有找到这样的仓库"))
|
||||
return
|
||||
}
|
||||
repo := info.Get("items.0")
|
||||
@@ -61,9 +61,9 @@ func init() { // 插件主体
|
||||
"Star/Fork/Issue: ",
|
||||
repo.Get("watchers").Int(), "/", repo.Get("forks").Int(), "/", repo.Get("open_issues").Int(), "\n",
|
||||
"Language: ",
|
||||
notnull(repo.Get("language").Str, "None"), "\n",
|
||||
notnull(repo.Get("language").Str), "\n",
|
||||
"License: ",
|
||||
notnull(strings.ToUpper(repo.Get("license.key").Str), "None"), "\n",
|
||||
notnull(strings.ToUpper(repo.Get("license.key").Str)), "\n",
|
||||
"Last pushed: ",
|
||||
repo.Get("pushed_at").Str, "\n",
|
||||
"Jump: ",
|
||||
@@ -79,9 +79,9 @@ func init() { // 插件主体
|
||||
"Star/Fork/Issue: ",
|
||||
repo.Get("watchers").Int(), "/", repo.Get("forks").Int(), "/", repo.Get("open_issues").Int(), "\n",
|
||||
"Language: ",
|
||||
notnull(repo.Get("language").Str, "None"), "\n",
|
||||
notnull(repo.Get("language").Str), "\n",
|
||||
"License: ",
|
||||
notnull(strings.ToUpper(repo.Get("license.key").Str), "None"), "\n",
|
||||
notnull(strings.ToUpper(repo.Get("license.key").Str)), "\n",
|
||||
"Last pushed: ",
|
||||
repo.Get("pushed_at").Str, "\n",
|
||||
"Jump: ",
|
||||
@@ -97,9 +97,9 @@ func init() { // 插件主体
|
||||
|
||||
// notnull 如果传入文本为空,则返回默认值
|
||||
|
||||
func notnull(text, defstr string) string {
|
||||
func notnull(text string) string {
|
||||
if text == "" {
|
||||
return defstr
|
||||
return "None"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
862
plugin/guessmusic/main.go
Normal file
862
plugin/guessmusic/main.go
Normal file
@@ -0,0 +1,862 @@
|
||||
// Package guessmusic 基于zbp的猜歌插件
|
||||
package guessmusic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// 网易云插件
|
||||
wyy "github.com/FloatTech/AnimeAPI/neteasemusic"
|
||||
|
||||
// 图片输出
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
var (
|
||||
filelist []listinfo
|
||||
musictypelist = "mp3;MP3;wav;WAV;amr;AMR;3gp;3GP;3gpp;3GPP;acc;ACC"
|
||||
cuttime = [...]string{"00:00:05", "00:00:30", "00:01:00"} // 音乐切割时间点,可自行调节时间(时:分:秒)
|
||||
cfg config
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("guessmusic", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "猜歌插件",
|
||||
Help: "由于不可抗因素无法获取网易云歌单内容, 插件改为本地猜歌了, 但保留了下歌功能\n" +
|
||||
"------bot主人指令------\n" +
|
||||
"- 设置猜歌歌库路径 [绝对路径]\n" +
|
||||
"- (指令仅歌词有效) 猜歌[开启/关闭][歌单/歌词]自动下载\n" +
|
||||
"- (指令已失效) 添加歌单 [网易云歌单链接/ID] [歌单名称]\n" +
|
||||
"- 下载歌曲 [歌曲名称/网易云歌曲ID] [歌单名称]\n" +
|
||||
"- 删除歌单 [网易云歌单ID/歌单名称]\n" +
|
||||
"注: 删除网易云歌单ID仅只是解除绑定\n删除歌单名称是将本地数据全部删除, 慎用\n" +
|
||||
"------管 理 员 指 令------\n" +
|
||||
"- 设置猜歌默认歌单 [歌单名称]\n" +
|
||||
"------公 用 指 令------\n" +
|
||||
"- 歌单列表\n" +
|
||||
"- [个人/团队]猜歌\n" +
|
||||
"注: 默认歌库为歌单列表第一个, 如果设置了默认歌单变为指定的歌单\n" +
|
||||
"可在\"[个人/团队]猜歌指令\"后面添加[-歌单名称]进行指定歌单猜歌\n" +
|
||||
"猜歌内容必须以[-]开头才会识别\n" +
|
||||
"本地歌曲命名规则为:\n歌名 - 歌手 - 其他(歌曲出处之类)\n" +
|
||||
"重要事项: 本插件依赖ffmpeg",
|
||||
PrivateDataFolder: "guessmusic",
|
||||
}).ApplySingle(single.New(
|
||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("已经有正在进行的游戏..."),
|
||||
),
|
||||
)
|
||||
}),
|
||||
))
|
||||
serviceErr := "[guessmusic]"
|
||||
// 用于存放歌曲三个片段的文件夹
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
err := os.MkdirAll(cachePath, 0777)
|
||||
if err != nil {
|
||||
panic(serviceErr + "ERROR:" + err.Error())
|
||||
}
|
||||
// 获取用户的配置
|
||||
cfgFile := engine.DataFolder() + "config.json"
|
||||
if file.IsExist(cfgFile) {
|
||||
reader, err := os.Open(cfgFile)
|
||||
if err == nil {
|
||||
err = json.NewDecoder(reader).Decode(&cfg)
|
||||
}
|
||||
if err != nil {
|
||||
panic(serviceErr + "ERROR:" + err.Error())
|
||||
}
|
||||
err = reader.Close()
|
||||
if err != nil {
|
||||
panic(serviceErr + "ERROR:" + err.Error())
|
||||
}
|
||||
} else {
|
||||
cfg = config{ // 配置默认 config
|
||||
MusicPath: file.BOTPATH + "/data/guessmusic/music/", // 绝对路径,歌库根目录,通过指令进行更改
|
||||
API: true,
|
||||
Local: true,
|
||||
Playlist: []listRaw{
|
||||
{
|
||||
Name: "FM",
|
||||
ID: 3136952023,
|
||||
}},
|
||||
}
|
||||
err = saveConfig(cfgFile)
|
||||
if err != nil {
|
||||
panic(serviceErr + "ERROR:" + err.Error())
|
||||
}
|
||||
}
|
||||
filelist, err = getlist(cfg.MusicPath)
|
||||
if err != nil {
|
||||
logrus.Errorln(serviceErr + "ERROR:" + err.Error())
|
||||
}
|
||||
// 用户配置
|
||||
engine.OnRegex(`^设置猜歌(歌库路径|默认歌单)\s*(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
value := ctx.State["regex_matched"].([]string)[2]
|
||||
var err error
|
||||
switch option {
|
||||
case "歌库路径":
|
||||
if !zero.SuperUserPermission(ctx) {
|
||||
ctx.SendChain(message.Text("只有bot主人可以设置!"))
|
||||
return
|
||||
}
|
||||
musicPath := strings.ReplaceAll(value, "\\", "/")
|
||||
if !strings.HasSuffix(musicPath, "/") {
|
||||
musicPath += "/"
|
||||
}
|
||||
err = os.MkdirAll(musicPath, 0777)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "生成文件夹ERROR:\n", err))
|
||||
return
|
||||
}
|
||||
cfg.MusicPath = musicPath
|
||||
case "默认歌单":
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 || !zero.AdminPermission(ctx) {
|
||||
ctx.SendChain(message.Text("无权设置!"))
|
||||
return
|
||||
}
|
||||
index := ""
|
||||
for _, listinfo := range filelist {
|
||||
if listinfo.Name == value {
|
||||
index = value
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == "" {
|
||||
ctx.SendChain(message.Text("歌单名称错误,可以发送“歌单列表”获取歌单名称"))
|
||||
return
|
||||
}
|
||||
cfg.Defaultlist = append(cfg.Defaultlist, dlist{
|
||||
GroupID: gid,
|
||||
Name: value,
|
||||
})
|
||||
}
|
||||
err = saveConfig(cfgFile)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:\n", err))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^猜歌(开启|关闭)(歌单|歌词)自动下载`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
swtich := ctx.State["regex_matched"].([]string)[1]
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
chose := true
|
||||
if swtich == "关闭" {
|
||||
chose = false
|
||||
}
|
||||
if option == "歌单" {
|
||||
cfg.API = chose
|
||||
} else {
|
||||
cfg.Local = chose
|
||||
}
|
||||
err = saveConfig(cfgFile)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:\n", err))
|
||||
}
|
||||
})
|
||||
// 本地绑定网易云歌单ID
|
||||
engine.OnRegex(`^添加歌单\s?(https:.*id=)?(\d+)\s?(.*)$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
listID := ctx.State["regex_matched"].([]string)[2]
|
||||
listName := ctx.State["regex_matched"].([]string)[3]
|
||||
ctx.SendChain(message.Text("正在校验歌单信息,请稍等"))
|
||||
// 是否存在该歌单
|
||||
apiURL := "https://ovooa.com/API/163_Music_Rand/api.php?id=" + listID
|
||||
data, err := web.GetData(apiURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "error:", err))
|
||||
return
|
||||
}
|
||||
var parsed ovooaData
|
||||
err = json.Unmarshal(data, &parsed)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "无法解析歌单ID内容:", err))
|
||||
return
|
||||
}
|
||||
if parsed.Code != 1 {
|
||||
ctx.SendChain(message.Text(serviceErr, "error:", parsed.Text))
|
||||
return
|
||||
}
|
||||
pathOfMusic := cfg.MusicPath + listName + "/"
|
||||
err = os.MkdirAll(pathOfMusic, 0777)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "歌单不存在于本地,尝试创建该歌单失败:\n", err))
|
||||
return
|
||||
}
|
||||
mid, _ := strconv.ParseInt(listID, 10, 64)
|
||||
cfg.Playlist = append(cfg.Playlist, listRaw{
|
||||
Name: listName,
|
||||
ID: mid,
|
||||
})
|
||||
err = saveConfig(cfgFile)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "error:", err))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^删除歌单\s?(.*)$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
delList := ctx.State["regex_matched"].([]string)[1]
|
||||
filelist, err = getlist(cfg.MusicPath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "歌单列表获取error:", err))
|
||||
return
|
||||
}
|
||||
index := 1024
|
||||
for i, listinfo := range filelist {
|
||||
if delList == listinfo.Name || delList == strconv.FormatInt(listinfo.ID, 10) {
|
||||
if delList == listinfo.Name {
|
||||
err = os.RemoveAll(cfg.MusicPath + delList)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("歌单文件删除失败:\n", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == 1024 {
|
||||
ctx.SendChain(message.Text("歌单名称错误,可以发送“歌单列表”获取歌单名称"))
|
||||
return
|
||||
}
|
||||
var newCatList []listRaw
|
||||
for _, list := range cfg.Playlist {
|
||||
if list.Name == filelist[index].Name {
|
||||
continue
|
||||
}
|
||||
newCatList = append(newCatList, list)
|
||||
}
|
||||
cfg.Playlist = newCatList
|
||||
err = saveConfig(cfgFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
}
|
||||
filelist, err = getlist(cfg.MusicPath)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
}
|
||||
})
|
||||
// 下载歌曲到对应的歌单里面
|
||||
engine.OnRegex(`^下载歌曲\s?(\d+|.*[^\s$])\s(.*[^\s$])$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
listName := ctx.State["regex_matched"].([]string)[2]
|
||||
ctx.SendChain(message.Text("正在校验歌单信息,请稍等"))
|
||||
// 是否存在该歌单
|
||||
filelist, err := getlist(cfg.MusicPath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "获取歌单列表ERROR:", err))
|
||||
return
|
||||
}
|
||||
ok := true
|
||||
for _, listinfo := range filelist {
|
||||
if listName == listinfo.Name {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
ctx.SendChain(message.Text("歌单不存在,是否创建?(是/否)"))
|
||||
next := zero.NewFutureEvent("message", 999, false, zero.OnlyGroup, zero.RegexRule(`(是|否)`), ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
wait := time.NewTimer(120 * time.Second)
|
||||
answer := ""
|
||||
for {
|
||||
select {
|
||||
case <-wait.C:
|
||||
wait.Stop()
|
||||
ctx.SendChain(message.Text("等待超时,取消下载"))
|
||||
return
|
||||
case c := <-recv:
|
||||
wait.Stop()
|
||||
answer = c.Event.Message.String()
|
||||
}
|
||||
if answer == "否" {
|
||||
ctx.SendChain(message.Text("下载已经取消"))
|
||||
return
|
||||
}
|
||||
if answer != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
err = os.MkdirAll(cfg.MusicPath+listName, 0777)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "生成文件夹ERROR:\n", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
searchlist, err := wyy.SearchMusic(keyword, 5)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("查询歌曲失败!\nerr:", err))
|
||||
return
|
||||
}
|
||||
listmun := len(searchlist)
|
||||
if listmun == 0 {
|
||||
ctx.SendChain(message.Text("歌曲没有查询到,请确认信息正确"))
|
||||
return
|
||||
}
|
||||
musicList := make([]string, listmun)
|
||||
i := 0
|
||||
for musicName := range searchlist {
|
||||
musicList[i] = musicName
|
||||
i++
|
||||
}
|
||||
savePath := cfg.MusicPath + listName + "/"
|
||||
if listmun == 1 {
|
||||
musicName := musicList[0]
|
||||
musicID := searchlist[musicName]
|
||||
// 下载歌曲
|
||||
err = wyy.DownloadMusic(musicID, musicName, savePath)
|
||||
if err == nil {
|
||||
if cfg.Local {
|
||||
// 下载歌词
|
||||
_ = wyy.DownloadLrc(musicID, musicName, savePath+"歌词/")
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "error:", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
var msg []string
|
||||
msg = append(msg, "搜索到相近的歌曲,请回复对应序号进行下载或回复取消")
|
||||
for j, musicName := range musicList {
|
||||
msg = append(msg, strconv.Itoa(j)+"."+musicName)
|
||||
}
|
||||
ctx.SendChain(message.Text(strings.Join(msg, "\n")))
|
||||
next := zero.NewFutureEvent("message", 999, false, zero.OnlyGroup, zero.RegexRule(`[0-4]|取消`), ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
wait := time.NewTimer(120 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-wait.C:
|
||||
wait.Stop()
|
||||
ctx.SendChain(message.Text("等待超时,取消下载"))
|
||||
return
|
||||
case c := <-recv:
|
||||
wait.Stop()
|
||||
answer := c.Event.Message.String()
|
||||
if answer == "取消" {
|
||||
ctx.SendChain(message.Text("已取消下载"))
|
||||
return
|
||||
}
|
||||
index, _ := strconv.Atoi(answer)
|
||||
// 下载歌曲
|
||||
musicName := musicList[index]
|
||||
err = wyy.DownloadMusic(searchlist[musicName], musicName, savePath)
|
||||
if err == nil {
|
||||
if cfg.Local {
|
||||
// 下载歌词
|
||||
_ = wyy.DownloadLrc(searchlist[musicName], musicName, savePath+"歌词/")
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(serviceErr, "error:", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch("歌单列表").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
filelist, err := getlist(cfg.MusicPath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "获取歌单列表ERROR:", err))
|
||||
return
|
||||
}
|
||||
/***********设置图片的大小和底色***********/
|
||||
number := len(filelist)
|
||||
fontSize := 20.0
|
||||
if number < 10 {
|
||||
number = 10
|
||||
}
|
||||
canvas := gg.NewContext(480, int(80+fontSize*float64(number)))
|
||||
canvas.SetRGB(1, 1, 1) // 白色
|
||||
canvas.Clear()
|
||||
/***********下载字体,可以注销掉***********/
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
}
|
||||
_, err = file.GetLazyData(text.FontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
}
|
||||
/***********设置字体颜色为黑色***********/
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
return
|
||||
}
|
||||
_, h := canvas.MeasureString("序号\t\t歌单名\t\t\t歌曲数量\t\t网易云歌单ID")
|
||||
/***********绘制标题***********/
|
||||
canvas.DrawString("序号\t\t歌单名\t\t歌曲数量\t\t网易云歌单ID", 20, 50-h) // 放置在中间位置
|
||||
canvas.DrawString("——————————————————————", 20, 70-h)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.FontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
return
|
||||
}
|
||||
_, h = canvas.MeasureString("焯")
|
||||
j := 0
|
||||
for i, listinfo := range filelist {
|
||||
canvas.DrawString(strconv.Itoa(i), 15, float64(85+20*i)-h)
|
||||
canvas.DrawString(listinfo.Name, 85, float64(85+20*i)-h)
|
||||
canvas.DrawString(strconv.Itoa(listinfo.Number), 220, float64(85+20*i)-h)
|
||||
if listinfo.ID != 0 {
|
||||
canvas.DrawString(strconv.FormatInt(listinfo.ID, 10), 320, float64(85+20*i)-h)
|
||||
}
|
||||
j = i + 2
|
||||
}
|
||||
for _, dlist := range cfg.Defaultlist {
|
||||
if dlist.GroupID == ctx.Event.GroupID {
|
||||
canvas.DrawString("当前设置的默认歌单为: "+dlist.Name, 80, float64(85+20*j)-h)
|
||||
}
|
||||
}
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
if id := ctx.SendChain(message.ImageBytes(data)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
cl()
|
||||
})
|
||||
engine.OnRegex(`^(个人|团队)猜歌(-(.*))?$`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
mode := ctx.State["regex_matched"].([]string)[3]
|
||||
gid := ctx.Event.GroupID
|
||||
filelist, err := getlist(cfg.MusicPath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "获取歌单列表ERROR:", err))
|
||||
return
|
||||
}
|
||||
if mode == "" {
|
||||
for _, dlist := range cfg.Defaultlist {
|
||||
if dlist.GroupID == gid {
|
||||
mode = dlist.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if mode == "" {
|
||||
mode = filelist[0].Name
|
||||
} else {
|
||||
ok := true
|
||||
for _, listinfo := range filelist {
|
||||
if mode == listinfo.Name {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
ctx.SendChain(message.Text("歌单名称错误,可以发送“歌单列表”获取歌单名称"))
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("正在准备歌曲,请稍等\n回答“-[歌曲信息(歌名歌手等)|提示|取消]”\n一共3段语音,6次机会"))
|
||||
// 随机抽歌
|
||||
pathOfMusic, musicName, err := musicLottery(cfg.MusicPath, mode)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:", err))
|
||||
return
|
||||
}
|
||||
// 解析歌曲信息
|
||||
music := strings.Split(musicName, ".")
|
||||
// 获取音乐后缀
|
||||
musictype := music[len(music)-1]
|
||||
if !strings.Contains(musictypelist, musictype) {
|
||||
ctx.SendChain(message.Text("抽取到了歌曲:\n",
|
||||
musicName, "\n该歌曲不是音乐后缀,请联系bot主人修改"))
|
||||
return
|
||||
}
|
||||
// 获取音乐信息
|
||||
musicInfo := strings.Split(strings.ReplaceAll(musicName, "."+musictype, ""), " - ")
|
||||
infoNum := len(musicInfo)
|
||||
if infoNum == 1 {
|
||||
ctx.SendChain(message.Text("抽取到了歌曲:\n",
|
||||
musicName, "\n该歌曲命名不符合命名规则,请联系bot主人修改"))
|
||||
return
|
||||
}
|
||||
answerString := "歌名:" + musicInfo[0] + "\n歌手:" + musicInfo[1]
|
||||
musicAlia := ""
|
||||
if infoNum > 2 {
|
||||
musicAlia = musicInfo[2]
|
||||
answerString += "\n其他信息:\n" + strings.ReplaceAll(musicAlia, "&", "\n")
|
||||
}
|
||||
// 切割音频,生成3个10秒的音频
|
||||
outputPath := cachePath + strconv.FormatInt(gid, 10) + "/"
|
||||
err = cutMusic(musicName, pathOfMusic, outputPath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(err))
|
||||
return
|
||||
}
|
||||
// 进行猜歌环节
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + "0.wav"))
|
||||
var next *zero.FutureEvent
|
||||
if ctx.State["regex_matched"].([]string)[1] == "个人" {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.OnlyGroup, zero.RegexRule(`^-\S{1,}`), ctx.CheckSession())
|
||||
} else {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.OnlyGroup, zero.RegexRule(`^-\S{1,}`), zero.CheckGroup(ctx.Event.GroupID))
|
||||
}
|
||||
var musicCount = 0 // 音频数量
|
||||
var answerCount = 0 // 问答次数
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
wait := time.NewTimer(40 * time.Second)
|
||||
tick := time.NewTimer(105 * time.Second)
|
||||
after := time.NewTimer(120 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
ctx.SendChain(message.Text("猜歌游戏,你还有15s作答时间"))
|
||||
case <-after.C:
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("时间超时,猜歌结束,公布答案:\n", answerString)))
|
||||
return
|
||||
case <-wait.C:
|
||||
wait.Reset(40 * time.Second)
|
||||
musicCount++
|
||||
if musicCount > 2 {
|
||||
wait.Stop()
|
||||
continue
|
||||
}
|
||||
ctx.SendChain(
|
||||
message.Text("好像有些难度呢,再听这段音频,要仔细听哦"),
|
||||
)
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + strconv.Itoa(musicCount) + ".wav"))
|
||||
case c := <-recv:
|
||||
wait.Reset(40 * time.Second)
|
||||
tick.Reset(105 * time.Second)
|
||||
after.Reset(120 * time.Second)
|
||||
answer := strings.Replace(c.Event.Message.String(), "-", "", 1)
|
||||
switch {
|
||||
case answer == "取消":
|
||||
if c.Event.UserID == ctx.Event.UserID {
|
||||
wait.Stop()
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("游戏已取消,猜歌答案是\n", answerString, "\n\n\n下面欣赏猜歌的歌曲")))
|
||||
ctx.SendChain(message.Record("file:///" + pathOfMusic + musicName))
|
||||
return
|
||||
}
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("你无权限取消"),
|
||||
),
|
||||
)
|
||||
case answer == "提示":
|
||||
musicCount++
|
||||
if musicCount > 2 {
|
||||
wait.Stop()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("已经没有提示了哦"),
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
wait.Reset(40 * time.Second)
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("再听这段音频,要仔细听哦"),
|
||||
),
|
||||
)
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + strconv.Itoa(musicCount) + ".wav"))
|
||||
case strings.Contains(musicInfo[0], answer) || strings.EqualFold(musicInfo[0], answer):
|
||||
wait.Stop()
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("太棒了,你猜对歌曲名了!答案是\n", answerString, "\n\n下面欣赏猜歌的歌曲")))
|
||||
ctx.SendChain(message.Record("file:///" + pathOfMusic + musicName))
|
||||
return
|
||||
case strings.Contains(musicInfo[1], answer) || strings.EqualFold(musicInfo[1], answer):
|
||||
wait.Stop()
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("太棒了,你猜对歌手名了!答案是\n", answerString, "\n\n下面欣赏猜歌的歌曲")))
|
||||
ctx.SendChain(message.Record("file:///" + pathOfMusic + musicName))
|
||||
return
|
||||
case strings.Contains(musicAlia, answer) || strings.EqualFold(musicAlia, answer):
|
||||
wait.Stop()
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("太棒了,你猜对出处了!答案是\n", answerString, "\n\n下面欣赏猜歌的歌曲")))
|
||||
ctx.SendChain(message.Record("file:///" + pathOfMusic + musicName))
|
||||
return
|
||||
default:
|
||||
musicCount++
|
||||
switch {
|
||||
case musicCount > 2 && answerCount < 6:
|
||||
wait.Stop()
|
||||
answerCount++
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("答案不对哦,加油啊~"),
|
||||
),
|
||||
)
|
||||
case musicCount > 2:
|
||||
wait.Stop()
|
||||
tick.Stop()
|
||||
after.Stop()
|
||||
ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("次数到了,没能猜出来。答案是\n", answerString, "\n\n下面欣赏猜歌的歌曲")))
|
||||
ctx.SendChain(message.Record("file:///" + pathOfMusic + musicName))
|
||||
return
|
||||
default:
|
||||
wait.Reset(40 * time.Second)
|
||||
answerCount++
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(c.Event.MessageID,
|
||||
message.Text("答案不对,再听这段音频,要仔细听哦"),
|
||||
),
|
||||
)
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + strconv.Itoa(musicCount) + ".wav"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 保存用户配置
|
||||
func saveConfig(cfgFile string) error {
|
||||
if reader, err := os.Create(cfgFile); err == nil {
|
||||
err = json.NewEncoder(reader).Encode(&cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取本地歌单列表
|
||||
func getlist(pathOfMusic string) (list []listinfo, err error) {
|
||||
wyyID := make(map[string]int64, 100)
|
||||
for _, wyyinfo := range cfg.Playlist {
|
||||
if wyyinfo.ID != 0 {
|
||||
wyyID[wyyinfo.Name] = wyyinfo.ID
|
||||
}
|
||||
}
|
||||
err = os.MkdirAll(pathOfMusic, 0777)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(pathOfMusic)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(files) == 0 {
|
||||
err = errors.Errorf("所设置的歌库不存在任何歌单!")
|
||||
return
|
||||
}
|
||||
for _, name := range files {
|
||||
if !name.IsDir() {
|
||||
continue
|
||||
}
|
||||
listName := name.Name()
|
||||
listfiles, err := os.ReadDir(pathOfMusic + listName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
list = append(list, listinfo{
|
||||
Name: listName,
|
||||
Number: len(listfiles),
|
||||
ID: wyyID[listName],
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 随机抽取音乐
|
||||
func musicLottery(musicPath, listName string) (pathOfMusic, musicName string, err error) {
|
||||
filelist, err := getlist(musicPath)
|
||||
if err != nil {
|
||||
err = errors.Errorf("获取列表错误,%s", err)
|
||||
return
|
||||
}
|
||||
var fileList = make(map[string]int64, 100)
|
||||
for _, listinfo := range filelist {
|
||||
fileList[listinfo.Name] = listinfo.ID
|
||||
}
|
||||
playlistID, ok := fileList[listName]
|
||||
if !ok {
|
||||
err = errors.Errorf("指定的歌单不存在与列表当中")
|
||||
return
|
||||
}
|
||||
pathOfMusic = musicPath + listName + "/"
|
||||
err = os.MkdirAll(pathOfMusic, 0777)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
files, err := os.ReadDir(pathOfMusic)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//如果本地列表为空
|
||||
if len(files) == 0 {
|
||||
if playlistID == 0 || !cfg.API {
|
||||
err = errors.New("本地歌单数据为0")
|
||||
return
|
||||
}
|
||||
// 如果绑定了歌单ID
|
||||
musicName, err = downloadByOvooa(playlistID, pathOfMusic)
|
||||
err = errors.Errorf("本地歌单数据为0,API下载歌曲失败\n%s", err)
|
||||
return
|
||||
}
|
||||
// 进行随机抽取
|
||||
if playlistID == 0 || !cfg.API {
|
||||
musicName = getLocalMusic(files)
|
||||
} else {
|
||||
switch rand.Intn(3) { //三分二概率抽取API的
|
||||
case 1:
|
||||
musicName = getLocalMusic(files)
|
||||
default:
|
||||
musicName, err = downloadByOvooa(playlistID, pathOfMusic)
|
||||
if err != nil {
|
||||
musicName = getLocalMusic(files)
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 从本地列表中随机抽取一首
|
||||
func getLocalMusic(files []fs.DirEntry) (musicName string) {
|
||||
if len(files) > 1 {
|
||||
music := files[rand.Intn(len(files))]
|
||||
// 如果是文件夹就递归
|
||||
if music.IsDir() {
|
||||
musicName = getLocalMusic(files)
|
||||
} else {
|
||||
musicName = music.Name()
|
||||
}
|
||||
} else {
|
||||
music := files[0]
|
||||
if !music.IsDir() {
|
||||
musicName = files[0].Name()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 下载从独角兽抽到的歌曲ID(歌单ID, 音乐保存路径, 歌词保存路径)
|
||||
func downloadByOvooa(playlistID int64, musicPath string) (musicName string, err error) {
|
||||
// 抽取歌曲
|
||||
mid, err := drawByOvooa(playlistID)
|
||||
if err != nil {
|
||||
err = errors.Errorf("API ERROR: %s", err)
|
||||
return
|
||||
}
|
||||
// 获取完成的歌名
|
||||
musiclist, err := wyy.SearchMusic(strconv.Itoa(mid), 1)
|
||||
if err != nil {
|
||||
err = errors.Errorf("API歌曲下载ERROR: %s", err)
|
||||
return
|
||||
}
|
||||
// 歌曲ID理论是唯一的
|
||||
mun := len(musiclist)
|
||||
if mun == 1 {
|
||||
// 拉取歌名
|
||||
musicList := make([]string, mun)
|
||||
i := 0
|
||||
for musicName := range musiclist {
|
||||
musicList[i] = musicName
|
||||
}
|
||||
name := musicList[0]
|
||||
// 下载歌曲
|
||||
err = wyy.DownloadMusic(mid, name, musicPath)
|
||||
if err == nil {
|
||||
musicName = name + ".mp3"
|
||||
if cfg.Local {
|
||||
// 下载歌词
|
||||
_ = wyy.DownloadLrc(mid, name, musicPath+"歌词/")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = errors.Errorf("music ID ERROR: This music ID sreached munber is %d", mun)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 通过独角兽API随机抽取歌单歌曲ID(参数:歌单ID)
|
||||
func drawByOvooa(playlistID int64) (musicID int, err error) {
|
||||
apiURL := "https://ovooa.com/API/163_Music_Rand/api.php?id=" + strconv.FormatInt(playlistID, 10)
|
||||
data, err := web.GetData(apiURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var parsed ovooaData
|
||||
err = json.Unmarshal(data, &parsed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if parsed.Code != 1 {
|
||||
return
|
||||
}
|
||||
return parsed.Data.ID, nil
|
||||
}
|
||||
|
||||
// 切割音乐成三个10s音频
|
||||
func cutMusic(musicName, pathOfMusic, outputPath string) (err error) {
|
||||
err = os.MkdirAll(outputPath, 0777)
|
||||
if err != nil {
|
||||
err = errors.Errorf("[生成歌曲目录错误]ERROR: %s", err)
|
||||
return
|
||||
}
|
||||
var stderr bytes.Buffer
|
||||
cmdArguments := []string{"-y", "-i", pathOfMusic + musicName,
|
||||
"-ss", cuttime[0], "-t", "10", file.BOTPATH + "/" + outputPath + "0.wav",
|
||||
"-ss", cuttime[1], "-t", "10", file.BOTPATH + "/" + outputPath + "1.wav",
|
||||
"-ss", cuttime[2], "-t", "10", file.BOTPATH + "/" + outputPath + "2.wav", "-hide_banner"}
|
||||
cmd := exec.Command("ffmpeg", cmdArguments...)
|
||||
cmd.Stderr = &stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
err = errors.Errorf("[生成歌曲错误]ERROR: %s", stderr.String())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
43
plugin/guessmusic/struct.go
Normal file
43
plugin/guessmusic/struct.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package guessmusic
|
||||
|
||||
// config内容
|
||||
type config struct {
|
||||
MusicPath string `json:"musicPath"`
|
||||
Local bool `json:"local"`
|
||||
API bool `json:"api"`
|
||||
Cookie string `json:"cookie"`
|
||||
Playlist []listRaw `json:"playlist"`
|
||||
Defaultlist []dlist `json:"defaultlist"`
|
||||
}
|
||||
|
||||
// 记录歌单绑定的网易云歌单ID
|
||||
type listRaw struct {
|
||||
Name string `json:"name"` // 歌单名称
|
||||
ID int64 `json:"id"` // 歌单绑定的网易云ID
|
||||
}
|
||||
|
||||
// 记录群默认猜歌
|
||||
type dlist struct {
|
||||
GroupID int64 `json:"gid"` // 群号
|
||||
Name string `json:"name"` // 歌单名称
|
||||
}
|
||||
|
||||
// 本地歌单列表信息
|
||||
type listinfo struct {
|
||||
Name string `json:"name"` // 歌单名称
|
||||
Number int // 歌曲数量
|
||||
ID int64 // 歌单绑定的歌曲ID
|
||||
}
|
||||
|
||||
// 独角兽API随机抽歌信息
|
||||
type ovooaData struct {
|
||||
Code int `json:"code"`
|
||||
Text string `json:"text"`
|
||||
Data struct {
|
||||
Song string `json:"song"`
|
||||
Singer string `json:"singer"`
|
||||
Cover string `json:"cover"`
|
||||
Music string `json:"Music"`
|
||||
ID int `json:"id"`
|
||||
} `json:"data"`
|
||||
}
|
||||
88
plugin/heisi/heisi.go
Normal file
88
plugin/heisi/heisi.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Package heisi 黑丝
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
fbctxext "github.com/FloatTech/floatbox/ctxext"
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
heisiPic []item
|
||||
baisiPic []item
|
||||
jkPic []item
|
||||
jurPic []item
|
||||
zukPic []item
|
||||
mcnPic []item
|
||||
fileList = [...]string{"heisi.bin", "baisi.bin", "jk.bin", "jur.bin", "zuk.bin", "mcn.bin"}
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("heisi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "黑丝",
|
||||
Help: "- 来点黑丝\n- 来点白丝\n- 来点jk\n- 来点巨乳\n- 来点足控\n- 来点网红",
|
||||
PublicDataFolder: "Heisi",
|
||||
})
|
||||
|
||||
engine.OnFullMatchGroup([]string{"来点黑丝", "来点白丝", "来点jk", "来点巨乳", "来点足控", "来点网红"}, zero.OnlyGroup, fbctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
for i, filePath := range fileList {
|
||||
data, err := engine.GetLazyData(filePath, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
if len(data)%10 != 0 {
|
||||
ctx.SendChain(message.Text("ERROR: invalid data " + strconv.Itoa(i)))
|
||||
return false
|
||||
}
|
||||
s := (*slice)(unsafe.Pointer(&data))
|
||||
s.len /= 10
|
||||
s.cap /= 10
|
||||
switch i {
|
||||
case 0:
|
||||
heisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 1:
|
||||
baisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 2:
|
||||
jkPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 3:
|
||||
jurPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 4:
|
||||
zukPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 5:
|
||||
mcnPic = *(*[]item)(unsafe.Pointer(s))
|
||||
}
|
||||
}
|
||||
return true
|
||||
})).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
var pic item
|
||||
switch matched {
|
||||
case "来点黑丝":
|
||||
pic = heisiPic[rand.Intn(len(heisiPic))]
|
||||
case "来点白丝":
|
||||
pic = baisiPic[rand.Intn(len(baisiPic))]
|
||||
case "来点jk":
|
||||
pic = jkPic[rand.Intn(len(jkPic))]
|
||||
case "来点巨乳":
|
||||
pic = jurPic[rand.Intn(len(jurPic))]
|
||||
case "来点足控":
|
||||
pic = zukPic[rand.Intn(len(zukPic))]
|
||||
case "来点网红":
|
||||
pic = mcnPic[rand.Intn(len(mcnPic))]
|
||||
}
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image(pic.String()))}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
}
|
||||
48
plugin/heisi/packer.go
Normal file
48
plugin/heisi/packer.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
template2021 = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%4d%02d16%06d-611a3%8s.jpg"
|
||||
templategeneral = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%015x"
|
||||
)
|
||||
|
||||
type item [10]byte
|
||||
|
||||
// String item to url
|
||||
func (it item) String() string {
|
||||
year, month := int((it[0]>>4)&0x0f), int(it[0]&0x0f)
|
||||
year += 2021
|
||||
if year == 2021 {
|
||||
num := binary.BigEndian.Uint32(it[1:5])
|
||||
dstr := hex.EncodeToString(it[5:9])
|
||||
return fmt.Sprintf(template2021, year, month, year, month, num, dstr)
|
||||
}
|
||||
d := binary.BigEndian.Uint64(it[1:9])
|
||||
isscaled := it[9]&0x80 > 0
|
||||
num := int(it[9] & 0x7f)
|
||||
trestore := fmt.Sprintf(templategeneral, year, month, d&0x0fffffff_ffffffff)
|
||||
if num > 0 {
|
||||
trestore += fmt.Sprintf("-%d", num)
|
||||
}
|
||||
if isscaled {
|
||||
trestore += "-scaled"
|
||||
}
|
||||
d = bits.RotateLeft64(d, 4) & 0x0f
|
||||
switch d {
|
||||
case 0:
|
||||
trestore += ".jpg"
|
||||
case 1:
|
||||
trestore += ".png"
|
||||
case 2:
|
||||
trestore += ".webp"
|
||||
default:
|
||||
return "invalid ext"
|
||||
}
|
||||
return trestore
|
||||
}
|
||||
15
plugin/heisi/slice.go
Normal file
15
plugin/heisi/slice.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package heisi
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type slice struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
)
|
||||
|
||||
var reqconf = [...]string{"GET", "https://hs.fbigame.com",
|
||||
@@ -43,8 +43,8 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("hs", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "炉石\n" +
|
||||
"- 搜卡[xxxx]\n" +
|
||||
Brief: "炉石搜卡",
|
||||
Help: "- 搜卡[xxxx]\n" +
|
||||
"- [卡组代码xxx]\n" +
|
||||
"- 更多搜卡指令参数:https://hs.fbigame.com/misc/searchhelp",
|
||||
PrivateDataFolder: "hs",
|
||||
@@ -81,7 +81,7 @@ func init() {
|
||||
ctx.Event.GroupID,
|
||||
sk,
|
||||
).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:可能被风控了"))
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
// 卡组
|
||||
|
||||
@@ -4,24 +4,26 @@ package hyaku
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const bed = "https://gitcode.net/u011570312/OguraHyakuninIsshu/-/raw/master/"
|
||||
|
||||
//nolint: asciicheck
|
||||
// nolint: asciicheck
|
||||
type line struct {
|
||||
番号, 歌人, 上の句, 下の句, 上の句ひらがな, 下の句ひらがな string
|
||||
}
|
||||
@@ -54,23 +56,36 @@ var lines [100]*line
|
||||
func init() {
|
||||
engine := control.Register("hyaku", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "百人一首\n" +
|
||||
"- 百人一首(随机发一首)\n" +
|
||||
Brief: "百人一首",
|
||||
Help: "- 百人一首(随机发一首)\n" +
|
||||
"- 百人一首之n",
|
||||
PrivateDataFolder: "hyaku",
|
||||
})
|
||||
csvfile := engine.DataFolder() + "hyaku.csv"
|
||||
err := os.MkdirAll(engine.DataFolder()+"img", 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
var f *os.File
|
||||
if file.IsNotExist(csvfile) {
|
||||
err := file.DownloadTo(bed+"小倉百人一首.csv", csvfile, true)
|
||||
data, err := web.RequestDataWith(web.NewTLS12Client(), bed+"小倉百人一首.csv", "GET", "gitcode.net", web.RandUA())
|
||||
if err != nil {
|
||||
_ = os.Remove(csvfile)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
f, err := os.Open(csvfile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
f, err = os.Create(csvfile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, _ = f.Write(data)
|
||||
_, _ = f.Seek(0, io.SeekStart)
|
||||
} else {
|
||||
var err error
|
||||
f, err = os.Open(csvfile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
records, err := csv.NewReader(f).ReadAll()
|
||||
if err != nil {
|
||||
@@ -98,26 +113,46 @@ func init() {
|
||||
}()
|
||||
engine.OnFullMatch("百人一首").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
i := rand.Intn(100)
|
||||
img0, err := engine.GetCustomLazyData(bed, fmt.Sprintf("img/%03d.jpg", i+1))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
img1, err := engine.GetCustomLazyData(bed, fmt.Sprintf("img/%03d.png", i+1))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(
|
||||
message.Image(fmt.Sprintf(bed+"img/%03d.jpg", i+1)),
|
||||
message.ImageBytes(img0),
|
||||
message.Text("\n", lines[i]),
|
||||
message.Image(fmt.Sprintf(bed+"img/%03d.png", i+1)),
|
||||
message.ImageBytes(img1),
|
||||
)
|
||||
})
|
||||
engine.OnRegex(`^百人一首之\s?(\d+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
i, err := strconv.Atoi(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if i > 100 || i < 1 {
|
||||
ctx.SendChain(message.Text("ERROR:超出范围"))
|
||||
ctx.SendChain(message.Text("ERROR: 超出范围"))
|
||||
return
|
||||
}
|
||||
img0, err := engine.GetCustomLazyData(bed, fmt.Sprintf("img/%03d.jpg", i))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
img1, err := engine.GetCustomLazyData(bed, fmt.Sprintf("img/%03d.png", i))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(
|
||||
message.Image(fmt.Sprintf(bed+"img/%03d.jpg", i)),
|
||||
message.ImageBytes(img0),
|
||||
message.Text("\n", lines[i-1]),
|
||||
message.Image(fmt.Sprintf(bed+"img/%03d.png", i)),
|
||||
message.ImageBytes(img1),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ import (
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/pixiv"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/pool"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
)
|
||||
|
||||
type resultjson struct {
|
||||
@@ -64,21 +64,21 @@ var hrefre = regexp.MustCompile(`<a href=".*">`)
|
||||
func init() {
|
||||
control.Register("imgfinder", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "关键字搜图\n" +
|
||||
"- 来张 [xxx]",
|
||||
Brief: "关键字搜图",
|
||||
Help: "- 来张 [xxx]",
|
||||
}).OnRegex(`^来张\s?(.*)$`, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
soutujson, err := soutuapi(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
rannum := rand.Intn(len(soutujson.Data.Illusts))
|
||||
il := soutujson.Data.Illusts[rannum]
|
||||
illust, err := pixiv.Works(il.ID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
u := illust.ImageUrls[0]
|
||||
@@ -101,7 +101,7 @@ func init() {
|
||||
),
|
||||
), ctxext.GetFirstMessageInForward(ctx))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("inject", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "注入指令\n" +
|
||||
"- run[CQ码]",
|
||||
Brief: "注入指令",
|
||||
Help: "- run[CQ码]",
|
||||
})
|
||||
// 运行 CQ 码
|
||||
en.OnPrefix("run", zero.SuperUserPermission).SetBlock(true).
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/antchfx/htmlquery"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@@ -25,26 +25,27 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("jandan", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "煎蛋网无聊图\n- 来份[屌|弔|吊]图\n- 更新[屌|弔|吊]图\n",
|
||||
Brief: "煎蛋网无聊图",
|
||||
Help: "- 来份[屌|弔|吊]图\n- 更新[屌|弔|吊]图\n",
|
||||
PublicDataFolder: "Jandan",
|
||||
})
|
||||
|
||||
getdb := ctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
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)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("picture", &picture{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("picture")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Printf("[jandan]读取%d张图片", n)
|
||||
@@ -55,7 +56,7 @@ func init() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
u, err := getRandomPicture()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image(u))
|
||||
@@ -67,13 +68,13 @@ func init() {
|
||||
webpageURL := api
|
||||
doc, err := htmlquery.LoadURL(webpageURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
re := regexp.MustCompile(`\d+`)
|
||||
pageTotal, err := strconv.Atoi(re.FindString(htmlquery.FindOne(doc, "//*[@id='comments']/div[2]/div/span[@class='current-comment-page']/text()").Data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
LOOP:
|
||||
@@ -81,12 +82,12 @@ func init() {
|
||||
logrus.Debugln("[jandan]", fmt.Sprintf("处理第%d/%d页...", i, pageTotal))
|
||||
doc, err = htmlquery.LoadURL(webpageURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
picList, err := htmlquery.QueryAll(doc, "//*[@class='view_img_link']")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(picList) != 0 {
|
||||
|
||||
65
plugin/jiami/jiami.go
Normal file
65
plugin/jiami/jiami.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Package jiami 兽语加密与解密
|
||||
package jiami
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
jiami1 = "http://ovooa.com/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.com/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
|
||||
)
|
||||
|
||||
type nmd struct { // struct解析格式大概是
|
||||
Data struct {
|
||||
Message string
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.Register("jiami", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "兽语加解密",
|
||||
Help: "兽语加解密\n" +
|
||||
"- 兽语加密xxx\n- 兽语解密xxx",
|
||||
})
|
||||
en.OnRegex(`^兽语加密\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es, err := web.GetData(fmt.Sprintf(jiami1, str)) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var r nmd // r数组
|
||||
err = json.Unmarshal(es, &r) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(r.Data.Message)) // 输出提取后的结果
|
||||
})
|
||||
|
||||
en.OnRegex(`^兽语解密\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es, err := web.GetData(fmt.Sprintf(jiami2, str)) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var n nmd // r数组
|
||||
err = json.Unmarshal(es, &n) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(n.Data.Message)) // 输出提取后的结果
|
||||
})
|
||||
}
|
||||
121
plugin/jikipedia/main.go
Normal file
121
plugin/jikipedia/main.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// Package jikipedia 小鸡词典
|
||||
// 修改自https://github.com/TeamPGM/PagerMaid_Plugins_Pyro ,非常感谢!!
|
||||
package jikipedia
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
url = "https://api.jikipedia.com/go/search_entities"
|
||||
)
|
||||
|
||||
type value struct {
|
||||
Phrase string `json:"phrase"`
|
||||
Page int `json:"page"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 初始化engine
|
||||
engine := control.Register("jikipedia", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "小鸡词典",
|
||||
Help: "- [查梗|小鸡词典][梗]",
|
||||
},
|
||||
)
|
||||
engine.OnPrefixGroup([]string{"小鸡词典", "查梗"}).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(
|
||||
func(ctx *zero.Ctx) {
|
||||
keyWord := strings.Trim(ctx.State["args"].(string), " ")
|
||||
|
||||
definition, err := parseKeyword(keyWord)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if definition.String() == "" {
|
||||
ctx.SendChain(message.Text("好像什么都没查到,换个关键词试一试?"))
|
||||
return
|
||||
}
|
||||
imgURL := definition.Get("images.0.scaled.path").String()
|
||||
ctx.SendChain(message.Text("【标题】:", definition.Get("term.title"),
|
||||
"\n【释义】:", definition.Get("plaintext"),
|
||||
"\n【原文】:https://jikipedia.com/definition/", definition.Get("id")),
|
||||
message.Image(imgURL))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func parseKeyword(keyWord string) (definition gjson.Result, err error) {
|
||||
client := &http.Client{}
|
||||
|
||||
values := value{Phrase: keyWord, Page: 1, Size: 10}
|
||||
jsonData, err := json.Marshal(values)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var request *http.Request
|
||||
request, err = http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
request.Header = http.Header{
|
||||
"Accept": {"application/json, text/plain, */*"},
|
||||
"Accept-Encoding": {"gzip, deflate, br"},
|
||||
"Accept-Language": {"zh-CN,zh-TW;q=0.9,zh;q=0.8"},
|
||||
"Client": {"web"},
|
||||
"Client-Version": {"2.7.2g"},
|
||||
"Connection": {"keep-alive"},
|
||||
"Host": {"api.jikipedia.com"},
|
||||
"Origin": {"https://jikipedia.com"},
|
||||
"Referer": {"https://jikipedia.com/"},
|
||||
"Sec-Fetch-Dest": {"empty"},
|
||||
"Sec-Fetch-Mode": {"cors"},
|
||||
"Sec-Fetch-Site": {"same-site"},
|
||||
"Token": {""},
|
||||
"User-Agent": {"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36"},
|
||||
"XID": {"uNo5bL1nyNCp/Gm7lJAHQ91220HLbMT8jqk9IJYhtHA4ofP+zgxwM6lSDIKiYoppP2k1IW/1Vxc2vOVGxOOVReebsLmWPHhTs7NCRygfDkE="},
|
||||
"sec-ch-ua": {`" Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"`},
|
||||
"sec-ch-ua-mobile": {"?1"},
|
||||
"sec-ch-ua-platform": {`"Android"`},
|
||||
}
|
||||
request.Header.Set("Content-Type", "application/json;charset=UTF-8")
|
||||
var response *http.Response
|
||||
response, err = client.Do(request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != http.StatusOK {
|
||||
extraInfo := ""
|
||||
if response.StatusCode == 423 {
|
||||
extraInfo = "\n调用过多被网站暂时封禁,请等待数个小时后使用该功能~"
|
||||
}
|
||||
s := fmt.Sprintf("status code: %d%s", response.StatusCode, extraInfo)
|
||||
err = errors.New(s)
|
||||
return
|
||||
}
|
||||
data, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
gjson.Get(binary.BytesToString(data), "data").ForEach(func(key, value gjson.Result) bool {
|
||||
definition = value.Get("definitions.0")
|
||||
return definition.String() == ""
|
||||
})
|
||||
return
|
||||
}
|
||||
105
plugin/jptingroom/jptingroom.go
Normal file
105
plugin/jptingroom/jptingroom.go
Normal file
@@ -0,0 +1,105 @@
|
||||
// Package jptingroom 日语听力学习材料
|
||||
package jptingroom
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("jptingroom", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "日语听力学习材料",
|
||||
Help: "- 随机日语听力\n" +
|
||||
"- 随机日语歌曲\n" +
|
||||
"- 日语听力 xxx\n" +
|
||||
"- 日语歌曲 xxx\n",
|
||||
PublicDataFolder: "Jptingroom",
|
||||
})
|
||||
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "item.db"
|
||||
_, err := engine.GetLazyData("item.db", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("item", &item{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("item")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
log.Infof("[jptingroom]读取%d条日语听力材料", n)
|
||||
return true
|
||||
})
|
||||
// 开启
|
||||
engine.OnFullMatchGroup([]string{"随机日语听力", "随机日语歌曲"}, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
var t item
|
||||
switch matched {
|
||||
case "随机日语听力":
|
||||
t = getRandomAudioByCategory("tingli")
|
||||
case "随机日语歌曲":
|
||||
t = getRandomAudioByCategory("gequ")
|
||||
default:
|
||||
}
|
||||
if t.AudioURL == "" {
|
||||
ctx.SendChain(message.Text("未能找到相关材料"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record(t.AudioURL))
|
||||
content := t.Title + "\n\n" + t.Content
|
||||
data, err := text.RenderToBase64(content, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`日语(听力|歌曲)\s?([一-龥A-Za-z0-9ぁ-んァ-ヶ]{1,50})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
var t item
|
||||
switch regexMatched[1] {
|
||||
case "听力":
|
||||
t = getRandomAudioByCategoryAndKeyword("tingli", regexMatched[2])
|
||||
case "歌曲":
|
||||
t = getRandomAudioByCategoryAndKeyword("gequ", regexMatched[2])
|
||||
default:
|
||||
}
|
||||
if t.AudioURL == "" {
|
||||
ctx.SendChain(message.Text("未能找到相关材料"))
|
||||
return
|
||||
}
|
||||
content := t.Title + "\n\n" + t.Content
|
||||
data, err := text.RenderToBase64(content, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
30
plugin/jptingroom/model.go
Normal file
30
plugin/jptingroom/model.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package jptingroom
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
)
|
||||
|
||||
type item struct {
|
||||
ID int64 `db:"id"`
|
||||
Title string `db:"title"`
|
||||
PageURL string `db:"page_url"`
|
||||
Category string `db:"category"`
|
||||
Intro string `db:"intro"`
|
||||
AudioURL string `db:"audio_url"`
|
||||
Content string `db:"content"`
|
||||
Datetime time.Time `db:"datetime"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
|
||||
func getRandomAudioByCategory(category string) (t item) {
|
||||
_ = db.Find("item", &t, "where category = '"+category+"' ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
func getRandomAudioByCategoryAndKeyword(category string, keyword string) (t item) {
|
||||
_ = db.Find("item", &t, "where category = '"+category+"' and (title like '%"+keyword+"%' or content like '%"+keyword+"%') ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
@@ -25,8 +25,8 @@ const (
|
||||
func init() {
|
||||
control.Register("juejuezi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "绝绝子生成器\n" +
|
||||
"- 喝奶茶绝绝子 | 绝绝子吃饭",
|
||||
Brief: "绝绝子生成器",
|
||||
Help: "例: 喝奶茶绝绝子\n绝绝子吃饭",
|
||||
}).OnRegex("[\u4E00-\u9FA5]{0,10}绝绝子[\u4E00-\u9FA5]{0,10}").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
toDealStr := []rune(strings.ReplaceAll(ctx.ExtractPlainText(), "绝绝子", ""))
|
||||
switch len(toDealStr) {
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
case 2:
|
||||
data, err := juejuezi(string(toDealStr[0]), string(toDealStr[1]))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(gjson.Get(helper.BytesToString(data), "text").String()))
|
||||
@@ -43,7 +43,7 @@ func init() {
|
||||
params := ctx.GetWordSlices(string(toDealStr)).Get("slices").Array()
|
||||
data, err := juejuezi(params[0].String(), params[1].String())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(gjson.Get(helper.BytesToString(data), "text").String()))
|
||||
|
||||
@@ -3,6 +3,8 @@ package lolicon
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -10,13 +12,13 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"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/pool"
|
||||
"github.com/FloatTech/zbputils/math"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
imagepool "github.com/FloatTech/zbputils/img/pool"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,66 +27,69 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
queue = make(chan string, capacity)
|
||||
custapi = ""
|
||||
queue = make(chan string, capacity)
|
||||
customapi = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("lolicon", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "lolicon\n" +
|
||||
"- 来份萝莉\n" +
|
||||
Brief: "随机图片",
|
||||
Help: "- 随机图片\n" +
|
||||
"- 随机图片 萝莉|少女\n" +
|
||||
"- 设置随机图片地址[http...]",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
en.OnFullMatch("来份萝莉").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
en.OnPrefix("随机图片").Limit(ctxext.LimitByUser).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if imgtype := strings.TrimSpace(ctx.State["args"].(string)); imgtype != "" {
|
||||
imageurl, err := getimgurl(api + "?tag=" + url.QueryEscape(imgtype))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.Send(message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image(imageurl))}).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
for i := 0; i < math.Min(cap(queue)-len(queue), 2); i++ {
|
||||
if custapi != "" {
|
||||
data, err := web.GetData(custapi)
|
||||
if customapi != "" {
|
||||
data, err := web.GetData(customapi)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
continue
|
||||
}
|
||||
queue <- "base64://" + base64.StdEncoding.EncodeToString(data)
|
||||
continue
|
||||
}
|
||||
data, err := web.GetData(api)
|
||||
imageurl, err := getimgurl(api)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
continue
|
||||
}
|
||||
json := gjson.ParseBytes(data)
|
||||
if e := json.Get("error").Str; e != "" {
|
||||
ctx.SendChain(message.Text("ERROR:", e))
|
||||
continue
|
||||
}
|
||||
url := json.Get("data.0.urls.original").Str
|
||||
url = strings.ReplaceAll(url, "i.pixiv.cat", "i.pixiv.re")
|
||||
name := url[strings.LastIndex(url, "/")+1 : len(url)-4]
|
||||
m, err := pool.GetImage(name)
|
||||
name := imageurl[strings.LastIndex(imageurl, "/")+1 : len(imageurl)-4]
|
||||
m, err := imagepool.GetImage(name)
|
||||
if err != nil {
|
||||
m.SetFile(url)
|
||||
_, err = m.Push(ctxext.SendToSelf(ctx), ctxext.GetMessage(ctx))
|
||||
m.SetFile(imageurl)
|
||||
_, _ = m.Push(ctxext.SendToSelf(ctx), ctxext.GetMessage(ctx))
|
||||
process.SleepAbout1sTo2s()
|
||||
}
|
||||
if err == nil {
|
||||
queue <- m.String()
|
||||
} else {
|
||||
queue <- url
|
||||
queue <- imageurl
|
||||
}
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-time.After(time.Minute):
|
||||
ctx.SendChain(message.Text("ERROR:等待填充,请稍后再试......"))
|
||||
ctx.SendChain(message.Text("ERROR: 等待填充,请稍后再试......"))
|
||||
case img := <-queue:
|
||||
id := ctx.SendChain(message.Image(img))
|
||||
if id.ID() == 0 {
|
||||
if id := ctx.Send(message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image(img))}).ID(); id == 0 {
|
||||
process.SleepAbout1sTo2s()
|
||||
id = ctx.SendChain(message.Image(img).Add("cache", "0"))
|
||||
if id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR:图片发送失败,可能被风控了~"))
|
||||
if id := ctx.Send(message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image(img).Add("cache", "0"))}).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,10 +97,23 @@ func init() {
|
||||
en.OnPrefix("设置随机图片地址", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
u := strings.TrimSpace(ctx.State["args"].(string))
|
||||
if !strings.HasPrefix(u, "http") {
|
||||
ctx.SendChain(message.Text("ERROR:url非法!"))
|
||||
return
|
||||
}
|
||||
custapi = u
|
||||
ctx.SendChain(message.Text("成功设置随机图片地址为", u))
|
||||
customapi = u
|
||||
})
|
||||
}
|
||||
|
||||
func getimgurl(url string) (string, error) {
|
||||
data, err := web.GetData(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
json := gjson.ParseBytes(data)
|
||||
if e := json.Get("error").Str; e != "" {
|
||||
return "", errors.New(e)
|
||||
}
|
||||
var imageurl string
|
||||
if imageurl = json.Get("data.0.urls.original").Str; imageurl == "" {
|
||||
return "", errors.New("未找到相关内容, 换个tag试试吧")
|
||||
}
|
||||
return strings.ReplaceAll(imageurl, "i.pixiv.cat", "i.pixiv.re"), nil
|
||||
}
|
||||
|
||||
91
plugin/magicprompt/magicprompt.go
Normal file
91
plugin/magicprompt/magicprompt.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package magicprompt MagicPrompt-Stable-Diffusion吟唱提示
|
||||
package magicprompt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
hf "github.com/FloatTech/AnimeAPI/huggingface"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/RomiChan/websocket"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
magicpromptRepo = "Gustavosta/MagicPrompt-Stable-Diffusion"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("magicprompt", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "MagicPrompt-Stable-Diffusion吟唱提示",
|
||||
Help: "- 吟唱提示 xxx",
|
||||
PrivateDataFolder: "magicprompt",
|
||||
})
|
||||
|
||||
// 开启
|
||||
engine.OnPrefixGroup([]string{`吟唱提示`, "吟唱补全"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
_ctx, _cancel := context.WithTimeout(context.Background(), hf.TimeoutMax*time.Second)
|
||||
defer _cancel()
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
|
||||
magicpromptURL := fmt.Sprintf(hf.WssJoinPath, magicpromptRepo)
|
||||
args := ctx.State["args"].(string)
|
||||
c, _, err := websocket.DefaultDialer.Dial(magicpromptURL, nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
r := hf.PushRequest{
|
||||
FnIndex: 0,
|
||||
Data: []interface{}{args},
|
||||
}
|
||||
b, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = c.WriteMessage(websocket.TextMessage, b)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
t := time.NewTicker(time.Second * 1)
|
||||
defer t.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
_, data, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("msg").String() == hf.WssCompleteStatus {
|
||||
m := message.Message{}
|
||||
for _, v := range strings.Split(j.Get("output.data.0").String(), "\n\n") {
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(v)))
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-_ctx.Done():
|
||||
ctx.SendChain(message.Text("ERROR: 吟唱提示指令超时"))
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/zbputils/math"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
)
|
||||
|
||||
// user hash file
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/math"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/plugin/manager/timer"
|
||||
)
|
||||
@@ -47,11 +47,15 @@ const (
|
||||
"- 取消在\"cron\"的提醒\n" +
|
||||
"- 列出所有提醒\n" +
|
||||
"- 翻牌\n" +
|
||||
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}] {at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名\n" +
|
||||
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" +
|
||||
"- 测试欢迎语\n" +
|
||||
"- 设置告别辞 参数同设置欢迎语\n" +
|
||||
"- 测试告别辞\n" +
|
||||
"- [开启 | 关闭]入群验证"
|
||||
"- [开启 | 关闭]入群验证\n" +
|
||||
"- 对信息回复:[设置 | 取消]精华\n" +
|
||||
"- 取消精华 [信息ID]\n" +
|
||||
"- /精华列表\n" +
|
||||
"Tips: {at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -62,6 +66,7 @@ var (
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("manager", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "群管插件",
|
||||
Help: hint,
|
||||
PrivateDataFolder: "manager",
|
||||
})
|
||||
@@ -553,12 +558,9 @@ func init() { // 插件主体
|
||||
// 根据 gist 自动同意加群
|
||||
// 加群请在github新建一个gist,其文件名为本群群号的字符串的md5(小写),内容为一行,是当前unix时间戳(10分钟内有效)。
|
||||
// 然后请将您的用户名和gist哈希(小写)按照username/gisthash的格式填写到回答即可。
|
||||
engine.OnRequest().SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
/*if ctx.Event.RequestType == "friend" {
|
||||
ctx.SetFriendAddRequest(ctx.Event.Flag, true, "")
|
||||
}*/
|
||||
engine.On("request/group/add").SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok && c.GetData(ctx.Event.GroupID)&0x10 == 0x10 && ctx.Event.RequestType == "group" && ctx.Event.SubType == "add" {
|
||||
if ok && c.GetData(ctx.Event.GroupID)&0x10 == 0x10 {
|
||||
// gist 文件名是群号的 ascii 编码的 md5
|
||||
// gist 内容是当前 uinx 时间戳,在 10 分钟内视为有效
|
||||
ans := ctx.Event.Comment[strings.Index(ctx.Event.Comment, "答案:")+len("答案:"):]
|
||||
@@ -580,6 +582,72 @@ func init() { // 插件主体
|
||||
}
|
||||
}
|
||||
})
|
||||
// 设精
|
||||
engine.OnRegex(`^\[CQ:reply,id=(\d+)\].*(设置|取消)精华$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
essenceID, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||
option := ctx.State["regex_matched"].([]string)[2]
|
||||
var rsp zero.APIResponse
|
||||
switch option {
|
||||
case "设置":
|
||||
rsp = ctx.SetGroupEssenceMessage(essenceID)
|
||||
case "取消":
|
||||
rsp = ctx.DeleteGroupEssenceMessage(essenceID)
|
||||
}
|
||||
if rsp.RetCode == 0 {
|
||||
ctx.SendChain(message.Text(option, "成功"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(option, "失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
||||
}
|
||||
})
|
||||
engine.OnCommand("精华列表", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
list := ctx.GetGroupEssenceMessageList(ctx.Event.GroupID).Array()
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("本群精华列表:"))}
|
||||
n := len(list)
|
||||
if n > 30 {
|
||||
ctx.SendChain(message.Text("精华内容太多,仅显示前30个"))
|
||||
n = 30
|
||||
}
|
||||
for _, info := range list[:n] {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Text(fmt.Sprintf(
|
||||
"信息ID: %d\n发送者昵称: %s\n发送者QQ 号: %d\n消息发送时间: %s\n操作者昵称: %s\n操作者QQ 号: %d\n精华设置时间: %s",
|
||||
info.Get("message_id").Int(),
|
||||
info.Get("sender_nick").String(),
|
||||
info.Get("sender_id").Int(),
|
||||
time.Unix(info.Get("sender_time").Int(), 0).Format("2006/01/02 15:04:05"),
|
||||
info.Get("operator_nick").String(),
|
||||
info.Get("operator_id").Int(),
|
||||
time.Unix(info.Get("operator_time").Int(), 0).Format("2006/01/02 15:04:05"),
|
||||
))),
|
||||
)
|
||||
msgData := ctx.GetMessage(message.NewMessageIDFromInteger(info.Get("message_id").Int())).Elements
|
||||
if msgData != nil {
|
||||
msg = append(msg,
|
||||
message.CustomNode(info.Get("sender_nick").String(), info.Get("sender_id").Int(), msgData),
|
||||
)
|
||||
} else {
|
||||
msg = append(msg,
|
||||
message.CustomNode(info.Get("sender_nick").String(), info.Get("sender_id").Int(), "[error]信息久远,无法获取,如需查看原始内容请在“精华信息”中查看"),
|
||||
)
|
||||
}
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnPrefix("取消精华", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
essenceID, err := strconv.ParseInt(strings.TrimSpace(ctx.State["args"].(string)), 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的设精ID"))
|
||||
return
|
||||
}
|
||||
rsp := ctx.DeleteGroupEssenceMessage(essenceID)
|
||||
if rsp.RetCode == 0 {
|
||||
ctx.SendChain(message.Text("取消成功"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("取消失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 传入 ctx 和 welcome格式string 返回cq格式string 使用方法:welcometocq(ctx,w.Msg)
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/fumiama/cron"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
|
||||
@@ -14,15 +14,15 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/pkg/errors"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"gitlab.com/gomidi/midi/gm"
|
||||
"gitlab.com/gomidi/midi/v2"
|
||||
"gitlab.com/gomidi/midi/v2/smf"
|
||||
)
|
||||
@@ -30,11 +30,15 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("midicreate", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "midi音乐制作,该插件需要安装timidity,安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh\n" +
|
||||
"- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
||||
Brief: "midi音乐制作",
|
||||
Help: "- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
||||
"- 个人听音练习\n" +
|
||||
"- 团队听音练习\n" +
|
||||
"- *.mid (解析上传的mid文件)",
|
||||
"- *.mid (midi 转 txt)\n" +
|
||||
"- midi制作*.txt (txt 转 midi)\n" +
|
||||
"- 设置音色40 (0~127)\n" +
|
||||
"重要事项: 该插件依赖timidity\n" +
|
||||
"linux安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh\nwindows安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat?inline=false, windows需要管理员模式运行",
|
||||
PrivateDataFolder: "midicreate",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
@@ -48,13 +52,13 @@ func init() {
|
||||
uid := ctx.Event.UserID
|
||||
input := ctx.State["args"].(string)
|
||||
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err := str2music(input, midiFile)
|
||||
cmidiFile, err := str2music(ctx, input, midiFile)
|
||||
if err != nil {
|
||||
if file.IsExist(midiFile) {
|
||||
ctx.UploadThisGroupFile(file.BOTPATH+"/"+midiFile, filepath.Base(midiFile), "")
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("ERROR:无法转换midi文件,", err))
|
||||
ctx.SendChain(message.Text("ERROR: 无法转换midi文件,", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + cmidiFile))
|
||||
@@ -87,9 +91,9 @@ func init() {
|
||||
target := uint8(55 + rand.Intn(34))
|
||||
answer := name(target) + strconv.Itoa(int(target/12))
|
||||
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err := str2music(answer, midiFile)
|
||||
cmidiFile, err := str2music(ctx, answer, midiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
||||
ctx.SendChain(message.Text("ERROR: 听音练习结束, 无法转换midi文件, ", err))
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
@@ -137,7 +141,7 @@ func init() {
|
||||
),
|
||||
)
|
||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err = str2music(c.Event.Message.String(), midiFile)
|
||||
cmidiFile, err = str2music(ctx, c.Event.Message.String(), midiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
||||
return
|
||||
@@ -172,9 +176,9 @@ func init() {
|
||||
target = uint8(55 + rand.Intn(34))
|
||||
answer = name(target) + strconv.Itoa(int(target/12))
|
||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err = str2music(answer, midiFile)
|
||||
cmidiFile, err = str2music(ctx, answer, midiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:听音练习结束, 无法转换midi文件, ", err))
|
||||
ctx.SendChain(message.Text("ERROR: 听音练习结束, 无法转换midi文件, ", err))
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
@@ -193,7 +197,7 @@ func init() {
|
||||
)
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
midiFile = cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err = str2music(c.Event.Message.String(), midiFile)
|
||||
cmidiFile, err = str2music(ctx, c.Event.Message.String(), midiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: can't convert midi file,", err))
|
||||
return
|
||||
@@ -228,11 +232,57 @@ func init() {
|
||||
fileURL := ctx.GetThisGroupFileUrl(ctx.Event.File.BusID, ctx.Event.File.ID)
|
||||
data, err := web.GetData(fileURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
midStr := mid2txt(data)
|
||||
ctx.SendChain(message.Text("文件名:", ctx.Event.File.Name, "\n转化的midi字符:", midStr))
|
||||
s, err := smf.ReadFrom(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
for i := 0; i < int(s.NumTracks()); i++ {
|
||||
midStr := mid2txt(data, i)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
fileName := strings.ReplaceAll(cachePath+"/"+ctx.Event.File.Name, ".mid", fmt.Sprintf("-%d.txt", i))
|
||||
_ = os.WriteFile(fileName, binary.StringToBytes(midStr), 0666)
|
||||
ctx.UploadThisGroupFile(file.BOTPATH+"/"+fileName, filepath.Base(fileName), "")
|
||||
}
|
||||
})
|
||||
engine.On("notice/group_upload", func(ctx *zero.Ctx) bool {
|
||||
return path.Ext(ctx.Event.File.Name) == ".txt" && strings.Contains(ctx.Event.File.Name, "midi制作")
|
||||
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
fileURL := ctx.GetThisGroupFileUrl(ctx.Event.File.BusID, ctx.Event.File.ID)
|
||||
data, err := web.GetData(fileURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
uid := ctx.Event.UserID
|
||||
midiFile := cachePath + strconv.FormatInt(uid, 10) + time.Now().Format("20060102150405") + "_midicreate.mid"
|
||||
cmidiFile, err := str2music(ctx, binary.BytesToString(data), midiFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 无法转换midi文件,", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + cmidiFile))
|
||||
})
|
||||
engine.OnPrefix("设置音色").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
timbre, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
err = setTimbreMode(ctx, int64(timbre))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,8 +303,8 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func str2music(input, midiFile string) (cmidiFile string, err error) {
|
||||
err = mkMidi(midiFile, input)
|
||||
func str2music(ctx *zero.Ctx, input, midiFile string) (cmidiFile string, err error) {
|
||||
err = mkMidi(ctx, midiFile, input)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -264,7 +314,7 @@ func str2music(input, midiFile string) (cmidiFile string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func mkMidi(filePath, input string) error {
|
||||
func mkMidi(ctx *zero.Ctx, filePath, input string) error {
|
||||
if file.IsExist(filePath) {
|
||||
return nil
|
||||
}
|
||||
@@ -276,7 +326,8 @@ func mkMidi(filePath, input string) error {
|
||||
tr.Add(0, smf.MetaMeter(4, 4))
|
||||
tr.Add(0, smf.MetaTempo(72))
|
||||
tr.Add(0, smf.MetaInstrument("Violin"))
|
||||
tr.Add(0, midi.ProgramChange(0, gm.Instr_Violin.Value()))
|
||||
timbre := getTimbreMode(ctx)
|
||||
tr.Add(0, midi.ProgramChange(0, uint8(timbre)))
|
||||
|
||||
k := strings.ReplaceAll(input, " ", "")
|
||||
|
||||
@@ -410,46 +461,43 @@ func processOne(note string) uint8 {
|
||||
return o(base, level)
|
||||
}
|
||||
|
||||
func mid2txt(midBytes []byte) (midStr string) {
|
||||
func mid2txt(midBytes []byte, trackNo int) (midStr string) {
|
||||
var (
|
||||
absTicksStart float64
|
||||
absTicksEnd float64
|
||||
startNote byte
|
||||
endNote byte
|
||||
defaultMetric = 960.0
|
||||
defaultTrackNo = 0
|
||||
absTicksStart float64
|
||||
absTicksEnd float64
|
||||
startNote byte
|
||||
endNote byte
|
||||
defaultMetric = 960.0
|
||||
)
|
||||
_ = smf.ReadTracksFrom(bytes.NewReader(midBytes)).
|
||||
_ = smf.ReadTracksFrom(bytes.NewReader(midBytes), trackNo).
|
||||
Do(
|
||||
func(te smf.TrackEvent) {
|
||||
if !te.Message.IsMeta() && te.TrackNo == defaultTrackNo {
|
||||
if !te.Message.IsMeta() {
|
||||
b := te.Message.Bytes()
|
||||
if len(b) == 3 {
|
||||
if b[0] == 0x90 && b[2] > 0 {
|
||||
absTicksStart = float64(te.AbsTicks)
|
||||
startNote = b[1]
|
||||
}
|
||||
if b[0] == 0x80 || (b[0] == 0x90 && b[2] == 0x00) {
|
||||
absTicksEnd = float64(te.AbsTicks)
|
||||
endNote = b[1]
|
||||
if te.Message.Is(midi.NoteOnMsg) && b[2] > 0 {
|
||||
absTicksStart = float64(te.AbsTicks)
|
||||
startNote = b[1]
|
||||
}
|
||||
if te.Message.Is(midi.NoteOffMsg) || (te.Message.Is(midi.NoteOnMsg) && b[2] == 0x00) {
|
||||
absTicksEnd = float64(te.AbsTicks)
|
||||
endNote = b[1]
|
||||
if startNote == endNote {
|
||||
sign := name(b[1])
|
||||
level := b[1] / 12
|
||||
length := (absTicksEnd - absTicksStart) / defaultMetric
|
||||
midStr += sign
|
||||
if level != 5 {
|
||||
midStr += strconv.Itoa(int(level))
|
||||
}
|
||||
pow := int(math.Round(math.Log2(length)))
|
||||
if pow >= -4 && pow != 0 {
|
||||
midStr += "<" + strconv.Itoa(pow)
|
||||
}
|
||||
startNote = 0
|
||||
endNote = 0
|
||||
}
|
||||
}
|
||||
if (b[0] == 0x80 || (b[0] == 0x90 && b[2] == 0x00)) && startNote == endNote {
|
||||
sign := name(b[1])
|
||||
level := b[1] / 12
|
||||
length := (absTicksEnd - absTicksStart) / defaultMetric
|
||||
midStr += sign
|
||||
if level != 5 {
|
||||
midStr += strconv.Itoa(int(level))
|
||||
}
|
||||
pow := int(math.Round(math.Log2(length)))
|
||||
if pow >= -4 && pow != 0 {
|
||||
midStr += "<" + strconv.Itoa(pow)
|
||||
}
|
||||
startNote = 0
|
||||
endNote = 0
|
||||
}
|
||||
if (b[0] == 0x90 && b[2] > 0) && absTicksStart > absTicksEnd {
|
||||
if (te.Message.Is(midi.NoteOnMsg) && b[2] > 0) && absTicksStart > absTicksEnd {
|
||||
length := (absTicksStart - absTicksEnd) / defaultMetric
|
||||
pow := int(math.Round(math.Log2(length)))
|
||||
if pow == 0 {
|
||||
@@ -463,3 +511,31 @@ func mid2txt(midBytes []byte) (midStr string) {
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func setTimbreMode(ctx *zero.Ctx, timbre int64) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if timbre < 0 || timbre > 127 {
|
||||
return errors.New("音色应该在0~127之间")
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such plugin")
|
||||
}
|
||||
return m.SetData(gid, timbre)
|
||||
}
|
||||
|
||||
func getTimbreMode(ctx *zero.Ctx) (index int64) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
index := m.GetData(gid)
|
||||
return index
|
||||
}
|
||||
return 40
|
||||
}
|
||||
|
||||
54
plugin/moegoe/main.go
Normal file
54
plugin/moegoe/main.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Package moegoe 日韩中 VITS 模型拟声
|
||||
package moegoe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
)
|
||||
|
||||
const (
|
||||
jpapi = "https://moegoe.azurewebsites.net/api/speak?text=%s&id=%d"
|
||||
krapi = "https://moegoe.azurewebsites.net/api/speakkr?text=%s&id=%d"
|
||||
cnapi = "https://genshin.azurewebsites.net/api/speak?format=mp3&text=%s&id=%d"
|
||||
)
|
||||
|
||||
var speakers = map[string]uint{
|
||||
"宁宁": 0, "爱瑠": 1, "芳乃": 2, "茉子": 3, "丛雨": 4, "小春": 5, "七海": 6,
|
||||
"Sua": 0, "Mimiru": 1, "Arin": 2, "Yeonhwa": 3, "Yuhwa": 4, "Seonbae": 5,
|
||||
"派蒙": 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,
|
||||
}
|
||||
|
||||
func init() {
|
||||
en := control.Register("moegoe", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "日韩中 VITS 模型拟声",
|
||||
Help: "- 让[宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海]说(日语)\n" +
|
||||
"- 让[Sua|Mimiru|Arin|Yeonhwa|Yuhwa|Seonbae]说(韩语)\n" +
|
||||
"- 让[派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏]说(中文)",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
en.OnRegex("^让(宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海)说([A-Za-z\\s\\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(jpapi, url.QueryEscape(text), id)))
|
||||
})
|
||||
en.OnRegex("^让(Sua|Mimiru|Arin|Yeonhwa|Yuhwa|Seonbae)说([A-Za-z\\s\\d\u3131-\u3163\uac00-\ud7ff\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(krapi, url.QueryEscape(text), id)))
|
||||
})
|
||||
en.OnRegex("^让(派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(cnapi, url.QueryEscape(text), id)))
|
||||
})
|
||||
}
|
||||
@@ -31,23 +31,23 @@ func TestSetHoliday(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("清明节", 1, 2022, 4, 3)
|
||||
err = SetHoliday("清明节", 1, 2023, 4, 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("劳动节", 1, 2022, 4, 30)
|
||||
err = SetHoliday("劳动节", 1, 2023, 5, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("端午节", 1, 2022, 6, 3)
|
||||
err = SetHoliday("端午节", 1, 2023, 6, 22)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("中秋节", 1, 2022, 9, 10)
|
||||
err = SetHoliday("中秋节", 1, 2023, 9, 29)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("国庆节", 7, 2022, 10, 1)
|
||||
err = SetHoliday("国庆节", 7, 2023, 10, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ var (
|
||||
func init() { // 插件主体
|
||||
control.Register("moyu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "moyu\n" +
|
||||
"- /启用 moyu\n" +
|
||||
Brief: "摸鱼提醒",
|
||||
Help: "- /启用 moyu\n" +
|
||||
"- /禁用 moyu\n" +
|
||||
"- 记录在\"0 10 * * *\"触发的指令\n" +
|
||||
" - 摸鱼提醒",
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package moyucalendar
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
func init() {
|
||||
control.Register("moyucalendar", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "摸鱼人日历\n" +
|
||||
"- /启用 moyucalendar\n" +
|
||||
Brief: "摸鱼人日历",
|
||||
Help: "- /启用 moyucalendar\n" +
|
||||
"- /禁用 moyucalendar\n" +
|
||||
"- 记录在\"30 8 * * *\"触发的指令\n" +
|
||||
" - 摸鱼人日历",
|
||||
@@ -21,7 +21,7 @@ func init() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
data, err := web.GetData("https://api.vvhan.com/api/moyu")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
@@ -24,8 +24,8 @@ import (
|
||||
func init() {
|
||||
control.Register("music", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "点歌\n" +
|
||||
"- 点歌[xxx]\n" +
|
||||
Brief: "点歌",
|
||||
Help: "- 点歌[xxx]\n" +
|
||||
"- 网易点歌[xxx]\n" +
|
||||
"- 酷我点歌[xxx]\n" +
|
||||
"- 酷狗点歌[xxx]",
|
||||
@@ -138,10 +138,10 @@ func kugou(keyword string) message.MessageSegment {
|
||||
|
||||
// cloud163 返回网易云音乐卡片
|
||||
func cloud163(keyword string) (msg message.MessageSegment) {
|
||||
requestURL := "https://autumnfish.cn/search?keywords=" + url.QueryEscape(keyword)
|
||||
requestURL := "http://music.163.com/api/search/get/web?type=1&limit=1&s=" + url.QueryEscape(keyword)
|
||||
data, err := web.GetData(requestURL)
|
||||
if err != nil {
|
||||
msg = message.Text("ERROR:", err)
|
||||
msg = message.Text("ERROR: ", err)
|
||||
return
|
||||
}
|
||||
msg = message.Music("163", gjson.ParseBytes(data).Get("result.songs.0.id").Int())
|
||||
@@ -150,14 +150,13 @@ func cloud163(keyword string) (msg message.MessageSegment) {
|
||||
|
||||
// qqmusic 返回QQ音乐卡片
|
||||
func qqmusic(keyword string) (msg message.MessageSegment) {
|
||||
requestURL := "https://c.y.qq.com/soso/fcgi-bin/client_search_cp?w=" + url.QueryEscape(keyword)
|
||||
requestURL := "https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?platform=yqq.json&key=" + url.QueryEscape(keyword)
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), requestURL, "GET", "", web.RandUA())
|
||||
if err != nil {
|
||||
msg = message.Text("ERROR:", err)
|
||||
msg = message.Text("ERROR: ", err)
|
||||
return
|
||||
}
|
||||
info := gjson.ParseBytes(data[9 : len(data)-1]).Get("data.song.list.0")
|
||||
msg = message.Music("qq", info.Get("songid").Int())
|
||||
msg = message.Music("qq", gjson.ParseBytes(data).Get("data.song.itemlist.0.id").Int())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user