Compare commits

..

61 Commits

Author SHA1 Message Date
源文雨
c18f9b8b72 🔖 v1.7.0-beta4 2023-03-12 12:28:53 +08:00
源文雨
0df465e1c6 fix: saucenao panic 2023-03-12 12:27:29 +08:00
himawari
8b010321d5 添加一言 (#616)
*  添加一言

* 🎨 优化随机数

* 🎨 更新包

* 🎨 优化随机结构

* 🎨 修改随机算法

---------

Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
2023-03-12 11:09:07 +08:00
Fox_white
e1591c44b6 Fix: Intn Panic when the len is 0 (#617) 2023-03-11 15:45:40 +08:00
源文雨
cc26eb1332 优化 ai_false diskstate 2023-03-11 11:48:40 +08:00
源文雨
366c7acb90 Update README.md 2023-03-10 22:26:33 +08:00
苜蓿紫
d8cb5206e8 update: drawlots (#613) 2023-03-09 22:14:26 +08:00
源文雨
90efebf02f 🔖 v1.7.0-beta3 2023-03-09 13:57:31 +08:00
源文雨
960cd3ad8b fix: drawlots 2023-03-09 13:56:51 +08:00
源文雨
09a3e807c9 🚑 默认不编译webui 2023-03-09 13:55:15 +08:00
苜蓿紫
fb2718b495 fix README.md (#612)
修正抽签readme
2023-03-09 13:29:31 +08:00
方柳煜
1550cb7fcc 新增多功能抽签插件 (#606) 2023-03-09 00:04:09 +08:00
源文雨
7b27bc8f7a update icon 2023-03-08 16:21:46 +08:00
github-actions[bot]
54598fbf54 🎨 改进代码样式 (#611)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-08 00:57:14 +08:00
himawari
bb844eaa40 Feature gui 20230219 (#597)
*  添加gui

* 🐛 添加位置

*  修改为0.0.0.0

*  添加webui说明

* 🎨 修改为本地

*  添加webui默认url

* 📝 修改readme

* 🎨 修改方法名

*  修改readme

* 🎨 修改命令

* 🎨 更新包

* 🎨 调整位置
2023-03-08 00:44:47 +08:00
源文雨
4ef6f584c9 Update README.md 2023-03-07 19:14:08 +08:00
源文雨
861b3cc82f 优化baiduaudit 2023-03-05 00:46:53 +08:00
源文雨
5226548cec 优化代码结构 2023-03-04 23:30:51 +08:00
github-actions[bot]
d41ae01f01 🎨 改进代码样式 (#609)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-04 19:57:35 +08:00
GenesisAN
e294059de4 fix 初始化未能获取数据的问题 (#602)
* fix 初始化未能获取数据的问题

* fix 添加读写锁

* fix lint

* fix lint

* change 改为全局锁
2023-03-04 19:54:56 +08:00
源文雨
84bc79eaa6 fix 2023-03-01 21:14:51 +08:00
源文雨
8f9a396821 fix: platform that fails to set vt100 2023-03-01 21:13:18 +08:00
源文雨
6f96c389c4 make ci happy 2023-03-01 16:21:18 +08:00
源文雨
c55e31ed6f 🔖 v1.7.0-beta1 2023-03-01 16:17:10 +08:00
源文雨
f3a0813fed edit README 2023-03-01 16:14:37 +08:00
源文雨
c1602c323d fix: md5 cat & add: updater cache 2023-03-01 16:10:24 +08:00
源文雨
1bceaa52ff fix winres 2023-03-01 14:49:34 +08:00
源文雨
86296a28df 优化 manifest 2023-03-01 14:35:13 +08:00
源文雨
fe9b5023f6 feat: add icon 2023-03-01 14:20:36 +08:00
源文雨
d68223f63d add winres 2023-03-01 12:45:35 +08:00
源文雨
1c274d6eb8 优化 banner 2023-03-01 12:22:14 +08:00
源文雨
0e52bbe0f7 fix: set title 2023-03-01 12:07:15 +08:00
源文雨
a177448315 fix: set title 2023-03-01 11:47:49 +08:00
源文雨
ca3ff1b522 fix: set title 2023-03-01 11:46:00 +08:00
源文雨
41f0b11469 fix: set title 2023-03-01 11:43:37 +08:00
源文雨
ba0e471a19 fix: set title 2023-03-01 11:39:47 +08:00
源文雨
84115a7316 优化 windows console 2023-03-01 11:26:21 +08:00
源文雨
4dc837854b fix windows console input 2023-03-01 11:11:01 +08:00
Fox_white
64f9e309ef Feat: Better Setup Console (#601)
* Feat: Better Setup Console

* Feat: Better Setup Console
2023-02-28 20:18:10 +08:00
源文雨
67a1050df6 make lint happy 2023-02-28 18:33:36 +08:00
源文雨
d85865825e 优化windows输出 2023-02-28 18:29:39 +08:00
源文雨
2704d3e7d4 优化color 2023-02-28 12:15:54 +08:00
源文雨
0944fc7854 优化arch 2023-02-28 11:45:03 +08:00
源文雨
611c275092 🔖 v1.6.2 2023-02-27 21:01:31 +08:00
莫思潋
e3e991e6ab fix: ent->enr (#600) 2023-02-27 19:45:17 +08:00
源文雨
f2cebcf95a edit help 2023-02-27 14:14:02 +08:00
源文雨
4aca16a393 make lint happy 2023-02-27 14:11:07 +08:00
源文雨
891bbb96aa make lint happy 2023-02-27 14:10:44 +08:00
源文雨
d60acd3a47 update to go1.20 2023-02-27 13:59:31 +08:00
源文雨
7dc6499127 edit readme 2023-02-27 13:54:18 +08:00
源文雨
f28e746652 aireply add chatgpt 2023-02-27 13:52:12 +08:00
源文雨
3c905d9061 moegoe 恢复原 API 2023-02-27 13:22:31 +08:00
himawari
091d3170fc Feature zbpp bilibilipush 20230224 (#599)
* 🔥 删除小鸡词典

*  添加新插件和修改bilibilipush问题

* 🎨 去掉多余结构

* 🎨 简化语句
2023-02-25 19:48:13 +08:00
源文雨
bdc4138d78 fix: fortune 2023-02-24 11:29:15 +08:00
源文雨
e231235ed1 fix: 自检 2023-02-19 20:05:03 +08:00
源文雨
1795b9196b fix: 自检 2023-02-19 20:03:33 +08:00
源文雨
d5d0563544 fix: 自检 2023-02-19 19:52:45 +08:00
源文雨
723b7a9857 fix: 自检 2023-02-19 19:40:17 +08:00
源文雨
6a0a16662e fix: slow 自检 2023-02-19 19:30:47 +08:00
github-actions[bot]
f82ba852ba 🎨 改进代码样式 (#588)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-17 13:07:21 +08:00
MoeMagicMango
180945670b feat:新设计的签到 (#587) 2023-02-17 13:03:44 +08:00
47 changed files with 2170 additions and 800 deletions

View File

@@ -28,7 +28,7 @@ jobs:
- name: Setup Go environment
uses: actions/setup-go@master
with:
go-version: 1.19
go-version: '1.20'
- name: Cache downloaded module
uses: actions/cache@master
with:

View File

@@ -8,7 +8,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@master
with:
go-version: 1.19
go-version: '1.20'
- name: Check out code into the Go module directory
uses: actions/checkout@master

View File

@@ -8,7 +8,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@master
with:
go-version: 1.19
go-version: '1.20'
- name: Check out code into the Go module directory
uses: actions/checkout@master

View File

@@ -16,12 +16,12 @@ jobs:
- name: Set up Go
uses: actions/setup-go@master
with:
go-version: '1.19'
go-version: '1.20'
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@master
with:
version: latest
args: release --rm-dist
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ go-zero*
nohup.out
zerobot
ZeroBot-Plugin*
*.syso

View File

@@ -59,7 +59,7 @@ run:
tests: false
skip-dirs:
- order
go: '1.19'
go: '1.20'
# output configuration options
output:

View File

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

View File

@@ -1,7 +1,6 @@
<div align="center">
<a href="https://crypko.ai/crypko/5k8HyUVTq5421/">
<img src=".github/hua_nobg_512.gif" alt="椛" width = "400">
</a><br>
<br>
<h1>ZeroBot-Plugin</h1>
@@ -10,7 +9,7 @@
ZeroBot-Plugin 是 ZeroBot 的 实用插件合集<br><br>
<img src="http://cmoe.azurewebsites.net/cmoe?name=ZeroBot-Plugin&theme=r34" /><br>
<img src="https://counter.seku.su/cmoe?name=ZeroBot-Plugin&theme=r34" /><br>
[![miraigo](https://img.shields.io/badge/OneBot-MiraiGo-green.svg?style=social&logo=appveyor)](https://github.com/Mrs4s/MiraiGo)
[![oicq](https://img.shields.io/badge/OneBot-OICQ-green.svg?style=social&logo=appveyor)](https://github.com/takayama-lily/oicq)
@@ -18,7 +17,7 @@
[![go](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin?style=flat-square&logo=go)](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
[![onebot](https://img.shields.io/badge/onebot-v11-black?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAABwCAMAAADxPgR5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAxQTFRF////29vbr6+vAAAAk1hCcwAAAAR0Uk5T////AEAqqfQAAAKcSURBVHja7NrbctswDATQXfD//zlpO7FlmwAWIOnOtNaTM5JwDMa8E+PNFz7g3waJ24fviyDPgfhz8fHP39cBcBL9KoJbQUxjA2iYqHL3FAnvzhL4GtVNUcoSZe6eSHizBcK5LL7dBr2AUZlev1ARRHCljzRALIEog6H3U6bCIyqIZdAT0eBuJYaGiJaHSjmkYIZd+qSGWAQnIaz2OArVnX6vrItQvbhZJtVGB5qX9wKqCMkb9W7aexfCO/rwQRBzsDIsYx4AOz0nhAtWu7bqkEQBO0Pr+Ftjt5fFCUEbm0Sbgdu8WSgJ5NgH2iu46R/o1UcBXJsFusWF/QUaz3RwJMEgngfaGGdSxJkE/Yg4lOBryBiMwvAhZrVMUUvwqU7F05b5WLaUIN4M4hRocQQRnEedgsn7TZB3UCpRrIJwQfqvGwsg18EnI2uSVNC8t+0QmMXogvbPg/xk+Mnw/6kW/rraUlvqgmFreAA09xW5t0AFlHrQZ3CsgvZm0FbHNKyBmheBKIF2cCA8A600aHPmFtRB1XvMsJAiza7LpPog0UJwccKdzw8rdf8MyN2ePYF896LC5hTzdZqxb6VNXInaupARLDNBWgI8spq4T0Qb5H4vWfPmHo8OyB1ito+AysNNz0oglj1U955sjUN9d41LnrX2D/u7eRwxyOaOpfyevCWbTgDEoilsOnu7zsKhjRCsnD/QzhdkYLBLXjiK4f3UWmcx2M7PO21CKVTH84638NTplt6JIQH0ZwCNuiWAfvuLhdrcOYPVO9eW3A67l7hZtgaY9GZo9AFc6cryjoeFBIWeU+npnk/nLE0OxCHL1eQsc1IciehjpJv5mqCsjeopaH6r15/MrxNnVhu7tmcslay2gO2Z1QfcfX0JMACG41/u0RrI9QAAAABJRU5ErkJggg==)](https://t.me/zerobotplugin)
[![zerobot](https://img.shields.io/badge/zerobot-v1.6.7-black?style=flat-square&logo=go)](https://github.com/wdvxdr1123/ZeroBot)
[![zerobot](https://img.shields.io/badge/zerobot-v1.6.10-black?style=flat-square&logo=go)](https://github.com/wdvxdr1123/ZeroBot)
[![license](https://img.shields.io/github/license/FloatTech/ZeroBot-Plugin.svg?style=flat-square&logo=gnu)](https://raw.githubusercontent.com/FloatTech/ZeroBot-Plugin/master/LICENSE)
[![tencent-qq](https://img.shields.io/badge/group-1048452984-red?style=flat-square&logo=tencent-qq)](https://jq.qq.com/?_wv=1027&k=QMb7x1mM)
[![telegram](https://img.shields.io/badge/Telegram-click%20me-informational?style=flat-square&logo=telegram)](https://t.me/zerobotplugin)
@@ -38,15 +37,18 @@
> 如果您对开发插件感兴趣,欢迎加入[ZeroBot-Plugin-Playground](https://github.com/FloatTech/ZeroBot-Plugin-Playground)
> webui持续开发中, 欢迎加入[ZeroBot-Plugin-Webui](https://github.com/FloatTech/ZeroBot-Plugin-Webui)
## 命令行参数
> `[]`代表是可选参数
```bash
zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
zerobot [-h] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
```
- **-h**: 显示帮助
- **-n nickname**: 设置默认昵称,默认为`椛椛`
- **-t token**: 设置`AccessToken`,默认为空
- **-u url**: 设置`Url`,默认为`ws://127.0.0.1:6700`
- ~~**-g url**~~(默认禁用): 设置`webui url`,默认为`127.0.0.1:3000`
- **-p prefix**: 设置命令前缀,默认为`/`
- **-d|w**: 开启 debug | warning 级别及以上日志输出
- **-c config.json**: 从`config.json`加载`bot`配置
@@ -86,8 +88,12 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.j
## 功能
> 在编译时,以下功能除插件控制外,均可通过注释`main.go`中的相应`import`而物理禁用,减小插件体积。
> 通过插件控制,还可动态管理某个功能在某个群的打开/关闭。
> 插件的优先级为`import`的先后顺序
> 插件的优先级为`import`的先后顺序。
> `webui`默认禁用不编译,打开后会增加程序体积。
<details>
<summary>插件控制</summary>
@@ -130,9 +136,14 @@ zerobot [-h] [-n nickname] [-t token] [-u url] [-p prefix] [-d|w] [-c|s config.j
- [x] /服务列表
- [x] /设置服务列表显示行数 xx
- [x] /设置服务列表显示行数 xx (默认值为 9, 该设置仅运行时有效, zbp 重启后重置)
- [x] (默认禁用) /设置webui用户名 zerobot 密码 123456
- [x] (默认禁用) /webui启动
- [x] (默认禁用) /webui停止
默认值为9,该设置仅运行时有效,zbp重启后重置
- [x] @Bot 插件冲突检测 (会在本群发送一条消息并在约 1s 后撤回以检测其它同类 bot 中已启用的插件并禁用)
</details>
@@ -620,6 +631,14 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 磕cp大老师 雪乃
</details>
<details>
<summary>今日早报</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews"`
- [x] 今日早报
</details>
<details>
<summary>DeepDanbooru二次元图标签识别</summary>
@@ -640,6 +659,24 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 教你一篇小作文[作文]
</details>
<details>
<summary>多功能抽签</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots"`
支持图包文件夹和gif抽签
- [x] (刷新)抽签列表
- [x] 抽[签名]签
- [x] 看签[gif签名]
- [x] 加签[签名][gif图片]
- [x] 删签[gif签名]
</details>
<details>
<summary>女装</summary>
@@ -784,6 +821,16 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 来点黑丝/白丝/jk/巨乳/足控/网红
</details>
<details>
<summary>一言</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/hitokoto"`
- [x] 一言[xxx]
- [x] 系列一言
</details>
<details>
<summary>炉石</summary>
@@ -872,6 +919,14 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 喝奶茶绝绝子 | 绝绝子吃饭
</details>
<details>
<summary>疯狂星期四</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/kfccrazythursday"`
- [x] 疯狂星期四
</details>
<details>
<summary>kokomi原神面板</summary>
@@ -1283,6 +1338,16 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 更新vtb
</details>
<details>
<summary>vtb点歌</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic"`
- [x] vtb点歌
- [x] vtb随机点歌
</details>
<details>
<summary>钱包</summary>
@@ -1481,7 +1546,9 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] @Bot 任意文本(任意一句话回复)
- [x] 设置回复模式[青云客 | 小爱]
- [x] 设置回复模式[青云客 | 小爱 | ChatGPT]
- [x] 设置 ChatGPT api key xxx
</details>

14
console/console_ansi.go Normal file
View File

@@ -0,0 +1,14 @@
//go:build !windows
// Package console sets console's behavior on init
package console
import (
"fmt"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
)
func init() {
fmt.Print("\033]0;ZeroBot-Blugin " + banner.Version + " " + banner.Copyright + "\007")
}

144
console/console_windows.go Normal file
View File

@@ -0,0 +1,144 @@
// Package console sets console's behavior on init
package console
import (
"bytes"
"os"
"strings"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"github.com/sirupsen/logrus"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
)
var (
//go:linkname modkernel32 golang.org/x/sys/windows.modkernel32
modkernel32 *windows.LazyDLL
procSetConsoleTitle = modkernel32.NewProc("SetConsoleTitleW")
)
//go:linkname errnoErr golang.org/x/sys/windows.errnoErr
func errnoErr(e syscall.Errno) error
func setConsoleTitle(title string) (err error) {
var p0 *uint16
p0, err = syscall.UTF16PtrFromString(title)
if err != nil {
return
}
r1, _, e1 := syscall.Syscall(procSetConsoleTitle.Addr(), 1, uintptr(unsafe.Pointer(p0)), 0, 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func init() {
stdin := windows.Handle(os.Stdin.Fd())
var mode uint32
err := windows.GetConsoleMode(stdin, &mode)
if err != nil {
panic(err)
}
mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式
mode |= windows.ENABLE_EXTENDED_FLAGS // 启用扩展标志
mode &^= windows.ENABLE_MOUSE_INPUT // 禁用鼠标输入
mode |= windows.ENABLE_PROCESSED_INPUT // 启用控制输入
mode &^= windows.ENABLE_INSERT_MODE // 禁用插入模式
mode |= windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT // 启用输入回显&逐行输入
mode &^= windows.ENABLE_WINDOW_INPUT // 禁用窗口输入
mode &^= windows.ENABLE_VIRTUAL_TERMINAL_INPUT // 禁用虚拟终端输入
err = windows.SetConsoleMode(stdin, mode)
if err != nil {
panic(err)
}
stdout := windows.Handle(os.Stdout.Fd())
err = windows.GetConsoleMode(stdout, &mode)
if err != nil {
panic(err)
}
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING // 启用虚拟终端处理
mode |= windows.ENABLE_PROCESSED_OUTPUT // 启用处理后的输出
err = windows.SetConsoleMode(stdout, mode)
// windows 带颜色 log 自定义格式
logrus.SetFormatter(&logFormat{hasColor: err == nil})
if err != nil {
logrus.Warnln("VT100设置失败, 将以无色模式输出")
}
err = setConsoleTitle("ZeroBot-Blugin " + banner.Version + " " + banner.Copyright)
if err != nil {
panic(err)
}
}
const (
colorCodePanic = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
colorCodeFatal = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
colorCodeError = "\x1b[31m" // color.Style{color.Red}.String()
colorCodeWarn = "\x1b[33m" // color.Style{color.Yellow}.String()
colorCodeInfo = "\x1b[37m" // color.Style{color.White}.String()
colorCodeDebug = "\x1b[32m" // color.Style{color.Green}.String()
colorCodeTrace = "\x1b[36m" // color.Style{color.Cyan}.String()
colorReset = "\x1b[0m"
)
// logFormat specialize for zbp
type logFormat struct {
hasColor bool
}
// Format implements logrus.Formatter
func (f logFormat) Format(entry *logrus.Entry) ([]byte, error) {
buf := new(bytes.Buffer)
buf.WriteByte('[')
if f.hasColor {
buf.WriteString(getLogLevelColorCode(entry.Level))
}
buf.WriteString(strings.ToUpper(entry.Level.String()))
if f.hasColor {
buf.WriteString(colorReset)
}
buf.WriteString("] ")
buf.WriteString(entry.Message)
buf.WriteString(" \n")
return buf.Bytes(), nil
}
// getLogLevelColorCode 获取日志等级对应色彩code
func getLogLevelColorCode(level logrus.Level) string {
switch level {
case logrus.PanicLevel:
return colorCodePanic
case logrus.FatalLevel:
return colorCodeFatal
case logrus.ErrorLevel:
return colorCodeError
case logrus.WarnLevel:
return colorCodeWarn
case logrus.InfoLevel:
return colorCodeInfo
case logrus.DebugLevel:
return colorCodeDebug
case logrus.TraceLevel:
return colorCodeTrace
default:
return colorCodeInfo
}
}

2
data

Submodule data updated: 5e0fa81c3b...b9848c9a4e

20
go.mod
View File

@@ -1,18 +1,18 @@
module github.com/FloatTech/ZeroBot-Plugin
go 1.19
go 1.20
require (
github.com/Baidu-AIP/golang-sdk v1.1.1
github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194
github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d
github.com/FloatTech/AnimeAPI v1.6.1-0.20230312042320-53aa800c2c58
github.com/FloatTech/floatbox v0.0.0-20230312033609-f3826d7c8d00
github.com/FloatTech/gg v1.1.2
github.com/FloatTech/imgfactory v0.2.2-0.20230215052637-9f7b05520ca9
github.com/FloatTech/rendercard v0.0.10-0.20230215092509-ff0745852f23
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9
github.com/FloatTech/sqlite v1.5.7
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52
github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16
github.com/FloatTech/zbpctrl v1.5.3-0.20230301071613-f2c5c97cec88
github.com/FloatTech/zbputils v1.6.2-0.20230312042148-dd8632bf31f5
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
github.com/antchfx/htmlquery v1.2.5
@@ -22,7 +22,7 @@ require (
github.com/fumiama/ahsai v0.1.0
github.com/fumiama/cron v1.3.0
github.com/fumiama/go-base16384 v1.6.4
github.com/fumiama/go-registry v0.2.5
github.com/fumiama/go-registry v0.2.6
github.com/fumiama/gotracemoe v0.0.3
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430
@@ -37,9 +37,10 @@ require (
github.com/sirupsen/logrus v1.9.0
github.com/tidwall/gjson v1.14.4
github.com/wcharczuk/go-chart/v2 v2.1.0
github.com/wdvxdr1123/ZeroBot v1.6.9
github.com/wdvxdr1123/ZeroBot v1.6.10
gitlab.com/gomidi/midi/v2 v2.0.25
golang.org/x/image v0.3.0
golang.org/x/sys v0.4.0
golang.org/x/text v0.6.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -67,6 +68,7 @@ require (
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pkumza/numcn v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/quic-go/qpack v0.4.0 // indirect
@@ -85,8 +87,8 @@ require (
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect
golang.org/x/mod v0.6.0 // indirect
golang.org/x/net v0.4.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/tools v0.2.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
modernc.org/libc v1.21.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.4.0 // indirect

38
go.sum
View File

@@ -2,24 +2,24 @@ github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhv
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194 h1:+p85V0fdZNt3UoKreBeI6S3IOPvNmU5/Fnn39ipSkVk=
github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194/go.mod h1:LCiKZivPVazRRCnnADQfIBFZiIPHHCFqaCpwZWsFehI=
github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d h1:vVqMO5Kejt5pueuZvBxfX+psa7UwE110TpITf5eV7Zw=
github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d/go.mod h1:OoZE4Ra7olpFaJSrlD6mcyT4chPLg9QBRE1pzTC8R84=
github.com/FloatTech/AnimeAPI v1.6.1-0.20230312042320-53aa800c2c58 h1:26/j1fmDkBwk1UwRqMDV8+IC9HMz+9xbncK/Mx3t2YQ=
github.com/FloatTech/AnimeAPI v1.6.1-0.20230312042320-53aa800c2c58/go.mod h1:A+qtDCzq4rtwEcxzB1boBX8wjHxYWTFyafxiq0sNZyA=
github.com/FloatTech/floatbox v0.0.0-20230312033609-f3826d7c8d00 h1:KvQd0IaJqBPkc4mpyldX9UcRVlUPVazlcmS79LU0pJ8=
github.com/FloatTech/floatbox v0.0.0-20230312033609-f3826d7c8d00/go.mod h1:0l1xHjcTlONupyOY5lB5PY6kFWFMHQh89e1Zqm5QZlo=
github.com/FloatTech/gg v1.1.2 h1:YolgOYg3uDHc1+g0bLtt6QuRA/pvLn+b9IBCIhOOX88=
github.com/FloatTech/gg v1.1.2/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI=
github.com/FloatTech/imgfactory v0.2.2-0.20230215052637-9f7b05520ca9 h1:Havq0z/N79KeD50L7ms+Hv8F4Sw98Dt8lXM8jECp04o=
github.com/FloatTech/imgfactory v0.2.2-0.20230215052637-9f7b05520ca9/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
github.com/FloatTech/rendercard v0.0.10-0.20230215092509-ff0745852f23 h1:cffHoKe1wlm1kqmtpJ4ur/7h+E3gR1fzbaPkXAlVj38=
github.com/FloatTech/rendercard v0.0.10-0.20230215092509-ff0745852f23/go.mod h1:dsENe3jJB1LHbshfoGnIAU9V6+N1CKbf2y+RUeAPC3A=
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 h1:hffajvmQFfP68U6wUwHemPuuwCUoss+SEFfoLYwbGwE=
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9/go.mod h1:NBFPhWae4hqVMeG8ELBBnUQkKce3nDjkljVn6PdiUNs=
github.com/FloatTech/sqlite v1.5.7 h1:Bvo4LSojcZ6dVtbHrkqvt6z4v8e+sj0G5PSUIvdawsk=
github.com/FloatTech/sqlite v1.5.7/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52 h1:BrStRXeosWh8L0iA/EjPd8w6xNexDkqki39ITZko/9Q=
github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52/go.mod h1:qqMLUwR7tKpqnAqsgI7aZbn0hbs2FEVF4ylMXqIpBdY=
github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16 h1:fOnI0V//DOW62vAhnC1a+qDMnlbJIAIiUHVX7CaUk5s=
github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16/go.mod h1:Lo7y67u9EGt7l3ZBavc5bbryEIaeRYfbVy9KWIw6qk4=
github.com/FloatTech/zbpctrl v1.5.3-0.20230301071613-f2c5c97cec88 h1:jdTWiYXGtYZhxIn9oGYkObNVa8GtJvki+ihsoMlLJPs=
github.com/FloatTech/zbpctrl v1.5.3-0.20230301071613-f2c5c97cec88/go.mod h1:8IRMtcWhK4S8QdpStJqXQZtIBgAqUH72Imq3BQ45TWg=
github.com/FloatTech/zbputils v1.6.2-0.20230312042148-dd8632bf31f5 h1:/Zm5n+2bIpL5how66638nA0NIy+OQOgiCQuEgDYodpQ=
github.com/FloatTech/zbputils v1.6.2-0.20230312042148-dd8632bf31f5/go.mod h1:0xorZ1IN/UYFCUyUGwHyfA4azQHvDjk0M3F4Mh+gFss=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
@@ -60,8 +60,8 @@ github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
github.com/fumiama/go-base16384 v1.6.4 h1:rYDRwD/th2cG4U7QLokpzmST1cCxZGXtHmolOUePt5o=
github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
github.com/fumiama/go-registry v0.2.5 h1:Y6tnHnTThQPv7E4JPM2vBprU+4EQw/LEDO33HCmxgI4=
github.com/fumiama/go-registry v0.2.5/go.mod h1:GP45kejHuDLFxcWdksrt75r5rHBqYwtfeUl3JzGWxfQ=
github.com/fumiama/go-registry v0.2.6 h1:+vEeBUwa1+GC87ujW3Km42fi8O/H7QcpVJWu1iuGNh0=
github.com/fumiama/go-registry v0.2.6/go.mod h1:HjYagPZXzR2xCCxaSQerqX7JRzC0yiv2kslDdBiTq/g=
github.com/fumiama/go-simple-protobuf v0.1.0 h1:rLzJgNqB6LHNDVMl81yyNt6ZKziWtVfu+ioF0edlEVw=
github.com/fumiama/go-simple-protobuf v0.1.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
@@ -126,8 +126,11 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
@@ -151,6 +154,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -198,8 +203,8 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
github.com/wdvxdr1123/ZeroBot v1.6.9 h1:vaFqtIXpyeU60xEddg4EsN6cX6cpB3MKhLbe/MQ5OVw=
github.com/wdvxdr1123/ZeroBot v1.6.9/go.mod h1:T5kD5vLi/YxL/fyDOCOaawi96LRBdJjcXh2CIjDyFfg=
github.com/wdvxdr1123/ZeroBot v1.6.10 h1:exmPWNjWtOMLgLQW/svQDybExRJAfDkjpE3S2U6fBOY=
github.com/wdvxdr1123/ZeroBot v1.6.10/go.mod h1:y29UIOy0RD3P+0meDNIWRhcJF3jtWPN9xP9hgt/AJAU=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
@@ -293,9 +298,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,10 +0,0 @@
package kanban
// Version ...
var Version = "v1.6.2-beta4"
// Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - 2023-02-15 17:27:40 +0800 CST\n" +
"* Copyright © 2020 - 2023 FloatTech. All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"

15
kanban/banner/banner.go Normal file
View File

@@ -0,0 +1,15 @@
// Code generated by kanban/gen. DO NOT EDIT.
package banner
// Version ...
var Version = "v1.7.0-beta4"
// Copyright ...
var Copyright = "© 2020 - 2023 FloatTech"
// Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - 2023-03-12 12:28:19 +0800 CST\n" +
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"

View File

@@ -10,22 +10,27 @@ import (
"time"
)
const banner = `package kanban
const banner = `// Code generated by kanban/gen. DO NOT EDIT.
package banner
// Version ...
var Version = "%s"
// Copyright ...
var Copyright = "© 2020 - %d FloatTech"
// Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - %s\n" +
"* Copyright © 2020 - %d FloatTech. All Rights Reserved.\n" +
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
`
const timeformat = `2006-01-02 15:04:05 +0800 CST`
func main() {
f, err := os.Create("banner.go")
f, err := os.Create("banner/banner.go")
if err != nil {
panic(err)
}
@@ -39,7 +44,7 @@ func main() {
}
s := strings.Split(vartag.String(), "\n")
now := time.Now()
_, err = fmt.Fprintf(f, banner, s[len(s)-2], now.Format(timeformat), now.Year())
_, err = fmt.Fprintf(f, banner, s[len(s)-2], now.Year(), now.Format(timeformat))
if err != nil {
panic(err)
}

View File

@@ -3,18 +3,17 @@ package kanban
import (
"fmt"
"sync"
"github.com/FloatTech/zbputils/control"
"github.com/fumiama/go-registry"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
)
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/kanban/gen
var once sync.Once
func init() {
once.Do(PrintBanner)
PrintBanner()
}
var reg = registry.NewRegReader("reilia.fumiama.top:32664", control.Md5File, "fumiama")
@@ -23,7 +22,7 @@ var reg = registry.NewRegReader("reilia.fumiama.top:32664", control.Md5File, "fu
func PrintBanner() {
fmt.Print(
"\n======================[ZeroBot-Plugin]======================",
"\n", Banner, "\n",
"\n", banner.Banner, "\n",
"----------------------[ZeroBot-公告栏]----------------------",
"\n", Kanban(), "\n",
"============================================================\n\n",

192
main.go
View File

@@ -7,10 +7,14 @@ import (
"fmt"
"math/rand"
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 在最前打印 banner
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
// ----------------------插件优先级按顺序从高到低---------------------- //
@@ -56,89 +60,93 @@ import (
// vvvvvvvvvvvvvv //
// vvvv //
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_false" // 服务器监控
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint" // ai绘图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/autowithdraw" // 触发者撤回时也自动撤回
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/book_review" // 哀伤雪刃吧推书记录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi" // 藏头诗
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chouxianghua" // 说抽象话
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress" // 女装
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/event" // 好友申请群聊邀请事件处理
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/funny" // 笑话
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/genshin" // 原神抽卡
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi" // 黑丝
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami" // 兽语加密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jikipedia" // 小鸡词典
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom" // 日语听力学习材料
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe" // 日韩 VITS 模型拟声
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu_calendar" // 摸鱼人日历
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativesetu" // 本地涩图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife" // 本地老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nbnhhsh" // 拼音首字母缩写释义工具
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo" // 日语语法学习
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/quan" // QQ权重查询
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale" // 叔叔的AI二次元图片放大
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime" // 来份涩
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shadiao" // 沙雕app
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shindan" // 测定
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tarot" // 抽塔罗牌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtb_quotation" // vtb语录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_false" // 服务器监控
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint" // ai绘图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/autowithdraw" // 触发者撤回时也自动撤回
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/book_review" // 哀伤雪刃吧推书记录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi" // 藏头诗
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chouxianghua" // 说抽象话
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress" // 女装
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle" // 漂流瓶
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/event" // 好友申请群聊邀请事件处理
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/funny" // 笑话
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/genshin" // 原神抽卡
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi" // 黑丝
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hitokoto" // 一言
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami" // 兽语加密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom" // 日语听力学习材料
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/kfccrazythursday" // 疯狂星期四
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe" // 日韩 VITS 模型拟声
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu_calendar" // 摸鱼人日历
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativesetu" // 本地涩图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife" // 本地老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nbnhhsh" // 拼音首字母缩写释义工具
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo" // 日语语法学习
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/quan" // QQ权重查询
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale" // 叔叔的AI二次元图片放大
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime" // 来份涩图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shadiao" // 沙雕app
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shindan" // 测定
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tarot" // 抽塔罗牌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtb_quotation" // vtb语录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic" // vtb点歌
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI" // 百度文心AI画图
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count" // 聊天热词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf" // 鬼东西
@@ -184,6 +192,10 @@ import (
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/driver"
"github.com/wdvxdr1123/ZeroBot/message"
// webctrl "github.com/FloatTech/zbputils/control/web"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
// -----------------------以上为内置依赖,勿动------------------------ //
)
@@ -201,6 +213,7 @@ func init() {
d := flag.Bool("d", false, "Enable debug level log and higher.")
w := flag.Bool("w", false, "Enable warning level log and higher.")
h := flag.Bool("h", false, "Display this help.")
// g := flag.String("g", "127.0.0.1:3000", "Set webui url.")
// 直接写死 AccessToken 时,请更改下面第二个参数
token := flag.String("t", "", "Set AccessToken of WSClient.")
// 直接写死 URL 时,请更改下面第二个参数
@@ -286,18 +299,23 @@ func init() {
logrus.Infoln("[main] 配置文件已保存到", *save)
os.Exit(0)
}
// 启用 webui
// go webctrl.RunGui(*g)
}
func main() {
rand.Seed(time.Now().UnixNano()) // 全局 seed其他插件无需再 seed
if !strings.Contains(runtime.Version(), "go1.2") { // go1.20之前版本需要全局 seed其他插件无需再 seed
rand.Seed(time.Now().UnixNano()) //nolint: staticcheck
}
// 帮助
zero.OnFullMatchGroup([]string{"/help", ".help", "菜单"}, zero.OnlyToMe).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(kanban.Banner, "\n发送\"/服务列表\"查看 bot 功能"))
ctx.SendChain(message.Text(banner.Banner, "\n管理发送\"/服务列表\"查看 bot 功能\n发送\"/用法name\"查看功能用法"))
})
zero.OnFullMatch("查看zbp公告", zero.OnlyToMe, zero.AdminPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(kanban.Kanban()))
ctx.SendChain(message.Text(strings.ReplaceAll(kanban.Kanban(), "\t", "")))
})
zero.RunAndBlock(&config.Z, process.GlobalInitMutex.Unlock)
}

View File

@@ -1,70 +0,0 @@
//go:build windows
// +build windows
package main
import (
"bytes"
"strings"
"github.com/sirupsen/logrus"
)
func init() {
// windows 带颜色 log 自定义格式
logrus.SetFormatter(&LogFormat{})
}
const (
colorCodePanic = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
colorCodeFatal = "\x1b[1;31m" // color.Style{color.Bold, color.Red}.String()
colorCodeError = "\x1b[31m" // color.Style{color.Red}.String()
colorCodeWarn = "\x1b[33m" // color.Style{color.Yellow}.String()
colorCodeInfo = "\x1b[37m" // color.Style{color.White}.String()
colorCodeDebug = "\x1b[32m" // color.Style{color.Green}.String()
colorCodeTrace = "\x1b[36m" // color.Style{color.Cyan}.String()
colorReset = "\x1b[0m"
)
// LogFormat specialize for zbp
type LogFormat struct{}
// Format implements logrus.Formatter
func (f LogFormat) Format(entry *logrus.Entry) ([]byte, error) {
buf := new(bytes.Buffer)
buf.WriteString(getLogLevelColorCode(entry.Level))
buf.WriteByte('[')
buf.WriteString(strings.ToUpper(entry.Level.String()))
buf.WriteString("] ")
buf.WriteString(entry.Message)
buf.WriteString(" \n")
buf.WriteString(colorReset)
return buf.Bytes(), nil
}
// getLogLevelColorCode 获取日志等级对应色彩code
func getLogLevelColorCode(level logrus.Level) string {
switch level {
case logrus.PanicLevel:
return colorCodePanic
case logrus.FatalLevel:
return colorCodeFatal
case logrus.ErrorLevel:
return colorCodeError
case logrus.WarnLevel:
return colorCodeWarn
case logrus.InfoLevel:
return colorCodeInfo
case logrus.DebugLevel:
return colorCodeDebug
case logrus.TraceLevel:
return colorCodeTrace
default:
return colorCodeInfo
}
}

View File

@@ -10,7 +10,9 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"unsafe"
"github.com/FloatTech/AnimeAPI/bilibili"
"github.com/FloatTech/floatbox/file"
@@ -31,7 +33,7 @@ import (
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/FloatTech/ZeroBot-Plugin/kanban"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
@@ -42,7 +44,11 @@ const (
referer = "https://weibo.com/"
)
var boottime = time.Now()
var (
boottime = time.Now()
bgdata *[]byte
bgcount uintptr
)
func init() { // 插件主体
engine := control.Register("aifalse", &ctrl.Options[*zero.Ctx]{
@@ -134,14 +140,22 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
return
}
url, err := bilibili.GetRealURL(backgroundURL)
if err != nil {
return
}
data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
if err != nil {
return
dldata := (*[]byte)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&bgdata))))
if dldata == (*[]byte)(nil) || uintptr(time.Since(boottime).Hours()/24) >= atomic.LoadUintptr(&bgcount) {
url, err1 := bilibili.GetRealURL(backgroundURL)
if err1 != nil {
return nil, err1
}
data, err1 := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
if err1 != nil {
return nil, err1
}
atomic.AddUintptr(&bgcount, 1)
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&bgdata)), unsafe.Pointer(&data))
dldata = &data
}
data := *dldata
back, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return
@@ -439,9 +453,9 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string) (sendimg
return
}
canvas.SetRGBA255(0, 0, 0, 255)
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+kanban.Version, float64(canvas.W())/2+3, float64(canvas.H())-70/2+3, 0.5, 0.5)
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+banner.Version, float64(canvas.W())/2+3, float64(canvas.H())-70/2+3, 0.5, 0.5)
canvas.SetRGBA255(255, 255, 255, 255)
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+kanban.Version, float64(canvas.W())/2, float64(canvas.H())-70/2, 0.5, 0.5)
canvas.DrawStringAnchored("Created By ZeroBot-Plugin "+banner.Version, float64(canvas.W())/2, float64(canvas.H())-70/2, 0.5, 0.5)
sendimg = canvas.Image()
return
@@ -553,23 +567,21 @@ func diskstate() (stateinfo []*status, err error) {
if err != nil {
return
}
stateinfo = make([]*status, len(parts))
for i, v := range parts {
stateinfo = make([]*status, 0, len(parts))
for _, v := range parts {
mp := v.Mountpoint
if strings.HasPrefix(mp, "/snap/") || strings.HasPrefix(mp, "/apex/") {
continue
}
diskusage, err := disk.Usage(mp)
usage := ""
precent := 0.0
if err != nil {
usage = err.Error()
} else {
usage = storagefmt(float64(diskusage.Used)) + " / " + storagefmt(float64(diskusage.Total))
precent = math.Round(diskusage.UsedPercent)
continue
}
stateinfo[i] = &status{
precent: precent,
stateinfo = append(stateinfo, &status{
precent: math.Round(diskusage.UsedPercent),
name: mp,
text: []string{usage},
}
text: []string{storagefmt(float64(diskusage.Used)) + " / " + storagefmt(float64(diskusage.Total))},
})
}
return stateinfo, nil
}

View File

@@ -32,20 +32,28 @@ const (
mockingbirdttsindex
)
// extrattsname is the tts other than genshin vits
var extrattsname = []string{"百度", "拟声鸟"}
const (
defaultttsindexkey = -2905
defaultttsindexkey = -2905
gsapikeyextragrp = -1
chatgptapikeyextragrp = -2
)
var replyModes = [...]string{"青云客", "小爱"}
type replymode struct {
APIKey string // APIKey is for chatgpt
replyModes []string `json:"-"`
}
func setReplyMode(ctx *zero.Ctx, name string) error {
func (r *replymode) setReplyMode(ctx *zero.Ctx, name string) error {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
var ok bool
var index int64
for i, s := range replyModes {
for i, s := range r.replyModes {
if s == name {
ok = true
index = int64(i)
@@ -62,24 +70,47 @@ func setReplyMode(ctx *zero.Ctx, name string) error {
return m.SetData(gid, (m.GetData(index)&^0xff)|(index&0xff))
}
func getReplyMode(ctx *zero.Ctx) aireply.AIReply {
func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if ok {
if m.GetData(gid)&0xff == 1 {
switch m.GetData(gid) & 0xff {
case 0:
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
case 1:
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
case 2:
k := r.getAPIKey(ctx)
if k != "" {
return aireply.NewChatGPT(aireply.ChatGPTURL, k)
}
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
}
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
}
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
}
func (r *replymode) getAPIKey(ctx *zero.Ctx) string {
if r.APIKey == "" {
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
_ = m.Manager.GetExtra(chatgptapikeyextragrp, &r)
logrus.Debugln("[tts] get api key:", r.APIKey)
}
return r.APIKey
}
func (r *replymode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
r.APIKey = key
_ = m.Manager.Response(chatgptapikeyextragrp)
return m.Manager.SetExtra(chatgptapikeyextragrp, r)
}
var ttsins = func() map[string]tts.TTS {
m := make(map[string]tts.TTS, 128)
for _, mode := range append(genshin.SoundList[:], "百度", "拟声鸟") {
for _, mode := range append(genshin.SoundList[:], extrattsname...) {
m[mode] = nil
}
return m
@@ -87,7 +118,7 @@ var ttsins = func() map[string]tts.TTS {
var ttsModes = func() []string {
s := append(genshin.SoundList[:], make([]string, 64-len(genshin.SoundList))...) // 0-63
s = append(s, "百度", "拟声鸟") // 64 65
s = append(s, extrattsname...) // 64 65 ...
return s
}()
@@ -127,7 +158,7 @@ func newttsmode() *ttsmode {
func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string {
if t.APIKey == "" {
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
_ = m.Manager.GetExtra(-1, &t)
_ = m.Manager.GetExtra(gsapikeyextragrp, &t)
logrus.Debugln("[tts] get api key:", t.APIKey)
}
return url.QueryEscape(t.APIKey)
@@ -135,8 +166,8 @@ func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string {
func (t *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error {
t.APIKey = key
_ = m.Manager.Response(-1)
return m.Manager.SetExtra(-1, t)
_ = m.Manager.Response(gsapikeyextragrp)
return m.Manager.SetExtra(gsapikeyextragrp, t)
}
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt int) error {
@@ -157,9 +188,9 @@ func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt
}
if index == -1 {
switch name {
case "百度":
case extrattsname[0]:
index = baiduttsindex
case "拟声鸟":
case extrattsname[1]:
index = mockingbirdttsindex
default:
return errors.New("语音人物" + name + "未注册index")
@@ -189,9 +220,9 @@ func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
ins, ok := ttsins[mode]
if !ok || ins == nil {
switch mode {
case "百度":
case extrattsname[0]:
ins = baidutts.NewBaiduTTS(int(i&0x0f00) >> 8)
case "拟声鸟":
case extrattsname[1]:
var err error
ins, err = mockingbird.NewMockingBirdTTS(int(i&0xf000) >> 12)
if err != nil {
@@ -234,9 +265,9 @@ func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) er
}
if index == -1 {
switch name {
case "百度":
case extrattsname[0]:
index = baiduttsindex
case "拟声鸟":
case extrattsname[1]:
index = mockingbirdttsindex
default:
return errors.New("语音人物" + name + "未注册index")

View File

@@ -15,7 +15,11 @@ import (
"github.com/wdvxdr1123/ZeroBot/message"
)
var t = newttsmode()
var replmd = replymode{
replyModes: []string{"青云客", "小爱", "ChatGPT"},
}
var ttsmd = newttsmode()
func init() { // 插件主体
ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{
@@ -32,13 +36,13 @@ func init() { // 插件主体
enr := control.Register("aireply", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "人工智能回复",
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]",
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱|ChatGPT]\n- 设置 ChatGPT api key xxx",
PrivateDataFolder: "aireply",
})
enr.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) {
aireply := getReplyMode(ctx)
aireply := replmd.getReplyMode(ctx)
reply := message.ParseMessageFromString(aireply.Talk(ctx.Event.UserID, ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
// 回复
time.Sleep(time.Second * 1)
@@ -52,7 +56,7 @@ func init() { // 插件主体
enr.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
param := ctx.State["args"].(string)
err := setReplyMode(ctx, param)
err := replmd.setReplyMode(ctx, param)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
@@ -60,16 +64,25 @@ func init() { // 插件主体
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
})
enr.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := replmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功"))
})
endpre := regexp.MustCompile(`\pP$`)
ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) {
msg := ctx.ExtractPlainText()
// 获取回复模式
r := getReplyMode(ctx)
r := replmd.getReplyMode(ctx)
// 获取回复的文本
reply := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0])
// 获取语音
speaker, err := t.getSoundMode(ctx)
speaker, err := ttsmd.getSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
@@ -104,7 +117,7 @@ func init() { // 插件主体
}
// 保存设置
logrus.Debugln("[tts] t.setSoundMode( ctx", param, n, n, ")")
err = t.setSoundMode(ctx, param, n, n)
err = ttsmd.setSoundMode(ctx, param, n, n)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
@@ -112,7 +125,7 @@ func init() { // 插件主体
if banner, ok := genshin.TestRecord[param]; ok {
logrus.Debugln("[tts] banner:", banner, "get sound mode...")
// 设置验证
speaker, err := t.getSoundMode(ctx)
speaker, err := ttsmd.getSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
@@ -146,7 +159,7 @@ func init() { // 插件主体
}
}
// 保存设置
err = t.setDefaultSoundMode(param, n, n)
err = ttsmd.setDefaultSoundMode(param, n, n)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
@@ -155,13 +168,13 @@ func init() { // 插件主体
})
ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := t.resetSoundMode(ctx)
err := ttsmd.resetSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
}
// 设置验证
speaker, err := t.getSoundMode(ctx)
speaker, err := ttsmd.getSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
@@ -170,7 +183,7 @@ func init() { // 插件主体
})
ent.OnRegex(`^设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := t.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
err := ttsmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return

View File

@@ -4,115 +4,51 @@ package baiduaudit
import (
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"github.com/Baidu-AIP/golang-sdk/aip/censor"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/file"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/img/text"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
// 服务网址:https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index
// 返回参数说明https://cloud.baidu.com/doc/ANTIPORN/s/Nk3h6xbb2
type baiduRes struct {
LogID int `json:"log_id"` // 请求唯一id
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
ConclusionType int `json:"conclusionType"` // 审核结果类型可取值1.合规2.不合规3.疑似4.审核失败
Data []auditData `json:"data"`
ErrorCode int `json:"error_code"` // 错误提示码,失败才返回,成功不返回
ErrorMsg string `json:"error_msg"` // 错误提示信息,失败才返回,成功不返回
}
type auditData struct {
Type int `json:"type"` // 审核主类型11百度官方违禁词库、12文本反作弊、13:自定义文本黑名单、14:自定义文本白名单
SubType int `json:"subType"` // 审核子类型0:含多种类型具体看官方链接1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
ConclusionType int `json:"conclusionType"` // 审核结果类型可取值1.合规2.不合规3.疑似4.审核失败
Msg string `json:"msg"` // 不合规项描述信息
Hits []hit `json:"hits"`
} // 不合规/疑似/命中白名单项详细信息。响应成功并且conclusion为疑似或不合规或命中白名单时才返回响应失败或conclusion为合规且未命中白名单时不返回。
type hit struct {
DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
Words []string `json:"words"` // 送检文本命中词库的关键词备注建议参考新字段“wordHitPositions”包含信息更丰富关键词以及对应的位置及标签信息
Probability float64 `json:"probability,omitempty"` // 不合规项置信度
} // 送检文本违规原因的详细信息
type keyConfig struct {
Key1 string `json:"key1"` // 百度云服务内容审核key存储
Key2 string `json:"key2"` // 百度云服务内容审核key存储
Groups map[int64]group `json:"groups"` // 群配置存储
}
type group struct {
Enable EnableMark // 是否启用内容审核
TextAudit EnableMark // 文本检测
ImageAudit EnableMark // 图像检测
DMRemind EnableMark // 撤回提示
MoreRemind EnableMark // 详细违规提示
DMBAN EnableMark // 撤回后禁言
BANTimeAddEnable EnableMark // 禁言累加
BANTime int64 // 标准禁言时间,禁用累加,但开启禁言的的情况下采用该值
MaxBANTimeAddRange int64 // 最大禁言时间累加范围,最高禁言时间
BANTimeAddTime int64 // 禁言累加时间该值是开启禁累加功能后再次触发时根据被禁次数X该值计算出的禁言时间
WhiteListType [8]bool // 类型白名单,处于白名单类型的违规,不会被触发 0:含多种类型具体看官方链接1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
AuditHistory map[int64]auditHistory // 被封禁用户列表
}
// EnableMark 启用:●,禁用:○
type EnableMark bool
// String 打印启用状态
func (em EnableMark) String() string {
if em {
return "开启"
}
return "关闭"
}
type auditHistory struct {
Count int64 `json:"key2"` // 被禁次数
ResList []baiduRes `json:"reslist"` // 禁言原因
}
var bdcli *censor.ContentCensorClient // 百度云审核服务Client
var typetext = [8]string{
0: "默认违禁词库",
1: "违禁违规",
2: "文本色情",
3: "敏感信息",
4: "恶意推广",
5: "低俗辱骂",
6: "恶意推广-联系方式",
7: "恶意推广-软文推广",
} // 文本类型
var (
config keyConfig // 插件配置
configinit bool // 配置初始化
configpath string // 配置路径
bdcli *censor.ContentCensorClient // 百度云审核服务Client
txttyp = [...]string{
0: "默认违禁词库",
1: "违禁违规",
2: "文本色情",
3: "敏感信息",
4: "恶意推广",
5: "低俗辱骂",
6: "恶意推广-联系方式",
7: "恶意推广-软文推广",
} // 文本类型
config = newconfig() // 插件配置
)
func init() {
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "百度内容审核",
Help: "##该功能来自百度内容审核需购买相关服务并创建app##\n" +
Help: "##该功能来自百度内容审核, 需购买相关服务, 并创建app##\n" +
"- 获取BDAKey\n" +
"- 配置BDAKey [API key] [Secret Key]\n" +
"- 开启/关闭内容审核\n" +
"- 开启/关闭撤回提示\n" +
"- 开启/关闭详细提示\n" +
"- 开启/关闭撤回禁言\n" +
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时再次触发按最大禁言时间计算\n" +
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时, 再次触发按最大禁言时间计算\n" +
"- 开启/关闭禁言累加\n" +
"- 设置撤回禁言时间[分钟默认:1]\n" +
"- 设置最大禁言时间[分钟默认:60,最大43200]\n" +
"- 设置每次累加时间[分钟默认:1]\n" +
"- 设置撤回禁言时间[分钟, 默认:1]\n" +
"- 设置最大禁言时间[分钟, 默认:60,最大43200]\n" +
"- 设置每次累加时间[分钟, 默认:1]\n" +
"##检测类型设置## 类型编号列表:[1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广]\n" +
"- 查看检测类型\n" +
"- 查看检测配置\n" +
@@ -121,15 +57,19 @@ func init() {
"- 开启/关闭文本检测\n" +
"- 开启/关闭图像检测\n" +
"##测试功能##\n" +
"- 测试文本检测[文本内容]\n" +
"- 测试图像检测[图片]\n",
"- ^文本检测[文本内容]\n" +
"- ^图像检测[图片]\n",
PrivateDataFolder: "baiduaudit",
})
configpath = engine.DataFolder() + "config.json"
loadConfig()
if configinit {
configpath := engine.DataFolder() + "config.json"
err := config.load(configpath)
if err != nil {
logrus.Warnln("[baiduaudit] 加载配置错误:", err)
} else if config.Key1 != "" && config.Key2 != "" {
bdcli = censor.NewClient(config.Key1, config.Key2)
}
engine.OnFullMatch("获取BDAKey", zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("接口key创建网址:\n" +
@@ -138,28 +78,33 @@ func init() {
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/resource/getFree"))
})
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, clientCheck).SetBlock(true).
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
// 获取群配置
group := getGroup(ctx.Event.GroupID)
var msgs string
group := config.groupof(ctx.Event.GroupID)
msg := ""
k1 := ctx.State["regex_matched"].([]string)[1]
if k1 == "类型" {
msgs += "本群检测类型:"
find := false
sb := strings.Builder{}
sb.WriteString("本群检测类型:")
found := false
// 遍历群检测类型名单
for i, v := range group.WhiteListType {
for i, v := range group.copyWhiteListType() {
if !v {
find = true
msgs += fmt.Sprint("\n", i, ".", typetext[i])
found = true
sb.WriteByte('\n')
sb.WriteString(strconv.Itoa(i))
sb.WriteByte('.')
sb.WriteString(txttyp[i])
}
}
if !find {
msgs += "无"
if !found {
sb.WriteString("无")
}
msg = sb.String()
} else {
// 生成配置文本
msgs = fmt.Sprintf("本群配置:\n"+
msg = fmt.Sprintf("本群配置:\n"+
"内容审核:%s\n"+
"-文本:%s\n"+
"-图像:%s\n"+
@@ -171,138 +116,145 @@ func init() {
"-每次累加时间:%v分钟\n"+
"-最大禁言时间:%v分钟", group.Enable, group.TextAudit, group.ImageAudit, group.DMRemind, group.MoreRemind, group.DMBAN, group.BANTimeAddEnable, group.BANTime, group.BANTimeAddTime, group.MaxBANTimeAddRange)
}
b, err := text.RenderToBase64(msgs, text.FontFile, 300, 20)
b, err := text.RenderToBase64(msg, text.FontFile, 300, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
})
engine.OnRegex("^设置(不)?检测类型([01234567])$", zero.AdminPermission, clientCheck).SetBlock(true).
engine.OnRegex("^设置(不)?检测类型([0-7])$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
defer jsonSave(config, configpath)
k1 := ctx.State["regex_matched"].([]string)[1]
k2 := ctx.State["regex_matched"].([]string)[2]
group := getGroup(ctx.Event.GroupID)
group := config.groupof(ctx.Event.GroupID)
inputType, _ := strconv.Atoi(k2)
if k1 == "不" {
group.WhiteListType[inputType] = true // 不检测:则进入类型白名单
} else {
group.WhiteListType[inputType] = false // 检测:则退出白名单
group.setWhiteListType(inputType, k1 == "不")
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
config.Groups[ctx.Event.GroupID] = group
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, typetext[inputType])))
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, txttyp[inputType])))
})
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, clientCheck).SetBlock(true).
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
defer jsonSave(config, configpath)
k1 := ctx.State["regex_matched"].([]string)[1]
k3 := ctx.State["regex_matched"].([]string)[3]
group := getGroup(ctx.Event.GroupID)
time, _ := strconv.ParseInt(k1, 10, 64)
switch k1 {
case "最大":
group.MaxBANTimeAddRange = time
case "每次":
group.BANTimeAddTime = time
case "撤回":
group.BANTime = time
config.groupof(ctx.Event.GroupID).set(func(g *group) {
switch k1 {
case "最大":
g.MaxBANTimeAddRange = time
case "每次":
g.BANTimeAddTime = time
case "撤回":
g.BANTime = time
}
})
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
config.Groups[ctx.Event.GroupID] = group
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s禁言累加时间已设置为%s", k3, k1)))
})
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, clientCheck).SetBlock(true).
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
defer jsonSave(config, configpath)
k1 := ctx.State["regex_matched"].([]string)[1]
k2 := ctx.State["regex_matched"].([]string)[2]
isEnable := EnableMark(false)
group := getGroup(ctx.Event.GroupID)
if k1 == "开启" {
isEnable = true
isEnable := mark(k1 == "开启")
config.groupof(ctx.Event.GroupID).set(func(g *group) {
switch k2 {
case "内容审核":
g.Enable = isEnable
case "撤回提示":
g.DMRemind = isEnable
case "撤回禁言":
g.DMBAN = isEnable
case "禁言累加":
g.BANTimeAddEnable = isEnable
case "详细提示":
g.MoreRemind = isEnable
case "文本检测":
g.TextAudit = isEnable
case "图像检测":
g.ImageAudit = isEnable
}
})
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
switch k2 {
case "内容审核":
group.Enable = isEnable
case "撤回提示":
group.DMRemind = isEnable
case "撤回禁言":
group.DMBAN = isEnable
case "禁言累加":
group.BANTimeAddEnable = isEnable
case "详细提示":
group.MoreRemind = isEnable
case "文本检测":
group.TextAudit = isEnable
case "图像检测":
group.ImageAudit = isEnable
}
config.Groups[ctx.Event.GroupID] = group
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s已%s", k2, k1)))
})
engine.OnRegex(`^配置BDAKey\s(.*)\s(.*)$`, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
k1 := ctx.State["regex_matched"].([]string)[1]
k2 := ctx.State["regex_matched"].([]string)[2]
bdcli = censor.NewClient(k1, k2)
config.Key1 = k1
config.Key2 = k2
config.setkey(k1, k2)
if bdcli != nil {
jsonSave(config, configpath)
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("配置成功"))
}
})
engine.OnMessage().SetBlock(false).Handle(func(ctx *zero.Ctx) {
group, ok := config.Groups[ctx.Event.GroupID]
// 如果没该配置,或者审核功能未开启直接跳过
if !ok || !bool(group.Enable) {
engine.OnMessage(config.isgroupexist).SetBlock(false).Handle(func(ctx *zero.Ctx) {
group := config.groupof(ctx.Event.GroupID)
if !bool(group.Enable) {
return
}
var bdres baiduRes
var err error
for _, elem := range ctx.Event.Message {
switch elem.Type {
case "image":
if !group.ImageAudit {
return
if !group.ImageAudit || elem.Data["url"] == "" {
continue
}
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
bdres, err := jsonToBaiduRes(res)
bdres, err = parse2BaiduRes(res)
if err != nil {
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
continue
}
banCheck(ctx, bdres)
case "text":
if !group.TextAudit {
return
if !group.TextAudit || elem.Data["text"] == "" {
continue
}
res := bdcli.TextCensor(elem.Data["text"])
bdres, err := jsonToBaiduRes(res)
bdres, err = parse2BaiduRes(bdcli.TextCensor(elem.Data["text"]))
if err != nil {
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
continue
}
banCheck(ctx, bdres)
default:
continue
}
}
bdres.audit(ctx, configpath)
})
engine.OnPrefix("文本检测", clientCheck).SetBlock(false).
engine.OnPrefix("^文本检测", hasinit).SetBlock(false).
Handle(func(ctx *zero.Ctx) {
if bdcli == nil {
ctx.SendChain(message.Text("Key未配置"))
return
}
args := ctx.ExtractPlainText()
res := bdcli.TextCensor(args)
bdres, err := jsonToBaiduRes(res)
bdres, err := parse2BaiduRes(res)
if err != nil {
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
}
group := getGroup(ctx.Event.GroupID)
ctx.SendChain(buildResp(bdres, group)...)
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
})
engine.OnPrefix("^图像检测", clientCheck).SetBlock(false).
engine.OnPrefix("^图像检测", hasinit).SetBlock(false).
Handle(func(ctx *zero.Ctx) {
var urls []string
for _, elem := range ctx.Event.Message {
@@ -316,105 +268,17 @@ func init() {
return
}
res := bdcli.ImgCensorUrl(urls[0], nil)
bdres, err := jsonToBaiduRes(res)
bdres, err := parse2BaiduRes(res)
if err != nil {
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
}
group := getGroup(ctx.Event.GroupID)
ctx.SendChain(buildResp(bdres, group)...)
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
})
}
// 禁言检测
func banCheck(ctx *zero.Ctx, bdres baiduRes) {
// 如果返回类型为2不合规0为合规3为疑似
if bdres.ConclusionType == 2 {
// 创建消息ID
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
// 获取群配置
group := getGroup(ctx.Event.GroupID)
// 检测群配置里的不检测类型白名单,忽略掉不检测的违规类型
for i, b := range group.WhiteListType {
if i == bdres.Data[0].SubType && b {
return
}
}
// 生成回复文本
res := buildResp(bdres, group)
// 撤回消息
ctx.DeleteMessage(mid)
// 查看是否启用撤回后禁言
if group.DMBAN {
// 从历史违规记录中获取指定用户
user := group.getUser(ctx.Event.UserID)
// 用户违规次数自增
user.Count++
// 用户违规原因记录
user.ResList = append(user.ResList, bdres)
// 覆写该用户到群违规记录中
group.AuditHistory[ctx.Event.UserID] = user
// 覆写该群信息
config.Groups[ctx.Event.GroupID] = group
// 保存到json
jsonSave(config, configpath)
var bantime int64
// 查看是否开启禁言累加功能,并计算禁言时间
if group.BANTimeAddEnable {
bantime = user.Count * group.BANTimeAddTime * 60
} else {
bantime = group.BANTime * 60
}
// 执行禁言
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
}
// 查看是否开启撤回提示
if group.DMRemind {
res = append(res, message.At(ctx.Event.Sender.ID))
ctx.SendChain(res...)
}
}
}
// 获取群配置
func getGroup(groupID int64) group {
g, ok := config.Groups[groupID]
if ok {
return g
}
if config.Groups == nil {
config.Groups = make(map[int64]group)
}
g = group{
TextAudit: true,
ImageAudit: true,
BANTime: 1,
MaxBANTimeAddRange: 60,
BANTimeAddTime: 1,
WhiteListType: [8]bool{},
AuditHistory: map[int64]auditHistory{},
}
config.Groups[groupID] = g
return g
}
// 从群历史违规记录中获取用户
func (group *group) getUser(userID int64) auditHistory {
audit, ok := group.AuditHistory[userID]
if ok {
return audit
}
// 如果没有用户,则创建一个并返回
if group.AuditHistory == nil {
group.AuditHistory = make(map[int64]auditHistory)
}
audit = auditHistory{0, []baiduRes{}}
group.AuditHistory[userID] = audit
return audit
}
// 客户端是否初始化检测
func clientCheck(ctx *zero.Ctx) bool {
func hasinit(ctx *zero.Ctx) bool {
if bdcli == nil {
ctx.SendChain(message.Text("Key未配置"))
return false
@@ -422,79 +286,7 @@ func clientCheck(ctx *zero.Ctx) bool {
return true
}
// 加载JSON配置文件
func loadConfig() {
if file.IsExist(configpath) {
data, err := os.OpenFile(configpath, os.O_RDONLY, 0755)
if err != nil {
panic(err)
}
err = json.NewDecoder(data).Decode(&config)
if err != nil {
panic(err)
}
configinit = true
} else {
config = keyConfig{}
configinit = false
}
}
// 保存配置文件
func jsonSave(v keyConfig, path string) {
jsf, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
defer func(file *os.File) {
err := file.Close()
if err != nil {
fmt.Println(err)
}
}(jsf) // 结束时关闭句柄,释放资源
err := json.NewEncoder(jsf).Encode(v)
if err != nil {
fmt.Println(err)
}
}
// JSON反序列化
func jsonToBaiduRes(resjson string) (baiduRes, error) {
var bdres baiduRes
err := json.Unmarshal(binary.StringToBytes(resjson), &bdres)
return bdres, err
}
// 生成回复文本
func buildResp(bdres baiduRes, group group) []message.MessageSegment {
// 建立消息段
msgs := make([]message.MessageSegment, 0, 8)
// 生成简略审核结果回复
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
// 查看是否开启详细审核内容提示,并确定审核内容值为疑似,或者不合规
if !group.MoreRemind {
return msgs
}
// 遍历返回的不合规数据,生成详细违规内容
for i, datum := range bdres.Data {
msgs = append(msgs, message.Text("[", i, "]:", datum.Msg, "\n"))
// 检查命中词条是否大于0
if len(datum.Hits) == 0 {
return msgs
}
// 遍历打印命中的违规词条
for _, hit := range datum.Hits {
if len(datum.Hits) == 0 {
return msgs
}
msgs = append(msgs, message.Text("("))
for i4, i3 := range hit.Words {
// 检查是否是最后一个要打印的词条,如果是则不加上逗号
if i4 != len(hit.Words)-1 {
msgs = append(msgs, message.Text(i3, ","))
} else {
msgs = append(msgs, message.Text(i3))
}
}
msgs = append(msgs, message.Text(")"))
}
}
return msgs
func parse2BaiduRes(resjson string) (bdres baiduRes, err error) {
err = json.Unmarshal(binary.StringToBytes(resjson), &bdres)
return
}

271
plugin/baiduaudit/model.go Normal file
View File

@@ -0,0 +1,271 @@
package baiduaudit
import (
"encoding/json"
"os"
"sync"
"sync/atomic"
"github.com/FloatTech/floatbox/file"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
// 服务网址:https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index
// 返回参数说明https://cloud.baidu.com/doc/ANTIPORN/s/Nk3h6xbb2
type baiduRes struct {
mu sync.Mutex `json:"-"`
// LogID int `json:"log_id"` // 请求唯一id
Conclusion string `json:"conclusion"` // 审核结果, 可取值:合规、不合规、疑似、审核失败
ConclusionType int `json:"conclusionType"` // 审核结果类型, 可取值1.合规, 2.不合规, 3.疑似, 4.审核失败
Data []*auditData `json:"data"`
ErrorCode int `json:"error_code"` // 错误提示码, 失败才返回, 成功不返回
ErrorMsg string `json:"error_msg"` // 错误提示信息, 失败才返回, 成功不返回
}
// 禁言检测
func (bdres *baiduRes) audit(ctx *zero.Ctx, configpath string) {
bdres.mu.Lock()
defer bdres.mu.Unlock()
// 如果返回类型为2不合规, 0为合规, 3为疑似
if bdres.ConclusionType != 2 {
return
}
// 创建消息ID
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
// 获取群配置
group := config.groupof(ctx.Event.GroupID)
// 检测群配置里的不检测类型白名单, 忽略掉不检测的违规类型
for i, b := range group.copyWhiteListType() {
if i == bdres.Data[0].SubType && b {
return
}
}
// 生成回复文本
res := group.reply(bdres)
// 撤回消息
ctx.DeleteMessage(mid)
// 查看是否启用撤回后禁言
if group.DMBAN {
// 从历史违规记录中获取指定用户
user := group.historyof(ctx.Event.UserID)
// 用户违规次数自增
atomic.AddInt64(&user.Count, 1)
user.mu.Lock()
// 用户违规原因记录
user.ResList = append(user.ResList, bdres)
user.mu.Unlock()
// 保存到json
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
}
var bantime int64
// 查看是否开启禁言累加功能, 并计算禁言时间
if group.BANTimeAddEnable {
bantime = atomic.LoadInt64(&user.Count) * group.BANTimeAddTime * 60
} else {
bantime = group.BANTime * 60
}
// 执行禁言
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
}
// 查看是否开启撤回提示
if group.DMRemind {
res = append(res, message.At(ctx.Event.Sender.ID))
ctx.Send(res)
}
}
type auditData struct {
// Type int `json:"type"` // 审核主类型, 11百度官方违禁词库、12文本反作弊、13:自定义文本黑名单、14:自定义文本白名单
SubType int `json:"subType"` // 审核子类型, 0:含多种类型, 具体看官方链接, 1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
// Conclusion string `json:"conclusion"` // 审核结果, 可取值:合规、不合规、疑似、审核失败
// ConclusionType int `json:"conclusionType"` // 审核结果类型, 可取值1.合规, 2.不合规, 3.疑似, 4.审核失败
Msg string `json:"msg"` // 不合规项描述信息
Hits []*hit `json:"hits"`
} // 不合规/疑似/命中白名单项详细信息.响应成功并且conclusion为疑似或不合规或命中白名单时才返回, 响应失败或conclusion为合规且未命中白名单时不返回.
type auditHistory struct {
mu sync.Mutex `json:"-"`
Count int64 `json:"key2"` // 被禁次数
ResList []*baiduRes `json:"reslist"` // 禁言原因
}
type hit struct {
// DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
Words []string `json:"words"` // 送检文本命中词库的关键词备注建议参考新字段“wordHitPositions”, 包含信息更丰富:关键词以及对应的位置及标签信息)
// Probability float64 `json:"probability,omitempty"` // 不合规项置信度
} // 送检文本违规原因的详细信息
type keyConfig struct {
mu sync.Mutex `json:"-"`
Key1 string `json:"key1"` // 百度云服务内容审核key存储
Key2 string `json:"key2"` // 百度云服务内容审核key存储
Groups map[int64]*group `json:"groups"` // 群配置存储
}
func newconfig() (kc keyConfig) {
kc.Groups = make(map[int64]*group, 64)
return
}
func (kc *keyConfig) setkey(k1, k2 string) {
kc.mu.Lock()
defer kc.mu.Unlock()
kc.Key1 = k1
kc.Key2 = k2
}
// 加载JSON配置文件
func (kc *keyConfig) load(filename string) error {
if file.IsNotExist(filename) {
return nil
}
f, err := os.Open(filename)
if err != nil {
return err
}
kc.mu.Lock()
defer kc.mu.Unlock()
return json.NewDecoder(f).Decode(kc)
}
func (kc *keyConfig) isgroupexist(ctx *zero.Ctx) (ok bool) {
kc.mu.Lock()
defer kc.mu.Unlock()
_, ok = kc.Groups[ctx.Event.GroupID]
return
}
// 获取群配置
func (kc *keyConfig) groupof(groupID int64) *group {
kc.mu.Lock()
defer kc.mu.Unlock()
g, ok := kc.Groups[groupID]
if ok {
return g
}
g = &group{
TextAudit: true,
ImageAudit: true,
BANTime: 1,
MaxBANTimeAddRange: 60,
BANTimeAddTime: 1,
AuditHistory: map[int64]*auditHistory{},
}
kc.Groups[groupID] = g
return g
}
// 保存配置文件
func (kc *keyConfig) saveto(filename string) error {
kc.mu.Lock()
defer kc.mu.Unlock()
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(kc)
}
type group struct {
mu sync.Mutex
Enable mark // 是否启用内容审核
TextAudit mark // 文本检测
ImageAudit mark // 图像检测
DMRemind mark // 撤回提示
MoreRemind mark // 详细违规提示
DMBAN mark // 撤回后禁言
BANTimeAddEnable mark // 禁言累加
BANTime int64 // 标准禁言时间, 禁用累加, 但开启禁言的的情况下采用该值
MaxBANTimeAddRange int64 // 最大禁言时间累加范围, 最高禁言时间
BANTimeAddTime int64 // 禁言累加时间, 该值是开启禁累加功能后, 再次触发时, 根据被禁次数X该值计算出的禁言时间
WhiteListType [8]bool // 类型白名单, 处于白名单类型的违规, 不会被触发 0:含多种类型, 具体看官方链接, 1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
AuditHistory map[int64]*auditHistory // 被封禁用户列表
}
func (g *group) set(f func(g *group)) {
g.mu.Lock()
f(g)
g.mu.Unlock()
}
func (g *group) setWhiteListType(typ int, ok bool) {
g.mu.Lock()
defer g.mu.Unlock()
g.WhiteListType[typ] = ok
}
func (g *group) copyWhiteListType() [8]bool {
g.mu.Lock()
defer g.mu.Unlock()
return g.WhiteListType
}
// 从群历史违规记录中获取用户
func (g *group) historyof(userID int64) *auditHistory {
g.mu.Lock()
defer g.mu.Unlock()
audit, ok := g.AuditHistory[userID]
if ok {
return audit
}
// 如果没有用户, 则创建一个并返回
if g.AuditHistory == nil {
g.AuditHistory = make(map[int64]*auditHistory)
}
audit = &auditHistory{}
g.AuditHistory[userID] = audit
return audit
}
// 生成回复文本
func (g *group) reply(bdres *baiduRes) message.Message {
g.mu.Lock()
defer g.mu.Unlock()
// 建立消息段
msgs := make([]message.MessageSegment, 0, 8)
// 生成简略审核结果回复
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
// 查看是否开启详细审核内容提示, 并确定审核内容值为疑似, 或者不合规
if !g.MoreRemind {
return msgs
}
// 遍历返回的不合规数据, 生成详细违规内容
for i, datum := range bdres.Data {
msgs = append(msgs, message.Text("[", i, "]:", datum.Msg, "\n"))
// 检查命中词条是否大于0
if len(datum.Hits) == 0 {
return msgs
}
// 遍历打印命中的违规词条
for _, hit := range datum.Hits {
if len(datum.Hits) == 0 {
return msgs
}
msgs = append(msgs, message.Text("("))
for i4, i3 := range hit.Words {
// 检查是否是最后一个要打印的词条, 如果是则不加上逗号
if i4 != len(hit.Words)-1 {
msgs = append(msgs, message.Text(i3, ","))
} else {
msgs = append(msgs, message.Text(i3))
}
}
msgs = append(msgs, message.Text(")"))
}
}
return msgs
}
type mark bool
// String 打印启用状态
func (em mark) String() string {
if em {
return "开启"
}
return "关闭"
}

View File

@@ -340,7 +340,7 @@ func init() {
for i := 0; i < len(danmaku.Data.Data); i++ {
totalDanmuku += len(danmaku.Data.Data[i].Danmakus) + 1
}
cw := 10000
cw := 3000
mcw := float64(2000)
ch := 550 + len(danmaku.Data.Data)*int(faceH) + totalDanmuku*int(danmuH)
canvas = gg.NewContext(cw, ch)

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
@@ -175,7 +176,19 @@ func getName(buid int64) (name string, err error) {
var ok bool
if name, ok = upMap[buid]; !ok {
var data []byte
data, err = web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(infoURL, buid), "GET", referer, ua, nil)
data, err = web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(infoURL, buid), "GET", func(r *http.Request) error {
r.Header.Set("refer", referer)
r.Header.Set("user-agent", ua)
cookie := ""
if cfg != nil {
cookie, err = cfg.Load()
if err != nil {
return err
}
}
r.Header.Set("cookie", cookie)
return nil
}, nil)
if err != nil {
return
}

View File

@@ -44,6 +44,9 @@ func init() {
return "", err
}
arr := gjson.Get(helper.BytesToString(data), "data.data").Array()
if len(arr) == 0 {
return "", errors.New("data is empty")
}
pic := arr[rand.Intn(len(arr))]
return pic.String(), nil
}, web.GetData, time.Minute)

View File

@@ -0,0 +1,37 @@
// Package dailynews 今日早报
package dailynews
import (
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const api = "http://dwz.2xb.cn/zaob"
func init() {
engine := control.Register("dailynews", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "今日早报",
Help: "- 今日早报",
PrivateDataFolder: "dailynews",
})
engine.OnFullMatch(`今日早报`).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
data, err := web.GetData(api)
if err != nil {
return
}
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String()
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Image(picURL))
})
}

249
plugin/drawlots/main.go Normal file
View File

@@ -0,0 +1,249 @@
// Package drawlots 多功能抽签插件
package drawlots
import (
"errors"
"image"
"image/gif"
"math/rand"
"os"
"strconv"
"strings"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/imgfactory"
ctrl "github.com/FloatTech/zbpctrl"
control "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/img/text"
"github.com/fumiama/jieba/util/helper"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
type info struct {
lotsType string // 文件后缀
quantity int // 签数
}
var (
lotsList = func() map[string]info {
lotsList, err := getList()
if err != nil {
logrus.Infoln("[drawlots]加载失败:", err)
} else {
logrus.Infoln("[drawlots]加载", len(lotsList), "个抽签")
}
return lotsList
}()
en = control.Register("drawlots", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "多功能抽签",
Help: "支持图包文件夹和gif抽签\n-------------\n- (刷新)抽签列表\n- 抽[签名]签\n- 看签[gif签名]\n- 加签[签名][gif图片]\n- 删签[gif签名]",
PrivateDataFolder: "drawlots",
}).ApplySingle(ctxext.DefaultSingle)
datapath = file.BOTPATH + "/" + en.DataFolder()
)
func init() {
en.OnFullMatchGroup([]string{"抽签列表", "刷新抽签列表"}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
lotsList, err := getList() // 刷新列表
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
messageText := &strings.Builder{}
messageText.WriteString(" 签 名 [ 类 型 ]----签数\n")
messageText.WriteString("———————————\n")
for name, fileInfo := range lotsList {
messageText.WriteString(name + "[" + fileInfo.lotsType + "]----" + strconv.Itoa(fileInfo.quantity) + "\n")
messageText.WriteString("----------\n")
}
textPic, err := text.RenderToBase64(messageText.String(), text.BoldFontFile, 400, 50)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Image("base64://" + helper.BytesToString(textPic)))
})
en.OnRegex(`^抽(.+)签$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
lotsType := ctx.State["regex_matched"].([]string)[1]
fileInfo, ok := lotsList[lotsType]
if !ok {
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("才...才没有", lotsType, "签这种东西啦")))
return
}
if fileInfo.lotsType == "folder" {
picPath, err := randFile(lotsType, 3)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("file:///"+picPath))
return
}
lotsImg, err := randGif(lotsType + "." + fileInfo.lotsType)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
// 生成图片
data, err := imgfactory.ToBytes(lotsImg)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.ImageBytes(data))
})
en.OnPrefix("看签", zero.UserOrGrpAdmin).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
id := ctx.Event.MessageID
lotsName := strings.TrimSpace(ctx.State["args"].(string))
fileInfo, ok := lotsList[lotsName]
if !ok {
ctx.Send(message.ReplyWithMessage(id, message.Text("才...才没有", lotsName, "签这种东西啦")))
return
}
if fileInfo.lotsType == "folder" {
ctx.Send(message.ReplyWithMessage(id, message.Text("只能查看gif签哦~")))
return
}
ctx.Send(message.ReplyWithMessage(id, message.Image("file:///"+datapath+lotsName+"."+fileInfo.lotsType)))
})
en.OnPrefix("加签", zero.SuperUserPermission, zero.MustProvidePicture).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
id := ctx.Event.MessageID
lotsName := strings.TrimSpace(ctx.State["args"].(string))
if lotsName == "" {
ctx.Send(message.ReplyWithMessage(id, message.Text("请使用正确的指令形式哦~")))
return
}
picURL := ctx.State["image_url"].([]string)[0]
err := file.DownloadTo(picURL, datapath+"/"+lotsName+".gif")
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
file, err := os.Open(datapath + "/" + lotsName + ".gif")
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
im, err := gif.DecodeAll(file)
_ = file.Close()
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
lotsList[lotsName] = info{
lotsType: "gif",
quantity: len(im.Image),
}
ctx.Send(message.ReplyWithMessage(id, message.Text("成功!")))
})
en.OnPrefix("删签", zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
id := ctx.Event.MessageID
lotsName := strings.TrimSpace(ctx.State["args"].(string))
fileInfo, ok := lotsList[lotsName]
if !ok {
ctx.Send(message.ReplyWithMessage(id, message.Text("才...才没有", lotsName, "签这种东西啦")))
return
}
if fileInfo.lotsType == "folder" {
ctx.Send(message.ReplyWithMessage(id, message.Text("为了防止误删图源,图包请手动移除哦~")))
return
}
err := os.Remove(datapath + lotsName + "." + fileInfo.lotsType)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
delete(lotsList, lotsName)
ctx.Send(message.ReplyWithMessage(id, message.Text("成功!")))
})
}
func getList() (list map[string]info, err error) {
list = make(map[string]info, 100)
files, err := os.ReadDir(datapath)
if err != nil {
return
}
if len(files) == 0 {
err = errors.New("什么签也没有哦~")
return
}
for _, lots := range files {
if lots.IsDir() {
files, _ := os.ReadDir(datapath + "/" + lots.Name())
list[lots.Name()] = info{
lotsType: "folder",
quantity: len(files),
}
continue
}
before, after, ok := strings.Cut(lots.Name(), ".")
if !ok || before == "" {
continue
}
file, err := os.Open(datapath + "/" + lots.Name())
if err != nil {
return nil, err
}
im, err := gif.DecodeAll(file)
_ = file.Close()
if err != nil {
return nil, err
}
list[before] = info{
lotsType: after,
quantity: len(im.Image),
}
}
return
}
func randFile(path string, indexMax int) (string, error) {
picPath := datapath + path
files, err := os.ReadDir(picPath)
if err != nil {
return "", err
}
if len(files) > 0 {
drawFile := files[rand.Intn(len(files))]
// 如果是文件夹就递归
if drawFile.IsDir() {
indexMax--
if indexMax <= 0 {
return "", errors.New("图包[" + path + "]存在太多非图片文件,请清理~")
}
return randFile(path, indexMax)
}
return picPath + "/" + drawFile.Name(), err
}
return "", errors.New("图包[" + path + "]不存在签内容!")
}
func randGif(gifName string) (image.Image, error) {
name := datapath + gifName
file, err := os.Open(name)
if err != nil {
return nil, err
}
im, err := gif.DecodeAll(file)
_ = file.Close()
if err != nil {
return nil, err
}
/*
firstImg, err := imgfactory.Load(name)
if err != nil {
return nil, err
}
v := im.Image[rand.Intn(len(im.Image))]
return imgfactory.Size(firstImg, firstImg.Bounds().Max.X, firstImg.Bounds().Max.Y).InsertUpC(v, 0, 0, firstImg.Bounds().Max.X/2, firstImg.Bounds().Max.Y/2).Clone().Image(),err
/*/
// 如果gif图片出现信息缺失请使用上面注释掉的代码把下面注释了(上面代码部分图存在bug)
v := im.Image[rand.Intn(len(im.Image))]
return imgfactory.Size(v, v.Bounds().Max.X, v.Bounds().Max.Y).Image(), err
// */
}

View File

@@ -43,6 +43,7 @@ var (
index = make(map[string]uint8)
// 签文
omikujis []map[string]string
fontdata []byte
)
func init() {
@@ -98,12 +99,13 @@ func init() {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
fontdata, err := file.GetLazyData("data/Font/sakura.ttf", control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
if fontdata == nil {
fontdata, err = file.GetLazyData("data/Font/sakura.ttf", control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
}
ctx.State["fontdata"] = fontdata
return true
},
)).Limit(ctxext.LimitByGroup).SetBlock(true).
@@ -149,7 +151,7 @@ func init() {
if err != nil {
return err
}
_, err = draw(background, ctx.State["fontdata"].([]byte), title, text, f)
_, err = draw(background, fontdata, title, text, f)
_ = f.Close()
return err
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))

174
plugin/hitokoto/hitokoto.go Normal file
View File

@@ -0,0 +1,174 @@
// Package hitokoto 一言
package hitokoto
import (
"math/rand"
"strconv"
"strings"
"time"
"github.com/FloatTech/floatbox/binary"
fcext "github.com/FloatTech/floatbox/ctxext"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/img/text"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
func init() { // 插件主体
engine := control.Register("hitokoto", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "一言",
Help: "- 一言[xxx]\n" +
"- 系列一言",
PublicDataFolder: "Hitokoto",
})
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
dbfile := engine.DataFolder() + "hitokoto.db"
_, err := engine.GetLazyData("hitokoto.db", false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
hdb, err = initialize(dbfile)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
return true
})
engine.OnPrefix(`一言`, getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text("少女祈祷中..."))
args := ctx.State["args"].(string)
blist, err := hdb.getByKey(strings.TrimSpace(args))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if len(blist) == 0 {
ctx.SendChain(message.Text("ERROR: hitokoto empty"))
return
}
m := make(message.Message, 0, 10)
text := strings.Builder{}
if len(blist) <= 10 {
for _, b := range blist {
text.WriteString(b.Hitokoto)
text.WriteString("\n——")
text.WriteString(b.From)
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
text.Reset()
}
} else {
indexes := map[int]struct{}{}
for i := 0; i < 10; i++ {
ind := rand.Intn(len(blist))
if _, ok := indexes[ind]; ok {
i--
continue
}
indexes[ind] = struct{}{}
}
for k := range indexes {
b := blist[k]
text.WriteString(b.Hitokoto)
text.WriteString("\n——")
text.WriteString(b.From)
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
text.Reset()
}
}
if id := ctx.Send(m).ID(); id == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
}
})
engine.OnFullMatch(`系列一言`, getdb).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
recv, cancel := next.Repeat()
defer cancel()
results, err := hdb.getAllCategory()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
tex := strings.Builder{}
tex.WriteString("请输入系列一言序号\n")
for i, v := range results {
tex.WriteString(strconv.Itoa(i))
tex.WriteString(". ")
tex.WriteString(v.Category)
tex.WriteString("\n")
}
base64Str, err := text.RenderToBase64(tex.String(), text.FontFile, 400, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Image("base64://" + binary.BytesToString(base64Str)))
for {
select {
case <-time.After(time.Second * 120):
ctx.SendChain(message.Text("系列一言指令过期"))
return
case c := <-recv:
msg := c.Event.Message.ExtractPlainText()
num, err := strconv.Atoi(msg)
if err != nil {
ctx.SendChain(message.Text("请输入数字!"))
continue
}
if num < 0 || num >= len(results) {
ctx.SendChain(message.Text("序号非法!"))
continue
}
ctx.SendChain(message.Text("请欣赏系列一言: ", results[num].Category))
hlist, err := hdb.getByCategory(results[num].Category)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if len(hlist) == 0 {
ctx.SendChain(message.Text("ERROR: hitokoto empty"))
return
}
m := make(message.Message, 0, 10)
text := strings.Builder{}
if len(hlist) <= 10 {
for _, b := range hlist {
text.WriteString(b.Hitokoto)
text.WriteString("\n——")
text.WriteString(b.From)
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
text.Reset()
}
} else {
indexes := map[int]struct{}{}
for i := 0; i < 10; i++ {
ind := rand.Intn(len(hlist))
if _, ok := indexes[ind]; ok {
i--
continue
}
indexes[ind] = struct{}{}
}
for k := range indexes {
b := hlist[k]
text.WriteString(b.Hitokoto)
text.WriteString("\n——")
text.WriteString(b.From)
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(text.String())))
text.Reset()
}
}
if id := ctx.Send(m).ID(); id == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
}
return
}
}
})
}

73
plugin/hitokoto/model.go Normal file
View File

@@ -0,0 +1,73 @@
package hitokoto
import (
"os"
"github.com/jinzhu/gorm"
)
// hdb 表情包数据库全局变量
var hdb *hitokotodb
// hitokotodb 表情包数据库
type hitokotodb gorm.DB
// initialize 初始化
func initialize(dbpath string) (db *hitokotodb, err error) {
if _, err = os.Stat(dbpath); err != nil || os.IsNotExist(err) {
// 生成文件
f, err := os.Create(dbpath)
if err != nil {
return nil, err
}
_ = f.Close()
}
gdb, err := gorm.Open("sqlite3", dbpath)
if err != nil {
return
}
gdb.AutoMigrate(&hitokoto{})
return (*hitokotodb)(gdb), nil
}
type hitokoto struct {
ID int `json:"id" gorm:"column:id;primary_key"`
Hitokoto string `json:"hitokoto" gorm:"column:hitokoto"`
Type string `json:"type" gorm:"column:type"`
From string `json:"from" gorm:"column:from"`
FromWho string `json:"from_who" gorm:"column:from_who"`
Creator string `json:"creator" gorm:"column:creator"`
CreatorUID int `json:"creator_uid" gorm:"column:creator_uid"`
Reviewer int `json:"reviewer" gorm:"column:reviewer"`
UUID string `json:"uuid" gorm:"column:uuid"`
CreatedAt string `json:"created_at" gorm:"column:created_at"`
Category string `json:"catogory" gorm:"column:category"`
}
// TableName 表名
func (hitokoto) TableName() string {
return "hitokoto"
}
func (hdb *hitokotodb) getByKey(key string) (b []hitokoto, err error) {
db := (*gorm.DB)(hdb)
err = db.Where("hitokoto like ?", "%"+key+"%").Find(&b).Error
return
}
type result struct {
Category string
Count int
}
func (hdb *hitokotodb) getAllCategory() (results []result, err error) {
db := (*gorm.DB)(hdb)
err = db.Table("hitokoto").Select("category, count(1) as count").Group("category").Scan(&results).Error
return
}
func (hdb *hitokotodb) getByCategory(category string) (h []hitokoto, err error) {
db := (*gorm.DB)(hdb)
err = db.Where("category = ?", category).Find(&h).Error
return
}

View File

@@ -1,121 +0,0 @@
// Package jikipedia 小鸡词典
// 修改自https://github.com/TeamPGM/PagerMaid_Plugins_Pyro ,非常感谢!!
package jikipedia
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"github.com/FloatTech/floatbox/binary"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const (
url = "https://api.jikipedia.com/go/search_entities"
)
type value struct {
Phrase string `json:"phrase"`
Page int `json:"page"`
Size int `json:"size"`
}
func init() {
// 初始化engine
engine := control.Register("jikipedia", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "小鸡词典",
Help: "- [查梗|小鸡词典][梗]",
},
)
engine.OnPrefixGroup([]string{"小鸡词典", "查梗"}).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(
func(ctx *zero.Ctx) {
keyWord := strings.Trim(ctx.State["args"].(string), " ")
definition, err := parseKeyword(keyWord)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if definition.String() == "" {
ctx.SendChain(message.Text("好像什么都没查到,换个关键词试一试?"))
return
}
imgURL := definition.Get("images.0.scaled.path").String()
ctx.SendChain(message.Text("【标题】:", definition.Get("term.title"),
"\n【释义】:", definition.Get("plaintext"),
"\n【原文】:https://jikipedia.com/definition/", definition.Get("id")),
message.Image(imgURL))
},
)
}
func parseKeyword(keyWord string) (definition gjson.Result, err error) {
client := &http.Client{}
values := value{Phrase: keyWord, Page: 1, Size: 10}
jsonData, err := json.Marshal(values)
if err != nil {
return
}
var request *http.Request
request, err = http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return
}
request.Header = http.Header{
"Accept": {"application/json, text/plain, */*"},
"Accept-Encoding": {"gzip, deflate, br"},
"Accept-Language": {"zh-CN,zh-TW;q=0.9,zh;q=0.8"},
"Client": {"web"},
"Client-Version": {"2.7.2g"},
"Connection": {"keep-alive"},
"Host": {"api.jikipedia.com"},
"Origin": {"https://jikipedia.com"},
"Referer": {"https://jikipedia.com/"},
"Sec-Fetch-Dest": {"empty"},
"Sec-Fetch-Mode": {"cors"},
"Sec-Fetch-Site": {"same-site"},
"Token": {""},
"User-Agent": {"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36"},
"XID": {"uNo5bL1nyNCp/Gm7lJAHQ91220HLbMT8jqk9IJYhtHA4ofP+zgxwM6lSDIKiYoppP2k1IW/1Vxc2vOVGxOOVReebsLmWPHhTs7NCRygfDkE="},
"sec-ch-ua": {`" Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"`},
"sec-ch-ua-mobile": {"?1"},
"sec-ch-ua-platform": {`"Android"`},
}
request.Header.Set("Content-Type", "application/json;charset=UTF-8")
var response *http.Response
response, err = client.Do(request)
if err != nil {
return
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
extraInfo := ""
if response.StatusCode == 423 {
extraInfo = "\n调用过多被网站暂时封禁请等待数个小时后使用该功能~"
}
s := fmt.Sprintf("status code: %d%s", response.StatusCode, extraInfo)
err = errors.New(s)
return
}
data, err := io.ReadAll(response.Body)
if err != nil {
return
}
gjson.Get(binary.BytesToString(data), "data").ForEach(func(key, value gjson.Result) bool {
definition = value.Get("definitions.0")
return definition.String() == ""
})
return
}

View File

@@ -0,0 +1,31 @@
// Package kfccrazythursday 疯狂星期四
package kfccrazythursday
import (
"github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/tidwall/gjson"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const (
crazyURL = "https://www.iculture.cc/demo/CrazyThursday/api/kfc.php"
)
func init() {
engine := control.Register("kfccrazythursday", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "疯狂星期四",
Help: "疯狂星期四\n",
})
engine.OnFullMatch("疯狂星期四").SetBlock(true).Handle(func(ctx *zero.Ctx) {
data, err := web.GetData(crazyURL)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text(gjson.ParseBytes(data).Get("@this.0.content").String()))
})
}

View File

@@ -8,6 +8,7 @@ import (
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/AnimeAPI/tts/genshin"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
@@ -16,12 +17,12 @@ import (
const (
jpapi = "https://moegoe.azurewebsites.net/api/speak?text=%s&id=%d"
krapi = "https://moegoe.azurewebsites.net/api/speakkr?text=%s&id=%d"
cnapi = "https://genshinvoice.top/api?text=%s&speaker=%s&format=wav&length=1&noise=0.6&noisew=0.8"
)
var speakers = map[string]uint{
"宁宁": 0, "爱瑠": 1, "芳乃": 2, "茉子": 3, "丛雨": 4, "小春": 5, "七海": 6,
"Sua": 0, "Mimiru": 1, "Arin": 2, "Yeonhwa": 3, "Yuhwa": 4, "Seonbae": 5,
"派蒙": 0, "凯亚": 1, "安柏": 2, "丽莎": 3, "琴": 4, "香菱": 5, "枫原万叶": 6, "迪卢克": 7, "温迪": 8, "可莉": 9, "早柚": 10, "托马": 11, "芭芭拉": 12, "优菈": 13, "云堇": 14, "钟离": 15, "魈": 16, "凝光": 17, "雷电将军": 18, "北斗": 19, "甘雨": 20, "七七": 21, "刻晴": 22, "神里绫华": 23, "戴因斯雷布": 24, "雷泽": 25, "神里绫人": 26, "罗莎莉亚": 27, "阿贝多": 28, "八重神子": 29, "宵宫": 30, "荒泷一斗": 31, "九条裟罗": 32, "夜兰": 33, "珊瑚宫心海": 34, "五郎": 35, "散兵": 36, "女士": 37, "达达利亚": 38, "莫娜": 39, "班尼特": 40, "申鹤": 41, "行秋": 42, "烟绯": 43, "久岐忍": 44, "辛焱": 45, "砂糖": 46, "胡桃": 47, "重云": 48, "菲谢尔": 49, "诺艾尔": 50, "迪奥娜": 51, "鹿野院平藏": 52,
}
func init() {
@@ -30,7 +31,7 @@ func init() {
Brief: "日韩中 VITS 模型拟声",
Help: "- 让[宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海]说(日语)\n" +
"- 让[Sua|Mimiru|Arin|Yeonhwa|Yuhwa|Seonbae]说(韩语)\n" +
"- 让[派蒙|空|荧|阿贝多|枫原万叶|温迪|八重神子|纳西妲|钟离|诺艾尔|凝光|托马|北斗|莫娜|荒泷一斗|提纳里|芭芭拉|艾尔海森|雷电将军|赛诺|琴|班尼特|五郎|神里绫华|迪希雅|夜兰|辛焱|安柏|宵宫|云堇|妮露|烟绯|鹿野院平藏|凯亚|达达利亚|迪卢克|可莉|早柚|香菱|重云|刻晴|久岐忍|珊瑚宫心海|迪奥娜|戴因斯雷布|魈|神里绫人|丽莎|优菈|凯瑟琳|雷泽|菲谢尔|九条裟罗|甘雨|行秋|胡桃|迪娜泽黛|柯莱|申鹤|砂糖|萍姥姥|奥兹|罗莎莉亚|式大将|哲平|坎蒂丝|托克|留云借风真君|昆钧|塞琉斯|多莉|大肉丸|莱依拉|散兵|拉赫曼|杜拉夫|阿守|玛乔丽|纳比尔|海芭夏|九条镰治|阿娜耶|阿晃|阿扎尔|七七|博士|白术|埃洛伊|大慈树王|女士|丽塔|失落迷迭|缭乱星棘|伊甸|伏特加女孩|狂热蓝调|莉莉娅|萝莎莉娅|八重樱|八重霞|卡莲|第六夜想曲|卡萝尔|姬子|极地战刃|布洛妮娅|次生银翼|理之律者|迷城骇兔|希儿|魇夜星渊|黑希儿|帕朵菲莉丝|天元骑英|幽兰黛尔|德丽莎|月下初拥|朔夜观星|暮光骑士|明日香|李素裳|格蕾修|梅比乌斯|渡鸦|人之律者|爱莉希雅|爱衣|天穹游侠|琪亚娜|空之律者|薪炎之律者|云墨丹心|符华|识之律者|维尔薇|芽衣|雷之律者|阿波尼亚]说(中文)",
"- 让[派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏]说(中文)",
}).ApplySingle(ctxext.DefaultSingle)
en.OnRegex("^让(宁宁|爱瑠|芳乃|茉子|丛雨|小春|七海)说([A-Za-z\\s\\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
@@ -44,10 +45,23 @@ func init() {
id := speakers[ctx.State["regex_matched"].([]string)[1]]
ctx.SendChain(message.Record(fmt.Sprintf(krapi, url.QueryEscape(text), id)))
})
en.OnRegex("^让(派蒙|空|荧|阿贝多|枫原万叶|温迪|八重神子|纳西妲|钟离|诺艾尔|凝光|托马|北斗|莫娜|荒泷一斗|提纳里|芭芭拉|艾尔海森|雷电将军|赛诺|琴|班尼特|五郎|神里绫华|迪希雅|夜兰|辛焱|安柏|宵宫|云堇|妮露|烟绯|鹿野院平藏|凯亚|达达利亚|迪卢克|可莉|早柚|香菱|重云|刻晴|久岐忍|珊瑚宫心海|迪奥娜|戴因斯雷布|魈|神里绫人|丽莎|优菈|凯瑟琳|雷泽|菲谢尔|九条裟罗|甘雨|行秋|胡桃|迪娜泽黛|柯莱|申鹤|砂糖|萍姥姥|奥兹|罗莎莉亚|式大将|哲平|坎蒂丝|托克|留云借风真君|昆钧|塞琉斯|多莉|大肉丸|莱依拉|散兵|拉赫曼|杜拉夫|阿守|玛乔丽|纳比尔|海芭夏|九条镰治|阿娜耶|阿晃|阿扎尔|七七|博士|白术|埃洛伊|大慈树王|女士|丽塔|失落迷迭|缭乱星棘|伊甸|伏特加女孩|狂热蓝调|莉莉娅|萝莎莉娅|八重樱|八重霞|卡莲|第六夜想曲|卡萝尔|姬子|极地战刃|布洛妮娅|次生银翼|理之律者|迷城骇兔|希儿|魇夜星渊|黑希儿|帕朵菲莉丝|天元骑英|幽兰黛尔|德丽莎|月下初拥|朔夜观星|暮光骑士|明日香|李素裳|格蕾修|梅比乌斯|渡鸦|人之律者|爱莉希雅|爱衣|天穹游侠|琪亚娜|空之律者|薪炎之律者|云墨丹心|符华|识之律者|维尔薇|芽衣|雷之律者|阿波尼亚)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
en.OnRegex("^让(派蒙|凯亚|安柏|丽莎|琴|香菱|枫原万叶|迪卢克|温迪|可莉|早柚|托马|芭芭拉|优菈|云堇|钟离|魈|凝光|雷电将军|北斗|甘雨|七七|刻晴|神里绫华|雷泽|神里绫人|罗莎莉亚|阿贝多|八重神子|宵宫|荒泷一斗|九条裟罗|夜兰|珊瑚宫心海|五郎|达达利亚|莫娜|班尼特|申鹤|行秋|烟绯|久岐忍|辛焱|砂糖|胡桃|重云|菲谢尔|诺艾尔|迪奥娜|鹿野院平藏)说([\\s\u4e00-\u9fa5\\pP]+)$").Limit(ctxext.LimitByGroup).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[2]
speaker := ctx.State["regex_matched"].([]string)[1]
ctx.SendChain(message.Record(fmt.Sprintf(cnapi, url.QueryEscape(text), speaker)))
id := speakers[ctx.State["regex_matched"].([]string)[1]]
c, ok := control.Lookup("tts")
if !ok {
ctx.SendChain(message.Text("ERROR: plugin tts not found"))
return
}
var key struct {
APIKey string
}
err := c.Manager.GetExtra(-1, &key)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Record(fmt.Sprintf(genshin.CNAPI, id, url.QueryEscape(text), url.QueryEscape(key.APIKey))))
})
}

View File

@@ -109,8 +109,13 @@ func init() { // 插件主体
engine.OnKeywordGroup([]string{"以图搜图", "搜索图片", "以图识图"}, zero.MustProvidePicture).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
// 开始搜索图片
pics, ok := ctx.State["image_url"].([]string)
if !ok {
ctx.SendChain(message.Text("ERROR: 未获取到图片链接"))
return
}
ctx.SendChain(message.Text("少女祈祷中..."))
for _, pic := range ctx.State["image_url"].([]string) {
for _, pic := range pics {
if saucenaocli != nil {
resp, err := saucenaocli.FromURL(pic)
if err == nil && resp.Count() > 0 {

View File

@@ -2,13 +2,19 @@
package score
import (
"fmt"
"bytes"
"image"
"image/color"
"math"
"math/rand"
"os"
"strconv"
"time"
"github.com/disintegration/imaging"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
"github.com/FloatTech/AnimeAPI/bilibili"
"github.com/FloatTech/AnimeAPI/wallet"
"github.com/FloatTech/floatbox/file"
@@ -21,7 +27,6 @@ import (
"github.com/FloatTech/zbputils/ctxext"
"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"
@@ -109,7 +114,7 @@ func init() {
}
score := wallet.GetWalletOf(uid)
// 绘图
err = initPic(picFile)
getAvatar, err := initPic(picFile, uid)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
@@ -121,58 +126,106 @@ func init() {
}
// 避免图片过大,最大 1280*720
back = imgfactory.Limit(back, 1280, 720)
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7))
canvas.SetRGB(1, 1, 1)
canvas.Clear()
imgDX := back.Bounds().Dx()
imgDY := back.Bounds().Dy()
canvas := gg.NewContext(imgDX, imgDY)
// draw Aero Style
aeroStyle := gg.NewContext(imgDX-202, imgDY-202)
aeroStyle.DrawImage(imaging.Blur(back, 2.5), -100, -100)
// aero draw image.
aeroStyle.DrawRoundedRectangle(0, 0, float64(imgDX-200), float64(imgDY-200), 16)
// SideLine
aeroStyle.SetLineWidth(3)
aeroStyle.SetRGBA255(255, 255, 255, 100)
aeroStyle.StrokePreserve()
aeroStyle.SetRGBA255(255, 255, 255, 140)
// fill
aeroStyle.Fill()
// draw background
canvas.DrawImage(back, 0, 0)
monthWord := now.Format("01/02")
// Aero style combine
canvas.DrawImage(aeroStyle.Image(), 100, 100)
canvas.Fill()
hourWord := getHourWord(now)
avatar, _, err := image.Decode(bytes.NewReader(getAvatar))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
avatarf := imgfactory.Size(avatar, 200, 200)
canvas.DrawImage(avatarf.Circle(0).Image(), 120, 120)
// draw info(name,coin,etc)
canvas.SetRGB255(0, 0, 0)
data, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if err = canvas.ParseFontFace(data, float64(back.Bounds().Size().X)*0.1); err != nil {
if err = canvas.ParseFontFace(data, 50); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
canvas.SetRGB(0, 0, 0)
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2)
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2)
// draw head
nickName := ctx.CardOrNickName(uid)
canvas.DrawStringWrapped(nickName, 350, 180, 0.5, 0.5, 0.5, 0.5, gg.AlignLeft)
canvas.Fill()
// main draw
data, err = file.GetLazyData(text.FontFile, control.Md5File, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if err = canvas.ParseFontFace(data, float64(back.Bounds().Size().X)*0.04); err != nil {
if err = canvas.ParseFontFace(data, 30); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
canvas.DrawString(nickName+fmt.Sprintf(" ATRI币+%d", add), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3)
canvas.DrawString("当前ATRI币:"+strconv.FormatInt(int64(score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4)
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(rank), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5)
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1)
canvas.SetRGB255(150, 150, 150)
canvas.Fill()
canvas.DrawStringAnchored(hourWord, 350, 280, 0, 0)
canvas.DrawStringAnchored("ATRI币 + "+strconv.Itoa(add), 350, 350, 0, 0)
canvas.DrawStringAnchored("当前ATRI币"+strconv.Itoa(score), 350, 400, 0, 0)
canvas.DrawStringAnchored("LEVEL: "+strconv.Itoa(getrank(level)), 350, 450, 0, 0)
// draw Info(Time,etc.)
getTime := time.Now().Format("2006-01-02 15:04:05")
getTimeLengthWidth, getTimeLengthHight := canvas.MeasureString(getTime)
canvas.DrawStringAnchored(getTime, float64(imgDX)-100-20-getTimeLengthWidth/2, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
var nextrankScore int
if rank < 10 {
nextrankScore = rankArray[rank+1]
} else {
nextrankScore = SCOREMAX
}
canvas.SetRGB255(0, 0, 0)
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(level)/float64(nextrankScore), float64(back.Bounds().Size().Y)*0.1)
canvas.SetRGB255(102, 102, 102)
nextLevelStyle := strconv.Itoa(level) + "/" + strconv.Itoa(nextrankScore)
getLevelLength, _ := canvas.MeasureString(nextLevelStyle)
canvas.DrawStringAnchored(nextLevelStyle, 100+getLevelLength, float64(imgDY)-100-getTimeLengthHight, 0.5, 0.5) // time
canvas.Fill()
canvas.DrawString(fmt.Sprintf("%d/%d", level, nextrankScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62)
canvas.SetRGB255(255, 255, 255)
if err = canvas.ParseFontFace(data, 20); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2, float64(imgDY)-20, 0.5, 0.5) // zbp
canvas.SetRGB255(0, 0, 0)
canvas.DrawStringAnchored("Created By Zerobot-Plugin "+banner.Version, float64(imgDX)/2-3, float64(imgDY)-19, 0.5, 0.5) // zbp
canvas.SetRGB255(255, 255, 255)
// Gradient
grad := gg.NewLinearGradient(20, 320, 400, 20)
grad.AddColorStop(0, color.RGBA{G: 255, A: 255})
grad.AddColorStop(1, color.RGBA{B: 255, A: 255})
grad.AddColorStop(0.5, color.RGBA{R: 255, A: 255})
canvas.SetStrokeStyle(grad)
canvas.SetLineWidth(4)
// level array with rectangle work.
gradLineLength := float64(imgDX-120) - 120
renderLine := (float64(level) / float64(nextrankScore)) * gradLineLength
canvas.MoveTo(120, float64(imgDY)-102)
canvas.LineTo(120+renderLine, float64(imgDY)-102)
canvas.ClosePath()
canvas.Stroke()
// done.
f, err := os.Create(drawedFile)
if err != nil {
log.Errorln("[score]", err)
data, err := imgfactory.ToBytes(canvas.Image())
if err != nil {
log.Errorln("[score]", err)
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.ImageBytes(data))
@@ -186,6 +239,7 @@ func init() {
}
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
})
engine.OnPrefix("获得签到背景", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
param := ctx.State["args"].(string)
@@ -305,18 +359,22 @@ func getrank(count int) int {
return -1
}
func initPic(picFile string) error {
func initPic(picFile string, uid int64) (avatar []byte, err error) {
if file.IsExist(picFile) {
return nil
return nil, nil
}
defer process.SleepAbout1sTo2s()
url, err := bilibili.GetRealURL(backgroundURL)
if err != nil {
return err
return nil, err
}
data, err := web.RequestDataWith(web.NewDefaultClient(), url, "", referer, "", nil)
if err != nil {
return err
return nil, err
}
return os.WriteFile(picFile, data, 0644)
avatar, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
if err != nil {
return nil, err
}
return avatar, os.WriteFile(picFile, data, 0644)
}

321
plugin/vtbmusic/vtbmusic.go Normal file
View File

@@ -0,0 +1,321 @@
// Package vtbmusic vtb点歌
package vtbmusic
import (
"encoding/json"
"fmt"
"math/rand"
"net/http"
"os"
"path"
"strconv"
"strings"
"time"
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/img/text"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const (
getGroupListURL = "https://aqua.chat/v1/GetGroupsList"
getMusicListURL = "https://aqua.chat/v1/GetMusicList"
fileURL = "https://cdn.aqua.chat/"
musicListBody = `{"search":{"condition":"VocalId","keyword":"%v"},"sortField":"CreateTime","sortType":"desc","pageIndex":1,"pageRows":10000}`
)
type groupsList struct {
Total int `json:"Total"`
Data []struct {
ID string `json:"Id"`
CreateTime string `json:"CreateTime"`
Name string `json:"Name"`
GroupImg string `json:"GroupImg"`
VocalList []struct {
ID string `json:"Id"`
CreateTime string `json:"CreateTime"`
ChineseName string `json:"ChineseName"`
OriginName string `json:"OriginName"`
AvatarImg string `json:"AvatarImg"`
} `json:"VocalList"`
} `json:"Data"`
Success bool `json:"Success"`
ErrorCode int `json:"ErrorCode"`
Msg interface{} `json:"Msg"`
}
type musicList struct {
Total int `json:"Total"`
Data []struct {
ID string `json:"Id"`
CreateTime string `json:"CreateTime"`
PublishTime interface{} `json:"PublishTime"`
CreatorID interface{} `json:"CreatorId"`
CreatorRealName interface{} `json:"CreatorRealName"`
Deleted bool `json:"Deleted"`
OriginName string `json:"OriginName"`
VocalID string `json:"VocalId"`
VocalName string `json:"VocalName"`
CoverImg string `json:"CoverImg"`
Music string `json:"Music"`
Lyric interface{} `json:"Lyric"`
CDN string `json:"CDN"`
BiliBili interface{} `json:"BiliBili"`
YouTube interface{} `json:"YouTube"`
Twitter interface{} `json:"Twitter"`
Likes interface{} `json:"Likes"`
Length float64 `json:"Length"`
Label interface{} `json:"Label"`
IsLike bool `json:"isLike"`
Duration float64 `json:"Duration"`
Source interface{} `json:"Source"`
SourceName interface{} `json:"SourceName"`
Statis struct {
PlayCount int `json:"PlayCount"`
CommentCount int `json:"CommentCount"`
LikeCount int `json:"LikeCount"`
ShareCount int `json:"ShareCount"`
} `json:"Statis"`
VocalList []struct {
ID string `json:"Id"`
Cn string `json:"cn"`
Jp string `json:"jp"`
En string `json:"en"`
Originlang string `json:"originlang"`
} `json:"VocalList"`
} `json:"Data"`
Success bool `json:"Success"`
ErrorCode int `json:"ErrorCode"`
Msg interface{} `json:"Msg"`
}
func init() { // 插件主体
engine := control.Register("vtbmusic", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "vtbmusic.com点歌",
Help: "- vtb点歌\n" +
"- vtb随机点歌",
PrivateDataFolder: "vtbmusic",
})
storePath := engine.DataFolder()
// 开启
engine.OnFullMatch(`vtb点歌`).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession(), zero.RegexRule(`^\d+$`))
recv, cancel := next.Repeat()
defer cancel()
i := 0
paras := [3]int{}
data, err := web.PostData(getGroupListURL, "application/json", strings.NewReader(`{"PageIndex":1,"PageRows":9999}`))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
var (
gl groupsList
ml musicList
num int
imageBytes []byte
)
err = json.Unmarshal(data, &gl)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
tex := "请输入群组序号\n"
for i, v := range gl.Data {
tex += fmt.Sprintf("%d. %s\n", i, v.Name)
}
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
}
for {
select {
case <-time.After(time.Second * 120):
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("vtb点歌超时"))
return
case c := <-recv:
msg := c.Event.Message.ExtractPlainText()
num, err = strconv.Atoi(msg)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请输入数字!"))
continue
}
switch i {
case 0:
if num < 0 || num >= len(gl.Data) {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
continue
}
if len(gl.Data[num].VocalList) == 0 {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无内容, 点歌失败"))
return
}
paras[0] = num
tex = "请输入vtb序号\n"
for i, v := range gl.Data[paras[0]].VocalList {
tex += fmt.Sprintf("%d. %s\n", i, v.OriginName)
}
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
}
case 1:
if num < 0 || num >= len(gl.Data[paras[0]].VocalList) {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
continue
}
paras[1] = num
data, err := web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
err = json.Unmarshal(data, &ml)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if len(ml.Data) == 0 {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无内容, 点歌失败"))
return
}
tex = "请输入歌曲序号\n"
for i, v := range ml.Data {
tex += fmt.Sprintf("%d. %s\n", i, v.OriginName)
}
imageBytes, err = text.RenderToBase64(tex, text.FontFile, 400, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("base64://"+binary.BytesToString(imageBytes))); id.ID() == 0 {
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
}
case 2:
if num < 0 || num >= len(ml.Data) {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("序号非法!"))
continue
}
paras[2] = num
// 最后播放歌曲
groupName := gl.Data[paras[0]].Name
vtbName := gl.Data[paras[0]].VocalList[paras[1]].OriginName
musicName := ml.Data[paras[2]].OriginName
recURL := fileURL + ml.Data[paras[2]].Music
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请欣赏", groupName, "-", vtbName, "的《", musicName, "》"))
recordFile := storePath + fmt.Sprintf("%d-%d-%d", paras[0], paras[1], paras[2]) + path.Ext(recURL)
if file.IsExist(recordFile) {
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
return
}
err = dlrec(recordFile, recURL)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
return
}
i++
}
}
})
engine.OnFullMatch(`vtb随机点歌`).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
var (
paras = [3]int{}
gl groupsList
ml musicList
)
data, err := web.PostData(getGroupListURL, "application/json", strings.NewReader(`{"PageIndex":1,"PageRows":9999}`))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
err = json.Unmarshal(data, &gl)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
if len(gl.Data) == 0 {
ctx.SendChain(message.Text("ERROR: 数组为空"))
return
}
paras[0] = rand.Intn(len(gl.Data))
for len(gl.Data[paras[0]].VocalList) == 0 {
paras[0] = rand.Intn(len(gl.Data))
}
paras[1] = rand.Intn(len(gl.Data[paras[0]].VocalList))
data, err = web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
err = json.Unmarshal(data, &ml)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
for len(ml.Data) == 0 {
paras[1] = rand.Intn(len(gl.Data[paras[0]].VocalList))
data, err = web.PostData(getMusicListURL, "application/json", strings.NewReader(fmt.Sprintf(musicListBody, gl.Data[paras[0]].VocalList[paras[1]].ID)))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
err = json.Unmarshal(data, &ml)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
}
paras[2] = rand.Intn(len(ml.Data))
// 最后播放歌曲
groupName := gl.Data[paras[0]].Name
vtbName := gl.Data[paras[0]].VocalList[paras[1]].OriginName
musicName := ml.Data[paras[2]].OriginName
recURL := fileURL + ml.Data[paras[2]].Music
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("请欣赏", groupName, "-", vtbName, "的《", musicName, "》"))
recordFile := storePath + fmt.Sprintf("%d-%d-%d", paras[0], paras[1], paras[2]) + path.Ext(recURL)
if file.IsExist(recordFile) {
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
return
}
err = dlrec(recordFile, recURL)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + recordFile))
})
}
func dlrec(recordFile, recordURL string) error {
if file.IsNotExist(recordFile) {
data, err := web.RequestDataWithHeaders(web.NewTLS12Client(), recordURL, "GET", func(r *http.Request) error {
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
r.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0")
return nil
}, nil)
if err != nil {
return err
}
return os.WriteFile(recordFile, data, 0666)
}
return nil
}

View File

@@ -7,6 +7,9 @@ import (
"net/http"
"sort"
"github.com/RomiChan/syncx"
"github.com/sirupsen/logrus"
"github.com/FloatTech/floatbox/web"
)
@@ -68,27 +71,40 @@ func getitemsorder(cnName string, onlyMaxRank bool) (od orders, it *itemsInSet,
return
}
func newwm() (wmitems map[string]items, itemNames []string) {
var itemapi wfAPIItem // WarFrame市场的数据实例
type wmdata struct {
wmitems map[string]items
itemNames []string
}
var (
wderr error
wd = syncx.Lazy[*wmdata]{Init: func() (d *wmdata) {
d, wderr = newwm()
return
}}
)
func newwm() (*wmdata, error) {
var itemapi wfAPIItem // WarFrame市场的数据实例
var wd wmdata
data, err := web.RequestDataWithHeaders(&http.Client{}, wfitemurl, "GET", func(request *http.Request) error {
request.Header.Add("Accept", "application/json")
request.Header.Add("Language", "zh-hans")
return nil
}, nil)
if err != nil {
panic(err)
return &wd, err
}
err = json.Unmarshal(data, &itemapi)
if err != nil {
panic(err)
return &wd, err
}
wmitems = make(map[string]items, len(itemapi.Payload.Items)*4)
itemNames = make([]string, len(itemapi.Payload.Items))
wd.wmitems = make(map[string]items, len(itemapi.Payload.Items)*4)
wd.itemNames = make([]string, len(itemapi.Payload.Items))
for i, v := range itemapi.Payload.Items {
wmitems[v.ItemName] = v
itemNames[i] = v.ItemName
wd.wmitems[v.ItemName] = v
wd.itemNames[i] = v.ItemName
}
return
logrus.Infoln("[wfapi] 获取", len(wd.itemNames), "项内容")
return &wd, nil
}

View File

@@ -10,13 +10,12 @@ import (
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/RomiChan/syncx"
"github.com/lithammer/fuzzysearch/fuzzy"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
var wmitems, itemNames = newwm()
func init() {
eng := control.Register("warframeapi", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
@@ -234,10 +233,24 @@ func init() {
ctx.SendChain(message.Text("已拉取服务器时间并同步到本地模拟"))
})
// 根据名称从Warframe市场查询物品售价
eng.OnPrefix(".wm ").SetBlock(true).
eng.OnPrefix(".wm ", func(ctx *zero.Ctx) bool {
if wd.Get().wmitems == nil || wd.Get().itemNames == nil {
if wderr != nil { // 获取失败
ctx.SendChain(message.Text("ERROR: 获取Warframe市场物品列表失败: ", wderr))
} else {
ctx.SendChain(message.Text("ERROR: Warframe市场物品列表为空!"))
}
wd = syncx.Lazy[*wmdata]{Init: func() (d *wmdata) {
d, wderr = newwm()
return
}}
return false
}
return true
}).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
// 根据输入的名称, 从游戏物品名称列表中进行模糊搜索
sol := fuzzy.FindNormalizedFold(ctx.State["args"].(string), itemNames)
sol := fuzzy.FindNormalizedFold(ctx.State["args"].(string), wd.Get().itemNames)
// 物品名称
var name string
@@ -282,16 +295,17 @@ func init() {
if onlymaxrank {
msgs = msgs[:0]
}
sells, iteminfo, txt, err := getitemsorder(wmitems[name].URLName, onlymaxrank)
sells, iteminfo, txt, err := getitemsorder(wd.Get().wmitems[name].URLName, onlymaxrank)
if !onlymaxrank {
if iteminfo.ZhHans.WikiLink == "" {
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
message.Image("https://warframe.market/static/assets/"+wmitems[name].Thumb),
message.Text("\n", wmitems[name].ItemName)))
message.Image("https://warframe.market/static/assets/"+wd.Get().wmitems[name].Thumb),
message.Text("\n", wd.Get().wmitems[name].ItemName)))
} else {
msgs = append(msgs, ctxext.FakeSenderForwardNode(ctx,
message.Image("https://warframe.market/static/assets/"+wmitems[name].Thumb),
message.Text("\n", wmitems[name].ItemName, "\nwiki: ", iteminfo.ZhHans.WikiLink)))
message.Image("https://warframe.market/static/assets/"+wd.Get().wmitems[name].Thumb),
message.Text("\n", wd.Get().wmitems[name].ItemName, "\nwiki: ", iteminfo.ZhHans.WikiLink)))
}
}

View File

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

2
run.sh
View File

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

103
winres/gen/json.go Normal file
View File

@@ -0,0 +1,103 @@
// Package main generates winres.json
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"time"
"github.com/FloatTech/ZeroBot-Plugin/kanban/banner"
)
const js = `{
"RT_GROUP_ICON": {
"APP": {
"0000": [
"icon.png",
"icon16.png"
]
}
},
"RT_MANIFEST": {
"#1": {
"0409": {
"identity": {
"name": "ZeroBot-Plugin",
"version": "%s"
},
"description": "",
"minimum-os": "vista",
"execution-level": "as invoker",
"ui-access": false,
"auto-elevate": false,
"dpi-awareness": "system",
"disable-theming": false,
"disable-window-filtering": false,
"high-resolution-scrolling-aware": false,
"ultra-high-resolution-scrolling-aware": false,
"long-path-aware": false,
"printer-driver-isolation": false,
"gdi-scaling": false,
"segment-heap": false,
"use-common-controls-v6": false
}
}
},
"RT_VERSION": {
"#1": {
"0000": {
"fixed": {
"file_version": "%s",
"product_version": "%s",
"timestamp": "%s"
},
"info": {
"0409": {
"Comments": "OneBot plugins based on ZeroBot",
"CompanyName": "FloatTech",
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
"FileVersion": "%s",
"InternalName": "",
"LegalCopyright": "%s",
"LegalTrademarks": "",
"OriginalFilename": "ZBP.EXE",
"PrivateBuild": "",
"ProductName": "ZeroBot-Plugin",
"ProductVersion": "%s",
"SpecialBuild": ""
}
}
}
}
}
}`
const timeformat = `2006-01-02T15:04:05+08:00`
func main() {
f, err := os.Create("winres.json")
if err != nil {
panic(err)
}
defer f.Close()
i := strings.LastIndex(banner.Version, "-")
if i <= 0 {
i = len(banner.Version)
}
commitcnt := strings.Builder{}
commitcnt.WriteString(banner.Version[1:i])
commitcnt.WriteByte('.')
commitcntcmd := exec.Command("git", "rev-list", "--count", "master")
commitcntcmd.Stdout = &commitcnt
err = commitcntcmd.Run()
if err != nil {
panic(err)
}
fv := commitcnt.String()[:commitcnt.Len()-1]
_, err = fmt.Fprintf(f, js, fv, fv, banner.Version, time.Now().Format(timeformat), fv, banner.Copyright+". All Rights Reserved.", banner.Version)
if err != nil {
panic(err)
}
}

BIN
winres/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
winres/icon16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

4
winres/init.go Normal file
View File

@@ -0,0 +1,4 @@
// Package winres 生成windows资源
package winres
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/winres/gen

62
winres/winres.json Normal file
View File

@@ -0,0 +1,62 @@
{
"RT_GROUP_ICON": {
"APP": {
"0000": [
"icon.png",
"icon16.png"
]
}
},
"RT_MANIFEST": {
"#1": {
"0409": {
"identity": {
"name": "ZeroBot-Plugin",
"version": "1.7.0.1744"
},
"description": "",
"minimum-os": "vista",
"execution-level": "as invoker",
"ui-access": false,
"auto-elevate": false,
"dpi-awareness": "system",
"disable-theming": false,
"disable-window-filtering": false,
"high-resolution-scrolling-aware": false,
"ultra-high-resolution-scrolling-aware": false,
"long-path-aware": false,
"printer-driver-isolation": false,
"gdi-scaling": false,
"segment-heap": false,
"use-common-controls-v6": false
}
}
},
"RT_VERSION": {
"#1": {
"0000": {
"fixed": {
"file_version": "1.7.0.1744",
"product_version": "v1.7.0-beta4",
"timestamp": "2023-03-12T12:28:32+08:00"
},
"info": {
"0409": {
"Comments": "OneBot plugins based on ZeroBot",
"CompanyName": "FloatTech",
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
"FileVersion": "1.7.0.1744",
"InternalName": "",
"LegalCopyright": "© 2020 - 2023 FloatTech. All Rights Reserved.",
"LegalTrademarks": "",
"OriginalFilename": "ZBP.EXE",
"PrivateBuild": "",
"ProductName": "ZeroBot-Plugin",
"ProductVersion": "v1.7.0-beta4",
"SpecialBuild": ""
}
}
}
}
}
}