mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-11 01:30:25 +00:00
Compare commits
68 Commits
v1.5.1-bet
...
v1.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f5fb2d87 | ||
|
|
8674c14754 | ||
|
|
6c2fc1b4c2 | ||
|
|
5d94980e7c | ||
|
|
9bed71a99f | ||
|
|
6faa2b65e2 | ||
|
|
98812b103e | ||
|
|
deb655de36 | ||
|
|
8d1c18cb4a | ||
|
|
88824126f7 | ||
|
|
68a9ecf995 | ||
|
|
57404b2dcd | ||
|
|
29705c63c9 | ||
|
|
5a854d9715 | ||
|
|
eb1cbeae3f | ||
|
|
b6246cfee6 | ||
|
|
0619000f9a | ||
|
|
01361781c8 | ||
|
|
3c03a308b3 | ||
|
|
7895e48420 | ||
|
|
ba15713b99 | ||
|
|
bd98fa3aed | ||
|
|
fce75a9475 | ||
|
|
7616d5759f | ||
|
|
ea2c81a9c7 | ||
|
|
37cff9ff31 | ||
|
|
b8d3d6af9b | ||
|
|
fdf90a72cc | ||
|
|
ba0c05a774 | ||
|
|
3250ec14ac | ||
|
|
ce2f390361 | ||
|
|
71434232fe | ||
|
|
852629fa2e | ||
|
|
f10676d16d | ||
|
|
d43ea7df1d | ||
|
|
21712c6299 | ||
|
|
2fc47a38fa | ||
|
|
cbb4408668 | ||
|
|
a0df41b859 | ||
|
|
494c1b33b4 | ||
|
|
2034d91912 | ||
|
|
235ced0b78 | ||
|
|
3339b6a16f | ||
|
|
c08e3dfe4a | ||
|
|
894cf41d37 | ||
|
|
55aa869b1a | ||
|
|
42b18619c3 | ||
|
|
b0c57dfec5 | ||
|
|
bdbcf2a5f8 | ||
|
|
7807e68519 | ||
|
|
4cd81cb2e9 | ||
|
|
dc34a33346 | ||
|
|
2922854f96 | ||
|
|
29c85442ff | ||
|
|
048cbf51ca | ||
|
|
467dd2ea65 | ||
|
|
aef678be5c | ||
|
|
77f7567b29 | ||
|
|
c3c0685d3a | ||
|
|
c4c3f79c8c | ||
|
|
9cb54a34da | ||
|
|
519ae62760 | ||
|
|
6971da1abc | ||
|
|
5f3054d344 | ||
|
|
5b586a7402 | ||
|
|
f2ff66ec1d | ||
|
|
92b9bab76a | ||
|
|
4609985b79 |
372
README.md
372
README.md
@@ -26,7 +26,9 @@
|
||||
| [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp) | [MiraiGo](https://github.com/Mrs4s/MiraiGo) | Mrs4s |
|
||||
| [yyuueexxiinngg/cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) | [Mirai](https://github.com/mamoe/mirai) | yyuueexxiinngg |
|
||||
| [takayama-lily/onebot](https://github.com/takayama-lily/onebot) | [OICQ](https://github.com/takayama-lily/oicq) | takayama |
|
||||
|
||||
|
||||
[](https://seladb.github.io/StarTrack-js/#/preload?r=FloatTech,ZeroBot-Plugin)
|
||||
|
||||
</div>
|
||||
|
||||
> 如果您不知道什么是 [OneBot](https://github.com/howmanybots/onebot) 或不希望运行多个程序,还可以直接前往 [gocqzbp](https://github.com/FloatTech/gocqzbp) 的 [Release](https://github.com/FloatTech/gocqzbp/releases) 页面下载单一可执行文件或前往 [Packages](https://github.com/FloatTech/gocqzbp/pkgs/container/gocqzbp) 页面使用`docker`,运行后按提示登录即可。
|
||||
@@ -36,16 +38,19 @@
|
||||
## 命令行参数
|
||||
> `[]`代表是可选参数
|
||||
```bash
|
||||
zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname] [-p prefix] [-d|w] [qq1 qq2 qq3 ...] [&]
|
||||
zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
```
|
||||
- **-c config.json**: 从`config.json`加载`bot`配置
|
||||
- **-h**: 显示帮助
|
||||
- **-s config.json**: 保存现在`bot`配置到`config.json`
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-t token**: 设置`AccessToken`,默认为空
|
||||
- **-u url**: 设置`Url`,默认为`ws://127.0.0.1:6700`
|
||||
- **-n nickname**: 设置默认昵称,默认为`椛椛`
|
||||
- **-p prefix**: 设置命令前缀,默认为`/`
|
||||
- **-d|w**: 开启 debug | warning 级别及以上日志输出
|
||||
- **-c config.json**: 从`config.json`加载`bot`配置
|
||||
- **-s config.json**: 保存现在`bot`配置到`config.json`
|
||||
- **-l latency**: 全局处理延时 (ms)
|
||||
- **-r ringlen**: 接收消息环缓冲区大小
|
||||
- **-x max process time**: 最大处理时间 (min)
|
||||
- **qqs**: superusers 的 qq 号
|
||||
- **&**: 驻留在后台,必须放在最后,仅`Linux`下有效
|
||||
|
||||
@@ -61,7 +66,10 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
"アトリ"
|
||||
],
|
||||
"command_prefix": "/",
|
||||
"super_users": []
|
||||
"super_users": [],
|
||||
"ring_len": 4096,
|
||||
"latency": 233000000,
|
||||
"max_process_time": 240000000000
|
||||
},
|
||||
"ws": [
|
||||
{
|
||||
@@ -220,6 +228,12 @@ zerobot [-c config.json] [-h] [-s config.json] [-t token] [-u url] [-n nickname]
|
||||
|
||||
- [x] [开启 | 关闭]gist加群自动审批
|
||||
|
||||
- [x] 对信息回复:[设置 | 取消]精华
|
||||
|
||||
- [x] 取消精华 [信息ID]
|
||||
|
||||
- [x] /精华列表
|
||||
|
||||
- [ ] 同意好友请求
|
||||
|
||||
- [ ] 撤回[@xxx] [xxx]
|
||||
@@ -346,6 +360,30 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 设置默认限速为每 m [分钟 | 秒] n 次触发
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>ai绘图</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint"`
|
||||
|
||||
- [x] [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx
|
||||
|
||||
- [x] [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] xxx
|
||||
|
||||
- [x] [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]
|
||||
|
||||
- [x] 设置ai绘图配置 [server] [token]
|
||||
|
||||
- [x] 设置ai绘图撤回时间90s
|
||||
|
||||
- [x] 查看ai绘图配置
|
||||
|
||||
例: 设置ai绘图配置 http://91.216.169.75:5010 abc
|
||||
|
||||
参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010
|
||||
|
||||
通过 http://91.217.139.190:5010/token 获取token
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>AIWife</summary>
|
||||
@@ -354,6 +392,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] waifu | 随机waifu(从[100000个AI生成的waifu](https://www.thiswaifudoesnotexist.net/)中随机一位)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>支付宝到账语音</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice"`
|
||||
|
||||
- [x] 支付宝到账 1
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>base16384加解密</summary>
|
||||
@@ -377,6 +423,51 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 百度下[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度内容审核</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit"`
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] 配置BDAKey [API Key] [Secret Key]
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] [开启|关闭]内容审核
|
||||
|
||||
- [x] [开启|关闭]撤回提示
|
||||
|
||||
- [x] [开启|关闭]详细提示
|
||||
|
||||
- [x] [开启|关闭]撤回禁言
|
||||
|
||||
- [x] [开启|关闭]禁言累加
|
||||
|
||||
- [x] [开启|关闭]文本检测
|
||||
|
||||
- [x] [开启|关闭]图像检测
|
||||
|
||||
- [x] 设置最大禁言时间[分钟,默认:60,最大43200]
|
||||
|
||||
- [x] 设置每次累加时间[分钟,默认:1]
|
||||
|
||||
- [x] 设置撤回禁言时间[分钟,默认:1]
|
||||
|
||||
- [x] 查看检测类型
|
||||
|
||||
- [x] 查看检测配置
|
||||
|
||||
- [x] 测试文本检测[文本内容]
|
||||
|
||||
- [x] 测试图像检测[图片]
|
||||
|
||||
- [x] 设置检测类型[类型编号]
|
||||
|
||||
- [x] 设置不检测类型[类型编号]
|
||||
|
||||
检测类型编号列表:[1:违禁违规|2:文本色情|3:敏感信息|4:恶意推广|5:低俗辱骂|6:恶意推广-联系方式|7:恶意推广-软文推广]
|
||||
</details>
|
||||
<details>
|
||||
<summary>base64卦加解密</summary>
|
||||
|
||||
@@ -418,7 +509,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 查弹幕 [xxx] 2 (最后一个参数是页码)
|
||||
|
||||
- [x] 设置b站cookie SESSDATA=82da790d,1663822823,06ecf\*31 (最好把cookie设全)
|
||||
- [x] 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0; (最好把cookie设全)
|
||||
|
||||
获取Cookie可以使用[这个工具](https://github.com/XiaoMiku01/login_bili_go)
|
||||
|
||||
@@ -546,41 +637,9 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle"`
|
||||
|
||||
- [x] (在群xxx)丢漂流瓶(到频道xxx) [消息]
|
||||
- [x] @Bot pick (随机捞一个漂流瓶)
|
||||
|
||||
- [x] (从频道xxx)捡漂流瓶
|
||||
|
||||
- [x] @BOT 创建频道 xxx
|
||||
|
||||
- [x] 跳入(频道)海中
|
||||
|
||||
- [x] 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一群一天一夫一妻制群老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife"`
|
||||
|
||||
- 引入好感度系统,好感度越高,自由恋爱成功率越高
|
||||
|
||||
- [x] 设置CD为xx小时
|
||||
|
||||
- [x] 允许/禁止自由恋爱
|
||||
|
||||
- [x] 允许/禁止牛头人
|
||||
|
||||
- [x] 娶群友
|
||||
|
||||
- [x] (娶|嫁)[@对方QQ]
|
||||
|
||||
- [x] 当[对方Q号|@对方QQ]的小三
|
||||
|
||||
- [x] 做媒 @攻方QQ @受方QQ
|
||||
|
||||
- [x] 群老婆列表
|
||||
|
||||
- [x] 重置花名册
|
||||
- [x] @Bot throw xxx (投递内容xxx,支持图片文字,投递内容需要大于10个字符或者带有图片)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -677,31 +736,43 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- 猜歌插件(该插件依赖ffmpeg)
|
||||
|
||||
- [x] 设置猜歌缓存歌库路径 [绝对路径]
|
||||
- 因为API不可抗因素,更改为了本地猜歌,但仍支持歌曲下载(VIP歌曲无法下载,黑胶可以)
|
||||
|
||||
- [x] 设置猜歌[本地/Api] [true/false]
|
||||
- [x] 设置猜歌歌库路径 [绝对路径]
|
||||
|
||||
- [x] 登录网易云
|
||||
- [x] 猜歌[开启/关闭][歌单/歌词]自动下载
|
||||
|
||||
- 注:不登陆也能用,API有几率返回400
|
||||
- 现只有歌词指令有效
|
||||
|
||||
- [x] 添加歌单 [网易云歌单ID] [歌单名称]
|
||||
- [ ] 添加歌单 [网易云歌单链接/ID] [歌单名称]
|
||||
|
||||
- 注:[歌单名称]可为空,默认原标题
|
||||
- [x] 下载歌曲 [歌曲名称/网易云歌曲ID] [歌单名称]
|
||||
|
||||
- [x] 删除歌单 [网易云歌单ID/API歌单名称]
|
||||
- [x] 删除歌单 [网易云歌单ID/歌单名称]
|
||||
|
||||
- [x] 获取歌单列表
|
||||
- 注:删除网易云歌单ID仅只是解除绑定,删除歌单名称是将本地数据全部删除!
|
||||
|
||||
- [x] [网易云歌单ID/API歌单名称]歌单信息
|
||||
- [x] 设置猜歌默认歌单 [歌单名称]
|
||||
|
||||
- [x] 歌单列表
|
||||
|
||||
- [x] [个人/团队]猜歌
|
||||
|
||||
- 注:默认歌库为网易云ACG动画榜
|
||||
- 注:默认歌库为歌单列表第一个,如果设置了默认歌单变为指定的歌单
|
||||
|
||||
- 可在后面添加[-歌单名称]进行指定歌单猜歌
|
||||
- 可在“[个人/团队]猜歌指令”后面添加[-歌单名称]进行指定歌单猜歌
|
||||
|
||||
- 歌单的歌曲命名规则为:歌名 - 歌手 - 其他(歌曲出处之类)
|
||||
- 猜歌内容必须以[-]开头才会识别
|
||||
|
||||
- 本地歌曲命名规则为:\n歌名 - 歌手 - 其他(歌曲出处之类)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>黑丝</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi"`
|
||||
|
||||
- [x] 来点黑丝/白丝/jk/巨乳/足控/网红
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -751,6 +822,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新[屌|弔|吊]图
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>兽语加密(嗷呜~)</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami"`
|
||||
|
||||
- [x] 兽语加密xxx
|
||||
|
||||
- [x] 兽语解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>小鸡词典</summary>
|
||||
@@ -759,6 +840,20 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] [查梗|小鸡词典][梗]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>日语听力学习材料</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom"`
|
||||
|
||||
- [x] 随机日语听力
|
||||
|
||||
- [x] 随机日语歌曲
|
||||
|
||||
- [x] 日语听力 xxx
|
||||
|
||||
- [x] 日语歌曲 xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>绝绝子</summary>
|
||||
@@ -785,6 +880,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
来份萝莉
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>MagicPrompt-Stable-Diffusion吟唱提示</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt"`
|
||||
|
||||
- [x] 吟唱提示[xxxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>简易midi音乐制作</summary>
|
||||
@@ -910,6 +1013,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo"`
|
||||
|
||||
- [x] 日语语法 [xxx] (使用tag随机)
|
||||
|
||||
- [x] 搜索日语语法 [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -939,6 +1044,43 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 解签
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一群一天一夫一妻制群老婆</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife"`
|
||||
|
||||
- 引入好感度系统,好感度越高,自由恋爱成功率越高
|
||||
|
||||
- [x] 设置CD为xx小时
|
||||
|
||||
- [x] [允许|禁止]自由恋爱
|
||||
|
||||
- [x] [允许|禁止]牛头人
|
||||
|
||||
- [x] 娶群友
|
||||
|
||||
- [x] [娶|嫁][@对方QQ]
|
||||
|
||||
- [x] 当[对方Q号|@对方QQ]的小三
|
||||
|
||||
- [x] 做媒 @攻方QQ @受方QQ
|
||||
|
||||
- [x] 买礼物给[对方Q号|@对方QQ]
|
||||
|
||||
- [x] 群老婆列表
|
||||
|
||||
- [x] 重置花名册
|
||||
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Real-CUGAN清晰术</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan"`
|
||||
|
||||
- [x] 清晰术(双重吟唱|三重吟唱|四重吟唱)(强力术式|中等术式|弱术式|不变式|原式)[图片]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>投胎</summary>
|
||||
@@ -955,11 +1097,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode"`
|
||||
|
||||
- [x] > runcode [language] help
|
||||
- [x] >runcode [language] help
|
||||
|
||||
- [x] > runcode [language] [code block]
|
||||
- [x] >runcode [language] [code block]
|
||||
|
||||
- [x] > runcoderaw [language] [code block]
|
||||
- [x] >runcoderaw [language] [code block]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -971,6 +1113,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 搜图[P站图片ID]
|
||||
|
||||
- [x] 设置 saucenao api key [apikey]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>叔叔的AI二次元图片放大</summary>
|
||||
@@ -987,6 +1131,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 签到
|
||||
- [x] 获得签到背景[@xxx] | 获得签到背景
|
||||
- [x] 查看等级排名
|
||||
- 注:跨群排行
|
||||
- [x] 查看我的钱包
|
||||
- [x] 查看钱包排名
|
||||
- 注:本群排行,若群人数太多不建议使用该功能!!!
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1029,6 +1178,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 解塔罗牌[牌名]
|
||||
- [x] [塔罗|大阿卡纳|小阿卡纳|混合]牌阵[圣三角|时间之流|四要素|五牌阵|吉普赛十字|马蹄|六芒星]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>舔狗日记</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
|
||||
- [x] 舔狗日记
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>搜番</summary>
|
||||
@@ -1037,20 +1194,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 搜番 | 搜索番剧[图片]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜单词</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle"`
|
||||
|
||||
- [x] 个人猜单词
|
||||
|
||||
- [x] 团队猜单词
|
||||
|
||||
- [x] 团队六阶猜单词
|
||||
|
||||
- [x] 团队七阶猜单词
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>翻译</summary>
|
||||
@@ -1059,6 +1202,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] >TL 你好
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vits猫雷</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru"`
|
||||
|
||||
- [x] 让猫雷说[xxxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vtb语录</summary>
|
||||
@@ -1079,6 +1230,64 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 来份网易云热评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>天气/拼音查询-名言</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben"`
|
||||
|
||||
- [x] xx天气
|
||||
|
||||
- [x] xx拼音
|
||||
|
||||
- [x] 每日情话/一言/鸡汤
|
||||
|
||||
- [x] 绕口令
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度文心AI</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI"`
|
||||
|
||||
基于百度文心API的一些功能
|
||||
|
||||
key申请链接:https://wenxin.baidu.com/moduleApi/key
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]
|
||||
|
||||
例:“为10086设置画图key 123 456”;“为群10010设置画图key 789 101”
|
||||
|
||||
文心key和画图key的API key 可以是相同的,只是文心key日限为200,画图日限为50,以此作区别。
|
||||
|
||||
- [x] 文心作文 (x字的)[作文题目]
|
||||
|
||||
- [x] 文心提案 (x字的)[文案标题]
|
||||
|
||||
- [x] 文心摘要 (x字的)[文章内容]
|
||||
|
||||
- [x] 文心小说 (x字的)[小说上文]
|
||||
|
||||
- [x] 文心对联 [上联]
|
||||
|
||||
- [x] 文心问答 [问题]
|
||||
|
||||
- [x] 文心补全 [带“_”的填空题]
|
||||
|
||||
- [x] 文心自定义 [prompt]
|
||||
|
||||
- [x] [bot名称]画几张[图片描述]的[图片类型][图片尺寸]
|
||||
|
||||
指令示例:
|
||||
|
||||
- 文心作文 我的椛椛机器人
|
||||
|
||||
- 文心作文 300字的我的椛椛机器人
|
||||
|
||||
- 椛椛帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>月幕galgame图</summary>
|
||||
@@ -1095,14 +1304,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新gal
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>舔狗日记</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
|
||||
- [x] 舔狗日记
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>聊天热词</summary>
|
||||
@@ -1111,6 +1312,20 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 热词 [群号] [消息数目]|热词 123456 1000
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>猜单词</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle"`
|
||||
|
||||
- [x] 个人猜单词
|
||||
|
||||
- [x] 团队猜单词
|
||||
|
||||
- [x] 团队六阶猜单词
|
||||
|
||||
- [x] 团队七阶猜单词
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>鬼东西</summary>
|
||||
@@ -1145,7 +1360,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] @Bot 任意文本(任意一句话回复)
|
||||
|
||||
- [x] 设置回复模式[青云客 | 小爱]
|
||||
|
||||
</details>
|
||||
|
||||
## 三种使用方法,推荐第一种
|
||||
|
||||
2
data
2
data
Submodule data updated: aa8f7eb30a...7bc1828db5
20
go.mod
20
go.mod
@@ -3,20 +3,22 @@ module github.com/FloatTech/ZeroBot-Plugin
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/Coloured-glaze/gg v1.3.4
|
||||
github.com/FloatTech/AnimeAPI v1.5.1-0.20221004094358-91497e10dd03
|
||||
github.com/FloatTech/floatbox v0.0.0-20221004092550-1ebf9b4e6198
|
||||
github.com/FloatTech/sqlite v0.4.0
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9
|
||||
github.com/FloatTech/sqlite v0.5.0
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20220921013146-40d64bc7799c
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221004094248-ad5a9235757e
|
||||
github.com/FloatTech/zbpctrl v1.5.2
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/fumiama/ahsai v0.1.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
github.com/fumiama/go-base16384 v1.6.1
|
||||
github.com/fumiama/go-registry v0.1.6
|
||||
github.com/fumiama/go-registry v0.2.1
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/sqlite3 v1.14.6
|
||||
github.com/fumiama/unibase2n v0.0.0-20221003115227-e7db987de949
|
||||
@@ -31,18 +33,18 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/tidwall/gjson v1.14.3
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220917061201-be873b3fa0fb
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc // 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/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 // indirect
|
||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
@@ -71,7 +73,7 @@ require (
|
||||
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/exp/shiny v0.0.0-20220916125017-b168a2c6b86b // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741 // indirect
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
|
||||
36
go.sum
36
go.sum
@@ -1,19 +1,21 @@
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Coloured-glaze/gg v1.3.4 h1:l31zIF/HaVwkzjrj+A56RGQoSKyKuR1IWtIrqXGFStI=
|
||||
github.com/Coloured-glaze/gg v1.3.4/go.mod h1:Ih5NLNNDHOy3RJbB0EPqGTreIzq/H02TGThIagh8HJg=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/FloatTech/AnimeAPI v1.5.1-0.20221004094358-91497e10dd03 h1:BDFRtCpTlJxrEpV26VMauAIURqa5L4BD728L6n0xpvM=
|
||||
github.com/FloatTech/AnimeAPI v1.5.1-0.20221004094358-91497e10dd03/go.mod h1:wY11pOy/T2MBXIGSbYHaynyGzU4Pxz0X2hGPmnlUCCk=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221004092550-1ebf9b4e6198 h1:AkwB7LKMK74yS5rIERhOQbJosDgOefJBSkhEiMbyr+A=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221004092550-1ebf9b4e6198/go.mod h1:4UDl6E/I2HqAqRnKdsxxfO28fkqGo3CzFOP2BhyI6ag=
|
||||
github.com/FloatTech/sqlite v0.4.0 h1:fvQ1vc7fw99jYXccs5KItMluy7QL1t6NxbkH7aN1F4g=
|
||||
github.com/FloatTech/sqlite v0.4.0/go.mod h1:i33d92OtR8jcp5fBUvQtospf27+MkfUxnGwnZ95E/dA=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051 h1:NEW8HzBNybMXAV0NrDpMF31n/e9BFGvNiGkDPGSkouc=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221105044443-0c9004b2f051/go.mod h1:Z+Q4kIPNo/OX4RWw6WGQOQcaNsbkv/wPmPDw8p4aQIY=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9 h1:HYJ7lwaqaOKmbYooPUMWxMhXRTp+JItoyeqa320ARD4=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221029160423-446812ec82d9/go.mod h1:w+ND28mRaJvxUJ6pRXS6i4cLzutpXsWyroutCzBdL78=
|
||||
github.com/FloatTech/sqlite v0.5.0 h1:U7J5Omc534PqmH6csfu+ypCo3DS8L91l5lTsxUu3b/U=
|
||||
github.com/FloatTech/sqlite v0.5.0/go.mod h1:i33d92OtR8jcp5fBUvQtospf27+MkfUxnGwnZ95E/dA=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20220921013146-40d64bc7799c h1:zYcKvMbwQeifSQg0LnxhmCdyP3mb7ZqS6rjt68jbukw=
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20220921013146-40d64bc7799c/go.mod h1:+2mGs9vUWJsvfcbodcmFegqOKEqHnLwopF1jTLVs/gU=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221004094248-ad5a9235757e h1:3B58NvXqYrIEDhFOl2535yL9zj2cwDAv1eq63adh/Wg=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221004094248-ad5a9235757e/go.mod h1:0hU2b4bnYGHBll52SHErCf34yU/PditejgAOkGZ/Czw=
|
||||
github.com/FloatTech/zbpctrl v1.5.2 h1:5ap0t2KgROpfTVHqMd9vHKXLeLmRFGI3ZrTPASgFP6s=
|
||||
github.com/FloatTech/zbpctrl v1.5.2/go.mod h1:BVPivMDJCBImPSdwgizb6sqb7rcDaRE65ZjfgthoC7g=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24 h1:6d9o83ZFI3LSPf4isDUmShiaU9CXqqggFwKFuof2Ghs=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221107030239-f8dd8b9a6e24/go.mod h1:KDPJDu4KHeB4Gdyt8sqR5+QnIsIDW6XXsFfT1kD7okw=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c h1:cNPOdTNiVwxLpROLjXCgbIPvdkE+BwvxDvgmdYmWx6Q=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c/go.mod h1:KqZzu7slNKROh3TSYEH/IUMG6f4M+1qubZ5e52QypsE=
|
||||
@@ -50,8 +52,10 @@ 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.1 h1:4yb4JgmBJDnQtq3XGXXdLrVwEnRpjhMUt4eAcsNeA30=
|
||||
github.com/fumiama/go-base16384 v1.6.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.1.6 h1:Ee/tXCCIR/xt8celhbbw0W/xDMdhAXLwy2YFBB/LWFk=
|
||||
github.com/fumiama/go-registry v0.1.6/go.mod h1:dIUVbiOgfk9oZcsgwDvNLC72i+ctibVukSXR/9bLviI=
|
||||
github.com/fumiama/go-registry v0.2.1 h1:PCu4d1OIYkLmoSufyxov3QXRul4lXrAfXfK1pVS2wrQ=
|
||||
github.com/fumiama/go-registry v0.2.1/go.mod h1:GP45kejHuDLFxcWdksrt75r5rHBqYwtfeUl3JzGWxfQ=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 h1:rLzJgNqB6LHNDVMl81yyNt6ZKziWtVfu+ioF0edlEVw=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
|
||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||
@@ -189,8 +193,8 @@ github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
|
||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220917061201-be873b3fa0fb h1:USIo1bqnc1hF+q/meb/OV//rs0xZTK0QU8RINp3gMqM=
|
||||
github.com/wdvxdr1123/ZeroBot v1.5.2-0.20220917061201-be873b3fa0fb/go.mod h1:shG/ruauisKaVcov4amrFJtkeDl7nl+Q00IXB2PqFsc=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3 h1:Xf+rM8fR9Etc7ydcGHuqCk0ulAAn7Oa7nD9Zy/qZ6Pk=
|
||||
github.com/wdvxdr1123/ZeroBot v1.6.3/go.mod h1:shG/ruauisKaVcov4amrFJtkeDl7nl+Q00IXB2PqFsc=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
@@ -209,8 +213,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/exp/shiny v0.0.0-20220916125017-b168a2c6b86b h1:MJd2zuDfsuomOxzoB2i4Gs8s3V9gqJEHl+hcKRV2+oI=
|
||||
golang.org/x/exp/shiny v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741 h1:b7y8iQCnzOE0NhgpMj2yHw17Us+lhXxFbdzKlTpqm5I=
|
||||
golang.org/x/exp/shiny v0.0.0-20221004215720-b9f4876ce741/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
var (
|
||||
// Banner ...
|
||||
Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version 1.5.1-beta5 - 2022-10-04 22:18:37 +0800 CST\n" +
|
||||
"* Version 1.5.2 - 2022-11-09 15:15:01 +0800 CST\n" +
|
||||
"* Copyright © 2020 - 2022 FloatTech. All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
reg = registry.NewRegReader("reilia.fumiama.top:32664", "fumiama")
|
||||
|
||||
27
main.go
27
main.go
@@ -60,9 +60,12 @@ import (
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_false" // 服务器监控
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint" // ai绘图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
|
||||
@@ -86,14 +89,18 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/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" // 摸鱼
|
||||
@@ -107,6 +114,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
|
||||
@@ -119,8 +127,11 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtb_quotation" // vtb语录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||
@@ -193,6 +204,9 @@ func init() {
|
||||
prefix := flag.String("p", "/", "Set command prefix.")
|
||||
runcfg := flag.String("c", "", "Run from config file.")
|
||||
save := flag.String("s", "", "Save default config to file and exit.")
|
||||
late := flag.Uint("l", 233, "Response latency (ms).")
|
||||
rsz := flag.Uint("r", 4096, "Receiving buffer ring size.")
|
||||
maxpt := flag.Uint("x", 4, "Max process time (min).")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@@ -242,10 +256,13 @@ func init() {
|
||||
|
||||
config.W = []*driver.WSClient{driver.NewWebSocketClient(*url, *token)}
|
||||
config.Z = zero.Config{
|
||||
NickName: append([]string{*adana}, "ATRI", "atri", "亚托莉", "アトリ"),
|
||||
CommandPrefix: *prefix,
|
||||
SuperUsers: sus,
|
||||
Driver: []zero.Driver{config.W[0]},
|
||||
NickName: append([]string{*adana}, "ATRI", "atri", "亚托莉", "アトリ"),
|
||||
CommandPrefix: *prefix,
|
||||
SuperUsers: sus,
|
||||
RingLen: *rsz,
|
||||
Latency: time.Duration(*late) * time.Millisecond,
|
||||
MaxProcessTime: time.Duration(*maxpt) * time.Minute,
|
||||
Driver: []zero.Driver{config.W[0]},
|
||||
}
|
||||
|
||||
if *save != "" {
|
||||
@@ -274,5 +291,5 @@ func main() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(kanban.Kanban()))
|
||||
})
|
||||
zero.RunAndBlock(config.Z, process.GlobalInitMutex.Unlock)
|
||||
zero.RunAndBlock(&config.Z, process.GlobalInitMutex.Unlock)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("ahsai", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "ahsai tts\n- 使[伊織弓鶴|紲星あかり|結月ゆかり|京町セイカ|東北きりたん|東北イタコ|ついなちゃん標準語|ついなちゃん関西弁|音街ウナ|琴葉茜|吉田くん|民安ともえ|桜乃そら|月読アイ|琴葉葵|東北ずん子|月読ショウタ|水奈瀬コウ]说(日语)\n",
|
||||
Brief: "フリーテキスト音声合成",
|
||||
Help: "- 使[伊織弓鶴|紲星あかり|結月ゆかり|京町セイカ|東北きりたん|東北イタコ|ついなちゃん標準語|ついなちゃん関西弁|音街ウナ|琴葉茜|吉田くん|民安ともえ|桜乃そら|月読アイ|琴葉葵|東北ずん子|月読ショウタ|水奈瀬コウ]说(日语)\n",
|
||||
PrivateDataFolder: "ahsai",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("aifalse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "AIfalse\n" +
|
||||
"- 查询计算机当前活跃度: [检查身体 | 自检 | 启动自检 | 系统状态]\n" +
|
||||
Brief: "自检, 全局限速",
|
||||
Help: "- 查询计算机当前活跃度: [检查身体 | 自检 | 启动自检 | 系统状态]\n" +
|
||||
"- 设置默认限速为每 m [分钟 | 秒] n 次触发",
|
||||
})
|
||||
c, ok := control.Lookup("aifalse")
|
||||
|
||||
@@ -12,8 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
cnapi = "http://233366.proxy.nscc-gz.cn:8888?speaker=%s&text=%s"
|
||||
// testString = "这是测试语音......"
|
||||
cnapi = "https://genshin.azurewebsites.net/api/speak?format=mp3&id=%d&text=%s"
|
||||
)
|
||||
|
||||
// 每个角色的测试文案
|
||||
@@ -86,6 +85,51 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
/*************************************************************
|
||||
*******************************AIreply************************
|
||||
*************************************************************/
|
||||
func setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var ok bool
|
||||
var index int64
|
||||
for i, s := range replyModes {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("no such mode")
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such plugin")
|
||||
}
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func getReplyMode(ctx *zero.Ctx) (name string) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
index := m.GetData(gid)
|
||||
if int(index) < len(replyModes) {
|
||||
return replyModes[index]
|
||||
}
|
||||
}
|
||||
return "青云客"
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
***********************tts************************************
|
||||
*************************************************************/
|
||||
type ttsmode struct {
|
||||
sync.RWMutex
|
||||
mode map[int64]int64
|
||||
@@ -106,10 +150,16 @@ func list(list []string, num int) string {
|
||||
|
||||
func newttsmode() *ttsmode {
|
||||
tts := &ttsmode{}
|
||||
m, ok := control.Lookup(ttsServiceName)
|
||||
tts.mode = make(map[int64]int64)
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m, ok := control.Lookup("tts")
|
||||
tts.mode = make(map[int64]int64, 2*len(soundList))
|
||||
tts.mode[-2905] = 1
|
||||
if ok {
|
||||
tts.mode[-2905] = m.GetData(-2905)
|
||||
index := m.GetData(-2905)
|
||||
if index > 0 && index < int64(len(soundList)) {
|
||||
tts.mode[-2905] = index
|
||||
}
|
||||
}
|
||||
return tts
|
||||
}
|
||||
@@ -119,31 +169,42 @@ func (tts *ttsmode) setSoundMode(ctx *zero.Ctx, name string) error {
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var i int
|
||||
var s string
|
||||
for i, s = range soundList {
|
||||
var index int64
|
||||
for i, s := range soundList {
|
||||
if s == name {
|
||||
index = int64(i + 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == 0 {
|
||||
return errors.New("不支持设置语音人物" + name)
|
||||
}
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
tts.mode[gid] = int64(i)
|
||||
return m.SetData(gid, int64(i))
|
||||
tts.mode[gid] = index
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func (tts *ttsmode) getSoundMode(ctx *zero.Ctx) (name string) {
|
||||
func (tts *ttsmode) getSoundMode(ctx *zero.Ctx) int64 {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
tts.RLock()
|
||||
defer tts.RUnlock()
|
||||
return soundList[tts.mode[gid]]
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
i, ok := tts.mode[gid]
|
||||
if !ok {
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
i = m.GetData(gid)
|
||||
}
|
||||
if i <= 0 || i >= int64(len(soundList)) {
|
||||
i = tts.mode[-2905]
|
||||
}
|
||||
return i - 1
|
||||
}
|
||||
|
||||
func (tts *ttsmode) resetSoundMode(ctx *zero.Ctx) {
|
||||
func (tts *ttsmode) resetSoundMode(ctx *zero.Ctx) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
@@ -151,20 +212,27 @@ func (tts *ttsmode) resetSoundMode(ctx *zero.Ctx) {
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
tts.mode[gid] = m.GetData(-2905)
|
||||
tts.mode[gid] = 0
|
||||
return m.SetData(gid, 0) // 重置数据
|
||||
}
|
||||
|
||||
func setDefaultSoundMode(name string) error {
|
||||
var i int
|
||||
var s string
|
||||
for i, s = range soundList {
|
||||
func (tts *ttsmode) setDefaultSoundMode(name string) error {
|
||||
var index int64
|
||||
for i, s := range soundList {
|
||||
if s == name {
|
||||
index = int64(i + 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
m, ok := control.Lookup(ttsServiceName)
|
||||
if index == 0 {
|
||||
return errors.New("不支持设置语音人物" + name)
|
||||
}
|
||||
tts.Lock()
|
||||
defer tts.Unlock()
|
||||
m, ok := control.Lookup("tts")
|
||||
if !ok {
|
||||
return errors.New("[tts] service not found")
|
||||
}
|
||||
return m.SetData(-2905, int64(i))
|
||||
tts.mode[-2905] = index
|
||||
return m.SetData(-2905, index)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -18,35 +17,62 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
replyServiceName = "aireply"
|
||||
ttsServiceName = "tts"
|
||||
)
|
||||
|
||||
var replyModes = [...]string{"青云客", "小爱"}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register(ttsServiceName, &ctrl.Options[*zero.Ctx]{
|
||||
enOftts := control.Register("tts", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "语音回复(大家一起来炼丹)\n" +
|
||||
"- @Bot 任意文本(任意一句话回复)\n" +
|
||||
Brief: "人工智能语音回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n" +
|
||||
"- 设置语音模式[原神人物]\n" +
|
||||
"- 设置默认语音模式[原神人物]\n" +
|
||||
"- 恢复成默认语音模式\n" +
|
||||
"当前适用的原神人物含有以下:\n" + list(soundList[:], 5),
|
||||
})
|
||||
tts := newttsmode()
|
||||
engine.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
enOfreply := control.Register("aireply", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "人工智能回复",
|
||||
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]",
|
||||
})
|
||||
/*************************************************************
|
||||
*******************************AIreply************************
|
||||
*************************************************************/
|
||||
enOfreply.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
aireply := aireply.NewAIReply(getReplyMode(ctx))
|
||||
reply := message.ParseMessageFromString(aireply.Talk(ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
|
||||
// 回复
|
||||
time.Sleep(time.Second * 1)
|
||||
if zero.OnlyPublic(ctx) {
|
||||
reply = append(reply, message.Reply(ctx.Event.MessageID))
|
||||
ctx.Send(reply)
|
||||
return
|
||||
}
|
||||
ctx.Send(reply)
|
||||
})
|
||||
enOfreply.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
err := setReplyMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
/*************************************************************
|
||||
***********************tts************************************
|
||||
*************************************************************/
|
||||
enOftts.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msg := ctx.ExtractPlainText()
|
||||
// 获取回复模式
|
||||
r := aireply.NewAIReply(getReplyMode(ctx))
|
||||
// 获取回复的文本
|
||||
reply := r.TalkPlain(msg, zero.BotConfig.NickName[0])
|
||||
// 获取角色
|
||||
name := tts.getSoundMode(ctx)
|
||||
// 获取语音
|
||||
record := message.Record(fmt.Sprintf(cnapi, url.QueryEscape(name), url.QueryEscape(
|
||||
index := tts.getSoundMode(ctx)
|
||||
record := message.Record(fmt.Sprintf(cnapi, index, url.QueryEscape(
|
||||
// 将数字转文字
|
||||
re.ReplaceAllStringFunc(reply, func(s string) string {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
@@ -57,16 +83,12 @@ func init() { // 插件主体
|
||||
return numcn.EncodeFromFloat64(f)
|
||||
}),
|
||||
))).Add("cache", 0)
|
||||
if record.Data == nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
return
|
||||
}
|
||||
// 发送语音
|
||||
if ID := ctx.SendChain(record); ID.ID() == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^设置语音模式(.*)$`, zero.AdminPermission, func(ctx *zero.Ctx) bool {
|
||||
enOftts.OnRegex(`^设置语音模式(.*)$`, zero.AdminPermission, func(ctx *zero.Ctx) bool {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
if _, ok := testRecord[param]; !ok {
|
||||
return false
|
||||
@@ -81,12 +103,12 @@ func init() { // 插件主体
|
||||
return
|
||||
}
|
||||
// 设置验证
|
||||
name := tts.getSoundMode(ctx)
|
||||
if _, ok := testRecord[name]; !ok {
|
||||
i := tts.getSoundMode(ctx)
|
||||
if _, ok := testRecord[soundList[i]]; !ok {
|
||||
ctx.SendChain(message.Text("配置的语音人物数据丢失!请重新设置语音人物。"))
|
||||
return
|
||||
}
|
||||
record := message.Record(fmt.Sprintf(cnapi, url.QueryEscape(name), url.QueryEscape(testRecord[name]))).Add("cache", 0)
|
||||
record := message.Record(fmt.Sprintf(cnapi, i, url.QueryEscape(testRecord[soundList[i]]))).Add("cache", 0)
|
||||
if ID := ctx.SendChain(record); ID.ID() == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置失败!无法发送测试语音,请重试。"))
|
||||
return
|
||||
@@ -94,7 +116,7 @@ func init() { // 插件主体
|
||||
time.Sleep(time.Second * 2)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
||||
})
|
||||
engine.OnRegex(`^设置默认语音模式(.*)$`, zero.SuperUserPermission, func(ctx *zero.Ctx) bool {
|
||||
enOftts.OnRegex(`^设置默认语音模式(.*)$`, zero.SuperUserPermission, func(ctx *zero.Ctx) bool {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
if _, ok := testRecord[param]; !ok {
|
||||
return false
|
||||
@@ -103,85 +125,21 @@ func init() { // 插件主体
|
||||
}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["regex_matched"].([]string)[1]
|
||||
// 保存设置
|
||||
err := setDefaultSoundMode(param)
|
||||
err := tts.setDefaultSoundMode(param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
||||
})
|
||||
engine.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
tts.resetSoundMode(ctx)
|
||||
enOftts.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
err := tts.resetSoundMode(ctx)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
// 设置验证
|
||||
name := tts.getSoundMode(ctx)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", name))
|
||||
index := tts.getSoundMode(ctx)
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", soundList[index]))
|
||||
})
|
||||
engine = control.Register(replyServiceName, &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "人工智能回复\n" +
|
||||
"- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]",
|
||||
})
|
||||
// 回复 @和包括名字
|
||||
engine.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
aireply := aireply.NewAIReply(getReplyMode(ctx))
|
||||
reply := message.ParseMessageFromString(aireply.Talk(ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
|
||||
// 回复
|
||||
time.Sleep(time.Second * 1)
|
||||
if zero.OnlyPublic(ctx) {
|
||||
reply = append(reply, message.Reply(ctx.Event.MessageID))
|
||||
ctx.Send(reply)
|
||||
return
|
||||
}
|
||||
ctx.Send(reply)
|
||||
})
|
||||
engine.OnPrefix("设置回复模式").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
param := ctx.State["args"].(string)
|
||||
err := setReplyMode(ctx, param)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
||||
})
|
||||
}
|
||||
|
||||
func setReplyMode(ctx *zero.Ctx, name string) error {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
var ok bool
|
||||
var index int64
|
||||
for i, s := range replyModes {
|
||||
if s == name {
|
||||
ok = true
|
||||
index = int64(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("no such mode")
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if !ok {
|
||||
return errors.New("no such plugin")
|
||||
}
|
||||
return m.SetData(gid, index)
|
||||
}
|
||||
|
||||
func getReplyMode(ctx *zero.Ctx) (name string) {
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok {
|
||||
index := m.GetData(gid)
|
||||
if int(index) < len(replyModes) {
|
||||
return replyModes[index]
|
||||
}
|
||||
}
|
||||
return "青云客"
|
||||
}
|
||||
|
||||
271
plugin/aipaint/aipaint.go
Normal file
271
plugin/aipaint/aipaint.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// Package aipaint ai绘图
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
datapath string
|
||||
predictRe = regexp.MustCompile(`{"steps".+?}`)
|
||||
// 参考host http://91.217.139.190:5010 http://91.216.169.75:5010
|
||||
aipaintTxt2ImgURL = "/got_image?token=%v&tags=%v"
|
||||
aipaintImg2ImgURL = "/got_image2image?token=%v&tags=%v"
|
||||
cfg = newServerConfig("data/aipaint/config.json")
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Steps int `json:"steps"`
|
||||
Sampler string `json:"sampler"`
|
||||
Seed int `json:"seed"`
|
||||
Strength float64 `json:"strength"`
|
||||
Noise float64 `json:"noise"`
|
||||
Scale float64 `json:"scale"`
|
||||
Uc string `json:"uc"`
|
||||
}
|
||||
|
||||
func (r *result) String() string {
|
||||
return fmt.Sprintf("steps: %v\nsampler: %v\nseed: %v\nstrength: %v\nnoise: %v\nscale: %v\nuc: %v\n", r.Steps, r.Sampler, r.Seed, r.Strength, r.Noise, r.Scale, r.Uc)
|
||||
}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("aipaint", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "ai绘图",
|
||||
Help: "- [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx\n" +
|
||||
"- [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] [prompt]\n" +
|
||||
"- [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]\n" +
|
||||
"- 设置ai绘图配置 [server] [token]\n" +
|
||||
"- 设置ai绘图撤回时间90s\n" +
|
||||
"- 查看ai绘图配置\n" +
|
||||
"例: 设置ai绘图配置 http://91.217.139.190:5010 abc\n" +
|
||||
"参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010\n" +
|
||||
"通过 http://91.217.139.190:5010/token 获取token\n" +
|
||||
"[prompt]参数如下\n" +
|
||||
"tags:tag词条\nntags:ntag词条\nshape:[Portrait|Landscape|Square]\nscale:[6:20]\nseed:种子\n" +
|
||||
"参数与参数内容用:连接,每个参数之间用回车分割",
|
||||
PrivateDataFolder: "aipaint",
|
||||
})
|
||||
datapath = file.BOTPATH + "/" + engine.DataFolder()
|
||||
engine.OnPrefixGroup([]string{`ai绘图`, `生成色图`, `生成涩图`, `ai画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
args := ctx.State["args"].(string)
|
||||
data, err := web.GetData(cfg.BaseURL + fmt.Sprintf(aipaintTxt2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20")))))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^(以图绘图|以图生图|以图画图)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
c := newContext(ctx.Event.UserID)
|
||||
list := ctx.State["regex_matched"].([]string)
|
||||
err = c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
args := strings.TrimSuffix(strings.TrimPrefix(list[0], list[1]), list[2])
|
||||
if args == "" {
|
||||
ctx.SendChain(message.Text("ERROR: 以图绘图必须添加tag"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
postURL := cfg.BaseURL + fmt.Sprintf(aipaintImg2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20"))))
|
||||
|
||||
f, err := os.Open(c.headimgsdir[0])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
imageShape := ""
|
||||
switch {
|
||||
case img.Bounds().Dx() > img.Bounds().Dy():
|
||||
imageShape = "Landscape"
|
||||
case img.Bounds().Dx() == img.Bounds().Dy():
|
||||
imageShape = "Square"
|
||||
default:
|
||||
imageShape = "Portrait"
|
||||
}
|
||||
|
||||
// 图片转base64
|
||||
base64Bytes, err := writer.ToBase64(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := web.PostData(postURL+"&shape="+imageShape, "text/plain", bytes.NewReader(base64Bytes))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnPrefixGroup([]string{`ai高级绘图`, `高级生成色图`, `高级生成涩图`, `ai高级画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tags := make(map[string]string)
|
||||
args := strings.Split(ctx.State["args"].(string), "\n")
|
||||
if len(args) < 1 {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的参数"))
|
||||
return
|
||||
}
|
||||
for _, info := range args {
|
||||
value := strings.Split(info, ":")
|
||||
if len(value) > 1 {
|
||||
if value[0] == "R18" && value[1] == "1" {
|
||||
value[1] = "0"
|
||||
ctx.SendChain(message.Text("不准涩涩! 已将R18设置为0. "))
|
||||
}
|
||||
tags[value[0]] = strings.Join(value[1:], ":")
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
apiurl := "/got_image?token=" + cfg.Token
|
||||
if _, ok := tags["tags"]; ok {
|
||||
apiurl += "&tags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["tags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["ntags"]; ok {
|
||||
apiurl += "&ntags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["ntags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["R18"]; ok {
|
||||
apiurl += "&R18=" + url.QueryEscape(strings.TrimSpace(tags["R18"]))
|
||||
}
|
||||
if _, ok := tags["shape"]; ok {
|
||||
apiurl += "&shape=" + url.QueryEscape(strings.TrimSpace(tags["shape"]))
|
||||
}
|
||||
if _, ok := tags["scale"]; ok {
|
||||
apiurl += "&scale=" + url.QueryEscape(strings.TrimSpace(tags["scale"]))
|
||||
}
|
||||
if _, ok := tags["seed"]; ok {
|
||||
apiurl += "&seed=" + url.QueryEscape(strings.TrimSpace(tags["seed"]))
|
||||
}
|
||||
data, err := web.GetData(cfg.BaseURL + apiurl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(regexMatched[1], regexMatched[2], cfg.Interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("成功设置\nbase_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图撤回时间(\d{1,3})s$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
interval, err := strconv.Atoi(regexMatched[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(cfg.BaseURL, cfg.Token, interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("成功设置\nbase_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
engine.OnFullMatch(`查看ai绘图配置`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text := fmt.Sprintf("base_url: %v\ntoken: %v\ninterval: %v\n", cfg.BaseURL, cfg.Token, cfg.Interval)
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
}
|
||||
|
||||
func sendAiImg(ctx *zero.Ctx, data []byte, interval int) {
|
||||
var loadData string
|
||||
if predictRe.MatchString(binary.BytesToString(data)) {
|
||||
loadData = predictRe.FindStringSubmatch(binary.BytesToString(data))[0]
|
||||
}
|
||||
var r result
|
||||
if loadData != "" {
|
||||
err := json.Unmarshal(binary.StringToBytes(loadData), &r)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
r.Uc, err = url.QueryUnescape(r.Uc)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
encodeStr := base64.StdEncoding.EncodeToString(data)
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+encodeStr))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(r.String())))
|
||||
if mid := ctx.Send(m); mid.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
} else if interval > 0 {
|
||||
go func(i message.MessageID) {
|
||||
time.Sleep(time.Duration(interval) * time.Second)
|
||||
ctx.DeleteMessage(i)
|
||||
}(mid)
|
||||
}
|
||||
}
|
||||
56
plugin/aipaint/config.go
Normal file
56
plugin/aipaint/config.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
// 配置结构体
|
||||
type serverConfig struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
Token string `json:"token"`
|
||||
Interval int `json:"interval"`
|
||||
file string
|
||||
}
|
||||
|
||||
func newServerConfig(file string) *serverConfig {
|
||||
return &serverConfig{
|
||||
file: file,
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) update(baseURL, token string, interval int) (err error) {
|
||||
if baseURL != "" {
|
||||
cfg.BaseURL = baseURL
|
||||
}
|
||||
if token != "" {
|
||||
cfg.Token = token
|
||||
}
|
||||
cfg.Interval = interval
|
||||
reader, err := os.Create(cfg.file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
return json.NewEncoder(reader).Encode(cfg)
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) load() (err error) {
|
||||
if cfg.BaseURL != "" && cfg.Token != "" && cfg.Interval != 0 {
|
||||
return
|
||||
}
|
||||
if file.IsNotExist(cfg.file) {
|
||||
err = errors.New("no server config")
|
||||
return
|
||||
}
|
||||
reader, err := os.Open(cfg.file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
err = json.NewDecoder(reader).Decode(cfg)
|
||||
return
|
||||
}
|
||||
39
plugin/aipaint/context.go
Normal file
39
plugin/aipaint/context.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
type context struct {
|
||||
usrdir string
|
||||
headimgsdir []string
|
||||
}
|
||||
|
||||
func newContext(user int64) *context {
|
||||
c := new(context)
|
||||
c.usrdir = datapath + "users/" + strconv.FormatInt(user, 10) + `/`
|
||||
_ = os.MkdirAll(c.usrdir, 0755)
|
||||
c.headimgsdir = make([]string, 2)
|
||||
c.headimgsdir[0] = c.usrdir + "0.gif"
|
||||
c.headimgsdir[1] = c.usrdir + "1.gif"
|
||||
return c
|
||||
}
|
||||
|
||||
func (cc *context) prepareLogos(s ...string) error {
|
||||
for i, v := range s {
|
||||
_, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.usrdir+strconv.Itoa(i)+".gif", true)
|
||||
} else {
|
||||
err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.usrdir+strconv.Itoa(i)+".gif", true)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -19,8 +19,8 @@ const (
|
||||
func init() { // 插件主体
|
||||
control.Register("aiwife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "AIWife\n" +
|
||||
"- waifu | 随机waifu",
|
||||
Brief: "ai随机生成老婆",
|
||||
Help: "- waifu | 随机waifu",
|
||||
}).ApplySingle(ctxext.DefaultSingle).OnFullMatchGroup([]string{"waifu", "随机waifu"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
miku := rand.Intn(100000) + 1
|
||||
|
||||
32
plugin/alipayvoice/alipayvoice.go
Normal file
32
plugin/alipayvoice/alipayvoice.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Package alipayvoice 支付宝到账语音
|
||||
package alipayvoice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
alipayvoiceURL = "https://mm.cqu.cc/share/zhifubaodaozhang/mp3/%v.mp3"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("alipayvoice", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "支付宝到账语音",
|
||||
Help: "- 支付宝到账 1",
|
||||
PrivateDataFolder: "alipayvoice",
|
||||
})
|
||||
|
||||
// 开启
|
||||
engine.OnPrefix(`支付宝到账`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(alipayvoiceURL, strings.TrimSpace(args))))
|
||||
})
|
||||
}
|
||||
@@ -40,7 +40,8 @@ func onDel(uid int64, _ struct{}) {
|
||||
func init() {
|
||||
engine := control.Register("antiabuse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "违禁词检测\n- /[添加|删除|查看]违禁词",
|
||||
Brief: "违禁词检测",
|
||||
Help: "- /[添加|删除|查看]违禁词",
|
||||
PrivateDataFolder: "anti_abuse",
|
||||
})
|
||||
|
||||
|
||||
@@ -17,16 +17,12 @@ import (
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
)
|
||||
|
||||
const (
|
||||
// 服务名
|
||||
servicename = "atri"
|
||||
// ATRI 表情的 codechina 镜像
|
||||
res = "https://gitcode.net/u011570312/zbpdata/-/raw/main/Atri/"
|
||||
)
|
||||
const res = "https://gitcode.net/u011570312/zbpdata/-/raw/main/Atri/"
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register(servicename, &ctrl.Options[*zero.Ctx]{
|
||||
engine := control.Register("atri", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "atri人格文本回复",
|
||||
Help: "本插件基于 ATRI ,为 Golang 移植版\n" +
|
||||
"- ATRI醒醒\n- ATRI睡吧\n- 萝卜子\n- 喜欢 | 爱你 | 爱 | suki | daisuki | すき | 好き | 贴贴 | 老婆 | 亲一个 | mua\n" +
|
||||
"- 草你妈 | 操你妈 | 脑瘫 | 废柴 | fw | 废物 | 战斗 | 爬 | 爪巴 | sb | SB | 傻B\n- 早安 | 早哇 | 早上好 | ohayo | 哦哈哟 | お早う | 早好 | 早 | 早早早\n" +
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("base16384", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "base16384加解密\n" +
|
||||
"- 加密xxx\n- 解密xxx\n- 用yyy加密xxx\n- 用yyy解密xxx",
|
||||
Brief: "base16384加解密",
|
||||
Help: "- 加密xxx\n- 解密xxx\n- 用yyy加密xxx\n- 用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
func init() {
|
||||
control.Register("baidu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "baidu\n" +
|
||||
"- 百度下[xxx]",
|
||||
Brief: "不会百度吗",
|
||||
Help: "- 百度下[xxx]",
|
||||
}).OnPrefix("百度下").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
txt := ctx.State["args"].(string)
|
||||
|
||||
502
plugin/baiduaudit/audit.go
Normal file
502
plugin/baiduaudit/audit.go
Normal file
@@ -0,0 +1,502 @@
|
||||
// Package baiduaudit 百度内容审核
|
||||
package baiduaudit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Baidu-AIP/golang-sdk/aip/censor"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
// 服务网址:https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index
|
||||
// 返回参数说明:https://cloud.baidu.com/doc/ANTIPORN/s/Nk3h6xbb2
|
||||
type baiduRes struct {
|
||||
LogID int `json:"log_id"` // 请求唯一id
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Data []auditData `json:"data"`
|
||||
ErrorCode int `json:"error_code"` // 错误提示码,失败才返回,成功不返回
|
||||
ErrorMsg string `json:"error_msg"` // 错误提示信息,失败才返回,成功不返回
|
||||
}
|
||||
|
||||
type auditData struct {
|
||||
Type int `json:"type"` // 审核主类型,11:百度官方违禁词库、12:文本反作弊、13:自定义文本黑名单、14:自定义文本白名单
|
||||
SubType int `json:"subType"` // 审核子类型,0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Msg string `json:"msg"` // 不合规项描述信息
|
||||
Hits []hit `json:"hits"`
|
||||
} // 不合规/疑似/命中白名单项详细信息。响应成功并且conclusion为疑似或不合规或命中白名单时才返回,响应失败或conclusion为合规且未命中白名单时不返回。
|
||||
|
||||
type hit struct {
|
||||
DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
|
||||
Words []string `json:"words"` // 送检文本命中词库的关键词(备注:建议参考新字段“wordHitPositions”,包含信息更丰富:关键词以及对应的位置及标签信息)
|
||||
Probability float64 `json:"probability,omitempty"` // 不合规项置信度
|
||||
} // 送检文本违规原因的详细信息
|
||||
type keyConfig struct {
|
||||
Key1 string `json:"key1"` // 百度云服务内容审核key存储
|
||||
Key2 string `json:"key2"` // 百度云服务内容审核key存储
|
||||
Groups map[int64]group `json:"groups"` // 群配置存储
|
||||
}
|
||||
|
||||
type group struct {
|
||||
Enable EnableMark // 是否启用内容审核
|
||||
TextAudit EnableMark // 文本检测
|
||||
ImageAudit EnableMark // 图像检测
|
||||
DMRemind EnableMark // 撤回提示
|
||||
MoreRemind EnableMark // 详细违规提示
|
||||
DMBAN EnableMark // 撤回后禁言
|
||||
BANTimeAddEnable EnableMark // 禁言累加
|
||||
BANTime int64 // 标准禁言时间,禁用累加,但开启禁言的的情况下采用该值
|
||||
MaxBANTimeAddRange int64 // 最大禁言时间累加范围,最高禁言时间
|
||||
BANTimeAddTime int64 // 禁言累加时间,该值是开启禁累加功能后,再次触发时,根据被禁次数X该值计算出的禁言时间
|
||||
WhiteListType [8]bool // 类型白名单,处于白名单类型的违规,不会被触发 0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
AuditHistory map[int64]auditHistory // 被封禁用户列表
|
||||
}
|
||||
|
||||
// EnableMark 启用:●,禁用:○
|
||||
type EnableMark bool
|
||||
|
||||
// String 打印启用状态
|
||||
func (em EnableMark) String() string {
|
||||
if em {
|
||||
return "开启"
|
||||
}
|
||||
return "关闭"
|
||||
}
|
||||
|
||||
type auditHistory struct {
|
||||
Count int64 `json:"key2"` // 被禁次数
|
||||
ResList []baiduRes `json:"reslist"` // 禁言原因
|
||||
}
|
||||
|
||||
var bdcli *censor.ContentCensorClient // 百度云审核服务Client
|
||||
var typetext = [8]string{
|
||||
0: "默认违禁词库",
|
||||
1: "违禁违规",
|
||||
2: "文本色情",
|
||||
3: "敏感信息",
|
||||
4: "恶意推广",
|
||||
5: "低俗辱骂",
|
||||
6: "恶意推广-联系方式",
|
||||
7: "恶意推广-软文推广",
|
||||
} // 文本类型
|
||||
|
||||
var (
|
||||
config keyConfig // 插件配置
|
||||
configinit bool // 配置初始化
|
||||
configpath string // 配置路径
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "百度内容审核",
|
||||
Help: "##该功能来自百度内容审核,需购买相关服务,并创建app##\n" +
|
||||
"- 获取BDAKey\n" +
|
||||
"- 配置BDAKey [API key] [Secret Key]\n" +
|
||||
"- 开启/关闭内容审核\n" +
|
||||
"- 开启/关闭撤回提示\n" +
|
||||
"- 开启/关闭详细提示\n" +
|
||||
"- 开启/关闭撤回禁言\n" +
|
||||
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时,再次触发按最大禁言时间计算\n" +
|
||||
"- 开启/关闭禁言累加\n" +
|
||||
"- 设置撤回禁言时间[分钟,默认:1]\n" +
|
||||
"- 设置最大禁言时间[分钟,默认:60,最大43200]\n" +
|
||||
"- 设置每次累加时间[分钟,默认:1]\n" +
|
||||
"##检测类型设置## 类型编号列表:[1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广]\n" +
|
||||
"- 查看检测类型\n" +
|
||||
"- 查看检测配置\n" +
|
||||
"- 设置检测类型[类型编号]\n" +
|
||||
"- 设置不检测类型[类型编号]\n" +
|
||||
"- 开启/关闭文本检测\n" +
|
||||
"- 开启/关闭图像检测\n" +
|
||||
"##测试功能##\n" +
|
||||
"- 测试文本检测[文本内容]\n" +
|
||||
"- 测试图像检测[图片]\n",
|
||||
PrivateDataFolder: "baiduaudit",
|
||||
})
|
||||
configpath = engine.DataFolder() + "config.json"
|
||||
loadConfig()
|
||||
if configinit {
|
||||
bdcli = censor.NewClient(config.Key1, config.Key2)
|
||||
}
|
||||
engine.OnFullMatch("获取BDAKey", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("接口key创建网址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index\n" +
|
||||
"免费8w次数领取地址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/resource/getFree"))
|
||||
})
|
||||
|
||||
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
var msgs string
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
if k1 == "类型" {
|
||||
msgs += "本群检测类型:"
|
||||
find := false
|
||||
// 遍历群检测类型名单
|
||||
for i, v := range group.WhiteListType {
|
||||
if !v {
|
||||
find = true
|
||||
msgs += fmt.Sprint("\n", i, ".", typetext[i])
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
msgs += "无"
|
||||
}
|
||||
|
||||
} else {
|
||||
// 生成配置文本
|
||||
msgs = fmt.Sprintf("本群配置:\n"+
|
||||
"内容审核:%s\n"+
|
||||
"-文本:%s\n"+
|
||||
"-图像:%s\n"+
|
||||
"撤回提示:%s\n"+
|
||||
"-详细提示:%s\n"+
|
||||
"撤回禁言:%s\n"+
|
||||
"-禁言累加:%s\n"+
|
||||
"-撤回禁言时间:%v分钟\n"+
|
||||
"-每次累加时间:%v分钟\n"+
|
||||
"-最大禁言时间:%v分钟", group.Enable, group.TextAudit, group.ImageAudit, group.DMRemind, group.MoreRemind, group.DMBAN, group.BANTimeAddEnable, group.BANTime, group.BANTimeAddTime, group.MaxBANTimeAddRange)
|
||||
}
|
||||
b, err := text.RenderToBase64(msgs, text.FontFile, 300, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
})
|
||||
engine.OnRegex("^设置(不)?检测类型([01234567])$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
inputType, _ := strconv.Atoi(k2)
|
||||
if k1 == "不" {
|
||||
group.WhiteListType[inputType] = true //不检测:则进入类型白名单
|
||||
} else {
|
||||
group.WhiteListType[inputType] = false //检测:则退出白名单
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, typetext[inputType])))
|
||||
})
|
||||
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k3 := ctx.State["regex_matched"].([]string)[3]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
time, _ := strconv.ParseInt(k1, 10, 64)
|
||||
switch k1 {
|
||||
case "最大":
|
||||
group.MaxBANTimeAddRange = time
|
||||
case "每次":
|
||||
group.BANTimeAddTime = time
|
||||
case "撤回":
|
||||
group.BANTime = time
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s禁言累加时间已设置为%s", k3, k1)))
|
||||
})
|
||||
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
isEnable := EnableMark(false)
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
if k1 == "开启" {
|
||||
isEnable = true
|
||||
}
|
||||
switch k2 {
|
||||
case "内容审核":
|
||||
group.Enable = isEnable
|
||||
case "撤回提示":
|
||||
group.DMRemind = isEnable
|
||||
case "撤回禁言":
|
||||
group.DMBAN = isEnable
|
||||
case "禁言累加":
|
||||
group.BANTimeAddEnable = isEnable
|
||||
case "详细提示":
|
||||
group.MoreRemind = isEnable
|
||||
case "文本检测":
|
||||
group.TextAudit = isEnable
|
||||
case "图像检测":
|
||||
group.ImageAudit = isEnable
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s已%s", k2, k1)))
|
||||
})
|
||||
engine.OnRegex(`^配置BDAKey\s*(.*)\s*(.*)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
bdcli = censor.NewClient(k1, k2)
|
||||
config.Key1 = k1
|
||||
config.Key2 = k2
|
||||
if bdcli != nil {
|
||||
jsonSave(config, configpath)
|
||||
ctx.SendChain(message.Text("配置成功"))
|
||||
}
|
||||
})
|
||||
engine.OnMessage().SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
group, ok := config.Groups[ctx.Event.GroupID]
|
||||
// 如果没该配置,或者审核功能未开启直接跳过
|
||||
if !ok || !bool(group.Enable) {
|
||||
return
|
||||
}
|
||||
for _, elem := range ctx.Event.Message {
|
||||
switch elem.Type {
|
||||
case "image":
|
||||
if !group.ImageAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
|
||||
case "text":
|
||||
if !group.TextAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.TextCensor(elem.Data["text"])
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnPrefix("文本检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return
|
||||
}
|
||||
args := ctx.ExtractPlainText()
|
||||
res := bdcli.TextCensor(args)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
})
|
||||
engine.OnPrefix("^图像检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var urls []string
|
||||
for _, elem := range ctx.Event.Message {
|
||||
if elem.Type == "image" {
|
||||
if elem.Data["url"] != "" {
|
||||
urls = append(urls, elem.Data["url"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(urls) == 0 {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(urls[0], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 禁言检测
|
||||
func banCheck(ctx *zero.Ctx, bdres baiduRes) {
|
||||
// 如果返回类型为2(不合规),0为合规,3为疑似
|
||||
if bdres.ConclusionType == 2 {
|
||||
// 创建消息ID
|
||||
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
// 检测群配置里的不检测类型白名单,忽略掉不检测的违规类型
|
||||
for i, b := range group.WhiteListType {
|
||||
if i == bdres.Data[0].SubType && b {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 生成回复文本
|
||||
res := buildResp(bdres, group)
|
||||
// 撤回消息
|
||||
ctx.DeleteMessage(mid)
|
||||
// 查看是否启用撤回后禁言
|
||||
if group.DMBAN {
|
||||
// 从历史违规记录中获取指定用户
|
||||
user := group.getUser(ctx.Event.UserID)
|
||||
// 用户违规次数自增
|
||||
user.Count++
|
||||
// 用户违规原因记录
|
||||
user.ResList = append(user.ResList, bdres)
|
||||
// 覆写该用户到群违规记录中
|
||||
group.AuditHistory[ctx.Event.UserID] = user
|
||||
// 覆写该群信息
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
// 保存到json
|
||||
jsonSave(config, configpath)
|
||||
var bantime int64
|
||||
// 查看是否开启禁言累加功能,并计算禁言时间
|
||||
if group.BANTimeAddEnable {
|
||||
bantime = user.Count * group.BANTimeAddTime * 60
|
||||
} else {
|
||||
bantime = group.BANTime * 60
|
||||
}
|
||||
//执行禁言
|
||||
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
|
||||
}
|
||||
//查看是否开启撤回提示
|
||||
if group.DMRemind {
|
||||
res = append(res, message.At(ctx.Event.Sender.ID))
|
||||
ctx.SendChain(res...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群配置
|
||||
func getGroup(groupID int64) group {
|
||||
g, ok := config.Groups[groupID]
|
||||
if ok {
|
||||
return g
|
||||
}
|
||||
if config.Groups == nil {
|
||||
config.Groups = make(map[int64]group)
|
||||
}
|
||||
g = group{
|
||||
TextAudit: true,
|
||||
ImageAudit: true,
|
||||
BANTime: 1,
|
||||
MaxBANTimeAddRange: 60,
|
||||
BANTimeAddTime: 1,
|
||||
WhiteListType: [8]bool{},
|
||||
AuditHistory: map[int64]auditHistory{},
|
||||
}
|
||||
config.Groups[groupID] = g
|
||||
return g
|
||||
}
|
||||
|
||||
// 从群历史违规记录中获取用户
|
||||
func (group *group) getUser(userID int64) auditHistory {
|
||||
audit, ok := group.AuditHistory[userID]
|
||||
if ok {
|
||||
return audit
|
||||
}
|
||||
// 如果没有用户,则创建一个并返回
|
||||
if group.AuditHistory == nil {
|
||||
group.AuditHistory = make(map[int64]auditHistory)
|
||||
}
|
||||
audit = auditHistory{0, []baiduRes{}}
|
||||
group.AuditHistory[userID] = audit
|
||||
return audit
|
||||
}
|
||||
|
||||
// 客户端是否初始化检测
|
||||
func clientCheck(ctx *zero.Ctx) bool {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 加载JSON配置文件
|
||||
func loadConfig() {
|
||||
if file.IsExist(configpath) {
|
||||
data, err := os.OpenFile(configpath, os.O_RDONLY, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = json.NewDecoder(data).Decode(&config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
configinit = true
|
||||
} else {
|
||||
config = keyConfig{}
|
||||
configinit = false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
func jsonSave(v keyConfig, path string) {
|
||||
jsf, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}(jsf) // 结束时关闭句柄,释放资源
|
||||
err := json.NewEncoder(jsf).Encode(v)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// JSON反序列化
|
||||
func jsonToBaiduRes(resjson string) (baiduRes, error) {
|
||||
var bdres baiduRes
|
||||
err := json.Unmarshal(binary.StringToBytes(resjson), &bdres)
|
||||
return bdres, err
|
||||
}
|
||||
|
||||
// 生成回复文本
|
||||
func buildResp(bdres baiduRes, group group) []message.MessageSegment {
|
||||
// 建立消息段
|
||||
msgs := make([]message.MessageSegment, 0, 8)
|
||||
// 生成简略审核结果回复
|
||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||
// 查看是否开启详细审核内容提示,并确定审核内容值为疑似,或者不合规
|
||||
if !group.MoreRemind {
|
||||
return msgs
|
||||
}
|
||||
// 遍历返回的不合规数据,生成详细违规内容
|
||||
for i, datum := range bdres.Data {
|
||||
msgs = append(msgs, message.Text("[", i, "]:", datum.Msg, "\n"))
|
||||
// 检查命中词条是否大于0
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
// 遍历打印命中的违规词条
|
||||
for _, hit := range datum.Hits {
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
msgs = append(msgs, message.Text("("))
|
||||
for i4, i3 := range hit.Words {
|
||||
// 检查是否是最后一个要打印的词条,如果是则不加上逗号
|
||||
if i4 != len(hit.Words)-1 {
|
||||
msgs = append(msgs, message.Text(i3, ","))
|
||||
} else {
|
||||
msgs = append(msgs, message.Text(i3))
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, message.Text(")"))
|
||||
}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("base64gua", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "base64gua加解密\n" +
|
||||
"- 六十四卦加密xxx\n- 六十四卦解密xxx\n- 六十四卦用yyy加密xxx\n- 六十四卦用yyy解密xxx",
|
||||
Brief: "六十四卦加解密",
|
||||
Help: "- 六十四卦加密xxx\n- 六十四卦解密xxx\n- 六十四卦用yyy加密xxx\n- 六十四卦用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^六十四卦加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("baseamasiro", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "base天城文加解密\n" +
|
||||
"- 天城文加密xxx\n- 天城文解密xxx\n- 天城文用yyy加密xxx\n- 天城文用yyy解密xxx",
|
||||
Brief: "天城文加解密",
|
||||
Help: "- 天城文加密xxx\n- 天城文解密xxx\n- 天城文用yyy加密xxx\n- 天城文用yyy解密xxx",
|
||||
})
|
||||
en.OnRegex(`^天城文加密\s*(.+)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
var (
|
||||
errNeedCookie = errors.New("该api需要设置b站cookie,请发送命令设置cookie,例如\"设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\"")
|
||||
)
|
||||
|
||||
// searchUser 查找b站用户
|
||||
func searchUser(keyword string) (r []searchResult, err error) {
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf(searchUserURL, keyword), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = reflushBilibiliCookie()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Add("cookie", cfg.BilibiliCookie)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
s := fmt.Sprintf("status code: %d", res.StatusCode)
|
||||
err = errors.New(s)
|
||||
return
|
||||
}
|
||||
var sd searchData
|
||||
err = json.NewDecoder(res.Body).Decode(&sd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r = sd.Data.Result
|
||||
return
|
||||
}
|
||||
|
||||
// getVtbDetail 查找vtb信息
|
||||
func getVtbDetail(uid string) (result vtbDetail, err error) {
|
||||
data, err := web.GetData(fmt.Sprintf(vtbDetailURL, uid))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &result); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getMemberCard 获取b站个人详情
|
||||
func getMemberCard(uid interface{}) (result memberCard, err error) {
|
||||
data, err := web.GetData(fmt.Sprintf(memberCardURL, uid))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("card").Raw), &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getMedalwall 用b站uid获得牌子
|
||||
func getMedalwall(uid string) (result []medal, err error) {
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf(medalwallURL, uid), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = reflushBilibiliCookie()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Add("cookie", cfg.BilibiliCookie)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
var md medalData
|
||||
err = json.NewDecoder(res.Body).Decode(&md)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if md.Code == -101 {
|
||||
err = errNeedCookie
|
||||
return
|
||||
}
|
||||
if md.Code != 0 {
|
||||
err = errors.New(md.Message)
|
||||
}
|
||||
result = md.Data.List
|
||||
return
|
||||
}
|
||||
|
||||
// getArticleInfo 用id查专栏信息
|
||||
func getArticleInfo(id string) (card Card, err error) {
|
||||
var data []byte
|
||||
data, err = web.GetData(fmt.Sprintf(articleInfoURL, id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
|
||||
return
|
||||
}
|
||||
|
||||
// getLiveRoomInfo 用直播间id查直播间信息
|
||||
func getLiveRoomInfo(roomID string) (card roomCard, err error) {
|
||||
var data []byte
|
||||
data, err = web.GetData(fmt.Sprintf(liveRoomInfoURL, roomID))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
|
||||
return
|
||||
}
|
||||
|
||||
// getVideoInfo 用av或bv查视频信息
|
||||
func getVideoInfo(id string) (card Card, err error) {
|
||||
var data []byte
|
||||
_, err = strconv.Atoi(id)
|
||||
if err == nil {
|
||||
data, err = web.GetData(fmt.Sprintf(videoInfoURL, id, ""))
|
||||
} else {
|
||||
data, err = web.GetData(fmt.Sprintf(videoInfoURL, "", id))
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
|
||||
return
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"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"
|
||||
@@ -40,21 +41,21 @@ var (
|
||||
4: "进入直播间",
|
||||
5: "标题变动",
|
||||
}
|
||||
cfgFile = "data/Bilibili/config.json"
|
||||
cfg config
|
||||
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||
)
|
||||
|
||||
// 查成分的
|
||||
func init() {
|
||||
engine := control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "bilibili (412就是拦截的意思,建议私聊把cookie设全)\n" +
|
||||
"- >vup info [xxx]\n" +
|
||||
Brief: "b站查成分查弹幕",
|
||||
Help: "- >vup info [xxx]\n" +
|
||||
"- >user info [xxx]\n" +
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 查弹幕 [xxx]\n" +
|
||||
"- 设置b站cookie [xxx]\n" +
|
||||
"- 更新vup",
|
||||
"- 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0;\n" +
|
||||
"- 更新vup" +
|
||||
"Tips: (412就是拦截的意思,建议私聊把cookie设全)\n",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
@@ -73,7 +74,7 @@ func init() {
|
||||
engine.OnRegex(`^>user info\s?(.{1,25})$`, getPara).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
card, err := getMemberCard(id)
|
||||
card, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -92,7 +93,7 @@ func init() {
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
id := ctx.State["uid"].(string)
|
||||
// 获取详情
|
||||
fo, err := getVtbDetail(id)
|
||||
fo, err := bz.GetVtbDetail(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -120,7 +121,7 @@ func init() {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
return
|
||||
}
|
||||
u, err := getMemberCard(id)
|
||||
u, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -131,13 +132,13 @@ func init() {
|
||||
return
|
||||
}
|
||||
vupLen := len(vups)
|
||||
medals, err := getMedalwall(id)
|
||||
sort.Sort(medalSlice(medals))
|
||||
medals, err := bz.GetMedalWall(cfg, id)
|
||||
sort.Sort(bz.MedalSorter(medals))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
frontVups := make([]vup, 0)
|
||||
medalMap := make(map[int64]medal)
|
||||
medalMap := make(map[int64]bz.Medal)
|
||||
for _, v := range medals {
|
||||
up := vup{
|
||||
Mid: v.Mid,
|
||||
@@ -173,7 +174,7 @@ func init() {
|
||||
back = img.Size(back, backX, backY).Im
|
||||
}
|
||||
if len(vups) > 50 {
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了,只展示前50个up"))
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了, 只展示前50个up"))
|
||||
vups = vups[:50]
|
||||
}
|
||||
canvas := gg.NewContext(1500, int(500*(1.1+float64(len(vups))/3)))
|
||||
@@ -275,19 +276,19 @@ func init() {
|
||||
if pagenum == "" {
|
||||
pagenum = "0"
|
||||
}
|
||||
u, err := getMemberCard(id)
|
||||
u, err := bz.GetMemberCard(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var danmaku danmakusuki
|
||||
var danmaku bz.Danmakusuki
|
||||
tr := &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
data, err := web.RequestDataWith(client, fmt.Sprintf(danmakuAPI, id, pagenum), "GET", "", web.RandUA())
|
||||
data, err := web.RequestDataWith(client, fmt.Sprintf(bz.DanmakuAPI, id, pagenum), "GET", "", web.RandUA())
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -363,7 +364,7 @@ func init() {
|
||||
canvas.DrawString(u.Mid, 900+n, 122.5)
|
||||
canvas.DrawString(fmt.Sprintf("粉丝:%d 关注:%d", u.Fans, u.Attention), startWidth, 222.5)
|
||||
canvas.DrawString(fmt.Sprintf("页码:[%d/%d]", danmaku.Data.PageNum, (danmaku.Data.Total-1)/5), startWidth, 322.5)
|
||||
canvas.DrawString("网页链接: "+fmt.Sprintf(danmakuURL, u.Mid), startWidth, 422.5)
|
||||
canvas.DrawString("网页链接: "+fmt.Sprintf(bz.DanmakuURL, u.Mid), startWidth, 422.5)
|
||||
var channelStart float64
|
||||
channelStart = float64(550)
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
@@ -527,7 +528,7 @@ func init() {
|
||||
engine.OnRegex(`^设置b站cookie?\s+(.*)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
cookie := ctx.State["regex_matched"].([]string)[1]
|
||||
err := setBilibiliCookie(cookie)
|
||||
err := cfg.Set(cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -571,7 +572,7 @@ func int2rbg(t int64) (int64, int64, int64) {
|
||||
func getPara(ctx *zero.Ctx) bool {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
if !re.MatchString(keyword) {
|
||||
searchRes, err := searchUser(keyword)
|
||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
@@ -582,7 +583,7 @@ func getPara(ctx *zero.Ctx) bool {
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
ctx.SendChain(message.Text("输入为纯数字,请选择查询uid还是用户名,输入对应序号:\n0. 查询uid\n1. 查询用户名"))
|
||||
ctx.SendChain(message.Text("输入为纯数字, 请选择查询uid还是用户名, 输入对应序号:\n0. 查询uid\n1. 查询用户名"))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 10):
|
||||
@@ -604,7 +605,7 @@ func getPara(ctx *zero.Ctx) bool {
|
||||
ctx.State["uid"] = keyword
|
||||
return true
|
||||
} else if num == 1 {
|
||||
searchRes, err := searchUser(keyword)
|
||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@@ -28,13 +29,13 @@ var (
|
||||
func init() {
|
||||
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "b站动态、专栏、视频、直播解析\n" +
|
||||
"- t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245 ",
|
||||
Brief: "b站链接解析",
|
||||
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
|
||||
})
|
||||
en.OnRegex(`((b23|acg).tv|bili2233.cn)/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
url := ctx.State["regex_matched"].([]string)[0]
|
||||
realurl, err := getrealurl("https://" + url)
|
||||
realurl, err := bz.GetRealUrl("https://" + url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -65,7 +66,7 @@ func handleVideo(ctx *zero.Ctx) {
|
||||
if id == "" {
|
||||
id = ctx.State["regex_matched"].([]string)[2]
|
||||
}
|
||||
card, err := getVideoInfo(id)
|
||||
card, err := bz.GetVideoInfo(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -88,7 +89,7 @@ func handleDynamic(ctx *zero.Ctx) {
|
||||
}
|
||||
|
||||
func handleArticle(ctx *zero.Ctx) {
|
||||
card, err := getArticleInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
card, err := bz.GetArticleInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -97,7 +98,7 @@ func handleArticle(ctx *zero.Ctx) {
|
||||
}
|
||||
|
||||
func handleLive(ctx *zero.Ctx) {
|
||||
card, err := getLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
_ "github.com/fumiama/sqlite3" // use sql
|
||||
"github.com/jinzhu/gorm"
|
||||
@@ -92,32 +89,3 @@ func updateVup() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setBilibiliCookie(cookie string) (err error) {
|
||||
cfg = config{
|
||||
BilibiliCookie: cookie,
|
||||
}
|
||||
return saveConfig(cfg)
|
||||
}
|
||||
|
||||
func reflushBilibiliCookie() (err error) {
|
||||
if file.IsNotExist(cfgFile) {
|
||||
err = errors.New("未初始化配置")
|
||||
return
|
||||
}
|
||||
reader, err := os.Open(cfgFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
return json.NewDecoder(reader).Decode(&cfg)
|
||||
}
|
||||
|
||||
func saveConfig(cfg config) (err error) {
|
||||
reader, err := os.Create(cfgFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
return json.NewEncoder(reader).Encode(&cfg)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
@@ -21,10 +22,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
referer = "https://www.bilibili.com/"
|
||||
infoURL = "https://api.bilibili.com/x/space/acc/info?mid=%v"
|
||||
serviceName = "bilibilipush"
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
referer = "https://www.bilibili.com/"
|
||||
infoURL = "https://api.bilibili.com/x/space/acc/info?mid=%v"
|
||||
)
|
||||
|
||||
// bdb bilibili推送数据库
|
||||
@@ -37,16 +37,18 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register(serviceName, &ctrl.Options[*zero.Ctx]{
|
||||
en := control.Register("bilibilipush", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "bilibilipush,需要配合job一起使用\n" +
|
||||
"- 添加b站订阅[uid|name]\n" +
|
||||
Brief: "b站推送",
|
||||
Help: "- 添加b站订阅[uid|name]\n" +
|
||||
"- 取消b站订阅[uid|name]\n" +
|
||||
"- 取消b站动态订阅[uid|name]\n" +
|
||||
"- 取消b站直播订阅[uid|name]\n" +
|
||||
"- b站推送列表\n" +
|
||||
"- 拉取b站推送 (使用job执行定时任务------记录在\"@every 10s\"触发的指令)",
|
||||
PrivateDataFolder: serviceName,
|
||||
"Tips: 需要配合job一起使用, 全局只需要设置一个, 无视响应状态推送, 下为例子\n" +
|
||||
"记录在\"@every 5m\"触发的指令)\n" +
|
||||
"拉取b站推送",
|
||||
PrivateDataFolder: "bilibilipush",
|
||||
})
|
||||
|
||||
// 加载bilibili推送数据库
|
||||
@@ -191,7 +193,7 @@ func getName(buid int64) (name string, err error) {
|
||||
|
||||
// subscribe 订阅
|
||||
func subscribe(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]interface{}{
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 0,
|
||||
@@ -202,7 +204,7 @@ func subscribe(buid, groupid int64) (err error) {
|
||||
|
||||
// unsubscribe 取消订阅
|
||||
func unsubscribe(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]interface{}{
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 1,
|
||||
@@ -212,7 +214,7 @@ func unsubscribe(buid, groupid int64) (err error) {
|
||||
}
|
||||
|
||||
func unsubscribeDynamic(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]interface{}{
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"dynamic_disable": 1,
|
||||
@@ -221,7 +223,7 @@ func unsubscribeDynamic(buid, groupid int64) (err error) {
|
||||
}
|
||||
|
||||
func unsubscribeLive(buid, groupid int64) (err error) {
|
||||
bpMap := map[string]interface{}{
|
||||
bpMap := map[string]any{
|
||||
"bilibili_uid": buid,
|
||||
"group_id": groupid,
|
||||
"live_disable": 1,
|
||||
@@ -230,7 +232,7 @@ func unsubscribeLive(buid, groupid int64) (err error) {
|
||||
}
|
||||
|
||||
func getUserDynamicCard(buid int64) (cardList []gjson.Result, err error) {
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(spaceHistoryURL, buid, 0), "GET", referer, ua)
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(bz.SpaceHistoryURL, buid, 0), "GET", referer, ua)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -239,13 +241,13 @@ func getUserDynamicCard(buid int64) (cardList []gjson.Result, err error) {
|
||||
}
|
||||
|
||||
func getLiveList(uids ...int64) (string, error) {
|
||||
m := make(map[string]interface{})
|
||||
m := make(map[string]any)
|
||||
m["uids"] = uids
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := web.PostData(liveListURL, "application/json", bytes.NewReader(b))
|
||||
data, err := web.PostData(bz.LiveListURL, "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -273,10 +275,15 @@ func sendDynamic(ctx *zero.Ctx) error {
|
||||
ct := cardList[i].Get("desc.timestamp").Int()
|
||||
if ct > t && ct > time.Now().Unix()-600 {
|
||||
lastTime[buid] = ct
|
||||
m, ok := control.Lookup(serviceName)
|
||||
m, ok := control.Lookup("bilibilipush")
|
||||
if ok {
|
||||
groupList := bdb.getAllGroupByBuidAndDynamic(buid)
|
||||
msg, err := dynamicCard2msg(cardList[i].Raw, 0)
|
||||
dc, err := bz.LoadDynamicDetail(cardList[i].Raw)
|
||||
if err != nil {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
}
|
||||
msg, err := dynamicCard2msg(&dc)
|
||||
if err != nil {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
@@ -317,14 +324,14 @@ func sendLive(ctx *zero.Ctx) error {
|
||||
oldStatus := liveStatus[key.Int()]
|
||||
if newStatus != oldStatus && newStatus == 1 {
|
||||
liveStatus[key.Int()] = newStatus
|
||||
m, ok := control.Lookup(serviceName)
|
||||
m, ok := control.Lookup("bilibilipush")
|
||||
if ok {
|
||||
groupList := bdb.getAllGroupByBuidAndLive(key.Int())
|
||||
roomID := value.Get("short_id").Int()
|
||||
if roomID == 0 {
|
||||
roomID = value.Get("room_id").Int()
|
||||
}
|
||||
lURL := liveURL + strconv.FormatInt(roomID, 10)
|
||||
lURL := bz.LiveURL + strconv.FormatInt(roomID, 10)
|
||||
lName := value.Get("uname").String()
|
||||
lTitle := value.Get("title").String()
|
||||
lCover := value.Get("cover_from_user").String()
|
||||
|
||||
@@ -54,7 +54,7 @@ func initializePush(dbpath string) *bilibilipushdb {
|
||||
}
|
||||
|
||||
// insertOrUpdateLiveAndDynamic 插入或更新数据库
|
||||
func (bdb *bilibilipushdb) insertOrUpdateLiveAndDynamic(bpMap map[string]interface{}) (err error) {
|
||||
func (bdb *bilibilipushdb) insertOrUpdateLiveAndDynamic(bpMap map[string]any) (err error) {
|
||||
db := (*gorm.DB)(bdb)
|
||||
bp := bilibilipush{}
|
||||
data, err := json.Marshal(&bpMap)
|
||||
|
||||
@@ -2,18 +2,15 @@ package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
typeMsg = map[int]string{
|
||||
msgType = map[int]string{
|
||||
1: "转发了动态",
|
||||
2: "有图营业",
|
||||
4: "无图营业",
|
||||
@@ -27,66 +24,56 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// dynamicCard2msg cType=0时,处理DynCard字符串,cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
|
||||
func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err error) {
|
||||
// dynamicCard2msg 处理DynCard
|
||||
func dynamicCard2msg(dynamicCard *bz.DynamicCard) (msg []message.MessageSegment, err error) {
|
||||
var (
|
||||
dynamicCard dynamicCard
|
||||
card Card
|
||||
vote Vote
|
||||
card bz.Card
|
||||
vote bz.Vote
|
||||
cType int
|
||||
)
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
// 初始化结构体
|
||||
switch cType {
|
||||
case 0:
|
||||
err = json.Unmarshal(binary.StringToBytes(str), &dynamicCard)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
cType = dynamicCard.Desc.Type
|
||||
case 1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308:
|
||||
err = json.Unmarshal(binary.StringToBytes(str), &card)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = errors.New("只有0, 1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308模式")
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
cType = dynamicCard.Desc.Type
|
||||
// 生成消息
|
||||
switch cType {
|
||||
case 1:
|
||||
msg = append(msg, message.Text(card.User.Uname, typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Item.Content, "\n",
|
||||
"转发的内容: \n"))
|
||||
var originMsg []message.MessageSegment
|
||||
originMsg, err = dynamicCard2msg(card.Origin, card.Item.OrigType)
|
||||
var co bz.Card
|
||||
co, err = bz.LoadCardDetail(card.Origin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, originMsg...)
|
||||
case 2:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
||||
}
|
||||
case 4:
|
||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Content, "\n"))
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
||||
"参与人数: ", humanNum(vote.JoinNum), "\n",
|
||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
||||
for i := 0; i < len(vote.Options); i++ {
|
||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
||||
@@ -96,18 +83,18 @@ func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err e
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text(card.Desc, "\n",
|
||||
card.ShareSubtitle, "\n",
|
||||
"视频链接: ", card.ShortLink, "\n"))
|
||||
case 16:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
||||
case 64:
|
||||
msg = append(msg, message.Text(card.Author.(map[string]interface{})["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title, "\n",
|
||||
card.Summary))
|
||||
for i := 0; i < len(card.ImageUrls); i++ {
|
||||
@@ -117,7 +104,7 @@ func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err e
|
||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
||||
}
|
||||
case 256:
|
||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Cover))
|
||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
||||
@@ -126,7 +113,7 @@ func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err e
|
||||
}
|
||||
|
||||
case 2048:
|
||||
msg = append(msg, message.Text(card.User.Uname, typeMsg[cType], "\n",
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Vest.Content, "\n",
|
||||
card.Sketch.Title, "\n",
|
||||
card.Sketch.DescText, "\n"))
|
||||
@@ -134,7 +121,7 @@ func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err e
|
||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
||||
case 4308:
|
||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, typeMsg[cType], "\n"))
|
||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
||||
}
|
||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
||||
@@ -153,35 +140,141 @@ func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err e
|
||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
||||
}
|
||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
||||
msg = append(msg, message.Text("动态链接: ", tURL, dynamicCard.Desc.DynamicIDStr))
|
||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// card2msg cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
|
||||
func card2msg(dynamicCard *bz.DynamicCard, card *bz.Card, cType int) (msg []message.MessageSegment, err error) {
|
||||
var (
|
||||
vote bz.Vote
|
||||
)
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
// 生成消息
|
||||
switch cType {
|
||||
case 1:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Item.Content, "\n",
|
||||
"转发的内容: \n"))
|
||||
var originMsg []message.MessageSegment
|
||||
var co bz.Card
|
||||
co, err = bz.LoadCardDetail(card.Origin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, originMsg...)
|
||||
case 2:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
||||
}
|
||||
case 4:
|
||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Content, "\n"))
|
||||
if dynamicCard.Extension.Vote != "" {
|
||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
||||
for i := 0; i < len(vote.Options); i++ {
|
||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
||||
if vote.Options[i].ImgURL != "" {
|
||||
msg = append(msg, message.Image(vote.Options[i].ImgURL))
|
||||
}
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text(card.Desc, "\n",
|
||||
card.ShareSubtitle, "\n",
|
||||
"视频链接: ", card.ShortLink, "\n"))
|
||||
case 16:
|
||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Item.Description))
|
||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
||||
case 64:
|
||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title, "\n",
|
||||
card.Summary))
|
||||
for i := 0; i < len(card.ImageUrls); i++ {
|
||||
msg = append(msg, message.Image(card.ImageUrls[i]))
|
||||
}
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
||||
}
|
||||
case 256:
|
||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
||||
card.Title))
|
||||
msg = append(msg, message.Image(card.Cover))
|
||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
||||
if card.ID != 0 {
|
||||
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
|
||||
}
|
||||
|
||||
case 2048:
|
||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
||||
card.Vest.Content, "\n",
|
||||
card.Sketch.Title, "\n",
|
||||
card.Sketch.DescText, "\n"))
|
||||
msg = append(msg, message.Image(card.Sketch.CoverURL))
|
||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
||||
case 4308:
|
||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
||||
}
|
||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
||||
"房间号: ", card.LivePlayInfo.RoomID, "\n",
|
||||
"分区: ", card.LivePlayInfo.ParentAreaName))
|
||||
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
|
||||
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
|
||||
}
|
||||
if card.LivePlayInfo.LiveStatus == 0 {
|
||||
msg = append(msg, message.Text("未开播 \n"))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
|
||||
default:
|
||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
||||
}
|
||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// dynamicDetail 用动态id查动态信息
|
||||
func dynamicDetail(dynamicIDStr string) (msg []message.MessageSegment, err error) {
|
||||
var data []byte
|
||||
data, err = web.GetData(fmt.Sprintf(dynamicDetailURL, dynamicIDStr))
|
||||
dyc, err := bz.GetDynamicDetail(dynamicIDStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return dynamicCard2msg(gjson.ParseBytes(data).Get("data.card").Raw, 0)
|
||||
return dynamicCard2msg(&dyc)
|
||||
}
|
||||
|
||||
// articleCard2msg 专栏转消息
|
||||
func articleCard2msg(card Card, defaultID string) (msg []message.MessageSegment) {
|
||||
func articleCard2msg(card bz.Card, defaultID string) (msg []message.MessageSegment) {
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
for i := 0; i < len(card.OriginImageUrls); i++ {
|
||||
msg = append(msg, message.Image(card.OriginImageUrls[i]))
|
||||
}
|
||||
msg = append(msg, message.Text("\n", card.Title, "\n", "UP主: ", card.AuthorName, "\n",
|
||||
"阅读: ", humanNum(card.Stats.View), " 评论: ", humanNum(card.Stats.Reply), "\n",
|
||||
cvURL, defaultID))
|
||||
"阅读: ", bz.HumanNum(card.Stats.View), " 评论: ", bz.HumanNum(card.Stats.Reply), "\n",
|
||||
bz.CVURL, defaultID))
|
||||
return
|
||||
}
|
||||
|
||||
// liveCard2msg 直播卡片转消息
|
||||
func liveCard2msg(card roomCard) (msg []message.MessageSegment) {
|
||||
func liveCard2msg(card bz.RoomCard) (msg []message.MessageSegment) {
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
msg = append(msg, message.Image(card.RoomInfo.Keyframe))
|
||||
msg = append(msg, message.Text("\n", card.RoomInfo.Title, "\n",
|
||||
@@ -197,37 +290,37 @@ func liveCard2msg(card roomCard) (msg []message.MessageSegment) {
|
||||
if card.RoomInfo.LiveStatus == 0 {
|
||||
msg = append(msg, message.Text("未开播 \n"))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播中 ", humanNum(card.RoomInfo.Online), "人气\n"))
|
||||
msg = append(msg, message.Text("直播中 ", bz.HumanNum(card.RoomInfo.Online), "人气\n"))
|
||||
}
|
||||
if card.RoomInfo.ShortID != 0 {
|
||||
msg = append(msg, message.Text("直播间链接: ", lURL, card.RoomInfo.ShortID))
|
||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.ShortID))
|
||||
} else {
|
||||
msg = append(msg, message.Text("直播间链接: ", lURL, card.RoomInfo.RoomID))
|
||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.RoomID))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// videoCard2msg 视频卡片转消息
|
||||
func videoCard2msg(card Card) (msg []message.MessageSegment, err error) {
|
||||
var mCard memberCard
|
||||
func videoCard2msg(card bz.Card) (msg []message.MessageSegment, err error) {
|
||||
var mCard bz.MemberCard
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
mCard, err = getMemberCard(card.Owner.Mid)
|
||||
mCard, err = bz.GetMemberCard(card.Owner.Mid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
|
||||
if card.Rights.IsCooperation == 1 {
|
||||
for i := 0; i < len(card.Staff); i++ {
|
||||
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", humanNum(card.Staff[i].Follower), "\n"))
|
||||
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", bz.HumanNum(card.Staff[i].Follower), "\n"))
|
||||
}
|
||||
} else {
|
||||
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", humanNum(mCard.Fans), "\n"))
|
||||
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", bz.HumanNum(mCard.Fans), "\n"))
|
||||
}
|
||||
msg = append(msg, message.Text("播放: ", humanNum(card.Stat.View), " 弹幕: ", humanNum(card.Stat.Danmaku)))
|
||||
msg = append(msg, message.Text("播放: ", bz.HumanNum(card.Stat.View), " 弹幕: ", bz.HumanNum(card.Stat.Danmaku)))
|
||||
msg = append(msg, message.Image(card.Pic))
|
||||
msg = append(msg, message.Text("\n点赞: ", humanNum(card.Stat.Like), " 投币: ", humanNum(card.Stat.Coin), "\n",
|
||||
"收藏: ", humanNum(card.Stat.Favorite), " 分享: ", humanNum(card.Stat.Share), "\n",
|
||||
vURL, card.BvID))
|
||||
msg = append(msg, message.Text("\n点赞: ", bz.HumanNum(card.Stat.Like), " 投币: ", bz.HumanNum(card.Stat.Coin), "\n",
|
||||
"收藏: ", bz.HumanNum(card.Stat.Favorite), " 分享: ", bz.HumanNum(card.Stat.Share), "\n",
|
||||
bz.VURL, card.BvID))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@ package bilibili
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
)
|
||||
|
||||
func TestArticleInfo(t *testing.T) {
|
||||
card, err := getArticleInfo("17279244")
|
||||
card, err := bz.GetArticleInfo("17279244")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -43,7 +45,7 @@ func TestDynamicDetail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMemberCard(t *testing.T) {
|
||||
card, err := getMemberCard(2)
|
||||
card, err := bz.GetMemberCard(2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -51,22 +53,22 @@ func TestMemberCard(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVideoInfo(t *testing.T) {
|
||||
card, err := getVideoInfo("10007")
|
||||
card, err := bz.GetVideoInfo("10007")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = getVideoInfo("BV1xx411c7mD")
|
||||
card, err = bz.GetVideoInfo("BV1xx411c7mD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = getVideoInfo("bv1xx411c7mD")
|
||||
card, err = bz.GetVideoInfo("bv1xx411c7mD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(videoCard2msg(card))
|
||||
card, err = getVideoInfo("BV1mF411j7iU")
|
||||
card, err = bz.GetVideoInfo("BV1mF411j7iU")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -74,7 +76,7 @@ func TestVideoInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLiveRoomInfo(t *testing.T) {
|
||||
card, err := getLiveRoomInfo("83171")
|
||||
card, err := bz.GetLiveRoomInfo("83171")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
const (
|
||||
// tURL bilibili动态前缀
|
||||
tURL = "https://t.bilibili.com/"
|
||||
// liveURL bilibili直播前缀
|
||||
liveURL = "https://live.bilibili.com/"
|
||||
// dynamicDetailURL 当前动态信息,一个card
|
||||
dynamicDetailURL = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=%v"
|
||||
// memberCardURL 个人信息
|
||||
memberCardURL = "https://account.bilibili.com/api/member/getCardByMid?mid=%v"
|
||||
// articleInfoURL 查看专栏信息
|
||||
articleInfoURL = "https://api.bilibili.com/x/article/viewinfo?id=%v"
|
||||
// cvURL b站专栏前缀
|
||||
cvURL = "https://www.bilibili.com/read/cv"
|
||||
// liveRoomInfoURL 查看直播间信息
|
||||
liveRoomInfoURL = "https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=%v"
|
||||
// lURL b站直播间前缀
|
||||
lURL = "https://live.bilibili.com/"
|
||||
// videoInfoURL 查看视频信息
|
||||
videoInfoURL = "https://api.bilibili.com/x/web-interface/view?aid=%v&bvid=%v"
|
||||
// vURL 视频网址前缀
|
||||
vURL = "https://www.bilibili.com/video/"
|
||||
// searchUserURL 查找b站用户
|
||||
searchUserURL = "http://api.bilibili.com/x/web-interface/search/type?search_type=bili_user&keyword=%v"
|
||||
// vtbDetailURL 查找vtb信息
|
||||
vtbDetailURL = "https://api.vtbs.moe/v1/detail/%v"
|
||||
// medalwallURL 查找牌子
|
||||
medalwallURL = "https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id=%v"
|
||||
// spaceHistoryURL 历史动态信息,一共12个card
|
||||
spaceHistoryURL = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?host_uid=%v&offset_dynamic_id=%v&need_top=0"
|
||||
// liveListURL 获得直播状态
|
||||
liveListURL = "https://api.live.bilibili.com/room/v1/Room/get_status_info_by_uids"
|
||||
// danmakuAPI 弹幕网获得用户弹幕api
|
||||
danmakuAPI = "https://danmaku.suki.club/api/search/user/detail?uid=%v&pagenum=%v&pagesize=5"
|
||||
// danmakuURL 弹幕网链接
|
||||
danmakuURL = "https://danmaku.suki.club/user/%v"
|
||||
)
|
||||
|
||||
// dynamicCard 总动态结构体,包括desc,card
|
||||
type dynamicCard struct {
|
||||
Desc Desc `json:"desc"`
|
||||
Card string `json:"card"`
|
||||
Extension struct {
|
||||
VoteCfg struct {
|
||||
VoteID int `json:"vote_id"`
|
||||
Desc string `json:"desc"`
|
||||
JoinNum int `json:"join_num"`
|
||||
} `json:"vote_cfg"`
|
||||
Vote string `json:"vote"`
|
||||
} `json:"extension"`
|
||||
}
|
||||
|
||||
// Card 卡片结构体
|
||||
type Card struct {
|
||||
Item struct {
|
||||
Content string `json:"content"`
|
||||
UploadTime int `json:"upload_time"`
|
||||
Description string `json:"description"`
|
||||
Pictures []struct {
|
||||
ImgSrc string `json:"img_src"`
|
||||
} `json:"pictures"`
|
||||
Timestamp int `json:"timestamp"`
|
||||
Cover struct {
|
||||
Default string `json:"default"`
|
||||
} `json:"cover"`
|
||||
OrigType int `json:"orig_type"`
|
||||
} `json:"item"`
|
||||
AID interface{} `json:"aid"`
|
||||
BvID interface{} `json:"bvid"`
|
||||
Dynamic interface{} `json:"dynamic"`
|
||||
Pic string `json:"pic"`
|
||||
Title string `json:"title"`
|
||||
ID int `json:"id"`
|
||||
Summary string `json:"summary"`
|
||||
ImageUrls []string `json:"image_urls"`
|
||||
OriginImageUrls []string `json:"origin_image_urls"`
|
||||
Sketch struct {
|
||||
Title string `json:"title"`
|
||||
DescText string `json:"desc_text"`
|
||||
CoverURL string `json:"cover_url"`
|
||||
TargetURL string `json:"target_url"`
|
||||
} `json:"sketch"`
|
||||
Stat struct {
|
||||
Aid int `json:"aid"`
|
||||
View int `json:"view"`
|
||||
Danmaku int `json:"danmaku"`
|
||||
Reply int `json:"reply"`
|
||||
Favorite int `json:"favorite"`
|
||||
Coin int `json:"coin"`
|
||||
Share int `json:"share"`
|
||||
Like int `json:"like"`
|
||||
} `json:"stat"`
|
||||
Stats struct {
|
||||
Aid int `json:"aid"`
|
||||
View int `json:"view"`
|
||||
Danmaku int `json:"danmaku"`
|
||||
Reply int `json:"reply"`
|
||||
Favorite int `json:"favorite"`
|
||||
Coin int `json:"coin"`
|
||||
Share int `json:"share"`
|
||||
Like int `json:"like"`
|
||||
} `json:"stats"`
|
||||
Owner struct {
|
||||
Name string `json:"name"`
|
||||
Pubdate int `json:"pubdate"`
|
||||
Mid int `json:"mid"`
|
||||
} `json:"owner"`
|
||||
Cover string `json:"cover"`
|
||||
ShortID interface{} `json:"short_id"`
|
||||
LivePlayInfo struct {
|
||||
ParentAreaName string `json:"parent_area_name"`
|
||||
AreaName string `json:"area_name"`
|
||||
Cover string `json:"cover"`
|
||||
Link string `json:"link"`
|
||||
Online int `json:"online"`
|
||||
RoomID int `json:"room_id"`
|
||||
LiveStatus int `json:"live_status"`
|
||||
WatchedShow string `json:"watched_show"`
|
||||
Title string `json:"title"`
|
||||
} `json:"live_play_info"`
|
||||
Intro string `json:"intro"`
|
||||
Schema string `json:"schema"`
|
||||
Author interface{} `json:"author"`
|
||||
AuthorName string `json:"author_name"`
|
||||
PlayCnt int `json:"play_cnt"`
|
||||
ReplyCnt int `json:"reply_cnt"`
|
||||
TypeInfo string `json:"type_info"`
|
||||
User struct {
|
||||
Name string `json:"name"`
|
||||
Uname string `json:"uname"`
|
||||
} `json:"user"`
|
||||
Desc string `json:"desc"`
|
||||
ShareSubtitle string `json:"share_subtitle"`
|
||||
ShortLink string `json:"short_link"`
|
||||
PublishTime int `json:"publish_time"`
|
||||
BannerURL string `json:"banner_url"`
|
||||
Ctime int `json:"ctime"`
|
||||
Vest struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"vest"`
|
||||
Upper string `json:"upper"`
|
||||
Origin string `json:"origin"`
|
||||
Pubdate int `json:"pubdate"`
|
||||
Rights struct {
|
||||
IsCooperation int `json:"is_cooperation"`
|
||||
} `json:"rights"`
|
||||
Staff []struct {
|
||||
Title string `json:"title"`
|
||||
Name string `json:"name"`
|
||||
Follower int `json:"follower"`
|
||||
} `json:"staff"`
|
||||
}
|
||||
|
||||
// Desc 描述结构体
|
||||
type Desc struct {
|
||||
Type int `json:"type"`
|
||||
DynamicIDStr string `json:"dynamic_id_str"`
|
||||
OrigType int `json:"orig_type"`
|
||||
Timestamp int `json:"timestamp"`
|
||||
Origin struct {
|
||||
DynamicIDStr string `json:"dynamic_id_str"`
|
||||
} `json:"origin"`
|
||||
UserProfile struct {
|
||||
Info struct {
|
||||
Uname string `json:"uname"`
|
||||
} `json:"info"`
|
||||
} `json:"user_profile"`
|
||||
}
|
||||
|
||||
// Vote 投票结构体
|
||||
type Vote struct {
|
||||
ChoiceCnt int `json:"choice_cnt"`
|
||||
Desc string `json:"desc"`
|
||||
Endtime int `json:"endtime"`
|
||||
JoinNum int `json:"join_num"`
|
||||
Options []struct {
|
||||
Idx int `json:"idx"`
|
||||
Desc string `json:"desc"`
|
||||
ImgURL string `json:"img_url"`
|
||||
} `json:"options"`
|
||||
}
|
||||
|
||||
// memberCard 个人信息卡片
|
||||
type memberCard struct {
|
||||
Mid string `json:"mid"`
|
||||
Name string `json:"name"`
|
||||
Sex string `json:"sex"`
|
||||
Face string `json:"face"`
|
||||
Coins float64 `json:"coins"`
|
||||
Regtime int64 `json:"regtime"`
|
||||
Birthday string `json:"birthday"`
|
||||
Sign string `json:"sign"`
|
||||
Attentions []int64 `json:"attentions"`
|
||||
Fans int `json:"fans"`
|
||||
Friend int `json:"friend"`
|
||||
Attention int `json:"attention"`
|
||||
LevelInfo struct {
|
||||
CurrentLevel int `json:"current_level"`
|
||||
} `json:"level_info"`
|
||||
}
|
||||
|
||||
// roomCard 直播间卡片
|
||||
type roomCard struct {
|
||||
RoomInfo struct {
|
||||
RoomID int `json:"room_id"`
|
||||
ShortID int `json:"short_id"`
|
||||
Title string `json:"title"`
|
||||
LiveStatus int `json:"live_status"`
|
||||
AreaName string `json:"area_name"`
|
||||
ParentAreaName string `json:"parent_area_name"`
|
||||
Keyframe string `json:"keyframe"`
|
||||
Online int `json:"online"`
|
||||
} `json:"room_info"`
|
||||
AnchorInfo struct {
|
||||
BaseInfo struct {
|
||||
Uname string `json:"uname"`
|
||||
} `json:"base_info"`
|
||||
} `json:"anchor_info"`
|
||||
}
|
||||
|
||||
// searchData 查找b站用户总结构体
|
||||
type searchData struct {
|
||||
Data struct {
|
||||
NumResults int `json:"numResults"`
|
||||
Result []searchResult `json:"result"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// searchResult 查找b站用户结果
|
||||
type searchResult struct {
|
||||
Mid int64 `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Gender int64 `json:"gender"`
|
||||
Usign string `json:"usign"`
|
||||
Level int64 `json:"level"`
|
||||
}
|
||||
|
||||
// medalData 牌子接口返回结构体
|
||||
type medalData struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
List []medal `json:"list"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// medalInfo b站牌子信息
|
||||
type medalInfo struct {
|
||||
Mid int64 `json:"target_id"`
|
||||
MedalName string `json:"medal_name"`
|
||||
Level int64 `json:"level"`
|
||||
MedalColorStart int64 `json:"medal_color_start"`
|
||||
MedalColorEnd int64 `json:"medal_color_end"`
|
||||
MedalColorBorder int64 `json:"medal_color_border"`
|
||||
}
|
||||
|
||||
type medal struct {
|
||||
Uname string `json:"target_name"`
|
||||
medalInfo `json:"medal_info"`
|
||||
}
|
||||
|
||||
type medalSlice []medal
|
||||
|
||||
func (m medalSlice) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
func (m medalSlice) Swap(i, j int) {
|
||||
m[i], m[j] = m[j], m[i]
|
||||
}
|
||||
func (m medalSlice) Less(i, j int) bool {
|
||||
return m[i].Level > m[j].Level
|
||||
}
|
||||
|
||||
// vtb信息
|
||||
type vtbDetail struct {
|
||||
Mid int `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Video int `json:"video"`
|
||||
Roomid int `json:"roomid"`
|
||||
Rise int `json:"rise"`
|
||||
Follower int `json:"follower"`
|
||||
GuardNum int `json:"guardNum"`
|
||||
AreaRank int `json:"areaRank"`
|
||||
}
|
||||
|
||||
// danmakusuki 弹幕网结构体
|
||||
type danmakusuki struct {
|
||||
Code int64 `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
Data []struct {
|
||||
Channel struct {
|
||||
Name string `json:"name"`
|
||||
IsLiving bool `json:"isLiving"`
|
||||
UID int64 `json:"uId"`
|
||||
RoomID int64 `json:"roomId"`
|
||||
FaceURL string `json:"faceUrl"`
|
||||
LiveCount int64 `json:"liveCount"`
|
||||
} `json:"channel"`
|
||||
Live struct {
|
||||
LiveID string `json:"liveId"`
|
||||
Title string `json:"title"`
|
||||
IsFinish bool `json:"isFinish"`
|
||||
CoverURL string `json:"coverUrl"`
|
||||
StartDate int64 `json:"startDate"`
|
||||
StopDate int64 `json:"stopDate"`
|
||||
DanmakusCount int64 `json:"danmakusCount"`
|
||||
TotalIncome float64 `json:"totalIncome"`
|
||||
WatchCount int64 `json:"watchCount"`
|
||||
} `json:"live"`
|
||||
Danmakus []struct {
|
||||
Name string `json:"name"`
|
||||
Type int64 `json:"type"`
|
||||
UID int64 `json:"uId"`
|
||||
SendDate int64 `json:"sendDate"`
|
||||
Price float64 `json:"price"`
|
||||
Message string `json:"message"`
|
||||
} `json:"danmakus"`
|
||||
} `json:"data"`
|
||||
Total int64 `json:"total"`
|
||||
PageNum int64 `json:"pageNum"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
HasMore bool `json:"hasMore"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// 配置结构体
|
||||
type config struct {
|
||||
BilibiliCookie string `json:"bilibili_cookie"`
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// humanNum 格式化人数
|
||||
func humanNum(res int) string {
|
||||
if res/10000 != 0 {
|
||||
return strconv.FormatFloat(float64(res)/10000, 'f', 2, 64) + "万"
|
||||
}
|
||||
return strconv.Itoa(res)
|
||||
}
|
||||
|
||||
// getrealurl 获取跳转后的链接
|
||||
func getrealurl(url string) (realurl string, err error) {
|
||||
data, err := http.Head(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = data.Body.Close()
|
||||
realurl = data.Request.URL.String()
|
||||
return
|
||||
}
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("bookreview", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "哀伤雪刃推书记录\n- 书评[xxx]\n- 随机书评",
|
||||
Brief: "哀伤雪刃推书书评",
|
||||
Help: "- 书评[xxx]\n- 随机书评",
|
||||
PublicDataFolder: "BookReview",
|
||||
})
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ var sm syncx.Map[int64, string]
|
||||
func init() {
|
||||
engine := control.Register("breakrepeat", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "打断复读\n- 打断" + strconv.Itoa(throttle) + "次以上复读\n",
|
||||
Brief: "打断复读",
|
||||
Help: "- 打断" + strconv.Itoa(throttle) + "次以上复读\n",
|
||||
})
|
||||
engine.On("message/group", zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||
return !zero.HasPicture(ctx)
|
||||
@@ -37,8 +38,8 @@ func init() {
|
||||
return
|
||||
}
|
||||
sm.Delete(gid)
|
||||
if len(r) > 2 {
|
||||
ru := []rune(r)
|
||||
if len(r) > 5 {
|
||||
ru := []rune(r[3:])
|
||||
rand.Shuffle(len(ru), func(i, j int) {
|
||||
ru[i], ru[j] = ru[j], ru[i]
|
||||
})
|
||||
|
||||
@@ -32,8 +32,8 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("cangtoushi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "藏头诗\n" +
|
||||
"- 藏头诗[xxx]\n- 藏尾诗[xxx]",
|
||||
Brief: "藏头诗, 藏尾诗",
|
||||
Help: "- 藏头诗[xxx]\n- 藏尾诗[xxx]",
|
||||
})
|
||||
engine.OnRegex(`藏头诗\s?([一-龥]{3,10})$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
kw := ctx.State["regex_matched"].([]string)[1]
|
||||
|
||||
@@ -17,6 +17,7 @@ var (
|
||||
poke = rate.NewManager[int64](time.Minute*5, 8) // 戳一戳
|
||||
engine = control.Register("chat", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "基础反应, 群空调",
|
||||
Help: "chat\n- [BOT名字]\n- [戳一戳BOT]\n- 空调开\n- 空调关\n- 群温度\n- 设置温度[正整数]",
|
||||
})
|
||||
)
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("choose", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "choose\n" +
|
||||
"- 选择可口可乐还是百事可乐\n" +
|
||||
"- 选择肯德基还是麦当劳还是必胜客",
|
||||
Brief: "选择困难症帮手",
|
||||
Help: "例: 选择可口可乐还是百事可乐\n" +
|
||||
"选择肯德基还是麦当劳还是必胜客",
|
||||
})
|
||||
engine.OnPrefix("选择").SetBlock(true).Handle(handle)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("chouxianghua", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "抽象话\n- 抽象翻译xxx",
|
||||
Brief: "翻译为抽象话",
|
||||
Help: "- 抽象翻译xxx",
|
||||
PublicDataFolder: "ChouXiangHua",
|
||||
})
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ func init() {
|
||||
// 初始化engine
|
||||
engine := control.Register("chrev", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "字符翻转\n- 翻转 I love you",
|
||||
Brief: "英文字符翻转",
|
||||
Help: "例: 翻转 I love you",
|
||||
})
|
||||
// 处理字符翻转指令
|
||||
engine.OnRegex(`^翻转\s*([A-Za-z\s]*)$`).SetBlock(true).
|
||||
|
||||
@@ -25,7 +25,8 @@ var (
|
||||
func init() {
|
||||
control.Register("coser", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "三次元小姐姐\n- coser",
|
||||
Brief: "三次元coser",
|
||||
Help: "- coser",
|
||||
}).ApplySingle(ctxext.DefaultSingle).OnFullMatch("coser").SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("cpstory", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "cp短打\n- 组cp[@xxx][@xxx]\n- 磕cp大老师 雪乃",
|
||||
Brief: "cp短打", // 这里也许有更好的名字
|
||||
Help: "- 组cp[@xxx][@xxx]\n- 磕cp大老师 雪乃",
|
||||
PublicDataFolder: "CpStory",
|
||||
})
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("curse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "骂人(求骂,自卫)\n- 骂我\n- 大力骂我",
|
||||
Brief: "骂人反击",
|
||||
Help: "- 骂我\n- 大力骂我",
|
||||
PublicDataFolder: "Curse",
|
||||
})
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ package deepdanbooru
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/danbooru"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
@@ -17,9 +18,9 @@ import (
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("danbooru", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "二次元图片标签识别\n" +
|
||||
"- 鉴赏图片[图片]",
|
||||
DisableOnDefault: false,
|
||||
Brief: "二次元图片标签识别",
|
||||
Help: "- 鉴赏图片[图片]",
|
||||
PrivateDataFolder: "danbooru",
|
||||
})
|
||||
|
||||
@@ -30,7 +31,7 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
for _, url := range ctx.State["image_url"].([]string) {
|
||||
t, err := danbooru.TagURL("", url)
|
||||
t, st, err := tagurl("", url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -40,7 +41,11 @@ func init() { // 插件主体
|
||||
if file.IsNotExist(f) {
|
||||
_ = writer.SavePNG2Path(f, t)
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + f))
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("file:///"+file.BOTPATH+"/"+f))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text("tags: ", strings.Join(st.tseq, ","))))
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
118
plugin/danbooru/tag.go
Normal file
118
plugin/danbooru/tag.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package deepdanbooru
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
imgutils "github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text" // jpg png gif
|
||||
_ "golang.org/x/image/webp" // webp
|
||||
)
|
||||
|
||||
const api = "https://nsfwtag.azurewebsites.net/api/tag?limit=0.5&url="
|
||||
|
||||
type sorttags struct {
|
||||
tags map[string]float64
|
||||
tseq []string
|
||||
}
|
||||
|
||||
func newsorttags(tags map[string]float64) (s *sorttags) {
|
||||
t := make([]string, 0, len(tags))
|
||||
for k := range tags {
|
||||
t = append(t, k)
|
||||
}
|
||||
return &sorttags{tags: tags, tseq: t}
|
||||
}
|
||||
|
||||
func (s *sorttags) Len() int {
|
||||
return len(s.tags)
|
||||
}
|
||||
|
||||
func (s *sorttags) Less(i, j int) bool {
|
||||
v1 := s.tseq[i]
|
||||
v2 := s.tseq[j]
|
||||
return s.tags[v1] >= s.tags[v2]
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (s *sorttags) Swap(i, j int) {
|
||||
s.tseq[j], s.tseq[i] = s.tseq[i], s.tseq[j]
|
||||
}
|
||||
|
||||
func tagurl(name, u string) (im image.Image, st *sorttags, err error) {
|
||||
ch := make(chan []byte, 1)
|
||||
go func() {
|
||||
var data []byte
|
||||
data, err = web.GetData(u)
|
||||
ch <- data
|
||||
}()
|
||||
|
||||
data, err := web.GetData(api + url.QueryEscape(u))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tags := make(map[string]float64)
|
||||
err = json.Unmarshal(data, &tags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
longestlen := 0
|
||||
for k := range tags {
|
||||
if len(k) > longestlen {
|
||||
longestlen = len(k)
|
||||
}
|
||||
}
|
||||
longestlen++
|
||||
|
||||
st = newsorttags(tags)
|
||||
sort.Sort(st)
|
||||
|
||||
_, err = file.GetLazyData(text.BoldFontFile, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = file.GetLazyData(text.ConsolasFontFile, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data = <-ch
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
img = imgutils.Limit(img, 1280, 720)
|
||||
|
||||
canvas := gg.NewContext(img.Bounds().Size().X, img.Bounds().Size().Y+int(float64(img.Bounds().Size().X)*0.2)+len(tags)*img.Bounds().Size().X/25)
|
||||
canvas.SetRGB(1, 1, 1)
|
||||
canvas.Clear()
|
||||
canvas.DrawImage(img, 0, 0)
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, float64(img.Bounds().Size().X)*0.1); err != nil {
|
||||
return
|
||||
}
|
||||
canvas.SetRGB(0, 0, 0)
|
||||
canvas.DrawString(name, float64(img.Bounds().Size().X)*0.02, float64(img.Bounds().Size().Y)+float64(img.Bounds().Size().X)*0.1)
|
||||
i := float64(img.Bounds().Size().Y) + float64(img.Bounds().Size().X)*0.2
|
||||
if err = canvas.LoadFontFace(text.ConsolasFontFile, float64(img.Bounds().Size().X)*0.04); err != nil {
|
||||
return
|
||||
}
|
||||
rate := float64(img.Bounds().Size().X) * 0.04
|
||||
for _, k := range st.tseq {
|
||||
canvas.DrawString(fmt.Sprintf("* %-*s -%.3f-", longestlen, k, tags[k]), float64(img.Bounds().Size().X)*0.04, i)
|
||||
i += rate
|
||||
}
|
||||
im = canvas.Image()
|
||||
return
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
|
||||
var engine = control.Register("diana", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "嘉然\n" +
|
||||
"- 小作文\n" +
|
||||
Brief: "嘉然相关", // 也许使用常用功能当Brief更好
|
||||
Help: "- 小作文\n" +
|
||||
"- 发大病\n" +
|
||||
"- 教你一篇小作文[作文]",
|
||||
PublicDataFolder: "Diana",
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
)
|
||||
|
||||
type bottle struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64
|
||||
QQ int64 `db:"qq"` // QQ 发送者 qq
|
||||
Grp int64 `db:"grp"` // Grp 限制抽出的群 / 人(负数)
|
||||
Name string `db:"name"` // Name 发送者 昵称
|
||||
Msg string `db:"msg"` // Msg 消息,纯文本
|
||||
}
|
||||
|
||||
var sea = &sql.Sqlite{}
|
||||
var seamu sync.RWMutex
|
||||
|
||||
func newBottle(qq, grp int64, name, msg string) *bottle {
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s", qq, grp, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &bottle{ID: id, QQ: qq, Grp: grp, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (b *bottle) throw(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Insert(channel, b)
|
||||
}
|
||||
|
||||
func (b *bottle) destroy(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Del(channel, "WHERE id="+strconv.FormatInt(b.ID, 10))
|
||||
}
|
||||
|
||||
// fetchBottle grp != 0
|
||||
func fetchBottle(db *sql.Sqlite, channel string, grp int64) (*bottle, error) {
|
||||
seamu.RLock()
|
||||
defer seamu.RUnlock()
|
||||
b := new(bottle)
|
||||
return b, db.Find(channel, b, "WHERE grp=0 or grp="+strconv.FormatInt(grp, 10)+" ORDER BY RANDOM() limit 1")
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Create(channel, &bottle{})
|
||||
}
|
||||
@@ -2,132 +2,108 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type sea struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64 hashCheck.
|
||||
QQ int64 `db:"qq"` // Get current user(Who sends this)
|
||||
Name string `db:"Name"` // his or her name at that time:P
|
||||
Msg string `db:"msg"` // What he or she sent to bot?
|
||||
Grp int64 `db:"grp"` // which group sends this msg?
|
||||
Time string `db:"time"` // we need to know the current time,master>
|
||||
}
|
||||
|
||||
var seaSide = &sql.Sqlite{}
|
||||
var seaLocker sync.RWMutex
|
||||
|
||||
// We need a container to inject what we need :(
|
||||
|
||||
func init() {
|
||||
en := control.Register("driftbottle", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "漂流瓶\n- (在群xxx)丢漂流瓶(到频道xxx) [消息]\n- (从频道xxx)捡漂流瓶\n- @BOT 创建频道 xxx\n- 跳入(频道)海中\n- 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global",
|
||||
Brief: "漂流瓶",
|
||||
Help: "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
||||
PrivateDataFolder: "driftbottle",
|
||||
})
|
||||
sea.DBPath = en.DataFolder() + "sea.db"
|
||||
err := sea.Open(time.Hour * 24)
|
||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
||||
err := seaSide.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = createChannel(sea, "global")
|
||||
en.OnRegex(`^(在群\d+)?丢漂流瓶(到频道\w+)?\s+(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
channel := "global"
|
||||
msg := msgs[3]
|
||||
var err error
|
||||
if msgs[1] != "" {
|
||||
grp, err = strconv.ParseInt(msgs[1][6:], 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("群号非法!"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if msgs[2] != "" {
|
||||
channel = msgs[2][9:]
|
||||
}
|
||||
if msg == "" {
|
||||
ctx.SendChain(message.Text("消息为空!"))
|
||||
return
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel, msg)
|
||||
err = newBottle(
|
||||
ctx.Event.UserID,
|
||||
grp,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
msg,
|
||||
).throw(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你将它扔进大海,希望有人捞到吧~")))
|
||||
})
|
||||
en.OnRegex(`^(从频道\w+)?捡漂流瓶$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
if grp == 0 {
|
||||
grp = -ctx.Event.UserID
|
||||
}
|
||||
if grp == 0 {
|
||||
ctx.SendChain(message.Text("找不到对象!"))
|
||||
return
|
||||
}
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1][9:]
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel)
|
||||
b, err := fetchBottle(sea, channel, grp)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = b.destroy(sea, channel)
|
||||
wg.Done()
|
||||
}()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(
|
||||
ctx.Event.MessageID,
|
||||
message.Text("你在海边捡到了一个来自 ", b.Name, " 的漂流瓶,打开瓶子,里面有一张纸条,写着:"),
|
||||
message.Text(b.Msg),
|
||||
),
|
||||
)
|
||||
wg.Wait()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
en.OnPrefix("创建频道", zero.SuperUserPermission, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
channel := strings.TrimRight(ctx.State["args"].(string), " ")
|
||||
if channel == "" {
|
||||
ctx.SendChain(message.Text("频道名为空!"))
|
||||
return
|
||||
}
|
||||
err := createChannel(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功~")))
|
||||
})
|
||||
en.OnRegex(`^跳入(\w+)?海中$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1]
|
||||
}
|
||||
seamu.RLock()
|
||||
c, err := sea.Count(channel)
|
||||
seamu.RUnlock()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你缓缓走入大海,感受着海浪轻柔地拍打着你的小腿,膝盖……\n波浪卷着你的腰腹,你感觉有些把握不住平衡了……\n……\n你沉入海中,", c, " 个物体与你一同沉浮。\n不知何处涌来一股暗流,你失去了意识。")))
|
||||
})
|
||||
|
||||
_ = createChannel(seaSide)
|
||||
en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
be, err := fetchBottle(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERR:", err))
|
||||
}
|
||||
idstr := strconv.Itoa(int(be.ID))
|
||||
qqstr := strconv.Itoa(int(be.QQ))
|
||||
grpstr := strconv.Itoa(int(be.Grp))
|
||||
botname := zero.BotConfig.NickName[0]
|
||||
msg := message.Message{message.CustomNode(botname, ctx.Event.SelfID, botname+"试着帮你捞出来了这个~\nID:"+idstr+"\n投递人: "+be.Name+"("+qqstr+")"+"\n群号: "+grpstr+"\n时间: "+be.Time+"\n内容: \n"+be.Msg)}
|
||||
ctx.Send(msg)
|
||||
})
|
||||
|
||||
en.OnRegex(`throw.*?(.*)`, zero.OnlyToMe, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
senderFormatTime := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
|
||||
rawSenderMessage := ctx.State["regex_matched"].([]string)[1]
|
||||
rawMessageCallBack := message.UnescapeCQCodeText(rawSenderMessage)
|
||||
keyWordsNum := utf8.RuneCountInString(rawMessageCallBack)
|
||||
if keyWordsNum < 10 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("需要投递的内容过少( "))
|
||||
return
|
||||
}
|
||||
// check current needs and prepare to throw drift_bottle.
|
||||
err = globalbottle(
|
||||
ctx.Event.UserID,
|
||||
ctx.Event.GroupID,
|
||||
senderFormatTime,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
rawMessageCallBack,
|
||||
).throw(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("已经帮你丢出去了哦~")))
|
||||
})
|
||||
}
|
||||
|
||||
func globalbottle(qq, grp int64, time, name, msg string) *sea { // Check as if the User is available and collect information to store.
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s_%s", grp, qq, time, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &sea{ID: id, Grp: grp, Time: time, QQ: qq, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (be *sea) throw(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Insert("global", be)
|
||||
}
|
||||
|
||||
func fetchBottle(db *sql.Sqlite) (*sea, error) {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
be := new(sea)
|
||||
return be, db.Pick("global", be)
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Create("global", &sea{})
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ const bed = "https://www.gstatic.com/android/keyboard/emojikitchen/%d/u%x/u%x_u%
|
||||
func init() {
|
||||
control.Register("emojimix", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "合成emoji\n" +
|
||||
"- [emoji][emoji]",
|
||||
Brief: "合成emoji",
|
||||
Help: "- [emoji][emoji]",
|
||||
}).OnMessage(match).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
r := ctx.State["emojimix"].([]rune)
|
||||
|
||||
@@ -13,10 +13,7 @@ import (
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
)
|
||||
|
||||
const (
|
||||
servicename = "epidemic"
|
||||
txurl = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf"
|
||||
)
|
||||
const txurl = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf"
|
||||
|
||||
// result 疫情查询结果
|
||||
type result struct {
|
||||
@@ -35,8 +32,8 @@ type epidemic struct {
|
||||
type area struct {
|
||||
Name string `json:"name"`
|
||||
Today struct {
|
||||
Confirm int `json:"confirm"`
|
||||
Wzzadd interface{} `json:"wzz_add"`
|
||||
Confirm int `json:"confirm"`
|
||||
Wzzadd any `json:"wzz_add"`
|
||||
} `json:"today"`
|
||||
Total struct {
|
||||
NowConfirm int `json:"nowConfirm"`
|
||||
@@ -50,10 +47,10 @@ type area struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
engine := control.Register(servicename, &ctrl.Options[*zero.Ctx]{
|
||||
engine := control.Register("epidemic", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "城市疫情查询\n" +
|
||||
"- xxx疫情\n",
|
||||
Brief: "城市疫情查询",
|
||||
Help: "- xxx疫情\n",
|
||||
})
|
||||
engine.OnSuffix("疫情").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
@@ -17,10 +17,10 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("event", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "好友申请以及群聊邀请事件处理,默认发送给主人列表第一位\n" +
|
||||
"- [开启|关闭]自动同意[申请|邀请|主人]\n" +
|
||||
Brief: "好友申请和群聊邀请事件处理",
|
||||
Help: "- [开启|关闭]自动同意[申请|邀请|主人]\n" +
|
||||
"- [同意|拒绝][申请|邀请][flag]\n" +
|
||||
"flag跟随事件一起发送, 默认同意主人的事件",
|
||||
"Tips: 信息默认发送给主人列表第一位, 默认同意所有主人的事件, flag跟随事件一起发送",
|
||||
})
|
||||
engine.On("request/group/invite").SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
func init() {
|
||||
control.Register("font", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "渲染任意文字到图片\n- (用[终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体])渲染文字xxx",
|
||||
Brief: "渲染任意文字到图片",
|
||||
Help: "- (用[字体])渲染文字xxx\n可选字体: [终末体|终末变体|紫罗兰体|樱酥体|Consolas体|苹方体]",
|
||||
}).OnRegex(`^(用.+)?渲染文字([\s\S]+)$`).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
fnt := ctx.State["regex_matched"].([]string)[1]
|
||||
txt := ctx.State["regex_matched"].([]string)[2]
|
||||
|
||||
@@ -51,8 +51,8 @@ func init() {
|
||||
// 插件主体
|
||||
en := control.Register("fortune", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "每日运势: \n" +
|
||||
"- 运势 | 抽签\n" +
|
||||
Brief: "每日运势",
|
||||
Help: "- 运势 | 抽签\n" +
|
||||
"- 设置底图[车万 | DC4 | 爱因斯坦 | 星空列车 | 樱云之恋 | 富婆妹 | 李清歌 | 公主连结 | 原神 | 明日方舟 | 碧蓝航线 | 碧蓝幻想 | 战双 | 阴阳师 | 赛马娘 | 东方归言录 | 奇异恩典 | 夏日口袋 | ASoul]",
|
||||
PublicDataFolder: "Fortune",
|
||||
})
|
||||
|
||||
@@ -26,8 +26,8 @@ var db = &sql.Sqlite{}
|
||||
func init() {
|
||||
en := control.Register("funny", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "讲个笑话\n" +
|
||||
"- 讲个笑话[@xxx|qq号|人名] | 夸夸[@xxx|qq号|人名] ",
|
||||
Brief: "讲个笑话",
|
||||
Help: "- 讲个笑话[@xxx|qq号|人名] | 夸夸[@xxx|qq号|人名] ",
|
||||
PublicDataFolder: "Funny",
|
||||
})
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("genshin", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "原神抽卡\n- 原神十连\n- 切换原神卡池",
|
||||
Brief: "原神模拟抽卡",
|
||||
Help: "- 原神十连\n- 切换原神卡池",
|
||||
PublicDataFolder: "Genshin",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ func init() { // 插件主体
|
||||
}
|
||||
en := control.Register("gif", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "GIF制图,命令后艾特群友/QQ号/一张图方可触发命令\n其中XXX可以为任何文字,可以不写\n对机器人操作请先艾特机器人再执行命令\n" +
|
||||
Brief: "制图",
|
||||
Help: "下为制图命令: " +
|
||||
"- 搓|-冲|-摸|-拍|-丢|-吃|-敲|-啃|-蹭|-爬|-撕|-灰度|-上翻|-下翻\n" +
|
||||
"- 左翻|-右翻|-反色|-浮雕|- 打码|- 负片|- 旋转|- 变形|- 亲\n" +
|
||||
"- 结婚申请|结婚登记|- 阿尼亚喜欢XXX|- 像只|- 我永远喜欢XXX\n" +
|
||||
@@ -141,7 +142,10 @@ func init() { // 插件主体
|
||||
"- 抬棺|- 远离|- 我老婆|- 小天使XXX|- 你的XXX|- 不要看\n" +
|
||||
"- 玩一下XXX|- 给我变|- 揍|- 吞|- 膜拜|- 诶嘿|- 2蹭|- 你犯法了\n" +
|
||||
"- 砰|- 注意力涣散|- 蒙蔽|- 踩|- 好玩|- 2转|- 踢球|- 2舔|\n" +
|
||||
"- 可莉吃|- 胡桃啃|- 怀|- 一直(支持动图)",
|
||||
"- 可莉吃|- 胡桃啃|- 怀|- 一直(支持动图)\n" +
|
||||
"例: 制图命令XXX[@用户|QQ号|图片]" +
|
||||
"Tips: XXX可以为限制长度的任何文字\n" +
|
||||
"对Bot使用为 @Bot制图命令[XXX]@Bot",
|
||||
PrivateDataFolder: "gif",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
datapath = file.BOTPATH + "/" + en.DataFolder()
|
||||
|
||||
@@ -20,8 +20,8 @@ import (
|
||||
func init() { // 插件主体
|
||||
control.Register("github", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "GitHub仓库搜索\n" +
|
||||
"- >github [xxx]\n" +
|
||||
Brief: "GitHub仓库搜索",
|
||||
Help: "- >github [xxx]\n" +
|
||||
"- >github -p [xxx]",
|
||||
}).OnRegex(`^>github\s(-.{1,10}? )?(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,406 +1,43 @@
|
||||
package guessmusic
|
||||
|
||||
type listRaw struct {
|
||||
Name string `json:"name"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// config内容
|
||||
type config struct {
|
||||
MusicPath string `json:"musicPath"`
|
||||
Local bool `json:"local"`
|
||||
API bool `json:"api"`
|
||||
Cookie string `json:"cookie"`
|
||||
Playlist []listRaw `json:"playlist"`
|
||||
MusicPath string `json:"musicPath"`
|
||||
Local bool `json:"local"`
|
||||
API bool `json:"api"`
|
||||
Cookie string `json:"cookie"`
|
||||
Playlist []listRaw `json:"playlist"`
|
||||
Defaultlist []dlist `json:"defaultlist"`
|
||||
}
|
||||
|
||||
type keyInfo struct {
|
||||
Data struct {
|
||||
Code int `json:"code"`
|
||||
Unikey string `json:"unikey"`
|
||||
} `json:"data"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
type cookyInfo struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Cookie string `json:"cookie"`
|
||||
}
|
||||
type qrInfo struct {
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Qrurl string `json:"qrurl"`
|
||||
Qrimg string `json:"qrimg"`
|
||||
} `json:"data"`
|
||||
}
|
||||
type topList struct {
|
||||
Code int `json:"code"`
|
||||
RelatedVideos interface{} `json:"relatedVideos"`
|
||||
Playlist struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CoverImgID int64 `json:"coverImgId"`
|
||||
CoverImgURL string `json:"coverImgUrl"`
|
||||
CoverImgIDStr string `json:"coverImgId_str"`
|
||||
AdType int `json:"adType"`
|
||||
UserID int `json:"userId"`
|
||||
CreateTime int64 `json:"createTime"`
|
||||
Status int `json:"status"`
|
||||
OpRecommend bool `json:"opRecommend"`
|
||||
HighQuality bool `json:"highQuality"`
|
||||
NewImported bool `json:"newImported"`
|
||||
UpdateTime int64 `json:"updateTime"`
|
||||
TrackCount int `json:"trackCount"`
|
||||
SpecialType int `json:"specialType"`
|
||||
Privacy int `json:"privacy"`
|
||||
TrackUpdateTime int64 `json:"trackUpdateTime"`
|
||||
CommentThreadID string `json:"commentThreadId"`
|
||||
PlayCount int `json:"playCount"`
|
||||
TrackNumberUpdateTime int64 `json:"trackNumberUpdateTime"`
|
||||
SubscribedCount int `json:"subscribedCount"`
|
||||
CloudTrackCount int `json:"cloudTrackCount"`
|
||||
Ordered bool `json:"ordered"`
|
||||
Description string `json:"description"`
|
||||
Tags []string `json:"tags"`
|
||||
UpdateFrequency interface{} `json:"updateFrequency"`
|
||||
BackgroundCoverID int `json:"backgroundCoverId"`
|
||||
BackgroundCoverURL interface{} `json:"backgroundCoverUrl"`
|
||||
TitleImage int `json:"titleImage"`
|
||||
TitleImageURL interface{} `json:"titleImageUrl"`
|
||||
EnglishTitle interface{} `json:"englishTitle"`
|
||||
OfficialPlaylistType interface{} `json:"officialPlaylistType"`
|
||||
Subscribers []struct {
|
||||
DefaultAvatar bool `json:"defaultAvatar"`
|
||||
Province int `json:"province"`
|
||||
AuthStatus int `json:"authStatus"`
|
||||
Followed bool `json:"followed"`
|
||||
AvatarURL string `json:"avatarUrl"`
|
||||
AccountStatus int `json:"accountStatus"`
|
||||
Gender int `json:"gender"`
|
||||
City int `json:"city"`
|
||||
Birthday int `json:"birthday"`
|
||||
UserID int `json:"userId"`
|
||||
UserType int `json:"userType"`
|
||||
Nickname string `json:"nickname"`
|
||||
Signature string `json:"signature"`
|
||||
Description string `json:"description"`
|
||||
DetailDescription string `json:"detailDescription"`
|
||||
AvatarImgID int64 `json:"avatarImgId"`
|
||||
BackgroundImgID int64 `json:"backgroundImgId"`
|
||||
BackgroundURL string `json:"backgroundUrl"`
|
||||
Authority int `json:"authority"`
|
||||
Mutual bool `json:"mutual"`
|
||||
ExpertTags interface{} `json:"expertTags"`
|
||||
Experts interface{} `json:"experts"`
|
||||
DjStatus int `json:"djStatus"`
|
||||
VipType int `json:"vipType"`
|
||||
RemarkName interface{} `json:"remarkName"`
|
||||
AuthenticationTypes int `json:"authenticationTypes"`
|
||||
AvatarDetail interface{} `json:"avatarDetail"`
|
||||
Anchor bool `json:"anchor"`
|
||||
BackgroundImgIDStr string `json:"backgroundImgIdStr"`
|
||||
AvatarImgIDStr string `json:"avatarImgIdStr"`
|
||||
AvatarImgIDString string `json:"AvatarImgIDString"`
|
||||
} `json:"subscribers"`
|
||||
Subscribed interface{} `json:"subscribed"`
|
||||
Creator struct {
|
||||
DefaultAvatar bool `json:"defaultAvatar"`
|
||||
Province int `json:"province"`
|
||||
AuthStatus int `json:"authStatus"`
|
||||
Followed bool `json:"followed"`
|
||||
AvatarURL string `json:"avatarUrl"`
|
||||
AccountStatus int `json:"accountStatus"`
|
||||
Gender int `json:"gender"`
|
||||
City int `json:"city"`
|
||||
Birthday int `json:"birthday"`
|
||||
UserID int `json:"userId"`
|
||||
UserType int `json:"userType"`
|
||||
Nickname string `json:"nickname"`
|
||||
Signature string `json:"signature"`
|
||||
Description string `json:"description"`
|
||||
DetailDescription string `json:"detailDescription"`
|
||||
AvatarImgID int64 `json:"avatarImgId"`
|
||||
BackgroundImgID int64 `json:"backgroundImgId"`
|
||||
BackgroundURL string `json:"backgroundUrl"`
|
||||
Authority int `json:"authority"`
|
||||
Mutual bool `json:"mutual"`
|
||||
ExpertTags interface{} `json:"expertTags"`
|
||||
Experts interface{} `json:"experts"`
|
||||
DjStatus int `json:"djStatus"`
|
||||
VipType int `json:"vipType"`
|
||||
RemarkName interface{} `json:"remarkName"`
|
||||
AuthenticationTypes int `json:"authenticationTypes"`
|
||||
AvatarDetail struct {
|
||||
UserType int `json:"userType"`
|
||||
IdentityLevel int `json:"identityLevel"`
|
||||
IdentityIconURL string `json:"identityIconUrl"`
|
||||
} `json:"avatarDetail"`
|
||||
Anchor bool `json:"anchor"`
|
||||
BackgroundImgIDStr string `json:"backgroundImgIdStr"`
|
||||
AvatarImgIDStr string `json:"avatarImgIdStr"`
|
||||
AvatarImgIDString string `json:"AvatarImgIDString"`
|
||||
} `json:"creator"`
|
||||
Tracks []struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"id"`
|
||||
Pst int `json:"pst"`
|
||||
T int `json:"t"`
|
||||
Ar []struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Tns []interface{} `json:"tns"`
|
||||
Alias []interface{} `json:"alias"`
|
||||
} `json:"ar"`
|
||||
Alia []string `json:"alia"`
|
||||
Pop int `json:"pop"`
|
||||
St int `json:"st"`
|
||||
Rt string `json:"rt"`
|
||||
Fee int `json:"fee"`
|
||||
V int `json:"v"`
|
||||
Crbt interface{} `json:"crbt"`
|
||||
Cf string `json:"cf"`
|
||||
Al struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PicURL string `json:"picUrl"`
|
||||
Tns []interface{} `json:"tns"`
|
||||
PicStr string `json:"pic_str"`
|
||||
Pic int64 `json:"pic"`
|
||||
} `json:"al"`
|
||||
Dt int `json:"dt"`
|
||||
H struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float64 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"h"`
|
||||
M struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float64 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"m"`
|
||||
L struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float64 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"l"`
|
||||
Sq interface{} `json:"sq"`
|
||||
Hr interface{} `json:"hr"`
|
||||
A interface{} `json:"a"`
|
||||
Cd string `json:"cd"`
|
||||
No int `json:"no"`
|
||||
RtURL interface{} `json:"rtUrl"`
|
||||
Ftype int `json:"ftype"`
|
||||
RtUrls []interface{} `json:"rtUrls"`
|
||||
DjID int `json:"djId"`
|
||||
Copyright int `json:"copyright"`
|
||||
SID int `json:"s_id"`
|
||||
Mark int `json:"mark"`
|
||||
OriginCoverType int `json:"originCoverType"`
|
||||
OriginSongSimpleData interface{} `json:"originSongSimpleData"`
|
||||
TagPicList interface{} `json:"tagPicList"`
|
||||
ResourceState bool `json:"resourceState"`
|
||||
Version int `json:"version"`
|
||||
SongJumpInfo interface{} `json:"songJumpInfo"`
|
||||
EntertainmentTags interface{} `json:"entertainmentTags"`
|
||||
Single int `json:"single"`
|
||||
NoCopyrightRcmd interface{} `json:"noCopyrightRcmd"`
|
||||
Alg interface{} `json:"alg"`
|
||||
Rtype int `json:"rtype"`
|
||||
Rurl interface{} `json:"rurl"`
|
||||
Mst int `json:"mst"`
|
||||
Cp int `json:"cp"`
|
||||
Mv int `json:"mv"`
|
||||
PublishTime int64 `json:"publishTime"`
|
||||
Tns []string `json:"tns,omitempty"`
|
||||
} `json:"tracks"`
|
||||
VideoIds interface{} `json:"videoIds"`
|
||||
Videos interface{} `json:"videos"`
|
||||
TrackIds []struct {
|
||||
ID int `json:"id"`
|
||||
V int `json:"v"`
|
||||
T int `json:"t"`
|
||||
At int64 `json:"at"`
|
||||
Alg interface{} `json:"alg"`
|
||||
UID int `json:"uid"`
|
||||
RcmdReason string `json:"rcmdReason"`
|
||||
Sc interface{} `json:"sc"`
|
||||
Lr int `json:"lr,omitempty"`
|
||||
} `json:"trackIds"`
|
||||
ShareCount int `json:"shareCount"`
|
||||
CommentCount int `json:"commentCount"`
|
||||
RemixVideo interface{} `json:"remixVideo"`
|
||||
SharedUsers interface{} `json:"sharedUsers"`
|
||||
HistorySharedUsers interface{} `json:"historySharedUsers"`
|
||||
GradeStatus string `json:"gradeStatus"`
|
||||
Score interface{} `json:"score"`
|
||||
AlgTags interface{} `json:"algTags"`
|
||||
} `json:"playlist"`
|
||||
Urls interface{} `json:"urls"`
|
||||
Privileges []struct {
|
||||
ID int `json:"id"`
|
||||
Fee int `json:"fee"`
|
||||
Payed int `json:"payed"`
|
||||
RealPayed int `json:"realPayed"`
|
||||
St int `json:"st"`
|
||||
Pl int `json:"pl"`
|
||||
Dl int `json:"dl"`
|
||||
Sp int `json:"sp"`
|
||||
Cp int `json:"cp"`
|
||||
Subp int `json:"subp"`
|
||||
Cs bool `json:"cs"`
|
||||
Maxbr int `json:"maxbr"`
|
||||
Fl int `json:"fl"`
|
||||
Pc interface{} `json:"pc"`
|
||||
Toast bool `json:"toast"`
|
||||
Flag int `json:"flag"`
|
||||
PaidBigBang bool `json:"paidBigBang"`
|
||||
PreSell bool `json:"preSell"`
|
||||
PlayMaxbr int `json:"playMaxbr"`
|
||||
DownloadMaxbr int `json:"downloadMaxbr"`
|
||||
MaxBrLevel string `json:"maxBrLevel"`
|
||||
PlayMaxBrLevel string `json:"playMaxBrLevel"`
|
||||
DownloadMaxBrLevel string `json:"downloadMaxBrLevel"`
|
||||
PlLevel string `json:"plLevel"`
|
||||
DlLevel string `json:"dlLevel"`
|
||||
FlLevel string `json:"flLevel"`
|
||||
Rscl int `json:"rscl"`
|
||||
FreeTrialPrivilege struct {
|
||||
ResConsumable bool `json:"resConsumable"`
|
||||
UserConsumable bool `json:"userConsumable"`
|
||||
ListenType interface{} `json:"listenType"`
|
||||
} `json:"freeTrialPrivilege"`
|
||||
ChargeInfoList []struct {
|
||||
Rate int `json:"rate"`
|
||||
ChargeURL interface{} `json:"chargeUrl"`
|
||||
ChargeMessage interface{} `json:"chargeMessage"`
|
||||
ChargeType int `json:"chargeType"`
|
||||
} `json:"chargeInfoList"`
|
||||
} `json:"privileges"`
|
||||
SharedPrivilege interface{} `json:"sharedPrivilege"`
|
||||
ResEntrance interface{} `json:"resEntrance"`
|
||||
// 记录歌单绑定的网易云歌单ID
|
||||
type listRaw struct {
|
||||
Name string `json:"name"` // 歌单名称
|
||||
ID int64 `json:"id"` // 歌单绑定的网易云ID
|
||||
}
|
||||
|
||||
type topMusicInfo struct {
|
||||
Songs []struct {
|
||||
Name string `json:"name"`
|
||||
ID int `json:"id"`
|
||||
Pst int `json:"pst"`
|
||||
T int `json:"t"`
|
||||
Ar []struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Tns []interface{} `json:"tns"`
|
||||
Alias []interface{} `json:"alias"`
|
||||
} `json:"ar"`
|
||||
Alia []string `json:"alia"`
|
||||
Pop int `json:"pop"`
|
||||
St int `json:"st"`
|
||||
Rt string `json:"rt"`
|
||||
Fee int `json:"fee"`
|
||||
V int `json:"v"`
|
||||
Crbt interface{} `json:"crbt"`
|
||||
Cf string `json:"cf"`
|
||||
Al struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PicURL string `json:"picUrl"`
|
||||
Tns []interface{} `json:"tns"`
|
||||
PicStr string `json:"pic_str"`
|
||||
Pic int64 `json:"pic"`
|
||||
} `json:"al"`
|
||||
Dt int `json:"dt"`
|
||||
H struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float32 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"h"`
|
||||
M struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float32 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"m"`
|
||||
L struct {
|
||||
Br int `json:"br"`
|
||||
Fid int `json:"fid"`
|
||||
Size int `json:"size"`
|
||||
Vd float32 `json:"vd"`
|
||||
Sr int `json:"sr"`
|
||||
} `json:"l"`
|
||||
Sq interface{} `json:"sq"`
|
||||
Hr interface{} `json:"hr"`
|
||||
A interface{} `json:"a"`
|
||||
Cd string `json:"cd"`
|
||||
No int `json:"no"`
|
||||
RtURL interface{} `json:"rtUrl"`
|
||||
Ftype int `json:"ftype"`
|
||||
RtUrls []interface{} `json:"rtUrls"`
|
||||
DjID int `json:"djId"`
|
||||
Copyright int `json:"copyright"`
|
||||
SID int `json:"s_id"`
|
||||
Mark int `json:"mark"`
|
||||
OriginCoverType int `json:"originCoverType"`
|
||||
OriginSongSimpleData interface{} `json:"originSongSimpleData"`
|
||||
TagPicList interface{} `json:"tagPicList"`
|
||||
ResourceState bool `json:"resourceState"`
|
||||
Version int `json:"version"`
|
||||
SongJumpInfo interface{} `json:"songJumpInfo"`
|
||||
EntertainmentTags interface{} `json:"entertainmentTags"`
|
||||
AwardTags interface{} `json:"awardTags"`
|
||||
Single int `json:"single"`
|
||||
NoCopyrightRcmd interface{} `json:"noCopyrightRcmd"`
|
||||
Rtype int `json:"rtype"`
|
||||
Rurl interface{} `json:"rurl"`
|
||||
Mst int `json:"mst"`
|
||||
Cp int `json:"cp"`
|
||||
Mv int `json:"mv"`
|
||||
PublishTime int64 `json:"publishTime"`
|
||||
Tns []string `json:"tns,omitempty"`
|
||||
} `json:"songs"`
|
||||
Privileges []struct {
|
||||
ID int `json:"id"`
|
||||
Fee int `json:"fee"`
|
||||
Payed int `json:"payed"`
|
||||
St int `json:"st"`
|
||||
Pl int `json:"pl"`
|
||||
Dl int `json:"dl"`
|
||||
Sp int `json:"sp"`
|
||||
Cp int `json:"cp"`
|
||||
Subp int `json:"subp"`
|
||||
Cs bool `json:"cs"`
|
||||
Maxbr int `json:"maxbr"`
|
||||
Fl int `json:"fl"`
|
||||
Toast bool `json:"toast"`
|
||||
Flag int `json:"flag"`
|
||||
PreSell bool `json:"preSell"`
|
||||
PlayMaxbr int `json:"playMaxbr"`
|
||||
DownloadMaxbr int `json:"downloadMaxbr"`
|
||||
MaxBrLevel string `json:"maxBrLevel"`
|
||||
PlayMaxBrLevel string `json:"playMaxBrLevel"`
|
||||
DownloadMaxBrLevel string `json:"downloadMaxBrLevel"`
|
||||
PlLevel string `json:"plLevel"`
|
||||
DlLevel string `json:"dlLevel"`
|
||||
FlLevel string `json:"flLevel"`
|
||||
Rscl int `json:"rscl"`
|
||||
FreeTrialPrivilege struct {
|
||||
ResConsumable bool `json:"resConsumable"`
|
||||
UserConsumable bool `json:"userConsumable"`
|
||||
ListenType interface{} `json:"listenType"`
|
||||
} `json:"freeTrialPrivilege"`
|
||||
ChargeInfoList []struct {
|
||||
Rate int `json:"rate"`
|
||||
ChargeURL interface{} `json:"chargeUrl"`
|
||||
ChargeMessage interface{} `json:"chargeMessage"`
|
||||
ChargeType int `json:"chargeType"`
|
||||
} `json:"chargeInfoList"`
|
||||
} `json:"privileges"`
|
||||
Code int `json:"code"`
|
||||
// 记录群默认猜歌
|
||||
type dlist struct {
|
||||
GroupID int64 `json:"gid"` // 群号
|
||||
Name string `json:"name"` // 歌单名称
|
||||
}
|
||||
|
||||
// 本地歌单列表信息
|
||||
type listinfo struct {
|
||||
Name string `json:"name"` // 歌单名称
|
||||
Number int // 歌曲数量
|
||||
ID int64 // 歌单绑定的歌曲ID
|
||||
}
|
||||
|
||||
// 独角兽API随机抽歌信息
|
||||
type ovooaData struct {
|
||||
Code int `json:"code"`
|
||||
Text string `json:"text"`
|
||||
Data struct {
|
||||
Song string `json:"song"`
|
||||
Singer string `json:"singer"`
|
||||
Cover string `json:"cover"`
|
||||
Music string `json:"Music"`
|
||||
ID int `json:"id"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
88
plugin/heisi/heisi.go
Normal file
88
plugin/heisi/heisi.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Package heisi 黑丝
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
fbctxext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
heisiPic []item
|
||||
baisiPic []item
|
||||
jkPic []item
|
||||
jurPic []item
|
||||
zukPic []item
|
||||
mcnPic []item
|
||||
fileList = [...]string{"heisi.bin", "baisi.bin", "jk.bin", "jur.bin", "zuk.bin", "mcn.bin"}
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("heisi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "黑丝",
|
||||
Help: "- 来点黑丝\n- 来点白丝\n- 来点jk\n- 来点巨乳\n- 来点足控\n- 来点网红",
|
||||
PublicDataFolder: "Heisi",
|
||||
})
|
||||
|
||||
engine.OnFullMatchGroup([]string{"来点黑丝", "来点白丝", "来点jk", "来点巨乳", "来点足控", "来点网红"}, zero.OnlyGroup, fbctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
for i, filePath := range fileList {
|
||||
data, err := engine.GetLazyData(filePath, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
if len(data)%10 != 0 {
|
||||
ctx.SendChain(message.Text("ERROR: invalid data " + strconv.Itoa(i)))
|
||||
return false
|
||||
}
|
||||
s := (*slice)(unsafe.Pointer(&data))
|
||||
s.len /= 10
|
||||
s.cap /= 10
|
||||
switch i {
|
||||
case 0:
|
||||
heisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 1:
|
||||
baisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 2:
|
||||
jkPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 3:
|
||||
jurPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 4:
|
||||
zukPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 5:
|
||||
mcnPic = *(*[]item)(unsafe.Pointer(s))
|
||||
}
|
||||
}
|
||||
return true
|
||||
})).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
var pic item
|
||||
switch matched {
|
||||
case "来点黑丝":
|
||||
pic = heisiPic[rand.Intn(len(heisiPic))]
|
||||
case "来点白丝":
|
||||
pic = baisiPic[rand.Intn(len(baisiPic))]
|
||||
case "来点jk":
|
||||
pic = jkPic[rand.Intn(len(jkPic))]
|
||||
case "来点巨乳":
|
||||
pic = jurPic[rand.Intn(len(jurPic))]
|
||||
case "来点足控":
|
||||
pic = zukPic[rand.Intn(len(zukPic))]
|
||||
case "来点网红":
|
||||
pic = mcnPic[rand.Intn(len(mcnPic))]
|
||||
}
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image(pic.String()))}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
}
|
||||
48
plugin/heisi/packer.go
Normal file
48
plugin/heisi/packer.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
template2021 = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%4d%02d16%06d-611a3%8s.jpg"
|
||||
templategeneral = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%015x"
|
||||
)
|
||||
|
||||
type item [10]byte
|
||||
|
||||
// String item to url
|
||||
func (it item) String() string {
|
||||
year, month := int((it[0]>>4)&0x0f), int(it[0]&0x0f)
|
||||
year += 2021
|
||||
if year == 2021 {
|
||||
num := binary.BigEndian.Uint32(it[1:5])
|
||||
dstr := hex.EncodeToString(it[5:9])
|
||||
return fmt.Sprintf(template2021, year, month, year, month, num, dstr)
|
||||
}
|
||||
d := binary.BigEndian.Uint64(it[1:9])
|
||||
isscaled := it[9]&0x80 > 0
|
||||
num := int(it[9] & 0x7f)
|
||||
trestore := fmt.Sprintf(templategeneral, year, month, d&0x0fffffff_ffffffff)
|
||||
if num > 0 {
|
||||
trestore += fmt.Sprintf("-%d", num)
|
||||
}
|
||||
if isscaled {
|
||||
trestore += "-scaled"
|
||||
}
|
||||
d = bits.RotateLeft64(d, 4) & 0x0f
|
||||
switch d {
|
||||
case 0:
|
||||
trestore += ".jpg"
|
||||
case 1:
|
||||
trestore += ".png"
|
||||
case 2:
|
||||
trestore += ".webp"
|
||||
default:
|
||||
return "invalid ext"
|
||||
}
|
||||
return trestore
|
||||
}
|
||||
15
plugin/heisi/slice.go
Normal file
15
plugin/heisi/slice.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package heisi
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type slice struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
@@ -43,8 +43,8 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("hs", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "炉石\n" +
|
||||
"- 搜卡[xxxx]\n" +
|
||||
Brief: "炉石搜卡",
|
||||
Help: "- 搜卡[xxxx]\n" +
|
||||
"- [卡组代码xxx]\n" +
|
||||
"- 更多搜卡指令参数:https://hs.fbigame.com/misc/searchhelp",
|
||||
PrivateDataFolder: "hs",
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
const bed = "https://gitcode.net/u011570312/OguraHyakuninIsshu/-/raw/master/"
|
||||
|
||||
//nolint: asciicheck
|
||||
// nolint: asciicheck
|
||||
type line struct {
|
||||
番号, 歌人, 上の句, 下の句, 上の句ひらがな, 下の句ひらがな string
|
||||
}
|
||||
@@ -56,8 +56,8 @@ var lines [100]*line
|
||||
func init() {
|
||||
engine := control.Register("hyaku", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "百人一首\n" +
|
||||
"- 百人一首(随机发一首)\n" +
|
||||
Brief: "百人一首",
|
||||
Help: "- 百人一首(随机发一首)\n" +
|
||||
"- 百人一首之n",
|
||||
PrivateDataFolder: "hyaku",
|
||||
})
|
||||
|
||||
@@ -64,8 +64,8 @@ var hrefre = regexp.MustCompile(`<a href=".*">`)
|
||||
func init() {
|
||||
control.Register("imgfinder", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "关键字搜图\n" +
|
||||
"- 来张 [xxx]",
|
||||
Brief: "关键字搜图",
|
||||
Help: "- 来张 [xxx]",
|
||||
}).OnRegex(`^来张\s?(.*)$`, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("inject", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "注入指令\n" +
|
||||
"- run[CQ码]",
|
||||
Brief: "注入指令",
|
||||
Help: "- run[CQ码]",
|
||||
})
|
||||
// 运行 CQ 码
|
||||
en.OnPrefix("run", zero.SuperUserPermission).SetBlock(true).
|
||||
|
||||
@@ -25,7 +25,8 @@ const (
|
||||
func init() {
|
||||
engine := control.Register("jandan", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "煎蛋网无聊图\n- 来份[屌|弔|吊]图\n- 更新[屌|弔|吊]图\n",
|
||||
Brief: "煎蛋网无聊图",
|
||||
Help: "- 来份[屌|弔|吊]图\n- 更新[屌|弔|吊]图\n",
|
||||
PublicDataFolder: "Jandan",
|
||||
})
|
||||
|
||||
|
||||
65
plugin/jiami/jiami.go
Normal file
65
plugin/jiami/jiami.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Package jiami 兽语加密与解密
|
||||
package jiami
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
jiami1 = "http://ovooa.com/API/sho_u/?msg=%v" // 加密api地址
|
||||
jiami2 = "http://ovooa.com/API/sho_u/?format=1&msg=%v" // 解密api地址
|
||||
|
||||
)
|
||||
|
||||
type nmd struct { // struct解析格式大概是
|
||||
Data struct {
|
||||
Message string
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.Register("jiami", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "兽语加解密",
|
||||
Help: "兽语加解密\n" +
|
||||
"- 兽语加密xxx\n- 兽语解密xxx",
|
||||
})
|
||||
en.OnRegex(`^兽语加密\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es, err := web.GetData(fmt.Sprintf(jiami1, str)) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var r nmd // r数组
|
||||
err = json.Unmarshal(es, &r) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(r.Data.Message)) // 输出提取后的结果
|
||||
})
|
||||
|
||||
en.OnRegex(`^兽语解密\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
str := ctx.State["regex_matched"].([]string)[1]
|
||||
es, err := web.GetData(fmt.Sprintf(jiami2, str)) // 将网站返回结果赋值
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var n nmd // r数组
|
||||
err = json.Unmarshal(es, &n) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(n.Data.Message)) // 输出提取后的结果
|
||||
})
|
||||
}
|
||||
@@ -32,12 +32,11 @@ type value struct {
|
||||
|
||||
func init() {
|
||||
// 初始化engine
|
||||
engine := control.Register(
|
||||
"jikipedia",
|
||||
&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "小鸡词典\n -[查梗|小鸡词典][梗]",
|
||||
},
|
||||
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) {
|
||||
|
||||
105
plugin/jptingroom/jptingroom.go
Normal file
105
plugin/jptingroom/jptingroom.go
Normal file
@@ -0,0 +1,105 @@
|
||||
// Package jptingroom 日语听力学习材料
|
||||
package jptingroom
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("jptingroom", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "日语听力学习材料",
|
||||
Help: "- 随机日语听力\n" +
|
||||
"- 随机日语歌曲\n" +
|
||||
"- 日语听力 xxx\n" +
|
||||
"- 日语歌曲 xxx\n",
|
||||
PublicDataFolder: "Jptingroom",
|
||||
})
|
||||
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "item.db"
|
||||
_, err := engine.GetLazyData("item.db", true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
err = db.Create("item", &item{})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
n, err := db.Count("item")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
log.Infof("[jptingroom]读取%d条日语听力材料", n)
|
||||
return true
|
||||
})
|
||||
// 开启
|
||||
engine.OnFullMatchGroup([]string{"随机日语听力", "随机日语歌曲"}, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
var t item
|
||||
switch matched {
|
||||
case "随机日语听力":
|
||||
t = getRandomAudioByCategory("tingli")
|
||||
case "随机日语歌曲":
|
||||
t = getRandomAudioByCategory("gequ")
|
||||
default:
|
||||
}
|
||||
if t.AudioURL == "" {
|
||||
ctx.SendChain(message.Text("未能找到相关材料"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Record(t.AudioURL))
|
||||
content := t.Title + "\n\n" + t.Content
|
||||
data, err := text.RenderToBase64(content, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`日语(听力|歌曲)\s?([一-龥A-Za-z0-9ぁ-んァ-ヶ]{1,50})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
var t item
|
||||
switch regexMatched[1] {
|
||||
case "听力":
|
||||
t = getRandomAudioByCategoryAndKeyword("tingli", regexMatched[2])
|
||||
case "歌曲":
|
||||
t = getRandomAudioByCategoryAndKeyword("gequ", regexMatched[2])
|
||||
default:
|
||||
}
|
||||
if t.AudioURL == "" {
|
||||
ctx.SendChain(message.Text("未能找到相关材料"))
|
||||
return
|
||||
}
|
||||
content := t.Title + "\n\n" + t.Content
|
||||
data, err := text.RenderToBase64(content, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
30
plugin/jptingroom/model.go
Normal file
30
plugin/jptingroom/model.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package jptingroom
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
)
|
||||
|
||||
type item struct {
|
||||
ID int64 `db:"id"`
|
||||
Title string `db:"title"`
|
||||
PageURL string `db:"page_url"`
|
||||
Category string `db:"category"`
|
||||
Intro string `db:"intro"`
|
||||
AudioURL string `db:"audio_url"`
|
||||
Content string `db:"content"`
|
||||
Datetime time.Time `db:"datetime"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
|
||||
func getRandomAudioByCategory(category string) (t item) {
|
||||
_ = db.Find("item", &t, "where category = '"+category+"' ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
func getRandomAudioByCategoryAndKeyword(category string, keyword string) (t item) {
|
||||
_ = db.Find("item", &t, "where category = '"+category+"' and (title like '%"+keyword+"%' or content like '%"+keyword+"%') ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
@@ -25,8 +25,8 @@ const (
|
||||
func init() {
|
||||
control.Register("juejuezi", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "绝绝子生成器\n" +
|
||||
"- 喝奶茶绝绝子 | 绝绝子吃饭",
|
||||
Brief: "绝绝子生成器",
|
||||
Help: "例: 喝奶茶绝绝子\n绝绝子吃饭",
|
||||
}).OnRegex("[\u4E00-\u9FA5]{0,10}绝绝子[\u4E00-\u9FA5]{0,10}").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
toDealStr := []rune(strings.ReplaceAll(ctx.ExtractPlainText(), "绝绝子", ""))
|
||||
switch len(toDealStr) {
|
||||
|
||||
@@ -34,8 +34,8 @@ var (
|
||||
func init() {
|
||||
en := control.Register("lolicon", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "lolicon\n" +
|
||||
"- 随机图片\n" +
|
||||
Brief: "随机图片",
|
||||
Help: "- 随机图片\n" +
|
||||
"- 随机图片 萝莉|少女\n" +
|
||||
"- 设置随机图片地址[http...]",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
|
||||
91
plugin/magicprompt/magicprompt.go
Normal file
91
plugin/magicprompt/magicprompt.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package magicprompt MagicPrompt-Stable-Diffusion吟唱提示
|
||||
package magicprompt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
hf "github.com/FloatTech/AnimeAPI/huggingface"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/RomiChan/websocket"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
magicpromptRepo = "Gustavosta/MagicPrompt-Stable-Diffusion"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("magicprompt", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "MagicPrompt-Stable-Diffusion吟唱提示",
|
||||
Help: "- 吟唱提示 xxx",
|
||||
PrivateDataFolder: "magicprompt",
|
||||
})
|
||||
|
||||
// 开启
|
||||
engine.OnPrefixGroup([]string{`吟唱提示`, "吟唱补全"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
_ctx, _cancel := context.WithTimeout(context.Background(), hf.TimeoutMax*time.Second)
|
||||
defer _cancel()
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
|
||||
magicpromptURL := fmt.Sprintf(hf.WssJoinPath, magicpromptRepo)
|
||||
args := ctx.State["args"].(string)
|
||||
c, _, err := websocket.DefaultDialer.Dial(magicpromptURL, nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
r := hf.PushRequest{
|
||||
FnIndex: 0,
|
||||
Data: []interface{}{args},
|
||||
}
|
||||
b, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = c.WriteMessage(websocket.TextMessage, b)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
t := time.NewTicker(time.Second * 1)
|
||||
defer t.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
_, data, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("msg").String() == hf.WssCompleteStatus {
|
||||
m := message.Message{}
|
||||
for _, v := range strings.Split(j.Get("output.data.0").String(), "\n\n") {
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(v)))
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-_ctx.Done():
|
||||
ctx.SendChain(message.Text("ERROR: 吟唱提示指令超时"))
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -47,11 +47,15 @@ const (
|
||||
"- 取消在\"cron\"的提醒\n" +
|
||||
"- 列出所有提醒\n" +
|
||||
"- 翻牌\n" +
|
||||
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}] {at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名\n" +
|
||||
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" +
|
||||
"- 测试欢迎语\n" +
|
||||
"- 设置告别辞 参数同设置欢迎语\n" +
|
||||
"- 测试告别辞\n" +
|
||||
"- [开启 | 关闭]入群验证"
|
||||
"- [开启 | 关闭]入群验证\n" +
|
||||
"- 对信息回复:[设置 | 取消]精华\n" +
|
||||
"- 取消精华 [信息ID]\n" +
|
||||
"- /精华列表\n" +
|
||||
"Tips: {at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -62,6 +66,7 @@ var (
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("manager", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "群管插件",
|
||||
Help: hint,
|
||||
PrivateDataFolder: "manager",
|
||||
})
|
||||
@@ -577,6 +582,72 @@ func init() { // 插件主体
|
||||
}
|
||||
}
|
||||
})
|
||||
// 设精
|
||||
engine.OnRegex(`^\[CQ:reply,id=(\d+)\].*(设置|取消)精华$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
essenceID, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||
option := ctx.State["regex_matched"].([]string)[2]
|
||||
var rsp zero.APIResponse
|
||||
switch option {
|
||||
case "设置":
|
||||
rsp = ctx.SetGroupEssenceMessage(essenceID)
|
||||
case "取消":
|
||||
rsp = ctx.DeleteGroupEssenceMessage(essenceID)
|
||||
}
|
||||
if rsp.RetCode == 0 {
|
||||
ctx.SendChain(message.Text(option, "成功"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text(option, "失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
||||
}
|
||||
})
|
||||
engine.OnCommand("精华列表", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
list := ctx.GetGroupEssenceMessageList(ctx.Event.GroupID).Array()
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("本群精华列表:"))}
|
||||
n := len(list)
|
||||
if n > 30 {
|
||||
ctx.SendChain(message.Text("精华内容太多,仅显示前30个"))
|
||||
n = 30
|
||||
}
|
||||
for _, info := range list[:n] {
|
||||
msg = append(msg, ctxext.FakeSenderForwardNode(ctx,
|
||||
message.Text(fmt.Sprintf(
|
||||
"信息ID: %d\n发送者昵称: %s\n发送者QQ 号: %d\n消息发送时间: %s\n操作者昵称: %s\n操作者QQ 号: %d\n精华设置时间: %s",
|
||||
info.Get("message_id").Int(),
|
||||
info.Get("sender_nick").String(),
|
||||
info.Get("sender_id").Int(),
|
||||
time.Unix(info.Get("sender_time").Int(), 0).Format("2006/01/02 15:04:05"),
|
||||
info.Get("operator_nick").String(),
|
||||
info.Get("operator_id").Int(),
|
||||
time.Unix(info.Get("operator_time").Int(), 0).Format("2006/01/02 15:04:05"),
|
||||
))),
|
||||
)
|
||||
msgData := ctx.GetMessage(message.NewMessageIDFromInteger(info.Get("message_id").Int())).Elements
|
||||
if msgData != nil {
|
||||
msg = append(msg,
|
||||
message.CustomNode(info.Get("sender_nick").String(), info.Get("sender_id").Int(), msgData),
|
||||
)
|
||||
} else {
|
||||
msg = append(msg,
|
||||
message.CustomNode(info.Get("sender_nick").String(), info.Get("sender_id").Int(), "[error]信息久远,无法获取,如需查看原始内容请在“精华信息”中查看"),
|
||||
)
|
||||
}
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnPrefix("取消精华", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
essenceID, err := strconv.ParseInt(strings.TrimSpace(ctx.State["args"].(string)), 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的设精ID"))
|
||||
return
|
||||
}
|
||||
rsp := ctx.DeleteGroupEssenceMessage(essenceID)
|
||||
if rsp.RetCode == 0 {
|
||||
ctx.SendChain(message.Text("取消成功"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("取消失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 传入 ctx 和 welcome格式string 返回cq格式string 使用方法:welcometocq(ctx,w.Msg)
|
||||
|
||||
@@ -30,13 +30,15 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("midicreate", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "midi音乐制作, 该插件需要安装timidity, linux安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh, windows安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat?inline=false, windows需要管理员模式运行\n" +
|
||||
"- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
||||
Brief: "midi音乐制作",
|
||||
Help: "- midi制作 CCGGAAGR FFEEDDCR GGFFEEDR GGFFEEDR CCGGAAGR FFEEDDCR\n" +
|
||||
"- 个人听音练习\n" +
|
||||
"- 团队听音练习\n" +
|
||||
"- *.mid (midi 转 txt)\n" +
|
||||
"- midi制作*.txt (txt 转 midi)\n" +
|
||||
"- 设置音色40 (0~127)",
|
||||
"- 设置音色40 (0~127)\n" +
|
||||
"重要事项: 该插件依赖timidity\n" +
|
||||
"linux安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.sh\nwindows安装脚本可参考https://gitcode.net/anto_july/midi/-/raw/master/timidity.bat?inline=false, windows需要管理员模式运行",
|
||||
PrivateDataFolder: "midicreate",
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
|
||||
@@ -16,19 +16,20 @@ 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://233366.proxy.nscc-gz.cn:8888?speaker=%s&text=%s"
|
||||
cnapi = "https://genshin.azurewebsites.net/api/speak?format=mp3&text=%s&id=%d"
|
||||
)
|
||||
|
||||
var speakers = map[string]uint{
|
||||
"宁宁": 0, "爱瑠": 1, "芳乃": 2, "茉子": 3, "丛雨": 4, "小春": 5, "七海": 6,
|
||||
"Sua": 0, "Mimiru": 1, "Arin": 2, "Yeonhwa": 3, "Yuhwa": 4, "Seonbae": 5,
|
||||
"派蒙": 0, "凯亚": 1, "安柏": 2, "丽莎": 3, "琴": 4, "香菱": 5, "枫原万叶": 6, "迪卢克": 7, "温迪": 8, "可莉": 9, "早柚": 10, "托马": 11, "芭芭拉": 12, "优菈": 13, "云堇": 14, "钟离": 15, "魈": 16, "凝光": 17, "雷电将军": 18, "北斗": 19, "甘雨": 20, "七七": 21, "刻晴": 22, "神里绫华": 23, "戴因斯雷布": 24, "雷泽": 25, "神里绫人": 26, "罗莎莉亚": 27, "阿贝多": 28, "八重神子": 29, "宵宫": 30, "荒泷一斗": 31, "九条裟罗": 32, "夜兰": 33, "珊瑚宫心海": 34, "五郎": 35, "散兵": 36, "女士": 37, "达达利亚": 38, "莫娜": 39, "班尼特": 40, "申鹤": 41, "行秋": 42, "烟绯": 43, "久岐忍": 44, "辛焱": 45, "砂糖": 46, "胡桃": 47, "重云": 48, "菲谢尔": 49, "诺艾尔": 50, "迪奥娜": 51, "鹿野院平藏": 52,
|
||||
}
|
||||
|
||||
func init() {
|
||||
en := control.Register("moegoe", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "moegoe\n" +
|
||||
"- 让[宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海]说(日语)\n" +
|
||||
Brief: "日韩中 VITS 模型拟声",
|
||||
Help: "- 让[宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海]说(日语)\n" +
|
||||
"- 让[Sua|Mimiru|Arin|Yeonhwa|Yuhwa|Seonbae]说(韩语)\n" +
|
||||
"- 让[派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏]说(中文)",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
@@ -46,8 +47,8 @@ func init() {
|
||||
})
|
||||
en.OnRegex("^让(派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
speaker := ctx.State["regex_matched"].([]string)[1]
|
||||
text := ctx.State["regex_matched"].([]string)[2]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(cnapi, url.QueryEscape(speaker), url.QueryEscape(text))))
|
||||
id := speakers[ctx.State["regex_matched"].([]string)[1]]
|
||||
ctx.SendChain(message.Record(fmt.Sprintf(cnapi, url.QueryEscape(text), id)))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@ func TestSetHoliday(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("中秋节", 1, 2022, 9, 10)
|
||||
err = SetHoliday("中秋节", 1, 2023, 9, 29)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("国庆节", 7, 2022, 10, 1)
|
||||
err = SetHoliday("国庆节", 7, 2023, 10, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ var (
|
||||
func init() { // 插件主体
|
||||
control.Register("moyu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "moyu\n" +
|
||||
"- /启用 moyu\n" +
|
||||
Brief: "摸鱼提醒",
|
||||
Help: "- /启用 moyu\n" +
|
||||
"- /禁用 moyu\n" +
|
||||
"- 记录在\"0 10 * * *\"触发的指令\n" +
|
||||
" - 摸鱼提醒",
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
func init() {
|
||||
control.Register("moyucalendar", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "摸鱼人日历\n" +
|
||||
"- /启用 moyucalendar\n" +
|
||||
Brief: "摸鱼人日历",
|
||||
Help: "- /启用 moyucalendar\n" +
|
||||
"- /禁用 moyucalendar\n" +
|
||||
"- 记录在\"30 8 * * *\"触发的指令\n" +
|
||||
" - 摸鱼人日历",
|
||||
|
||||
@@ -24,8 +24,8 @@ import (
|
||||
func init() {
|
||||
control.Register("music", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "点歌\n" +
|
||||
"- 点歌[xxx]\n" +
|
||||
Brief: "点歌",
|
||||
Help: "- 点歌[xxx]\n" +
|
||||
"- 网易点歌[xxx]\n" +
|
||||
"- 酷我点歌[xxx]\n" +
|
||||
"- 酷狗点歌[xxx]",
|
||||
@@ -138,7 +138,7 @@ func kugou(keyword string) message.MessageSegment {
|
||||
|
||||
// cloud163 返回网易云音乐卡片
|
||||
func cloud163(keyword string) (msg message.MessageSegment) {
|
||||
requestURL := "https://music.cyrilstudio.top/search?keywords=" + url.QueryEscape(keyword)
|
||||
requestURL := "http://music.163.com/api/search/get/web?type=1&limit=1&s=" + url.QueryEscape(keyword)
|
||||
data, err := web.GetData(requestURL)
|
||||
if err != nil {
|
||||
msg = message.Text("ERROR: ", err)
|
||||
@@ -150,14 +150,13 @@ func cloud163(keyword string) (msg message.MessageSegment) {
|
||||
|
||||
// qqmusic 返回QQ音乐卡片
|
||||
func qqmusic(keyword string) (msg message.MessageSegment) {
|
||||
requestURL := "https://c.y.qq.com/soso/fcgi-bin/client_search_cp?w=" + url.QueryEscape(keyword)
|
||||
requestURL := "https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?platform=yqq.json&key=" + url.QueryEscape(keyword)
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), requestURL, "GET", "", web.RandUA())
|
||||
if err != nil {
|
||||
msg = message.Text("ERROR: ", err)
|
||||
return
|
||||
}
|
||||
info := gjson.ParseBytes(data[9 : len(data)-1]).Get("data.song.list.0")
|
||||
msg = message.Music("qq", info.Get("songid").Int())
|
||||
msg = message.Music("qq", gjson.ParseBytes(data).Get("data.song.itemlist.0.id").Int())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ var (
|
||||
func init() {
|
||||
engine := control.Register("nativesetu", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "本地涩图\n" +
|
||||
"- 本地[xxx]\n" +
|
||||
Brief: "本地涩图",
|
||||
Help: "- 本地[xxx]\n" +
|
||||
"- 刷新本地[xxx]\n" +
|
||||
"- 设置本地setu绝对路径[xxx]\n" +
|
||||
"- 刷新所有本地setu\n" +
|
||||
@@ -95,7 +95,8 @@ func init() {
|
||||
})
|
||||
engine.OnFullMatch("所有本地setu分类").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msg := "所有本地setu分类"
|
||||
msg := "本地setu分类一览"
|
||||
hasnotchange := true
|
||||
ns.mu.RLock()
|
||||
for i, c := range ns.List() {
|
||||
n, err := ns.db.Count(c)
|
||||
@@ -105,8 +106,12 @@ func init() {
|
||||
msg += fmt.Sprintf("\n%02d. %s(error)", i, c)
|
||||
logrus.Errorln("[nsetu]", err)
|
||||
}
|
||||
hasnotchange = false
|
||||
}
|
||||
ns.mu.RUnlock()
|
||||
if hasnotchange {
|
||||
msg += "\n空"
|
||||
}
|
||||
ctx.SendChain(message.Text(msg))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("nwife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "nativewife\n- 抽wife[@xxx]\n- 添加wife[名字][图片]\n- 删除wife[名字]\n- [让 | 不让]所有人均可添加wife",
|
||||
Brief: "本地老婆",
|
||||
Help: "- 抽wife[@xxx]\n- 添加wife[名字][图片]\n- 删除wife[名字]\n- [让 | 不让]所有人均可添加wife",
|
||||
PrivateDataFolder: "nwife",
|
||||
})
|
||||
base := engine.DataFolder()
|
||||
@@ -32,7 +33,7 @@ func init() {
|
||||
engine.OnPrefix("抽wife", zero.OnlyGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
grpf := strconv.FormatInt(ctx.Event.GroupID, 36)
|
||||
wifes, err := os.ReadDir(base + "/" + grpf)
|
||||
wifes, err := os.ReadDir(base + grpf)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("一个wife也没有哦~"))
|
||||
return
|
||||
@@ -42,7 +43,7 @@ func init() {
|
||||
ctx.SendChain(message.Text("一个wife也没有哦~"))
|
||||
case 1:
|
||||
wn := wifes[0].Name()
|
||||
ctx.SendChain(message.Text("大家的wife都是", wn, "\n"), message.Image(baseuri+"/"+grpf+"/"+wn), message.Text("\n哦~"))
|
||||
ctx.SendChain(message.Text("大家的wife都是", wn, "\n"), message.Image(baseuri+grpf+"/"+wn), message.Text("\n哦~"))
|
||||
default:
|
||||
// 获取名字
|
||||
name := ctx.NickName()
|
||||
@@ -51,7 +52,7 @@ func init() {
|
||||
r := rand.New(rand.NewSource(int64(binary.LittleEndian.Uint64(s[:]))))
|
||||
n := r.Intn(len(wifes))
|
||||
wn := wifes[n].Name()
|
||||
ctx.SendChain(message.Text(name, "的wife是", wn, "\n"), message.Image(baseuri+"/"+grpf+"/"+wn), message.Text("\n哦~"))
|
||||
ctx.SendChain(message.Text(name, "的wife是", wn, "\n"), message.Image(baseuri+grpf+"/"+wn), message.Text("\n哦~"))
|
||||
}
|
||||
})
|
||||
// 上传一张图
|
||||
@@ -69,7 +70,7 @@ func init() {
|
||||
}
|
||||
if name != "" {
|
||||
url := ctx.State["image_url"].([]string)[0]
|
||||
grpfolder := base + "/" + strconv.FormatInt(ctx.Event.GroupID, 36)
|
||||
grpfolder := base + strconv.FormatInt(ctx.Event.GroupID, 36)
|
||||
if file.IsNotExist(grpfolder) {
|
||||
err := os.Mkdir(grpfolder, 0755)
|
||||
if err != nil {
|
||||
@@ -100,7 +101,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
if name != "" {
|
||||
grpfolder := base + "/" + strconv.FormatInt(ctx.Event.GroupID, 36)
|
||||
grpfolder := base + strconv.FormatInt(ctx.Event.GroupID, 36)
|
||||
err := os.Remove(grpfolder + "/" + name)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功!"))
|
||||
|
||||
@@ -17,7 +17,8 @@ import (
|
||||
func init() {
|
||||
control.Register("nbnhhsh", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "拼音首字母释义工具\n- ?? [缩写]",
|
||||
Brief: "拼音首字母释义工具",
|
||||
Help: "- ?? [缩写]",
|
||||
}).OnRegex(`^[??]{1,2} ?([a-z0-9]+)$`).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
|
||||
@@ -25,6 +25,11 @@ func (g *grammar) string() string {
|
||||
var db = &sql.Sqlite{}
|
||||
|
||||
func getRandomGrammarByTag(tag string) (g grammar) {
|
||||
_ = db.Find("grammar", &g, "where tag LIKE '%"+tag+"%' ORDER BY RANDOM() limit 1")
|
||||
_ = db.Find("grammar", &g, "WHERE tag LIKE '%"+tag+"%' ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
func getRandomGrammarByKeyword(keyword string) (g grammar) {
|
||||
_ = db.Find("grammar", &g, "WHERE (name LIKE '%"+keyword+"%' or pronunciation LIKE '%"+keyword+"%') ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("nihongo", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "日语学习\n- 日语语法[xxx](使用tag随机)",
|
||||
Brief: "日语学习",
|
||||
Help: "- 日语语法[xxx](使用tag随机)\n" +
|
||||
"搜索日语语法[xxx]",
|
||||
PublicDataFolder: "Nihongo",
|
||||
})
|
||||
|
||||
@@ -47,7 +49,7 @@ func init() {
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnRegex(`^日语语法\s?([0-9A-Za-zぁ-んァ-ヶ]{1,6})$`, getdb).SetBlock(true).
|
||||
engine.OnRegex(`^日语语法\s?([0-9A-Za-zぁ-んァ-ヶ~]{1,6})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
g := getRandomGrammarByTag(ctx.State["regex_matched"].([]string)[1])
|
||||
if g.ID == 0 {
|
||||
@@ -63,4 +65,20 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^搜索日语语法\s?([0-9A-Za-zぁ-んァ-ヶ~]{1,25})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
g := getRandomGrammarByKeyword(ctx.State["regex_matched"].([]string)[1])
|
||||
if g.ID == 0 {
|
||||
ctx.SendChain(message.Text("未能找到", ctx.State["regex_matched"].([]string)[1], "相关标签的语法"))
|
||||
return
|
||||
}
|
||||
data, err := text.RenderToBase64(g.string(), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ var gCurCookieJar *cookiejar.Jar
|
||||
func init() {
|
||||
control.Register("novel", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "铅笔小说网搜索\n- 小说[xxx]",
|
||||
Brief: "铅笔小说网搜索",
|
||||
Help: "- 小说[xxx]",
|
||||
}).OnRegex("^小说([\u4E00-\u9FA5A-Za-z0-9]{1,25})$").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
|
||||
@@ -16,7 +16,8 @@ const hso = "https://gchat.qpic.cn/gchatpic_new//--4234EDEC5F147A4C319A41149D7E0
|
||||
func init() {
|
||||
engine := control.Register("nsfw", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "nsfw图片识别\n- nsfw打分[图片]",
|
||||
Brief: "nsfw图片识别",
|
||||
Help: "- nsfw打分[图片]",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
// 上传一张图进行评价
|
||||
engine.OnKeywordGroup([]string{"nsfw打分"}, zero.OnlyGroup, zero.MustProvidePicture).SetBlock(true).
|
||||
@@ -34,7 +35,8 @@ func init() {
|
||||
})
|
||||
control.Register("nsfwauto", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Help: "nsfw图片自动识别\n- 当图片属于非 neutral 类别时自动发送评价",
|
||||
Brief: "nsfw图片自动识别",
|
||||
Help: "- 当图片属于非 neutral 类别时自动发送评价",
|
||||
}).OnMessage(zero.HasPicture).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
url := ctx.State["image_url"].([]string)
|
||||
|
||||
@@ -22,8 +22,8 @@ const bed = "https://gitcode.net/u011570312/senso-ji-omikuji/-/raw/main/"
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("omikuji", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "浅草寺求签\n" +
|
||||
"- 求签 | 占卜\n- 解签",
|
||||
Brief: "浅草寺求签",
|
||||
Help: "- 求签 | 占卜\n- 解签",
|
||||
PublicDataFolder: "Omikuji",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ import (
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
|
||||
// 货币系统
|
||||
"github.com/FloatTech/AnimeAPI/wallet"
|
||||
)
|
||||
|
||||
// nolint: asciicheck
|
||||
@@ -58,17 +61,19 @@ var (
|
||||
|
||||
func init() {
|
||||
engine := control.Register("qqwife", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
PrivateDataFolder: "qqwife",
|
||||
Help: "一群一天一夫一妻制群老婆\n(每天凌晨刷新CP)\n" +
|
||||
"- 娶群友\n- 群老婆列表\n- 允许/禁止自由恋爱\n- 允许/禁止牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n" +
|
||||
DisableOnDefault: false,
|
||||
Brief: "一群一天一夫一妻制群老婆",
|
||||
Help: "- 娶群友\n- 群老婆列表\n- [允许|禁止]自由恋爱\n- [允许|禁止]牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n" +
|
||||
"--------------------------------\n以下指令存在CD,不跨天刷新,前两个受指令开关\n--------------------------------\n" +
|
||||
"- (娶|嫁)@对方QQ\n自由选择对象,自由恋爱(好感度越高成功率越高,保底30%概率)\n" +
|
||||
"- 当[对方Q号|@对方QQ]的小三\n我和你才是真爱,为了你我愿意付出一切(好感度越高成功率越高,保底10%概率)\n" +
|
||||
"- 闹离婚\n你谁啊,给我滚(好感度越高成功率越低)\n" +
|
||||
"- 做媒 @攻方QQ @受方QQ\n身为管理,群友的xing福是要搭把手的(攻受双方好感度越高成功率越高,保底30%概率)\n" +
|
||||
"- (娶|嫁)@对方QQ\n自由选择对象, 自由恋爱(好感度越高成功率越高,保底30%概率)\n" +
|
||||
"- 当[对方Q号|@对方QQ]的小三\n我和你才是真爱, 为了你我愿意付出一切(好感度越高成功率越高,保底10%概率)\n" +
|
||||
"- 闹离婚\n你谁啊, 给我滚(好感度越高成功率越低)\n" +
|
||||
"- 买礼物给[对方Q号|@对方QQ]\n使用小熊饼干获取好感度\n" +
|
||||
"- 做媒 @攻方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",
|
||||
"\"娶群友\"指令好感度随机增加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点刷新",
|
||||
PrivateDataFolder: "qqwife",
|
||||
}).ApplySingle(single.New(
|
||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
||||
@@ -89,7 +94,7 @@ func init() {
|
||||
return true
|
||||
})
|
||||
// 技能CD设置
|
||||
engine.OnRegex(`^设置CD为(\d+)小时`, zero.OnlyGroup, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
engine.OnRegex(`^设置CD为(\d+)小时`, zero.OnlyGroup, zero.AdminPermission, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
cdTime, err := strconv.ParseFloat(ctx.State["regex_matched"].([]string)[1], 64)
|
||||
if err != nil {
|
||||
@@ -104,7 +109,7 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Text("设置成功"))
|
||||
})
|
||||
engine.OnRegex(`^(允许|禁止)(自由恋爱|牛头人)$`, zero.AdminPermission, getdb).SetBlock(true).
|
||||
engine.OnRegex(`^(允许|禁止)(自由恋爱|牛头人)$`, zero.OnlyGroup, zero.AdminPermission, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
status := ctx.State["regex_matched"].([]string)[1]
|
||||
mode := ctx.State["regex_matched"].([]string)[2]
|
||||
@@ -161,7 +166,7 @@ func init() {
|
||||
case status == "攻": // 娶过别人
|
||||
ctx.SendChain(
|
||||
message.At(uid),
|
||||
message.Text("\n今天你已经娶过了,群老婆是"),
|
||||
message.Text("\n今天你在", targetinfo.Updatetime, "娶了群友"),
|
||||
message.Image("http://q4.qlogo.cn/g?b=qq&nk="+strconv.FormatInt(targetinfo.Target, 10)+"&s=640").Add("cache", 0),
|
||||
message.Text(
|
||||
"\n",
|
||||
@@ -173,12 +178,12 @@ func init() {
|
||||
case status == "受": // 嫁给别人
|
||||
ctx.SendChain(
|
||||
message.At(uid),
|
||||
message.Text("\n今天你被娶了,群老公是"),
|
||||
message.Text("\n今天你在", targetinfo.Updatetime, "被群友"),
|
||||
message.Image("http://q4.qlogo.cn/g?b=qq&nk="+strconv.FormatInt(targetinfo.User, 10)+"&s=640").Add("cache", 0),
|
||||
message.Text(
|
||||
"\n",
|
||||
"[", targetinfo.Username, "]",
|
||||
"(", targetinfo.User, ")哒",
|
||||
"(", targetinfo.User, ")娶了",
|
||||
),
|
||||
)
|
||||
return
|
||||
@@ -243,6 +248,11 @@ func init() {
|
||||
uid := ctx.Event.UserID
|
||||
choice := ctx.State["regex_matched"].([]string)[1]
|
||||
fiancee, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64)
|
||||
// 写入CD
|
||||
err := 民政局.writeCDtime(gid, uid, 1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
if uid == fiancee { // 如果是自己
|
||||
switch rand.Intn(3) {
|
||||
case 1:
|
||||
@@ -307,6 +317,11 @@ func init() {
|
||||
uid := ctx.Event.UserID
|
||||
fid := ctx.State["regex_matched"].([]string)
|
||||
fiancee, _ := strconv.ParseInt(fid[2]+fid[3], 10, 64)
|
||||
// 写入CD
|
||||
err := 民政局.writeCDtime(gid, uid, 2)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
if fiancee == uid {
|
||||
ctx.SendChain(message.Text("今日获得成就:自我攻略"))
|
||||
return
|
||||
@@ -391,6 +406,11 @@ func init() {
|
||||
uid := ctx.Event.UserID
|
||||
gayOne, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||
gayZero, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64)
|
||||
// 写入CD
|
||||
err := 民政局.writeCDtime(gid, uid, 3)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
favor, err := 民政局.getFavorability(gayOne, gayZero)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]好感度库发生问题力\n", err))
|
||||
@@ -443,10 +463,84 @@ func init() {
|
||||
),
|
||||
)
|
||||
})
|
||||
// 礼物系统
|
||||
engine.OnRegex(`^买礼物给\s?(\[CQ:at,qq=(\d+)\]|(\d+))`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
fiancee := ctx.State["regex_matched"].([]string)
|
||||
gay, _ := strconv.ParseInt(fiancee[2]+fiancee[3], 10, 64)
|
||||
// 获取CD
|
||||
cdTime, err := 民政局.getCDtime(gid)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]获取该群技能CD错误(将以CD12H计算)\n", err))
|
||||
}
|
||||
ok, err := 民政局.compareCDtime(gid, uid, 5, cdTime)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]查询用户CD状态失败,请重试\n", err))
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("舔狗,今天你已经送过礼物了。"))
|
||||
return
|
||||
}
|
||||
// 获取好感度
|
||||
favor, err := 民政局.getFavorability(uid, gay)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]好感度库发生问题力\n", err))
|
||||
return
|
||||
}
|
||||
// 对接小熊饼干
|
||||
walletinfo := wallet.GetWalletOf(uid)
|
||||
if walletinfo < 1 {
|
||||
ctx.SendChain(message.Text("你钱包没钱啦!"))
|
||||
return
|
||||
}
|
||||
moneyToFavor := rand.Intn(math.Min(walletinfo, 100)) + 1
|
||||
// 计算钱对应的好感值
|
||||
newFavor := 1
|
||||
if favor > 50 {
|
||||
newFavor += moneyToFavor % 10 // 礼物厌倦
|
||||
} else {
|
||||
newFavor += rand.Intn(moneyToFavor)
|
||||
}
|
||||
// 随机对方心情
|
||||
mood := rand.Intn(5)
|
||||
if mood == 0 {
|
||||
newFavor = -newFavor
|
||||
}
|
||||
// 记录结果
|
||||
err = wallet.InsertWalletOf(uid, -moneyToFavor)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]钱包坏掉力:\n", err))
|
||||
return
|
||||
}
|
||||
lastfavor, err := 民政局.setFavorability(uid, gay, newFavor)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]好感度数据库发生问题力\n", err))
|
||||
return
|
||||
}
|
||||
// 写入CD
|
||||
err = 民政局.writeCDtime(gid, uid, 5)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
// 输出结果
|
||||
if mood == 0 {
|
||||
ctx.SendChain(message.Text("你花了", moneyToFavor, "ATRI币买了一件女装送给了ta,ta很不喜欢,你们的好感度降低至", lastfavor))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("你花了", moneyToFavor, "ATRI币买了一件女装送给了ta,ta很喜欢,你们的好感度升至", lastfavor))
|
||||
}
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"闹离婚", "办离婚"}, zero.OnlyGroup, getdb, checkdivorce).Limit(ctxext.LimitByUser).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
// 写入CD
|
||||
err := 民政局.writeCDtime(gid, uid, 4)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
info, uidstatus, err := 民政局.查户口(gid, uid)
|
||||
mun := 2
|
||||
var fiancee int64
|
||||
@@ -466,7 +560,10 @@ func init() {
|
||||
ctx.SendChain(message.Text("[qqwife]好感度库发生问题力\n", err))
|
||||
return
|
||||
}
|
||||
if rand.Intn(1+favor) > favor/10 {
|
||||
if favor < 20 {
|
||||
favor = 10
|
||||
}
|
||||
if rand.Intn(101) > 100-favor {
|
||||
ctx.SendChain(message.Text(sendtext[3][rand.Intn(len(sendtext[3]))]))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
)
|
||||
|
||||
// nolint: asciicheck
|
||||
//nolint: asciicheck
|
||||
// nolint: asciicheck
|
||||
type 婚姻登记 struct {
|
||||
db *sql.Sqlite
|
||||
dbmu sync.RWMutex
|
||||
db *sql.Sqlite
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// 结婚证信息
|
||||
@@ -55,17 +55,12 @@ type cdsheet struct {
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 开门时间(gid int64) (ok bool, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
ok = false
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
if err = sql.db.Drop("updateinfo"); err == nil {
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
gidstr := strconv.FormatInt(gid, 10)
|
||||
dbinfo := updateinfo{}
|
||||
@@ -91,8 +86,9 @@ func (sql *婚姻登记) 开门时间(gid int64) (ok bool, err error) {
|
||||
// 开门了就拿新的花名册
|
||||
err = sql.db.Drop("group" + gidstr)
|
||||
if err != nil {
|
||||
err = sql.db.Create("group"+gidstr, &userinfo{})
|
||||
return
|
||||
if err = sql.db.Create("group"+gidstr, &userinfo{}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
dbinfo.Updatetime = time.Now().Format("2006/01/02")
|
||||
err = sql.db.Insert("updateinfo", &dbinfo)
|
||||
@@ -103,8 +99,8 @@ func (sql *婚姻登记) 开门时间(gid int64) (ok bool, err error) {
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 营业模式(gid int64) (canMatch, canNtr int, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
if err = sql.db.Drop("updateinfo"); err == nil {
|
||||
@@ -134,8 +130,8 @@ func (sql *婚姻登记) 营业模式(gid int64) (canMatch, canNtr int, err erro
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 修改模式(gid int64, mode string, stauts int) (err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
if err = sql.db.Drop("updateinfo"); err == nil {
|
||||
@@ -173,8 +169,8 @@ func (sql *婚姻登记) 修改模式(gid int64, mode string, stauts int) (err e
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 清理花名册(gid string) error {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
grouplist, err := sql.db.ListTables()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -213,8 +209,8 @@ func (sql *婚姻登记) 清理花名册(gid string) error {
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 查户口(gid, uid int64) (info userinfo, status string, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
uidstr := strconv.FormatInt(uid, 10)
|
||||
status = "单"
|
||||
@@ -236,14 +232,14 @@ func (sql *婚姻登记) 查户口(gid, uid int64) (info userinfo, status string
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 登记(gid, uid, target int64, username, targetname string) error {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
err := sql.db.Create(gidstr, &userinfo{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatetime := time.Now().Format("2006/01/02")
|
||||
updatetime := time.Now().Format("15:04:05")
|
||||
// 填写夫妻信息
|
||||
uidinfo := userinfo{
|
||||
User: uid,
|
||||
@@ -258,24 +254,24 @@ func (sql *婚姻登记) 登记(gid, uid, target int64, username, targetname str
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 离婚休妻(gid, wife int64) error {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
wifestr := strconv.FormatInt(wife, 10)
|
||||
return sql.db.Del(gidstr, "where target = "+wifestr)
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 离婚休夫(gid, husband int64) error {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
husbandstr := strconv.FormatInt(husband, 10)
|
||||
return sql.db.Del(gidstr, "where user = "+husbandstr)
|
||||
}
|
||||
|
||||
func (sql *婚姻登记) 花名册(gid int64) (list [][4]string, number int, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
gidstr := "group" + strconv.FormatInt(gid, 10)
|
||||
err = sql.db.Create(gidstr, &userinfo{})
|
||||
if err != nil {
|
||||
@@ -300,9 +296,7 @@ func (sql *婚姻登记) 花名册(gid int64) (list [][4]string, number int, err
|
||||
list = append(list, dbinfo)
|
||||
return nil
|
||||
})
|
||||
if len(list) == 0 {
|
||||
number = 0
|
||||
}
|
||||
number = len(list)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -328,8 +322,8 @@ func slicename(name string, canvas *gg.Context) (resultname string) {
|
||||
|
||||
// 获取好感度
|
||||
func (sql *婚姻登记) getFavorability(uid, target int64) (favor int, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err = sql.db.Create("favorability", &favorability{})
|
||||
if err != nil {
|
||||
return
|
||||
@@ -351,8 +345,8 @@ func (sql *婚姻登记) getFavorability(uid, target int64) (favor int, err erro
|
||||
|
||||
// 设置好感度 正增负减
|
||||
func (sql *婚姻登记) setFavorability(uid, target int64, score int) (favor int, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err = sql.db.Create("favorability", &favorability{})
|
||||
if err != nil {
|
||||
return
|
||||
@@ -366,7 +360,10 @@ func (sql *婚姻登记) setFavorability(uid, target int64, score int) (favor in
|
||||
Userinfo: uidstr + "+" + targstr + "+" + uidstr,
|
||||
Favor: score,
|
||||
})
|
||||
return score, err
|
||||
if err == nil {
|
||||
err = sql.db.Find("favorability", &info, "where Userinfo glob '*"+uidstr+"+"+targstr+"*'")
|
||||
}
|
||||
return info.Favor, err
|
||||
}
|
||||
info.Favor += score
|
||||
if info.Favor > 100 {
|
||||
@@ -380,8 +377,8 @@ func (sql *婚姻登记) setFavorability(uid, target int64, score int) (favor in
|
||||
|
||||
// 获取技能时长
|
||||
func (sql *婚姻登记) getCDtime(gid int64) (skillCD float64, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
skillCD = 12
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
@@ -410,8 +407,8 @@ func (sql *婚姻登记) getCDtime(gid int64) (skillCD float64, err error) {
|
||||
|
||||
// 设置技能时长
|
||||
func (sql *婚姻登记) setCDtime(gid int64, cdTime float64) (err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err = sql.db.Create("updateinfo", &updateinfo{})
|
||||
if err != nil {
|
||||
if err = sql.db.Drop("updateinfo"); err == nil {
|
||||
@@ -441,8 +438,8 @@ func (sql *婚姻登记) setCDtime(gid int64, cdTime float64) (err error) {
|
||||
|
||||
// 记录CD
|
||||
func (sql *婚姻登记) writeCDtime(gid, uid, mun int64) error {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
err := sql.db.Create("cdsheet", &cdsheet{})
|
||||
if err != nil {
|
||||
if err = sql.db.Drop("cdsheet"); err == nil {
|
||||
@@ -463,8 +460,8 @@ func (sql *婚姻登记) writeCDtime(gid, uid, mun int64) error {
|
||||
|
||||
// 判断CD是否过时
|
||||
func (sql *婚姻登记) compareCDtime(gid, uid, mun int64, cdtime float64) (ok bool, err error) {
|
||||
sql.dbmu.Lock()
|
||||
defer sql.dbmu.Unlock()
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
ok = false
|
||||
err = sql.db.Create("cdsheet", &cdsheet{})
|
||||
if err != nil {
|
||||
@@ -498,7 +495,6 @@ func (sql *婚姻登记) compareCDtime(gid, uid, mun int64, cdtime float64) (ok
|
||||
|
||||
// 注入判断 是否为单身
|
||||
func checkdog(ctx *zero.Ctx) bool {
|
||||
mode := int64(1) // 指代技能1
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
// 获取CD
|
||||
@@ -506,7 +502,7 @@ func checkdog(ctx *zero.Ctx) bool {
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]获取该群技能CD错误(将以CD12H计算)\n", err))
|
||||
}
|
||||
ok, err := 民政局.compareCDtime(gid, uid, mode, cdTime)
|
||||
ok, err := 民政局.compareCDtime(gid, uid, 1, cdTime)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]查询用户CD状态失败,请重试\n", err))
|
||||
return false
|
||||
@@ -515,11 +511,6 @@ func checkdog(ctx *zero.Ctx) bool {
|
||||
ctx.SendChain(message.Text("你的技能还在CD中..."))
|
||||
return false
|
||||
}
|
||||
// 写入CD
|
||||
err = 民政局.writeCDtime(gid, uid, mode)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
// 判断是否符合条件
|
||||
stauts, _, err := 民政局.营业模式(gid)
|
||||
if err != nil {
|
||||
@@ -583,7 +574,6 @@ func checkdog(ctx *zero.Ctx) bool {
|
||||
|
||||
// 注入判断 是否满足小三要求
|
||||
func checkcp(ctx *zero.Ctx) bool {
|
||||
mode := int64(2) // 指代技能2
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
// 获取CD
|
||||
@@ -591,7 +581,7 @@ func checkcp(ctx *zero.Ctx) bool {
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]获取该群技能CD错误(将以CD12H计算)\n", err))
|
||||
}
|
||||
ok, err := 民政局.compareCDtime(gid, uid, mode, cdTime)
|
||||
ok, err := 民政局.compareCDtime(gid, uid, 2, cdTime)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]查询用户CD状态失败,请重试\n", err))
|
||||
return false
|
||||
@@ -600,11 +590,6 @@ func checkcp(ctx *zero.Ctx) bool {
|
||||
ctx.SendChain(message.Text("你的技能还在CD中..."))
|
||||
return false
|
||||
}
|
||||
// 写入CD
|
||||
err = 民政局.writeCDtime(gid, uid, mode)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
// 判断是否符合条件
|
||||
_, stauts, err := 民政局.营业模式(gid)
|
||||
if err != nil {
|
||||
@@ -669,7 +654,6 @@ func checkcp(ctx *zero.Ctx) bool {
|
||||
|
||||
// 注入判断 是否满足离婚要求
|
||||
func checkdivorce(ctx *zero.Ctx) bool {
|
||||
mode := int64(3) // 指代技能3
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
// 获取CD
|
||||
@@ -677,7 +661,7 @@ func checkdivorce(ctx *zero.Ctx) bool {
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]获取该群技能CD错误(将以CD12H计算)\n", err))
|
||||
}
|
||||
ok, err := 民政局.compareCDtime(gid, uid, mode, cdTime)
|
||||
ok, err := 民政局.compareCDtime(gid, uid, 4, cdTime)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]查询用户CD状态失败,请重试\n", err))
|
||||
return false
|
||||
@@ -686,11 +670,6 @@ func checkdivorce(ctx *zero.Ctx) bool {
|
||||
ctx.SendChain(message.Text("你的技能还在CD中..."))
|
||||
return false
|
||||
}
|
||||
// 写入CD
|
||||
err = 民政局.writeCDtime(gid, uid, mode)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
// 判断是否符合条件
|
||||
_, uidstatus, err := 民政局.查户口(gid, uid)
|
||||
switch uidstatus {
|
||||
@@ -706,7 +685,6 @@ func checkdivorce(ctx *zero.Ctx) bool {
|
||||
|
||||
// 注入判断 是否满足做媒要求
|
||||
func checkCondition(ctx *zero.Ctx) bool {
|
||||
mode := int64(4) // 指代技能4
|
||||
gid := ctx.Event.GroupID
|
||||
uid := ctx.Event.UserID
|
||||
// 获取CD
|
||||
@@ -714,7 +692,7 @@ func checkCondition(ctx *zero.Ctx) bool {
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]获取该群技能CD错误(将以CD12H计算)\n", err))
|
||||
}
|
||||
ok, err := 民政局.compareCDtime(gid, uid, mode, cdTime)
|
||||
ok, err := 民政局.compareCDtime(gid, uid, 3, cdTime)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("[qqwife]查询用户CD状态失败,请重试\n", err))
|
||||
return false
|
||||
@@ -723,11 +701,6 @@ func checkCondition(ctx *zero.Ctx) bool {
|
||||
ctx.SendChain(message.Text("你的技能还在CD中..."))
|
||||
return false
|
||||
}
|
||||
// 写入CD
|
||||
err = 民政局.writeCDtime(gid, uid, mode)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.At(uid), message.Text("[qqwife]你的技能CD记录失败\n", err))
|
||||
}
|
||||
// 得先判断用户是否存在才行在,再重置
|
||||
gayOne, err := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||
if err != nil {
|
||||
|
||||
105
plugin/realcugan/realcugan.go
Normal file
105
plugin/realcugan/realcugan.go
Normal file
@@ -0,0 +1,105 @@
|
||||
// Package realcugan Real-CUGAN清晰术
|
||||
package realcugan
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"strings"
|
||||
|
||||
hf "github.com/FloatTech/AnimeAPI/huggingface"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
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 (
|
||||
realcuganRepo = "shichen1231/Real-CUGAN"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("realcugan", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "Real-CUGAN清晰术",
|
||||
Help: "- 清晰术(双重吟唱|三重吟唱|四重吟唱)(强力术式|中等术式|弱术式|不变式|原式)[图片]",
|
||||
PrivateDataFolder: "realcugan",
|
||||
})
|
||||
engine.OnPrefix("清晰术", zero.MustProvidePicture).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
realcuganURL := fmt.Sprintf(hf.HTTPSPredictPath, realcuganRepo)
|
||||
for _, url := range ctx.State["image_url"].([]string) {
|
||||
imgdata, err := web.GetData(url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
img, _, err := image.Decode(bytes.NewReader(imgdata))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
// 初始化参数
|
||||
var (
|
||||
fashu = ctx.Event.Message.ExtractPlainText()
|
||||
scale = 2
|
||||
con = "conservative"
|
||||
)
|
||||
switch {
|
||||
case strings.Contains(fashu, "双重吟唱"):
|
||||
scale = 2
|
||||
case strings.Contains(fashu, "三重吟唱") && img.Bounds().Dx()*img.Bounds().Dy() < 400000:
|
||||
scale = 3
|
||||
case strings.Contains(fashu, "四重吟唱") && img.Bounds().Dx()*img.Bounds().Dy() < 400000:
|
||||
scale = 4
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(fashu, "强力术式"):
|
||||
con = "denoise3x"
|
||||
case strings.Contains(fashu, "中等术式"):
|
||||
con = "no-denoise"
|
||||
if scale == 2 {
|
||||
con = "denoise2x"
|
||||
}
|
||||
case strings.Contains(fashu, "弱术式"):
|
||||
con = "no-denoise"
|
||||
if scale == 2 {
|
||||
con = "denoise1x"
|
||||
}
|
||||
case strings.Contains(fashu, "不变式"):
|
||||
con = "no-denoise"
|
||||
case strings.Contains(fashu, "原式"):
|
||||
con = "conservative"
|
||||
}
|
||||
modelname := fmt.Sprintf("up%vx-latest-%v.pth", scale, con)
|
||||
encodeStr := base64.StdEncoding.EncodeToString(imgdata)
|
||||
encodeStr = "data:image/jpeg;base64," + encodeStr
|
||||
pr := hf.PushRequest{
|
||||
Data: []interface{}{encodeStr, modelname, 2},
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
err = json.NewEncoder(buf).Encode(pr)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := web.PostData(realcuganURL, "application/json", buf)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
imgStr := gjson.ParseBytes(data).Get("data.0").String()
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text(scale, "重唱", con, "分支大清晰术!")),
|
||||
ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+strings.TrimPrefix(imgStr, "data:image/png;base64,")))}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -17,7 +17,8 @@ import (
|
||||
func init() {
|
||||
en := control.Register("reborn", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "投胎\n- reborn",
|
||||
Brief: "投胎模拟器",
|
||||
Help: "- reborn",
|
||||
PublicDataFolder: "Reborn",
|
||||
})
|
||||
|
||||
|
||||
@@ -2,100 +2,23 @@
|
||||
package runcode
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/runoob"
|
||||
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"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
var (
|
||||
templates = map[string]string{
|
||||
"py2": "print 'Hello World!'",
|
||||
"ruby": "puts \"Hello World!\";",
|
||||
"rb": "puts \"Hello World!\";",
|
||||
"php": "<?php\n\techo 'Hello World!';\n?>",
|
||||
"javascript": "console.log(\"Hello World!\");",
|
||||
"js": "console.log(\"Hello World!\");",
|
||||
"node.js": "console.log(\"Hello World!\");",
|
||||
"scala": "object Main {\n def main(args:Array[String])\n {\n println(\"Hello World!\")\n }\n\t\t\n}",
|
||||
"go": "package main\n\nimport \"fmt\"\n\nfunc main() {\n fmt.Println(\"Hello, World!\")\n}",
|
||||
"c": "#include <stdio.h>\n\nint main()\n{\n printf(\"Hello, World! \n\");\n return 0;\n}",
|
||||
"c++": "#include <iostream>\nusing namespace std;\n\nint main()\n{\n cout << \"Hello World\";\n return 0;\n}",
|
||||
"cpp": "#include <iostream>\nusing namespace std;\n\nint main()\n{\n cout << \"Hello World\";\n return 0;\n}",
|
||||
"java": "public class HelloWorld {\n public static void main(String []args) {\n System.out.println(\"Hello World!\");\n }\n}",
|
||||
"rust": "fn main() {\n println!(\"Hello World!\");\n}",
|
||||
"rs": "fn main() {\n println!(\"Hello World!\");\n}",
|
||||
"c#": "using System;\nnamespace HelloWorldApplication\n{\n class HelloWorld\n {\n static void Main(string[] args)\n {\n Console.WriteLine(\"Hello World!\");\n }\n }\n}",
|
||||
"cs": "using System;\nnamespace HelloWorldApplication\n{\n class HelloWorld\n {\n static void Main(string[] args)\n {\n Console.WriteLine(\"Hello World!\");\n }\n }\n}",
|
||||
"csharp": "using System;\nnamespace HelloWorldApplication\n{\n class HelloWorld\n {\n static void Main(string[] args)\n {\n Console.WriteLine(\"Hello World!\");\n }\n }\n}",
|
||||
"shell": "echo 'Hello World!'",
|
||||
"bash": "echo 'Hello World!'",
|
||||
"erlang": "% escript will ignore the first line\n\nmain(_) ->\n io:format(\"Hello World!~n\").",
|
||||
"perl": "print \"Hello, World!\n\";",
|
||||
"python": "print(\"Hello, World!\")",
|
||||
"py": "print(\"Hello, World!\")",
|
||||
"swift": "var myString = \"Hello, World!\"\nprint(myString)",
|
||||
"lua": "var myString = \"Hello, World!\"\nprint(myString)",
|
||||
"pascal": "runcode Hello;\nbegin\n writeln ('Hello, world!')\nend.",
|
||||
"kotlin": "fun main(args : Array<String>){\n println(\"Hello World!\")\n}",
|
||||
"kt": "fun main(args : Array<String>){\n println(\"Hello World!\")\n}",
|
||||
"r": "myString <- \"Hello, World!\"\nprint ( myString)",
|
||||
"vb": "Module Module1\n\n Sub Main()\n Console.WriteLine(\"Hello World!\")\n End Sub\n\nEnd Module",
|
||||
"typescript": "const hello : string = \"Hello World!\"\nconsole.log(hello)",
|
||||
"ts": "const hello : string = \"Hello World!\"\nconsole.log(hello)",
|
||||
}
|
||||
table = map[string][2]string{
|
||||
"py2": {"0", "py"},
|
||||
"ruby": {"1", "rb"},
|
||||
"rb": {"1", "rb"},
|
||||
"php": {"3", "php"},
|
||||
"javascript": {"4", "js"},
|
||||
"js": {"4", "js"},
|
||||
"node.js": {"4", "js"},
|
||||
"scala": {"5", "scala"},
|
||||
"go": {"6", "go"},
|
||||
"c": {"7", "c"},
|
||||
"c++": {"7", "cpp"},
|
||||
"cpp": {"7", "cpp"},
|
||||
"java": {"8", "java"},
|
||||
"rust": {"9", "rs"},
|
||||
"rs": {"9", "rs"},
|
||||
"c#": {"10", "cs"},
|
||||
"cs": {"10", "cs"},
|
||||
"csharp": {"10", "cs"},
|
||||
"shell": {"10", "sh"},
|
||||
"bash": {"10", "sh"},
|
||||
"erlang": {"12", "erl"},
|
||||
"perl": {"14", "pl"},
|
||||
"python": {"15", "py3"},
|
||||
"py": {"15", "py3"},
|
||||
"swift": {"16", "swift"},
|
||||
"lua": {"17", "lua"},
|
||||
"pascal": {"18", "pas"},
|
||||
"kotlin": {"19", "kt"},
|
||||
"kt": {"19", "kt"},
|
||||
"r": {"80", "r"},
|
||||
"vb": {"84", "vb"},
|
||||
"typescript": {"1010", "ts"},
|
||||
"ts": {"1010", "ts"},
|
||||
}
|
||||
)
|
||||
var ro = runoob.NewRunOOB("b6365362a90ac2ac7098ba52c13e352b")
|
||||
|
||||
func init() {
|
||||
control.Register("runcode", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "在线代码运行: \n" +
|
||||
">runcode [language] [code block]\n" +
|
||||
Brief: "在线代码运行",
|
||||
Help: ">runcode [language] [code block]\n" +
|
||||
"模板查看: \n" +
|
||||
">runcode [language] help\n" +
|
||||
"支持语种: \n" +
|
||||
@@ -108,7 +31,7 @@ func init() {
|
||||
israw := ctx.State["regex_matched"].([]string)[1] != ""
|
||||
language := ctx.State["regex_matched"].([]string)[2]
|
||||
language = strings.ToLower(language)
|
||||
if runType, exist := table[language]; !exist {
|
||||
if _, exist := runoob.LangTable[language]; !exist {
|
||||
// 不支持语言
|
||||
ctx.SendChain(
|
||||
message.Text("> ", ctx.Event.Sender.NickName, "\n"),
|
||||
@@ -123,11 +46,11 @@ func init() {
|
||||
message.Text("> ", ctx.Event.Sender.NickName, " ", language, "-template:\n"),
|
||||
message.Text(
|
||||
">runcode ", language, "\n",
|
||||
templates[language],
|
||||
runoob.Templates[language],
|
||||
),
|
||||
)
|
||||
default:
|
||||
if output, err := runCode(block, runType); err != nil {
|
||||
if output, err := ro.Run(block, language, ""); err != nil {
|
||||
// 运行失败
|
||||
ctx.SendChain(
|
||||
message.Text("> ", ctx.Event.Sender.NickName, "\n"),
|
||||
@@ -135,6 +58,7 @@ func init() {
|
||||
)
|
||||
} else {
|
||||
// 运行成功
|
||||
output = cutTooLong(strings.Trim(output, "\n"))
|
||||
if israw {
|
||||
ctx.SendChain(message.Text(output))
|
||||
} else {
|
||||
@@ -149,59 +73,6 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func runCode(code string, runType [2]string) (string, error) {
|
||||
// 对菜鸟api发送数据并返回结果
|
||||
api := "https://tool.runoob.com/compile2.php"
|
||||
|
||||
header := http.Header{
|
||||
"Content-Type": []string{"application/x-www-form-urlencoded; charset=UTF-8"},
|
||||
"Referer": []string{"https://c.runoob.com/"},
|
||||
"User-Agent": []string{"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0"},
|
||||
}
|
||||
|
||||
val := url.Values{
|
||||
"code": []string{code},
|
||||
"token": []string{"4381fe197827ec87cbac9552f14ec62a"},
|
||||
"stdin": []string{""},
|
||||
"language": []string{runType[0]},
|
||||
"fileext": []string{runType[1]},
|
||||
}
|
||||
// 发送请求
|
||||
client := &http.Client{
|
||||
Timeout: 15 * time.Second,
|
||||
}
|
||||
request, _ := http.NewRequest("POST", api, strings.NewReader(val.Encode()))
|
||||
request.Header = header
|
||||
body, err := client.Do(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer body.Body.Close()
|
||||
if body.StatusCode != http.StatusOK {
|
||||
return "", errors.New("code not 200")
|
||||
}
|
||||
res, err := io.ReadAll(body.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 结果处理
|
||||
content := gjson.ParseBytes(res)
|
||||
if e := content.Get("errors").Str; e != "\n\n" {
|
||||
return "", errors.New(cutTooLong(clearNewLineSuffix(e)))
|
||||
}
|
||||
output := content.Get("output").Str
|
||||
|
||||
return cutTooLong(clearNewLineSuffix(output)), nil
|
||||
}
|
||||
|
||||
// 清除末尾多余的换行符
|
||||
func clearNewLineSuffix(text string) string {
|
||||
for strings.HasSuffix(text, "\n") {
|
||||
text = text[:len(text)-1]
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// 截断过长文本
|
||||
func cutTooLong(text string) string {
|
||||
temp := []rune(text)
|
||||
|
||||
@@ -31,8 +31,8 @@ var (
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("saucenao", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "搜图\n" +
|
||||
"- 以图搜图 | 搜索图片 | 以图识图[图片]\n" +
|
||||
Brief: "以图搜图",
|
||||
Help: "- 以图搜图 | 搜索图片 | 以图识图[图片]\n" +
|
||||
"- 搜图[P站图片ID]",
|
||||
PrivateDataFolder: "saucenao",
|
||||
})
|
||||
@@ -147,14 +147,14 @@ func init() { // 插件主体
|
||||
msg = append(msg, message.Image(pic))
|
||||
}
|
||||
msg = append(msg, message.Text("\n图源: ", result.Header.IndexName, binary.BytesToString(b)))
|
||||
ctx.Send(ctxext.FakeSenderForwardNode(ctx, msg...))
|
||||
ctx.Send(message.Message{ctxext.FakeSenderForwardNode(ctx, msg...)})
|
||||
if s > 80.0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ctx.SendChain(message.Text("请私聊发送 设置 saucenao api key [apikey] 以启用 saucenao 搜图, key 请前往 https://saucenao.com/user.php?page=search-api 获取"))
|
||||
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 {
|
||||
|
||||
@@ -34,7 +34,8 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("scale", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "叔叔的AI二次元图片放大\n- 放大图片[图片]",
|
||||
Brief: "二次元图片放大",
|
||||
Help: "- 放大图片[图片]",
|
||||
PrivateDataFolder: "scale",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
cachedir := engine.DataFolder()
|
||||
|
||||
@@ -83,7 +83,7 @@ func (sdb *scoredb) InsertOrUpdateScoreByUID(uid int64, score int) (err error) {
|
||||
}
|
||||
} else {
|
||||
err = db.Model(&scoretable{}).Where("uid = ? ", uid).Update(
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"score": score,
|
||||
}).Error
|
||||
}
|
||||
@@ -107,11 +107,11 @@ func (sdb *scoredb) InsertOrUpdateSignInCountByUID(uid int64, count int) (err er
|
||||
if err = db.Model(&signintable{}).First(&si, "uid = ? ", uid).Error; err != nil {
|
||||
// error handling...
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
db.Model(&signintable{}).Create(&si) // newUser not user
|
||||
err = db.Model(&signintable{}).Create(&si).Error // newUser not user
|
||||
}
|
||||
} else {
|
||||
err = db.Model(&signintable{}).Where("uid = ? ", uid).Update(
|
||||
map[string]interface{}{
|
||||
map[string]any{
|
||||
"count": count,
|
||||
}).Error
|
||||
}
|
||||
|
||||
@@ -3,17 +3,13 @@ package score
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Coloured-glaze/gg"
|
||||
"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/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/img/writer"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
@@ -21,20 +17,29 @@ import (
|
||||
"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"
|
||||
signinMax = 1
|
||||
// SCOREMAX 分数上限定为120
|
||||
SCOREMAX = 120
|
||||
// SCOREMAX 分数上限定为1200
|
||||
SCOREMAX = 1200
|
||||
)
|
||||
|
||||
var (
|
||||
levelArray = [...]int{0, 1, 2, 5, 10, 20, 35, 55, 75, 100, 120}
|
||||
engine = control.Register("score", &ctrl.Options[*zero.Ctx]{
|
||||
rankArray = [...]int{0, 10, 20, 50, 100, 200, 350, 550, 750, 1000, 1200}
|
||||
engine = control.Register("score", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "签到得分\n- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 查看分数排名",
|
||||
Brief: "签到",
|
||||
Help: "- 签到\n- 获得签到背景[@xxx] | 获得签到背景\n- 查看等级排名\n注:为跨群排名\n- 查看我的钱包\n- 查看钱包排名\n注:为本群排行,若群人数太多不建议使用该功能!!!",
|
||||
PrivateDataFolder: "score",
|
||||
})
|
||||
)
|
||||
@@ -49,25 +54,66 @@ func init() {
|
||||
}
|
||||
sdb = initialize(engine.DataFolder() + "score.db")
|
||||
}()
|
||||
zero.OnFullMatch("查看我的钱包").SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
uid := ctx.Event.UserID
|
||||
money := wallet.GetWalletOf(uid)
|
||||
ctx.SendChain(message.At(uid), message.Text("你的钱包当前有", money, "ATRI币"))
|
||||
})
|
||||
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")
|
||||
drawedFile := cachePath + strconv.FormatInt(uid, 10) + today + "signin.png"
|
||||
|
||||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png"
|
||||
|
||||
if si.Count >= signinMax && siUpdateTimeStr == today {
|
||||
switch {
|
||||
case si.Count >= signinMax && siUpdateTimeStr == today:
|
||||
// 如果签到时间是今天
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!"))
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
}
|
||||
return
|
||||
case siUpdateTimeStr != today:
|
||||
// 如果是跨天签到就清数据
|
||||
err := sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
err := initPic(picFile)
|
||||
// 更新签到次数
|
||||
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
|
||||
}
|
||||
score := wallet.GetWalletOf(uid)
|
||||
// 绘图
|
||||
err = initPic(picFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@@ -77,20 +123,12 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if siUpdateTimeStr != today {
|
||||
_ = sdb.InsertOrUpdateSignInCountByUID(uid, 0)
|
||||
}
|
||||
|
||||
_ = sdb.InsertOrUpdateSignInCountByUID(uid, si.Count+1)
|
||||
|
||||
// 避免图片过大,最大 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, true)
|
||||
@@ -115,32 +153,23 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
add := 1
|
||||
canvas.DrawString(nickName+fmt.Sprintf(" 小熊饼干+%d", add), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
|
||||
score := sdb.GetScoreByUID(uid).Score
|
||||
score += add
|
||||
if score > SCOREMAX {
|
||||
score = SCOREMAX
|
||||
ctx.SendChain(message.At(uid), message.Text("你获得的小熊饼干已经达到上限"))
|
||||
}
|
||||
_ = sdb.InsertOrUpdateScoreByUID(uid, score)
|
||||
level := getLevel(score)
|
||||
canvas.DrawString("当前小熊饼干:"+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(level), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
|
||||
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 nextLevelScore int
|
||||
if level < 10 {
|
||||
nextLevelScore = levelArray[level+1]
|
||||
var nextrankScore int
|
||||
if rank < 10 {
|
||||
nextrankScore = rankArray[rank+1]
|
||||
} else {
|
||||
nextLevelScore = SCOREMAX
|
||||
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(score)/float64(nextLevelScore), float64(back.Bounds().Size().Y)*0.1)
|
||||
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", score, nextLevelScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
|
||||
canvas.DrawString(fmt.Sprintf("%d/%d", level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
|
||||
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
@@ -174,7 +203,7 @@ func init() {
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile))
|
||||
})
|
||||
engine.OnFullMatch("查看分数排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
engine.OnFullMatch("查看等级排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
today := time.Now().Format("20060102")
|
||||
drawedFile := cachePath + today + "scoreRank.png"
|
||||
@@ -211,19 +240,111 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
bars := make([]chart.Value, len(st))
|
||||
for i, v := range st {
|
||||
bars[i].Value = float64(v.Score)
|
||||
bars[i].Label = ctx.CardOrNickName(v.UID)
|
||||
var bars []chart.Value
|
||||
for _, v := range st {
|
||||
if v.Score != 0 {
|
||||
bars = append(bars, chart.Value{
|
||||
Label: ctx.CardOrNickName(v.UID),
|
||||
Value: float64(v.Score),
|
||||
})
|
||||
}
|
||||
}
|
||||
err = chart.BarChart{
|
||||
Font: font,
|
||||
Title: "饼干排名",
|
||||
Title: "等级排名(1天只刷新1次)",
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 40,
|
||||
},
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 0,
|
||||
Max: math.Ceil(bars[0].Value/10) * 10,
|
||||
},
|
||||
},
|
||||
Height: 500,
|
||||
BarWidth: 50,
|
||||
Bars: bars,
|
||||
}.Render(chart.PNG, f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
_ = os.Remove(drawedFile)
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
engine.OnFullMatch("查看钱包排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
gid := strconv.FormatInt(ctx.Event.GroupID, 10)
|
||||
today := time.Now().Format("20060102")
|
||||
drawedFile := cachePath + gid + today + "walletRank.png"
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
return
|
||||
}
|
||||
// 无缓存获取群员列表
|
||||
temp := ctx.GetThisGroupMemberListNoCache().Array()
|
||||
var usergroup []int64
|
||||
for _, info := range temp {
|
||||
usergroup = append(usergroup, info.Get("user_id").Int())
|
||||
}
|
||||
// 获取钱包信息
|
||||
st, err := wallet.GetGroupWalletOf(usergroup, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if len(st) == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 当前没人获取过ATRI币"))
|
||||
return
|
||||
} else if len(st) > 10 {
|
||||
st = st[:10]
|
||||
}
|
||||
_, err = file.GetLazyData(text.FontFile, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
b, err := os.ReadFile(text.FontFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
font, err := freetype.ParseFont(b)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var bars []chart.Value
|
||||
for _, v := range st {
|
||||
if v.Money != 0 {
|
||||
bars = append(bars, chart.Value{
|
||||
Label: ctx.CardOrNickName(v.UID),
|
||||
Value: float64(v.Money),
|
||||
})
|
||||
}
|
||||
}
|
||||
err = chart.BarChart{
|
||||
Font: font,
|
||||
Title: "ATRI币排名(1天只刷新1次)",
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 40,
|
||||
},
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Range: &chart.ContinuousRange{
|
||||
Min: 0,
|
||||
Max: math.Ceil(bars[0].Value/10) * 10,
|
||||
},
|
||||
},
|
||||
Height: 500,
|
||||
BarWidth: 50,
|
||||
Bars: bars,
|
||||
@@ -256,8 +377,8 @@ func getHourWord(t time.Time) string {
|
||||
}
|
||||
}
|
||||
|
||||
func getLevel(count int) int {
|
||||
for k, v := range levelArray {
|
||||
func getrank(count int) int {
|
||||
for k, v := range rankArray {
|
||||
if count == v {
|
||||
return k
|
||||
} else if count < v {
|
||||
|
||||
@@ -53,8 +53,8 @@ var pool = &imgpool{
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("setutime", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "涩图\n" +
|
||||
"- 来份[涩图/二次元/风景/车万]\n" +
|
||||
Brief: "涩图",
|
||||
Help: "- 来份[涩图/二次元/风景/车万]\n" +
|
||||
"- 添加[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- 删除[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- >setu status",
|
||||
@@ -94,7 +94,8 @@ func init() { // 插件主体
|
||||
}
|
||||
}
|
||||
// 从缓冲池里抽一张
|
||||
if id := ctx.Send(ctxext.FakeSenderForwardNode(ctx, *pool.pop(imgtype))); id.ID() == 0 {
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, *pool.pop(imgtype))}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -12,15 +12,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
chpURL = "https://api.shadiao.app/chp"
|
||||
duURL = "https://api.shadiao.app/du"
|
||||
pyqURL = "https://api.shadiao.app/pyq"
|
||||
shadiaoURL = "https://api.shadiao.pro"
|
||||
chpURL = shadiaoURL + "/chp"
|
||||
duURL = shadiaoURL + "/du"
|
||||
pyqURL = shadiaoURL + "/pyq"
|
||||
yduanziURL = "http://www.yduanzi.com/duanzi/getduanzi"
|
||||
chayiURL = "https://api.lovelive.tools/api/SweetNothings/Web/0"
|
||||
ganhaiURL = "https://api.lovelive.tools/api/SweetNothings/Web/1"
|
||||
ergofabulousURL = "https://ergofabulous.org/luther/?"
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||
sdReferer = "https://api.shadiao.app/"
|
||||
sdReferer = shadiaoURL
|
||||
yduanziReferer = "http://www.yduanzi.com/?utm_source=shadiao.app"
|
||||
loveliveReferer = "https://lovelive.tools/"
|
||||
)
|
||||
@@ -28,8 +29,8 @@ const (
|
||||
var (
|
||||
engine = control.Register("shadiao", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "沙雕app\n" +
|
||||
"- 哄我\n- 渣我\n- 来碗绿茶\n- 发个朋友圈\n- 来碗毒鸡汤\n- 讲个段子\n- 马丁路德骂我\n",
|
||||
Brief: "沙雕app", // 也许可以更好
|
||||
Help: "- 哄我\n- 渣我\n- 来碗绿茶\n- 发个朋友圈\n- 来碗毒鸡汤\n- 讲个段子\n- 马丁路德骂我\n",
|
||||
})
|
||||
sdMap = map[string]string{"哄我": chpURL, "来碗毒鸡汤": duURL, "发个朋友圈": pyqURL}
|
||||
)
|
||||
|
||||
@@ -16,11 +16,12 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("shindan", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "shindan\n" +
|
||||
"- 今天是什么少女[@xxx]\n" +
|
||||
Brief: "shindan测定",
|
||||
Help: "- 今天是什么少女[@xxx]\n" +
|
||||
"- 异世界转生[@xxx]\n" +
|
||||
"- 卖萌[@xxx]\n" +
|
||||
"- 抽老婆[@xxx]",
|
||||
"- 抽老婆[@xxx]\n" +
|
||||
"- 黄油角色[@xxx]",
|
||||
})
|
||||
engine.OnPrefix("异世界转生", number(587874)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
engine.OnPrefix("今天是什么少女", number(162207)).SetBlock(true).Limit(ctxext.LimitByUser).Handle(handlepic)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user