mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-06 15:20:22 +00:00
Compare commits
138 Commits
v1.6.1-bet
...
v1.7.1-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76dbf5a4b6 | ||
|
|
f1ea658c7d | ||
|
|
2964986ee5 | ||
|
|
52ef28cd6a | ||
|
|
df4c0438a2 | ||
|
|
864f92a728 | ||
|
|
6ea50cf8b7 | ||
|
|
d66dd9b7fa | ||
|
|
4a15326977 | ||
|
|
b4a1f93993 | ||
|
|
0c8dfb3f9c | ||
|
|
1aa11879dc | ||
|
|
14c596be1f | ||
|
|
309afecadd | ||
|
|
f465e78460 | ||
|
|
aa5c324592 | ||
|
|
1a0575af64 | ||
|
|
587d3967ef | ||
|
|
d693f988bb | ||
|
|
500dcaa9ed | ||
|
|
1376803b07 | ||
|
|
68386910c4 | ||
|
|
1734f1f7d4 | ||
|
|
86b87c2b4e | ||
|
|
e9eb4c5602 | ||
|
|
6474b36ccd | ||
|
|
107149892c | ||
|
|
f1dba97922 | ||
|
|
bc3c4303be | ||
|
|
f7a61ed0ee | ||
|
|
107b38e2f5 | ||
|
|
0d85fa04e1 | ||
|
|
1d8f5a7869 | ||
|
|
5e93368e57 | ||
|
|
56e931665e | ||
|
|
e5b2b369e3 | ||
|
|
58cf08fc39 | ||
|
|
c18f9b8b72 | ||
|
|
0df465e1c6 | ||
|
|
8b010321d5 | ||
|
|
e1591c44b6 | ||
|
|
cc26eb1332 | ||
|
|
366c7acb90 | ||
|
|
d8cb5206e8 | ||
|
|
90efebf02f | ||
|
|
960cd3ad8b | ||
|
|
09a3e807c9 | ||
|
|
fb2718b495 | ||
|
|
1550cb7fcc | ||
|
|
7b27bc8f7a | ||
|
|
54598fbf54 | ||
|
|
bb844eaa40 | ||
|
|
4ef6f584c9 | ||
|
|
861b3cc82f | ||
|
|
5226548cec | ||
|
|
d41ae01f01 | ||
|
|
e294059de4 | ||
|
|
84bc79eaa6 | ||
|
|
8f9a396821 | ||
|
|
6f96c389c4 | ||
|
|
c55e31ed6f | ||
|
|
f3a0813fed | ||
|
|
c1602c323d | ||
|
|
1bceaa52ff | ||
|
|
86296a28df | ||
|
|
fe9b5023f6 | ||
|
|
d68223f63d | ||
|
|
1c274d6eb8 | ||
|
|
0e52bbe0f7 | ||
|
|
a177448315 | ||
|
|
ca3ff1b522 | ||
|
|
41f0b11469 | ||
|
|
ba0e471a19 | ||
|
|
84115a7316 | ||
|
|
4dc837854b | ||
|
|
64f9e309ef | ||
|
|
67a1050df6 | ||
|
|
d85865825e | ||
|
|
2704d3e7d4 | ||
|
|
0944fc7854 | ||
|
|
611c275092 | ||
|
|
e3e991e6ab | ||
|
|
f2cebcf95a | ||
|
|
4aca16a393 | ||
|
|
891bbb96aa | ||
|
|
d60acd3a47 | ||
|
|
7dc6499127 | ||
|
|
f28e746652 | ||
|
|
3c905d9061 | ||
|
|
091d3170fc | ||
|
|
bdc4138d78 | ||
|
|
e231235ed1 | ||
|
|
1795b9196b | ||
|
|
d5d0563544 | ||
|
|
723b7a9857 | ||
|
|
6a0a16662e | ||
|
|
f82ba852ba | ||
|
|
180945670b | ||
|
|
56984ef7fb | ||
|
|
ac4de84188 | ||
|
|
591ad79201 | ||
|
|
2e51c9e9c3 | ||
|
|
ca89f01f7d | ||
|
|
5dfc118f64 | ||
|
|
2410a7b3ed | ||
|
|
7e11924b3f | ||
|
|
4f65900688 | ||
|
|
20821827b3 | ||
|
|
3dd10169e3 | ||
|
|
8cd60a84d5 | ||
|
|
03a2f4c331 | ||
|
|
cfc9b55fce | ||
|
|
fc99eb3e22 | ||
|
|
93625f9c4f | ||
|
|
b6ce9f7b2e | ||
|
|
20642b3776 | ||
|
|
16ab7c08f6 | ||
|
|
7bce7f28dc | ||
|
|
8c695c96d7 | ||
|
|
d4a057e21a | ||
|
|
f18c809355 | ||
|
|
0d9c8d9a43 | ||
|
|
76e7f81a6c | ||
|
|
faf00dfea7 | ||
|
|
39af90e63d | ||
|
|
36b09b8e94 | ||
|
|
7ec2b46d75 | ||
|
|
7cc5771a9a | ||
|
|
f96b5f8965 | ||
|
|
07e6f33b04 | ||
|
|
f1a33a1845 | ||
|
|
0a72566378 | ||
|
|
a029add486 | ||
|
|
778b8749ea | ||
|
|
7d5944fccf | ||
|
|
3e16a24ab5 | ||
|
|
ff682da3fe | ||
|
|
a0120485de |
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.19
|
||||
go-version: '1.20'
|
||||
- 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.19
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
|
||||
2
.github/workflows/push.yml
vendored
2
.github/workflows/push.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: 1.19
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.19'
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@master
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ go-zero*
|
||||
nohup.out
|
||||
zerobot
|
||||
ZeroBot-Plugin*
|
||||
*.syso
|
||||
|
||||
@@ -59,7 +59,7 @@ run:
|
||||
tests: false
|
||||
skip-dirs:
|
||||
- order
|
||||
go: '1.19'
|
||||
go: '1.20'
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
|
||||
@@ -4,6 +4,8 @@ env:
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
- go install github.com/tc-hib/go-winres@latest
|
||||
- go-winres make
|
||||
builds:
|
||||
- id: nowin
|
||||
env:
|
||||
|
||||
218
README.md
218
README.md
@@ -1,7 +1,6 @@
|
||||
<div align="center">
|
||||
<a href="https://crypko.ai/crypko/5k8HyUVTq5421/">
|
||||
<img src=".github/hua_nobg_512.gif" alt="椛" width = "400">
|
||||
</a><br>
|
||||
<br>
|
||||
|
||||
<h1>ZeroBot-Plugin</h1>
|
||||
|
||||
@@ -10,7 +9,7 @@
|
||||
ZeroBot-Plugin 是 ZeroBot 的 实用插件合集<br><br>
|
||||
|
||||
|
||||
<img src="http://cmoe.azurewebsites.net/cmoe?name=ZeroBot-Plugin&theme=r34" /><br>
|
||||
<img src="https://counter.seku.su/cmoe?name=ZeroBot-Plugin&theme=r34" /><br>
|
||||
|
||||
[](https://github.com/Mrs4s/MiraiGo)
|
||||
[](https://github.com/takayama-lily/oicq)
|
||||
@@ -18,7 +17,7 @@
|
||||
|
||||
[](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
|
||||
[](https://t.me/zerobotplugin)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
[](https://raw.githubusercontent.com/FloatTech/ZeroBot-Plugin/master/LICENSE)
|
||||
[](https://jq.qq.com/?_wv=1027&k=QMb7x1mM)
|
||||
[](https://t.me/zerobotplugin)
|
||||
@@ -38,21 +37,24 @@
|
||||
|
||||
> 如果您对开发插件感兴趣,欢迎加入[ZeroBot-Plugin-Playground](https://github.com/FloatTech/ZeroBot-Plugin-Playground)
|
||||
|
||||
> webui持续开发中, 欢迎加入[ZeroBot-Plugin-Webui](https://github.com/FloatTech/ZeroBot-Plugin-Webui)
|
||||
|
||||
## 命令行参数
|
||||
> `[]`代表是可选参数
|
||||
```bash
|
||||
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 ...] [&]
|
||||
zerobot [-h] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
```
|
||||
- **-h**: 显示帮助
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-t token**: 设置`AccessToken`,默认为空
|
||||
- **-u url**: 设置`Url`,默认为`ws://127.0.0.1:6700`
|
||||
- ~~**-g url**~~(默认禁用): 设置`webui url`,默认为`127.0.0.1:3000`
|
||||
- **-p prefix**: 设置命令前缀,默认为`/`
|
||||
- **-d|w**: 开启 debug | warning 级别及以上日志输出
|
||||
- **-c config.json**: 从`config.json`加载`bot`配置
|
||||
- **-s config.json**: 保存现在`bot`配置到`config.json`
|
||||
- **-l latency**: 全局处理延时 (ms)
|
||||
- **-r ringlen**: 接收消息环缓冲区大小
|
||||
- **-r ringlen**: 接收消息环缓冲区大小,`0`为不设缓冲,并发处理
|
||||
- **-x max process time**: 最大处理时间 (min)
|
||||
- **qqs**: superusers 的 qq 号
|
||||
- **&**: 驻留在后台,必须放在最后,仅`Linux`下有效
|
||||
@@ -86,8 +88,12 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.j
|
||||
|
||||
## 功能
|
||||
> 在编译时,以下功能除插件控制外,均可通过注释`main.go`中的相应`import`而物理禁用,减小插件体积。
|
||||
|
||||
> 通过插件控制,还可动态管理某个功能在某个群的打开/关闭。
|
||||
> 插件的优先级为`import`的先后顺序
|
||||
|
||||
> 插件的优先级为`import`的先后顺序。
|
||||
|
||||
> `webui`默认禁用不编译,打开后会增加程序体积。
|
||||
|
||||
<details>
|
||||
<summary>插件控制</summary>
|
||||
@@ -104,6 +110,10 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.j
|
||||
|
||||
- [x] /禁用 xxx (在发送的群/用户禁用xxx)
|
||||
|
||||
- [x] /此处启用所有插件
|
||||
|
||||
- [x] /此处禁用所有插件
|
||||
|
||||
- [x] /全局启用 xxx
|
||||
|
||||
- [x] /全局禁用 xxx
|
||||
@@ -126,9 +136,14 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.j
|
||||
|
||||
- [x] /服务列表
|
||||
|
||||
- [x] /设置服务列表显示行数 xx
|
||||
- [x] /设置服务列表显示行数 xx (默认值为 9, 该设置仅运行时有效, zbp 重启后重置)
|
||||
|
||||
- [x] (默认禁用) /设置webui用户名 zerobot 密码 123456
|
||||
|
||||
- [x] (默认禁用) /webui启动
|
||||
|
||||
- [x] (默认禁用) /webui停止
|
||||
|
||||
默认值为9,该设置仅运行时有效,zbp重启后重置
|
||||
- [x] @Bot 插件冲突检测 (会在本群发送一条消息并在约 1s 后撤回以检测其它同类 bot 中已启用的插件并禁用)
|
||||
|
||||
</details>
|
||||
@@ -421,11 +436,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度一下</summary>
|
||||
<summary>百度百科</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu"`
|
||||
|
||||
- [x] 百度下[xxx]
|
||||
- [x] 百度/百科[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -544,7 +559,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] b站推送列表
|
||||
|
||||
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 10s"触发的指令)
|
||||
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 5m"触发的指令)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -556,14 +571,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 随机书评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>打断复读</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat"`
|
||||
|
||||
- [x] (打断三次以上的复读)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>藏头诗</summary>
|
||||
@@ -616,6 +623,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 磕cp大老师 雪乃
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>今日早报</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews"`
|
||||
|
||||
- [x] 今日早报
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>DeepDanbooru二次元图标签识别</summary>
|
||||
@@ -636,6 +651,24 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 教你一篇小作文[作文]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>多功能抽签</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots"`
|
||||
|
||||
支持图包文件夹和gif抽签
|
||||
|
||||
- [x] (刷新)抽签列表
|
||||
|
||||
- [x] 抽[签名]签
|
||||
|
||||
- [x] 看签[gif签名]
|
||||
|
||||
- [x] 加签[签名][gif图片]
|
||||
|
||||
- [x] 删签[gif签名]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>女装</summary>
|
||||
@@ -686,7 +719,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/font"`
|
||||
|
||||
- [x] (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体])渲染文字xxx
|
||||
- [x] (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|粗苹方体|未来荧黑体|Gugi体|八丸体|Impact体|猫啃体|苹方体])渲染(抖动)文字xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>每日运势</summary>
|
||||
@@ -780,6 +814,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 来点黑丝/白丝/jk/巨乳/足控/网红
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一言</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/hitokoto"`
|
||||
|
||||
- [x] 一言[xxx]
|
||||
|
||||
- [x] 系列一言
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>炉石</summary>
|
||||
@@ -868,6 +912,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 喝奶茶绝绝子 | 绝绝子吃饭
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>疯狂星期四</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/kfccrazythursday"`
|
||||
|
||||
- [x] 疯狂星期四
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>kokomi原神面板</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/kokomi"`
|
||||
|
||||
- [x] kokomi菜单
|
||||
|
||||
- [x] XX面板
|
||||
|
||||
- 注:本插件未并入主仓库,需自行安装(须源码方式运行才能添加插件),安装地址[kokomi-原神面板查询插件](https://github.com/lianhong2758/kokomi-plugin)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>lolicon</summary>
|
||||
@@ -1032,6 +1096,12 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 小说[xxx]
|
||||
|
||||
- 设置小说配置 zerobot 123456
|
||||
|
||||
- 下载小说30298
|
||||
|
||||
- 注: 建议去https://www.23qb.com/ 注册一个账号, 小说下载有积分限制
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>nsfw图片识别</summary>
|
||||
@@ -1170,6 +1240,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 签到
|
||||
- [x] 获得签到背景[@xxx] | 获得签到背景
|
||||
- [x] 设置[默认]签到预设(1~9)
|
||||
- [x] 查看等级排名
|
||||
- 注:跨群排行
|
||||
- [x] 查看我的钱包
|
||||
@@ -1202,10 +1273,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 卖萌[@xxx]
|
||||
|
||||
- [x] 抽老婆[@xxx]
|
||||
- [x] 今日老婆[@xxx]
|
||||
|
||||
- [x] 黄油角色[@xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>steam</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/steam"`
|
||||
|
||||
- [x] steam[添加|删除]订阅xxxxx
|
||||
|
||||
- [x] steam查看订阅
|
||||
|
||||
- [x] steam绑定 api key xxxxxxx
|
||||
|
||||
- [x] 查看apikey
|
||||
|
||||
- [x] 拉取steam订阅 (使用job执行定时任务------记录在"@every 1m"触发的指令)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>抽塔罗牌</summary>
|
||||
@@ -1261,6 +1348,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新vtb
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vtb点歌</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic"`
|
||||
|
||||
- [x] vtb点歌
|
||||
|
||||
- [x] vtb随机点歌
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>钱包</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet"`
|
||||
|
||||
- [x] 查看我的钱包
|
||||
|
||||
- [x] 查看钱包排名
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>网易云音乐热评</summary>
|
||||
@@ -1269,6 +1376,23 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 来份网易云热评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>星际战甲</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi"`
|
||||
|
||||
- [x] wf时间同步
|
||||
|
||||
- [x] [金星|地球|火卫二]平原状态
|
||||
|
||||
- [x] .wm [物品名称]
|
||||
|
||||
- [x] 仲裁
|
||||
|
||||
- [x] 警报
|
||||
|
||||
- [x] 每日特惠
|
||||
</details>
|
||||
<details>
|
||||
<summary>天气/拼音查询-名言</summary>
|
||||
@@ -1329,19 +1453,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>月幕galgame图</summary>
|
||||
<summary>抽老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife"`
|
||||
|
||||
- [x] 随机galCG
|
||||
|
||||
- [x] 随机gal表情包
|
||||
|
||||
- [x] galCG[xxx]
|
||||
|
||||
- [x] gal表情包[xxx]
|
||||
|
||||
- [x] 更新gal
|
||||
- [x] 抽老婆
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1390,14 +1506,19 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>词典匹配回复</summary>
|
||||
<summary>月幕galgame图</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal"`
|
||||
|
||||
- [x] 切换[kimo|傲娇|可爱]词库
|
||||
- [x] 设置词库触发概率0.x (0<x<9)
|
||||
- [x] 随机galCG
|
||||
|
||||
- 注:由于占用资源较大,默认注释。
|
||||
- [x] 随机gal表情包
|
||||
|
||||
- [x] galCG[xxx]
|
||||
|
||||
- [x] gal表情包[xxx]
|
||||
|
||||
- [x] 更新gal
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1432,7 +1553,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] @Bot 任意文本(任意一句话回复)
|
||||
|
||||
- [x] 设置回复模式[青云客 | 小爱]
|
||||
- [x] 设置回复模式[青云客 | 小爱 | ChatGPT]
|
||||
|
||||
- [x] 设置 ChatGPT api key xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>词典匹配回复</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||
|
||||
- [x] 切换[kimo|傲娇|可爱]词库
|
||||
- [x] 设置词库触发概率0.x (0<x<9)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>打断复读</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat"`
|
||||
|
||||
- [x] (打断三次以上的复读)
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
14
console/console_ansi.go
Normal file
14
console/console_ansi.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build !windows
|
||||
|
||||
// Package console sets console's behavior on init
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fmt.Print("\033]0;ZeroBot-Blugin " + banner.Version + " " + banner.Copyright + "\007")
|
||||
}
|
||||
144
console/console_windows.go
Normal file
144
console/console_windows.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Package console sets console's behavior on init
|
||||
package console
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:linkname modkernel32 golang.org/x/sys/windows.modkernel32
|
||||
modkernel32 *windows.LazyDLL
|
||||
procSetConsoleTitle = modkernel32.NewProc("SetConsoleTitleW")
|
||||
)
|
||||
|
||||
//go:linkname errnoErr golang.org/x/sys/windows.errnoErr
|
||||
func errnoErr(e syscall.Errno) error
|
||||
|
||||
func setConsoleTitle(title string) (err error) {
|
||||
var p0 *uint16
|
||||
p0, err = syscall.UTF16PtrFromString(title)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall(procSetConsoleTitle.Addr(), 1, uintptr(unsafe.Pointer(p0)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
stdin := windows.Handle(os.Stdin.Fd())
|
||||
|
||||
var mode uint32
|
||||
err := windows.GetConsoleMode(stdin, &mode)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式
|
||||
mode |= windows.ENABLE_EXTENDED_FLAGS // 启用扩展标志
|
||||
|
||||
mode &^= windows.ENABLE_MOUSE_INPUT // 禁用鼠标输入
|
||||
mode |= windows.ENABLE_PROCESSED_INPUT // 启用控制输入
|
||||
|
||||
mode &^= windows.ENABLE_INSERT_MODE // 禁用插入模式
|
||||
mode |= windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT // 启用输入回显&逐行输入
|
||||
|
||||
mode &^= windows.ENABLE_WINDOW_INPUT // 禁用窗口输入
|
||||
mode &^= windows.ENABLE_VIRTUAL_TERMINAL_INPUT // 禁用虚拟终端输入
|
||||
|
||||
err = windows.SetConsoleMode(stdin, mode)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stdout := windows.Handle(os.Stdout.Fd())
|
||||
err = windows.GetConsoleMode(stdout, &mode)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING // 启用虚拟终端处理
|
||||
mode |= windows.ENABLE_PROCESSED_OUTPUT // 启用处理后的输出
|
||||
|
||||
err = windows.SetConsoleMode(stdout, mode)
|
||||
// windows 带颜色 log 自定义格式
|
||||
logrus.SetFormatter(&logFormat{hasColor: err == nil})
|
||||
if err != nil {
|
||||
logrus.Warnln("VT100设置失败, 将以无色模式输出")
|
||||
}
|
||||
|
||||
err = setConsoleTitle("ZeroBot-Blugin " + banner.Version + " " + banner.Copyright)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
colorCodePanic = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
|
||||
colorCodeFatal = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
|
||||
colorCodeError = "\x1b[31m" // color.Style{color.Red}.String()
|
||||
colorCodeWarn = "\x1b[33m" // color.Style{color.Yellow}.String()
|
||||
colorCodeInfo = "\x1b[37m" // color.Style{color.White}.String()
|
||||
colorCodeDebug = "\x1b[32m" // color.Style{color.Green}.String()
|
||||
colorCodeTrace = "\x1b[36m" // color.Style{color.Cyan}.String()
|
||||
colorReset = "\x1b[0m"
|
||||
)
|
||||
|
||||
// logFormat specialize for zbp
|
||||
type logFormat struct {
|
||||
hasColor bool
|
||||
}
|
||||
|
||||
// Format implements logrus.Formatter
|
||||
func (f logFormat) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
buf.WriteByte('[')
|
||||
if f.hasColor {
|
||||
buf.WriteString(getLogLevelColorCode(entry.Level))
|
||||
}
|
||||
buf.WriteString(strings.ToUpper(entry.Level.String()))
|
||||
if f.hasColor {
|
||||
buf.WriteString(colorReset)
|
||||
}
|
||||
buf.WriteString("] ")
|
||||
buf.WriteString(entry.Message)
|
||||
buf.WriteString(" \n")
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// getLogLevelColorCode 获取日志等级对应色彩code
|
||||
func getLogLevelColorCode(level logrus.Level) string {
|
||||
switch level {
|
||||
case logrus.PanicLevel:
|
||||
return colorCodePanic
|
||||
case logrus.FatalLevel:
|
||||
return colorCodeFatal
|
||||
case logrus.ErrorLevel:
|
||||
return colorCodeError
|
||||
case logrus.WarnLevel:
|
||||
return colorCodeWarn
|
||||
case logrus.InfoLevel:
|
||||
return colorCodeInfo
|
||||
case logrus.DebugLevel:
|
||||
return colorCodeDebug
|
||||
case logrus.TraceLevel:
|
||||
return colorCodeTrace
|
||||
|
||||
default:
|
||||
return colorCodeInfo
|
||||
}
|
||||
}
|
||||
2
data
2
data
Submodule data updated: 00088d0e74...541c1dec93
51
go.mod
51
go.mod
@@ -1,47 +1,53 @@
|
||||
module github.com/FloatTech/ZeroBot-Plugin
|
||||
|
||||
go 1.19
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/Coloured-glaze/gg v1.3.4
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230111055153-4d8aebd3eab9
|
||||
github.com/FloatTech/floatbox v0.0.0-20230111053652-a03d6334fadf
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944
|
||||
github.com/FloatTech/gg v1.1.2
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9
|
||||
github.com/FloatTech/sqlite v1.5.7
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230109124217-41203036b80a
|
||||
github.com/FloatTech/zbputils v1.6.1
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230331074541-89a5b4840e92
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/fumiama/ahsai v0.1.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
github.com/fumiama/go-base16384 v1.6.4
|
||||
github.com/fumiama/go-registry v0.2.5
|
||||
github.com/fumiama/go-registry v0.2.6
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/imgsz v0.0.2
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
||||
github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430
|
||||
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.31.1
|
||||
github.com/lithammer/fuzzysearch v1.1.5
|
||||
github.com/mroth/weightedrand v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/shirou/gopsutil/v3 v3.22.11
|
||||
github.com/quic-go/quic-go v0.32.0
|
||||
github.com/shirou/gopsutil/v3 v3.23.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.7
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25
|
||||
golang.org/x/image v0.3.0
|
||||
golang.org/x/sys v0.4.0
|
||||
golang.org/x/text v0.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/FloatTech/rendercard v0.0.3 // indirect
|
||||
github.com/antchfx/xpath v1.2.1 // 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/fumiama/go-simple-protobuf v0.1.0 // indirect
|
||||
@@ -59,29 +65,30 @@ require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pkumza/numcn v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9 // indirect
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
modernc.org/libc v1.21.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
|
||||
92
go.sum
92
go.sum
@@ -1,23 +1,25 @@
|
||||
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.6.1-0.20230111055153-4d8aebd3eab9 h1:TOd10BBqoHPwbOmULK4a6imdaljkOxKIZFyFKbQqTEA=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230111055153-4d8aebd3eab9/go.mod h1:aOU5EVMvflX5Btv0jGLgB6gcSYeR/FNiR2cJG07vd4U=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230111053652-a03d6334fadf h1:aVmgzw9hJA39/2iR800qq1dU682LpW9/czIkoshDzKw=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230111053652-a03d6334fadf/go.mod h1:0+3iDgifrdiEoEsmYe+yiAlUQcmnudhTiiBdSkam2XY=
|
||||
github.com/FloatTech/rendercard v0.0.3 h1:eKOKlmotlDq/YbAcJKe0GMzBjGTsT5eSsyEfjT+hy10=
|
||||
github.com/FloatTech/rendercard v0.0.3/go.mod h1:FwwKoWpv1fW7AZ1mwBVWF8GCH9mEqYYIE9LzdmozCZQ=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e h1:4V7UZyLZKmjXUDtmYFK5+EWIrrkSuN+jHjKXkWsqQ/A=
|
||||
github.com/FloatTech/AnimeAPI v1.6.1-0.20230331074616-e33f890df71e/go.mod h1:LSJN8VkJXBhyAdOolVNeUptJz6l1TZ+/CfXN1OafyEY=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944 h1:/eQoMa6Aj3coF5F7yhzZe1+SzX6SItul7MW8//pl18o=
|
||||
github.com/FloatTech/floatbox v0.0.0-20230331064925-9af336a84944/go.mod h1:FwQm6wk+b4wuW54KCKn3zccMX47Q5apnHD/Yakzv0fI=
|
||||
github.com/FloatTech/gg v1.1.2 h1:YolgOYg3uDHc1+g0bLtt6QuRA/pvLn+b9IBCIhOOX88=
|
||||
github.com/FloatTech/gg v1.1.2/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI=
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b h1:VMNci4SWBySdw/6poqF9Dn9zlT5ntTFSJOEEBjRnJ/4=
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230322091809-b0ddbe44b94b/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 h1:hffajvmQFfP68U6wUwHemPuuwCUoss+SEFfoLYwbGwE=
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9/go.mod h1:NBFPhWae4hqVMeG8ELBBnUQkKce3nDjkljVn6PdiUNs=
|
||||
github.com/FloatTech/sqlite v1.5.7 h1:Bvo4LSojcZ6dVtbHrkqvt6z4v8e+sj0G5PSUIvdawsk=
|
||||
github.com/FloatTech/sqlite v1.5.7/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230109124217-41203036b80a h1:O+GS8J1pEM4E8q05EcopHBK6kfIr0BJJ/cHuPa8yWLM=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230109124217-41203036b80a/go.mod h1:UT3bZNKMF/+r2XzSvIVXWudnTgmWsQrRPOJ3bmBfjFI=
|
||||
github.com/FloatTech/zbputils v1.6.1 h1:VcufWTkZl8ny4aB6leJ+CE4TS6OdA4i4zeKgYQdx97c=
|
||||
github.com/FloatTech/zbputils v1.6.1/go.mod h1:IrPicT+CKYW2ZwPlG//DSNG7bHAQAII2mNyETnRQDG4=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3 h1:mCVrTvS2LMNaI2bNA1Gu/B4F5MnfGaTaJClgR6+rhdA=
|
||||
github.com/FloatTech/zbpctrl v1.5.3-0.20230316111343-dd078fa43fe3/go.mod h1:IagyEhY38VcbbQgVRzAM9f9mhaUn90rM5BTPfudtl1g=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230331074541-89a5b4840e92 h1:yp2hYvK+FaaozRG9+KPgoknbdvp5ZbrNHOjMfES0lEM=
|
||||
github.com/FloatTech/zbputils v1.6.2-0.20230331074541-89a5b4840e92/go.mod h1:3bpENp0t2puKC4Kwp+ksEcMPkuw/8pWI4G6/+/e3jCA=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||
@@ -38,6 +40,8 @@ github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozb
|
||||
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=
|
||||
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3 h1:qshMBFxVjYjzI+kwvWvgoByF3uMCvnJiaK8KslWAbr8=
|
||||
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3/go.mod h1:M9fx6rAdHSYLKxXPgUXGgblb586CA7ceNrpu4DEc2No=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
@@ -56,14 +60,16 @@ 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.6.4 h1:rYDRwD/th2cG4U7QLokpzmST1cCxZGXtHmolOUePt5o=
|
||||
github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.2.5 h1:Y6tnHnTThQPv7E4JPM2vBprU+4EQw/LEDO33HCmxgI4=
|
||||
github.com/fumiama/go-registry v0.2.5/go.mod h1:GP45kejHuDLFxcWdksrt75r5rHBqYwtfeUl3JzGWxfQ=
|
||||
github.com/fumiama/go-registry v0.2.6 h1:+vEeBUwa1+GC87ujW3Km42fi8O/H7QcpVJWu1iuGNh0=
|
||||
github.com/fumiama/go-registry v0.2.6/go.mod h1:HjYagPZXzR2xCCxaSQerqX7JRzC0yiv2kslDdBiTq/g=
|
||||
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/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
|
||||
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ=
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
||||
github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=
|
||||
@@ -120,23 +126,20 @@ 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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
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.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
|
||||
github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
|
||||
github.com/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMrOBEp1c=
|
||||
github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q=
|
||||
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/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
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=
|
||||
@@ -151,6 +154,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -161,10 +166,20 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
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/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U=
|
||||
github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
||||
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/shirou/gopsutil/v3 v3.22.11 h1:kxsPKS+Eeo+VnEQ2XCaGJepeP6KY53QoRTETx3+1ndM=
|
||||
github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0XdevQOe5MZ1oY=
|
||||
github.com/shirou/gopsutil/v3 v3.23.1 h1:a9KKO+kGLKEvcPIs4W62v0nu3sciVDOOOPUD0Hz7z/4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.1/go.mod h1:NN6mnm5/0k8jw4cBfCnJtr5L7ErOTg18tMNpgFkn0hA=
|
||||
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=
|
||||
@@ -188,8 +203,8 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.7 h1:JK29W0j9k82X4FdGcbgqP5IFikUYMaUysUOIALGfQrw=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.7/go.mod h1:T5kD5vLi/YxL/fyDOCOaawi96LRBdJjcXh2CIjDyFfg=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11 h1:44Wr6CsCtWlFensK5IhuVCWkosdRw0rA8SygVD8DgoI=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.11/go.mod h1:y29UIOy0RD3P+0meDNIWRhcJF3jtWPN9xP9hgt/AJAU=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
@@ -201,12 +216,13 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
|
||||
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-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
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 v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9 h1:tLxpBz7qD8qFkRDC159unetNbxKp4zeqsqw2rLwvdxc=
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
@@ -224,8 +240,9 @@ 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -237,8 +254,8 @@ golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b h1:tvrvnPFcdzp294diPnrdZZZ8XUt2Tyj7svb7X52iDuU=
|
||||
golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -259,8 +276,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -273,15 +291,17 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package kanban
|
||||
|
||||
// Version ...
|
||||
var Version = "v1.6.1-beta5"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - 2023-01-11 14:46:24 +0800 CST\n" +
|
||||
"* Copyright © 2020 - 2023 FloatTech. All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
15
kanban/banner/banner.go
Normal file
15
kanban/banner/banner.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Code generated by kanban/gen. DO NOT EDIT.
|
||||
|
||||
package banner
|
||||
|
||||
// Version ...
|
||||
var Version = "v1.7.1-beta1"
|
||||
|
||||
// Copyright ...
|
||||
var Copyright = "© 2020 - 2023 FloatTech"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - 2023-03-31 15:53:05 +0800 CST\n" +
|
||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
@@ -10,22 +10,27 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const banner = `package kanban
|
||||
const banner = `// Code generated by kanban/gen. DO NOT EDIT.
|
||||
|
||||
package banner
|
||||
|
||||
// Version ...
|
||||
var Version = "%s"
|
||||
|
||||
// Copyright ...
|
||||
var Copyright = "© 2020 - %d FloatTech"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - %s\n" +
|
||||
"* Copyright © 2020 - %d FloatTech. All Rights Reserved.\n" +
|
||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
`
|
||||
|
||||
const timeformat = `2006-01-02 15:04:05 +0800 CST`
|
||||
|
||||
func main() {
|
||||
f, err := os.Create("banner.go")
|
||||
f, err := os.Create("banner/banner.go")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -39,7 +44,7 @@ func main() {
|
||||
}
|
||||
s := strings.Split(vartag.String(), "\n")
|
||||
now := time.Now()
|
||||
_, err = fmt.Fprintf(f, banner, s[len(s)-2], now.Format(timeformat), now.Year())
|
||||
_, err = fmt.Fprintf(f, banner, s[len(s)-2], now.Year(), now.Format(timeformat))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -3,18 +3,17 @@ package kanban
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/fumiama/go-registry"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/kanban/gen
|
||||
|
||||
var once sync.Once
|
||||
|
||||
func init() {
|
||||
once.Do(PrintBanner)
|
||||
PrintBanner()
|
||||
}
|
||||
|
||||
var reg = registry.NewRegReader("reilia.fumiama.top:32664", control.Md5File, "fumiama")
|
||||
@@ -23,7 +22,7 @@ var reg = registry.NewRegReader("reilia.fumiama.top:32664", control.Md5File, "fu
|
||||
func PrintBanner() {
|
||||
fmt.Print(
|
||||
"\n======================[ZeroBot-Plugin]======================",
|
||||
"\n", Banner, "\n",
|
||||
"\n", banner.Banner, "\n",
|
||||
"----------------------[ZeroBot-公告栏]----------------------",
|
||||
"\n", Kanban(), "\n",
|
||||
"============================================================\n\n",
|
||||
|
||||
210
main.go
210
main.go
@@ -7,10 +7,14 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 在最前打印 banner
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
|
||||
|
||||
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
|
||||
// ----------------------插件优先级按顺序从高到低---------------------- //
|
||||
@@ -56,90 +60,96 @@ import (
|
||||
// vvvvvvvvvvvvvv //
|
||||
// vvvv //
|
||||
|
||||
_ "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/autowithdraw" // 触发者撤回时也自动撤回
|
||||
_ "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/dress" // 女装
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
||||
_ "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/quan" // QQ权重查询
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
|
||||
_ "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/wallet" // 钱包
|
||||
_ "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/ygo" // 游戏王相关插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
_ "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/autowithdraw" // 触发者撤回时也自动撤回
|
||||
_ "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/dailynews" // 今日早报
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress" // 女装
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
||||
_ "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/hitokoto" // 一言
|
||||
_ "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/jptingroom" // 日语听力学习材料
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/kfccrazythursday" // 疯狂星期四
|
||||
_ "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/quan" // QQ权重查询
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
|
||||
_ "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/steam" // steam相关
|
||||
_ "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/vtbmusic" // vtb点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf" // 鬼东西
|
||||
|
||||
// ^^^^ //
|
||||
@@ -164,6 +174,8 @@ import (
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_reply" // 人工智能回复
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat" // 打断复读
|
||||
|
||||
// ^^^^ //
|
||||
@@ -183,6 +195,10 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/driver"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// webctrl "github.com/FloatTech/zbputils/control/web"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
// -----------------------以上为内置依赖,勿动------------------------ //
|
||||
)
|
||||
|
||||
@@ -200,6 +216,7 @@ func init() {
|
||||
d := flag.Bool("d", false, "Enable debug level log and higher.")
|
||||
w := flag.Bool("w", false, "Enable warning level log and higher.")
|
||||
h := flag.Bool("h", false, "Display this help.")
|
||||
// g := flag.String("g", "127.0.0.1:3000", "Set webui url.")
|
||||
// 直接写死 AccessToken 时,请更改下面第二个参数
|
||||
token := flag.String("t", "", "Set AccessToken of WSClient.")
|
||||
// 直接写死 URL 时,请更改下面第二个参数
|
||||
@@ -219,13 +236,12 @@ func init() {
|
||||
fmt.Println("Usage:")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
} else {
|
||||
if *d && !*w {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
if *w {
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
}
|
||||
if *d && !*w {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
if *w {
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
|
||||
for _, s := range flag.Args() {
|
||||
@@ -261,7 +277,6 @@ func init() {
|
||||
logrus.Infoln("[main] 从", *runcfg, "读取配置文件")
|
||||
return
|
||||
}
|
||||
|
||||
config.W = []*driver.WSClient{driver.NewWebSocketClient(*url, *token)}
|
||||
config.Z = zero.Config{
|
||||
NickName: append([]string{*adana}, "ATRI", "atri", "亚托莉", "アトリ"),
|
||||
@@ -286,18 +301,23 @@ func init() {
|
||||
logrus.Infoln("[main] 配置文件已保存到", *save)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 启用 webui
|
||||
// go webctrl.RunGui(*g)
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano()) // 全局 seed,其他插件无需再 seed
|
||||
if !strings.Contains(runtime.Version(), "go1.2") { // go1.20之前版本需要全局 seed,其他插件无需再 seed
|
||||
rand.Seed(time.Now().UnixNano()) //nolint: staticcheck
|
||||
}
|
||||
// 帮助
|
||||
zero.OnFullMatchGroup([]string{"/help", ".help", "菜单"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(kanban.Banner, "\n可发送\"/服务列表\"查看 bot 功能"))
|
||||
ctx.SendChain(message.Text(banner.Banner, "\n管理发送\"/服务列表\"查看 bot 功能\n发送\"/用法name\"查看功能用法"))
|
||||
})
|
||||
zero.OnFullMatch("查看zbp公告", zero.OnlyToMe, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(kanban.Kanban()))
|
||||
ctx.SendChain(message.Text(strings.ReplaceAll(kanban.Kanban(), "\t", "")))
|
||||
})
|
||||
zero.RunAndBlock(&config.Z, process.GlobalInitMutex.Unlock)
|
||||
}
|
||||
|
||||
70
main_win.go
70
main_win.go
@@ -1,70 +0,0 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// windows 带颜色 log 自定义格式
|
||||
logrus.SetFormatter(&LogFormat{})
|
||||
}
|
||||
|
||||
const (
|
||||
colorCodePanic = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
|
||||
colorCodeFatal = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
|
||||
colorCodeError = "\x1b[31m" // color.Style{color.Red}.String()
|
||||
colorCodeWarn = "\x1b[33m" // color.Style{color.Yellow}.String()
|
||||
colorCodeInfo = "\x1b[37m" // color.Style{color.White}.String()
|
||||
colorCodeDebug = "\x1b[32m" // color.Style{color.Green}.String()
|
||||
colorCodeTrace = "\x1b[36m" // color.Style{color.Cyan}.String()
|
||||
colorReset = "\x1b[0m"
|
||||
)
|
||||
|
||||
// LogFormat specialize for zbp
|
||||
type LogFormat struct{}
|
||||
|
||||
// Format implements logrus.Formatter
|
||||
func (f LogFormat) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
buf.WriteString(getLogLevelColorCode(entry.Level))
|
||||
|
||||
buf.WriteByte('[')
|
||||
buf.WriteString(strings.ToUpper(entry.Level.String()))
|
||||
buf.WriteString("] ")
|
||||
buf.WriteString(entry.Message)
|
||||
buf.WriteString(" \n")
|
||||
|
||||
buf.WriteString(colorReset)
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// getLogLevelColorCode 获取日志等级对应色彩code
|
||||
func getLogLevelColorCode(level logrus.Level) string {
|
||||
switch level {
|
||||
case logrus.PanicLevel:
|
||||
return colorCodePanic
|
||||
case logrus.FatalLevel:
|
||||
return colorCodeFatal
|
||||
case logrus.ErrorLevel:
|
||||
return colorCodeError
|
||||
case logrus.WarnLevel:
|
||||
return colorCodeWarn
|
||||
case logrus.InfoLevel:
|
||||
return colorCodeInfo
|
||||
case logrus.DebugLevel:
|
||||
return colorCodeDebug
|
||||
case logrus.TraceLevel:
|
||||
return colorCodeTrace
|
||||
|
||||
default:
|
||||
return colorCodeInfo
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func init() {
|
||||
engine := control.Register("ahsai", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "フリーテキスト音声合成",
|
||||
Help: "- 使[伊織弓鶴|紲星あかり|結月ゆかり|京町セイカ|東北きりたん|東北イタコ|ついなちゃん標準語|ついなちゃん関西弁|音街ウナ|琴葉茜|吉田くん|民安ともえ|桜乃そら|月読アイ|琴葉葵|東北ずん子|月読ショウタ|水奈瀬コウ]说(日语)\n",
|
||||
Help: "- 使[伊織弓鶴|紲星あかり|結月ゆかり|京町セイカ|東北きりたん|東北イタコ|ついなちゃん標準語|ついなちゃん関西弁|音街ウナ|琴葉茜|吉田くん|民安ともえ|桜乃そら|月読アイ|琴葉葵|東北ずん子|月読ショウタ|水奈瀬コウ]说(日语)",
|
||||
PrivateDataFolder: "ahsai",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
|
||||
@@ -2,23 +2,54 @@
|
||||
package aifalse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"math"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/rendercard"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
backgroundURL = "https://iw233.cn/api.php?sort=mp"
|
||||
referer = "https://weibo.com/"
|
||||
)
|
||||
|
||||
var (
|
||||
boottime = time.Now()
|
||||
bgdata *[]byte
|
||||
bgcount uintptr
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("aifalse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
@@ -39,12 +70,19 @@ func init() { // 插件主体
|
||||
}
|
||||
engine.OnFullMatchGroup([]string{"检查身体", "自检", "启动自检", "系统状态"}, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(
|
||||
"* CPU占用: ", cpuPercent(), "%\n",
|
||||
"* RAM占用: ", memPercent(), "%\n",
|
||||
"* 硬盘使用: ", diskPercent(),
|
||||
),
|
||||
)
|
||||
img, err := drawstatus(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.Event.SelfID, zero.BotConfig.NickName[0])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendimg, err := imgfactory.ToBytes(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.ImageBytes(sendimg)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^设置默认限速为每\s*(\d+)\s*(分钟|秒)\s*(\d+)\s*次触发$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -84,38 +122,493 @@ func init() { // 插件主体
|
||||
})
|
||||
}
|
||||
|
||||
func cpuPercent() float64 {
|
||||
func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg image.Image, err error) {
|
||||
diskstate, err := diskstate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
diskcardh := 40 + (20+50)*len(diskstate) + 40 - 20
|
||||
|
||||
moreinfo, err := moreinfo(m)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
moreinfocardh := 30 + (20+32*72/96)*len(moreinfo) + 30 - 20
|
||||
|
||||
basicstate, err := basicstate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dldata := (*[]byte)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&bgdata))))
|
||||
if dldata == (*[]byte)(nil) || uintptr(time.Since(boottime).Hours()/24) >= atomic.LoadUintptr(&bgcount) {
|
||||
url, err1 := bilibili.GetRealURL(backgroundURL)
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
data, err1 := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
atomic.AddUintptr(&bgcount, 1)
|
||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&bgdata)), unsafe.Pointer(&data))
|
||||
dldata = &data
|
||||
}
|
||||
data := *dldata
|
||||
|
||||
back, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
avatar, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 200, 200)
|
||||
|
||||
fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
canvas := gg.NewContext(1280, 70+250+40+380+diskcardh+40+moreinfocardh+40+70)
|
||||
|
||||
bh, bw, ch, cw := float64(back.Bounds().Dy()), float64(back.Bounds().Dx()), float64(canvas.H()), float64(canvas.W())
|
||||
|
||||
if bh/bw < ch/cw {
|
||||
back = imgfactory.Size(back, int(bw*ch/bh), int(bh*ch/bh)).Image()
|
||||
canvas.DrawImageAnchored(back, canvas.W()/2, canvas.H()/2, 0.5, 0.5)
|
||||
} else {
|
||||
back = imgfactory.Size(back, int(bw*cw/bw), int(bh*cw/bw)).Image()
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
var blurback image.Image
|
||||
bwg := &sync.WaitGroup{}
|
||||
bwg.Add(1)
|
||||
go func() {
|
||||
defer bwg.Done()
|
||||
blurback = imaging.Blur(canvas.Image(), 8)
|
||||
}()
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(5)
|
||||
|
||||
cardw := canvas.W() - 70 - 70
|
||||
|
||||
titlecardh := 250
|
||||
basiccardh := 380
|
||||
|
||||
var titleimg, basicimg, diskimg, moreinfoimg, shadowimg image.Image
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
titlecard := gg.NewContext(cardw, titlecardh)
|
||||
bwg.Wait()
|
||||
titlecard.DrawImage(blurback, -70, -70)
|
||||
|
||||
titlecard.DrawRoundedRectangle(1, 1, float64(titlecard.W()-1*2), float64(titlecardh-1*2), 16)
|
||||
titlecard.SetLineWidth(3)
|
||||
titlecard.SetRGBA255(255, 255, 255, 100)
|
||||
titlecard.StrokePreserve()
|
||||
titlecard.SetRGBA255(255, 255, 255, 140)
|
||||
titlecard.Fill()
|
||||
|
||||
titlecard.DrawImage(avatarf.Circle(0).Image(), (titlecardh-avatarf.H())/2, (titlecardh-avatarf.H())/2)
|
||||
|
||||
err = titlecard.ParseFontFace(fontbyte, 72)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fw, _ := titlecard.MeasureString(botname)
|
||||
|
||||
titlecard.SetRGBA255(30, 30, 30, 255)
|
||||
|
||||
titlecard.DrawStringAnchored(botname, float64(titlecardh)+fw/2, float64(titlecardh)*0.5/2, 0.5, 0.5)
|
||||
|
||||
err = titlecard.ParseFontFace(fontbyte, 24)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
titlecard.SetRGBA255(30, 30, 30, 180)
|
||||
|
||||
titlecard.NewSubPath()
|
||||
titlecard.MoveTo(float64(titlecardh), float64(titlecardh)/2)
|
||||
titlecard.LineTo(float64(titlecard.W()-titlecardh), float64(titlecardh)/2)
|
||||
titlecard.Stroke()
|
||||
|
||||
brt, err := botruntime()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fw, _ = titlecard.MeasureString(brt)
|
||||
|
||||
titlecard.DrawStringAnchored(brt, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.25/2), 0.5, 0.5)
|
||||
|
||||
bs, err := botstatus()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fw, _ = titlecard.MeasureString(bs)
|
||||
|
||||
titlecard.DrawStringAnchored(bs, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.5/2), 0.5, 0.5)
|
||||
titleimg = rendercard.Fillet(titlecard.Image(), 16)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
basiccard := gg.NewContext(cardw, basiccardh)
|
||||
bwg.Wait()
|
||||
basiccard.DrawImage(blurback, -70, -70-titlecardh-40)
|
||||
|
||||
basiccard.DrawRoundedRectangle(1, 1, float64(basiccard.W()-1*2), float64(basiccardh-1*2), 16)
|
||||
basiccard.SetLineWidth(3)
|
||||
basiccard.SetRGBA255(255, 255, 255, 100)
|
||||
basiccard.StrokePreserve()
|
||||
basiccard.SetRGBA255(255, 255, 255, 140)
|
||||
basiccard.Fill()
|
||||
|
||||
bslen := len(basicstate)
|
||||
for i, v := range basicstate {
|
||||
offset := float64(i) * ((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1) + 200)
|
||||
|
||||
basiccard.SetRGBA255(235, 235, 235, 255)
|
||||
basiccard.DrawCircle((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 100)
|
||||
basiccard.Fill()
|
||||
|
||||
switch {
|
||||
case v.precent > 90:
|
||||
basiccard.SetRGBA255(255, 70, 0, 255)
|
||||
case v.precent > 70:
|
||||
basiccard.SetRGBA255(255, 165, 0, 255)
|
||||
default:
|
||||
basiccard.SetRGBA255(145, 240, 145, 255)
|
||||
}
|
||||
|
||||
basiccard.NewSubPath()
|
||||
basiccard.MoveTo((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2)
|
||||
basiccard.DrawEllipticalArc((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 100, 100, -0.5*math.Pi, -0.5*math.Pi+2*v.precent*0.01*math.Pi)
|
||||
basiccard.Fill()
|
||||
|
||||
basiccard.SetRGBA255(255, 255, 255, 255)
|
||||
basiccard.DrawCircle((float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 80)
|
||||
basiccard.Fill()
|
||||
|
||||
err = basiccard.ParseFontFace(fontbyte, 42)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
basiccard.SetRGBA255(213, 213, 213, 255)
|
||||
basiccard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200/2, 0.5, 0.5)
|
||||
|
||||
basiccard.SetRGBA255(30, 30, 30, 255)
|
||||
_, fw := basiccard.MeasureString(v.name)
|
||||
basiccard.DrawStringAnchored(v.name, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+basiccard.FontHeight()/2, 0.5, 0.5)
|
||||
|
||||
err = basiccard.ParseFontFace(fontbyte, 20)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
basiccard.SetRGBA255(30, 30, 30, 180)
|
||||
|
||||
textoffsety := basiccard.FontHeight() + 10
|
||||
for k, s := range v.text {
|
||||
basiccard.DrawStringAnchored(s, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+fw+15+basiccard.FontHeight()/2+float64(k)*textoffsety, 0.5, 0.5)
|
||||
}
|
||||
}
|
||||
basicimg = rendercard.Fillet(basiccard.Image(), 16)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
diskcard := gg.NewContext(cardw, diskcardh)
|
||||
bwg.Wait()
|
||||
diskcard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40)
|
||||
|
||||
diskcard.DrawRoundedRectangle(1, 1, float64(diskcard.W()-1*2), float64(diskcardh-1*2), 16)
|
||||
diskcard.SetLineWidth(3)
|
||||
diskcard.SetRGBA255(255, 255, 255, 100)
|
||||
diskcard.StrokePreserve()
|
||||
diskcard.SetRGBA255(255, 255, 255, 140)
|
||||
diskcard.Fill()
|
||||
|
||||
err = diskcard.ParseFontFace(fontbyte, 32)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dslen := len(diskstate)
|
||||
if dslen == 1 {
|
||||
diskcard.SetRGBA255(192, 192, 192, 255)
|
||||
diskcard.DrawRoundedRectangle(40, 40, float64(diskcard.W())-40-100, 50, 12)
|
||||
diskcard.ClipPreserve()
|
||||
diskcard.Fill()
|
||||
|
||||
switch {
|
||||
case diskstate[0].precent > 90:
|
||||
diskcard.SetRGBA255(255, 70, 0, 255)
|
||||
case diskstate[0].precent > 70:
|
||||
diskcard.SetRGBA255(255, 165, 0, 255)
|
||||
default:
|
||||
diskcard.SetRGBA255(145, 240, 145, 255)
|
||||
}
|
||||
|
||||
diskcard.DrawRoundedRectangle(40, 40, (float64(diskcard.W())-40-100)*diskstate[0].precent*0.01, 50, 12)
|
||||
diskcard.Fill()
|
||||
diskcard.ResetClip()
|
||||
diskcard.SetRGBA255(30, 30, 30, 255)
|
||||
|
||||
fw, _ := diskcard.MeasureString(diskstate[0].name)
|
||||
fw1, _ := diskcard.MeasureString(diskstate[0].text[0])
|
||||
|
||||
diskcard.DrawStringAnchored(diskstate[0].name, 40+10+fw/2, 40+50/2, 0.5, 0.5)
|
||||
diskcard.DrawStringAnchored(diskstate[0].text[0], (float64(diskcard.W())-100-10)-fw1/2, 40+50/2, 0.5, 0.5)
|
||||
diskcard.DrawStringAnchored(strconv.FormatFloat(diskstate[0].precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+50/2, 0.5, 0.5)
|
||||
} else {
|
||||
for i, v := range diskstate {
|
||||
offset := float64(i)*(50+20) - 20
|
||||
|
||||
diskcard.SetRGBA255(192, 192, 192, 255)
|
||||
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, float64(diskcard.W())-40-100, 50, 12)
|
||||
diskcard.Fill()
|
||||
|
||||
switch {
|
||||
case v.precent > 90:
|
||||
diskcard.SetRGBA255(255, 70, 0, 255)
|
||||
case v.precent > 70:
|
||||
diskcard.SetRGBA255(255, 165, 0, 255)
|
||||
default:
|
||||
diskcard.SetRGBA255(145, 240, 145, 255)
|
||||
}
|
||||
|
||||
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, (float64(diskcard.W())-40-100)*v.precent*0.01, 50, 12)
|
||||
diskcard.Fill()
|
||||
|
||||
diskcard.SetRGBA255(30, 30, 30, 255)
|
||||
|
||||
fw, _ := diskcard.MeasureString(v.name)
|
||||
fw1, _ := diskcard.MeasureString(v.text[0])
|
||||
|
||||
diskcard.DrawStringAnchored(v.name, 40+10+fw/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5)
|
||||
diskcard.DrawStringAnchored(v.text[0], (float64(diskcard.W())-100-10)-fw1/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5)
|
||||
diskcard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5)
|
||||
}
|
||||
}
|
||||
diskimg = rendercard.Fillet(diskcard.Image(), 16)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
moreinfocard := gg.NewContext(cardw, moreinfocardh)
|
||||
bwg.Wait()
|
||||
moreinfocard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
||||
|
||||
moreinfocard.DrawRoundedRectangle(1, 1, float64(moreinfocard.W()-1*2), float64(moreinfocard.H()-1*2), 16)
|
||||
moreinfocard.SetLineWidth(3)
|
||||
moreinfocard.SetRGBA255(255, 255, 255, 100)
|
||||
moreinfocard.StrokePreserve()
|
||||
moreinfocard.SetRGBA255(255, 255, 255, 140)
|
||||
moreinfocard.Fill()
|
||||
|
||||
err = moreinfocard.ParseFontFace(fontbyte, 32)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
milen := len(moreinfo)
|
||||
for i, v := range moreinfo {
|
||||
offset := float64(i)*(20+moreinfocard.FontHeight()) - 20
|
||||
|
||||
moreinfocard.SetRGBA255(30, 30, 30, 255)
|
||||
|
||||
fw, _ := moreinfocard.MeasureString(v.name)
|
||||
fw1, _ := moreinfocard.MeasureString(v.text[0])
|
||||
|
||||
moreinfocard.DrawStringAnchored(v.name, 20+fw/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
||||
moreinfocard.DrawStringAnchored(v.text[0], float64(moreinfocard.W())-20-fw1/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
||||
}
|
||||
moreinfoimg = rendercard.Fillet(moreinfocard.Image(), 16)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
shadow := gg.NewContext(canvas.W(), canvas.H())
|
||||
shadow.SetRGBA255(0, 0, 0, 100)
|
||||
shadow.SetLineWidth(12)
|
||||
shadow.DrawRoundedRectangle(70, 70, float64(cardw), float64(titlecardh), 16)
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40), float64(cardw), float64(basiccardh), 16)
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40), float64(cardw), float64(diskcardh), 16)
|
||||
shadow.Stroke()
|
||||
shadow.DrawRoundedRectangle(70, float64(70+titlecardh+40+basiccardh+40+diskcardh+40), float64(cardw), float64(moreinfocardh), 16)
|
||||
shadow.Stroke()
|
||||
shadowimg = imaging.Blur(shadow.Image(), 24)
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
if shadowimg == nil || titleimg == nil || basicimg == nil || diskimg == nil || moreinfoimg == nil {
|
||||
err = errors.New("图片渲染失败")
|
||||
return
|
||||
}
|
||||
canvas.DrawImage(shadowimg, 0, 0)
|
||||
canvas.DrawImage(titleimg, 70, 70)
|
||||
canvas.DrawImage(basicimg, 70, 70+titlecardh+40)
|
||||
canvas.DrawImage(diskimg, 70, 70+titlecardh+40+basiccardh+40)
|
||||
canvas.DrawImage(moreinfoimg, 70, 70+titlecardh+40+basiccardh+40+diskcardh+40)
|
||||
|
||||
err = canvas.ParseFontFace(fontbyte, 28)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
canvas.SetRGBA255(0, 0, 0, 255)
|
||||
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+banner.Version, float64(canvas.W())/2+3, float64(canvas.H())-70/2+3, 0.5, 0.5)
|
||||
canvas.SetRGBA255(255, 255, 255, 255)
|
||||
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+banner.Version, float64(canvas.W())/2, float64(canvas.H())-70/2, 0.5, 0.5)
|
||||
|
||||
sendimg = canvas.Image()
|
||||
return
|
||||
}
|
||||
|
||||
func botruntime() (string, error) {
|
||||
hostinfo, err := host.Info()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
t := &strings.Builder{}
|
||||
t.WriteString("ZeroBot-Plugin 已运行 ")
|
||||
t.WriteString(strconv.FormatInt((time.Now().Unix()-boottime.Unix())/86400, 10))
|
||||
t.WriteString(" 天 ")
|
||||
t.WriteString(time.Unix(time.Now().Unix()-boottime.Unix(), 0).UTC().Format("15:04:05"))
|
||||
t.WriteString(" | 系统运行 ")
|
||||
t.WriteString(strconv.FormatInt(int64(hostinfo.Uptime)/86400, 10))
|
||||
t.WriteString(" 天 ")
|
||||
t.WriteString(time.Unix(int64(hostinfo.Uptime), 0).UTC().Format("15:04:05"))
|
||||
return t.String(), nil
|
||||
}
|
||||
|
||||
func botstatus() (string, error) {
|
||||
hostinfo, err := host.Info()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
t := &strings.Builder{}
|
||||
t.WriteString(time.Now().Format("2006-01-02 15:04:05"))
|
||||
t.WriteString(" | Compiled by ")
|
||||
t.WriteString(runtime.Version())
|
||||
t.WriteString(" | ")
|
||||
t.WriteString(cases.Title(language.English).String(hostinfo.OS))
|
||||
return t.String(), nil
|
||||
}
|
||||
|
||||
type status struct {
|
||||
precent float64
|
||||
name string
|
||||
text []string
|
||||
}
|
||||
|
||||
func basicstate() (stateinfo [3]*status, err error) {
|
||||
percent, err := cpu.Percent(time.Second, false)
|
||||
if err != nil {
|
||||
return -1
|
||||
return
|
||||
}
|
||||
return math.Round(percent[0])
|
||||
cpuinfo, err := cpu.Info()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cores := strconv.Itoa(int(cpuinfo[0].Cores)) + " Core"
|
||||
times := "最大 " + strconv.FormatFloat(cpuinfo[0].Mhz/1000, 'f', 1, 64) + "Ghz"
|
||||
|
||||
stateinfo[0] = &status{
|
||||
precent: math.Round(percent[0]),
|
||||
name: "CPU",
|
||||
text: []string{cores, times},
|
||||
}
|
||||
|
||||
raminfo, err := mem.VirtualMemory()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
total := "总共 " + storagefmt(float64(raminfo.Total))
|
||||
used := "已用 " + storagefmt(float64(raminfo.Used))
|
||||
free := "剩余 " + storagefmt(float64(raminfo.Free))
|
||||
|
||||
stateinfo[1] = &status{
|
||||
precent: math.Round(raminfo.UsedPercent),
|
||||
name: "RAM",
|
||||
text: []string{total, used, free},
|
||||
}
|
||||
|
||||
swapinfo, err := mem.SwapMemory()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
total = "总共 " + storagefmt(float64(swapinfo.Total))
|
||||
used = "已用 " + storagefmt(float64(swapinfo.Used))
|
||||
free = "剩余 " + storagefmt(float64(swapinfo.Free))
|
||||
|
||||
stateinfo[2] = &status{
|
||||
precent: math.Round(swapinfo.UsedPercent),
|
||||
name: "SWAP",
|
||||
text: []string{total, used, free},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func memPercent() float64 {
|
||||
memInfo, err := mem.VirtualMemory()
|
||||
if err != nil {
|
||||
return -1
|
||||
func storagefmt(num float64) string {
|
||||
if num /= 1024; num < 1 {
|
||||
return strconv.FormatFloat(num*1024, 'f', 2, 64) + "B"
|
||||
}
|
||||
return math.Round(memInfo.UsedPercent)
|
||||
if num /= 1024; num < 1 {
|
||||
return strconv.FormatFloat(num*1024, 'f', 2, 64) + "KB"
|
||||
}
|
||||
if num /= 1024; num < 1 {
|
||||
return strconv.FormatFloat(num*1024, 'f', 2, 64) + "MB"
|
||||
}
|
||||
if num /= 1024; num < 1 {
|
||||
return strconv.FormatFloat(num*1024, 'f', 2, 64) + "GB"
|
||||
}
|
||||
return strconv.FormatFloat(num, 'f', 2, 64) + "TB"
|
||||
}
|
||||
|
||||
func diskPercent() string {
|
||||
parts, err := disk.Partitions(true)
|
||||
func diskstate() (stateinfo []*status, err error) {
|
||||
parts, err := disk.Partitions(false)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
return
|
||||
}
|
||||
msg := ""
|
||||
for _, p := range parts {
|
||||
diskInfo, err := disk.Usage(p.Mountpoint)
|
||||
if err != nil {
|
||||
msg += "\n - " + err.Error()
|
||||
stateinfo = make([]*status, 0, len(parts))
|
||||
for _, v := range parts {
|
||||
mp := v.Mountpoint
|
||||
if strings.HasPrefix(mp, "/snap/") || strings.HasPrefix(mp, "/apex/") {
|
||||
continue
|
||||
}
|
||||
pc := uint(math.Round(diskInfo.UsedPercent))
|
||||
if pc > 0 {
|
||||
msg += fmt.Sprintf("\n - %s(%dM) %d%%", p.Mountpoint, diskInfo.Total/1024/1024, pc)
|
||||
diskusage, err := disk.Usage(mp)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
stateinfo = append(stateinfo, &status{
|
||||
precent: math.Round(diskusage.UsedPercent),
|
||||
name: mp,
|
||||
text: []string{storagefmt(float64(diskusage.Used)) + " / " + storagefmt(float64(diskusage.Total))},
|
||||
})
|
||||
}
|
||||
return msg
|
||||
return stateinfo, nil
|
||||
}
|
||||
|
||||
func moreinfo(m *ctrl.Control[*zero.Ctx]) (stateinfo []*status, err error) {
|
||||
hostinfo, err := host.Info()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cpuinfo, err := cpu.Info()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
count := len(m.Manager.M)
|
||||
stateinfo = []*status{
|
||||
{name: "OS", text: []string{hostinfo.Platform}},
|
||||
{name: "CPU", text: []string{cpuinfo[0].ModelName}},
|
||||
{name: "Version", text: []string{hostinfo.PlatformVersion}},
|
||||
{name: "Plugin", text: []string{"共 " + strconv.Itoa(count) + " 个"}},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,20 +32,28 @@ const (
|
||||
mockingbirdttsindex
|
||||
)
|
||||
|
||||
// extrattsname is the tts other than genshin vits
|
||||
var extrattsname = []string{"百度", "拟声鸟"}
|
||||
|
||||
const (
|
||||
defaultttsindexkey = -2905
|
||||
defaultttsindexkey = -2905
|
||||
gsapikeyextragrp = -1
|
||||
chatgptapikeyextragrp = -2
|
||||
)
|
||||
|
||||
var replyModes = [...]string{"青云客", "小爱"}
|
||||
type replymode struct {
|
||||
APIKey string // APIKey is for chatgpt
|
||||
replyModes []string `json:"-"`
|
||||
}
|
||||
|
||||
func setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
func (r *replymode) setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var ok bool
|
||||
var index int64
|
||||
for i, s := range replyModes {
|
||||
for i, s := range r.replyModes {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
@@ -62,24 +70,47 @@ func setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
return m.SetData(gid, (m.GetData(index)&^0xff)|(index&0xff))
|
||||
}
|
||||
|
||||
func getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
if m.GetData(gid)&0xff == 1 {
|
||||
switch m.GetData(gid) & 0xff {
|
||||
case 0:
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
case 1:
|
||||
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
|
||||
case 2:
|
||||
k := r.getAPIKey(ctx)
|
||||
if k != "" {
|
||||
return aireply.NewChatGPT(aireply.ChatGPTURL, k)
|
||||
}
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
|
||||
func (r *replymode) getAPIKey(ctx *zero.Ctx) string {
|
||||
if r.APIKey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(chatgptapikeyextragrp, &r)
|
||||
logrus.Debugln("[tts] get api key:", r.APIKey)
|
||||
}
|
||||
return r.APIKey
|
||||
}
|
||||
|
||||
func (r *replymode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
r.APIKey = key
|
||||
_ = m.Manager.Response(chatgptapikeyextragrp)
|
||||
return m.Manager.SetExtra(chatgptapikeyextragrp, r)
|
||||
}
|
||||
|
||||
var ttsins = func() map[string]tts.TTS {
|
||||
m := make(map[string]tts.TTS, 128)
|
||||
for _, mode := range append(genshin.SoundList[:], "百度", "拟声鸟") {
|
||||
for _, mode := range append(genshin.SoundList[:], extrattsname...) {
|
||||
m[mode] = nil
|
||||
}
|
||||
return m
|
||||
@@ -87,7 +118,7 @@ var ttsins = func() map[string]tts.TTS {
|
||||
|
||||
var ttsModes = func() []string {
|
||||
s := append(genshin.SoundList[:], make([]string, 64-len(genshin.SoundList))...) // 0-63
|
||||
s = append(s, "百度", "拟声鸟") // 64 65
|
||||
s = append(s, extrattsname...) // 64 65 ...
|
||||
return s
|
||||
}()
|
||||
|
||||
@@ -127,7 +158,7 @@ func newttsmode() *ttsmode {
|
||||
func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string {
|
||||
if t.APIKey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(-1, &t)
|
||||
_ = m.Manager.GetExtra(gsapikeyextragrp, &t)
|
||||
logrus.Debugln("[tts] get api key:", t.APIKey)
|
||||
}
|
||||
return url.QueryEscape(t.APIKey)
|
||||
@@ -135,8 +166,8 @@ func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string {
|
||||
|
||||
func (t *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
t.APIKey = key
|
||||
_ = m.Manager.Response(-1)
|
||||
return m.Manager.SetExtra(-1, t)
|
||||
_ = m.Manager.Response(gsapikeyextragrp)
|
||||
return m.Manager.SetExtra(gsapikeyextragrp, t)
|
||||
}
|
||||
|
||||
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt int) error {
|
||||
@@ -157,9 +188,9 @@ func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt
|
||||
}
|
||||
if index == -1 {
|
||||
switch name {
|
||||
case "百度":
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case "拟声鸟":
|
||||
case extrattsname[1]:
|
||||
index = mockingbirdttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
@@ -189,9 +220,9 @@ func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
|
||||
ins, ok := ttsins[mode]
|
||||
if !ok || ins == nil {
|
||||
switch mode {
|
||||
case "百度":
|
||||
case extrattsname[0]:
|
||||
ins = baidutts.NewBaiduTTS(int(i&0x0f00) >> 8)
|
||||
case "拟声鸟":
|
||||
case extrattsname[1]:
|
||||
var err error
|
||||
ins, err = mockingbird.NewMockingBirdTTS(int(i&0xf000) >> 12)
|
||||
if err != nil {
|
||||
@@ -234,9 +265,9 @@ func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) er
|
||||
}
|
||||
if index == -1 {
|
||||
switch name {
|
||||
case "百度":
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case "拟声鸟":
|
||||
case extrattsname[1]:
|
||||
index = mockingbirdttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -14,7 +15,11 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var t = newttsmode()
|
||||
var replmd = replymode{
|
||||
replyModes: []string{"青云客", "小爱", "ChatGPT"},
|
||||
}
|
||||
|
||||
var ttsmd = newttsmode()
|
||||
|
||||
func init() { // 插件主体
|
||||
ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{
|
||||
@@ -31,13 +36,13 @@ func init() { // 插件主体
|
||||
enr := control.Register("aireply", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "人工智能回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱|ChatGPT]\n- 设置 ChatGPT api key xxx",
|
||||
PrivateDataFolder: "aireply",
|
||||
})
|
||||
|
||||
enr.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
aireply := getReplyMode(ctx)
|
||||
aireply := replmd.getReplyMode(ctx)
|
||||
reply := message.ParseMessageFromString(aireply.Talk(ctx.Event.UserID, ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
|
||||
// 回复
|
||||
time.Sleep(time.Second * 1)
|
||||
@@ -51,7 +56,7 @@ func init() { // 插件主体
|
||||
|
||||
enr.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
err := setReplyMode(ctx, param)
|
||||
err := replmd.setReplyMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
@@ -59,20 +64,35 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
|
||||
enr.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := replmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("设置成功"))
|
||||
})
|
||||
|
||||
endpre := regexp.MustCompile(`\pP$`)
|
||||
ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msg := ctx.ExtractPlainText()
|
||||
// 获取回复模式
|
||||
r := getReplyMode(ctx)
|
||||
r := replmd.getReplyMode(ctx)
|
||||
// 获取回复的文本
|
||||
reply := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0])
|
||||
// 获取语音
|
||||
speaker, err := t.getSoundMode(ctx)
|
||||
speaker, err := ttsmd.getSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
rec, err := speaker.Speak(ctx.Event.UserID, func() string { return reply })
|
||||
rec, err := speaker.Speak(ctx.Event.UserID, func() string {
|
||||
if !endpre.MatchString(reply) {
|
||||
return reply + "。"
|
||||
}
|
||||
return reply
|
||||
})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
return
|
||||
@@ -97,7 +117,7 @@ func init() { // 插件主体
|
||||
}
|
||||
// 保存设置
|
||||
logrus.Debugln("[tts] t.setSoundMode( ctx", param, n, n, ")")
|
||||
err = t.setSoundMode(ctx, param, n, n)
|
||||
err = ttsmd.setSoundMode(ctx, param, n, n)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
@@ -105,7 +125,7 @@ func init() { // 插件主体
|
||||
if banner, ok := genshin.TestRecord[param]; ok {
|
||||
logrus.Debugln("[tts] banner:", banner, "get sound mode...")
|
||||
// 设置验证
|
||||
speaker, err := t.getSoundMode(ctx)
|
||||
speaker, err := ttsmd.getSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -139,7 +159,7 @@ func init() { // 插件主体
|
||||
}
|
||||
}
|
||||
// 保存设置
|
||||
err = t.setDefaultSoundMode(param, n, n)
|
||||
err = ttsmd.setDefaultSoundMode(param, n, n)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
@@ -148,13 +168,13 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := t.resetSoundMode(ctx)
|
||||
err := ttsmd.resetSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
// 设置验证
|
||||
speaker, err := t.getSoundMode(ctx)
|
||||
speaker, err := ttsmd.getSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -163,7 +183,7 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
ent.OnRegex(`^设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := t.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
|
||||
err := ttsmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
@@ -54,9 +54,9 @@ func init() { // 插件主体
|
||||
"- 设置ai绘图配置 [server] [token]\n" +
|
||||
"- 设置ai绘图撤回时间90s\n" +
|
||||
"- 查看ai绘图配置\n" +
|
||||
"例: 设置ai绘图配置 http://91.217.139.190:5010 abc\n" +
|
||||
"Tips: 使用前请先前往 http://91.217.139.190:5010/token 按提示获取token" +
|
||||
"设置token示例(请确保是主人并且响应): 设置ai绘图配置 http://91.217.139.190:5010 [token] (中括号无需输入)\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:种子\nstrength:[0-1] 建议0-0.7\nnoise:[0-1] 建议0-0.15" +
|
||||
"参数与参数内容用:连接,每个参数之间用回车分割",
|
||||
@@ -146,7 +146,7 @@ func init() { // 插件主体
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
err := cfg.load()
|
||||
@@ -159,8 +159,7 @@ func init() { // 插件主体
|
||||
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))
|
||||
ctx.SendChain(message.Text("成功设置\nbase_url: ", cfg.BaseURL, "\ntoken: ", cfg.Token, "\ninterval: ", cfg.Interval))
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图撤回时间(\d{1,3})s$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -180,18 +179,16 @@ func init() { // 插件主体
|
||||
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))
|
||||
ctx.SendChain(message.Text("成功设置撤回时间为", cfg.Interval, "s"))
|
||||
})
|
||||
engine.OnFullMatch(`查看ai绘图配置`, zero.SuperUserPermission).SetBlock(true).
|
||||
engine.OnFullMatch(`查看ai绘图配置`, zero.OnlyPrivate, 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))
|
||||
ctx.SendChain(message.Text("base_url: ", cfg.BaseURL, "\ntoken: ", cfg.Token, "\ninterval: ", cfg.Interval))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@@ -73,7 +73,7 @@ func init() { // 插件主体
|
||||
}
|
||||
|
||||
// 图片转base64
|
||||
base64Bytes, err := writer.ToBase64(img)
|
||||
base64Bytes, err := imgfactory.ToBase64(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
@@ -13,7 +13,6 @@ 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"
|
||||
)
|
||||
@@ -41,7 +40,7 @@ func randText(text ...string) message.MessageSegment {
|
||||
}
|
||||
|
||||
// isAtriSleeping 凌晨0点到6点,ATRI 在睡觉,不回应任何请求
|
||||
func isAtriSleeping(ctx *zero.Ctx) bool {
|
||||
func isAtriSleeping(*zero.Ctx) bool {
|
||||
if now := time.Now().Hour(); now >= 1 && now < 6 {
|
||||
return false
|
||||
}
|
||||
@@ -58,12 +57,11 @@ func init() { // 插件主体
|
||||
"- 中午好 | 午安 | 午好\n- 晚安 | oyasuminasai | おやすみなさい | 晚好 | 晚上好\n- 高性能 | 太棒了 | すごい | sugoi | 斯国一 | よかった\n" +
|
||||
"- 没事 | 没关系 | 大丈夫 | 还好 | 不要紧 | 没出大问题 | 没伤到哪\n- 好吗 | 是吗 | 行不行 | 能不能 | 可不可以\n- 啊这\n- 我好了\n- ? | ? | ¿\n" +
|
||||
"- 离谱\n- 答应我",
|
||||
PublicDataFolder: "Atri",
|
||||
OnEnable: func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Text("嗯呜呜……夏生先生……?"))
|
||||
},
|
||||
OnDisable: func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Text("Zzz……Zzz……"))
|
||||
},
|
||||
})
|
||||
@@ -71,7 +69,6 @@ func init() { // 插件主体
|
||||
var dgtr datagetter = engine.GetLazyData
|
||||
engine.OnFullMatch("萝卜子").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
switch rand.Intn(2) {
|
||||
case 0:
|
||||
ctx.SendChain(randText("萝卜子是对机器人的蔑称!", "是亚托莉......萝卜子可是对机器人的蔑称"))
|
||||
@@ -81,18 +78,15 @@ func init() { // 插件主体
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"喜欢", "爱你", "爱", "suki", "daisuki", "すき", "好き", "贴贴", "老婆", "亲一个", "mua"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(dgtr.randImage("SUKI.jpg", "SUKI1.jpg", "SUKI2.png"))
|
||||
})
|
||||
engine.OnKeywordGroup([]string{"草你妈", "操你妈", "脑瘫", "废柴", "fw", "five", "废物", "战斗", "爬", "爪巴", "sb", "SB", "傻B"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(dgtr.randImage("FN.jpg", "WQ.jpg", "WQ1.jpg"))
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"早安", "早哇", "早上好", "ohayo", "哦哈哟", "お早う", "早好", "早", "早早早"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
now := time.Now().Hour()
|
||||
process.SleepAbout1sTo2s()
|
||||
switch {
|
||||
case now < 6: // 凌晨
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), randText(
|
||||
@@ -133,7 +127,6 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
now := time.Now().Hour()
|
||||
if now > 11 && now < 15 { // 中午
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), randText(
|
||||
"午安w",
|
||||
"午觉要好好睡哦,ATRI会陪伴在你身旁的w",
|
||||
@@ -145,7 +138,6 @@ func init() { // 插件主体
|
||||
engine.OnFullMatchGroup([]string{"晚安", "oyasuminasai", "おやすみなさい", "晚好", "晚上好"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
now := time.Now().Hour()
|
||||
process.SleepAbout1sTo2s()
|
||||
switch {
|
||||
case now < 6: // 凌晨
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), randText(
|
||||
@@ -187,7 +179,6 @@ func init() { // 插件主体
|
||||
})
|
||||
engine.OnKeywordGroup([]string{"高性能", "太棒了", "すごい", "sugoi", "斯国一", "よかった"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(randText(
|
||||
"当然,我是高性能的嘛~!",
|
||||
"小事一桩,我是高性能的嘛",
|
||||
@@ -208,7 +199,6 @@ func init() { // 插件主体
|
||||
})
|
||||
engine.OnKeywordGroup([]string{"没事", "没关系", "大丈夫", "还好", "不要紧", "没出大问题", "没伤到哪"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(randText(
|
||||
"当然,我是高性能的嘛~!",
|
||||
"没事没事,因为我是高性能的嘛!嗯哼!",
|
||||
@@ -223,26 +213,22 @@ func init() { // 插件主体
|
||||
|
||||
engine.OnKeywordGroup([]string{"好吗", "是吗", "行不行", "能不能", "可不可以"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
if rand.Intn(2) == 0 {
|
||||
ctx.SendChain(dgtr.randImage("YES.png", "NO.jpg"))
|
||||
}
|
||||
})
|
||||
engine.OnKeywordGroup([]string{"啊这"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
if rand.Intn(2) == 0 {
|
||||
ctx.SendChain(dgtr.randImage("AZ.jpg", "AZ1.jpg"))
|
||||
}
|
||||
})
|
||||
engine.OnKeywordGroup([]string{"我好了"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), randText("不许好!", "憋回去!"))
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"?", "?", "¿"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
switch rand.Intn(5) {
|
||||
case 0:
|
||||
ctx.SendChain(randText("?", "?", "嗯?", "(。´・ω・)ん?", "ん?"))
|
||||
@@ -261,7 +247,6 @@ func init() { // 插件主体
|
||||
})
|
||||
engine.OnKeyword("答应我", zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(randText("我无法回应你的请求"))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,27 +1,51 @@
|
||||
// Package baidu 百度一下
|
||||
// Package baidu 百度百科
|
||||
package baidu
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "不会百度吗",
|
||||
Help: "- 百度下[xxx]",
|
||||
}).OnPrefix("百度下").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
txt := ctx.State["args"].(string)
|
||||
if txt != "" {
|
||||
ctx.SendChain(message.Text("https://buhuibaidu.me/?s=" + url.QueryEscape(txt)))
|
||||
}
|
||||
})
|
||||
const (
|
||||
api = "https://api.a20safe.com/api.php?api=21&key=7d06a110e9e20a684e02934549db1d3d&text=%s" // api地址
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data []struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "百度百科\n" +
|
||||
"- 百度/百科[关键字]",
|
||||
})
|
||||
en.OnRegex(`^百[度科]\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
es, err := web.GetData(fmt.Sprintf(api, ctx.State["regex_matched"].([]string)[1])) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var r result // r数组
|
||||
err = json.Unmarshal(es, &r) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
if r.Code == 0 && len(r.Data) > 0 {
|
||||
ctx.SendChain(message.Text(r.Data[0].Content)) // 输出提取后的结果
|
||||
} else {
|
||||
ctx.SendChain(message.Text("API访问错误"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,115 +4,51 @@ package baiduaudit
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Baidu-AIP/golang-sdk/aip/censor"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"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 // 配置路径
|
||||
bdcli *censor.ContentCensorClient // 百度云审核服务Client
|
||||
txttyp = [...]string{
|
||||
0: "默认违禁词库",
|
||||
1: "违禁违规",
|
||||
2: "文本色情",
|
||||
3: "敏感信息",
|
||||
4: "恶意推广",
|
||||
5: "低俗辱骂",
|
||||
6: "恶意推广-联系方式",
|
||||
7: "恶意推广-软文推广",
|
||||
} // 文本类型
|
||||
config = newconfig() // 插件配置
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "百度内容审核",
|
||||
Help: "##该功能来自百度内容审核,需购买相关服务,并创建app##\n" +
|
||||
Help: "##该功能来自百度内容审核, 需购买相关服务, 并创建app##\n" +
|
||||
"- 获取BDAKey\n" +
|
||||
"- 配置BDAKey [API key] [Secret Key]\n" +
|
||||
"- 开启/关闭内容审核\n" +
|
||||
"- 开启/关闭撤回提示\n" +
|
||||
"- 开启/关闭详细提示\n" +
|
||||
"- 开启/关闭撤回禁言\n" +
|
||||
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时,再次触发按最大禁言时间计算\n" +
|
||||
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时, 再次触发按最大禁言时间计算\n" +
|
||||
"- 开启/关闭禁言累加\n" +
|
||||
"- 设置撤回禁言时间[分钟,默认:1]\n" +
|
||||
"- 设置最大禁言时间[分钟,默认:60,最大43200]\n" +
|
||||
"- 设置每次累加时间[分钟,默认:1]\n" +
|
||||
"- 设置撤回禁言时间[分钟, 默认:1]\n" +
|
||||
"- 设置最大禁言时间[分钟, 默认:60,最大43200]\n" +
|
||||
"- 设置每次累加时间[分钟, 默认:1]\n" +
|
||||
"##检测类型设置## 类型编号列表:[1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广]\n" +
|
||||
"- 查看检测类型\n" +
|
||||
"- 查看检测配置\n" +
|
||||
@@ -121,15 +57,19 @@ func init() {
|
||||
"- 开启/关闭文本检测\n" +
|
||||
"- 开启/关闭图像检测\n" +
|
||||
"##测试功能##\n" +
|
||||
"- 测试文本检测[文本内容]\n" +
|
||||
"- 测试图像检测[图片]\n",
|
||||
"- ^文本检测[文本内容]\n" +
|
||||
"- ^图像检测[图片]\n",
|
||||
PrivateDataFolder: "baiduaudit",
|
||||
})
|
||||
configpath = engine.DataFolder() + "config.json"
|
||||
loadConfig()
|
||||
if configinit {
|
||||
|
||||
configpath := engine.DataFolder() + "config.json"
|
||||
err := config.load(configpath)
|
||||
if err != nil {
|
||||
logrus.Warnln("[baiduaudit] 加载配置错误:", err)
|
||||
} else if config.Key1 != "" && config.Key2 != "" {
|
||||
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" +
|
||||
@@ -138,28 +78,33 @@ func init() {
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/resource/getFree"))
|
||||
})
|
||||
|
||||
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, hasinit).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
var msgs string
|
||||
group := config.groupof(ctx.Event.GroupID)
|
||||
msg := ""
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
if k1 == "类型" {
|
||||
msgs += "本群检测类型:"
|
||||
find := false
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("本群检测类型:")
|
||||
found := false
|
||||
// 遍历群检测类型名单
|
||||
for i, v := range group.WhiteListType {
|
||||
for i, v := range group.copyWhiteListType() {
|
||||
if !v {
|
||||
find = true
|
||||
msgs += fmt.Sprint("\n", i, ".", typetext[i])
|
||||
found = true
|
||||
sb.WriteByte('\n')
|
||||
sb.WriteString(strconv.Itoa(i))
|
||||
sb.WriteByte('.')
|
||||
sb.WriteString(txttyp[i])
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
msgs += "无"
|
||||
if !found {
|
||||
sb.WriteString("无")
|
||||
}
|
||||
msg = sb.String()
|
||||
} else {
|
||||
// 生成配置文本
|
||||
msgs = fmt.Sprintf("本群配置:\n"+
|
||||
msg = fmt.Sprintf("本群配置:\n"+
|
||||
"内容审核:%s\n"+
|
||||
"-文本:%s\n"+
|
||||
"-图像:%s\n"+
|
||||
@@ -171,138 +116,145 @@ func init() {
|
||||
"-每次累加时间:%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)
|
||||
b, err := text.RenderToBase64(msg, 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).
|
||||
|
||||
engine.OnRegex("^设置(不)?检测类型([0-7])$", zero.AdminPermission, hasinit).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)
|
||||
group := config.groupof(ctx.Event.GroupID)
|
||||
inputType, _ := strconv.Atoi(k2)
|
||||
if k1 == "不" {
|
||||
group.WhiteListType[inputType] = true // 不检测:则进入类型白名单
|
||||
} else {
|
||||
group.WhiteListType[inputType] = false // 检测:则退出白名单
|
||||
group.setWhiteListType(inputType, k1 == "不")
|
||||
err := config.saveto(configpath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, typetext[inputType])))
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, txttyp[inputType])))
|
||||
})
|
||||
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
|
||||
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, hasinit).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.groupof(ctx.Event.GroupID).set(func(g *group) {
|
||||
switch k1 {
|
||||
case "最大":
|
||||
g.MaxBANTimeAddRange = time
|
||||
case "每次":
|
||||
g.BANTimeAddTime = time
|
||||
case "撤回":
|
||||
g.BANTime = time
|
||||
}
|
||||
})
|
||||
err := config.saveto(configpath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
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).
|
||||
|
||||
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, hasinit).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
|
||||
isEnable := mark(k1 == "开启")
|
||||
config.groupof(ctx.Event.GroupID).set(func(g *group) {
|
||||
switch k2 {
|
||||
case "内容审核":
|
||||
g.Enable = isEnable
|
||||
case "撤回提示":
|
||||
g.DMRemind = isEnable
|
||||
case "撤回禁言":
|
||||
g.DMBAN = isEnable
|
||||
case "禁言累加":
|
||||
g.BANTimeAddEnable = isEnable
|
||||
case "详细提示":
|
||||
g.MoreRemind = isEnable
|
||||
case "文本检测":
|
||||
g.TextAudit = isEnable
|
||||
case "图像检测":
|
||||
g.ImageAudit = isEnable
|
||||
}
|
||||
})
|
||||
err := config.saveto(configpath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
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
|
||||
config.setkey(k1, k2)
|
||||
if bdcli != nil {
|
||||
jsonSave(config, configpath)
|
||||
err := config.saveto(configpath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
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) {
|
||||
|
||||
engine.OnMessage(config.isgroupexist).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
group := config.groupof(ctx.Event.GroupID)
|
||||
if !bool(group.Enable) {
|
||||
return
|
||||
}
|
||||
var bdres baiduRes
|
||||
var err error
|
||||
for _, elem := range ctx.Event.Message {
|
||||
switch elem.Type {
|
||||
case "image":
|
||||
if !group.ImageAudit {
|
||||
return
|
||||
if !group.ImageAudit || elem.Data["url"] == "" {
|
||||
continue
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
bdres, err = parse2BaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
continue
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
|
||||
case "text":
|
||||
if !group.TextAudit {
|
||||
return
|
||||
if !group.TextAudit || elem.Data["text"] == "" {
|
||||
continue
|
||||
}
|
||||
res := bdcli.TextCensor(elem.Data["text"])
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
bdres, err = parse2BaiduRes(bdcli.TextCensor(elem.Data["text"]))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
continue
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
bdres.audit(ctx, configpath)
|
||||
})
|
||||
engine.OnPrefix("文本检测", clientCheck).SetBlock(false).
|
||||
|
||||
engine.OnPrefix("^文本检测", hasinit).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)
|
||||
bdres, err := parse2BaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
|
||||
})
|
||||
engine.OnPrefix("^图像检测", clientCheck).SetBlock(false).
|
||||
|
||||
engine.OnPrefix("^图像检测", hasinit).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var urls []string
|
||||
for _, elem := range ctx.Event.Message {
|
||||
@@ -316,105 +268,17 @@ func init() {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(urls[0], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
bdres, err := parse2BaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
|
||||
})
|
||||
}
|
||||
|
||||
// 禁言检测
|
||||
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 {
|
||||
func hasinit(ctx *zero.Ctx) bool {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return false
|
||||
@@ -422,79 +286,7 @@ func clientCheck(ctx *zero.Ctx) bool {
|
||||
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
|
||||
func parse2BaiduRes(resjson string) (bdres baiduRes, err error) {
|
||||
err = json.Unmarshal(binary.StringToBytes(resjson), &bdres)
|
||||
return
|
||||
}
|
||||
|
||||
271
plugin/baiduaudit/model.go
Normal file
271
plugin/baiduaudit/model.go
Normal file
@@ -0,0 +1,271 @@
|
||||
package baiduaudit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
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 {
|
||||
mu sync.Mutex `json:"-"`
|
||||
// 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"` // 错误提示信息, 失败才返回, 成功不返回
|
||||
}
|
||||
|
||||
// 禁言检测
|
||||
func (bdres *baiduRes) audit(ctx *zero.Ctx, configpath string) {
|
||||
bdres.mu.Lock()
|
||||
defer bdres.mu.Unlock()
|
||||
// 如果返回类型为2(不合规), 0为合规, 3为疑似
|
||||
if bdres.ConclusionType != 2 {
|
||||
return
|
||||
}
|
||||
// 创建消息ID
|
||||
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
|
||||
// 获取群配置
|
||||
group := config.groupof(ctx.Event.GroupID)
|
||||
// 检测群配置里的不检测类型白名单, 忽略掉不检测的违规类型
|
||||
for i, b := range group.copyWhiteListType() {
|
||||
if i == bdres.Data[0].SubType && b {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 生成回复文本
|
||||
res := group.reply(bdres)
|
||||
// 撤回消息
|
||||
ctx.DeleteMessage(mid)
|
||||
// 查看是否启用撤回后禁言
|
||||
if group.DMBAN {
|
||||
// 从历史违规记录中获取指定用户
|
||||
user := group.historyof(ctx.Event.UserID)
|
||||
// 用户违规次数自增
|
||||
atomic.AddInt64(&user.Count, 1)
|
||||
user.mu.Lock()
|
||||
// 用户违规原因记录
|
||||
user.ResList = append(user.ResList, bdres)
|
||||
user.mu.Unlock()
|
||||
// 保存到json
|
||||
err := config.saveto(configpath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
var bantime int64
|
||||
// 查看是否开启禁言累加功能, 并计算禁言时间
|
||||
if group.BANTimeAddEnable {
|
||||
bantime = atomic.LoadInt64(&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.Send(res)
|
||||
}
|
||||
}
|
||||
|
||||
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 auditHistory struct {
|
||||
mu sync.Mutex `json:"-"`
|
||||
Count int64 `json:"key2"` // 被禁次数
|
||||
ResList []*baiduRes `json:"reslist"` // 禁言原因
|
||||
}
|
||||
|
||||
type hit struct {
|
||||
// DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
|
||||
Words []string `json:"words"` // 送检文本命中词库的关键词(备注:建议参考新字段“wordHitPositions”, 包含信息更丰富:关键词以及对应的位置及标签信息)
|
||||
// Probability float64 `json:"probability,omitempty"` // 不合规项置信度
|
||||
} // 送检文本违规原因的详细信息
|
||||
|
||||
type keyConfig struct {
|
||||
mu sync.Mutex `json:"-"`
|
||||
Key1 string `json:"key1"` // 百度云服务内容审核key存储
|
||||
Key2 string `json:"key2"` // 百度云服务内容审核key存储
|
||||
Groups map[int64]*group `json:"groups"` // 群配置存储
|
||||
}
|
||||
|
||||
func newconfig() (kc keyConfig) {
|
||||
kc.Groups = make(map[int64]*group, 64)
|
||||
return
|
||||
}
|
||||
|
||||
func (kc *keyConfig) setkey(k1, k2 string) {
|
||||
kc.mu.Lock()
|
||||
defer kc.mu.Unlock()
|
||||
kc.Key1 = k1
|
||||
kc.Key2 = k2
|
||||
}
|
||||
|
||||
// 加载JSON配置文件
|
||||
func (kc *keyConfig) load(filename string) error {
|
||||
if file.IsNotExist(filename) {
|
||||
return nil
|
||||
}
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kc.mu.Lock()
|
||||
defer kc.mu.Unlock()
|
||||
return json.NewDecoder(f).Decode(kc)
|
||||
}
|
||||
|
||||
func (kc *keyConfig) isgroupexist(ctx *zero.Ctx) (ok bool) {
|
||||
kc.mu.Lock()
|
||||
defer kc.mu.Unlock()
|
||||
_, ok = kc.Groups[ctx.Event.GroupID]
|
||||
return
|
||||
}
|
||||
|
||||
// 获取群配置
|
||||
func (kc *keyConfig) groupof(groupID int64) *group {
|
||||
kc.mu.Lock()
|
||||
defer kc.mu.Unlock()
|
||||
g, ok := kc.Groups[groupID]
|
||||
if ok {
|
||||
return g
|
||||
}
|
||||
g = &group{
|
||||
TextAudit: true,
|
||||
ImageAudit: true,
|
||||
BANTime: 1,
|
||||
MaxBANTimeAddRange: 60,
|
||||
BANTimeAddTime: 1,
|
||||
AuditHistory: map[int64]*auditHistory{},
|
||||
}
|
||||
kc.Groups[groupID] = g
|
||||
return g
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
func (kc *keyConfig) saveto(filename string) error {
|
||||
kc.mu.Lock()
|
||||
defer kc.mu.Unlock()
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return json.NewEncoder(f).Encode(kc)
|
||||
}
|
||||
|
||||
type group struct {
|
||||
mu sync.Mutex
|
||||
Enable mark // 是否启用内容审核
|
||||
TextAudit mark // 文本检测
|
||||
ImageAudit mark // 图像检测
|
||||
DMRemind mark // 撤回提示
|
||||
MoreRemind mark // 详细违规提示
|
||||
DMBAN mark // 撤回后禁言
|
||||
BANTimeAddEnable mark // 禁言累加
|
||||
BANTime int64 // 标准禁言时间, 禁用累加, 但开启禁言的的情况下采用该值
|
||||
MaxBANTimeAddRange int64 // 最大禁言时间累加范围, 最高禁言时间
|
||||
BANTimeAddTime int64 // 禁言累加时间, 该值是开启禁累加功能后, 再次触发时, 根据被禁次数X该值计算出的禁言时间
|
||||
WhiteListType [8]bool // 类型白名单, 处于白名单类型的违规, 不会被触发 0:含多种类型, 具体看官方链接, 1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
AuditHistory map[int64]*auditHistory // 被封禁用户列表
|
||||
}
|
||||
|
||||
func (g *group) set(f func(g *group)) {
|
||||
g.mu.Lock()
|
||||
f(g)
|
||||
g.mu.Unlock()
|
||||
}
|
||||
|
||||
func (g *group) setWhiteListType(typ int, ok bool) {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
g.WhiteListType[typ] = ok
|
||||
}
|
||||
|
||||
func (g *group) copyWhiteListType() [8]bool {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.WhiteListType
|
||||
}
|
||||
|
||||
// 从群历史违规记录中获取用户
|
||||
func (g *group) historyof(userID int64) *auditHistory {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
audit, ok := g.AuditHistory[userID]
|
||||
if ok {
|
||||
return audit
|
||||
}
|
||||
// 如果没有用户, 则创建一个并返回
|
||||
if g.AuditHistory == nil {
|
||||
g.AuditHistory = make(map[int64]*auditHistory)
|
||||
}
|
||||
audit = &auditHistory{}
|
||||
g.AuditHistory[userID] = audit
|
||||
return audit
|
||||
}
|
||||
|
||||
// 生成回复文本
|
||||
func (g *group) reply(bdres *baiduRes) message.Message {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
// 建立消息段
|
||||
msgs := make([]message.MessageSegment, 0, 8)
|
||||
// 生成简略审核结果回复
|
||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||
// 查看是否开启详细审核内容提示, 并确定审核内容值为疑似, 或者不合规
|
||||
if !g.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
|
||||
}
|
||||
|
||||
type mark bool
|
||||
|
||||
// String 打印启用状态
|
||||
func (em mark) String() string {
|
||||
if em {
|
||||
return "开启"
|
||||
}
|
||||
return "关闭"
|
||||
}
|
||||
@@ -16,15 +16,14 @@ import (
|
||||
"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"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
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"
|
||||
@@ -57,7 +56,7 @@ func init() {
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 查弹幕 [xxx]\n" +
|
||||
"- 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0;\n" +
|
||||
"- 更新vup" +
|
||||
"- 更新vup\n" +
|
||||
"Tips: (412就是拦截的意思,建议私聊把cookie设全)\n",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
@@ -174,7 +173,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
back = imgfactory.Size(back, backX, backY).Image()
|
||||
}
|
||||
if len(vups) > 50 {
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了, 只展示前50个up"))
|
||||
@@ -188,11 +187,11 @@ func init() {
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -259,12 +258,15 @@ func init() {
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
data, err := imgfactory.ToBytes(canvas.Image())
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(canvas.Image(), f)
|
||||
_, err = imgfactory.WriteTo(canvas.Image(), f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
@@ -318,15 +320,15 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
back = imgfactory.Size(back, backX, backY).Image()
|
||||
}
|
||||
canvas := gg.NewContext(100, 100)
|
||||
fontSize := 50.0
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -338,14 +340,14 @@ func init() {
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
totalDanmuku += len(danmaku.Data.Data[i].Danmakus) + 1
|
||||
}
|
||||
cw := 10000
|
||||
cw := 3000
|
||||
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 {
|
||||
if err = canvas.ParseFontFace(data, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -384,7 +386,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back = img.Size(back, backX, backY).Im
|
||||
back = imgfactory.Size(back, backX, backY).Image()
|
||||
}
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, facestart, int(channelStart))
|
||||
@@ -520,12 +522,15 @@ func init() {
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(nim)
|
||||
data, err := imgfactory.ToBytes(nim)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(nim, f)
|
||||
_, err = imgfactory.WriteTo(nim, f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -175,7 +176,19 @@ 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, nil)
|
||||
data, err = web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(infoURL, buid), "GET", func(r *http.Request) error {
|
||||
r.Header.Set("refer", referer)
|
||||
r.Header.Set("user-agent", ua)
|
||||
cookie := ""
|
||||
if cfg != nil {
|
||||
cookie, err = cfg.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
r.Header.Set("cookie", cookie)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ func init() {
|
||||
return "", err
|
||||
}
|
||||
arr := gjson.Get(helper.BytesToString(data), "data.data").Array()
|
||||
if len(arr) == 0 {
|
||||
return "", errors.New("data is empty")
|
||||
}
|
||||
pic := arr[rand.Intn(len(arr))]
|
||||
return pic.String(), nil
|
||||
}, web.GetData, time.Minute)
|
||||
|
||||
@@ -53,7 +53,7 @@ func init() {
|
||||
text := strings.ReplaceAll(cs.Story, "<攻>", gong)
|
||||
text = strings.ReplaceAll(text, "<受>", shou)
|
||||
text = strings.ReplaceAll(text, cs.Gong, gong)
|
||||
text = strings.ReplaceAll(text, cs.Shou, gong)
|
||||
text = strings.ReplaceAll(text, cs.Shou, shou)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
engine.OnPrefix("磕cp", getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
37
plugin/dailynews/dailynews.go
Normal file
37
plugin/dailynews/dailynews.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Package dailynews 今日早报
|
||||
package dailynews
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const api = "http://dwz.2xb.cn/zaob"
|
||||
|
||||
func init() {
|
||||
engine := control.Register("dailynews", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "今日早报",
|
||||
Help: "- 今日早报",
|
||||
PrivateDataFolder: "dailynews",
|
||||
})
|
||||
|
||||
engine.OnFullMatch(`今日早报`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
data, err := web.GetData(api)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image(picURL))
|
||||
})
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -39,7 +39,7 @@ func init() { // 插件主体
|
||||
digest := md5.Sum(helper.StringToBytes(url))
|
||||
f := cachefolder + hex.EncodeToString(digest[:])
|
||||
if file.IsNotExist(f) {
|
||||
_ = writer.SavePNG2Path(f, t)
|
||||
_ = imgfactory.SavePNG2Path(f, t)
|
||||
}
|
||||
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, ","))))
|
||||
|
||||
@@ -8,11 +8,11 @@ import (
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
imgutils "github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text" // jpg png gif
|
||||
_ "golang.org/x/image/webp" // webp
|
||||
)
|
||||
@@ -76,11 +76,11 @@ func tagurl(name, u string) (im image.Image, st *sorttags, err error) {
|
||||
st = newsorttags(tags)
|
||||
sort.Sort(st)
|
||||
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
boldfd, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = file.GetLazyData(text.ConsolasFontFile, control.Md5File, true)
|
||||
consfd, err := file.GetLazyData(text.ConsolasFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -94,19 +94,19 @@ func tagurl(name, u string) (im image.Image, st *sorttags, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
img = imgutils.Limit(img, 1280, 720)
|
||||
img = imgfactory.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 {
|
||||
if err = canvas.ParseFontFace(boldfd, 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 {
|
||||
if err = canvas.ParseFontFace(consfd, float64(img.Bounds().Size().X)*0.04); err != nil {
|
||||
return
|
||||
}
|
||||
rate := float64(img.Bounds().Size().X) * 0.04
|
||||
|
||||
253
plugin/drawlots/main.go
Normal file
253
plugin/drawlots/main.go
Normal file
@@ -0,0 +1,253 @@
|
||||
// Package drawlots 多功能抽签插件
|
||||
package drawlots
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/gif"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
control "github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/fumiama/jieba/util/helper"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type info struct {
|
||||
lotsType string // 文件后缀
|
||||
quantity int // 签数
|
||||
}
|
||||
|
||||
var (
|
||||
lotsList = func() map[string]info {
|
||||
lotsList, err := getList()
|
||||
if err != nil {
|
||||
logrus.Infoln("[drawlots]加载失败:", err)
|
||||
} else {
|
||||
logrus.Infoln("[drawlots]加载", len(lotsList), "个抽签")
|
||||
}
|
||||
return lotsList
|
||||
}()
|
||||
en = control.Register("drawlots", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "多功能抽签",
|
||||
Help: "支持图包文件夹和gif抽签\n" +
|
||||
"-------------\n" +
|
||||
"- (刷新)抽签列表\n- 抽[签名]签\n- 看[gif签名]签\n- 加[签名]签[gif图片]\n- 删[gif签名]签",
|
||||
PrivateDataFolder: "drawlots",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
datapath = file.BOTPATH + "/" + en.DataFolder()
|
||||
)
|
||||
|
||||
func init() {
|
||||
en.OnFullMatchGroup([]string{"抽签列表", "刷新抽签列表"}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
lotsList, err := getList() // 刷新列表
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
messageText := &strings.Builder{}
|
||||
messageText.WriteString(" 签 名 [ 类 型 ]----签数\n")
|
||||
messageText.WriteString("———————————\n")
|
||||
for name, fileInfo := range lotsList {
|
||||
messageText.WriteString(name + "[" + fileInfo.lotsType + "]----" + strconv.Itoa(fileInfo.quantity) + "\n")
|
||||
messageText.WriteString("----------\n")
|
||||
}
|
||||
textPic, err := text.RenderToBase64(messageText.String(), text.BoldFontFile, 400, 50)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + helper.BytesToString(textPic)))
|
||||
})
|
||||
en.OnRegex(`^抽(.+)签$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
lotsType := ctx.State["regex_matched"].([]string)[1]
|
||||
fileInfo, ok := lotsList[lotsType]
|
||||
if !ok {
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("才...才没有", lotsType, "签这种东西啦")))
|
||||
return
|
||||
}
|
||||
if fileInfo.lotsType == "folder" {
|
||||
picPath, err := randFile(lotsType, 3)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("file:///"+picPath))
|
||||
return
|
||||
}
|
||||
lotsImg, err := randGif(lotsType + "." + fileInfo.lotsType)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 生成图片
|
||||
data, err := imgfactory.ToBytes(lotsImg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.ImageBytes(data))
|
||||
})
|
||||
en.OnRegex(`^看(.+)签$`, zero.UserOrGrpAdmin).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.Event.MessageID
|
||||
lotsName := ctx.State["regex_matched"].([]string)[1]
|
||||
fileInfo, ok := lotsList[lotsName]
|
||||
if !ok {
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("才...才没有", lotsName, "签这种东西啦")))
|
||||
return
|
||||
}
|
||||
if fileInfo.lotsType == "folder" {
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("只能查看gif签哦~")))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Image("file:///"+datapath+lotsName+"."+fileInfo.lotsType)))
|
||||
})
|
||||
en.OnRegex(`^加(.+)签.*`, zero.SuperUserPermission, zero.MustProvidePicture).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.Event.MessageID
|
||||
lotsName := ctx.State["regex_matched"].([]string)[1]
|
||||
if lotsName == "" {
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("请使用正确的指令形式哦~")))
|
||||
return
|
||||
}
|
||||
picURL := ctx.State["image_url"].([]string)[0]
|
||||
gifdata, err := web.GetData(picURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
im, err := gif.DecodeAll(bytes.NewReader(gifdata))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
fileName := datapath + "/" + lotsName + ".gif"
|
||||
err = file.DownloadTo(picURL, fileName)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
lotsList[lotsName] = info{
|
||||
lotsType: "gif",
|
||||
quantity: len(im.Image),
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("成功!")))
|
||||
})
|
||||
en.OnRegex(`^删(.+)签$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.Event.MessageID
|
||||
lotsName := ctx.State["regex_matched"].([]string)[1]
|
||||
fileInfo, ok := lotsList[lotsName]
|
||||
if !ok {
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("才...才没有", lotsName, "签这种东西啦")))
|
||||
return
|
||||
}
|
||||
if fileInfo.lotsType == "folder" {
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("为了防止误删图源,图包请手动移除哦~")))
|
||||
return
|
||||
}
|
||||
err := os.Remove(datapath + lotsName + "." + fileInfo.lotsType)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
delete(lotsList, lotsName)
|
||||
ctx.Send(message.ReplyWithMessage(id, message.Text("成功!")))
|
||||
})
|
||||
}
|
||||
|
||||
func getList() (list map[string]info, err error) {
|
||||
list = make(map[string]info, 100)
|
||||
files, err := os.ReadDir(datapath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(files) == 0 {
|
||||
err = errors.New("什么签也没有哦~")
|
||||
return
|
||||
}
|
||||
for _, lots := range files {
|
||||
if lots.IsDir() {
|
||||
files, _ := os.ReadDir(datapath + "/" + lots.Name())
|
||||
list[lots.Name()] = info{
|
||||
lotsType: "folder",
|
||||
quantity: len(files),
|
||||
}
|
||||
continue
|
||||
}
|
||||
before, after, ok := strings.Cut(lots.Name(), ".")
|
||||
if !ok || before == "" {
|
||||
continue
|
||||
}
|
||||
file, err := os.Open(datapath + "/" + lots.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
im, err := gif.DecodeAll(file)
|
||||
_ = file.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list[before] = info{
|
||||
lotsType: after,
|
||||
quantity: len(im.Image),
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func randFile(path string, indexMax int) (string, error) {
|
||||
picPath := datapath + path
|
||||
files, err := os.ReadDir(picPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(files) > 0 {
|
||||
drawFile := files[rand.Intn(len(files))]
|
||||
// 如果是文件夹就递归
|
||||
if drawFile.IsDir() {
|
||||
indexMax--
|
||||
if indexMax <= 0 {
|
||||
return "", errors.New("图包[" + path + "]存在太多非图片文件,请清理~")
|
||||
}
|
||||
return randFile(path, indexMax)
|
||||
}
|
||||
return picPath + "/" + drawFile.Name(), err
|
||||
}
|
||||
return "", errors.New("图包[" + path + "]不存在签内容!")
|
||||
}
|
||||
|
||||
func randGif(gifName string) (image.Image, error) {
|
||||
name := datapath + gifName
|
||||
file, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
im, err := gif.DecodeAll(file)
|
||||
_ = file.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
firstImg, err := imgfactory.Load(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.Size(firstImg, firstImg.Bounds().Dx(), firstImg.Bounds().Dy()).InsertUpC(v, 0, 0, firstImg.Bounds().Dx()/2, firstImg.Bounds().Dy()/2).Clone().Image(),err
|
||||
/*/
|
||||
// 如果gif图片出现信息缺失请使用上面注释掉的代码,把下面注释了(上面代码部分图存在bug)
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.NewFactoryBG(v.Rect.Dx(), v.Rect.Dy(), color.NRGBA{0, 0, 0, 255}).InsertUp(v, 0, 0, 0, 0).Clone().Image(), err
|
||||
// */
|
||||
}
|
||||
@@ -2,7 +2,17 @@
|
||||
package font
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/gif"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -15,10 +25,10 @@ func init() {
|
||||
control.Register("font", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "渲染任意文字到图片",
|
||||
Help: "- (用[字体])渲染文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体]",
|
||||
}).OnRegex(`^(用.+)?渲染文字([\s\S]+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
Help: "- (用[字体])渲染(抖动)文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|粗苹方体|未来荧黑体|Gugi体|八丸体|Impact体|猫啃体|苹方体]",
|
||||
}).OnRegex(`^(用.+)?渲染(抖动)?文字([\s\S]+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
fnt := ctx.State["regex_matched"].([]string)[1]
|
||||
txt := ctx.State["regex_matched"].([]string)[2]
|
||||
txt := ctx.State["regex_matched"].([]string)[3]
|
||||
switch fnt {
|
||||
case "用终末体":
|
||||
fnt = text.SyumatuFontFile
|
||||
@@ -30,16 +40,73 @@ func init() {
|
||||
fnt = text.SakuraFontFile
|
||||
case "用Consolas体":
|
||||
fnt = text.ConsolasFontFile
|
||||
case "用粗苹方体":
|
||||
fnt = text.BoldFontFile
|
||||
case "用未来荧黑体":
|
||||
fnt = text.GlowSansFontFile
|
||||
case "用Gugi体":
|
||||
fnt = text.GugiRegularFontFile
|
||||
case "用八丸体":
|
||||
fnt = text.HachiMaruPopRegularFontFile
|
||||
case "用Impact体":
|
||||
fnt = text.ImpactFontFile
|
||||
case "用猫啃体":
|
||||
fnt = text.MaokenFontFile
|
||||
case "用苹方体":
|
||||
fallthrough
|
||||
default:
|
||||
fnt = text.FontFile
|
||||
}
|
||||
b, err := text.RenderToBase64(txt, fnt, 400, 20)
|
||||
if ctx.State["regex_matched"].([]string)[2] == "" {
|
||||
b, err := text.RenderToBase64(txt, fnt, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
return
|
||||
}
|
||||
nilx, nily := 1.0, 8.0
|
||||
s := []*image.NRGBA{}
|
||||
strlist := strings.Split(txt, "\n")
|
||||
data, err := file.GetLazyData(fnt, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
// 获得画布预计
|
||||
testcov := gg.NewContext(1, 1)
|
||||
if err = testcov.ParseFontFace(data, 30); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 取最长段
|
||||
txt = ""
|
||||
for _, v := range strlist {
|
||||
if len([]rune(v)) > len([]rune(txt)) {
|
||||
txt = v
|
||||
}
|
||||
}
|
||||
w, h := testcov.MeasureString(txt)
|
||||
for i := 0; i < 10; i++ {
|
||||
cov := gg.NewContext(int(w+float64(len([]rune(txt)))*nilx)+40, int(h+nily)*len(strlist)+30)
|
||||
cov.SetRGB(1, 1, 1)
|
||||
cov.Clear()
|
||||
if err = cov.ParseFontFace(data, 30); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
cov.SetColor(color.NRGBA{R: 0, G: 0, B: 0, A: 127})
|
||||
for k, v := range strlist {
|
||||
for kk, vv := range []rune(v) {
|
||||
x, y := cov.MeasureString(string([]rune(v)[:kk]))
|
||||
cov.DrawString(string(vv), x+float64(rand.Intn(5))+10+nilx, y+float64(rand.Intn(5))+15+float64(k)*(y+nily))
|
||||
}
|
||||
}
|
||||
s = append(s, imgfactory.Size(cov.Image(), 0, 0).Image())
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
_ = gif.EncodeAll(&buf, imgfactory.MergeGif(5, s))
|
||||
ctx.SendChain(message.ImageBytes(buf.Bytes()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Coloured-glaze/gg" // 注册了 jpg png gif
|
||||
"github.com/FloatTech/gg" // 注册了 jpg png gif
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
@@ -19,7 +20,6 @@ import (
|
||||
|
||||
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"
|
||||
@@ -32,8 +32,6 @@ const (
|
||||
images = "data/Fortune/"
|
||||
// 基础文件位置
|
||||
omikujson = "data/Fortune/text.json"
|
||||
// 字体文件位置
|
||||
font = "data/Font/sakura.ttf"
|
||||
// 生成图缓存位置
|
||||
cache = images + "cache/"
|
||||
)
|
||||
@@ -45,6 +43,7 @@ var (
|
||||
index = make(map[string]uint8)
|
||||
// 签文
|
||||
omikujis []map[string]string
|
||||
fontdata []byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -100,10 +99,12 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
_, err = file.GetLazyData(font, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
if fontdata == nil {
|
||||
fontdata, err = file.GetLazyData("data/Font/sakura.ttf", control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
@@ -150,7 +151,7 @@ func init() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = draw(background, title, text, f)
|
||||
_, err = draw(background, fontdata, title, text, f)
|
||||
_ = f.Close()
|
||||
return err
|
||||
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))
|
||||
@@ -189,19 +190,19 @@ func randimage(path string, ctx *zero.Ctx) (im image.Image, index int, err error
|
||||
// @param title 签名
|
||||
// @param text 签文
|
||||
// @return 错误信息
|
||||
func draw(back image.Image, title, txt string, f io.Writer) (int64, error) {
|
||||
func draw(back image.Image, fontdata []byte, title, txt string, f io.Writer) (int64, error) {
|
||||
canvas := gg.NewContext(back.Bounds().Size().Y, back.Bounds().Size().X)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
// 写标题
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
if err := canvas.LoadFontFace(font, 45); err != nil {
|
||||
if err := canvas.ParseFontFace(fontdata, 45); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
sw, _ := canvas.MeasureString(title)
|
||||
canvas.DrawString(title, 140-sw/2, 112)
|
||||
// 写正文
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
if err := canvas.LoadFontFace(font, 23); err != nil {
|
||||
if err := canvas.ParseFontFace(fontdata, 23); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
tw, th := canvas.MeasureString("测")
|
||||
@@ -230,7 +231,7 @@ func draw(back image.Image, title, txt string, f io.Writer) (int64, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return writer.WriteTo(canvas.Image(), f)
|
||||
return imgfactory.WriteTo(canvas.Image(), f)
|
||||
}
|
||||
|
||||
func offest(total, now int, distance float64) float64 {
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -100,7 +100,11 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
b, cl := writer.ToBytes(img)
|
||||
b, err := imgfactory.ToBytes(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if mode {
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("恭喜你抽到了: \n", str), message.ImageBytes(b)))
|
||||
@@ -108,7 +112,6 @@ func init() {
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text("十连成功~"), message.ImageBytes(b)))
|
||||
}
|
||||
cl()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -97,10 +97,10 @@ func newContext(user int64) *context {
|
||||
return c
|
||||
}
|
||||
|
||||
func loadFirstFrames(paths []string, size int) (imgs []*img.Factory, err error) {
|
||||
imgs = make([]*img.Factory, size)
|
||||
func loadFirstFrames(paths []string, size int) (imgs []*imgfactory.Factory, err error) {
|
||||
imgs = make([]*imgfactory.Factory, size)
|
||||
for i := range imgs {
|
||||
imgs[i], err = img.LoadFirstFrame(paths[i], 0, 0)
|
||||
imgs[i], err = imgfactory.LoadFirstFrame(paths[i], 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -6,11 +6,10 @@ import (
|
||||
"image/color"
|
||||
"sync"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
@@ -39,13 +38,13 @@ func mo(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
mo := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 80, 80, 32, 32).Im,
|
||||
imgs[1].InsertBottom(tou, 70, 90, 42, 22).Im,
|
||||
imgs[2].InsertBottom(tou, 75, 85, 37, 27).Im,
|
||||
imgs[3].InsertBottom(tou, 85, 75, 27, 37).Im,
|
||||
imgs[4].InsertBottom(tou, 90, 70, 22, 42).Im,
|
||||
imgs[0].InsertBottom(tou, 80, 80, 32, 32).Image(),
|
||||
imgs[1].InsertBottom(tou, 70, 90, 42, 22).Image(),
|
||||
imgs[2].InsertBottom(tou, 75, 85, 37, 27).Image(),
|
||||
imgs[3].InsertBottom(tou, 85, 75, 27, 37).Image(),
|
||||
imgs[4].InsertBottom(tou, 90, 70, 22, 42).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(1, mo))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, mo))
|
||||
}
|
||||
|
||||
// cuo 搓
|
||||
@@ -64,10 +63,10 @@ func cuo(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
m1 := img.Rotate(tou, 72, 0, 0)
|
||||
m2 := img.Rotate(tou, 144, 0, 0)
|
||||
m3 := img.Rotate(tou, 216, 0, 0)
|
||||
m4 := img.Rotate(tou, 288, 0, 0)
|
||||
m1 := imgfactory.Rotate(tou, 72, 0, 0)
|
||||
m2 := imgfactory.Rotate(tou, 144, 0, 0)
|
||||
m3 := imgfactory.Rotate(tou, 216, 0, 0)
|
||||
m4 := imgfactory.Rotate(tou, 288, 0, 0)
|
||||
wg.Wait()
|
||||
if errwg != nil {
|
||||
return "", errwg
|
||||
@@ -77,13 +76,13 @@ func cuo(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
cuo := []*image.NRGBA{
|
||||
imgs[0].InsertBottomC(tou, 0, 0, 75, 130).Im,
|
||||
imgs[1].InsertBottomC(m1.Im, 0, 0, 75, 130).Im,
|
||||
imgs[2].InsertBottomC(m2.Im, 0, 0, 75, 130).Im,
|
||||
imgs[3].InsertBottomC(m3.Im, 0, 0, 75, 130).Im,
|
||||
imgs[4].InsertBottomC(m4.Im, 0, 0, 75, 130).Im,
|
||||
imgs[0].InsertBottomC(tou, 0, 0, 75, 130).Image(),
|
||||
imgs[1].InsertBottomC(m1.Image(), 0, 0, 75, 130).Image(),
|
||||
imgs[2].InsertBottomC(m2.Image(), 0, 0, 75, 130).Image(),
|
||||
imgs[3].InsertBottomC(m3.Image(), 0, 0, 75, 130).Image(),
|
||||
imgs[4].InsertBottomC(m4.Image(), 0, 0, 75, 130).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(5, cuo))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(5, cuo))
|
||||
}
|
||||
|
||||
// qiao 敲
|
||||
@@ -111,10 +110,10 @@ func qiao(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
qiao := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 40, 33, 57, 52).Im,
|
||||
imgs[1].InsertUp(tou, 38, 36, 58, 50).Im,
|
||||
imgs[0].InsertUp(tou, 40, 33, 57, 52).Image(),
|
||||
imgs[1].InsertUp(tou, 38, 36, 58, 50).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(1, qiao))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, qiao))
|
||||
}
|
||||
|
||||
// chi 吃
|
||||
@@ -142,11 +141,11 @@ func chi(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
chi := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 0, 0, 1, 38).Im,
|
||||
imgs[1].InsertBottom(tou, 0, 0, 1, 38).Im,
|
||||
imgs[2].InsertBottom(tou, 0, 0, 1, 38).Im,
|
||||
imgs[0].InsertBottom(tou, 0, 0, 1, 38).Image(),
|
||||
imgs[1].InsertBottom(tou, 0, 0, 1, 38).Image(),
|
||||
imgs[2].InsertBottom(tou, 0, 0, 1, 38).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(1, chi))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, chi))
|
||||
}
|
||||
|
||||
// ceng 蹭
|
||||
@@ -178,14 +177,14 @@ func ceng(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
ceng := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 75, 77, 40, 88).InsertUp(tou2, 77, 103, 102, 81).Im,
|
||||
imgs[1].InsertUp(tou, 75, 77, 46, 100).InsertUp(img.Rotate(tou2, 10, 62, 127).Im, 0, 0, 92, 40).Im,
|
||||
imgs[2].InsertUp(tou, 75, 77, 67, 99).InsertUp(tou2, 76, 117, 90, 8).Im,
|
||||
imgs[3].InsertUp(tou, 75, 77, 52, 83).InsertUp(img.Rotate(tou2, -40, 94, 94).Im, 0, 0, 53, -20).Im,
|
||||
imgs[4].InsertUp(tou, 75, 77, 56, 110).InsertUp(img.Rotate(tou2, -66, 132, 80).Im, 0, 0, 78, 40).Im,
|
||||
imgs[5].InsertUp(tou, 75, 77, 62, 102).InsertUp(tou2, 71, 100, 110, 94).Im,
|
||||
imgs[0].InsertUp(tou, 75, 77, 40, 88).InsertUp(tou2, 77, 103, 102, 81).Image(),
|
||||
imgs[1].InsertUp(tou, 75, 77, 46, 100).InsertUp(imgfactory.Rotate(tou2, 10, 62, 127).Image(), 0, 0, 92, 40).Image(),
|
||||
imgs[2].InsertUp(tou, 75, 77, 67, 99).InsertUp(tou2, 76, 117, 90, 8).Image(),
|
||||
imgs[3].InsertUp(tou, 75, 77, 52, 83).InsertUp(imgfactory.Rotate(tou2, -40, 94, 94).Image(), 0, 0, 53, -20).Image(),
|
||||
imgs[4].InsertUp(tou, 75, 77, 56, 110).InsertUp(imgfactory.Rotate(tou2, -66, 132, 80).Image(), 0, 0, 78, 40).Image(),
|
||||
imgs[5].InsertUp(tou, 75, 77, 62, 102).InsertUp(tou2, 71, 100, 110, 94).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, ceng))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, ceng))
|
||||
}
|
||||
|
||||
// ken 啃
|
||||
@@ -213,24 +212,24 @@ func ken(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
ken := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 90, 90, 105, 150).Im,
|
||||
imgs[1].InsertBottom(tou, 90, 83, 96, 172).Im,
|
||||
imgs[2].InsertBottom(tou, 90, 90, 106, 148).Im,
|
||||
imgs[3].InsertBottom(tou, 88, 88, 97, 167).Im,
|
||||
imgs[4].InsertBottom(tou, 90, 85, 89, 179).Im,
|
||||
imgs[5].InsertBottom(tou, 90, 90, 106, 151).Im,
|
||||
imgs[6].Im,
|
||||
imgs[7].Im,
|
||||
imgs[8].Im,
|
||||
imgs[9].Im,
|
||||
imgs[10].Im,
|
||||
imgs[11].Im,
|
||||
imgs[12].Im,
|
||||
imgs[13].Im,
|
||||
imgs[14].Im,
|
||||
imgs[15].Im,
|
||||
imgs[0].InsertBottom(tou, 90, 90, 105, 150).Image(),
|
||||
imgs[1].InsertBottom(tou, 90, 83, 96, 172).Image(),
|
||||
imgs[2].InsertBottom(tou, 90, 90, 106, 148).Image(),
|
||||
imgs[3].InsertBottom(tou, 88, 88, 97, 167).Image(),
|
||||
imgs[4].InsertBottom(tou, 90, 85, 89, 179).Image(),
|
||||
imgs[5].InsertBottom(tou, 90, 90, 106, 151).Image(),
|
||||
imgs[6].Image(),
|
||||
imgs[7].Image(),
|
||||
imgs[8].Image(),
|
||||
imgs[9].Image(),
|
||||
imgs[10].Image(),
|
||||
imgs[11].Image(),
|
||||
imgs[12].Image(),
|
||||
imgs[13].Image(),
|
||||
imgs[14].Image(),
|
||||
imgs[15].Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, ken))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ken))
|
||||
}
|
||||
|
||||
// pai 拍
|
||||
@@ -258,10 +257,10 @@ func pai(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
pai := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 0, 0, 1, 47).Im,
|
||||
imgs[1].InsertUp(tou, 0, 0, 1, 67).Im,
|
||||
imgs[0].InsertUp(tou, 0, 0, 1, 47).Image(),
|
||||
imgs[1].InsertUp(tou, 0, 0, 1, 67).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(1, pai))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, pai))
|
||||
}
|
||||
|
||||
// xqe 冲
|
||||
@@ -289,10 +288,10 @@ func xqe(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
chong := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 30, 30, 15, 53).Im,
|
||||
imgs[1].InsertUp(tou, 30, 30, 40, 53).Im,
|
||||
imgs[0].InsertUp(tou, 30, 30, 15, 53).Image(),
|
||||
imgs[1].InsertUp(tou, 30, 30, 40, 53).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(1, chong))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(1, chong))
|
||||
}
|
||||
|
||||
// diu 丢
|
||||
@@ -320,16 +319,16 @@ func diu(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
diu := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 32, 32, 108, 36).Im,
|
||||
imgs[1].InsertUp(tou, 32, 32, 122, 36).Im,
|
||||
imgs[2].Im,
|
||||
imgs[3].InsertUp(tou, 123, 123, 19, 129).Im,
|
||||
imgs[4].InsertUp(tou, 185, 185, -50, 200).InsertUp(tou, 33, 33, 289, 70).Im,
|
||||
imgs[5].InsertUp(tou, 32, 32, 280, 73).Im,
|
||||
imgs[6].InsertUp(tou, 35, 35, 259, 31).Im,
|
||||
imgs[7].InsertUp(tou, 175, 175, -50, 220).Im,
|
||||
imgs[0].InsertUp(tou, 32, 32, 108, 36).Image(),
|
||||
imgs[1].InsertUp(tou, 32, 32, 122, 36).Image(),
|
||||
imgs[2].Image(),
|
||||
imgs[3].InsertUp(tou, 123, 123, 19, 129).Image(),
|
||||
imgs[4].InsertUp(tou, 185, 185, -50, 200).InsertUp(tou, 33, 33, 289, 70).Image(),
|
||||
imgs[5].InsertUp(tou, 32, 32, 280, 73).Image(),
|
||||
imgs[6].InsertUp(tou, 35, 35, 259, 31).Image(),
|
||||
imgs[7].InsertUp(tou, 175, 175, -50, 220).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, diu))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, diu))
|
||||
}
|
||||
|
||||
// kiss 亲
|
||||
@@ -366,9 +365,9 @@ func kiss(cc *context, value ...string) (string, error) {
|
||||
kiss := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
kiss[i] = imgs[i].InsertUp(tou, 50, 50, userLocs[i][0], userLocs[i][1]).
|
||||
InsertUp(tou2, 40, 40, selfLocs[i][0], selfLocs[i][1]).Im
|
||||
InsertUp(tou2, 40, 40, selfLocs[i][0], selfLocs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, kiss))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, kiss))
|
||||
}
|
||||
|
||||
// garbage 垃圾 垃圾桶
|
||||
@@ -388,7 +387,7 @@ func garbage(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 79, 79)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 79, 79)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -399,9 +398,9 @@ func garbage(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
garbage := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
garbage[i] = imgs[i].InsertBottom(im.Im, 0, 0, locs[i][0], locs[i][1]).Im
|
||||
garbage[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, garbage))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, garbage))
|
||||
}
|
||||
|
||||
// thump 捶
|
||||
@@ -421,7 +420,7 @@ func thump(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -432,9 +431,9 @@ func thump(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
thump := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
thump[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
thump[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, thump))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, thump))
|
||||
}
|
||||
|
||||
// jiujiu 啾啾
|
||||
@@ -454,7 +453,7 @@ func jiujiu(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 75, 51)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 75, 51)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -464,9 +463,9 @@ func jiujiu(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
jiujiu := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
jiujiu[i] = imgs[i].InsertBottom(im.Im, 0, 0, 0, 0).Im
|
||||
jiujiu[i] = imgs[i].InsertBottom(im.Image(), 0, 0, 0, 0).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, jiujiu))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, jiujiu))
|
||||
}
|
||||
|
||||
// knock 2敲
|
||||
@@ -486,7 +485,7 @@ func knock(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -497,9 +496,9 @@ func knock(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
knock := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
knock[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
knock[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, knock))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, knock))
|
||||
}
|
||||
|
||||
// 听音乐 listenMusic
|
||||
@@ -529,9 +528,9 @@ func listenMusic(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
listenmusic := make([]*image.NRGBA, 36)
|
||||
for i := 0; i < 36; i++ {
|
||||
listenmusic[i] = imgs[0].InsertBottomC(img.Rotate(face, float64(-i*10), 215, 215).Im, 0, 0, 207, 207).Im
|
||||
listenmusic[i] = imgs[0].InsertBottomC(imgfactory.Rotate(face, float64(-i*10), 215, 215).Image(), 0, 0, 207, 207).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, listenmusic))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, listenmusic))
|
||||
}
|
||||
|
||||
// loveYou 永远爱你
|
||||
@@ -551,7 +550,7 @@ func loveYou(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -562,9 +561,9 @@ func loveYou(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
loveyou := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
loveyou[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
loveyou[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, loveyou))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, loveyou))
|
||||
}
|
||||
|
||||
// pat 2拍
|
||||
@@ -584,7 +583,7 @@ func pat(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -596,9 +595,9 @@ func pat(cc *context, value ...string) (string, error) {
|
||||
p := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
if i == 2 {
|
||||
p[i] = imgs[i].InsertBottom(im.Im, locs[1][2], locs[1][3], locs[1][0], locs[1][1]).Im
|
||||
p[i] = imgs[i].InsertBottom(im.Image(), locs[1][2], locs[1][3], locs[1][0], locs[1][1]).Image()
|
||||
} else {
|
||||
p[i] = imgs[i].InsertBottom(im.Im, locs[0][2], locs[0][3], locs[0][0], locs[0][1]).Im
|
||||
p[i] = imgs[i].InsertBottom(im.Image(), locs[0][2], locs[0][3], locs[0][0], locs[0][1]).Image()
|
||||
}
|
||||
}
|
||||
seq := []int{0, 1, 2, 3, 1, 2, 3, 0, 1, 2, 3, 0, 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 5, 5, 6, 7, 8, 9}
|
||||
@@ -606,7 +605,7 @@ func pat(cc *context, value ...string) (string, error) {
|
||||
for i := 0; i < len(pat); i++ {
|
||||
pat[i] = p[seq[i]]
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, pat))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, pat))
|
||||
}
|
||||
|
||||
// jackUp 顶
|
||||
@@ -626,7 +625,7 @@ func jackUp(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -638,9 +637,9 @@ func jackUp(cc *context, value ...string) (string, error) {
|
||||
p := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
if i < len(locs) {
|
||||
p[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
p[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
} else {
|
||||
p[i] = imgs[i].Im
|
||||
p[i] = imgs[i].Image()
|
||||
}
|
||||
}
|
||||
play := make([]*image.NRGBA, 0, 16)
|
||||
@@ -649,7 +648,7 @@ func jackUp(cc *context, value ...string) (string, error) {
|
||||
play = append(play, p[0:8]...)
|
||||
play = append(play, p[12:18]...)
|
||||
play = append(play, p[18:23]...)
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, play))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, play))
|
||||
}
|
||||
|
||||
// pound 捣
|
||||
@@ -669,7 +668,7 @@ func pound(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -680,9 +679,9 @@ func pound(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
pound := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
pound[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
pound[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, pound))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, pound))
|
||||
}
|
||||
|
||||
// punch 打拳
|
||||
@@ -702,7 +701,7 @@ func punch(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 260, 260)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 260, 260)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -713,9 +712,9 @@ func punch(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
punch := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
punch[i] = imgs[i].InsertBottom(im.Im, 0, 0, locs[i][0], locs[i][1]-15).Im
|
||||
punch[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]-15).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, punch))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, punch))
|
||||
}
|
||||
|
||||
// roll 滚
|
||||
@@ -735,7 +734,7 @@ func roll(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 210, 210)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 210, 210)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -746,9 +745,9 @@ func roll(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
roll := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
roll[i] = imgs[i].InsertBottomC(img.Rotate(im.Im, float64(locs[i][2]), 0, 0).Im, 0, 0, locs[i][0]+105, locs[i][1]+105).Im
|
||||
roll[i] = imgs[i].InsertBottomC(imgfactory.Rotate(im.Image(), float64(locs[i][2]), 0, 0).Image(), 0, 0, locs[i][0]+105, locs[i][1]+105).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, roll))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, roll))
|
||||
}
|
||||
|
||||
// suck 吸 嗦
|
||||
@@ -768,7 +767,7 @@ func suck(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -779,9 +778,9 @@ func suck(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
suck := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
suck[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
suck[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, suck))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, suck))
|
||||
}
|
||||
|
||||
// hammer 锤
|
||||
@@ -801,7 +800,7 @@ func hammer(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -812,9 +811,9 @@ func hammer(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
hammer := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
hammer[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
hammer[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, hammer))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, hammer))
|
||||
}
|
||||
|
||||
// tightly 紧贴 紧紧贴着
|
||||
@@ -834,7 +833,7 @@ func tightly(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -845,9 +844,9 @@ func tightly(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
tightly := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
tightly[i] = imgs[i].InsertBottom(im.Im, locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Im
|
||||
tightly[i] = imgs[i].InsertBottom(im.Image(), locs[i][2], locs[i][3], locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, tightly))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, tightly))
|
||||
}
|
||||
|
||||
// turn 转
|
||||
@@ -864,9 +863,9 @@ func turn(cc *context, value ...string) (string, error) {
|
||||
canvas.Fill()
|
||||
turn := make([]*image.NRGBA, 36)
|
||||
for i := 0; i < 36; i++ {
|
||||
turn[i] = img.Size(canvas.Image(), 0, 0).InsertUpC(img.Rotate(face, float64(10*i), 250, 250).Im, 0, 0, 125, 125).Im
|
||||
turn[i] = imgfactory.Size(canvas.Image(), 0, 0).InsertUpC(imgfactory.Rotate(face, float64(10*i), 250, 250).Image(), 0, 0, 125, 125).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, turn))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, turn))
|
||||
}
|
||||
|
||||
// taiguan 抬棺
|
||||
@@ -894,28 +893,28 @@ func taiguan(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
taiguan := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 85, 85, 180, 65).Im,
|
||||
imgs[1].InsertUp(tou, 85, 85, 180, 65).Im,
|
||||
imgs[2].InsertUp(tou, 85, 85, 180, 65).Im,
|
||||
imgs[3].InsertUp(tou, 85, 85, 180, 65).Im,
|
||||
imgs[4].InsertUp(tou, 85, 85, 177, 65).Im,
|
||||
imgs[5].InsertUp(tou, 85, 85, 175, 65).Im,
|
||||
imgs[6].InsertUp(tou, 85, 85, 173, 65).Im,
|
||||
imgs[7].InsertUp(tou, 85, 85, 171, 65).Im,
|
||||
imgs[8].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[9].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[10].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[11].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[12].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[13].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[14].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[15].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[16].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[17].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[18].InsertUp(tou, 85, 85, 170, 65).Im,
|
||||
imgs[19].InsertUp(tou, 85, 85, 175, 65).Im,
|
||||
imgs[0].InsertUp(tou, 85, 85, 180, 65).Image(),
|
||||
imgs[1].InsertUp(tou, 85, 85, 180, 65).Image(),
|
||||
imgs[2].InsertUp(tou, 85, 85, 180, 65).Image(),
|
||||
imgs[3].InsertUp(tou, 85, 85, 180, 65).Image(),
|
||||
imgs[4].InsertUp(tou, 85, 85, 177, 65).Image(),
|
||||
imgs[5].InsertUp(tou, 85, 85, 175, 65).Image(),
|
||||
imgs[6].InsertUp(tou, 85, 85, 173, 65).Image(),
|
||||
imgs[7].InsertUp(tou, 85, 85, 171, 65).Image(),
|
||||
imgs[8].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[9].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[10].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[11].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[12].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[13].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[14].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[15].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[16].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[17].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[18].InsertUp(tou, 85, 85, 170, 65).Image(),
|
||||
imgs[19].InsertUp(tou, 85, 85, 175, 65).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, taiguan))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, taiguan))
|
||||
}
|
||||
|
||||
// zou 揍
|
||||
@@ -947,11 +946,11 @@ func zou(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
zou := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 40, 40, 98, 138).InsertUp(tou2, 55, 55, 100, 45).Im,
|
||||
imgs[1].InsertUp(tou, 40, 40, 98, 138).InsertUp(tou2, 55, 55, 101, 45).Im,
|
||||
imgs[2].InsertUp(tou, 40, 40, 89, 140).InsertUp(tou2, 55, 55, 99, 40).Im,
|
||||
imgs[0].InsertUp(tou, 40, 40, 98, 138).InsertUp(tou2, 55, 55, 100, 45).Image(),
|
||||
imgs[1].InsertUp(tou, 40, 40, 98, 138).InsertUp(tou2, 55, 55, 101, 45).Image(),
|
||||
imgs[2].InsertUp(tou, 40, 40, 89, 140).InsertUp(tou2, 55, 55, 99, 40).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, zou))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, zou))
|
||||
}
|
||||
|
||||
// ci 吞
|
||||
@@ -979,34 +978,34 @@ func ci(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
ci := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 25, 25, 25, 57).Im,
|
||||
imgs[1].InsertBottom(tou, 25, 25, 27, 58).Im,
|
||||
imgs[2].InsertBottom(tou, 25, 25, 28, 57).Im,
|
||||
imgs[3].InsertBottom(tou, 25, 25, 30, 57).Im,
|
||||
imgs[4].InsertBottom(tou, 25, 25, 30, 58).Im,
|
||||
imgs[5].InsertBottom(tou, 25, 25, 30, 59).Im,
|
||||
imgs[6].Im,
|
||||
imgs[7].Im,
|
||||
imgs[8].Im,
|
||||
imgs[9].Im,
|
||||
imgs[10].Im,
|
||||
imgs[11].Im,
|
||||
imgs[12].Im,
|
||||
imgs[13].Im,
|
||||
imgs[14].Im,
|
||||
imgs[15].Im,
|
||||
imgs[16].Im,
|
||||
imgs[17].Im,
|
||||
imgs[18].Im,
|
||||
imgs[19].Im,
|
||||
imgs[20].Im,
|
||||
imgs[21].Im,
|
||||
imgs[22].Im,
|
||||
imgs[23].Im,
|
||||
imgs[24].Im,
|
||||
imgs[25].Im,
|
||||
imgs[0].InsertBottom(tou, 25, 25, 25, 57).Image(),
|
||||
imgs[1].InsertBottom(tou, 25, 25, 27, 58).Image(),
|
||||
imgs[2].InsertBottom(tou, 25, 25, 28, 57).Image(),
|
||||
imgs[3].InsertBottom(tou, 25, 25, 30, 57).Image(),
|
||||
imgs[4].InsertBottom(tou, 25, 25, 30, 58).Image(),
|
||||
imgs[5].InsertBottom(tou, 25, 25, 30, 59).Image(),
|
||||
imgs[6].Image(),
|
||||
imgs[7].Image(),
|
||||
imgs[8].Image(),
|
||||
imgs[9].Image(),
|
||||
imgs[10].Image(),
|
||||
imgs[11].Image(),
|
||||
imgs[12].Image(),
|
||||
imgs[13].Image(),
|
||||
imgs[14].Image(),
|
||||
imgs[15].Image(),
|
||||
imgs[16].Image(),
|
||||
imgs[17].Image(),
|
||||
imgs[18].Image(),
|
||||
imgs[19].Image(),
|
||||
imgs[20].Image(),
|
||||
imgs[21].Image(),
|
||||
imgs[22].Image(),
|
||||
imgs[23].Image(),
|
||||
imgs[24].Image(),
|
||||
imgs[25].Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, ci))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ci))
|
||||
}
|
||||
|
||||
// worship 膜拜
|
||||
@@ -1034,17 +1033,17 @@ func worship(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
worship := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[1].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[2].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[3].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[4].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[5].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[6].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[7].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[8].InsertBottom(face, 140, 140, 0, 0).Im,
|
||||
imgs[0].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[1].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[2].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[3].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[4].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[5].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[6].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[7].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
imgs[8].InsertBottom(face, 140, 140, 0, 0).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, worship))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, worship))
|
||||
}
|
||||
|
||||
// 2ceng 2蹭
|
||||
@@ -1072,12 +1071,12 @@ func ceng2(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
ceng2 := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 175, 175, 78, 263).Im,
|
||||
imgs[1].InsertBottom(tou, 175, 175, 78, 263).Im,
|
||||
imgs[2].InsertBottom(tou, 175, 175, 78, 263).Im,
|
||||
imgs[3].InsertBottom(tou, 175, 175, 78, 263).Im,
|
||||
imgs[0].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
imgs[1].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
imgs[2].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
imgs[3].InsertBottom(tou, 175, 175, 78, 263).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, ceng2))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, ceng2))
|
||||
}
|
||||
|
||||
// dun 炖
|
||||
@@ -1105,13 +1104,13 @@ func dun(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
dun := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 80, 80, 85, 45).Im,
|
||||
imgs[1].InsertBottom(tou, 80, 80, 85, 45).Im,
|
||||
imgs[2].InsertBottom(tou, 80, 80, 85, 45).Im,
|
||||
imgs[3].InsertBottom(tou, 80, 80, 85, 45).Im,
|
||||
imgs[4].InsertBottom(tou, 80, 80, 85, 45).Im,
|
||||
imgs[0].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
imgs[1].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
imgs[2].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
imgs[3].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
imgs[4].InsertBottom(tou, 80, 80, 85, 45).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, dun))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, dun))
|
||||
}
|
||||
|
||||
// push 滚高清重置版 过渡
|
||||
@@ -1141,9 +1140,9 @@ func push(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
push := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
push[i] = imgs[i].InsertUpC(img.Rotate(tou, float64(-22*i), 280, 280).Im, 0, 0, 523, 291).Im
|
||||
push[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-22*i), 280, 280).Image(), 0, 0, 523, 291).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, push))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, push))
|
||||
}
|
||||
|
||||
// peng 砰
|
||||
@@ -1162,10 +1161,10 @@ func peng(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
m1 := img.Rotate(tou, 1, 80, 80)
|
||||
m2 := img.Rotate(tou, 30, 80, 80)
|
||||
m3 := img.Rotate(tou, 45, 85, 85)
|
||||
m4 := img.Rotate(tou, 90, 80, 80)
|
||||
m1 := imgfactory.Rotate(tou, 1, 80, 80)
|
||||
m2 := imgfactory.Rotate(tou, 30, 80, 80)
|
||||
m3 := imgfactory.Rotate(tou, 45, 85, 85)
|
||||
m4 := imgfactory.Rotate(tou, 90, 80, 80)
|
||||
wg.Wait()
|
||||
if errwg != nil {
|
||||
return "", errwg
|
||||
@@ -1175,33 +1174,33 @@ func peng(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
peng := []*image.NRGBA{
|
||||
imgs[0].Im,
|
||||
imgs[1].Im,
|
||||
imgs[2].Im,
|
||||
imgs[3].Im,
|
||||
imgs[4].Im,
|
||||
imgs[5].Im,
|
||||
imgs[6].Im,
|
||||
imgs[7].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[8].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[9].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[10].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[11].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[12].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[13].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[14].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[15].InsertUp(m1.Im, 0, 0, 205, 80).Im,
|
||||
imgs[16].InsertUp(m1.Im, 0, 0, 200, 80).Im,
|
||||
imgs[17].InsertUp(m2.Im, 0, 0, 169, 65).Im,
|
||||
imgs[18].InsertUp(m2.Im, 0, 0, 160, 69).Im,
|
||||
imgs[19].InsertUp(m3.Im, 0, 0, 113, 90).Im,
|
||||
imgs[20].InsertUp(m4.Im, 0, 0, 89, 159).Im,
|
||||
imgs[21].InsertUp(m4.Im, 0, 0, 89, 159).Im,
|
||||
imgs[22].InsertUp(m4.Im, 0, 0, 86, 160).Im,
|
||||
imgs[23].InsertUp(m4.Im, 0, 0, 89, 159).Im,
|
||||
imgs[24].InsertUp(m4.Im, 0, 0, 86, 160).Im,
|
||||
imgs[0].Image(),
|
||||
imgs[1].Image(),
|
||||
imgs[2].Image(),
|
||||
imgs[3].Image(),
|
||||
imgs[4].Image(),
|
||||
imgs[5].Image(),
|
||||
imgs[6].Image(),
|
||||
imgs[7].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[8].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[9].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[10].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[11].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[12].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[13].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[14].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[15].InsertUp(m1.Image(), 0, 0, 205, 80).Image(),
|
||||
imgs[16].InsertUp(m1.Image(), 0, 0, 200, 80).Image(),
|
||||
imgs[17].InsertUp(m2.Image(), 0, 0, 169, 65).Image(),
|
||||
imgs[18].InsertUp(m2.Image(), 0, 0, 160, 69).Image(),
|
||||
imgs[19].InsertUp(m3.Image(), 0, 0, 113, 90).Image(),
|
||||
imgs[20].InsertUp(m4.Image(), 0, 0, 89, 159).Image(),
|
||||
imgs[21].InsertUp(m4.Image(), 0, 0, 89, 159).Image(),
|
||||
imgs[22].InsertUp(m4.Image(), 0, 0, 86, 160).Image(),
|
||||
imgs[23].InsertUp(m4.Image(), 0, 0, 89, 159).Image(),
|
||||
imgs[24].InsertUp(m4.Image(), 0, 0, 86, 160).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, peng))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, peng))
|
||||
}
|
||||
|
||||
// klee 可莉吃
|
||||
@@ -1221,7 +1220,7 @@ func klee(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 82, 83)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 82, 83)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1232,9 +1231,9 @@ func klee(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
klee := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
klee[i] = imgs[i].InsertBottom(im.Im, 0, 0, locs[i][0], locs[i][1]).Im
|
||||
klee[i] = imgs[i].InsertBottom(im.Image(), 0, 0, locs[i][0], locs[i][1]).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, klee))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, klee))
|
||||
}
|
||||
|
||||
// hutaoken 胡桃啃
|
||||
@@ -1262,10 +1261,10 @@ func hutaoken(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
hutaoken := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(tou, 98, 101, 108, 234).Im,
|
||||
imgs[1].InsertBottom(tou, 96, 100, 108, 237).Im,
|
||||
imgs[0].InsertBottom(tou, 98, 101, 108, 234).Image(),
|
||||
imgs[1].InsertBottom(tou, 96, 100, 108, 237).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, hutaoken))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, hutaoken))
|
||||
}
|
||||
|
||||
// lick 2舔
|
||||
@@ -1293,10 +1292,10 @@ func lick(cc *context, value ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
lick := []*image.NRGBA{
|
||||
imgs[0].InsertUp(tou, 44, 44, 10, 138).Im,
|
||||
imgs[1].InsertUp(tou, 44, 44, 10, 138).Im,
|
||||
imgs[0].InsertUp(tou, 44, 44, 10, 138).Image(),
|
||||
imgs[1].InsertUp(tou, 44, 44, 10, 138).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, lick))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, lick))
|
||||
}
|
||||
|
||||
// tiqiu 踢球
|
||||
@@ -1327,9 +1326,9 @@ func tiqiu(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
tiqiu := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
tiqiu[i] = imgs[i].InsertUpC(img.Rotate(tou, float64(-24*i), 0, 0).Im, 0, 0, locs[i][0]+38, locs[i][1]+38).Im
|
||||
tiqiu[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-24*i), 0, 0).Image(), 0, 0, locs[i][0]+38, locs[i][1]+38).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, tiqiu))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, tiqiu))
|
||||
}
|
||||
|
||||
// cai 踩
|
||||
@@ -1356,15 +1355,15 @@ func cai(cc *context, value ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
m1 := img.Rotate(tou, -20, 130, 80)
|
||||
m1 := imgfactory.Rotate(tou, -20, 130, 80)
|
||||
cai := []*image.NRGBA{
|
||||
imgs[0].InsertBottom(m1.Im, 123, 105, 39, 188).Im,
|
||||
imgs[1].InsertBottom(m1.Im, 123, 105, 39, 188).Im,
|
||||
imgs[2].InsertBottom(tou, 90, 71, 50, 209).Im,
|
||||
imgs[3].InsertBottom(tou, 85, 76, 52, 203).Im,
|
||||
imgs[4].InsertBottom(tou, 88, 82, 49, 198).Im,
|
||||
imgs[0].InsertBottom(m1.Image(), 123, 105, 39, 188).Image(),
|
||||
imgs[1].InsertBottom(m1.Image(), 123, 105, 39, 188).Image(),
|
||||
imgs[2].InsertBottom(tou, 90, 71, 50, 209).Image(),
|
||||
imgs[3].InsertBottom(tou, 85, 76, 52, 203).Image(),
|
||||
imgs[4].InsertBottom(tou, 88, 82, 49, 198).Image(),
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, cai))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, cai))
|
||||
}
|
||||
|
||||
// whir 2转
|
||||
@@ -1394,34 +1393,34 @@ func whirl(cc *context, value ...string) (string, error) {
|
||||
}
|
||||
whirl := make([]*image.NRGBA, piclen)
|
||||
for i := 0; i < piclen; i++ {
|
||||
whirl[i] = imgs[i].InsertUpC(img.Rotate(tou, float64(-24*i), 145, 145).Im, 0, 0, 115, 89).Im
|
||||
whirl[i] = imgs[i].InsertUpC(imgfactory.Rotate(tou, float64(-24*i), 145, 145).Image(), 0, 0, 115, 89).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(7, whirl))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(7, whirl))
|
||||
}
|
||||
|
||||
// always 一直
|
||||
func alwaysDoGif(cc *context, value ...string) (string, error) {
|
||||
_ = value
|
||||
var err error
|
||||
var face []*image.NRGBA
|
||||
var face []*imgfactory.Factory
|
||||
name := cc.usrdir + "AlwaysDo.gif"
|
||||
face, err = img.LoadAllFrames(cc.headimgsdir[0], 500, 500)
|
||||
face, err = imgfactory.LoadAllTrueFrames(cc.headimgsdir[0], 500, 500)
|
||||
if err != nil {
|
||||
// 载入失败尝试载入第一帧
|
||||
face = make([]*image.NRGBA, 0)
|
||||
first, err := img.LoadFirstFrame(cc.headimgsdir[0], 500, 500)
|
||||
face = nil
|
||||
first, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 500, 500)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
face = append(face, first.Im)
|
||||
face = append(face, imgfactory.NewFactory(first.Image()))
|
||||
}
|
||||
canvas := gg.NewContext(500, 600)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = canvas.LoadFontFace(text.BoldFontFile, 40)
|
||||
err = canvas.ParseFontFace(data, 40)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1437,13 +1436,13 @@ func alwaysDoGif(cc *context, value ...string) (string, error) {
|
||||
turn := make([]*image.NRGBA, length)
|
||||
for i, f := range face {
|
||||
canvas := gg.NewContext(500, 600)
|
||||
canvas.DrawImage(f, 0, 0)
|
||||
canvas.DrawImage(f.Image(), 0, 0)
|
||||
canvas.SetColor(color.Black)
|
||||
_ = canvas.LoadFontFace(text.BoldFontFile, 40)
|
||||
_ = canvas.ParseFontFace(data, 40)
|
||||
canvas.DrawString(arg, 280-l, 560)
|
||||
canvas.DrawImage(img.Size(f, 90, 90).Im, 280, 505)
|
||||
canvas.DrawImage(imgfactory.Size(f.Image(), 90, 90).Image(), 280, 505)
|
||||
canvas.DrawString("吗", 370, 560)
|
||||
turn[i] = img.Size(canvas.Image(), 0, 0).Im
|
||||
turn[i] = imgfactory.Size(canvas.Image(), 0, 0).Image()
|
||||
}
|
||||
return "file:///" + name, writer.SaveGIF2Path(name, img.MergeGif(8, turn))
|
||||
return "file:///" + name, imgfactory.SaveGIF2Path(name, imgfactory.MergeGif(8, turn))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
)
|
||||
|
||||
func (cc *context) prepareLogos(s ...string) error {
|
||||
@@ -27,17 +27,17 @@ func (cc *context) prepareLogos(s ...string) error {
|
||||
}
|
||||
|
||||
func (cc *context) getLogo(w int, h int) (*image.NRGBA, error) {
|
||||
frame, err := img.LoadFirstFrame(cc.headimgsdir[0], w, h)
|
||||
frame, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], w, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return frame.Circle(0).Im, nil
|
||||
return frame.Circle(0).Image(), nil
|
||||
}
|
||||
|
||||
func (cc *context) getLogo2(w int, h int) (*image.NRGBA, error) {
|
||||
frame, err := img.LoadFirstFrame(cc.headimgsdir[1], w, h)
|
||||
frame, err := imgfactory.LoadFirstFrame(cc.headimgsdir[1], w, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return frame.Circle(0).Im, nil
|
||||
return frame.Circle(0).Image(), nil
|
||||
}
|
||||
|
||||
@@ -8,11 +8,10 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
@@ -36,11 +35,11 @@ func pa(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgf, err := img.LoadFirstFrame(f, 0, 0)
|
||||
imgf, err := imgfactory.LoadFirstFrame(f, 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgf.InsertUp(tou, 100, 100, 0, 400).Im)
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgf.InsertUp(tou, 100, 100, 0, 400).Image())
|
||||
}
|
||||
|
||||
// si 撕
|
||||
@@ -51,8 +50,8 @@ func si(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
im1 := img.Rotate(tou, 20, 380, 380)
|
||||
im2 := img.Rotate(tou, -12, 380, 380)
|
||||
im1 := imgfactory.Rotate(tou, 20, 380, 380)
|
||||
im2 := imgfactory.Rotate(tou, -12, 380, 380)
|
||||
if file.IsNotExist(datapath + "materials/si") {
|
||||
err = os.MkdirAll(datapath+"materials/si", 0755)
|
||||
if err != nil {
|
||||
@@ -63,11 +62,11 @@ func si(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgf, err := img.LoadFirstFrame(f, 0, 0)
|
||||
imgf, err := imgfactory.LoadFirstFrame(f, 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgf.InsertBottom(im1.Im, im1.W, im1.H, -3, 370).InsertBottom(im2.Im, im2.W, im2.H, 653, 310).Im)
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgf.InsertBottom(im1.Image(), im1.W(), im1.H(), -3, 370).InsertBottom(im2.Image(), im2.W(), im2.H(), 653, 310).Image())
|
||||
}
|
||||
|
||||
// flipV 上翻,下翻
|
||||
@@ -75,12 +74,12 @@ func flipV(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "FlipV.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.FlipV().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.FlipV().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// flipH 左翻,右翻
|
||||
@@ -88,12 +87,12 @@ func flipH(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "FlipH.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.FlipH().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.FlipH().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// invert 反色
|
||||
@@ -101,12 +100,12 @@ func invert(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "Invert.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.Invert().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.Invert().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// blur 反色
|
||||
@@ -114,12 +113,12 @@ func blur(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "Blur.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.Blur(10).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.Blur(10).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// grayscale 灰度
|
||||
@@ -127,12 +126,12 @@ func grayscale(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "Grayscale.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.Grayscale().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.Grayscale().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// invertAndGrayscale 负片
|
||||
@@ -140,12 +139,12 @@ func invertAndGrayscale(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "InvertAndGrayscale.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.Invert().Grayscale().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.Invert().Grayscale().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// convolve3x3 浮雕
|
||||
@@ -153,32 +152,32 @@ func convolve3x3(cc *context, args ...string) (string, error) {
|
||||
_ = args
|
||||
name := cc.usrdir + "Convolve3x3.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.Convolve3x3().Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.Relief().Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// rotate 旋转
|
||||
func rotate(cc *context, args ...string) (string, error) {
|
||||
name := cc.usrdir + "Rotate.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
r, _ := strconv.ParseFloat(args[0], 64)
|
||||
imgnrgba := img.Rotate(im.Im, r, 0, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgfactory.Rotate(im.Image(), r, 0, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// deformation 变形
|
||||
func deformation(cc *context, args ...string) (string, error) {
|
||||
name := cc.usrdir + "Deformation.png"
|
||||
// 加载图片
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -190,8 +189,8 @@ func deformation(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := img.Size(im.Im, w, h).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgfactory.Size(im.Image(), w, h).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// alike 你像个xxx一样
|
||||
@@ -214,12 +213,12 @@ func alike(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Anyasuki.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 82, 69)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 82, 69)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertUp(im.Im, 0, 0, 136, 21).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertUp(im.Image(), 0, 0, 136, 21).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// marriage
|
||||
@@ -242,12 +241,12 @@ func marriage(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Marriage.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 1080, 1080)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 1080, 1080)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.InsertUp(imgs[0].Im, 0, 0, 0, 0).InsertUp(imgs[1].Im, 0, 0, 800, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.InsertUp(imgs[0].Image(), 0, 0, 0, 0).InsertUp(imgs[1].Image(), 0, 0, 800, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// anyasuki 阿尼亚喜欢
|
||||
@@ -275,14 +274,14 @@ func anyasuki(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
canvas := gg.NewContext(475, 540)
|
||||
canvas.DrawImage(img.Size(face, 347, 267).Im, 82, 53)
|
||||
canvas.DrawImage(imgfactory.Size(face, 347, 267).Image(), 82, 53)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 30); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -322,13 +321,13 @@ func alwaysLike(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(830, 599)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(face, 380, 380).Im, 44, 74)
|
||||
canvas.DrawImage(imgfactory.Size(face, 380, 380).Image(), 44, 74)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 56); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 56); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -363,12 +362,12 @@ func decentKiss(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "DecentKiss.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 589, 577)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 589, 577)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.InsertUp(imgs[0].Im, 0, 0, 0, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.InsertUp(imgs[0].Image(), 0, 0, 0, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// chinaFlag 国旗
|
||||
@@ -391,12 +390,12 @@ func chinaFlag(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "ChinaFlag.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 410, 410)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 410, 410)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.InsertUp(imgs[0].Im, 0, 0, 0, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.InsertUp(imgs[0].Image(), 0, 0, 0, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// dontTouch 不要靠近
|
||||
@@ -419,12 +418,12 @@ func dontTouch(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "DontTouch.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 410, 410)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 410, 410)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertUp(im.Im, 148, 148, 46, 238).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertUp(im.Image(), 148, 148, 46, 238).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// universal 万能表情 空白表情
|
||||
@@ -436,13 +435,13 @@ func universal(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
canvas := gg.NewContext(500, 550)
|
||||
canvas.DrawImage(img.Size(face, 500, 500).Im, 0, 0)
|
||||
canvas.DrawImage(imgfactory.Size(face, 500, 500).Image(), 0, 0)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 40); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 40); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -485,15 +484,15 @@ func interview(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
canvas := gg.NewContext(600, 300)
|
||||
canvas.DrawImage(img.Size(face, 124, 124).Im, 100, 50)
|
||||
canvas.DrawImage(imgfactory.Size(face, 124, 124).Image(), 100, 50)
|
||||
canvas.DrawImage(huaji, 376, 50)
|
||||
canvas.DrawImage(microphone, 300, 50)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 40); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 40); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -527,12 +526,12 @@ func need(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Need.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 114, 114)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 114, 114)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 327, 232).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 327, 232).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// paint 这像画吗
|
||||
@@ -555,12 +554,12 @@ func paint(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Paint.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 117, 135)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 117, 135)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 4, 0, 0).Im, 0, 0, 95, 107).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 4, 0, 0).Image(), 0, 0, 95, 107).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// painter 小画家
|
||||
@@ -583,12 +582,12 @@ func painter(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Painter.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 240, 345)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 240, 345)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 125, 91).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 125, 91).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// perfect 完美
|
||||
@@ -611,12 +610,12 @@ func perfect(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Perfect.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 310, 460)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 310, 460)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertUp(im.Im, 0, 0, 313, 64).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertUp(im.Image(), 0, 0, 313, 64).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// playGame 玩游戏
|
||||
@@ -644,14 +643,14 @@ func playGame(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
canvas := gg.NewContext(526, 503)
|
||||
canvas.DrawImage(img.Rotate(face, 10, 225, 160).Im, 161, 117)
|
||||
canvas.DrawImage(imgfactory.Rotate(face, 10, 225, 160).Image(), 161, 117)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 40); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 40); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -685,12 +684,12 @@ func police(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Police.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 245, 245)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 245, 245)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 224, 46).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 224, 46).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// police1 警察
|
||||
@@ -713,12 +712,12 @@ func police1(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Police1.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 60, 75)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 60, 75)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[1].InsertBottom(img.Rotate(im.Im, 16, 0, 0).Im, 0, 0, 37, 291).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[1].InsertBottom(imgfactory.Rotate(im.Image(), 16, 0, 0).Image(), 0, 0, 37, 291).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// prpr 舔 舔屏 prpr
|
||||
@@ -741,12 +740,12 @@ func prpr(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Prpr.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 330, 330)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 330, 330)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 8, 0, 0).Im, 0, 0, 46, 264).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 8, 0, 0).Image(), 0, 0, 46, 264).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// safeSense 安全感
|
||||
@@ -775,13 +774,13 @@ func safeSense(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(430, 478)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(face, 215, 343).Im, 215, 135)
|
||||
canvas.DrawImage(imgfactory.Size(face, 215, 343).Image(), 215, 135)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 30); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -817,12 +816,12 @@ func support(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Support.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 815, 815)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 815, 815)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 23, 0, 0).Im, 0, 0, -172, -17).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 23, 0, 0).Image(), 0, 0, -172, -17).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// thinkwhat 想什么
|
||||
@@ -845,12 +844,12 @@ func thinkwhat(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Thinkwhat.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 530, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 530, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// wallpaper 墙纸
|
||||
@@ -873,12 +872,12 @@ func wallpaper(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Wallpaper.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 775, 496)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 775, 496)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 260, 580).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 260, 580).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// whyatme 为什么at我
|
||||
@@ -901,12 +900,12 @@ func whyatme(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Whyatme.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 265, 265)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 265, 265)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 0, 0, 42, 13).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 0, 0, 42, 13).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// makeFriend 交个朋友
|
||||
@@ -934,16 +933,16 @@ func makeFriend(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
canvas := gg.NewContext(1000, 1000)
|
||||
canvas.DrawImage(img.Size(face, 1000, 1000).Im, 0, 0)
|
||||
canvas.DrawImage(img.Rotate(face, 9, 250, 250).Im, 743, 845)
|
||||
canvas.DrawImage(img.Rotate(face, 9, 55, 55).Im, 836, 722)
|
||||
canvas.DrawImage(imgfactory.Size(face, 1000, 1000).Image(), 0, 0)
|
||||
canvas.DrawImage(imgfactory.Rotate(face, 9, 250, 250).Image(), 743, 845)
|
||||
canvas.DrawImage(imgfactory.Rotate(face, 9, 55, 55).Image(), 836, 722)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.SetColor(color.White)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 20); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -978,12 +977,12 @@ func backToWork(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "BackToWork.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 220, 310)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 220, 310)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 25, 0, 0).Im, 0, 0, 56, 32).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 25, 0, 0).Image(), 0, 0, 56, 32).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// coupon 兑换券
|
||||
@@ -1016,13 +1015,13 @@ func coupon(cc *context, args ...string) (string, error) {
|
||||
canvas := gg.NewContext(500, 355)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.Rotate(gg.Radians(-22))
|
||||
canvas.DrawImage(img.Size(face, 60, 60).Im, 100, 163)
|
||||
canvas.DrawImage(imgfactory.Size(face, 60, 60).Image(), 100, 163)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 30); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -1057,12 +1056,12 @@ func distracted(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "Distracted.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 500, 500)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 500, 500)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := im.InsertUp(imgs[0].Im, 0, 0, 140, 320).InsertUp(imgs[1].Im, 0, 0, 0, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := im.InsertUp(imgs[0].Image(), 0, 0, 140, 320).InsertUp(imgs[1].Image(), 0, 0, 0, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// throw 扔
|
||||
@@ -1089,8 +1088,8 @@ func throw(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertUpC(img.Rotate(face, float64(rand.Intn(360)), 143, 143).Im, 0, 0, 86, 249).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertUpC(imgfactory.Rotate(face, float64(rand.Intn(360)), 143, 143).Image(), 0, 0, 86, 249).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// 远离
|
||||
@@ -1113,12 +1112,12 @@ func yuanli(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "yuanli.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 420, 420, 45, 90).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 420, 420, 45, 90).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// 不是你老婆
|
||||
@@ -1141,12 +1140,12 @@ func nowife(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "nowife.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 534, 493)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 400, 400, 112, 81).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 400, 400, 112, 81).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// youer 你老婆
|
||||
@@ -1175,13 +1174,13 @@ func youer(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(690, 690)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(tou, 350, 350).Im, 55, 165)
|
||||
canvas.DrawImage(imgfactory.Size(tou, 350, 350).Image(), 55, 165)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 56); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 56); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -1222,13 +1221,13 @@ func xiaotianshi(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(522, 665)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(face, 480, 480).Im, 20, 80)
|
||||
canvas.DrawImage(imgfactory.Size(face, 480, 480).Image(), 20, 80)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 35); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 35); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -1263,12 +1262,12 @@ func neko(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "neko.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 712, 949)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 712, 949)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 0, 0, 0).Im, 450, 450, 0, 170).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 0, 0, 0).Image(), 450, 450, 0, 170).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// 给我变
|
||||
@@ -1292,12 +1291,12 @@ func bian(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "bian.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 640, 550)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 640, 550)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(img.Rotate(im.Im, 0, 0, 0).Im, 380, 380, 225, -20).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(imgfactory.Rotate(im.Image(), 0, 0, 0).Image(), 380, 380, 225, -20).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// van 玩一下
|
||||
@@ -1326,13 +1325,13 @@ func van(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(522, 665)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(face, 480, 480).Im, 20, 80)
|
||||
canvas.DrawImage(imgfactory.Size(face, 480, 480).Image(), 20, 80)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 35); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 35); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
@@ -1367,12 +1366,12 @@ func eihei(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "eihei.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 690, 690)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 690, 690)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 450, 450, 121, 162).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 450, 450, 121, 162).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// fanfa 犯法
|
||||
@@ -1399,9 +1398,9 @@ func fanfa(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
m1 := img.Rotate(face, 45, 110, 110)
|
||||
imgnrgba := imgs[0].InsertUp(m1.Im, 0, 0, 125, 360).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
m1 := imgfactory.Rotate(face, 45, 110, 110)
|
||||
imgnrgba := imgs[0].InsertUp(m1.Image(), 0, 0, 125, 360).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// huai 怀
|
||||
@@ -1424,12 +1423,12 @@ func huai(cc *context, args ...string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
name := cc.usrdir + "huai.png"
|
||||
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 640, 640)
|
||||
im, err := imgfactory.LoadFirstFrame(cc.headimgsdir[0], 640, 640)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(im.Im, 640, 640, 0, 0).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(im.Image(), 640, 640, 0, 0).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// haowan 好玩
|
||||
@@ -1456,8 +1455,8 @@ func haowan(cc *context, args ...string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
imgnrgba := imgs[0].InsertBottom(face, 90, 90, 321, 172).Im
|
||||
return "file:///" + name, writer.SavePNG2Path(name, imgnrgba)
|
||||
imgnrgba := imgs[0].InsertBottom(face, 90, 90, 321, 172).Image()
|
||||
return "file:///" + name, imgfactory.SavePNG2Path(name, imgnrgba)
|
||||
}
|
||||
|
||||
// mengbi 蒙蔽
|
||||
@@ -1486,14 +1485,14 @@ func mengbi(cc *context, args ...string) (string, error) {
|
||||
}
|
||||
canvas := gg.NewContext(1080, 1080)
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
canvas.DrawImage(img.Size(face, 100, 100).Im, 392, 460)
|
||||
canvas.DrawImage(img.Size(face, 100, 100).Im, 606, 443)
|
||||
canvas.DrawImage(imgfactory.Size(face, 100, 100).Image(), 392, 460)
|
||||
canvas.DrawImage(imgfactory.Size(face, 100, 100).Image(), 606, 443)
|
||||
canvas.SetColor(color.Black)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, 80); err != nil {
|
||||
if err = canvas.ParseFontFace(data, 80); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if args[0] == "" {
|
||||
|
||||
@@ -129,21 +129,22 @@ func init() { // 插件主体
|
||||
en := control.Register("gif", &ctrl.Options[*zero.Ctx]{
|
||||
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号|图片]" +
|
||||
Help: "下为制图命令:\n" +
|
||||
"- 搓|- 冲|- 摸|-拍|- 丢|- 吃|- 敲|- 啃|- 蹭|- 爬|- 撕\n" +
|
||||
"- 吸|- 嗦|- 扔|- 锤|- 紧贴|紧紧贴着|- 转|- 抬棺|- 远离\n" +
|
||||
"- 揍|- 吞|- 膜拜|- 诶嘿|- 2蹭|- 你犯法了|- 砰|- 注意力涣散\n" +
|
||||
"- 2敲|- 听音乐|- 永远爱你|- 2拍|- 顶|- 捣|- 打拳|- 滚\n" +
|
||||
"- 灰度|- 上翻|- 下翻|- 左翻|- 右翻|- 反色|- 浮雕|- 打码\n" +
|
||||
"- 负片|- 旋转|- 变形|- 亲|- 结婚申请|结婚登记|- 阿尼亚喜欢XXX\n" +
|
||||
"- 像只|- 我永远喜欢XXX|- 像样的亲亲|- 国旗|- 不要靠近\n" +
|
||||
"- 蒙蔽|- 踩|- 好玩|- 2转|- 踢球|- 2舔|- 可莉吃|- 胡桃啃|- 怀\n" +
|
||||
"- 小画家|- 完美|- 玩游戏|- 出警|- 警察|- 舔|舔屏|prpr\n" +
|
||||
"- 安全感|- 精神支柱|- 想什么|- 墙纸|- 为什么at我|- 交个朋友\n" +
|
||||
"- 打工人|- 继续干活|- 兑换券|- 炖|- 垃圾桶|- 垃圾|- 捶|- 啾啾\n" +
|
||||
"- 我老婆|- 小天使XXX|- 你的XXX|- 不要看|- 玩一下XXX|- 给我变\n" +
|
||||
"- 万能表情|- 空白表情|- 采访|- 需要|- 你可能需要|- 这像画吗\n" +
|
||||
"- 一直(支持动图)\n" +
|
||||
"例: 制图命令XXX[@用户|QQ号|图片]\n" +
|
||||
"Tips: XXX可以为限制长度的任何文字\n" +
|
||||
"对Bot使用为 @Bot制图命令[XXX]@Bot",
|
||||
PrivateDataFolder: "gif",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
wyy "github.com/FloatTech/AnimeAPI/neteasemusic"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -18,10 +19,9 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// 图片输出
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
@@ -406,18 +406,18 @@ func init() {
|
||||
canvas.SetRGB(1, 1, 1) // 白色
|
||||
canvas.Clear()
|
||||
/***********下载字体,可以注销掉***********/
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
boldfd, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
}
|
||||
_, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
fd, err := file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
}
|
||||
/***********设置字体颜色为黑色***********/
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
if err = canvas.ParseFontFace(boldfd, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return
|
||||
}
|
||||
@@ -426,7 +426,7 @@ func init() {
|
||||
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 {
|
||||
if err = canvas.ParseFontFace(fd, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return
|
||||
}
|
||||
@@ -446,11 +446,14 @@ func init() {
|
||||
canvas.DrawString("当前设置的默认歌单为: "+dlist.Name, 80, float64(85+20*j)-h)
|
||||
}
|
||||
}
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
data, err := imgfactory.ToBytes(canvas.Image())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.ImageBytes(data)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
cl()
|
||||
})
|
||||
engine.OnPrefix("设置猜歌默认歌单", zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
174
plugin/hitokoto/hitokoto.go
Normal file
174
plugin/hitokoto/hitokoto.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Package hitokoto 一言
|
||||
package hitokoto
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"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/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("hitokoto", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "一言",
|
||||
Help: "- 一言[xxx]\n" +
|
||||
"- 系列一言",
|
||||
PublicDataFolder: "Hitokoto",
|
||||
})
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
dbfile := engine.DataFolder() + "hitokoto.db"
|
||||
_, err := engine.GetLazyData("hitokoto.db", false)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
hdb, err = initialize(dbfile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
engine.OnPrefix(`一言`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
args := ctx.State["args"].(string)
|
||||
blist, err := hdb.getByKey(strings.TrimSpace(args))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(blist) == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: hitokoto empty"))
|
||||
return
|
||||
}
|
||||
m := make(message.Message, 0, 10)
|
||||
text := strings.Builder{}
|
||||
if len(blist) <= 10 {
|
||||
for _, b := range blist {
|
||||
text.WriteString(b.Hitokoto)
|
||||
text.WriteString("\n——")
|
||||
text.WriteString(b.From)
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
|
||||
text.Reset()
|
||||
}
|
||||
} else {
|
||||
indexes := map[int]struct{}{}
|
||||
for i := 0; i < 10; i++ {
|
||||
ind := rand.Intn(len(blist))
|
||||
if _, ok := indexes[ind]; ok {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
indexes[ind] = struct{}{}
|
||||
}
|
||||
for k := range indexes {
|
||||
b := blist[k]
|
||||
text.WriteString(b.Hitokoto)
|
||||
text.WriteString("\n——")
|
||||
text.WriteString(b.From)
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
|
||||
text.Reset()
|
||||
}
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch(`系列一言`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
results, err := hdb.getAllCategory()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tex := strings.Builder{}
|
||||
tex.WriteString("请输入系列一言序号\n")
|
||||
for i, v := range results {
|
||||
tex.WriteString(strconv.Itoa(i))
|
||||
tex.WriteString(". ")
|
||||
tex.WriteString(v.Category)
|
||||
tex.WriteString("\n")
|
||||
}
|
||||
base64Str, err := text.RenderToBase64(tex.String(), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(base64Str)))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 120):
|
||||
ctx.SendChain(message.Text("系列一言指令过期"))
|
||||
return
|
||||
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 >= len(results) {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
ctx.SendChain(message.Text("请欣赏系列一言: ", results[num].Category))
|
||||
hlist, err := hdb.getByCategory(results[num].Category)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(hlist) == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: hitokoto empty"))
|
||||
return
|
||||
}
|
||||
m := make(message.Message, 0, 10)
|
||||
text := strings.Builder{}
|
||||
if len(hlist) <= 10 {
|
||||
for _, b := range hlist {
|
||||
text.WriteString(b.Hitokoto)
|
||||
text.WriteString("\n——")
|
||||
text.WriteString(b.From)
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
|
||||
text.Reset()
|
||||
}
|
||||
} else {
|
||||
indexes := map[int]struct{}{}
|
||||
for i := 0; i < 10; i++ {
|
||||
ind := rand.Intn(len(hlist))
|
||||
if _, ok := indexes[ind]; ok {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
indexes[ind] = struct{}{}
|
||||
}
|
||||
for k := range indexes {
|
||||
b := hlist[k]
|
||||
text.WriteString(b.Hitokoto)
|
||||
text.WriteString("\n——")
|
||||
text.WriteString(b.From)
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
|
||||
text.Reset()
|
||||
}
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
73
plugin/hitokoto/model.go
Normal file
73
plugin/hitokoto/model.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package hitokoto
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// hdb 表情包数据库全局变量
|
||||
var hdb *hitokotodb
|
||||
|
||||
// hitokotodb 表情包数据库
|
||||
type hitokotodb gorm.DB
|
||||
|
||||
// initialize 初始化
|
||||
func initialize(dbpath string) (db *hitokotodb, err error) {
|
||||
if _, err = os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = f.Close()
|
||||
}
|
||||
gdb, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
gdb.AutoMigrate(&hitokoto{})
|
||||
return (*hitokotodb)(gdb), nil
|
||||
}
|
||||
|
||||
type hitokoto struct {
|
||||
ID int `json:"id" gorm:"column:id;primary_key"`
|
||||
Hitokoto string `json:"hitokoto" gorm:"column:hitokoto"`
|
||||
Type string `json:"type" gorm:"column:type"`
|
||||
From string `json:"from" gorm:"column:from"`
|
||||
FromWho string `json:"from_who" gorm:"column:from_who"`
|
||||
Creator string `json:"creator" gorm:"column:creator"`
|
||||
CreatorUID int `json:"creator_uid" gorm:"column:creator_uid"`
|
||||
Reviewer int `json:"reviewer" gorm:"column:reviewer"`
|
||||
UUID string `json:"uuid" gorm:"column:uuid"`
|
||||
CreatedAt string `json:"created_at" gorm:"column:created_at"`
|
||||
Category string `json:"catogory" gorm:"column:category"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (hitokoto) TableName() string {
|
||||
return "hitokoto"
|
||||
}
|
||||
|
||||
func (hdb *hitokotodb) getByKey(key string) (b []hitokoto, err error) {
|
||||
db := (*gorm.DB)(hdb)
|
||||
err = db.Where("hitokoto like ?", "%"+key+"%").Find(&b).Error
|
||||
return
|
||||
}
|
||||
|
||||
type result struct {
|
||||
Category string
|
||||
Count int
|
||||
}
|
||||
|
||||
func (hdb *hitokotodb) getAllCategory() (results []result, err error) {
|
||||
db := (*gorm.DB)(hdb)
|
||||
err = db.Table("hitokoto").Select("category, count(1) as count").Group("category").Scan(&results).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (hdb *hitokotodb) getByCategory(category string) (h []hitokoto, err error) {
|
||||
db := (*gorm.DB)(hdb)
|
||||
err = db.Where("category = ?", category).Find(&h).Error
|
||||
return
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/http3"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
jiami1 = "http://ovooa.com/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.com/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
jiami1 = "http://ovooa.caonm.net/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.caonm.net/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
|
||||
)
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
31
plugin/kfccrazythursday/kfccrazythursday.go
Normal file
31
plugin/kfccrazythursday/kfccrazythursday.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Package kfccrazythursday 疯狂星期四
|
||||
package kfccrazythursday
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
crazyURL = "https://www.iculture.cc/demo/CrazyThursday/api/kfc.php"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("kfccrazythursday", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "疯狂星期四",
|
||||
Help: "疯狂星期四\n",
|
||||
})
|
||||
engine.OnFullMatch("疯狂星期四").SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
data, err := web.GetData(crazyURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(gjson.ParseBytes(data).Get("@this.0.content").String()))
|
||||
})
|
||||
}
|
||||
@@ -222,7 +222,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("那我就不手下留情了~"))
|
||||
})
|
||||
// 修改名片
|
||||
engine.OnRegex(`^修改名片.*(\d+).*\s+(.*)`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
engine.OnRegex(`^修改名片.*?(\d+).+?\s*(.*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if len(ctx.State["regex_matched"].([]string)[2]) > 60 {
|
||||
ctx.SendChain(message.Text("名字太长啦!"))
|
||||
@@ -236,30 +236,38 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("嗯!已经修改了"))
|
||||
})
|
||||
// 修改头衔
|
||||
engine.OnRegex(`^修改头衔.*(\d+).*\s+(.*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
engine.OnRegex(`^修改头衔.*?(\d+).+?\s*(.*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if len(ctx.State["regex_matched"].([]string)[1]) > 18 {
|
||||
sptitle := ctx.State["regex_matched"].([]string)[2]
|
||||
if sptitle == "" {
|
||||
ctx.SendChain(message.Text("头衔不能为空!"))
|
||||
return
|
||||
} else if len(sptitle) > 18 {
|
||||
ctx.SendChain(message.Text("头衔太长啦!"))
|
||||
return
|
||||
}
|
||||
ctx.SetGroupSpecialTitle(
|
||||
ctx.Event.GroupID,
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被修改群头衔的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群头衔
|
||||
sptitle, // 修改成的群头衔
|
||||
)
|
||||
ctx.SendChain(message.Text("嗯!已经修改了"))
|
||||
})
|
||||
// 申请头衔
|
||||
engine.OnRegex(`^申请头衔\s+(.*)$`, zero.OnlyGroup).SetBlock(true).
|
||||
engine.OnRegex(`^申请头衔\s*(.*)$`, zero.OnlyGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if len(ctx.State["regex_matched"].([]string)[1]) > 18 {
|
||||
sptitle := ctx.State["regex_matched"].([]string)[1]
|
||||
if sptitle == "" {
|
||||
ctx.SendChain(message.Text("头衔不能为空!"))
|
||||
return
|
||||
} else if len(sptitle) > 18 {
|
||||
ctx.SendChain(message.Text("头衔太长啦!"))
|
||||
return
|
||||
}
|
||||
ctx.SetGroupSpecialTitle(
|
||||
ctx.Event.GroupID,
|
||||
ctx.Event.UserID, // 被修改群头衔的人
|
||||
ctx.State["regex_matched"].([]string)[1], // 修改成的群头衔
|
||||
ctx.Event.UserID, // 被修改群头衔的人
|
||||
sptitle, // 修改成的群头衔
|
||||
)
|
||||
ctx.SendChain(message.Text("嗯!不错的头衔呢~"))
|
||||
})
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/tts/genshin"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -16,12 +17,12 @@ import (
|
||||
const (
|
||||
jpapi = "https://moegoe.azurewebsites.net/api/speak?text=%s&id=%d"
|
||||
krapi = "https://moegoe.azurewebsites.net/api/speakkr?text=%s&id=%d"
|
||||
cnapi = "http://267978.proxy.nscc-gz.cn:8888?text=%s&speaker=%s"
|
||||
)
|
||||
|
||||
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() {
|
||||
@@ -30,7 +31,7 @@ func init() {
|
||||
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) {
|
||||
@@ -44,10 +45,23 @@ func init() {
|
||||
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).
|
||||
en.OnRegex("^让(派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
speaker := ctx.State["regex_matched"].([]string)[1]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(cnapi, url.QueryEscape(text), speaker)))
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
c, ok := control.Lookup("tts")
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("ERROR: plugin tts not found"))
|
||||
return
|
||||
}
|
||||
var key struct {
|
||||
APIKey string
|
||||
}
|
||||
err := c.Manager.GetExtra(-1, &key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(genshin.CNAPI, id, url.QueryEscape(text), url.QueryEscape(key.APIKey))))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,19 +3,21 @@ package novel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/antchfx/htmlquery"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
ub "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"
|
||||
@@ -32,26 +34,47 @@ const (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||
loginURL = websiteURL + "/login.php?do=submit&jumpurl=https%3A%2F%2Fwww.23qb.com%2F"
|
||||
searchURL = websiteURL + "/saerch.php"
|
||||
downloadURL = websiteURL + "/modules/article/txtarticle.php?id=%v"
|
||||
detailURL = websiteURL + "/book/%v/"
|
||||
idReg = `/(\d+)/`
|
||||
)
|
||||
|
||||
var gCurCookieJar *cookiejar.Jar
|
||||
var (
|
||||
cachePath string
|
||||
// apikey 由账号和密码拼接而成, 例: zerobot,123456
|
||||
apikey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
control.Register("novel", &ctrl.Options[*zero.Ctx]{
|
||||
engine := control.Register("novel", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "铅笔小说网搜索",
|
||||
Help: "- 小说[xxx]",
|
||||
}).OnRegex("^小说([\u4E00-\u9FA5A-Za-z0-9]{1,25})$").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Help: "- 小说[xxx]\n" +
|
||||
"- 设置小说配置 zerobot 123456\n" +
|
||||
"- 下载小说30298\n" +
|
||||
"建议去https://www.23qb.com/ 注册一个账号, 小说下载有积分限制",
|
||||
PrivateDataFolder: "novel",
|
||||
})
|
||||
cachePath = engine.DataFolder() + "cache/"
|
||||
_ = os.MkdirAll(cachePath, 0755)
|
||||
engine.OnRegex("^小说([\u4E00-\u9FA5A-Za-z0-9]{1,25})$").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
err := login(username, password)
|
||||
key := getAPIKey(ctx)
|
||||
u, p, _ := strings.Cut(key, ",")
|
||||
if u == "" {
|
||||
u = username
|
||||
}
|
||||
if p == "" {
|
||||
p = password
|
||||
}
|
||||
cookie, err := login(u, p)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
searchKey := ctx.State["regex_matched"].([]string)[1]
|
||||
searchHTML, err := search(searchKey)
|
||||
searchHTML, err := search(searchKey, cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -93,7 +116,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + helper.BytesToString(data))); id.ID() == 0 {
|
||||
if id := ctx.SendChain(message.Image("base64://" + ub.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
} else {
|
||||
@@ -124,23 +147,76 @@ func init() {
|
||||
ctx.SendChain(message.Text(text))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^设置小说配置\s(.*[^\s$])\s(.+)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
err := setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), regexMatched[1]+","+regexMatched[2])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置小说配置\nusername: ", regexMatched[1], "\npassword: ", regexMatched[2]))
|
||||
})
|
||||
engine.OnRegex("^下载小说([0-9]{1,25})$").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
id := regexMatched[1]
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
key := getAPIKey(ctx)
|
||||
u, p, _ := strings.Cut(key, ",")
|
||||
if u == "" {
|
||||
u = username
|
||||
}
|
||||
if p == "" {
|
||||
p = password
|
||||
}
|
||||
cookie, err := login(u, p)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
detailHTML, err := detail(id, cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
doc, err := htmlquery.Parse(strings.NewReader(detailHTML))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
title := htmlquery.InnerText(htmlquery.FindOne(doc, "//*[@id='bookinfo']/div[@class='bookright']/div[@class='d_title']/h1"))
|
||||
fileName := filepath.Join(cachePath, title+".txt")
|
||||
if file.IsExist(fileName) {
|
||||
ctx.UploadThisGroupFile(filepath.Join(file.BOTPATH, fileName), filepath.Base(fileName), "")
|
||||
return
|
||||
}
|
||||
data, err := download(id, cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(fileName, ub.StringToBytes(data), 0666)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.UploadThisGroupFile(filepath.Join(file.BOTPATH, fileName), filepath.Base(fileName), "")
|
||||
})
|
||||
}
|
||||
|
||||
func login(username, password string) (err error) {
|
||||
gCurCookieJar, _ = cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
usernameData, err := ub.UTF82GBK(helper.StringToBytes(username))
|
||||
func login(username, password string) (cookie string, err error) {
|
||||
client := &http.Client{}
|
||||
usernameData, err := ub.UTF82GBK(ub.StringToBytes(username))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
usernameGbk := helper.BytesToString(usernameData)
|
||||
passwordData, err := ub.UTF82GBK(helper.StringToBytes(password))
|
||||
usernameGbk := ub.BytesToString(usernameData)
|
||||
passwordData, err := ub.UTF82GBK(ub.StringToBytes(password))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
passwordGbk := helper.BytesToString(passwordData)
|
||||
passwordGbk := ub.BytesToString(passwordData)
|
||||
loginReq, err := http.NewRequest("POST", loginURL, strings.NewReader(fmt.Sprintf("username=%s&password=%s&usecookie=315360000&action=login&submit=%s", url.QueryEscape(usernameGbk), url.QueryEscape(passwordGbk), submit)))
|
||||
if err != nil {
|
||||
return
|
||||
@@ -151,38 +227,79 @@ func login(username, password string) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = loginResp.Body.Close()
|
||||
defer loginResp.Body.Close()
|
||||
for _, v := range loginResp.Cookies() {
|
||||
cookie += v.Name + "=" + v.Value + ";"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func search(searchKey string) (searchHTML string, err error) {
|
||||
searchKeyData, err := ub.UTF82GBK(helper.StringToBytes(searchKey))
|
||||
func search(searchKey string, cookie string) (searchHTML string, err error) {
|
||||
searchKeyData, err := ub.UTF82GBK(ub.StringToBytes(searchKey))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
searchKeyGbk := helper.BytesToString(searchKeyData)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
searchReq, err := http.NewRequest("POST", searchURL, strings.NewReader(fmt.Sprintf("searchkey=%s&searchtype=all", url.QueryEscape(searchKeyGbk))))
|
||||
searchKeyGbk := ub.BytesToString(searchKeyData)
|
||||
data, err := web.RequestDataWithHeaders(web.NewDefaultClient(), searchURL, "POST", func(r *http.Request) error {
|
||||
r.Header.Set("Cookie", cookie)
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
r.Header.Set("User-Agent", ua)
|
||||
return nil
|
||||
}, strings.NewReader(fmt.Sprintf("searchkey=%s&searchtype=all", url.QueryEscape(searchKeyGbk))))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
searchReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
searchReq.Header.Set("User-Agent", ua)
|
||||
searchResp, err := client.Do(searchReq)
|
||||
searchData, err := ub.GBK2UTF8(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
searchData, err := io.ReadAll(searchResp.Body)
|
||||
_ = searchResp.Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
searchData, err = ub.GBK2UTF8(searchData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
searchHTML = helper.BytesToString(searchData)
|
||||
return searchHTML, nil
|
||||
searchHTML = ub.BytesToString(searchData)
|
||||
return
|
||||
}
|
||||
|
||||
func detail(id string, cookie string) (detailHTML string, err error) {
|
||||
data, err := web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(detailURL, id), "GET", func(r *http.Request) error {
|
||||
r.Header.Set("Cookie", cookie)
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
r.Header.Set("User-Agent", ua)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
detailData, err := ub.GBK2UTF8(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
detailHTML = ub.BytesToString(detailData)
|
||||
return
|
||||
}
|
||||
|
||||
func download(id string, cookie string) (downloadHTML string, err error) {
|
||||
data, err := web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(downloadURL, id), "GET", func(r *http.Request) error {
|
||||
r.Header.Set("Cookie", cookie)
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
r.Header.Set("User-Agent", ua)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
downloadHTML = ub.BytesToString(data)
|
||||
return
|
||||
}
|
||||
|
||||
func getAPIKey(ctx *zero.Ctx) string {
|
||||
if apikey == "" {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(-1, &apikey)
|
||||
logrus.Debugln("[novel] get api key:", apikey)
|
||||
}
|
||||
return apikey
|
||||
}
|
||||
|
||||
func setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
|
||||
apikey = key
|
||||
_ = m.Manager.Response(-1)
|
||||
return m.Manager.SetExtra(-1, apikey)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
control "github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -21,12 +22,10 @@ import (
|
||||
// 数据库
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
// 画图
|
||||
"github.com/Coloured-glaze/gg"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
// 货币系统
|
||||
)
|
||||
|
||||
type 婚姻登记 struct {
|
||||
@@ -60,7 +59,7 @@ var (
|
||||
engine = control.Register("qqwife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "一群一天一夫一妻制群老婆",
|
||||
Help: "- 娶群友\n- 群老婆列表\n- [允许|禁止]自由恋爱\n- [允许|禁止]牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n- 查好感度[对方Q号|@对方QQ]\n- 好感度列表\n" +
|
||||
Help: "- 娶群友\n- 群老婆列表\n- [允许|禁止]自由恋爱\n- [允许|禁止]牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n- 查好感度[对方Q号|@对方QQ]\n- 好感度列表\n- 好感度数据整理 (当好感度列表出现重复名字时使用)\n" +
|
||||
"--------------------------------\n以下指令存在CD,不跨天刷新,前两个受指令开关\n--------------------------------\n" +
|
||||
"- (娶|嫁)@对方QQ\n自由选择对象, 自由恋爱(好感度越高成功率越高,保底30%概率)\n" +
|
||||
"- 当[对方Q号|@对方QQ]的小三\n我和你才是真爱, 为了你我愿意付出一切(好感度越高成功率越高,保底10%概率)\n" +
|
||||
@@ -69,7 +68,7 @@ var (
|
||||
"- 做媒 @攻方QQ @受方QQ\n身为管理, 群友的xing福是要搭把手的(攻受双方好感度越高成功率越高,保底30%概率)\n" +
|
||||
"--------------------------------\n好感度规则\n--------------------------------\n" +
|
||||
"\"娶群友\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" +
|
||||
"Tips: 群老婆列表过0点刷新",
|
||||
"\nTips: 群老婆列表过0点刷新",
|
||||
PrivateDataFolder: "qqwife",
|
||||
}).ApplySingle(single.New(
|
||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
||||
@@ -236,14 +235,14 @@ func init() {
|
||||
canvas.SetRGB(1, 1, 1) // 白色
|
||||
canvas.Clear()
|
||||
/***********下载字体,可以注销掉***********/
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]ERROR: ", err))
|
||||
}
|
||||
/***********设置字体颜色为黑色***********/
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize*2); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize*2); err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -252,7 +251,7 @@ func init() {
|
||||
canvas.DrawString("群老婆列表", (1500-sl)/2, 160-h) // 放置在中间位置
|
||||
canvas.DrawString("————————————————————", 0, 250-h)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -264,9 +263,12 @@ func init() {
|
||||
canvas.DrawString(slicename(info[2], canvas), 800, float64(260+50*i)-h)
|
||||
canvas.DrawString("("+info[3]+")", 1150, float64(260+50*i)-h)
|
||||
}
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
data, err = imgfactory.ToBytes(canvas.Image())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
})
|
||||
engine.OnRegex(`^重置(所有|本群|/d+)?花名册$`, zero.SuperUserPermission, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
@@ -300,7 +302,7 @@ func init() {
|
||||
func (sql *婚姻登记) 查看设置(gid int64) (dbinfo updateinfo, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
// 创建群表哥
|
||||
// 创建群表格
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
return
|
||||
@@ -348,7 +350,7 @@ func (sql *婚姻登记) 查户口(gid, uid int64) (info userinfo, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
// 创建群表哥
|
||||
// 创建群表格
|
||||
err = sql.db.Create(gidstr, &userinfo{})
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@@ -8,15 +8,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
control "github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// 画图
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
|
||||
// 货币系统
|
||||
@@ -84,16 +84,18 @@ func init() {
|
||||
ctx.SendChain(message.Text("你钱包没钱啦!"))
|
||||
return
|
||||
}
|
||||
moneyToFavor := rand.Intn(math.Min(walletinfo, 100))
|
||||
moneyToFavor := rand.Intn(math.Min(walletinfo, 100)) + 1
|
||||
// 计算钱对应的好感值
|
||||
newFavor := 1
|
||||
moodMax := 2
|
||||
if favor > 50 {
|
||||
newFavor = moneyToFavor % 10 // 礼物厌倦
|
||||
} else {
|
||||
moodMax = 5
|
||||
newFavor += rand.Intn(moneyToFavor)
|
||||
}
|
||||
// 随机对方心情
|
||||
mood := rand.Intn(2)
|
||||
mood := rand.Intn(moodMax)
|
||||
if mood == 0 {
|
||||
newFavor = -newFavor
|
||||
}
|
||||
@@ -138,14 +140,14 @@ func init() {
|
||||
canvas.SetRGB(1, 1, 1) // 白色
|
||||
canvas.Clear()
|
||||
/***********下载字体***********/
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[ERROR]:ERROR: ", err))
|
||||
}
|
||||
/***********设置字体颜色为黑色***********/
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize*2); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize*2); err != nil {
|
||||
ctx.SendChain(message.Text("[ERROR]:ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -154,7 +156,7 @@ func init() {
|
||||
canvas.DrawString("你的好感度排行列表", (1100-sl)/2, 100) // 放置在中间位置
|
||||
canvas.DrawString("————————————————————", 0, 160)
|
||||
/***********设置字体大小,并获取字体高度用来定位***********/
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
if err = canvas.ParseFontFace(data, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("[ERROR]:ERROR: ", err))
|
||||
return
|
||||
}
|
||||
@@ -187,9 +189,77 @@ func init() {
|
||||
canvas.Fill()
|
||||
i++
|
||||
}
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
data, err = imgfactory.ToBytes(canvas.Image())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
})
|
||||
|
||||
engine.OnFullMatch("好感度数据整理", zero.SuperUserPermission, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("开始整理力,请稍等"))
|
||||
民政局.Lock()
|
||||
defer 民政局.Unlock()
|
||||
count, err := 民政局.db.Count("favorability")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[ERROR]: ", err))
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
ctx.SendChain(message.Text("[ERROR]: 不存在好感度数据."))
|
||||
return
|
||||
}
|
||||
favor := favorability{}
|
||||
delInfo := make([]string, 0, count*2)
|
||||
favorInfo := make(map[string]int, count*2)
|
||||
_ = 民政局.db.FindFor("favorability", &favor, "group by Userinfo", func() error {
|
||||
delInfo = append(delInfo, favor.Userinfo)
|
||||
// 解析旧数据
|
||||
userList := strings.Split(favor.Userinfo, "+")
|
||||
maxQQ, _ := strconv.ParseInt(userList[0], 10, 64)
|
||||
minQQ, _ := strconv.ParseInt(userList[1], 10, 64)
|
||||
if maxQQ > minQQ {
|
||||
favor.Userinfo = userList[0] + "+" + userList[1]
|
||||
} else {
|
||||
favor.Userinfo = userList[1] + "+" + userList[0]
|
||||
}
|
||||
// 判断是否是重复的
|
||||
score, ok := favorInfo[favor.Userinfo]
|
||||
if ok {
|
||||
if score < favor.Favor {
|
||||
favorInfo[favor.Userinfo] = favor.Favor
|
||||
}
|
||||
} else {
|
||||
favorInfo[favor.Userinfo] = favor.Favor
|
||||
}
|
||||
return nil
|
||||
})
|
||||
for _, updateinfo := range delInfo {
|
||||
// 删除旧数据
|
||||
err = 民政局.db.Del("favorability", "where Userinfo = '"+updateinfo+"'")
|
||||
if err != nil {
|
||||
userList := strings.Split(favor.Userinfo, "+")
|
||||
uid1, _ := strconv.ParseInt(userList[0], 10, 64)
|
||||
uid2, _ := strconv.ParseInt(userList[1], 10, 64)
|
||||
ctx.SendChain(message.Text("[ERROR]: 删除", ctx.CardOrNickName(uid1), "和", ctx.CardOrNickName(uid2), "的好感度时发生了错误。\n错误信息:", err))
|
||||
}
|
||||
}
|
||||
for userInfo, favor := range favorInfo {
|
||||
favorInfo := favorability{
|
||||
Userinfo: userInfo,
|
||||
Favor: favor,
|
||||
}
|
||||
err = 民政局.db.Insert("favorability", &favorInfo)
|
||||
if err != nil {
|
||||
userList := strings.Split(userInfo, "+")
|
||||
uid1, _ := strconv.ParseInt(userList[0], 10, 64)
|
||||
uid2, _ := strconv.ParseInt(userList[1], 10, 64)
|
||||
ctx.SendChain(message.Text("[ERROR]: 更新", ctx.CardOrNickName(uid1), "和", ctx.CardOrNickName(uid2), "的好感度时发生了错误。\n错误信息:", err))
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("清理好了哦"))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -201,9 +271,19 @@ func (sql *婚姻登记) 查好感度(uid, target int64) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
info := favorability{}
|
||||
uidstr := strconv.FormatInt(uid, 10)
|
||||
targstr := strconv.FormatInt(target, 10)
|
||||
_ = sql.db.Find("favorability", &info, "where Userinfo glob '*"+uidstr+"+"+targstr+"*'")
|
||||
if uid > target {
|
||||
userinfo := strconv.FormatInt(uid, 10) + "+" + strconv.FormatInt(target, 10)
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo is '"+userinfo+"'")
|
||||
if err != nil {
|
||||
_ = sql.db.Find("favorability", &info, "where Userinfo glob '*"+userinfo+"*'")
|
||||
}
|
||||
} else {
|
||||
userinfo := strconv.FormatInt(target, 10) + "+" + strconv.FormatInt(uid, 10)
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo is '"+userinfo+"'")
|
||||
if err != nil {
|
||||
_ = sql.db.Find("favorability", &info, "where Userinfo glob '*"+userinfo+"*'")
|
||||
}
|
||||
}
|
||||
return info.Favor, nil
|
||||
}
|
||||
|
||||
@@ -256,8 +336,19 @@ func (sql *婚姻登记) 更新好感度(uid, target int64, score int) (favor in
|
||||
info := favorability{}
|
||||
uidstr := strconv.FormatInt(uid, 10)
|
||||
targstr := strconv.FormatInt(target, 10)
|
||||
_ = sql.db.Find("favorability", &info, "where Userinfo glob '*"+uidstr+"+"+targstr+"*'")
|
||||
info.Userinfo = uidstr + "+" + targstr + "+" + uidstr
|
||||
if uid > target {
|
||||
info.Userinfo = uidstr + "+" + targstr
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo is '"+info.Userinfo+"'")
|
||||
} else {
|
||||
info.Userinfo = targstr + "+" + uidstr
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo is '"+info.Userinfo+"'")
|
||||
}
|
||||
if err != nil {
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo glob '*"+targstr+"+"+uidstr+"*'")
|
||||
if err == nil { // 如果旧数据存在就删除旧数据
|
||||
err = 民政局.db.Del("favorability", "where Userinfo = '"+info.Userinfo+"'")
|
||||
}
|
||||
}
|
||||
info.Favor += score
|
||||
if info.Favor > 100 {
|
||||
info.Favor = 100
|
||||
|
||||
@@ -4,6 +4,7 @@ package quan
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
@@ -35,6 +36,23 @@ func init() { // 主函数
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(str, helper.BytesToString(es))) // 输出结果
|
||||
if len(helper.BytesToString(es)) <= 24 {
|
||||
ctx.SendChain(message.Text("网站维护中")) // 输出结果
|
||||
return
|
||||
}
|
||||
f := helper.BytesToString(es)[24:]
|
||||
_, err = strconv.Atoi(f)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("网站维护中")) // 输出结果
|
||||
return
|
||||
}
|
||||
var msg strings.Builder
|
||||
msg.WriteString("查询账号:")
|
||||
msg.WriteString(str)
|
||||
msg.WriteString("\n")
|
||||
msg.WriteString("查询状态:成功\n")
|
||||
msg.WriteString("您的权重为:")
|
||||
msg.WriteString(f)
|
||||
ctx.SendChain(message.Text(msg.String())) // 输出结果
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,15 +12,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/AnimeAPI/qzone"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/jinzhu/gorm"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@@ -311,7 +310,6 @@ func renderForwardMsg(qq int64, raw string) (base64Bytes []byte, err error) {
|
||||
imgdata []byte
|
||||
msgImg image.Image
|
||||
faceImg image.Image
|
||||
t text.Text
|
||||
)
|
||||
if qq != 0 {
|
||||
face, err = web.GetData(fmt.Sprintf(faceURL, qq))
|
||||
@@ -325,18 +323,17 @@ func renderForwardMsg(qq int64, raw string) (base64Bytes []byte, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
back := img.Size(faceImg, backX, backY).Circle(0).Im
|
||||
back := imgfactory.Size(faceImg, backX, backY).Circle(0).Image()
|
||||
m := message.ParseMessageFromString(raw)
|
||||
maxHeight += margin
|
||||
|
||||
for _, v := range m {
|
||||
switch {
|
||||
case v.Type == "text" && strings.TrimSpace(v.Data["text"]) != "":
|
||||
t, err = text.Render(strings.TrimSuffix(v.Data["text"], "\r\n"), text.FontFile, 400, 40)
|
||||
msgImg, err = text.Render(strings.TrimSuffix(v.Data["text"], "\r\n"), text.FontFile, 400, 40)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msgImg = t.Image()
|
||||
case v.Type == "image" && v.Data["url"] != "":
|
||||
imgdata, err = web.GetData(v.Data["url"])
|
||||
if err != nil {
|
||||
@@ -351,7 +348,7 @@ func renderForwardMsg(qq int64, raw string) (base64Bytes []byte, err error) {
|
||||
}
|
||||
canvas.DrawImage(back, margin, maxHeight)
|
||||
if msgImg.Bounds().Dx() > 500 {
|
||||
msgImg = img.Size(msgImg, 500, msgImg.Bounds().Dy()*500/msgImg.Bounds().Dx()).Im
|
||||
msgImg = imgfactory.Size(msgImg, 500, msgImg.Bounds().Dy()*500/msgImg.Bounds().Dx()).Image()
|
||||
}
|
||||
canvas.DrawImage(msgImg, 2*margin+backX, maxHeight)
|
||||
if 3*margin+backX+msgImg.Bounds().Dx() > maxWidth {
|
||||
@@ -365,5 +362,5 @@ func renderForwardMsg(qq int64, raw string) (base64Bytes []byte, err error) {
|
||||
}
|
||||
im := canvas.Image().(*image.RGBA)
|
||||
nim := im.SubImage(image.Rect(0, 0, maxWidth, maxHeight))
|
||||
return writer.ToBase64(nim)
|
||||
return imgfactory.ToBase64(nim)
|
||||
}
|
||||
|
||||
@@ -74,15 +74,15 @@ func init() { // 插件主体
|
||||
imgs = append(imgs, message.Image(m.String()))
|
||||
continue
|
||||
}
|
||||
logrus.Debugln("[sausenao]开始下载", n)
|
||||
logrus.Debugln("[sausenao]urls:", illust.ImageUrls)
|
||||
logrus.Debugln("[saucenao]开始下载", n)
|
||||
logrus.Debugln("[saucenao]urls:", illust.ImageUrls)
|
||||
err1 := illust.DownloadToCache(i)
|
||||
if err1 == nil {
|
||||
m.SetFile(f)
|
||||
_, _ = m.Push(ctxext.SendToSelf(ctx), ctxext.GetMessage(ctx))
|
||||
}
|
||||
if err1 != nil {
|
||||
logrus.Debugln("[sausenao]下载err:", err1)
|
||||
logrus.Debugln("[saucenao]下载err:", err1)
|
||||
}
|
||||
}
|
||||
imgs = append(imgs, message.Image("file:///"+f))
|
||||
@@ -109,8 +109,13 @@ func init() { // 插件主体
|
||||
engine.OnKeywordGroup([]string{"以图搜图", "搜索图片", "以图识图"}, zero.MustProvidePicture).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 开始搜索图片
|
||||
pics, ok := ctx.State["image_url"].([]string)
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("ERROR: 未获取到图片链接"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
for _, pic := range ctx.State["image_url"].([]string) {
|
||||
for _, pic := range pics {
|
||||
if saucenaocli != nil {
|
||||
resp, err := saucenaocli.FromURL(pic)
|
||||
if err == nil && resp.Count() > 0 {
|
||||
@@ -157,27 +162,27 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text("请私聊发送 设置 saucenao api key [apikey] 以启用 saucenao 搜图 (方括号不需要输入), key 请前往 https://saucenao.com/user.php?page=search-api 获取"))
|
||||
}
|
||||
// ascii2d 搜索
|
||||
if result, err := ascii2d.ASCII2d(pic); err != nil {
|
||||
result, err := ascii2d.ASCII2d(pic)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
continue
|
||||
} else {
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("ascii2d搜图结果"))}
|
||||
for i := 0; i < len(result) && i < 5; i++ {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image(result[i].Thumb),
|
||||
message.Text(fmt.Sprintf(
|
||||
"标题: %s\n图源: %s\n画师: %s\n画师链接: %s\n图片链接: %s",
|
||||
result[i].Name,
|
||||
result[i].Type,
|
||||
result[i].AuthNm,
|
||||
result[i].Author,
|
||||
result[i].Link,
|
||||
))),
|
||||
)
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
}
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("ascii2d搜图结果"))}
|
||||
for i := 0; i < len(result) && i < 5; i++ {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image(result[i].Thumb),
|
||||
message.Text(fmt.Sprintf(
|
||||
"标题: %s\n图源: %s\n画师: %s\n画师链接: %s\n图片链接: %s",
|
||||
result[i].Name,
|
||||
result[i].Type,
|
||||
result[i].AuthNm,
|
||||
result[i].Author,
|
||||
result[i].Link,
|
||||
))),
|
||||
)
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -20,15 +20,14 @@ import (
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/nsfw"
|
||||
"github.com/FloatTech/AnimeAPI/scale"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
|
||||
"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"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -81,10 +80,10 @@ func init() {
|
||||
x := im.Bounds().Size().X * 512 / px
|
||||
y := im.Bounds().Size().Y * 512 / px
|
||||
ctx.SendChain(message.Text("图片", im.Bounds().Size().X, "x", im.Bounds().Size().Y, "过大,调整图片至", x, "x", y))
|
||||
im = img.Size(im, x, y).Im
|
||||
im = imgfactory.Size(im, x, y).Image()
|
||||
w := binary.SelectWriter()
|
||||
defer binary.PutWriter(w)
|
||||
_, err = writer.WriteTo(im, w)
|
||||
_, err = imgfactory.WriteTo(im, w)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
271
plugin/score/draw.go
Normal file
271
plugin/score/draw.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// Package score 签到
|
||||
package score
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/disintegration/imaging"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
func drawScore16(a *scdata) (image.Image, error) {
|
||||
// 绘图
|
||||
getAvatar, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
imgDX := back.Bounds().Dx()
|
||||
imgDY := back.Bounds().Dy()
|
||||
canvas := gg.NewContext(imgDX, imgDY)
|
||||
// draw Aero Style
|
||||
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
|
||||
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
|
||||
// aero draw image.
|
||||
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
|
||||
// SideLine
|
||||
aeroStyle.SetLineWidth(3)
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 100)
|
||||
aeroStyle.StrokePreserve()
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 140)
|
||||
// fill
|
||||
aeroStyle.Fill()
|
||||
// draw background
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
// Aero style combine
|
||||
canvas.DrawImage(aeroStyle.Image(), 100, 100)
|
||||
canvas.Fill()
|
||||
hourWord := getHourWord(time.Now())
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 200, 200)
|
||||
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
|
||||
// draw info(name,coin,etc)
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 50); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// draw head
|
||||
canvas.DrawStringWrapped(a.nickname, 350, 180, 0.5, 0.5, 0.5, 0.5, gg.AlignLeft)
|
||||
canvas.Fill()
|
||||
// main draw
|
||||
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 30); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), 350, 350, 0, 0)
|
||||
canvas.DrawStringAnchored("当前ATRI币:"+strconv.Itoa(a.score), 350, 400, 0, 0)
|
||||
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(a.level)), 350, 450, 0, 0)
|
||||
// draw Info(Time,etc.)
|
||||
getTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
|
||||
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
|
||||
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
|
||||
canvas.Fill()
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
// Gradient
|
||||
grad := gg.NewLinearGradient(20, 320, 400, 20)
|
||||
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
|
||||
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
|
||||
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
|
||||
canvas.SetStrokeStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
// level array with rectangle work.
|
||||
gradLineLength := float64(imgDX-120) - 120
|
||||
renderLine := (float64(a.level) / float64(nextrankScore)) * gradLineLength
|
||||
canvas.MoveTo(120, float64(imgDY)-102)
|
||||
canvas.LineTo(120+renderLine, float64(imgDY)-102)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
|
||||
func drawScore15(a *scdata) (image.Image, error) {
|
||||
// 绘图
|
||||
_, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7))
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
canvas.Clear()
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
monthWord := time.Now().Format("01/02")
|
||||
hourWord := getHourWord(time.Now())
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, float64(back.Bounds().Size().X)*0.1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2)
|
||||
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2)
|
||||
_, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.FontFile, float64(back.Bounds().Size().X)*0.04); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawString(a.nickname+fmt.Sprintf(" ATRI币+%d", a.inc), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
|
||||
canvas.DrawString("当前ATRI币:"+strconv.FormatInt(int64(a.score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4)
|
||||
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(a.rank), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(150, 150, 150)
|
||||
canvas.Fill()
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(a.level)/float64(nextrankScore), float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(102, 102, 102)
|
||||
canvas.Fill()
|
||||
canvas.DrawString(fmt.Sprintf("%d/%d", a.level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
|
||||
func drawScore17(a *scdata) (image.Image, error) {
|
||||
getAvatar, err := initPic(a.picfile, a.uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
back, err := gg.LoadImage(a.picfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = imgfactory.Limit(back, 1280, 720)
|
||||
imgDX := back.Bounds().Dx()
|
||||
imgDY := back.Bounds().Dy()
|
||||
canvas := gg.NewContext(imgDX, imgDY)
|
||||
|
||||
// draw background
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
|
||||
// Create smaller Aero Style boxes
|
||||
createAeroBox := func(x, y, width, height float64) {
|
||||
aeroStyle := gg.NewContext(int(width), int(height))
|
||||
aeroStyle.DrawRoundedRectangle(0, 0, width, height, 8)
|
||||
aeroStyle.SetLineWidth(2)
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 100)
|
||||
aeroStyle.StrokePreserve()
|
||||
aeroStyle.SetRGBA255(255, 255, 255, 140)
|
||||
aeroStyle.Fill()
|
||||
canvas.DrawImage(aeroStyle.Image(), int(x), int(y))
|
||||
}
|
||||
|
||||
// draw aero boxes for text
|
||||
createAeroBox(20, float64(imgDY-120), 280, 100) // left bottom
|
||||
createAeroBox(float64(imgDX-272), float64(imgDY-60), 252, 40) // right bottom
|
||||
|
||||
// draw info(name, coin, etc)
|
||||
hourWord := getHourWord(time.Now())
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
data, err := file.GetLazyData(text.MaokenFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = canvas.ParseFontFace(data, 24); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getNameLengthWidth, _ := canvas.MeasureString(a.nickname)
|
||||
// draw aero box
|
||||
if getNameLengthWidth > 140 {
|
||||
createAeroBox(20, 40, 140+getNameLengthWidth, 100) // left top
|
||||
} else {
|
||||
createAeroBox(20, 40, 280, 100) // left top
|
||||
}
|
||||
|
||||
// draw avatar
|
||||
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatarf := imgfactory.Size(avatar, 100, 100)
|
||||
canvas.DrawImage(avatarf.Circle(0).Image(), 30, 20)
|
||||
|
||||
canvas.DrawString(a.nickname, 140, 80)
|
||||
canvas.DrawStringAnchored(hourWord, 140, 120, 0, 0)
|
||||
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(a.inc), 40, float64(imgDY-90), 0, 0)
|
||||
canvas.DrawStringAnchored("当前ATRI币:"+strconv.Itoa(a.score), 40, float64(imgDY-60), 0, 0)
|
||||
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(a.level)), 40, float64(imgDY-30), 0, 0)
|
||||
|
||||
// Draw Info(Time, etc.)
|
||||
getTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
canvas.DrawStringAnchored(getTime, float64(imgDX)-146, float64(imgDY)-40, 0.5, 0.5) // time
|
||||
var nextrankScore int
|
||||
if a.rank < 10 {
|
||||
nextrankScore = rankArray[a.rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
nextLevelStyle := strconv.Itoa(a.level) + "/" + strconv.Itoa(nextrankScore)
|
||||
canvas.DrawStringAnchored(nextLevelStyle, 190, float64(imgDY-30), 0, 0) // time
|
||||
|
||||
// Draw Zerobot-Plugin information
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
if err = canvas.ParseFontFace(data, 20); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
|
||||
canvas.SetRGB255(255, 255, 255)
|
||||
return canvas.Image(), nil
|
||||
}
|
||||
@@ -122,3 +122,14 @@ func (sdb *scoredb) GetScoreRankByTopN(n int) (st []scoretable, err error) {
|
||||
err = db.Model(&scoretable{}).Order("score desc").Limit(n).Find(&st).Error
|
||||
return
|
||||
}
|
||||
|
||||
type scdata struct {
|
||||
drawedfile string
|
||||
picfile string
|
||||
uid int64
|
||||
nickname string
|
||||
inc int // 增加币
|
||||
score int // 钱包
|
||||
level int
|
||||
rank int
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// Package score 签到,答题得分
|
||||
// Package score 签到
|
||||
package score
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/AnimeAPI/wallet"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/golang/freetype"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// 货币系统
|
||||
"github.com/FloatTech/AnimeAPI/wallet"
|
||||
)
|
||||
|
||||
const (
|
||||
backgroundURL = "https://img.moehu.org/pic.php?id=pc"
|
||||
backgroundURL = "https://iw233.cn/api.php?sort=pc"
|
||||
referer = "https://weibo.com/"
|
||||
signinMax = 1
|
||||
// SCOREMAX 分数上限定为1200
|
||||
SCOREMAX = 1200
|
||||
SCOREMAX = 1200
|
||||
defKeyID int64 = -6
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -40,9 +40,20 @@ var (
|
||||
engine = control.Register("score", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "签到",
|
||||
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
|
||||
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 设置[默认]签到预设(1~9)\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
|
||||
PrivateDataFolder: "score",
|
||||
})
|
||||
initDef = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
var defkey string
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.Response(defKeyID)
|
||||
_ = m.Manager.GetExtra(defKeyID, &defkey)
|
||||
if defkey == "" {
|
||||
_ = m.Manager.SetExtra(defKeyID, "1")
|
||||
return true
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -55,134 +66,130 @@ func init() {
|
||||
}
|
||||
sdb = initialize(engine.DataFolder() + "score.db")
|
||||
}()
|
||||
engine.OnFullMatch("签到").Limit(ctxext.LimitByUser).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
uid := ctx.Event.UserID
|
||||
now := time.Now()
|
||||
today := now.Format("20060102")
|
||||
// 签到图片
|
||||
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
|
||||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
|
||||
// 获取签到时间
|
||||
si := sdb.GetSignInByUID(uid)
|
||||
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
|
||||
switch {
|
||||
case si.Count >= signinMax && siUpdateTimeStr == today:
|
||||
// 如果签到时间是今天
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
}
|
||||
return
|
||||
case siUpdateTimeStr != today:
|
||||
// 如果是跨天签到就清数据
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
engine.OnRegex(`^签到\s?(\d*)$`, initDef).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
// 选择key
|
||||
var key string
|
||||
gid := ctx.Event.GroupID
|
||||
if gid < 0 {
|
||||
// 个人用户设为负数
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if ctx.State["regex_matched"].([]string)[1] != "" {
|
||||
key = ctx.State["regex_matched"].([]string)[1]
|
||||
} else {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.GetExtra(gid, &key)
|
||||
if key == "" {
|
||||
_ = m.Manager.GetExtra(defKeyID, &key)
|
||||
}
|
||||
// 更新签到次数
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
|
||||
}
|
||||
if !isExist(key) {
|
||||
ctx.SendChain(message.Text("未找到签到设定:", key)) // 避免签到配置错误造成无图发送,但是已经签到的情况
|
||||
return
|
||||
}
|
||||
uid := ctx.Event.UserID
|
||||
today := time.Now().Format("20060102")
|
||||
// 签到图片
|
||||
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
|
||||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
|
||||
// 获取签到时间
|
||||
si := sdb.GetSignInByUID(uid)
|
||||
siUpdateTimeStr := si.UpdatedAt.Format("20060102")
|
||||
switch {
|
||||
case si.Count >= signinMax && siUpdateTimeStr == today:
|
||||
// 如果签到时间是今天
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
}
|
||||
return
|
||||
case siUpdateTimeStr != today:
|
||||
// 如果是跨天签到就清数据
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新经验
|
||||
level := sdb.GetScoreByUID(uid).Score + 1
|
||||
if level > SCOREMAX {
|
||||
level = SCOREMAX
|
||||
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
|
||||
}
|
||||
err = sdb.InsertOrUpdateScoreByUID(uid, level)
|
||||
}
|
||||
// 更新签到次数
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新经验
|
||||
level := sdb.GetScoreByUID(uid).Score + 1
|
||||
if level > SCOREMAX {
|
||||
level = SCOREMAX
|
||||
ctx.SendChain(message.At(uid), message.Text("你的等级已经达到上限"))
|
||||
}
|
||||
err = sdb.InsertOrUpdateScoreByUID(uid, level)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新钱包
|
||||
rank := getrank(level)
|
||||
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
|
||||
err = wallet.InsertWalletOf(uid, add)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
alldata := scdata{
|
||||
drawedfile: drawedFile,
|
||||
picfile: picFile,
|
||||
uid: uid,
|
||||
nickname: ctx.CardOrNickName(uid),
|
||||
inc: add,
|
||||
score: wallet.GetWalletOf(uid),
|
||||
level: level,
|
||||
rank: rank,
|
||||
}
|
||||
var drawimage image.Image
|
||||
switch key {
|
||||
case "1":
|
||||
drawimage, err = drawScore16(&alldata)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 更新钱包
|
||||
rank := getrank(level)
|
||||
add := 1 + rand.Intn(10) + rank*5 // 等级越高获得的钱越高
|
||||
err = wallet.InsertWalletOf(uid, add)
|
||||
case "2":
|
||||
drawimage, err = drawScore15(&alldata)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
score := wallet.GetWalletOf(uid)
|
||||
// 绘图
|
||||
err = initPic(picFile)
|
||||
case "3":
|
||||
drawimage, err = drawScore17(&alldata)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
back, err := gg.LoadImage(picFile)
|
||||
default:
|
||||
ctx.SendChain(message.Text("未添加签到设定:", key))
|
||||
return
|
||||
}
|
||||
// done.
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
data, err := imgfactory.ToBytes(drawimage)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 避免图片过大,最大 1280*720
|
||||
back = img.Limit(back, 1280, 720)
|
||||
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7))
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
canvas.Clear()
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
monthWord := now.Format("01/02")
|
||||
hourWord := getHourWord(now)
|
||||
_, err = file.GetLazyData(text.BoldFontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, float64(back.Bounds().Size().X)*0.1); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2)
|
||||
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2)
|
||||
nickName := ctx.CardOrNickName(uid)
|
||||
_, err = file.GetLazyData(text.FontFile, control.Md5File, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if err = canvas.LoadFontFace(text.FontFile, float64(back.Bounds().Size().X)*0.04); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
canvas.DrawString(nickName+fmt.Sprintf(" ATRI币+%d", add), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
|
||||
canvas.DrawString("当前ATRI币:"+strconv.FormatInt(int64(score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4)
|
||||
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(rank), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(150, 150, 150)
|
||||
canvas.Fill()
|
||||
var nextrankScore int
|
||||
if rank < 10 {
|
||||
nextrankScore = rankArray[rank+1]
|
||||
} else {
|
||||
nextrankScore = SCOREMAX
|
||||
}
|
||||
canvas.SetRGB255(0, 0, 0)
|
||||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(level)/float64(nextrankScore), float64(back.Bounds().Size().Y)*0.1)
|
||||
canvas.SetRGB255(102, 102, 102)
|
||||
canvas.Fill()
|
||||
canvas.DrawString(fmt.Sprintf("%d/%d", level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
return
|
||||
}
|
||||
_, err = imgfactory.WriteTo(drawimage, f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[score]", 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.OnPrefix("获得签到背景", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
@@ -271,6 +278,31 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
engine.OnRegex(`^设置(默认)?签到预设\s?(\d*)$`, zero.SuperUserPermission).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
if ctx.State["regex_matched"].([]string)[2] == "" {
|
||||
ctx.SendChain(message.Text("设置失败,数据为空"))
|
||||
} else {
|
||||
s := ctx.State["regex_matched"].([]string)[1]
|
||||
key := ctx.State["regex_matched"].([]string)[2]
|
||||
if !isExist(key) {
|
||||
ctx.SendChain(message.Text("未找到签到设定:", key)) // 避免签到配置错误
|
||||
return
|
||||
}
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
if s != "" {
|
||||
gid = defKeyID
|
||||
}
|
||||
err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.SetExtra(gid, key)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("设置成功,当前", s, "预设为:", key))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getHourWord(t time.Time) string {
|
||||
@@ -302,10 +334,29 @@ func getrank(count int) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func initPic(picFile string) error {
|
||||
func initPic(picFile string, uid int64) (avatar []byte, err error) {
|
||||
if file.IsExist(picFile) {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
defer process.SleepAbout1sTo2s()
|
||||
return file.DownloadTo(backgroundURL, picFile)
|
||||
url, err := bilibili.GetRealURL(backgroundURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return avatar, os.WriteFile(picFile, data, 0644)
|
||||
}
|
||||
|
||||
func isExist(key string) bool {
|
||||
if key != "1" && key != "2" && key != "3" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -236,10 +236,7 @@ func (p *imgpool) add(ctx *zero.Ctx, imgtype string, id int64) error {
|
||||
return err
|
||||
}
|
||||
// 添加插画到对应的数据库table
|
||||
if err := p.db.Insert(imgtype, illust); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return p.db.Insert(imgtype, illust)
|
||||
}
|
||||
|
||||
func (p *imgpool) remove(imgtype string, id int64) error {
|
||||
|
||||
@@ -26,7 +26,7 @@ func init() {
|
||||
engine.OnPrefix("异世界转生", number(587874)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
engine.OnPrefix("今天是什么少女", number(162207)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
engine.OnPrefix("卖萌", number(360578)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handletxt)
|
||||
engine.OnPrefix("抽老婆", number(1075116)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlecq)
|
||||
engine.OnPrefix("今日老婆", number(1075116)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlecq)
|
||||
engine.OnPrefix("黄油角色", number(1115465)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
}
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ func timeDuration(time time.Duration) (hour, minute, second int64) {
|
||||
}
|
||||
|
||||
// 只统计6点到12点的早安
|
||||
func isMorning(ctx *zero.Ctx) bool {
|
||||
func isMorning(*zero.Ctx) bool {
|
||||
now := time.Now().Hour()
|
||||
return now >= 6 && now <= 12
|
||||
}
|
||||
|
||||
// 只统计21点到凌晨3点的晚安
|
||||
func isEvening(ctx *zero.Ctx) bool {
|
||||
func isEvening(*zero.Ctx) bool {
|
||||
now := time.Now().Hour()
|
||||
return now >= 21 || now <= 3
|
||||
}
|
||||
|
||||
134
plugin/steam/listenter.go
Normal file
134
plugin/steam/listenter.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package steam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
// ----------------------- 远程调用 ----------------------
|
||||
const (
|
||||
URL = "https://api.steampowered.com/" // steam API 调用地址
|
||||
StatusURL = "ISteamUser/GetPlayerSummaries/v2/?key=%+v&steamids=%+v" // 根据用户steamID获取用户状态
|
||||
steamapikeygid = 3
|
||||
)
|
||||
|
||||
var apiKey string
|
||||
|
||||
func init() {
|
||||
engine.OnRegex(`^steam绑定\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
apiKey = ctx.State["regex_matched"].([]string)[1]
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.Response(steamapikeygid)
|
||||
err := m.Manager.SetExtra(steamapikeygid, apiKey)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 保存apikey失败!"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("保存apikey成功!"))
|
||||
})
|
||||
engine.OnFullMatch("查看apikey", zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("apikey为: ", apiKey))
|
||||
})
|
||||
engine.OnFullMatch("拉取steam订阅", getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
su := zero.BotConfig.SuperUsers[0]
|
||||
// 获取所有处于监听状态的用户信息
|
||||
infos, err := database.findAll()
|
||||
if err != nil {
|
||||
// 挂了就给管理员发消息
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(infos) == 0 {
|
||||
return
|
||||
}
|
||||
// 收集这波用户的streamId,然后查当前的状态,并建立信息映射表
|
||||
streamIds := make([]string, len(infos))
|
||||
localPlayerMap := make(map[int64]*player)
|
||||
for i := 0; i < len(infos); i++ {
|
||||
streamIds[i] = strconv.FormatInt(infos[i].SteamID, 10)
|
||||
localPlayerMap[infos[i].SteamID] = &infos[i]
|
||||
}
|
||||
// 将所有用户状态查一遍
|
||||
playerStatus, err := getPlayerStatus(streamIds...)
|
||||
if err != nil {
|
||||
// 出错就发消息
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 遍历返回的信息做对比,假如信息有变化则发消息
|
||||
now := time.Now()
|
||||
msg := make(message.Message, 0, len(playerStatus))
|
||||
for _, playerInfo := range playerStatus {
|
||||
msg = msg[:0]
|
||||
localInfo := localPlayerMap[playerInfo.SteamID]
|
||||
// 排除不需要处理的情况
|
||||
if localInfo.GameID == 0 && playerInfo.GameID == 0 {
|
||||
continue
|
||||
}
|
||||
// 打开游戏
|
||||
if localInfo.GameID == 0 && playerInfo.GameID != 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "正在玩", playerInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = now.Unix()
|
||||
}
|
||||
// 更换游戏
|
||||
if localInfo.GameID != 0 && playerInfo.GameID != localInfo.GameID && playerInfo.GameID != 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 丢下了", localInfo.GameExtraInfo, ", 转头去玩", playerInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = now.Unix()
|
||||
}
|
||||
// 关闭游戏
|
||||
if playerInfo.GameID != localInfo.GameID && playerInfo.GameID == 0 {
|
||||
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 关掉了", localInfo.GameExtraInfo))
|
||||
localInfo.LastUpdate = 0
|
||||
}
|
||||
if len(msg) != 0 {
|
||||
groups := strings.Split(localInfo.Target, ",")
|
||||
for _, groupString := range groups {
|
||||
group, err := strconv.ParseInt(groupString, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nOTHER: SteamID ", localInfo.SteamID))
|
||||
continue
|
||||
}
|
||||
ctx.SendGroupMessage(group, msg)
|
||||
}
|
||||
}
|
||||
// 更新数据
|
||||
localInfo.GameID = playerInfo.GameID
|
||||
localInfo.GameExtraInfo = playerInfo.GameExtraInfo
|
||||
if err = database.update(localInfo); err != nil {
|
||||
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据失败\nOTHER: SteamID ", localInfo.SteamID))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// getPlayerStatus 获取用户状态
|
||||
func getPlayerStatus(streamIds ...string) ([]*player, error) {
|
||||
players := make([]*player, 0)
|
||||
// 拼接请求地址
|
||||
url := fmt.Sprintf(URL+StatusURL, apiKey, strings.Join(streamIds, ","))
|
||||
// 拉取并解析数据
|
||||
data, err := web.GetData(url)
|
||||
if err != nil {
|
||||
return players, err
|
||||
}
|
||||
dataStr := binary.BytesToString(data)
|
||||
index := gjson.Get(dataStr, "response.players.#").Uint()
|
||||
for i := uint64(0); i < index; i++ {
|
||||
players = append(players, &player{
|
||||
SteamID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.steamid", i)).Int(),
|
||||
PersonaName: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.personaname", i)).String(),
|
||||
GameID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameid", i)).Int(),
|
||||
GameExtraInfo: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameextrainfo", i)).String(),
|
||||
})
|
||||
}
|
||||
return players, nil
|
||||
}
|
||||
158
plugin/steam/steam.go
Normal file
158
plugin/steam/steam.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Package steam 获取steam用户状态
|
||||
package steam
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
engine = control.Register("steam", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "steam相关插件",
|
||||
Help: "- steam添加订阅 xxxxxxx (可输入需要绑定的 steamid)\n" +
|
||||
"- steam删除订阅 xxxxxxx (删除你创建的对于 steamid 的绑定)\n" +
|
||||
"- steam查询订阅 (查询本群内所有的绑定对象)\n" +
|
||||
"-----------------------\n" +
|
||||
"- steam绑定 api key xxxxxxx (密钥在steam网站申请, 申请地址: https://steamcommunity.com/dev/apikey)\n" +
|
||||
"- 查看apikey (查询已经绑定的密钥)\n" +
|
||||
"- 拉取steam订阅 (使用插件定时任务开始)\n" +
|
||||
"-----------------------\n" +
|
||||
"Tips: steamID在用户资料页的链接上面, 形如7656119820673xxxx\n" +
|
||||
"需要先私聊绑定apikey, 订阅用户之后使用job插件设置定时, 例: \n" +
|
||||
"记录在\"@every 1m\"触发的指令\n" +
|
||||
"拉取steam订阅",
|
||||
PrivateDataFolder: "steam",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 创建绑定流程
|
||||
engine.OnRegex(`^steam添加订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
steamidstr := ctx.State["regex_matched"].([]string)[1]
|
||||
steamID := math.Str2Int64(steamidstr)
|
||||
// 获取用户状态
|
||||
playerStatus, err := getPlayerStatus(steamidstr)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败, 获取用户信息错误"))
|
||||
return
|
||||
}
|
||||
if len(playerStatus) == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 需要添加的用户不存在, 请检查id或url"))
|
||||
return
|
||||
}
|
||||
playerData := playerStatus[0]
|
||||
// 判断用户是否已经初始化:若未初始化,通过用户的steamID获取当前状态并初始化;若已经初始化则更新用户信息
|
||||
info, err := database.find(steamID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
// 处理数据
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
if info.Target == "" {
|
||||
info = player{
|
||||
SteamID: steamID,
|
||||
PersonaName: playerData.PersonaName,
|
||||
Target: groupID,
|
||||
GameID: playerData.GameID,
|
||||
GameExtraInfo: playerData.GameExtraInfo,
|
||||
LastUpdate: time.Now().Unix(),
|
||||
}
|
||||
} else if !strings.Contains(info.Target, groupID) {
|
||||
info.Target = strings.Join([]string{info.Target, groupID}, ",")
|
||||
}
|
||||
// 更新数据库
|
||||
if err = database.update(&info); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据库失败"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("添加成功"))
|
||||
})
|
||||
// 删除绑定流程
|
||||
engine.OnRegex(`^steam删除订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
steamID := math.Str2Int64(ctx.State["regex_matched"].([]string)[1])
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
// 判断是否已经绑定该steamID,若已绑定就将群列表从推送群列表钟去除
|
||||
info, err := database.findWithGroupID(steamID, groupID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
if info.SteamID == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 所需要删除的用户不存在。"))
|
||||
return
|
||||
}
|
||||
// 从绑定列表中剔除需要删除的对象
|
||||
targets := strings.Split(info.Target, ",")
|
||||
newTargets := make([]string, 0)
|
||||
for _, target := range targets {
|
||||
if target == groupID {
|
||||
continue
|
||||
}
|
||||
newTargets = append(newTargets, target)
|
||||
}
|
||||
if len(newTargets) == 0 {
|
||||
if err = database.del(steamID); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
info.Target = strings.Join(newTargets, ",")
|
||||
if err = database.update(&info); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("删除成功"))
|
||||
})
|
||||
// 查询当前群绑定信息
|
||||
engine.OnFullMatch("steam查询订阅", zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群信息
|
||||
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
// 获取所有绑定信息
|
||||
infos, err := database.findAll()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 查询订阅失败, 数据库错误"))
|
||||
return
|
||||
}
|
||||
if len(infos) == 0 {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: 还未订阅过用户关系!"))
|
||||
return
|
||||
}
|
||||
// 遍历所有信息,如果包含该群就收集对应的steamID
|
||||
var sb strings.Builder
|
||||
head := " 查询steam订阅成功, 该群订阅的用户有: \n"
|
||||
sb.WriteString(head)
|
||||
for _, info := range infos {
|
||||
if strings.Contains(info.Target, groupID) {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(info.PersonaName)
|
||||
sb.WriteString(":")
|
||||
sb.WriteString(strconv.FormatInt(info.SteamID, 10))
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
}
|
||||
if sb.String() == head {
|
||||
ctx.SendChain(message.Text("查询成功,该群暂时还没有被绑定的用户!"))
|
||||
return
|
||||
}
|
||||
// 组装并返回结果
|
||||
data, err := text.RenderToBase64(sb.String(), text.FontFile, 400, 18)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(data)))
|
||||
})
|
||||
}
|
||||
117
plugin/steam/store.go
Normal file
117
plugin/steam/store.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package steam
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
database streamDB
|
||||
// 开启并检查数据库链接
|
||||
getDB = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
database.db.DBPath = engine.DataFolder() + "steam.db"
|
||||
err := database.db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
if err = database.db.Create(TableListenPlayer, &player{}); err != nil {
|
||||
ctx.SendChain(message.Text("[steam] ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
// 校验密钥是否初始化
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
_ = m.Manager.Response(steamapikeygid)
|
||||
_ = m.Manager.GetExtra(steamapikeygid, &apiKey)
|
||||
if apiKey == "" {
|
||||
ctx.SendChain(message.Text("ERROR: 未设置steam apikey"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
|
||||
// streamDB 继承方法的存储结构
|
||||
type streamDB struct {
|
||||
sync.RWMutex
|
||||
db sql.Sqlite
|
||||
}
|
||||
|
||||
const (
|
||||
// TableListenPlayer 存储查询用户信息
|
||||
TableListenPlayer = "listen_player"
|
||||
)
|
||||
|
||||
// player 用户状态存储结构体
|
||||
type player struct {
|
||||
SteamID int64 `json:"steam_id"` // 绑定用户标识ID
|
||||
PersonaName string `json:"persona_name"` // 用户昵称
|
||||
Target string `json:"target"` // 信息推送群组
|
||||
GameID int64 `json:"game_id"` // 游戏ID
|
||||
GameExtraInfo string `json:"game_extra_info"` // 游戏信息
|
||||
LastUpdate int64 `json:"last_update"` // 更新时间
|
||||
}
|
||||
|
||||
// update 如果主键不存在则插入一条新的数据,如果主键存在直接复写
|
||||
func (sql *streamDB) update(dbInfo *player) error {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
return sql.db.Insert(TableListenPlayer, dbInfo)
|
||||
}
|
||||
|
||||
// find 根据主键查信息
|
||||
func (sql *streamDB) find(steamID int64) (dbInfo player, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
condition := "where steam_id = " + strconv.FormatInt(steamID, 10)
|
||||
if !sql.db.CanFind(TableListenPlayer, condition) {
|
||||
return player{}, nil // 规避没有该用户数据的报错
|
||||
}
|
||||
err = sql.db.Find(TableListenPlayer, &dbInfo, condition)
|
||||
return
|
||||
}
|
||||
|
||||
// findWithGroupID 根据用户steamID和groupID查询信息
|
||||
func (sql *streamDB) findWithGroupID(steamID int64, groupID string) (dbInfo player, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
condition := "where steam_id = " + strconv.FormatInt(steamID, 10) + " AND target LIKE '%" + groupID + "%'"
|
||||
if !sql.db.CanFind(TableListenPlayer, condition) {
|
||||
return player{}, nil // 规避没有该用户数据的报错
|
||||
}
|
||||
err = sql.db.Find(TableListenPlayer, &dbInfo, condition)
|
||||
return
|
||||
}
|
||||
|
||||
// findAll 查询所有库信息
|
||||
func (sql *streamDB) findAll() (dbInfos []player, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
var info player
|
||||
num, err := sql.db.Count(TableListenPlayer)
|
||||
if err != nil || num == 0 {
|
||||
return
|
||||
}
|
||||
dbInfos = make([]player, 0, num)
|
||||
err = sql.db.FindFor(TableListenPlayer, &info, "", func() error {
|
||||
if info.SteamID != 0 {
|
||||
dbInfos = append(dbInfos, info)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// del 删除指定数据
|
||||
func (sql *streamDB) del(steamID int64) error {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
return sql.db.Del(TableListenPlayer, "where steam_id = "+strconv.FormatInt(steamID, 10))
|
||||
}
|
||||
@@ -122,10 +122,6 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: 张数必须为正"))
|
||||
return
|
||||
}
|
||||
if n > 1 && !zero.OnlyGroup(ctx) {
|
||||
ctx.SendChain(message.Text("ERROR: 抽取多张仅支持群聊"))
|
||||
return
|
||||
}
|
||||
if n > 20 {
|
||||
ctx.SendChain(message.Text("ERROR: 抽取张数过多"))
|
||||
return
|
||||
|
||||
@@ -146,10 +146,7 @@ const (
|
||||
|
||||
func match(l []string, seg *jieba.Segmenter) zero.Rule {
|
||||
return func(ctx *zero.Ctx) bool {
|
||||
if zero.FullMatchRule(l...)(ctx) {
|
||||
return true
|
||||
}
|
||||
return ctxext.JiebaFullMatch(seg, func(ctx *zero.Ctx) string {
|
||||
return ctxext.JiebaSimilarity(0.66, seg, func(ctx *zero.Ctx) string {
|
||||
return ctx.ExtractPlainText()
|
||||
}, l...)(ctx)
|
||||
}
|
||||
|
||||
321
plugin/vtbmusic/vtbmusic.go
Normal file
321
plugin/vtbmusic/vtbmusic.go
Normal file
@@ -0,0 +1,321 @@
|
||||
// Package vtbmusic vtb点歌
|
||||
package vtbmusic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"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/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
getGroupListURL = "https://aqua.chat/v1/GetGroupsList"
|
||||
getMusicListURL = "https://aqua.chat/v1/GetMusicList"
|
||||
fileURL = "https://cdn.aqua.chat/"
|
||||
musicListBody = `{"search":{"condition":"VocalId","keyword":"%v"},"sortField":"CreateTime","sortType":"desc","pageIndex":1,"pageRows":10000}`
|
||||
)
|
||||
|
||||
type groupsList struct {
|
||||
Total int `json:"Total"`
|
||||
Data []struct {
|
||||
ID string `json:"Id"`
|
||||
CreateTime string `json:"CreateTime"`
|
||||
Name string `json:"Name"`
|
||||
GroupImg string `json:"GroupImg"`
|
||||
VocalList []struct {
|
||||
ID string `json:"Id"`
|
||||
CreateTime string `json:"CreateTime"`
|
||||
ChineseName string `json:"ChineseName"`
|
||||
OriginName string `json:"OriginName"`
|
||||
AvatarImg string `json:"AvatarImg"`
|
||||
} `json:"VocalList"`
|
||||
} `json:"Data"`
|
||||
Success bool `json:"Success"`
|
||||
ErrorCode int `json:"ErrorCode"`
|
||||
Msg interface{} `json:"Msg"`
|
||||
}
|
||||
|
||||
type musicList struct {
|
||||
Total int `json:"Total"`
|
||||
Data []struct {
|
||||
ID string `json:"Id"`
|
||||
CreateTime string `json:"CreateTime"`
|
||||
PublishTime interface{} `json:"PublishTime"`
|
||||
CreatorID interface{} `json:"CreatorId"`
|
||||
CreatorRealName interface{} `json:"CreatorRealName"`
|
||||
Deleted bool `json:"Deleted"`
|
||||
OriginName string `json:"OriginName"`
|
||||
VocalID string `json:"VocalId"`
|
||||
VocalName string `json:"VocalName"`
|
||||
CoverImg string `json:"CoverImg"`
|
||||
Music string `json:"Music"`
|
||||
Lyric interface{} `json:"Lyric"`
|
||||
CDN string `json:"CDN"`
|
||||
BiliBili interface{} `json:"BiliBili"`
|
||||
YouTube interface{} `json:"YouTube"`
|
||||
Twitter interface{} `json:"Twitter"`
|
||||
Likes interface{} `json:"Likes"`
|
||||
Length float64 `json:"Length"`
|
||||
Label interface{} `json:"Label"`
|
||||
IsLike bool `json:"isLike"`
|
||||
Duration float64 `json:"Duration"`
|
||||
Source interface{} `json:"Source"`
|
||||
SourceName interface{} `json:"SourceName"`
|
||||
Statis struct {
|
||||
PlayCount int `json:"PlayCount"`
|
||||
CommentCount int `json:"CommentCount"`
|
||||
LikeCount int `json:"LikeCount"`
|
||||
ShareCount int `json:"ShareCount"`
|
||||
} `json:"Statis"`
|
||||
VocalList []struct {
|
||||
ID string `json:"Id"`
|
||||
Cn string `json:"cn"`
|
||||
Jp string `json:"jp"`
|
||||
En string `json:"en"`
|
||||
Originlang string `json:"originlang"`
|
||||
} `json:"VocalList"`
|
||||
} `json:"Data"`
|
||||
Success bool `json:"Success"`
|
||||
ErrorCode int `json:"ErrorCode"`
|
||||
Msg interface{} `json:"Msg"`
|
||||
}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("vtbmusic", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "vtbmusic.com点歌",
|
||||
Help: "- vtb点歌\n" +
|
||||
"- vtb随机点歌",
|
||||
PrivateDataFolder: "vtbmusic",
|
||||
})
|
||||
storePath := engine.DataFolder()
|
||||
// 开启
|
||||
engine.OnFullMatch(`vtb点歌`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession(), zero.RegexRule(`^\d+$`))
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
i := 0
|
||||
paras := [3]int{}
|
||||
data, err := web.PostData(getGroupListURL, "application/json", strings.NewReader(`{"PageIndex":1,"PageRows":9999}`))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var (
|
||||
gl groupsList
|
||||
ml musicList
|
||||
num int
|
||||
imageBytes []byte
|
||||
)
|
||||
err = json.Unmarshal(data, &gl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tex := "请输入群组序号\n"
|
||||
for i, v := range gl.Data {
|
||||
tex += fmt.Sprintf("%d. %s\n", i, v.Name)
|
||||
}
|
||||
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 120):
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("vtb点歌超时"))
|
||||
return
|
||||
case c := <-recv:
|
||||
msg := c.Event.Message.ExtractPlainText()
|
||||
num, err = strconv.Atoi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请输入数字!"))
|
||||
continue
|
||||
}
|
||||
switch i {
|
||||
case 0:
|
||||
if num < 0 || num >= len(gl.Data) {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
if len(gl.Data[num].VocalList) == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无内容, 点歌失败"))
|
||||
return
|
||||
}
|
||||
paras[0] = num
|
||||
tex = "请输入vtb序号\n"
|
||||
for i, v := range gl.Data[paras[0]].VocalList {
|
||||
tex += fmt.Sprintf("%d. %s\n", i, v.OriginName)
|
||||
}
|
||||
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
case 1:
|
||||
if num < 0 || num >= len(gl.Data[paras[0]].VocalList) {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
paras[1] = num
|
||||
data, err := web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &ml)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(ml.Data) == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无内容, 点歌失败"))
|
||||
return
|
||||
}
|
||||
tex = "请输入歌曲序号\n"
|
||||
for i, v := range ml.Data {
|
||||
tex += fmt.Sprintf("%d. %s\n", i, v.OriginName)
|
||||
}
|
||||
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
case 2:
|
||||
if num < 0 || num >= len(ml.Data) {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
paras[2] = num
|
||||
// 最后播放歌曲
|
||||
groupName := gl.Data[paras[0]].Name
|
||||
vtbName := gl.Data[paras[0]].VocalList[paras[1]].OriginName
|
||||
musicName := ml.Data[paras[2]].OriginName
|
||||
recURL := fileURL + ml.Data[paras[2]].Music
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请欣赏", groupName, "-", vtbName, "的《", musicName, "》"))
|
||||
recordFile := storePath + fmt.Sprintf("%d-%d-%d", paras[0], paras[1], paras[2]) + path.Ext(recURL)
|
||||
if file.IsExist(recordFile) {
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
|
||||
return
|
||||
}
|
||||
err = dlrec(recordFile, recURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
|
||||
return
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch(`vtb随机点歌`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var (
|
||||
paras = [3]int{}
|
||||
gl groupsList
|
||||
ml musicList
|
||||
)
|
||||
data, err := web.PostData(getGroupListURL, "application/json", strings.NewReader(`{"PageIndex":1,"PageRows":9999}`))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &gl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(gl.Data) == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 数组为空"))
|
||||
return
|
||||
}
|
||||
paras[0] = rand.Intn(len(gl.Data))
|
||||
for len(gl.Data[paras[0]].VocalList) == 0 {
|
||||
paras[0] = rand.Intn(len(gl.Data))
|
||||
}
|
||||
paras[1] = rand.Intn(len(gl.Data[paras[0]].VocalList))
|
||||
data, err = web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &ml)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
for len(ml.Data) == 0 {
|
||||
paras[1] = rand.Intn(len(gl.Data[paras[0]].VocalList))
|
||||
data, err = web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &ml)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
paras[2] = rand.Intn(len(ml.Data))
|
||||
// 最后播放歌曲
|
||||
groupName := gl.Data[paras[0]].Name
|
||||
vtbName := gl.Data[paras[0]].VocalList[paras[1]].OriginName
|
||||
musicName := ml.Data[paras[2]].OriginName
|
||||
recURL := fileURL + ml.Data[paras[2]].Music
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请欣赏", groupName, "-", vtbName, "的《", musicName, "》"))
|
||||
recordFile := storePath + fmt.Sprintf("%d-%d-%d", paras[0], paras[1], paras[2]) + path.Ext(recURL)
|
||||
if file.IsExist(recordFile) {
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
|
||||
return
|
||||
}
|
||||
err = dlrec(recordFile, recURL)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
|
||||
})
|
||||
}
|
||||
|
||||
func dlrec(recordFile, recordURL string) error {
|
||||
if file.IsNotExist(recordFile) {
|
||||
data, err := web.RequestDataWithHeaders(web.NewTLS12Client(), recordURL, "GET", func(r *http.Request) error {
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
r.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0")
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(recordFile, data, 0666)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
110
plugin/warframeapi/api.go
Normal file
110
plugin/warframeapi/api.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package warframeapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/RomiChan/syncx"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
)
|
||||
|
||||
const wfapiurl = "https://api.warframestat.us/pc" // 星际战甲API
|
||||
const wfitemurl = "https://api.warframe.market/v1/items" // 星际战甲游戏品信息列表URL
|
||||
|
||||
// 从WFapi获取数据
|
||||
func newwfapi() (w wfapi, err error) {
|
||||
var data []byte
|
||||
data, err = web.GetData(wfapiurl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &w)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取Warframe市场的售价表,并进行排序,cn_name为物品中文名称,onlyMaxRank表示只取最高等级的物品,返回物品售价表,物品信息,物品英文
|
||||
func getitemsorder(cnName string, onlyMaxRank bool) (od orders, it *itemsInSet, n string, err error) {
|
||||
var wfapiio wfAPIItemsOrders
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{}, fmt.Sprintf("https://api.warframe.market/v1/items/%s/orders?include=item", cnName), "GET", func(request *http.Request) error {
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("Platform", "pc")
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &wfapiio)
|
||||
if len(wfapiio.Payload.Orders) == 0 {
|
||||
err = errors.New("no such name")
|
||||
}
|
||||
od = make(orders, 0, len(wfapiio.Payload.Orders))
|
||||
// 遍历市场物品列表
|
||||
for _, v := range wfapiio.Payload.Orders {
|
||||
// 取其中类型为售卖,且去掉不在线的玩家
|
||||
if v.OrderType == "sell" && v.User.Status != "offline" {
|
||||
if !onlyMaxRank {
|
||||
od = append(od, v)
|
||||
continue
|
||||
}
|
||||
if v.ModRank == wfapiio.Include.Item.ItemsInSet[0].ModMaxRank {
|
||||
od = append(od, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 对报价表进行排序,由低到高
|
||||
sort.Sort(od)
|
||||
// 获取物品信息
|
||||
for i, v := range wfapiio.Include.Item.ItemsInSet {
|
||||
if v.URLName == cnName {
|
||||
it = &wfapiio.Include.Item.ItemsInSet[i]
|
||||
n = v.En.ItemName
|
||||
return
|
||||
}
|
||||
}
|
||||
it = &wfapiio.Include.Item.ItemsInSet[0]
|
||||
n = wfapiio.Include.Item.ItemsInSet[0].En.ItemName
|
||||
return
|
||||
}
|
||||
|
||||
type wmdata struct {
|
||||
wmitems map[string]items
|
||||
itemNames []string
|
||||
}
|
||||
|
||||
var (
|
||||
wderr error
|
||||
wd = syncx.Lazy[*wmdata]{Init: func() (d *wmdata) {
|
||||
d, wderr = newwm()
|
||||
return
|
||||
}}
|
||||
)
|
||||
|
||||
func newwm() (*wmdata, error) {
|
||||
var itemapi wfAPIItem // WarFrame市场的数据实例
|
||||
var wd wmdata
|
||||
data, err := web.RequestDataWithHeaders(&http.Client{}, wfitemurl, "GET", func(request *http.Request) error {
|
||||
request.Header.Add("Accept", "application/json")
|
||||
request.Header.Add("Language", "zh-hans")
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return &wd, err
|
||||
}
|
||||
err = json.Unmarshal(data, &itemapi)
|
||||
if err != nil {
|
||||
return &wd, err
|
||||
}
|
||||
wd.wmitems = make(map[string]items, len(itemapi.Payload.Items)*4)
|
||||
wd.itemNames = make([]string, len(itemapi.Payload.Items))
|
||||
for i, v := range itemapi.Payload.Items {
|
||||
wd.wmitems[v.ItemName] = v
|
||||
wd.itemNames[i] = v.ItemName
|
||||
}
|
||||
logrus.Infoln("[wfapi] 获取", len(wd.itemNames), "项内容")
|
||||
return &wd, nil
|
||||
}
|
||||
418
plugin/warframeapi/main.go
Normal file
418
plugin/warframeapi/main.go
Normal file
@@ -0,0 +1,418 @@
|
||||
// Package warframeapi 星际战甲
|
||||
package warframeapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/RomiChan/syncx"
|
||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
eng := control.Register("warframeapi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "星际战甲",
|
||||
Help: "- wf时间同步\n" +
|
||||
"- [金星|地球|火卫二]平原时间\n" +
|
||||
"- .wm [物品名称]\n" +
|
||||
"- wf仲裁\n" +
|
||||
"- wf警报\n" +
|
||||
"- wf每日特惠",
|
||||
PrivateDataFolder: "warframeapi",
|
||||
})
|
||||
|
||||
// 获取具体的平原时间, 在触发后, 会启动持续时间按5分钟的时间更新模拟, 以此处理短时间内请求时, 时间不会变化的问题
|
||||
eng.OnSuffix("平原时间").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if !gameWorld.hasSync() { // 没有进行同步,就拉取一次服务器状态
|
||||
wfapi, err := newwfapi()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 获取服务器时间失败"))
|
||||
}
|
||||
gameWorld.refresh(&wfapi)
|
||||
}
|
||||
var msg any
|
||||
switch ctx.State["args"].(string) {
|
||||
case "地球", "夜灵":
|
||||
msg = gameWorld.w[0]
|
||||
case "金星", "奥布山谷":
|
||||
msg = gameWorld.w[1]
|
||||
case "魔胎之境", "火卫二", "火卫":
|
||||
msg = gameWorld.w[2]
|
||||
default:
|
||||
msg = "ERROR: 平原不存在"
|
||||
}
|
||||
ctx.SendChain(message.Text(msg))
|
||||
// 是否正在进行同步,没有就开启同步,有就不开启
|
||||
if !gameWorld.hasSync() {
|
||||
if gameWorld.setsync() {
|
||||
go func() {
|
||||
// 30*10=300=5分钟
|
||||
for i := 0; i < 30; i++ {
|
||||
time.Sleep(10 * time.Second)
|
||||
gameWorld.update() // 5分钟内每隔10秒更新一下时间
|
||||
}
|
||||
// 5分钟时间同步结束
|
||||
_ = gameWorld.resetsync()
|
||||
}()
|
||||
}
|
||||
}
|
||||
})
|
||||
eng.OnFullMatch("wf警报").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
wfapi, err := newwfapi()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 如果返回的wfapi中, 警报数量>0
|
||||
if len(wfapi.Alerts) > 0 {
|
||||
msgs := make(message.Message, len(wfapi.Alerts))
|
||||
// 遍历警报数据, 打印警报信息
|
||||
for i, v := range wfapi.Alerts {
|
||||
msgs[i] = ctxext.FakeSenderForwardNode(ctx, message.Text(
|
||||
"激活: ", v.Active,
|
||||
"\n节点: ", v.Mission.Node,
|
||||
"\n类型: ", v.Mission.Type,
|
||||
"\n敌人等级: ", v.Mission.MinEnemyLevel, "~", v.Mission.MaxEnemyLevel,
|
||||
"\n奖励: ", v.Mission.Reward.AsString,
|
||||
"\n剩余时间:", v.Eta))
|
||||
}
|
||||
ctx.SendChain(msgs...)
|
||||
}
|
||||
})
|
||||
//TODO:订阅功能-等待重做
|
||||
// eng.OnRegex(`^(订阅|取消订阅)(.*)平原(.*)$`).SetBlock(true).
|
||||
// Handle(func(ctx *zero.Ctx) {
|
||||
// args := ctx.State["regex_matched"].([]string)
|
||||
// var isEnable bool
|
||||
// if args[1] == "订阅" {
|
||||
// isEnable = true
|
||||
// }
|
||||
// updateWFAPI()
|
||||
// status := false
|
||||
// switch args[3] {
|
||||
// case "fass", "白天", "温暖":
|
||||
// status = true
|
||||
// }
|
||||
// switch args[2] {
|
||||
// case "金星", "奥布山谷":
|
||||
// //sublist = append(sublist, subList{ctx.Event.GroupID, ctx.Event.UserID, 1, status, false})
|
||||
// if isEnable {
|
||||
// addUseSub(ctx.Event.UserID, ctx.Event.GroupID, 1, status)
|
||||
// } else {
|
||||
// removeUseSub(ctx.Event.UserID, ctx.Event.GroupID, 1)
|
||||
// }
|
||||
// ctx.SendChain(
|
||||
// message.At(ctx.Event.UserID),
|
||||
// message.Text("已成功", args[1]),
|
||||
// message.Text(gameTimes[1].Name),
|
||||
// message.Text(status),
|
||||
// )
|
||||
// case "地球", "夜灵":
|
||||
// if isEnable {
|
||||
// addUseSub(ctx.Event.UserID, ctx.Event.GroupID, 0, status)
|
||||
// } else {
|
||||
// removeUseSub(ctx.Event.UserID, ctx.Event.GroupID, 0)
|
||||
// }
|
||||
// ctx.SendChain(
|
||||
// message.At(ctx.Event.UserID),
|
||||
// message.Text("已成功", args[1]),
|
||||
// message.Text(gameTimes[0].Name),
|
||||
// message.Text(status),
|
||||
// )
|
||||
// case "魔胎之境", "火卫", "火卫二":
|
||||
// if isEnable {
|
||||
// addUseSub(ctx.Event.UserID, ctx.Event.GroupID, 2, status)
|
||||
// } else {
|
||||
// removeUseSub(ctx.Event.UserID, ctx.Event.GroupID, 2)
|
||||
// }
|
||||
// ctx.SendChain(
|
||||
// message.At(ctx.Event.UserID),
|
||||
// message.Text("已成功", args[1]),
|
||||
// message.Text(gameTimes[2].Name),
|
||||
// message.Text(status),
|
||||
// )
|
||||
// default:
|
||||
// ctx.SendChain(message.Text("ERROR: 平原不存在"))
|
||||
// return
|
||||
// }
|
||||
// })
|
||||
// eng.OnFullMatch(`wf订阅检测`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
// rwm.Lock()
|
||||
// var msg []message.MessageSegment
|
||||
// for i, v := range gameTimes {
|
||||
// nt := time.Until(v.NextTime).Seconds()
|
||||
// switch {
|
||||
// case nt < 0:
|
||||
// if v.Status {
|
||||
// v.NextTime = v.NextTime.Add(time.Duration(v.NightTime) * time.Second)
|
||||
// } else {
|
||||
// v.NextTime = v.NextTime.Add(time.Duration(v.DayTime) * time.Second)
|
||||
// }
|
||||
// v.Status = !v.Status
|
||||
//
|
||||
// msg = callUser(i, v.Status, 0)
|
||||
// case nt < float64(5)*60:
|
||||
// msg = callUser(i, !v.Status, 5)
|
||||
// case nt < float64(15)*60:
|
||||
// if i == 2 && !v.Status {
|
||||
// return
|
||||
// }
|
||||
// msg = callUser(i, !v.Status, 15)
|
||||
// }
|
||||
// }
|
||||
// rwm.Unlock()
|
||||
// if msg != nil && len(msg) > 0 {
|
||||
// ctx.SendChain(msg...)
|
||||
// }
|
||||
// })
|
||||
eng.OnFullMatch("wf仲裁").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 通过wfapi获取仲裁信息
|
||||
wfapi, err := newwfapi()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"节点: ", wfapi.Arbitration.Node,
|
||||
"\n类型: ", wfapi.Arbitration.Type,
|
||||
"\n阵营: ", wfapi.Arbitration.Enemy,
|
||||
"\n剩余时间: ", int(wfapi.Arbitration.Expiry.Sub(time.Now().UTC()).Minutes()), "m",
|
||||
))
|
||||
})
|
||||
eng.OnFullMatch("wf每日特惠").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
wfapi, err := newwfapi()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(wfapi.DailyDeals) > 0 {
|
||||
msgs := make(message.Message, len(wfapi.DailyDeals))
|
||||
for i, dd := range wfapi.DailyDeals {
|
||||
msgs[i] = ctxext.FakeSenderForwardNode(ctx, message.Text(
|
||||
"物品: ", dd.Item,
|
||||
"\n价格: ", dd.OriginalPrice, "→", dd.SalePrice,
|
||||
"\n数量: (", dd.Total, "/", dd.Sold, ")",
|
||||
"\n时间: ", dd.Eta,
|
||||
))
|
||||
}
|
||||
ctx.SendChain(msgs...)
|
||||
}
|
||||
})
|
||||
// eng.OnRegex(`^入侵$`).SetBlock(true).
|
||||
// Handle(func(ctx *zero.Ctx) {
|
||||
// updateWFAPI(ctx)
|
||||
// for _, dd := range wfapi.dailyDeals {
|
||||
// imagebuild.DrawTextSend([]string{
|
||||
// "节点:" + wfapi.arbitration.Node,
|
||||
// "类型:" + wfapi.arbitration.Type,
|
||||
// "阵营:" + wfapi.arbitration.Enemy,
|
||||
// "剩余时间:" + fmt.Sprint(int(wfapi.arbitration.Expiry.Sub(time.Now().UTC()).Minutes())) + "m",
|
||||
// }, ctx)
|
||||
// }
|
||||
// })
|
||||
eng.OnFullMatch("wf时间同步").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
wfapi, err := newwfapi()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
gameWorld.refresh(&wfapi)
|
||||
ctx.SendChain(message.Text("已拉取服务器时间并同步到本地模拟"))
|
||||
})
|
||||
// 根据名称从Warframe市场查询物品售价
|
||||
eng.OnPrefix(".wm ", func(ctx *zero.Ctx) bool {
|
||||
if wd.Get().wmitems == nil || wd.Get().itemNames == nil {
|
||||
if wderr != nil { // 获取失败
|
||||
ctx.SendChain(message.Text("ERROR: 获取Warframe市场物品列表失败: ", wderr))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("ERROR: Warframe市场物品列表为空!"))
|
||||
}
|
||||
wd = syncx.Lazy[*wmdata]{Init: func() (d *wmdata) {
|
||||
d, wderr = newwm()
|
||||
return
|
||||
}}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 根据输入的名称, 从游戏物品名称列表中进行模糊搜索
|
||||
sol := fuzzy.FindNormalizedFold(ctx.State["args"].(string), wd.Get().itemNames)
|
||||
// 物品名称
|
||||
var name string
|
||||
|
||||
// 根据搜搜结果, 打印找到的物品
|
||||
switch len(sol) {
|
||||
case 0: // 没有搜索到任何东西
|
||||
ctx.SendChain(message.Text("无法查询到该物品"))
|
||||
return
|
||||
case 1: // 如果只搜索到了一个
|
||||
name = sol[0]
|
||||
default: // 如果搜搜到了多个
|
||||
sb := strings.Builder{}
|
||||
if len(sol) > 25 {
|
||||
sb.WriteString("数量过多, 只显示前25\n")
|
||||
sol = sol[:25]
|
||||
}
|
||||
sb.WriteString("[0] ")
|
||||
sb.WriteString(sol[0])
|
||||
for i, v := range sol[1:] {
|
||||
sb.WriteString("\n[")
|
||||
sb.WriteString(strconv.Itoa(i + 1))
|
||||
sb.WriteString("] ")
|
||||
sb.WriteString(v)
|
||||
}
|
||||
ctx.SendChain(
|
||||
ctxext.FakeSenderForwardNode(ctx, message.Text("包含多个结果, 请输入编号查看(30s内),输入c直接结束会话")),
|
||||
ctxext.FakeSenderForwardNode(ctx, message.Text(&sb)),
|
||||
)
|
||||
itemIndex := getitemnameindex(ctx)
|
||||
if itemIndex < 0 {
|
||||
return
|
||||
}
|
||||
if itemIndex >= len(sol) || itemIndex < 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 编号超出范围"))
|
||||
return
|
||||
}
|
||||
name = sol[itemIndex]
|
||||
}
|
||||
onlymaxrank := false
|
||||
msgs := message.Message{}
|
||||
GETWM:
|
||||
if onlymaxrank {
|
||||
msgs = msgs[:0]
|
||||
}
|
||||
|
||||
sells, iteminfo, txt, err := getitemsorder(wd.Get().wmitems[name].URLName, onlymaxrank)
|
||||
if !onlymaxrank {
|
||||
if iteminfo.ZhHans.WikiLink == "" {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image("https://warframe.market/static/assets/"+wd.Get().wmitems[name].Thumb),
|
||||
message.Text("\n", wd.Get().wmitems[name].ItemName)))
|
||||
} else {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Image("https://warframe.market/static/assets/"+wd.Get().wmitems[name].Thumb),
|
||||
message.Text("\n", wd.Get().wmitems[name].ItemName, "\nwiki: ", iteminfo.ZhHans.WikiLink)))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx, message.Text("ERROR: ", err)))
|
||||
ctx.SendChain(msgs...)
|
||||
return
|
||||
}
|
||||
if sells == nil {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx, message.Text("无可购买对象")))
|
||||
ctx.SendChain(msgs...)
|
||||
return
|
||||
}
|
||||
|
||||
ismod := iteminfo.ModMaxRank != 0
|
||||
max := 5
|
||||
if len(sells) < max {
|
||||
max = len(sells)
|
||||
}
|
||||
sb := strings.Builder{}
|
||||
if ismod {
|
||||
if !onlymaxrank {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx, message.Text("请输入编号选择, 或输入r获取满级报价(30s内)\n输入c直接结束会话")))
|
||||
} else {
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx, message.Text("请输入编号选择(30s内)\n输入c直接结束会话")))
|
||||
}
|
||||
for i := 0; i < max; i++ {
|
||||
// msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
|
||||
// message.Text(fmt.Sprintf("[%d] (Rank:%d/%d) %dP - %s\n", i, sells[i].ModRank, iteminfo.ModMaxRank, sells[i].Platinum, sells[i].User.IngameName))))
|
||||
sb.WriteString(fmt.Sprintf("[%d] (Rank:%d/%d) %dP - %s\n", i, sells[i].ModRank, iteminfo.ModMaxRank, sells[i].Platinum, sells[i].User.IngameName))
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < max; i++ {
|
||||
// msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
|
||||
// message.Text(fmt.Sprintf("[%d] %dP -%s\n", i, sells[i].Platinum, sells[i].User.IngameName))))
|
||||
sb.WriteString(fmt.Sprintf("[%d] %dP -%s\n", i, sells[i].Platinum, sells[i].User.IngameName))
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx, message.Text(&sb)))
|
||||
ctx.SendChain(msgs...)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession()).Next()
|
||||
select {
|
||||
case <-time.After(time.Second * 30):
|
||||
ctx.SendChain(message.Text("会话已结束!"))
|
||||
return
|
||||
case e := <-next:
|
||||
msg := e.Event.Message.ExtractPlainText()
|
||||
// 重新获取报价
|
||||
if msg == "r" {
|
||||
onlymaxrank = true
|
||||
goto GETWM
|
||||
}
|
||||
// 主动结束会话
|
||||
if msg == "c" {
|
||||
ctx.SendChain(message.Text("会话已结束!"))
|
||||
return
|
||||
}
|
||||
i, err := strconv.Atoi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("请输入数字! (输入c结束会话)"))
|
||||
continue
|
||||
}
|
||||
if ismod {
|
||||
ctx.SendChain(message.Text("/w ", sells[i].User.IngameName, " Hi! I want to buy: ", txt, "(Rank:", sells[i].ModRank, ") for ", sells[i].Platinum, " platinum. (warframe.market)"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("/w ", sells[i].User.IngameName, " Hi! I want to buy: ", txt, " for ", sells[i].Platinum, " platinum. (warframe.market)"))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取搜索结果中的物品具体名称index的FutureEvent
|
||||
//
|
||||
// 传入ctx和一个递归次数上限,返回一个int
|
||||
// 如果为返回内容为负, 说明
|
||||
// -1 会话超时
|
||||
// -2 主动结束
|
||||
// -3 连续3次错误
|
||||
func getitemnameindex(ctx *zero.Ctx) int {
|
||||
recv, cancel := zero.NewFutureEvent("message", 999, false, ctx.CheckSession()).Repeat()
|
||||
defer cancel()
|
||||
for i := 0; i < 3; i++ {
|
||||
select {
|
||||
case <-time.After(time.Second * 30):
|
||||
// 超时15秒处理
|
||||
ctx.SendChain(message.Text("会话已超时!"))
|
||||
return -1
|
||||
case e := <-recv:
|
||||
msg := e.Event.Message.ExtractPlainText()
|
||||
// 输入c主动结束的处理
|
||||
if msg == "c" {
|
||||
ctx.SendChain(message.Text("会话已结束!"))
|
||||
return -2
|
||||
}
|
||||
// 尝试对输入进行数字转换
|
||||
num, err := strconv.Atoi(msg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("请输入数字! (输入c结束会话)"))
|
||||
continue
|
||||
}
|
||||
return num
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("连续输入错误, 会话已结束!"))
|
||||
return -3
|
||||
}
|
||||
630
plugin/warframeapi/types.go
Normal file
630
plugin/warframeapi/types.go
Normal file
@@ -0,0 +1,630 @@
|
||||
package warframeapi
|
||||
|
||||
import "time"
|
||||
|
||||
type wfapi struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
News []news `json:"news"`
|
||||
Events []events `json:"events"`
|
||||
Alerts []alerts `json:"alerts"`
|
||||
Sortie sortie `json:"sortie"`
|
||||
SyndicateMissions []syndicateMissions `json:"syndicateMissions"`
|
||||
Fissures []fissures `json:"fissures"`
|
||||
GlobalUpgrades []interface{} `json:"globalUpgrades"`
|
||||
FlashSales []flashSales `json:"flashSales"`
|
||||
Invasions []invasions `json:"invasions"`
|
||||
DarkSectors []interface{} `json:"darkSectors"`
|
||||
VoidTrader voidTrader `json:"voidTrader"`
|
||||
DailyDeals []dailyDeals `json:"dailyDeals"`
|
||||
Simaris simaris `json:"simaris"`
|
||||
ConclaveChallenges []conclaveChallenges `json:"conclaveChallenges"`
|
||||
PersistentEnemies []interface{} `json:"persistentEnemies"`
|
||||
EarthCycle earthCycle `json:"earthCycle"`
|
||||
CetusCycle cetusCycle `json:"cetusCycle"`
|
||||
CambionCycle cambionCycle `json:"cambionCycle"`
|
||||
ZarimanCycle zarimanCycle `json:"zarimanCycle"`
|
||||
WeeklyChallenges []interface{} `json:"weeklyChallenges"`
|
||||
ConstructionProgress constructionProgress `json:"constructionProgress"`
|
||||
VallisCycle vallisCycle `json:"vallisCycle"`
|
||||
Nightwave nightwave `json:"nightwave"`
|
||||
Kuva []interface{} `json:"kuva"`
|
||||
Arbitration arbitration `json:"arbitration"`
|
||||
SentientOutposts sentientOutposts `json:"sentientOutposts"`
|
||||
SteelPath steelPath `json:"steelPath"`
|
||||
VaultTrader vaultTrader `json:"vaultTrader"`
|
||||
}
|
||||
type translations struct {
|
||||
En string `json:"en"`
|
||||
Fr string `json:"fr"`
|
||||
It string `json:"it"`
|
||||
De string `json:"de"`
|
||||
Es string `json:"es"`
|
||||
Pt string `json:"pt"`
|
||||
Ru string `json:"ru"`
|
||||
Pl string `json:"pl"`
|
||||
Uk string `json:"uk"`
|
||||
Tr string `json:"tr"`
|
||||
Ja string `json:"ja"`
|
||||
Zh string `json:"zh"`
|
||||
Ko string `json:"ko"`
|
||||
Tc string `json:"tc"`
|
||||
}
|
||||
type news struct {
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Link string `json:"link"`
|
||||
ImageLink string `json:"imageLink"`
|
||||
Priority bool `json:"priority"`
|
||||
Date time.Time `json:"date"`
|
||||
Eta string `json:"eta"`
|
||||
Update bool `json:"update"`
|
||||
PrimeAccess bool `json:"primeAccess"`
|
||||
Stream bool `json:"stream"`
|
||||
Translations translations `json:"translations"`
|
||||
AsString string `json:"asString"`
|
||||
}
|
||||
type metadata struct {
|
||||
}
|
||||
type nextAlt struct {
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
}
|
||||
type events struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
MaximumScore int `json:"maximumScore"`
|
||||
CurrentScore int `json:"currentScore"`
|
||||
SmallInterval interface{} `json:"smallInterval"`
|
||||
LargeInterval interface{} `json:"largeInterval"`
|
||||
Faction string `json:"faction"`
|
||||
Description string `json:"description"`
|
||||
Tooltip string `json:"tooltip"`
|
||||
Node string `json:"node"`
|
||||
ConcurrentNodes []interface{} `json:"concurrentNodes"`
|
||||
Rewards []interface{} `json:"rewards"`
|
||||
Expired bool `json:"expired"`
|
||||
InterimSteps []interface{} `json:"interimSteps"`
|
||||
ProgressSteps []interface{} `json:"progressSteps"`
|
||||
IsPersonal bool `json:"isPersonal"`
|
||||
RegionDrops []interface{} `json:"regionDrops"`
|
||||
ArchwingDrops []interface{} `json:"archwingDrops"`
|
||||
AsString string `json:"asString"`
|
||||
Metadata metadata `json:"metadata"`
|
||||
CompletionBonuses []interface{} `json:"completionBonuses"`
|
||||
AltExpiry time.Time `json:"altExpiry"`
|
||||
AltActivation time.Time `json:"altActivation"`
|
||||
NextAlt nextAlt `json:"nextAlt"`
|
||||
}
|
||||
type variants struct {
|
||||
MissionType string `json:"missionType"`
|
||||
Modifier string `json:"modifier"`
|
||||
ModifierDescription string `json:"modifierDescription"`
|
||||
Node string `json:"node"`
|
||||
}
|
||||
type sortie struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
RewardPool string `json:"rewardPool"`
|
||||
Variants []variants `json:"variants"`
|
||||
Boss string `json:"boss"`
|
||||
Faction string `json:"faction"`
|
||||
Expired bool `json:"expired"`
|
||||
Eta string `json:"eta"`
|
||||
}
|
||||
type jobs struct {
|
||||
ID string `json:"id"`
|
||||
RewardPool []string `json:"rewardPool"`
|
||||
Type string `json:"type"`
|
||||
EnemyLevels []int `json:"enemyLevels"`
|
||||
StandingStages []int `json:"standingStages"`
|
||||
MinMR int `json:"minMR"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
TimeBound string `json:"timeBound,omitempty"`
|
||||
}
|
||||
type syndicateMissions struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Syndicate string `json:"syndicate"`
|
||||
SyndicateKey string `json:"syndicateKey"`
|
||||
Nodes []interface{} `json:"nodes"`
|
||||
Jobs []jobs `json:"jobs"`
|
||||
Eta string `json:"eta"`
|
||||
}
|
||||
type fissures struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Node string `json:"node"`
|
||||
MissionType string `json:"missionType"`
|
||||
MissionKey string `json:"missionKey"`
|
||||
Enemy string `json:"enemy"`
|
||||
EnemyKey string `json:"enemyKey"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
Tier string `json:"tier"`
|
||||
TierNum int `json:"tierNum"`
|
||||
Expired bool `json:"expired"`
|
||||
Eta string `json:"eta"`
|
||||
IsStorm bool `json:"isStorm"`
|
||||
}
|
||||
type flashSales struct {
|
||||
Item string `json:"item"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Discount int `json:"discount"`
|
||||
RegularOverride int `json:"regularOverride"`
|
||||
PremiumOverride int `json:"premiumOverride"`
|
||||
IsShownInMarket bool `json:"isShownInMarket"`
|
||||
IsFeatured bool `json:"isFeatured"`
|
||||
IsPopular bool `json:"isPopular"`
|
||||
ID string `json:"id"`
|
||||
Expired bool `json:"expired"`
|
||||
Eta string `json:"eta"`
|
||||
}
|
||||
type countedItems struct {
|
||||
Count int `json:"count"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
}
|
||||
type attackerReward struct {
|
||||
Items []interface{} `json:"items"`
|
||||
CountedItems []countedItems `json:"countedItems"`
|
||||
Credits int `json:"credits"`
|
||||
AsString string `json:"asString"`
|
||||
ItemString string `json:"itemString"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Color int `json:"color"`
|
||||
}
|
||||
type reward struct {
|
||||
Items []interface{} `json:"items"`
|
||||
CountedItems []countedItems `json:"countedItems"`
|
||||
Credits int `json:"credits"`
|
||||
AsString string `json:"asString"`
|
||||
ItemString string `json:"itemString"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Color int `json:"color"`
|
||||
}
|
||||
type attacker struct {
|
||||
Reward reward `json:"reward"`
|
||||
Faction string `json:"faction"`
|
||||
FactionKey string `json:"factionKey"`
|
||||
}
|
||||
type defenderReward struct {
|
||||
Items []interface{} `json:"items"`
|
||||
CountedItems []countedItems `json:"countedItems"`
|
||||
Credits int `json:"credits"`
|
||||
AsString string `json:"asString"`
|
||||
ItemString string `json:"itemString"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Color int `json:"color"`
|
||||
}
|
||||
type defender struct {
|
||||
Reward reward `json:"reward"`
|
||||
Faction string `json:"faction"`
|
||||
FactionKey string `json:"factionKey"`
|
||||
}
|
||||
type invasions struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Node string `json:"node"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
Desc string `json:"desc"`
|
||||
AttackerReward attackerReward `json:"attackerReward"`
|
||||
AttackingFaction string `json:"attackingFaction"`
|
||||
Attacker attacker `json:"attacker"`
|
||||
DefenderReward defenderReward `json:"defenderReward"`
|
||||
DefendingFaction string `json:"defendingFaction"`
|
||||
Defender defender `json:"defender"`
|
||||
VsInfestation bool `json:"vsInfestation"`
|
||||
Count int `json:"count"`
|
||||
RequiredRuns int `json:"requiredRuns"`
|
||||
Completion float64 `json:"completion"`
|
||||
Completed bool `json:"completed"`
|
||||
Eta string `json:"eta"`
|
||||
RewardTypes []string `json:"rewardTypes"`
|
||||
}
|
||||
type voidTrader struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Character string `json:"character"`
|
||||
Location string `json:"location"`
|
||||
Inventory []interface{} `json:"inventory"`
|
||||
PsID string `json:"psId"`
|
||||
EndString string `json:"endString"`
|
||||
InitialStart time.Time `json:"initialStart"`
|
||||
Schedule []interface{} `json:"schedule"`
|
||||
}
|
||||
type dailyDeals struct {
|
||||
Item string `json:"item"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
OriginalPrice int `json:"originalPrice"`
|
||||
SalePrice int `json:"salePrice"`
|
||||
Total int `json:"total"`
|
||||
Sold int `json:"sold"`
|
||||
ID string `json:"id"`
|
||||
Eta string `json:"eta"`
|
||||
Discount int `json:"discount"`
|
||||
}
|
||||
type simaris struct {
|
||||
Target string `json:"target"`
|
||||
IsTargetActive bool `json:"isTargetActive"`
|
||||
AsString string `json:"asString"`
|
||||
}
|
||||
type conclaveChallenges struct {
|
||||
ID string `json:"id"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Amount int `json:"amount"`
|
||||
Mode string `json:"mode"`
|
||||
Category string `json:"category"`
|
||||
Eta string `json:"eta"`
|
||||
Expired bool `json:"expired"`
|
||||
Daily bool `json:"daily"`
|
||||
RootChallenge bool `json:"rootChallenge"`
|
||||
EndString string `json:"endString"`
|
||||
Description string `json:"description"`
|
||||
Title string `json:"title"`
|
||||
Standing int `json:"standing"`
|
||||
AsString string `json:"asString"`
|
||||
}
|
||||
type earthCycle struct {
|
||||
ID string `json:"id"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
IsDay bool `json:"isDay"`
|
||||
State string `json:"state"`
|
||||
TimeLeft string `json:"timeLeft"`
|
||||
}
|
||||
type cetusCycle struct {
|
||||
ID string `json:"id"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
IsDay bool `json:"isDay"`
|
||||
State string `json:"state"`
|
||||
TimeLeft string `json:"timeLeft"`
|
||||
IsCetus bool `json:"isCetus"`
|
||||
ShortString string `json:"shortString"`
|
||||
}
|
||||
type cambionCycle struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
TimeLeft string `json:"timeLeft"`
|
||||
Active string `json:"active"`
|
||||
}
|
||||
type zarimanCycle struct {
|
||||
ID string `json:"id"`
|
||||
BountiesEndDate time.Time `json:"bountiesEndDate"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Activation time.Time `json:"activation"`
|
||||
IsCorpus bool `json:"isCorpus"`
|
||||
State string `json:"state"`
|
||||
TimeLeft string `json:"timeLeft"`
|
||||
ShortString string `json:"shortString"`
|
||||
}
|
||||
type constructionProgress struct {
|
||||
ID string `json:"id"`
|
||||
FomorianProgress string `json:"fomorianProgress"`
|
||||
RazorbackProgress string `json:"razorbackProgress"`
|
||||
UnknownProgress string `json:"unknownProgress"`
|
||||
}
|
||||
type vallisCycle struct {
|
||||
ID string `json:"id"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
IsWarm bool `json:"isWarm"`
|
||||
State string `json:"state"`
|
||||
Activation time.Time `json:"activation"`
|
||||
TimeLeft string `json:"timeLeft"`
|
||||
ShortString string `json:"shortString"`
|
||||
}
|
||||
type params struct {
|
||||
}
|
||||
type activeChallenges struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
IsDaily bool `json:"isDaily,omitempty"`
|
||||
IsElite bool `json:"isElite"`
|
||||
Desc string `json:"desc"`
|
||||
Title string `json:"title"`
|
||||
Reputation int `json:"reputation"`
|
||||
}
|
||||
type nightwave struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Season int `json:"season"`
|
||||
Tag string `json:"tag"`
|
||||
Phase int `json:"phase"`
|
||||
Params params `json:"params"`
|
||||
PossibleChallenges []interface{} `json:"possibleChallenges"`
|
||||
ActiveChallenges []activeChallenges `json:"activeChallenges"`
|
||||
RewardTypes []string `json:"rewardTypes"`
|
||||
}
|
||||
type arbitration struct {
|
||||
Activation time.Time `json:"activation"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Enemy string `json:"enemy"`
|
||||
Type string `json:"type"`
|
||||
Archwing bool `json:"archwing"`
|
||||
Sharkwing bool `json:"sharkwing"`
|
||||
Node string `json:"node"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
TypeKey string `json:"typeKey"`
|
||||
ID string `json:"id"`
|
||||
Expired bool `json:"expired"`
|
||||
}
|
||||
type mission struct {
|
||||
Node string `json:"node"`
|
||||
Faction string `json:"faction"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type sentientOutposts struct {
|
||||
Mission mission `json:"mission"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
type currentReward struct {
|
||||
Name string `json:"name"`
|
||||
Cost int `json:"cost"`
|
||||
}
|
||||
type rotation struct {
|
||||
Name string `json:"name"`
|
||||
Cost int `json:"cost"`
|
||||
}
|
||||
type evergreens struct {
|
||||
Name string `json:"name"`
|
||||
Cost int `json:"cost"`
|
||||
}
|
||||
type incursions struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
}
|
||||
type steelPath struct {
|
||||
CurrentReward currentReward `json:"currentReward"`
|
||||
Activation time.Time `json:"activation"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Remaining string `json:"remaining"`
|
||||
Rotation []rotation `json:"rotation"`
|
||||
Evergreens []evergreens `json:"evergreens"`
|
||||
Incursions incursions `json:"incursions"`
|
||||
}
|
||||
type inventory struct {
|
||||
Item string `json:"item"`
|
||||
Ducats int `json:"ducats"`
|
||||
Credits interface{} `json:"credits"`
|
||||
}
|
||||
type schedule struct {
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Item string `json:"item"`
|
||||
}
|
||||
type vaultTrader struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Character string `json:"character"`
|
||||
Location string `json:"location"`
|
||||
Inventory []inventory `json:"inventory"`
|
||||
PsID string `json:"psId"`
|
||||
EndString string `json:"endString"`
|
||||
InitialStart time.Time `json:"initialStart"`
|
||||
Completed bool `json:"completed"`
|
||||
Schedule []schedule `json:"schedule"`
|
||||
}
|
||||
type alerts struct {
|
||||
ID string `json:"id"`
|
||||
Activation time.Time `json:"activation"`
|
||||
StartString string `json:"startString"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Active bool `json:"active"`
|
||||
Mission struct {
|
||||
Description string `json:"description"`
|
||||
Node string `json:"node"`
|
||||
NodeKey string `json:"nodeKey"`
|
||||
Type string `json:"type"`
|
||||
TypeKey string `json:"typeKey"`
|
||||
Faction string `json:"faction"`
|
||||
Reward struct {
|
||||
Items []interface{} `json:"items"`
|
||||
CountedItems []struct {
|
||||
Count int `json:"count"`
|
||||
Type string `json:"type"`
|
||||
Key string `json:"key"`
|
||||
} `json:"countedItems"`
|
||||
Credits int `json:"credits"`
|
||||
AsString string `json:"asString"`
|
||||
ItemString string `json:"itemString"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Color int `json:"color"`
|
||||
} `json:"reward"`
|
||||
MinEnemyLevel int `json:"minEnemyLevel"`
|
||||
MaxEnemyLevel int `json:"maxEnemyLevel"`
|
||||
MaxWaveNum int `json:"maxWaveNum"`
|
||||
Nightmare bool `json:"nightmare"`
|
||||
ArchwingRequired bool `json:"archwingRequired"`
|
||||
IsSharkwing bool `json:"isSharkwing"`
|
||||
LevelOverride string `json:"levelOverride"`
|
||||
EnemySpec string `json:"enemySpec"`
|
||||
AdvancedSpawners []interface{} `json:"advancedSpawners"`
|
||||
RequiredItems []interface{} `json:"requiredItems"`
|
||||
LevelAuras []interface{} `json:"levelAuras"`
|
||||
} `json:"mission"`
|
||||
Eta string `json:"eta"`
|
||||
RewardTypes []string `json:"rewardTypes"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
type wfAPIItem struct {
|
||||
Payload payload `json:"payload"`
|
||||
}
|
||||
type items struct {
|
||||
URLName string `json:"url_name"`
|
||||
Thumb string `json:"thumb"`
|
||||
ItemName string `json:"item_name"`
|
||||
ID string `json:"id"`
|
||||
Vaulted bool `json:"vaulted,omitempty"`
|
||||
}
|
||||
type payload struct {
|
||||
Items []items `json:"items"`
|
||||
Orders orders `json:"orders"`
|
||||
}
|
||||
|
||||
type wfAPIItemsOrders struct {
|
||||
Payload payload `json:"payload"`
|
||||
Include include `json:"include"`
|
||||
}
|
||||
type user struct {
|
||||
IngameName string `json:"ingame_name"`
|
||||
LastSeen time.Time `json:"last_seen"`
|
||||
Reputation int `json:"reputation"`
|
||||
Region string `json:"region"`
|
||||
ID string `json:"id"`
|
||||
Avatar interface{} `json:"avatar"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
type orders []struct {
|
||||
OrderType string `json:"order_type"`
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
Region string `json:"region"`
|
||||
Quantity int `json:"quantity"`
|
||||
Visible bool `json:"visible"`
|
||||
CreationDate time.Time `json:"creation_date"`
|
||||
Platinum int `json:"platinum"`
|
||||
Platform string `json:"platform"`
|
||||
User user `json:"user"`
|
||||
ID string `json:"id"`
|
||||
ModRank int `json:"mod_rank"`
|
||||
}
|
||||
|
||||
func (a orders) Len() int { // 重写 Len() 方法
|
||||
return len(a)
|
||||
}
|
||||
func (a orders) Swap(i, j int) { // 重写 Swap() 方法
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
func (a orders) Less(i, j int) bool { // 重写 Less() 方法, 从大到小排序
|
||||
return a[i].Platinum < a[j].Platinum
|
||||
}
|
||||
|
||||
type en struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type ru struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type ko struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type fr struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type sv struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type de struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type zhHant struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type zhHans struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type pt struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type es struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type pl struct {
|
||||
ItemName string `json:"item_name"`
|
||||
Description string `json:"description"`
|
||||
WikiLink string `json:"wiki_link"`
|
||||
Drop []interface{} `json:"drop"`
|
||||
}
|
||||
type itemsInSet struct {
|
||||
Icon string `json:"icon"`
|
||||
URLName string `json:"url_name"`
|
||||
SubIcon string `json:"sub_icon"`
|
||||
ModMaxRank int `json:"mod_max_rank"`
|
||||
Thumb string `json:"thumb"`
|
||||
SetRoot bool `json:"set_root"`
|
||||
QuantityForSet int `json:"quantity_for_set,omitempty"`
|
||||
ID string `json:"id"`
|
||||
TradingTax int `json:"trading_tax"`
|
||||
Tags []string `json:"tags"`
|
||||
MasteryLevel int `json:"mastery_level"`
|
||||
Ducats int `json:"ducats"`
|
||||
IconFormat string `json:"icon_format"`
|
||||
En en `json:"en"`
|
||||
Ru ru `json:"ru"`
|
||||
Ko ko `json:"ko"`
|
||||
Fr fr `json:"fr"`
|
||||
Sv sv `json:"sv"`
|
||||
De de `json:"de"`
|
||||
ZhHant zhHant `json:"zh-hant"`
|
||||
ZhHans zhHans `json:"zh-hans"`
|
||||
Pt pt `json:"pt"`
|
||||
Es es `json:"es"`
|
||||
Pl pl `json:"pl"`
|
||||
}
|
||||
type item struct {
|
||||
ID string `json:"id"`
|
||||
ItemsInSet []itemsInSet `json:"items_in_set"`
|
||||
}
|
||||
type include struct {
|
||||
Item item `json:"item"`
|
||||
}
|
||||
108
plugin/warframeapi/world.go
Normal file
108
plugin/warframeapi/world.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package warframeapi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/davidscholberg/go-durationfmt"
|
||||
)
|
||||
|
||||
// 游戏时间模拟
|
||||
type timezone struct {
|
||||
sync.RWMutex `json:"-"`
|
||||
Name string `json:"name"` // 时间名称
|
||||
NextTime time.Time `json:"time"` // 下次更新时间
|
||||
IsDay bool `json:"status"` // 状态
|
||||
DayDesc string `json:"true_des"` // 状态说明
|
||||
NightDesc string `json:"false_des"` // 状态说明
|
||||
DayLen int `json:"day"` // 白天时长
|
||||
NightLen int `json:"night"` // 夜间时长
|
||||
}
|
||||
|
||||
type world struct {
|
||||
w [3]*timezone
|
||||
hassync uintptr
|
||||
}
|
||||
|
||||
var gameWorld = newworld()
|
||||
|
||||
// String 根据传入的世界编号,获取对应的游戏时间文本
|
||||
func (t *timezone) String() string {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString("平原时间: ")
|
||||
if t.IsDay {
|
||||
sb.WriteString(t.DayDesc)
|
||||
} else {
|
||||
sb.WriteString(t.NightDesc)
|
||||
}
|
||||
sb.WriteString(", ")
|
||||
sb.WriteString("下次更新: ")
|
||||
d := time.Until(t.NextTime)
|
||||
durStr, _ := durationfmt.Format(d, "%m分%s秒后")
|
||||
sb.WriteString(durStr)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func newworld() (w world) {
|
||||
w.w = [3]*timezone{
|
||||
{Name: "地球平原", DayDesc: "白天", NightDesc: "夜晚", DayLen: 100 * 60, NightLen: 50 * 60},
|
||||
{Name: "金星平原", DayDesc: "温暖", NightDesc: "寒冷", DayLen: 400, NightLen: 20 * 60},
|
||||
{Name: "火卫二平原", DayDesc: "fass", NightDesc: "vome", DayLen: 100 * 60, NightLen: 50 * 60},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *world) hasSync() bool {
|
||||
return atomic.LoadUintptr(&w.hassync) != 0
|
||||
}
|
||||
|
||||
func (w *world) setsync() bool {
|
||||
return atomic.CompareAndSwapUintptr(&w.hassync, 0, 1)
|
||||
}
|
||||
|
||||
func (w *world) resetsync() bool {
|
||||
return atomic.CompareAndSwapUintptr(&w.hassync, 1, 0)
|
||||
}
|
||||
|
||||
// 根据API返回内容修正游戏时间
|
||||
func (w *world) refresh(api *wfapi) {
|
||||
for _, t := range w.w {
|
||||
t.Lock()
|
||||
}
|
||||
w.w[0].NextTime = api.CetusCycle.Expiry.Local()
|
||||
w.w[0].IsDay = api.CetusCycle.IsDay
|
||||
|
||||
w.w[1].NextTime = api.VallisCycle.Expiry.Local()
|
||||
w.w[1].IsDay = api.VallisCycle.IsWarm
|
||||
|
||||
w.w[2].NextTime = api.CambionCycle.Expiry.Local()
|
||||
w.w[2].IsDay = api.CambionCycle.Active == "fass"
|
||||
}
|
||||
|
||||
// 游戏时间更新
|
||||
func (w *world) update() {
|
||||
if !w.hasSync() {
|
||||
return
|
||||
}
|
||||
for _, t := range w.w {
|
||||
t.Lock()
|
||||
// 当前时间对比下一次游戏状态更新时间,看看还剩多少秒
|
||||
nt := time.Until(t.NextTime).Seconds()
|
||||
// 已经过了游戏时间状态更新时间
|
||||
if nt < 0 {
|
||||
// 更新游戏状态,如果是白天就切换到晚上,反之亦然
|
||||
if t.IsDay {
|
||||
// 计算下次的晚上更新时间
|
||||
t.NextTime = t.NextTime.Add(time.Duration(t.NightLen) * time.Second)
|
||||
} else {
|
||||
// 计算下次的白天更新时间
|
||||
t.NextTime = t.NextTime.Add(time.Duration(t.DayLen) * time.Second)
|
||||
}
|
||||
}
|
||||
t.Unlock()
|
||||
}
|
||||
}
|
||||
65
plugin/wife/main.go
Normal file
65
plugin/wife/main.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Package wife 抽老婆
|
||||
package wife
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("wife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "- 抽老婆",
|
||||
Brief: "从老婆库抽每日老婆",
|
||||
PublicDataFolder: "Wife",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
|
||||
cards := []string{}
|
||||
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
|
||||
func(ctx *zero.Ctx) bool {
|
||||
data, err := engine.GetLazyData("wife.json", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = json.Unmarshal(data, &cards)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
logrus.Infof("[wife]加载%d个老婆", len(cards))
|
||||
return true
|
||||
},
|
||||
)).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
|
||||
data, err := engine.GetLazyData("wives/"+card, true)
|
||||
card, _, _ = strings.Cut(card, ".")
|
||||
if err != nil {
|
||||
ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"),
|
||||
)
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒"),
|
||||
message.ImageBytes(data),
|
||||
); id.ID() == 0 {
|
||||
ctx.SendChain(
|
||||
message.At(ctx.Event.UserID),
|
||||
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/tl"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/gg"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -135,14 +135,13 @@ func init() {
|
||||
return
|
||||
}
|
||||
game := newWordleGame(target)
|
||||
_, img, cl, _ := game("")
|
||||
_, img, _ := game("")
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
message.Text("你有", class+1, "次机会猜出单词,单词长度为", class, ",请发送单词"),
|
||||
),
|
||||
)
|
||||
cl()
|
||||
var next *zero.FutureEvent
|
||||
if ctx.State["regex_matched"].([]string)[1] == "个人" {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([A-Z]|[a-z]){%d}$`, class)),
|
||||
@@ -170,7 +169,7 @@ func init() {
|
||||
case c := <-recv:
|
||||
tick.Reset(105 * time.Second)
|
||||
after.Reset(120 * time.Second)
|
||||
win, img, cl, err = game(c.Event.Message.String())
|
||||
win, img, err = game(c.Event.Message.String())
|
||||
switch {
|
||||
case win:
|
||||
tick.Stop()
|
||||
@@ -181,7 +180,6 @@ func init() {
|
||||
message.Text("太棒了,你猜出来了!答案是: ", target, "(", tt, ")"),
|
||||
),
|
||||
)
|
||||
cl()
|
||||
return
|
||||
case err == errTimesRunOut:
|
||||
tick.Stop()
|
||||
@@ -192,7 +190,6 @@ func init() {
|
||||
message.Text("游戏结束...答案是: ", target, "(", tt, ")"),
|
||||
),
|
||||
)
|
||||
cl()
|
||||
return
|
||||
case err == errLengthNotEnough:
|
||||
ctx.Send(
|
||||
@@ -212,17 +209,16 @@ func init() {
|
||||
message.ImageBytes(img),
|
||||
),
|
||||
)
|
||||
cl()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
func newWordleGame(target string) func(string) (bool, []byte, error) {
|
||||
var class = len(target)
|
||||
record := make([]string, 0, len(target)+1)
|
||||
return func(s string) (win bool, data []byte, cl func(), err error) {
|
||||
return func(s string) (win bool, data []byte, err error) {
|
||||
if s != "" {
|
||||
s = strings.ToLower(s)
|
||||
if target == s {
|
||||
@@ -241,6 +237,7 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
record = append(record, s)
|
||||
if len(record) >= cap(record) {
|
||||
err = errTimesRunOut
|
||||
return
|
||||
}
|
||||
}
|
||||
var side = 20
|
||||
@@ -271,7 +268,7 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
data, cl = writer.ToBytes(ctx.Image())
|
||||
data, err = imgfactory.ToBytes(ctx.Image())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
2
run.bat
2
run.bat
@@ -3,5 +3,5 @@ go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go env -w GO111MODULE=auto
|
||||
go mod tidy
|
||||
::go build -ldflags="-s -w" -o ZeroBot-Plugin.exe
|
||||
go run main.go main_win.go
|
||||
go run main.go
|
||||
pause
|
||||
|
||||
2
run.sh
2
run.sh
@@ -3,4 +3,4 @@ go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go env -w GO111MODULE=auto
|
||||
go mod tidy
|
||||
#go build -ldflags="-s -w" -o ZeroBot-Plugin
|
||||
go run main.go
|
||||
go run main.go
|
||||
|
||||
103
winres/gen/json.go
Normal file
103
winres/gen/json.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// Package main generates winres.json
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
|
||||
)
|
||||
|
||||
const js = `{
|
||||
"RT_GROUP_ICON": {
|
||||
"APP": {
|
||||
"0000": [
|
||||
"icon.png",
|
||||
"icon16.png"
|
||||
]
|
||||
}
|
||||
},
|
||||
"RT_MANIFEST": {
|
||||
"#1": {
|
||||
"0409": {
|
||||
"identity": {
|
||||
"name": "ZeroBot-Plugin",
|
||||
"version": "%s"
|
||||
},
|
||||
"description": "",
|
||||
"minimum-os": "vista",
|
||||
"execution-level": "as invoker",
|
||||
"ui-access": false,
|
||||
"auto-elevate": false,
|
||||
"dpi-awareness": "system",
|
||||
"disable-theming": false,
|
||||
"disable-window-filtering": false,
|
||||
"high-resolution-scrolling-aware": false,
|
||||
"ultra-high-resolution-scrolling-aware": false,
|
||||
"long-path-aware": false,
|
||||
"printer-driver-isolation": false,
|
||||
"gdi-scaling": false,
|
||||
"segment-heap": false,
|
||||
"use-common-controls-v6": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"RT_VERSION": {
|
||||
"#1": {
|
||||
"0000": {
|
||||
"fixed": {
|
||||
"file_version": "%s",
|
||||
"product_version": "%s",
|
||||
"timestamp": "%s"
|
||||
},
|
||||
"info": {
|
||||
"0409": {
|
||||
"Comments": "OneBot plugins based on ZeroBot",
|
||||
"CompanyName": "FloatTech",
|
||||
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
"FileVersion": "%s",
|
||||
"InternalName": "",
|
||||
"LegalCopyright": "%s",
|
||||
"LegalTrademarks": "",
|
||||
"OriginalFilename": "ZBP.EXE",
|
||||
"PrivateBuild": "",
|
||||
"ProductName": "ZeroBot-Plugin",
|
||||
"ProductVersion": "%s",
|
||||
"SpecialBuild": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
const timeformat = `2006-01-02T15:04:05+08:00`
|
||||
|
||||
func main() {
|
||||
f, err := os.Create("winres.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
i := strings.LastIndex(banner.Version, "-")
|
||||
if i <= 0 {
|
||||
i = len(banner.Version)
|
||||
}
|
||||
commitcnt := strings.Builder{}
|
||||
commitcnt.WriteString(banner.Version[1:i])
|
||||
commitcnt.WriteByte('.')
|
||||
commitcntcmd := exec.Command("git", "rev-list", "--count", "HEAD")
|
||||
commitcntcmd.Stdout = &commitcnt
|
||||
err = commitcntcmd.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fv := commitcnt.String()[:commitcnt.Len()-1]
|
||||
_, err = fmt.Fprintf(f, js, fv, fv, banner.Version, time.Now().Format(timeformat), fv, banner.Copyright+". All Rights Reserved.", banner.Version)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
BIN
winres/icon.png
Normal file
BIN
winres/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
winres/icon16.png
Normal file
BIN
winres/icon16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
4
winres/init.go
Normal file
4
winres/init.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package winres 生成windows资源
|
||||
package winres
|
||||
|
||||
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/winres/gen
|
||||
62
winres/winres.json
Normal file
62
winres/winres.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"RT_GROUP_ICON": {
|
||||
"APP": {
|
||||
"0000": [
|
||||
"icon.png",
|
||||
"icon16.png"
|
||||
]
|
||||
}
|
||||
},
|
||||
"RT_MANIFEST": {
|
||||
"#1": {
|
||||
"0409": {
|
||||
"identity": {
|
||||
"name": "ZeroBot-Plugin",
|
||||
"version": "1.7.1.1780"
|
||||
},
|
||||
"description": "",
|
||||
"minimum-os": "vista",
|
||||
"execution-level": "as invoker",
|
||||
"ui-access": false,
|
||||
"auto-elevate": false,
|
||||
"dpi-awareness": "system",
|
||||
"disable-theming": false,
|
||||
"disable-window-filtering": false,
|
||||
"high-resolution-scrolling-aware": false,
|
||||
"ultra-high-resolution-scrolling-aware": false,
|
||||
"long-path-aware": false,
|
||||
"printer-driver-isolation": false,
|
||||
"gdi-scaling": false,
|
||||
"segment-heap": false,
|
||||
"use-common-controls-v6": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"RT_VERSION": {
|
||||
"#1": {
|
||||
"0000": {
|
||||
"fixed": {
|
||||
"file_version": "1.7.1.1780",
|
||||
"product_version": "v1.7.1-beta1",
|
||||
"timestamp": "2023-03-31T15:53:17+08:00"
|
||||
},
|
||||
"info": {
|
||||
"0409": {
|
||||
"Comments": "OneBot plugins based on ZeroBot",
|
||||
"CompanyName": "FloatTech",
|
||||
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
"FileVersion": "1.7.1.1780",
|
||||
"InternalName": "",
|
||||
"LegalCopyright": "© 2020 - 2023 FloatTech. All Rights Reserved.",
|
||||
"LegalTrademarks": "",
|
||||
"OriginalFilename": "ZBP.EXE",
|
||||
"PrivateBuild": "",
|
||||
"ProductName": "ZeroBot-Plugin",
|
||||
"ProductVersion": "v1.7.1-beta1",
|
||||
"SpecialBuild": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user