mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-10 17:20:25 +00:00
Compare commits
34 Commits
v1.2.2-bet
...
v1.2.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce8d98b77d | ||
|
|
2858d0b0a4 | ||
|
|
1f982566e0 | ||
|
|
779ec5b2fe | ||
|
|
8499921d67 | ||
|
|
1e49bad1a6 | ||
|
|
1d3a61386d | ||
|
|
25ef2ca220 | ||
|
|
b953385bc5 | ||
|
|
4fdedd0a7b | ||
|
|
f4bc43e7a5 | ||
|
|
596c75eeca | ||
|
|
67a493ee84 | ||
|
|
f9c7d9419e | ||
|
|
1a1a006283 | ||
|
|
fd85ce0923 | ||
|
|
5ff9069ff2 | ||
|
|
4ad7ff7971 | ||
|
|
a9f98763c4 | ||
|
|
3b637fad78 | ||
|
|
f202797964 | ||
|
|
242d780048 | ||
|
|
bf23364097 | ||
|
|
7eaac7a20b | ||
|
|
45448e6f53 | ||
|
|
08ee458a27 | ||
|
|
3f97541956 | ||
|
|
e2c603338e | ||
|
|
a363623df9 | ||
|
|
b871573dc3 | ||
|
|
ad33c1ca3c | ||
|
|
810cb284b6 | ||
|
|
d0ffb25594 | ||
|
|
2b6796d1d1 |
59
.github/workflows/nightly.yml
vendored
Normal file
59
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
name: 最新版
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
BINARY_PREFIX: "zbp_"
|
||||
BINARY_SUFFIX: ""
|
||||
PR_PROMPT: "::warning:: Build artifact will not be uploaded due to the workflow is trigged by pull request."
|
||||
LD_FLAGS: "-w -s"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build binary CI
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64, darwin/arm64
|
||||
goos: [linux, windows, darwin]
|
||||
goarch: ["386", amd64, arm, arm64]
|
||||
exclude:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: "386"
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@v2.1.3
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: Cache downloaded module
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.goos }}-${{ matrix.goarch }}-${{ hashFiles('**/go.sum') }}
|
||||
- name: Build binary file
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
IS_PR: ${{ !!github.head_ref }}
|
||||
run: |
|
||||
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
||||
if $IS_PR ; then echo $PR_PROMPT; fi
|
||||
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
||||
export CGO_ENABLED=0
|
||||
go build -o "output/$BINARY_NAME" -trimpath -ldflags "$LD_FLAGS" .
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ !github.head_ref }}
|
||||
with:
|
||||
name: ${{ matrix.goos }}_${{ matrix.goarch }}
|
||||
path: output/
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: compile
|
||||
name: 发行版
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
|
||||
@@ -10,10 +10,6 @@ linters-settings:
|
||||
disabled-checks:
|
||||
- exitAfterDefer
|
||||
|
||||
gofumpt:
|
||||
# Select the Go version to target. The default is `1.15`.
|
||||
lang-version: "1.17"
|
||||
|
||||
forbidigo:
|
||||
# Forbid the following identifiers
|
||||
forbid:
|
||||
@@ -22,13 +18,13 @@ linters-settings:
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
fast: true
|
||||
disable-all: true
|
||||
fast: false
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- exportloopref
|
||||
- exhaustive
|
||||
@@ -43,7 +39,7 @@ linters:
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
#- misspell
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
@@ -58,23 +54,9 @@ linters:
|
||||
- prealloc
|
||||
- predeclared
|
||||
- asciicheck
|
||||
- revive
|
||||
- forbidigo
|
||||
- makezero
|
||||
- revive
|
||||
#- interfacer
|
||||
|
||||
# don't enable:
|
||||
# - scopelint
|
||||
# - gochecknoglobals
|
||||
# - gocognit
|
||||
# - godot
|
||||
# - godox
|
||||
# - goerr113
|
||||
# - interfacer
|
||||
# - maligned
|
||||
# - nestif
|
||||
# - testpackage
|
||||
# - wsl
|
||||
|
||||
run:
|
||||
# default concurrency is a available CPU number.
|
||||
@@ -95,4 +77,4 @@ issues:
|
||||
fix: true
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
|
||||
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Seek|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
|
||||
28
README.md
28
README.md
@@ -52,6 +52,8 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
|
||||
- [x] /全局启用 xxx
|
||||
- [x] /全局禁用 xxx
|
||||
- [x] /还原 xxx (在发送的群/用户还原xxx的开启状态到初始状态)
|
||||
- [x] /禁止 service qq1 qq2... (禁止 qqs 使用服务 service)
|
||||
- [x] /允许 service qq1 qq2... (重新允许 qqs 使用服务 service)
|
||||
- [x] /用法 xxx
|
||||
- [x] /服务列表
|
||||
- [x] /服务详情
|
||||
@@ -63,6 +65,7 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
|
||||
- [x] 空调关
|
||||
- [x] 群温度
|
||||
- [x] 设置温度[正整数]
|
||||
- [x] mua|啾咪|摸|上你|傻|裸|贴|老婆|抱|亲|一下|咬|操|123|进去|调教|搓|让|捏|挤|略|呐|原味|胖次|内裤|内衣|衣服|ghs|批|憨批|kkp|咕|骚|喜欢|suki|好き|看|不能|砸了|透|口我|草我|自慰|onani|オナニー|炸了|色图|涩图|告白|对不起|回来|吻|软|壁咚|掰开|女友|是|喵|嗷呜|叫|拜|佬|awsl|臭|香|腿|张开|脚|脸|头发|手|pr|舔|小穴|腰|诶嘿嘿|可爱|扭蛋|鼻|眼|色气|推|床|举|手冲|饿|变|敲|爬|怕|冲|射|不穿|迫害|猫粮|揪尾巴|薄荷|早|晚安|揉|榨|掐|胸|奶子|欧派|嫩|蹭|牵手|握手|拍照|w|睡不着|欧尼酱|哥|爱你|过来|自闭|打不过|么么哒|很懂|膝枕|累了|安慰|洗澡|一起睡觉|一起|多大|姐姐|糖|嗦|牛子|🐂子|🐮子|嫌弃|紧|baka|笨蛋|插|插进来|屁股|翘|翘起来|抬|抬起|爸|傲娇|rua|咕噜咕噜|咕噜|上床|做爱|吃掉|吃|揪|种草莓|种草|掀|妹|病娇|嘻
|
||||
- **ATRI** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_atri"`
|
||||
- [x] 具体指令看 /用法 atri
|
||||
- 注:本插件基于 [ATRI](https://github.com/Kyomotoi/ATRI) ,为 Golang 移植版
|
||||
@@ -91,11 +94,12 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
|
||||
- [x] 列出所有提醒
|
||||
- [x] 翻牌
|
||||
- [x] [开启|关闭]入群验证
|
||||
- [ ] 同意入群请求
|
||||
- [x] [开启|关闭]gist加群自动审批
|
||||
- [ ] 同意好友请求
|
||||
- [ ] 撤回[@xxx] [xxx]
|
||||
- [ ] 警告[@xxx]
|
||||
- [x] run[xxx]
|
||||
- 注:使用gist加群自动审批,请在群介绍添加以下说明,同时开启`需要回答问题并由管理员审核`:加群请在github新建一个gist,其文件名为本群群号的字符串的md5(小写),内容为一行,是当前unix时间戳(10分钟内有效)。然后请将您的用户名和gist哈希(小写)按照username/gisthash的格式填写到回答即可。
|
||||
- **GitHub仓库搜索** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_github"`
|
||||
- [x] >github [xxx]
|
||||
- [x] >github -p [xxx]
|
||||
@@ -175,7 +179,7 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
|
||||
- 注:由于需要科学,默认注释。
|
||||
- **AIfalse** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_ai_false"`
|
||||
- [x] 查询计算机当前活跃度: [检查身体|自检|启动自检|系统状态]
|
||||
- [x] 清理缓存
|
||||
- [x] 清理缓存 (仅适用于 gocq 且需要 bot 的运行目录和 gocq 相同)
|
||||
- [ ] 简易语音
|
||||
- [ ] 爬图合成 [@xxx]
|
||||
- **抽wife** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_nativewife"`
|
||||
@@ -210,8 +214,16 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
|
||||
- [x] vtb语录
|
||||
- [x] 随机vtb
|
||||
- **书评** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_book_review"`
|
||||
- [x] 书评[关键字]
|
||||
- [x] 书评[xxx]
|
||||
- [x] 随机书评
|
||||
- **coser** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_coser" `
|
||||
- [x] coser
|
||||
- **小说** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_novel" `
|
||||
- [x] 小说[xxx]
|
||||
- **骂人** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_curse"`
|
||||
- [x] 骂他[@xxx]|骂他[qq号]
|
||||
- **笑话** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_funny"`
|
||||
- [x] 讲个笑话[@xxx]|讲个笑话[qq号]
|
||||
- **TODO...**
|
||||
|
||||
## 使用方法
|
||||
@@ -259,15 +271,15 @@ go mod tidy
|
||||
|
||||
```bash
|
||||
# 本机平台
|
||||
go build -ldflags "-s -w" -o zerobot
|
||||
go build -ldflags "-s -w" -o zerobot -trimpath
|
||||
# x64 Linux 平台 如各种云服务器
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o zerobot
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o zerobot -trimpath
|
||||
# x64 Windows 平台 如大多数家用电脑
|
||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o zerobot.exe
|
||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o zerobot.exe -trimpath
|
||||
# armv6 Linux 平台 如树莓派 zero W
|
||||
GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=0 go build -ldflags "-s -w" -o zerobot
|
||||
GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=0 go build -ldflags "-s -w" -o zerobot -trimpath
|
||||
# (由于引入了github.com/logoove/sqlite,本项不再可用)mips Linux 平台 如 路由器 wndr4300
|
||||
GOOS=linux GOARCH=mips GOMIPS=softfloat CGO_ENABLED=0 go build -ldflags "-s -w" -o zerobot
|
||||
GOOS=linux GOARCH=mips GOMIPS=softfloat CGO_ENABLED=0 go build -ldflags "-s -w" -o zerobot -trimpath
|
||||
```
|
||||
|
||||
5. 运行 OneBot 框架,并同时运行本插件
|
||||
|
||||
@@ -9,7 +9,7 @@ var enmap = make(map[string]*zero.Engine)
|
||||
// Register 注册插件控制器
|
||||
func Register(service string, o *Options) *zero.Engine {
|
||||
engine := zero.New()
|
||||
engine.UsePreHandler(newctrl(service, o).Handler())
|
||||
engine.UsePreHandler(newctrl(service, o).Handler)
|
||||
enmap[service] = engine
|
||||
return engine
|
||||
}
|
||||
|
||||
157
control/rule.go
157
control/rule.go
@@ -2,6 +2,9 @@
|
||||
package control
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -11,6 +14,7 @@ import (
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
@@ -47,6 +51,10 @@ func newctrl(service string, o *Options) *Control {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Create(service+"ban", &ban{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -125,6 +133,78 @@ func (m *Control) IsEnabledIn(gid int64) bool {
|
||||
return !m.options.DisableOnDefault
|
||||
}
|
||||
|
||||
// Ban 禁止某人在某群使用本插件
|
||||
func (m *Control) Ban(uid, gid int64) {
|
||||
var err error
|
||||
var digest [16]byte
|
||||
logrus.Debugln("[control] Ban recv gid =", gid, "uid =", uid)
|
||||
if gid != 0 { // 特定群
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid)))
|
||||
m.RLock()
|
||||
err = db.Insert(m.service+"ban", &ban{ID: int64(binary.LittleEndian.Uint64(digest[:8])), UserID: uid, GroupID: gid})
|
||||
m.RUnlock()
|
||||
if err == nil {
|
||||
logrus.Debugf("[control] plugin %s is banned in grp %d for usr %d.", m.service, gid, uid)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 所有群
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid)))
|
||||
m.RLock()
|
||||
err = db.Insert(m.service+"ban", &ban{ID: int64(binary.LittleEndian.Uint64(digest[:8])), UserID: uid, GroupID: 0})
|
||||
m.RUnlock()
|
||||
if err == nil {
|
||||
logrus.Debugf("[control] plugin %s is banned in all grp for usr %d.", m.service, uid)
|
||||
}
|
||||
}
|
||||
|
||||
// Permit 允许某人在某群使用本插件
|
||||
func (m *Control) Permit(uid, gid int64) {
|
||||
var digest [16]byte
|
||||
logrus.Debugln("[control] Permit recv gid =", gid, "uid =", uid)
|
||||
if gid != 0 { // 特定群
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid)))
|
||||
m.RLock()
|
||||
_ = db.Del(m.service+"ban", "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10))
|
||||
m.RUnlock()
|
||||
logrus.Debugf("[control] plugin %s is permitted in grp %d for usr %d.", m.service, gid, uid)
|
||||
return
|
||||
}
|
||||
// 所有群
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid)))
|
||||
m.RLock()
|
||||
_ = db.Del(m.service+"ban", "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10))
|
||||
m.RUnlock()
|
||||
logrus.Debugf("[control] plugin %s is permitted in all grp for usr %d.", m.service, uid)
|
||||
}
|
||||
|
||||
// IsBannedIn 某人是否在某群被 ban
|
||||
func (m *Control) IsBannedIn(uid, gid int64) bool {
|
||||
var b ban
|
||||
var err error
|
||||
var digest [16]byte
|
||||
logrus.Debugln("[control] IsBannedIn recv gid =", gid, "uid =", uid)
|
||||
if gid != 0 {
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_%d", uid, gid)))
|
||||
m.RLock()
|
||||
err = db.Find(m.service+"ban", &b, "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10))
|
||||
m.RUnlock()
|
||||
if err == nil && gid == b.GroupID && uid == b.UserID {
|
||||
logrus.Debugf("[control] plugin %s is banned in grp %d for usr %d.", m.service, b.GroupID, b.UserID)
|
||||
return true
|
||||
}
|
||||
}
|
||||
digest = md5.Sum(helper.StringToBytes(fmt.Sprintf("%d_all", uid)))
|
||||
m.RLock()
|
||||
err = db.Find(m.service+"ban", &b, "WHERE id = "+strconv.FormatInt(int64(binary.LittleEndian.Uint64(digest[:8])), 10))
|
||||
m.RUnlock()
|
||||
if err == nil && b.GroupID == 0 && uid == b.UserID {
|
||||
logrus.Debugf("[control] plugin %s is banned in all grp for usr %d.", m.service, b.UserID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetData 获取某个群的 63 字节配置信息
|
||||
func (m *Control) GetData(gid int64) int64 {
|
||||
var c grpcfg
|
||||
@@ -173,21 +253,19 @@ func (m *Control) SetData(groupID int64, data int64) error {
|
||||
}
|
||||
|
||||
// Handler 返回 预处理器
|
||||
func (m *Control) Handler() zero.Rule {
|
||||
return func(ctx *zero.Ctx) bool {
|
||||
ctx.State["manager"] = m
|
||||
grp := ctx.Event.GroupID
|
||||
if grp == 0 {
|
||||
// 个人用户
|
||||
grp = -ctx.Event.UserID
|
||||
}
|
||||
logrus.Debugln("[control] handler get gid =", grp)
|
||||
return m.IsEnabledIn(grp)
|
||||
func (m *Control) Handler(ctx *zero.Ctx) bool {
|
||||
ctx.State["manager"] = m
|
||||
grp := ctx.Event.GroupID
|
||||
if grp == 0 {
|
||||
// 个人用户
|
||||
return m.IsEnabledIn(-ctx.Event.UserID)
|
||||
}
|
||||
logrus.Debugln("[control] handler get gid =", grp)
|
||||
return m.IsEnabledIn(grp) && !m.IsBannedIn(ctx.Event.UserID, grp)
|
||||
}
|
||||
|
||||
// Lookup returns a Manager by the service name, if
|
||||
// not exist, it will returns nil.
|
||||
// not exist, it will return nil.
|
||||
func Lookup(service string) (*Control, bool) {
|
||||
mu.RLock()
|
||||
m, ok := managers[service]
|
||||
@@ -276,6 +354,47 @@ func init() {
|
||||
ctx.SendChain(message.Text("已还原服务的默认启用状态: " + model.Args))
|
||||
})
|
||||
|
||||
zero.OnCommandGroup([]string{
|
||||
"禁止", "ban", "允许", "permit",
|
||||
"全局禁止", "banall", "全局允许", "permitall",
|
||||
}, zero.OnlyGroup, zero.AdminPermission).Handle(func(ctx *zero.Ctx) {
|
||||
model := extension.CommandModel{}
|
||||
_ = ctx.Parse(&model)
|
||||
args := strings.Split(model.Args, " ")
|
||||
if len(args) >= 2 {
|
||||
service, ok := Lookup(args[0])
|
||||
if !ok {
|
||||
ctx.SendChain(message.Text("没有找到指定服务!"))
|
||||
return
|
||||
}
|
||||
grp := ctx.Event.GroupID
|
||||
if strings.Contains(model.Command, "全局") || strings.Contains(model.Command, "all") {
|
||||
grp = 0
|
||||
}
|
||||
msg := "**" + args[0] + "报告**"
|
||||
if strings.Contains(model.Command, "允许") || strings.Contains(model.Command, "permit") {
|
||||
for _, usr := range args[1:] {
|
||||
uid, err := strconv.ParseInt(usr, 10, 64)
|
||||
if err == nil {
|
||||
service.Permit(uid, grp)
|
||||
msg += "\n+ 已允许" + usr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, usr := range args[1:] {
|
||||
uid, err := strconv.ParseInt(usr, 10, 64)
|
||||
if err == nil {
|
||||
service.Ban(uid, grp)
|
||||
msg += "\n- 已禁止" + usr
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text(msg))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("参数错误!"))
|
||||
})
|
||||
|
||||
zero.OnCommandGroup([]string{"用法", "usage"}, userOrGrpAdmin).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
model := extension.CommandModel{}
|
||||
@@ -310,13 +429,13 @@ func init() {
|
||||
ctx.SendChain(message.Text(msg))
|
||||
})
|
||||
|
||||
zero.OnCommandGroup([]string{"服务详情", "service_detail"}, userOrGrpAdmin).
|
||||
zero.OnCommandGroup([]string{"服务详情", "service_detail"}, userOrGrpAdmin, zero.OnlyGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var m message.Message
|
||||
m = append(m,
|
||||
message.CustomNode(
|
||||
ctx.Event.Sender.NickName,
|
||||
ctx.Event.UserID,
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
"---服务详情---",
|
||||
))
|
||||
i := 0
|
||||
@@ -333,17 +452,19 @@ func init() {
|
||||
msg += "\n" + help
|
||||
m = append(m,
|
||||
message.CustomNode(
|
||||
ctx.Event.Sender.NickName,
|
||||
ctx.Event.UserID,
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
msg,
|
||||
))
|
||||
return true
|
||||
})
|
||||
|
||||
ctx.SendGroupForwardMessage(
|
||||
if id := ctx.SendGroupForwardMessage(
|
||||
ctx.Event.GroupID,
|
||||
m,
|
||||
)
|
||||
).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ type grpcfg struct {
|
||||
Disable int64 `db:"disable"` // Disable 默认启用该插件
|
||||
}
|
||||
|
||||
type ban struct {
|
||||
ID int64 `db:"id"`
|
||||
UserID int64 `db:"uid"`
|
||||
GroupID int64 `db:"gid"`
|
||||
}
|
||||
|
||||
// Options holds the optional parameters for the Manager.
|
||||
type Options struct {
|
||||
DisableOnDefault bool
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
// Package webctrl
|
||||
/*
|
||||
* 一个用户webui的包,里面包含了webui所需的所有内容
|
||||
*/
|
||||
// Package webctrl 包含 webui 所需的所有内容
|
||||
package webctrl
|
||||
|
||||
import (
|
||||
|
||||
1607
data/Chat/kimoi.json
Normal file
1607
data/Chat/kimoi.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/Funny/jokes.db
Normal file
BIN
data/Funny/jokes.db
Normal file
Binary file not shown.
5
go.mod
5
go.mod
@@ -3,10 +3,10 @@ module github.com/FloatTech/ZeroBot-Plugin
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/FloatTech/AnimeAPI v1.1.10
|
||||
github.com/FloatTech/AnimeAPI v1.1.11
|
||||
github.com/FloatTech/ZeroBot-Plugin-Gif v0.2.4
|
||||
github.com/FloatTech/bot-manager v1.0.1-0.20211112011524-85b9895271ed
|
||||
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737
|
||||
github.com/antchfx/htmlquery v1.2.3
|
||||
github.com/corona10/goimagehash v1.0.3
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
@@ -25,4 +25,5 @@ require (
|
||||
github.com/tidwall/gjson v1.12.1
|
||||
github.com/wdvxdr1123/ZeroBot v1.4.1
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
golang.org/x/text v0.3.6
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@@ -1,6 +1,6 @@
|
||||
github.com/FloatTech/AnimeAPI v1.1.9/go.mod h1:CC+vF30UGBlcIUxwFOcXIEHoJ4r7c5x2iLQsnUCVdDI=
|
||||
github.com/FloatTech/AnimeAPI v1.1.10 h1:fYkv65P1HBukHi3GpzYulGx/xLshEL9635QXALDryf0=
|
||||
github.com/FloatTech/AnimeAPI v1.1.10/go.mod h1:CC+vF30UGBlcIUxwFOcXIEHoJ4r7c5x2iLQsnUCVdDI=
|
||||
github.com/FloatTech/AnimeAPI v1.1.11 h1:uuV4v5qweh0mI0E2KMiG5XGt0pKboV/EFAlIfSJxIi8=
|
||||
github.com/FloatTech/AnimeAPI v1.1.11/go.mod h1:CC+vF30UGBlcIUxwFOcXIEHoJ4r7c5x2iLQsnUCVdDI=
|
||||
github.com/FloatTech/ZeroBot-Plugin v1.1.5/go.mod h1:kWuUARvU7gs4xLggi8Sy37ja2GRL6k0X6kewe5TiZRs=
|
||||
github.com/FloatTech/ZeroBot-Plugin-Gif v0.2.4 h1:WW0BmmLLqAg+m6qGkrKbsfSIm91fkj3/udt3R7Myodo=
|
||||
github.com/FloatTech/ZeroBot-Plugin-Gif v0.2.4/go.mod h1:W7ag6hml1pZTNzRXKU74OMr6rS8awQKSU+o2g7Gj4O0=
|
||||
@@ -12,8 +12,6 @@ github.com/FloatTech/imgfactory v0.1.1/go.mod h1:ThDALab8aOuU6KVYESVWFqmjcqtm03e
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb h1:Rkj28fqIwGx/EgBzRYtpmJRfH6wqVn7cNdc7aJ0QE4M=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb/go.mod h1:imVKbfKqqeit+C/eaWGb4MKQ3z3gN6pRpBU5RMtp5so=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737 h1:p4o7/eSoP39jwnGZz08N1IpH/mNzg9SdCn7kPM9A9BE=
|
||||
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737/go.mod h1:CKKOWC7mBxd36zxsCB1V8DTrwlTNRQvkSVbYqyUiGEE=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M=
|
||||
|
||||
4
main.go
4
main.go
@@ -32,11 +32,15 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_ai_false" // 服务器监控
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_book_review" // 哀伤雪刃吧推书记录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_choose" // 选择困难症帮手
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_coser" // 三次元小姐姐
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_curse" // 骂人
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_fortune" // 运势
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_funny" // 笑话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_minecraft" // MCSManager
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_moyu" // 摸鱼
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_music" // 点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_novel" // 铅笔小说网搜索
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_omikuji" // 浅草寺求签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_reborn" // 投胎
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin_shindan" // 测定
|
||||
|
||||
@@ -23,7 +23,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
datapath = file.BOT_PATH + "/data/acgimage/"
|
||||
datapath = file.BOTPATH + "/data/acgimage/"
|
||||
cacheuri = "file:///" + datapath + "cache"
|
||||
// r18有一定保护,一般不会发出图片
|
||||
randapi = "&loli=true&r18=true"
|
||||
|
||||
@@ -58,7 +58,10 @@ func diskPercent() string {
|
||||
msg := ""
|
||||
for _, p := range parts {
|
||||
diskInfo, _ := disk.Usage(p.Mountpoint)
|
||||
msg += fmt.Sprintf("\n - %s(%dM) %d%%", p.Mountpoint, diskInfo.Total/1024/1024, uint(math.Round(diskInfo.UsedPercent)))
|
||||
pc := uint(math.Round(diskInfo.UsedPercent))
|
||||
if pc > 0 {
|
||||
msg += fmt.Sprintf("\n - %s(%dM) %d%%", p.Mountpoint, diskInfo.Total/1024/1024, pc)
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ const (
|
||||
// 服务名
|
||||
servicename = "atri"
|
||||
// ATRI 所有命令的优先级
|
||||
prio = 5
|
||||
prio = 15
|
||||
// ATRI 表情的 codechina 镜像
|
||||
res = "https://codechina.csdn.net/u011570312/ZeroBot-Plugin/-/raw/master/plugin_atri/"
|
||||
res = "https://gitcode.net/u011570312/ZeroBot-Plugin/-/raw/master/plugin_atri/"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package b14coder base16384 与 tea 加解密
|
||||
package b14coder
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
type book struct {
|
||||
Id uint64 `db:"id"`
|
||||
BookReview string `db:"bookreview"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
db, err := Open(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newdb := &sql.Sqlite{DBPath: os.Args[2]}
|
||||
err = newdb.Create("bookreview", &book{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rs, err := db.Table("book_review").Select("book_review", "").Rows()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var d string
|
||||
var i uint64
|
||||
for rs.Next() {
|
||||
err := rs.Scan(&d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i++
|
||||
err = newdb.Insert("bookreview", &book{i, d})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
db.Close()
|
||||
newdb.Close()
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/logoove/sqlite"
|
||||
)
|
||||
|
||||
type BrDB = gorm.DB
|
||||
|
||||
func Initialize(dbpath string) *BrDB {
|
||||
var err error
|
||||
if _, err = os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
gdb, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gdb.AutoMigrate(&BookReview{})
|
||||
return (*BrDB)(gdb)
|
||||
}
|
||||
|
||||
func Open(dbpath string) (*BrDB, error) {
|
||||
db, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return (*BrDB)(db), nil
|
||||
}
|
||||
}
|
||||
|
||||
type BookReview struct {
|
||||
gorm.Model
|
||||
BookReview string `gorm:"column:book_review"`
|
||||
}
|
||||
|
||||
func (BookReview) TableName() string {
|
||||
return "book_review"
|
||||
}
|
||||
@@ -13,16 +13,25 @@ import (
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
)
|
||||
|
||||
var poke = rate.NewManager(time.Minute*5, 8) // 戳一戳
|
||||
const (
|
||||
dbpath = "data/Chat/"
|
||||
dbfile = dbpath + "kimoi.json"
|
||||
prio = 10
|
||||
)
|
||||
|
||||
var engine = control.Register("chat", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "chat\n- [BOT名字]\n- [戳一戳BOT]\n- 空调开\n- 空调关\n- 群温度\n- 设置温度[正整数]",
|
||||
})
|
||||
var (
|
||||
poke = rate.NewManager(time.Minute*5, 8) // 戳一戳
|
||||
engine = control.Register("chat", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "chat\n- [BOT名字]\n- [戳一戳BOT]\n- 空调开\n- 空调关\n- 群温度\n- 设置温度[正整数]\n- mua|啾咪|摸|上你|傻|裸|贴|老婆|抱|亲|一下|咬|操|123|进去|调教|搓|让|捏|挤|略|呐|原味|胖次|内裤|内衣|衣服|ghs|批|憨批|kkp|咕|骚|喜欢|suki|好き|看|不能|砸了|透|口我|草我|自慰|onani|オナニー|炸了|色图|涩图|告白|对不起|回来|吻|软|壁咚|掰开|女友|是|喵|嗷呜|叫|拜|佬|awsl|臭|香|腿|张开|脚|脸|头发|手|pr|舔|小穴|腰|诶嘿嘿|可爱|扭蛋|鼻|眼|色气|推|床|举|手冲|饿|变|敲|爬|怕|冲|射|不穿|迫害|猫粮|揪尾巴|薄荷|早|晚安|揉|榨|掐|胸|奶子|欧派|嫩|蹭|牵手|握手|拍照|w|睡不着|欧尼酱|哥|爱你|过来|自闭|打不过|么么哒|很懂|膝枕|累了|安慰|洗澡|一起睡觉|一起|多大|姐姐|糖|嗦|牛子|🐂子|🐮子|嫌弃|紧|baka|笨蛋|插|插进来|屁股|翘|翘起来|抬|抬起|爸|傲娇|rua|咕噜咕噜|咕噜|上床|做爱|吃掉|吃|揪|种草莓|种草|掀|妹|病娇|嘻",
|
||||
})
|
||||
kimomap = make(kimo, 256)
|
||||
chatList = make([]string, 0, 256)
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
// 被喊名字
|
||||
engine.OnFullMatch("", zero.OnlyToMe).SetBlock(true).FirstPriority().
|
||||
engine.OnFullMatch("", zero.OnlyToMe).SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var nickname = zero.BotConfig.NickName[0]
|
||||
time.Sleep(time.Second * 1)
|
||||
@@ -36,7 +45,7 @@ func init() { // 插件主体
|
||||
))
|
||||
})
|
||||
// 戳一戳
|
||||
engine.On("notice/notify/poke", zero.OnlyToMe).SetBlock(false).FirstPriority().
|
||||
engine.On("notice/notify/poke", zero.OnlyToMe).SetBlock(false).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var nickname = zero.BotConfig.NickName[0]
|
||||
switch {
|
||||
@@ -55,18 +64,18 @@ func init() { // 插件主体
|
||||
// 群空调
|
||||
var AirConditTemp = map[int64]int{}
|
||||
var AirConditSwitch = map[int64]bool{}
|
||||
engine.OnFullMatch("空调开").SetBlock(true).FirstPriority().
|
||||
engine.OnFullMatch("空调开").SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
AirConditSwitch[ctx.Event.GroupID] = true
|
||||
ctx.SendChain(message.Text("❄️哔~"))
|
||||
})
|
||||
engine.OnFullMatch("空调关").SetBlock(true).FirstPriority().
|
||||
engine.OnFullMatch("空调关").SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
AirConditSwitch[ctx.Event.GroupID] = false
|
||||
delete(AirConditTemp, ctx.Event.GroupID)
|
||||
ctx.SendChain(message.Text("💤哔~"))
|
||||
})
|
||||
engine.OnRegex(`设置温度(\d+)`).SetBlock(true).FirstPriority().
|
||||
engine.OnRegex(`设置温度(\d+)`).SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if _, exist := AirConditTemp[ctx.Event.GroupID]; !exist {
|
||||
AirConditTemp[ctx.Event.GroupID] = 26
|
||||
@@ -85,7 +94,7 @@ func init() { // 插件主体
|
||||
))
|
||||
}
|
||||
})
|
||||
engine.OnFullMatch(`群温度`).SetBlock(true).FirstPriority().
|
||||
engine.OnFullMatch(`群温度`).SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if _, exist := AirConditTemp[ctx.Event.GroupID]; !exist {
|
||||
AirConditTemp[ctx.Event.GroupID] = 26
|
||||
@@ -102,4 +111,13 @@ func init() { // 插件主体
|
||||
))
|
||||
}
|
||||
})
|
||||
initChatList(func() {
|
||||
engine.OnFullMatchGroup(chatList, zero.OnlyToMe).SetBlock(true).SetPriority(prio).Handle(
|
||||
func(ctx *zero.Ctx) {
|
||||
key := ctx.MessageString()
|
||||
val := *kimomap[key]
|
||||
text := val[rand.Intn(len(val))]
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(text))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
30
plugin_chat/data.go
Normal file
30
plugin_chat/data.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/file"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/process"
|
||||
)
|
||||
|
||||
type kimo = map[string]*[]string
|
||||
|
||||
func initChatList(postinit func()) {
|
||||
go func() {
|
||||
process.SleepAbout1sTo2s()
|
||||
_ = os.MkdirAll(dbpath, 0755)
|
||||
data, err := file.GetLazyData(dbfile, true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
json.Unmarshal(data, &kimomap)
|
||||
for k := range kimomap {
|
||||
chatList = append(chatList, k)
|
||||
}
|
||||
logrus.Infoln("[chat]加载", len(chatList), "条kimoi")
|
||||
postinit()
|
||||
}()
|
||||
}
|
||||
67
plugin_coser/coser.go
Normal file
67
plugin_coser/coser.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// Package coser images
|
||||
package coser
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/web"
|
||||
)
|
||||
|
||||
var (
|
||||
engine = control.Register("coser", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "三次元小姐姐\n- coser\n",
|
||||
})
|
||||
prio = 20
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36"
|
||||
coserURL = "http://ovooa.com/API/cosplay/api.php"
|
||||
limit = rate.NewManager(time.Minute, 5)
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine.OnFullMatch("coser", zero.OnlyGroup).SetBlock(true).SetPriority(prio).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.GroupID).Acquire() {
|
||||
ctx.SendChain(message.Text("请稍后重试0x0..."))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
data, err := web.ReqWith(coserURL, "GET", "", ua)
|
||||
if err != nil {
|
||||
log.Println("err为:", err)
|
||||
}
|
||||
var m message.Message
|
||||
text := gjson.Get(helper.BytesToString(data), "data.Title").String()
|
||||
m = append(m,
|
||||
message.CustomNode(
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
text,
|
||||
))
|
||||
gjson.Get(helper.BytesToString(data), "data.data").ForEach(func(_, value gjson.Result) bool {
|
||||
imgcq := `[CQ:image,file=` + value.String() + `]`
|
||||
m = append(m,
|
||||
message.CustomNode(
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
imgcq),
|
||||
)
|
||||
return true
|
||||
})
|
||||
|
||||
if id := ctx.SendGroupForwardMessage(
|
||||
ctx.Event.GroupID,
|
||||
m).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
54
plugin_curse/curse.go
Normal file
54
plugin_curse/curse.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package curse
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/math"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/web"
|
||||
)
|
||||
|
||||
const (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
curseURL = "https://zuanbot.com/api.php?level=min&lang=zh_cn"
|
||||
)
|
||||
|
||||
var (
|
||||
engine = control.Register("curse", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "骂人\n" +
|
||||
"- 骂他[@xxx]|骂他[qq号]\n",
|
||||
})
|
||||
limit = rate.NewManager(time.Minute, 20)
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine.OnPrefix("骂我").SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.GroupID).Acquire() {
|
||||
return
|
||||
}
|
||||
data, err := web.ReqWith(curseURL, "GET", "", ua)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(helper.BytesToString(data)))
|
||||
})
|
||||
engine.OnRegex(`^骂他.*?(\d+)`, zero.OnlyGroup).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.GroupID).Acquire() {
|
||||
return
|
||||
}
|
||||
data, err := web.ReqWith(curseURL, "GET", "", ua)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.At(math.Str2Int64(ctx.State["regex_matched"].([]string)[1])), message.Text(helper.BytesToString(data)))
|
||||
})
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/RomiChan/protobuf/proto"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
type Composition struct {
|
||||
Array []string `protobuf:"bytes,1,rep"`
|
||||
}
|
||||
|
||||
var (
|
||||
compo Composition
|
||||
)
|
||||
|
||||
type Text struct {
|
||||
Id int64 `db:"id"`
|
||||
Data string `db:"data"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := LoadText(os.Args[1])
|
||||
if err == nil {
|
||||
arrl := len(compo.Array)
|
||||
fmt.Printf("[Diana]读取%d条小作文\n", arrl)
|
||||
db := sql.Sqlite{DBPath: os.Args[2]}
|
||||
err = db.Create("text", &Text{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, d := range compo.Array {
|
||||
s := md5.Sum(helper.StringToBytes(d))
|
||||
i := *(*int64)(unsafe.Pointer(&s))
|
||||
fmt.Printf("[Diana]id: %d\n", i)
|
||||
err = db.Insert("text", &Text{
|
||||
Id: i,
|
||||
Data: d,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c, _ := db.Count("text")
|
||||
fmt.Println("[Diana]转化", c, "条小作文")
|
||||
}
|
||||
err = db.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadText 加载小作文
|
||||
func LoadText(pbfile string) error {
|
||||
data, err := os.ReadFile(pbfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return proto.Unmarshal(data, &compo)
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package data
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
@@ -56,8 +56,8 @@ func LoadText() error {
|
||||
// AddText 添加小作文
|
||||
func AddText(txt string) error {
|
||||
s := md5.Sum(helper.StringToBytes(txt))
|
||||
i := *(*int64)(unsafe.Pointer(&s))
|
||||
return db.Insert("text", &Text{Id: i, Data: txt})
|
||||
i := binary.LittleEndian.Uint64(s[:8])
|
||||
return db.Insert("text", &Text{Id: int64(i), Data: txt})
|
||||
}
|
||||
|
||||
// RandText 随机小作文
|
||||
|
||||
38
plugin_funny/data.go
Normal file
38
plugin_funny/data.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package funny
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/file"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/process"
|
||||
)
|
||||
|
||||
type joke struct {
|
||||
ID uint32 `db:"id"`
|
||||
Text string `db:"text"`
|
||||
}
|
||||
|
||||
const (
|
||||
dbpath = "data/Funny/"
|
||||
dbfile = dbpath + "jokes.db"
|
||||
)
|
||||
|
||||
// 加载数据库
|
||||
func init() {
|
||||
go func() {
|
||||
process.SleepAbout1sTo2s()
|
||||
_ = os.MkdirAll(dbpath, 0755)
|
||||
_, err := file.GetLazyData(dbfile, false, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Create("jokes", &joke{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c, _ := db.Count("jokes")
|
||||
logrus.Infoln("[funny]加载", c, "个笑话")
|
||||
}()
|
||||
}
|
||||
33
plugin_funny/data_test.go
Normal file
33
plugin_funny/data_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package funny
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
func TestFillData(t *testing.T) {
|
||||
data, err := os.ReadFile("laugh.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
db := &sql.Sqlite{DBPath: "jokes.db"}
|
||||
err = db.Create("jokes", &joke{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
jokes := strings.Split(helper.BytesToString(data), "\n")
|
||||
for _, j := range jokes {
|
||||
s := md5.Sum(helper.StringToBytes(j))
|
||||
db.Insert("jokes", &joke{ID: binary.LittleEndian.Uint32(s[:4]), Text: j})
|
||||
}
|
||||
err = db.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
47
plugin_funny/laugh.go
Normal file
47
plugin_funny/laugh.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package funny
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
var (
|
||||
engine = control.Register("curse", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "讲个笑话\n" +
|
||||
"- 讲个笑话[@xxx]|讲个笑话[qq号]\n",
|
||||
})
|
||||
limit = rate.NewManager(time.Minute, 20)
|
||||
db = &sql.Sqlite{DBPath: dbfile}
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine.OnPrefix("讲个笑话").SetBlock(true).FirstPriority().Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.GroupID).Acquire() {
|
||||
return
|
||||
}
|
||||
// 获取名字
|
||||
name := ctx.State["args"].(string)
|
||||
if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" {
|
||||
qq, _ := strconv.ParseInt(ctx.Event.Message[1].Data["qq"], 10, 64)
|
||||
name = ctx.GetGroupMemberInfo(ctx.Event.GroupID, qq, false).Get("nickname").Str
|
||||
} else if name == "" {
|
||||
name = ctx.Event.Sender.NickName
|
||||
}
|
||||
var j joke
|
||||
err := db.Pick("jokes", &j)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(strings.ReplaceAll(j.Text, "%name", name)))
|
||||
})
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
cachedir = file.BOT_PATH + "/data/hs/"
|
||||
cachedir = file.BOTPATH + "/data/hs/"
|
||||
reqconf = [...]string{"GET", "https://hs.fbigame.com",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Mobile Safari/537.36"}
|
||||
)
|
||||
@@ -85,16 +85,18 @@ func init() {
|
||||
sk = append(
|
||||
sk,
|
||||
message.CustomNode(
|
||||
ctx.Event.Sender.NickName,
|
||||
ctx.Event.UserID,
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
imgcq, // 图片
|
||||
),
|
||||
)
|
||||
}
|
||||
ctx.SendGroupForwardMessage(
|
||||
if id := ctx.SendGroupForwardMessage(
|
||||
ctx.Event.GroupID,
|
||||
sk,
|
||||
)
|
||||
).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
// 卡组
|
||||
engine.OnRegex(`^[\s\S]*?(AAE[a-zA-Z0-9/\+=]{70,})[\s\S]*$`).
|
||||
|
||||
44
plugin_manager/gist.go
Normal file
44
plugin_manager/gist.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/math"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/web"
|
||||
)
|
||||
|
||||
// user hash file
|
||||
const gistraw = "https://gist.githubusercontent.com/%s/%s/raw/%s"
|
||||
|
||||
func checkNewUser(qq, gid int64, ghun, hash string) (bool, string) {
|
||||
if db.CanFind("member", "where ghun="+ghun) {
|
||||
return false, "该github用户已入群"
|
||||
}
|
||||
gidsum := md5.Sum(helper.StringToBytes(strconv.FormatInt(gid, 10)))
|
||||
gidhex := hex.EncodeToString(gidsum[:])
|
||||
u := fmt.Sprintf(gistraw, ghun, hash, gidhex)
|
||||
logrus.Debugln("[gist]visit url:", u)
|
||||
data, err := web.GetData(u)
|
||||
if err == nil {
|
||||
logrus.Debugln("[gist]get data:", helper.BytesToString(data))
|
||||
st, err := strconv.ParseInt(helper.BytesToString(data), 10, 64)
|
||||
if err == nil {
|
||||
// 600s 内验证成功
|
||||
ok := math.Abs(int(time.Now().Unix()-st)) < 600
|
||||
if ok {
|
||||
_ = db.Insert("member", &Member{QQ: qq, Ghun: ghun})
|
||||
return true, ""
|
||||
}
|
||||
return false, "时间戳超时"
|
||||
}
|
||||
return false, "时间戳格式错误: " + helper.BytesToString(data)
|
||||
}
|
||||
return false, "无法连接到gist: " + err.Error()
|
||||
}
|
||||
12
plugin_manager/manager.db.go
Normal file
12
plugin_manager/manager.db.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package manager
|
||||
|
||||
type Welcome struct {
|
||||
GrpID int64 `db:"gid"`
|
||||
Msg string `db:"msg"`
|
||||
}
|
||||
|
||||
type Member struct {
|
||||
QQ int64 `db:"qq"`
|
||||
// github username
|
||||
Ghun string `db:"ghun"`
|
||||
}
|
||||
@@ -3,15 +3,12 @@ package manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RomiChan/protobuf/proto"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
@@ -19,15 +16,15 @@ import (
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/plugin_manager/timer"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/file"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/math"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/process"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
const (
|
||||
datapath = "data/manager/"
|
||||
confile = datapath + "config.pb"
|
||||
timerfile = datapath + "timers.pb"
|
||||
hint = "====群管====\n" +
|
||||
datapath = "data/manager/"
|
||||
confile = datapath + "config.db"
|
||||
hint = "====群管====\n" +
|
||||
"- 禁言@QQ 1分钟\n" +
|
||||
"- 解除禁言 @QQ\n" +
|
||||
"- 我要自闭 1分钟\n" +
|
||||
@@ -55,32 +52,34 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
config Config
|
||||
limit = rate.NewManager(time.Minute*5, 2)
|
||||
clock timer.Clock
|
||||
db = &sql.Sqlite{DBPath: confile}
|
||||
limit = rate.NewManager(time.Minute*5, 2)
|
||||
clock timer.Clock
|
||||
)
|
||||
|
||||
var engine = control.Register("manager", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: hint,
|
||||
})
|
||||
|
||||
func init() { // 插件主体
|
||||
loadConfig()
|
||||
go func() {
|
||||
time.Sleep(time.Second + time.Millisecond*time.Duration(rand.Intn(1000)))
|
||||
clock = timer.NewClock(timerfile)
|
||||
process.SleepAbout1sTo2s()
|
||||
clock = timer.NewClock(db)
|
||||
db.Create("welcome", &Welcome{})
|
||||
db.Create("member", &Member{})
|
||||
}()
|
||||
// 升为管理
|
||||
engine.OnRegex(`^升为管理.*?(\d+)`, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupAdmin(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
true,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被升为管理的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被升为管理的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
ctx.SendChain(message.Text(nickname + " 升为了管理~"))
|
||||
@@ -90,12 +89,12 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupAdmin(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
false,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被取消管理的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被取消管理的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
ctx.SendChain(message.Text("残念~ " + nickname + " 暂时失去了管理员的资格"))
|
||||
@@ -105,12 +104,12 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupKick(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
false,
|
||||
)
|
||||
nickname := ctx.GetGroupMemberInfo( // 被踢出群聊的人的昵称
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被踢出群聊的人的qq
|
||||
false,
|
||||
).Get("nickname").Str
|
||||
ctx.SendChain(message.Text("残念~ " + nickname + " 被放逐"))
|
||||
@@ -119,7 +118,7 @@ func init() { // 插件主体
|
||||
engine.OnRegex(`^退出群聊.*?(\d+)`, zero.OnlyToMe, zero.SuperUserPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupLeave(
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 要退出的群的群号
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要退出的群的群号
|
||||
true,
|
||||
)
|
||||
})
|
||||
@@ -144,7 +143,7 @@ func init() { // 插件主体
|
||||
// 禁言
|
||||
engine.OnRegex(`^禁言.*?(\d+).*?\s(\d+)(.*)`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
duration := strToInt(ctx.State["regex_matched"].([]string)[2])
|
||||
duration := math.Str2Int64(ctx.State["regex_matched"].([]string)[2])
|
||||
switch ctx.State["regex_matched"].([]string)[3] {
|
||||
case "分钟":
|
||||
//
|
||||
@@ -160,7 +159,7 @@ func init() { // 插件主体
|
||||
}
|
||||
ctx.SetGroupBan(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 要禁言的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要禁言的人的qq
|
||||
duration*60, // 要禁言的时间(分钟)
|
||||
)
|
||||
ctx.SendChain(message.Text("小黑屋收留成功~"))
|
||||
@@ -170,7 +169,7 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupBan(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 要解除禁言的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要解除禁言的人的qq
|
||||
0,
|
||||
)
|
||||
ctx.SendChain(message.Text("小黑屋释放成功~"))
|
||||
@@ -178,7 +177,7 @@ func init() { // 插件主体
|
||||
// 自闭禁言
|
||||
engine.OnRegex(`^(我要自闭|禅定).*?(\d+)(.*)`, zero.OnlyGroup).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
duration := strToInt(ctx.State["regex_matched"].([]string)[2])
|
||||
duration := math.Str2Int64(ctx.State["regex_matched"].([]string)[2])
|
||||
switch ctx.State["regex_matched"].([]string)[3] {
|
||||
case "分钟", "min", "mins", "m":
|
||||
break
|
||||
@@ -204,8 +203,8 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupCard(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被修改群名片的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群名片
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被修改群名片的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群名片
|
||||
)
|
||||
ctx.SendChain(message.Text("嗯!已经修改了"))
|
||||
})
|
||||
@@ -214,8 +213,8 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SetGroupSpecialTitle(
|
||||
ctx.Event.GroupID,
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 被修改群头衔的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群头衔
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 被修改群头衔的人
|
||||
ctx.State["regex_matched"].([]string)[2], // 修改成的群头衔
|
||||
)
|
||||
ctx.SendChain(message.Text("嗯!已经修改了"))
|
||||
})
|
||||
@@ -237,7 +236,7 @@ func init() { // 插件主体
|
||||
content = strings.ReplaceAll(content, "[", "[")
|
||||
content = strings.ReplaceAll(content, "]", "]")
|
||||
ctx.SendGroupMessage(
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 需要发送的群
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 需要发送的群
|
||||
content, // 需要发送的信息
|
||||
)
|
||||
ctx.SendChain(message.Text("📧 --> " + ctx.State["regex_matched"].([]string)[1]))
|
||||
@@ -250,7 +249,7 @@ func init() { // 插件主体
|
||||
content = strings.ReplaceAll(content, "[", "[")
|
||||
content = strings.ReplaceAll(content, "]", "]")
|
||||
ctx.SendPrivateMessage(
|
||||
strToInt(ctx.State["regex_matched"].([]string)[1]), // 需要发送的人的qq
|
||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 需要发送的人的qq
|
||||
content, // 需要发送的信息
|
||||
)
|
||||
ctx.SendChain(message.Text("📧 --> " + ctx.State["regex_matched"].([]string)[1]))
|
||||
@@ -259,9 +258,9 @@ func init() { // 插件主体
|
||||
engine.OnRegex(`^在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分时(用.+)?提醒大家(.*)`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
dateStrs := ctx.State["regex_matched"].([]string)
|
||||
ts := timer.GetFilledTimer(dateStrs, ctx.Event.SelfID, false)
|
||||
ts := timer.GetFilledTimer(dateStrs, ctx.Event.SelfID, ctx.Event.GroupID, false)
|
||||
if ts.En() {
|
||||
go clock.RegisterTimer(ts, ctx.Event.GroupID, true)
|
||||
go clock.RegisterTimer(ts, true)
|
||||
ctx.SendChain(message.Text("记住了~"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("参数非法:" + ts.Alert))
|
||||
@@ -283,8 +282,8 @@ func init() { // 插件主体
|
||||
return
|
||||
}
|
||||
logrus.Debugln("[manager] cron:", dateStrs[1])
|
||||
ts := timer.GetFilledCronTimer(dateStrs[1], alert, url, ctx.Event.SelfID)
|
||||
if clock.RegisterTimer(ts, ctx.Event.GroupID, true) {
|
||||
ts := timer.GetFilledCronTimer(dateStrs[1], alert, url, ctx.Event.SelfID, ctx.Event.GroupID)
|
||||
if clock.RegisterTimer(ts, true) {
|
||||
ctx.SendChain(message.Text("记住了~"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("参数非法:" + ts.Alert))
|
||||
@@ -294,8 +293,8 @@ func init() { // 插件主体
|
||||
engine.OnRegex(`^取消在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分的提醒`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
dateStrs := ctx.State["regex_matched"].([]string)
|
||||
ts := timer.GetFilledTimer(dateStrs, ctx.Event.SelfID, true)
|
||||
ti := ts.GetTimerInfo(ctx.Event.GroupID)
|
||||
ts := timer.GetFilledTimer(dateStrs, ctx.Event.SelfID, ctx.Event.GroupID, true)
|
||||
ti := ts.GetTimerID()
|
||||
ok := clock.CancelTimer(ti)
|
||||
if ok {
|
||||
ctx.SendChain(message.Text("取消成功~"))
|
||||
@@ -307,8 +306,8 @@ func init() { // 插件主体
|
||||
engine.OnRegex(`^取消在"(.*)"的提醒`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
dateStrs := ctx.State["regex_matched"].([]string)
|
||||
ts := timer.Timer{Cron: dateStrs[1]}
|
||||
ti := ts.GetTimerInfo(ctx.Event.GroupID)
|
||||
ts := timer.Timer{Cron: dateStrs[1], GrpId: ctx.Event.GroupID}
|
||||
ti := ts.GetTimerID()
|
||||
ok := clock.CancelTimer(ti)
|
||||
if ok {
|
||||
ctx.SendChain(message.Text("取消成功~"))
|
||||
@@ -363,46 +362,50 @@ func init() { // 插件主体
|
||||
engine.OnNotice().SetBlock(false).FirstPriority().
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if ctx.Event.NoticeType == "group_increase" && ctx.Event.SelfID != ctx.Event.UserID {
|
||||
word, ok := config.Welcome[ctx.Event.GroupID]
|
||||
if ok {
|
||||
ctx.SendChain(message.Text(word))
|
||||
var w Welcome
|
||||
err := db.Find("welcome", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text(w.Msg))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("欢迎~"))
|
||||
}
|
||||
enable, ok1 := config.Checkin[ctx.Event.GroupID]
|
||||
if ok1 && enable {
|
||||
uid := ctx.Event.UserID
|
||||
a := rand.Intn(100)
|
||||
b := rand.Intn(100)
|
||||
r := a + b
|
||||
ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("考你一道题:%d+%d=?\n如果60秒之内答不上来,%s就要把你踢出去了哦~", a, b, zero.BotConfig.NickName[0])))
|
||||
// 匹配发送者进行验证
|
||||
rule := func(ctx *zero.Ctx) bool {
|
||||
for _, elem := range ctx.Event.Message {
|
||||
if elem.Type == "text" {
|
||||
text := strings.ReplaceAll(elem.Data["text"], " ", "")
|
||||
ans, err := strconv.Atoi(text)
|
||||
if err == nil {
|
||||
if ans != r {
|
||||
ctx.SendChain(message.Text("答案不对哦,再想想吧~"))
|
||||
return false
|
||||
c, ok := control.Lookup("manager")
|
||||
if ok {
|
||||
enable := c.GetData(ctx.Event.GroupID)&1 == 1
|
||||
if enable {
|
||||
uid := ctx.Event.UserID
|
||||
a := rand.Intn(100)
|
||||
b := rand.Intn(100)
|
||||
r := a + b
|
||||
ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("考你一道题:%d+%d=?\n如果60秒之内答不上来,%s就要把你踢出去了哦~", a, b, zero.BotConfig.NickName[0])))
|
||||
// 匹配发送者进行验证
|
||||
rule := func(ctx *zero.Ctx) bool {
|
||||
for _, elem := range ctx.Event.Message {
|
||||
if elem.Type == "text" {
|
||||
text := strings.ReplaceAll(elem.Data["text"], " ", "")
|
||||
ans, err := strconv.Atoi(text)
|
||||
if err == nil {
|
||||
if ans != r {
|
||||
ctx.SendChain(message.Text("答案不对哦,再想想吧~"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
next := zero.NewFutureEvent("message", 999, false, zero.CheckUser(ctx.Event.UserID), rule)
|
||||
recv, cancel := next.Repeat()
|
||||
select {
|
||||
case <-time.After(time.Minute):
|
||||
ctx.SendChain(message.Text("拜拜啦~"))
|
||||
ctx.SetGroupKick(ctx.Event.GroupID, uid, false)
|
||||
cancel()
|
||||
case <-recv:
|
||||
cancel()
|
||||
ctx.SendChain(message.Text("答对啦~"))
|
||||
}
|
||||
return false
|
||||
}
|
||||
next := zero.NewFutureEvent("message", 999, false, zero.CheckUser(ctx.Event.UserID), rule)
|
||||
recv, cancel := next.Repeat()
|
||||
select {
|
||||
case <-time.After(time.Minute):
|
||||
ctx.SendChain(message.Text("拜拜啦~"))
|
||||
ctx.SetGroupKick(ctx.Event.GroupID, uid, false)
|
||||
cancel()
|
||||
case <-recv:
|
||||
cancel()
|
||||
ctx.SendChain(message.Text("答对啦~"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,30 +422,66 @@ func init() { // 插件主体
|
||||
// 设置欢迎语
|
||||
engine.OnRegex(`^设置欢迎语([\s\S]*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
config.Welcome[ctx.Event.GroupID] = ctx.State["regex_matched"].([]string)[1]
|
||||
if saveConfig() == nil {
|
||||
w := &Welcome{
|
||||
GrpID: ctx.Event.GroupID,
|
||||
Msg: ctx.State["regex_matched"].([]string)[1],
|
||||
}
|
||||
err := db.Insert("welcome", w)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("记住啦!"))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("出错啦!"))
|
||||
ctx.SendChain(message.Text("出错啦: ", err))
|
||||
}
|
||||
})
|
||||
// 入群验证开关
|
||||
// 入群后验证开关
|
||||
engine.OnRegex(`^(.*)入群验证$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
switch option {
|
||||
case "开启":
|
||||
config.Checkin[ctx.Event.GroupID] = true
|
||||
case "关闭":
|
||||
config.Checkin[ctx.Event.GroupID] = false
|
||||
default:
|
||||
c, ok := control.Lookup("manager")
|
||||
if ok {
|
||||
data := c.GetData(ctx.Event.GroupID)
|
||||
switch option {
|
||||
case "开启", "打开", "启用":
|
||||
data |= 1
|
||||
case "关闭", "关掉", "禁用":
|
||||
data &= 0x7fffffff_fffffffe
|
||||
default:
|
||||
return
|
||||
}
|
||||
err := c.SetData(ctx.Event.GroupID, data)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("已", option))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("出错啦: ", err))
|
||||
return
|
||||
}
|
||||
if saveConfig() == nil {
|
||||
ctx.SendChain(message.Text("已", option))
|
||||
} else {
|
||||
ctx.SendChain(message.Text("出错啦!"))
|
||||
ctx.SendChain(message.Text("找不到服务!"))
|
||||
})
|
||||
// 加群 gist 验证开关
|
||||
engine.OnRegex(`^(.*)gist加群自动审批$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
c, ok := control.Lookup("manager")
|
||||
if ok {
|
||||
data := c.GetData(ctx.Event.GroupID)
|
||||
switch option {
|
||||
case "开启", "打开", "启用":
|
||||
data |= 0x10
|
||||
case "关闭", "关掉", "禁用":
|
||||
data &= 0x7fffffff_fffffffd
|
||||
default:
|
||||
return
|
||||
}
|
||||
err := c.SetData(ctx.Event.GroupID, data)
|
||||
if err == nil {
|
||||
ctx.SendChain(message.Text("已", option))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("出错啦: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("找不到服务!"))
|
||||
})
|
||||
// 运行 CQ 码
|
||||
engine.OnRegex(`^run(.*)$`, zero.SuperUserPermission).SetBlock(true).SetPriority(0).
|
||||
@@ -453,61 +492,32 @@ func init() { // 插件主体
|
||||
// 可注入,权限为主人
|
||||
ctx.Send(cmd)
|
||||
})
|
||||
// 自动同意加好友,被邀请入群(从qingyunke移过来,先注释)
|
||||
/*
|
||||
engine.OnRequest().SetBlock(false).FirstPriority().Handle(func(ctx *zero.Ctx) {
|
||||
if ctx.Event.RequestType == "friend" {
|
||||
ctx.SetFriendAddRequest(ctx.Event.Flag, true, "")
|
||||
// 根据 gist 自动同意加群
|
||||
// 加群请在github新建一个gist,其文件名为本群群号的字符串的md5(小写),内容为一行,是当前unix时间戳(10分钟内有效)。
|
||||
// 然后请将您的用户名和gist哈希(小写)按照username/gisthash的格式填写到回答即可。
|
||||
engine.OnRequest().SetBlock(false).FirstPriority().Handle(func(ctx *zero.Ctx) {
|
||||
/*if ctx.Event.RequestType == "friend" {
|
||||
ctx.SetFriendAddRequest(ctx.Event.Flag, true, "")
|
||||
}*/
|
||||
c, ok := control.Lookup("manager")
|
||||
if ok && c.GetData(ctx.Event.GroupID)&0x10 == 0x10 && ctx.Event.RequestType == "group" && ctx.Event.SubType == "add" {
|
||||
// gist 文件名是群号的 ascii 编码的 md5
|
||||
// gist 内容是当前 uinx 时间戳,在 10 分钟内视为有效
|
||||
ans := ctx.Event.Comment[strings.Index(ctx.Event.Comment, "答案:")+len("答案:"):]
|
||||
divi := strings.Index(ans, "/")
|
||||
if divi <= 0 {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", false, "格式错误!")
|
||||
return
|
||||
}
|
||||
if ctx.Event.RequestType == "group" && ctx.Event.SubType == "invite" {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "invite", true, "我爱你,mua~")
|
||||
}
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
func strToInt(str string) int64 {
|
||||
val, _ := strconv.ParseInt(str, 10, 64)
|
||||
return val
|
||||
}
|
||||
|
||||
// loadConfig 加载设置,没有则手动初始化
|
||||
func loadConfig() {
|
||||
mkdirerr := os.MkdirAll(datapath, 0755)
|
||||
if mkdirerr == nil {
|
||||
if file.IsExist(confile) {
|
||||
f, err := os.Open(confile)
|
||||
if err == nil {
|
||||
data, err1 := io.ReadAll(f)
|
||||
if err1 == nil {
|
||||
if len(data) > 0 {
|
||||
if proto.Unmarshal(data, &config) == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
ghun := ans[:divi]
|
||||
hash := ans[divi+1:]
|
||||
logrus.Infoln("[manager]收到加群申请, 用户:", ghun, ", hash:", hash)
|
||||
ok, reason := checkNewUser(ctx.Event.UserID, ctx.Event.GroupID, ghun, hash)
|
||||
if ok {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", true, "")
|
||||
} else {
|
||||
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", false, reason)
|
||||
}
|
||||
}
|
||||
config.Checkin = make(map[int64]bool)
|
||||
config.Welcome = make(map[int64]string)
|
||||
} else {
|
||||
panic(mkdirerr)
|
||||
}
|
||||
}
|
||||
|
||||
// saveConfig 保存设置,无此文件则新建
|
||||
func saveConfig() error {
|
||||
data, err := proto.Marshal(&config)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if file.IsExist(datapath) {
|
||||
f, err1 := os.OpenFile(confile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
defer f.Close()
|
||||
_, err2 := f.Write(data)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package manager
|
||||
|
||||
type Config struct {
|
||||
Checkin map[int64]bool `protobuf:"bytes,1,rep" protobuf_key:"varint,1,opt" protobuf_val:"varint,2,opt"`
|
||||
Welcome map[int64]string `protobuf:"bytes,2,rep" protobuf_key:"varint,1,opt" protobuf_val:"bytes,2,opt"`
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package timer
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -8,28 +10,37 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
// GetTimerInfo 获得标准化定时字符串
|
||||
func (ts *Timer) GetTimerInfo(grp int64) string {
|
||||
func (ts *Timer) GetTimerInfo() string {
|
||||
if ts.Cron != "" {
|
||||
return fmt.Sprintf("[%d]%s", grp, ts.Cron)
|
||||
return fmt.Sprintf("[%d]%s", ts.GrpId, ts.Cron)
|
||||
}
|
||||
return fmt.Sprintf("[%d]%d月%d日%d周%d:%d", grp, ts.Month(), ts.Day(), ts.Week(), ts.Hour(), ts.Minute())
|
||||
return fmt.Sprintf("[%d]%d月%d日%d周%d:%d", ts.GrpId, ts.Month(), ts.Day(), ts.Week(), ts.Hour(), ts.Minute())
|
||||
}
|
||||
|
||||
// GetTimerInfo 获得标准化 ID
|
||||
func (ts *Timer) GetTimerID() uint32 {
|
||||
key := ts.GetTimerInfo()
|
||||
m := md5.Sum(helper.StringToBytes(key))
|
||||
return binary.LittleEndian.Uint32(m[:4])
|
||||
}
|
||||
|
||||
// GetFilledCronTimer 获得以cron填充好的ts
|
||||
func GetFilledCronTimer(croncmd string, alert string, img string, botqq int64) *Timer {
|
||||
func GetFilledCronTimer(croncmd string, alert string, img string, botqq, gid int64) *Timer {
|
||||
var ts Timer
|
||||
ts.Alert = alert
|
||||
ts.Cron = croncmd
|
||||
ts.Url = img
|
||||
ts.Selfid = botqq
|
||||
ts.GrpId = gid
|
||||
return &ts
|
||||
}
|
||||
|
||||
// GetFilledTimer 获得填充好的ts
|
||||
func GetFilledTimer(dateStrs []string, botqq int64, matchDateOnly bool) *Timer {
|
||||
func GetFilledTimer(dateStrs []string, botqq, grp int64, matchDateOnly bool) *Timer {
|
||||
monthStr := []rune(dateStrs[1])
|
||||
dayWeekStr := []rune(dateStrs[2])
|
||||
hourStr := []rune(dateStrs[3])
|
||||
@@ -43,7 +54,8 @@ func GetFilledTimer(dateStrs []string, botqq int64, matchDateOnly bool) *Timer {
|
||||
}
|
||||
ts.SetMonth(mon)
|
||||
lenOfDW := len(dayWeekStr)
|
||||
if lenOfDW == 4 { // 包括末尾的"日"
|
||||
switch {
|
||||
case lenOfDW == 4: // 包括末尾的"日"
|
||||
dayWeekStr = []rune{dayWeekStr[0], dayWeekStr[2]} // 去除中间的十
|
||||
d := chineseNum2Int(dayWeekStr)
|
||||
if (d != -1 && d <= 0) || d > 31 { // 日期非法
|
||||
@@ -51,7 +63,7 @@ func GetFilledTimer(dateStrs []string, botqq int64, matchDateOnly bool) *Timer {
|
||||
return &ts
|
||||
}
|
||||
ts.SetDay(d)
|
||||
} else if dayWeekStr[lenOfDW-1] == rune('日') { // xx日
|
||||
case dayWeekStr[lenOfDW-1] == rune('日'): // xx日
|
||||
dayWeekStr = dayWeekStr[:lenOfDW-1]
|
||||
d := chineseNum2Int(dayWeekStr)
|
||||
if (d != -1 && d <= 0) || d > 31 { // 日期非法
|
||||
@@ -59,9 +71,9 @@ func GetFilledTimer(dateStrs []string, botqq int64, matchDateOnly bool) *Timer {
|
||||
return &ts
|
||||
}
|
||||
ts.SetDay(d)
|
||||
} else if dayWeekStr[0] == rune('每') { // 每周
|
||||
case dayWeekStr[0] == rune('每'): // 每周
|
||||
ts.SetWeek(-1)
|
||||
} else { // 周x
|
||||
default: // 周x
|
||||
w := chineseNum2Int(dayWeekStr[1:])
|
||||
if w == 7 { // 周天是0
|
||||
w = 0
|
||||
@@ -105,6 +117,7 @@ func GetFilledTimer(dateStrs []string, botqq int64, matchDateOnly bool) *Timer {
|
||||
ts.SetEn(true)
|
||||
}
|
||||
ts.Selfid = botqq
|
||||
ts.GrpId = grp
|
||||
return &ts
|
||||
}
|
||||
|
||||
@@ -116,13 +129,14 @@ func chineseNum2Int(rs []rune) int {
|
||||
if unicode.IsDigit(rs[0]) { // 默认可能存在的第二位也为int
|
||||
r, _ = strconv.Atoi(string(rs))
|
||||
} else {
|
||||
if rs[0] == mai {
|
||||
switch {
|
||||
case rs[0] == mai:
|
||||
if l == 2 {
|
||||
r = -chineseChar2Int(rs[1])
|
||||
}
|
||||
} else if l == 1 {
|
||||
case l == 1:
|
||||
r = chineseChar2Int(rs[0])
|
||||
} else {
|
||||
default:
|
||||
ten := chineseChar2Int(rs[0])
|
||||
if ten != 10 {
|
||||
ten *= 10
|
||||
|
||||
@@ -56,11 +56,12 @@ func (ts *Timer) nextWakeTime() (date time.Time) {
|
||||
} else {
|
||||
stable |= 0x8
|
||||
}
|
||||
if d < 0 {
|
||||
switch {
|
||||
case d < 0:
|
||||
d = date.Day()
|
||||
} else if d > 0 {
|
||||
case d > 0:
|
||||
stable |= 0x4
|
||||
} else {
|
||||
default:
|
||||
d = date.Day()
|
||||
if w >= 0 {
|
||||
stable |= 0x2
|
||||
@@ -148,14 +149,14 @@ func (ts *Timer) nextWakeTime() (date time.Time) {
|
||||
return date
|
||||
}
|
||||
|
||||
func (ts *Timer) judgeHM(grp int64) {
|
||||
func (ts *Timer) judgeHM() {
|
||||
if ts.Hour() < 0 || ts.Hour() == time.Now().Hour() {
|
||||
if ts.Minute() < 0 || ts.Minute() == time.Now().Minute() {
|
||||
if ts.Selfid != 0 {
|
||||
ts.sendmsg(grp, zero.GetBot(ts.Selfid))
|
||||
ts.sendmsg(ts.GrpId, zero.GetBot(ts.Selfid))
|
||||
} else {
|
||||
zero.RangeBot(func(id int64, ctx *zero.Ctx) (_ bool) {
|
||||
ts.sendmsg(grp, ctx)
|
||||
ts.sendmsg(ts.GrpId, ctx)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
26
plugin_manager/timer/timer.db.go
Normal file
26
plugin_manager/timer/timer.db.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package timer
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
type Timer struct {
|
||||
Id uint32 `db:"id"`
|
||||
En1Month4Day5Week3Hour5Min6 int32 `db:"emdwhm"`
|
||||
Selfid int64 `db:"sid"`
|
||||
GrpId int64 `db:"gid"`
|
||||
Alert string `db:"alert"`
|
||||
Cron string `db:"cron"`
|
||||
Url string `db:"url"`
|
||||
}
|
||||
|
||||
func (t *Timer) InsertInto(db *sql.Sqlite) error {
|
||||
return db.Insert("timer", t)
|
||||
}
|
||||
|
||||
func getTimerFrom(db *sql.Sqlite, id uint32) (t Timer, err error) {
|
||||
err = db.Find("timer", &t, "where id = "+strconv.Itoa(int(id)))
|
||||
return
|
||||
}
|
||||
@@ -2,34 +2,28 @@
|
||||
package timer
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/RomiChan/protobuf/proto"
|
||||
"github.com/fumiama/cron"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/file"
|
||||
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
|
||||
)
|
||||
|
||||
type Clock struct {
|
||||
// 记录每个定时器以便取消
|
||||
timersmap TimersMap
|
||||
// 定时器map
|
||||
timers *(map[string]*Timer)
|
||||
db *sql.Sqlite
|
||||
timers *(map[uint32]*Timer)
|
||||
timersmu sync.RWMutex
|
||||
// 定时器存储位置
|
||||
pbfile *string
|
||||
// cron 定时器
|
||||
cron *cron.Cron
|
||||
// entries key <-> cron
|
||||
entries map[string]cron.EntryID
|
||||
entries map[uint32]cron.EntryID
|
||||
entmu sync.Mutex
|
||||
}
|
||||
|
||||
@@ -43,26 +37,27 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func NewClock(pbfile string) (c Clock) {
|
||||
c.loadTimers(pbfile)
|
||||
c.timers = &c.timersmap.Timers
|
||||
c.pbfile = &pbfile
|
||||
func NewClock(db *sql.Sqlite) (c Clock) {
|
||||
c.loadTimers(db)
|
||||
c.cron = cron.New()
|
||||
c.entries = make(map[string]cron.EntryID)
|
||||
c.entries = make(map[uint32]cron.EntryID)
|
||||
c.cron.Start()
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterTimer 注册计时器
|
||||
func (c *Clock) RegisterTimer(ts *Timer, grp int64, save bool) bool {
|
||||
key := ts.GetTimerInfo(grp)
|
||||
func (c *Clock) RegisterTimer(ts *Timer, save bool) bool {
|
||||
var key uint32
|
||||
if save {
|
||||
key = ts.GetTimerID()
|
||||
ts.Id = key
|
||||
} else {
|
||||
key = ts.Id
|
||||
}
|
||||
t, ok := c.GetTimer(key)
|
||||
if t != ts && ok { // 避免重复注册定时器
|
||||
t.SetEn(false)
|
||||
}
|
||||
c.timersmu.Lock()
|
||||
(*c.timers)[key] = ts
|
||||
c.timersmu.Unlock()
|
||||
logrus.Println("[群管]注册计时器", key)
|
||||
if ts.Cron != "" {
|
||||
var ctx *zero.Ctx
|
||||
@@ -75,33 +70,33 @@ func (c *Clock) RegisterTimer(ts *Timer, grp int64, save bool) bool {
|
||||
return false
|
||||
})
|
||||
}
|
||||
eid, err := c.cron.AddFunc(ts.Cron, func() { ts.sendmsg(grp, ctx) })
|
||||
eid, err := c.cron.AddFunc(ts.Cron, func() { ts.sendmsg(ts.GrpId, ctx) })
|
||||
if err == nil {
|
||||
c.entmu.Lock()
|
||||
c.entries[key] = eid
|
||||
c.entmu.Unlock()
|
||||
if save {
|
||||
c.SaveTimers()
|
||||
err = c.AddTimer(ts)
|
||||
}
|
||||
return true
|
||||
return err == nil
|
||||
}
|
||||
ts.Alert = err.Error()
|
||||
} else {
|
||||
if save {
|
||||
c.SaveTimers()
|
||||
_ = c.AddTimer(ts)
|
||||
}
|
||||
for ts.En() {
|
||||
nextdate := ts.nextWakeTime()
|
||||
sleepsec := time.Until(nextdate)
|
||||
logrus.Printf("[群管]计时器%s将睡眠%ds", key, sleepsec/time.Second)
|
||||
logrus.Printf("[群管]计时器%08x将睡眠%ds", key, sleepsec/time.Second)
|
||||
time.Sleep(sleepsec)
|
||||
if ts.En() {
|
||||
if ts.Month() < 0 || ts.Month() == time.Now().Month() {
|
||||
if ts.Day() < 0 || ts.Day() == time.Now().Day() {
|
||||
ts.judgeHM(grp)
|
||||
ts.judgeHM()
|
||||
} else if ts.Day() == 0 {
|
||||
if ts.Week() < 0 || ts.Week() == time.Now().Weekday() {
|
||||
ts.judgeHM(grp)
|
||||
ts.judgeHM()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,8 +107,8 @@ func (c *Clock) RegisterTimer(ts *Timer, grp int64, save bool) bool {
|
||||
}
|
||||
|
||||
// CancelTimer 取消计时器
|
||||
func (c *Clock) CancelTimer(key string) bool {
|
||||
t, ok := (*c.timers)[key]
|
||||
func (c *Clock) CancelTimer(key uint32) bool {
|
||||
t, ok := c.GetTimer(key)
|
||||
if ok {
|
||||
if t.Cron != "" {
|
||||
c.entmu.Lock()
|
||||
@@ -126,41 +121,22 @@ func (c *Clock) CancelTimer(key string) bool {
|
||||
}
|
||||
c.timersmu.Lock()
|
||||
delete(*c.timers, key) // 避免重复取消
|
||||
e := c.db.Del("timer", "where id = "+strconv.Itoa(int(key)))
|
||||
c.timersmu.Unlock()
|
||||
_ = c.SaveTimers()
|
||||
return e == nil
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// SaveTimers 保存当前计时器
|
||||
func (c *Clock) SaveTimers() error {
|
||||
c.timersmu.RLock()
|
||||
data, err := proto.Marshal(&c.timersmap)
|
||||
c.timersmu.RUnlock()
|
||||
if err == nil {
|
||||
c.timersmu.Lock()
|
||||
defer c.timersmu.Unlock()
|
||||
f, err1 := os.OpenFile(*c.pbfile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err1 != nil {
|
||||
return err1
|
||||
} else {
|
||||
_, err2 := f.Write(data)
|
||||
f.Close()
|
||||
return err2
|
||||
}
|
||||
}
|
||||
return err
|
||||
return false
|
||||
}
|
||||
|
||||
// ListTimers 列出本群所有计时器
|
||||
func (c *Clock) ListTimers(grpID int64) []string {
|
||||
// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
|
||||
if c.timers != nil {
|
||||
g := strconv.FormatInt(grpID, 10)
|
||||
c.timersmu.RLock()
|
||||
keys := make([]string, 0, len(*c.timers))
|
||||
for k := range *c.timers {
|
||||
if strings.Contains(k, g) {
|
||||
for _, v := range *c.timers {
|
||||
if v.GrpId == grpID {
|
||||
k := v.GetTimerInfo()
|
||||
start := strings.Index(k, "]")
|
||||
msg := strings.ReplaceAll(k[start+1:]+"\n", "-1", "每")
|
||||
msg = strings.ReplaceAll(msg, "月0日0周", "月周天")
|
||||
@@ -176,35 +152,32 @@ func (c *Clock) ListTimers(grpID int64) []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Clock) GetTimer(key string) (t *Timer, ok bool) {
|
||||
func (c *Clock) GetTimer(key uint32) (t *Timer, ok bool) {
|
||||
c.timersmu.RLock()
|
||||
t, ok = (*c.timers)[key]
|
||||
c.timersmu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Clock) loadTimers(pbfile string) {
|
||||
if file.IsExist(pbfile) {
|
||||
f, err := os.Open(pbfile)
|
||||
func (c *Clock) AddTimer(t *Timer) (err error) {
|
||||
c.timersmu.Lock()
|
||||
(*c.timers)[t.Id] = t
|
||||
err = c.db.Insert("timer", t)
|
||||
c.timersmu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Clock) loadTimers(db *sql.Sqlite) {
|
||||
if file.IsExist(db.DBPath) {
|
||||
c.db = db
|
||||
err := c.db.Create("timer", &Timer{})
|
||||
if err == nil {
|
||||
data, err := io.ReadAll(f)
|
||||
if err == nil {
|
||||
if len(data) > 0 {
|
||||
err = proto.Unmarshal(data, &c.timersmap)
|
||||
if err == nil {
|
||||
for str, t := range c.timersmap.Timers {
|
||||
grp, err := strconv.ParseInt(str[1:strings.Index(str, "]")], 10, 64)
|
||||
if err == nil {
|
||||
go c.RegisterTimer(t, grp, false)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
logrus.Errorln("[群管]读取定时器文件失败,将在下一次保存时覆盖原文件。err:", err)
|
||||
logrus.Errorln("[群管]如不希望被覆盖,请运行源码plugin_manager/timers/migrate下的程序将timers.pb刷新为新版")
|
||||
}
|
||||
}
|
||||
var t Timer
|
||||
c.db.FindFor("timer", &t, "", func() error {
|
||||
tescape := t
|
||||
go c.RegisterTimer(&tescape, false)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
c.timersmap.Timers = make(map[string]*Timer)
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package timer
|
||||
|
||||
type Timer struct {
|
||||
Alert string `protobuf:"bytes,1,opt"`
|
||||
Cron string `protobuf:"bytes,2,opt"`
|
||||
En1Month4Day5Week3Hour5Min6 int32 `protobuf:"varint,4,opt"`
|
||||
Selfid int64 `protobuf:"varint,8,opt"`
|
||||
Url string `protobuf:"bytes,16,opt"`
|
||||
}
|
||||
|
||||
type TimersMap struct {
|
||||
Timers map[string]*Timer `protobuf:"bytes,1,rep" protobuf_key:"bytes,1,opt" protobuf_val:"bytes,2,opt"`
|
||||
}
|
||||
@@ -2,10 +2,12 @@ package timer
|
||||
|
||||
import "time"
|
||||
|
||||
// En isEnabled 1bit
|
||||
func (m *Timer) En() (en bool) {
|
||||
return m.En1Month4Day5Week3Hour5Min6&0x800000 != 0
|
||||
}
|
||||
|
||||
// Month 4bits
|
||||
func (m *Timer) Month() (mon time.Month) {
|
||||
mon = time.Month((m.En1Month4Day5Week3Hour5Min6 & 0x780000) >> 19)
|
||||
if mon == 0b1111 {
|
||||
@@ -14,6 +16,7 @@ func (m *Timer) Month() (mon time.Month) {
|
||||
return
|
||||
}
|
||||
|
||||
// Day 5bits
|
||||
func (m *Timer) Day() (d int) {
|
||||
d = int((m.En1Month4Day5Week3Hour5Min6 & 0x07c000) >> 14)
|
||||
if d == 0b11111 {
|
||||
@@ -22,6 +25,7 @@ func (m *Timer) Day() (d int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Week 3bits
|
||||
func (m *Timer) Week() (w time.Weekday) {
|
||||
w = time.Weekday((m.En1Month4Day5Week3Hour5Min6 & 0x003800) >> 11)
|
||||
if w == 0b111 {
|
||||
@@ -30,6 +34,7 @@ func (m *Timer) Week() (w time.Weekday) {
|
||||
return
|
||||
}
|
||||
|
||||
// Hour 5bits
|
||||
func (m *Timer) Hour() (h int) {
|
||||
h = int((m.En1Month4Day5Week3Hour5Min6 & 0x0007c0) >> 6)
|
||||
if h == 0b11111 {
|
||||
@@ -38,6 +43,7 @@ func (m *Timer) Hour() (h int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Minute 6bits
|
||||
func (m *Timer) Minute() (min int) {
|
||||
min = int(m.En1Month4Day5Week3Hour5Min6 & 0x00003f)
|
||||
if min == 0b111111 {
|
||||
@@ -46,6 +52,7 @@ func (m *Timer) Minute() (min int) {
|
||||
return
|
||||
}
|
||||
|
||||
// SetEn ...
|
||||
func (m *Timer) SetEn(en bool) {
|
||||
if en {
|
||||
m.En1Month4Day5Week3Hour5Min6 |= 0x800000
|
||||
@@ -54,22 +61,27 @@ func (m *Timer) SetEn(en bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetMonth ...
|
||||
func (m *Timer) SetMonth(mon time.Month) {
|
||||
m.En1Month4Day5Week3Hour5Min6 = ((int32(mon) << 19) & 0x780000) | (m.En1Month4Day5Week3Hour5Min6 & 0x87ffff)
|
||||
}
|
||||
|
||||
// SetDay ...
|
||||
func (m *Timer) SetDay(d int) {
|
||||
m.En1Month4Day5Week3Hour5Min6 = ((int32(d) << 14) & 0x07c000) | (m.En1Month4Day5Week3Hour5Min6 & 0xf83fff)
|
||||
}
|
||||
|
||||
// SetWeek ...
|
||||
func (m *Timer) SetWeek(w time.Weekday) {
|
||||
m.En1Month4Day5Week3Hour5Min6 = ((int32(w) << 11) & 0x003800) | (m.En1Month4Day5Week3Hour5Min6 & 0xffc7ff)
|
||||
}
|
||||
|
||||
// SetHour ...
|
||||
func (m *Timer) SetHour(h int) {
|
||||
m.En1Month4Day5Week3Hour5Min6 = ((int32(h) << 6) & 0x0007c0) | (m.En1Month4Day5Week3Hour5Min6 & 0xfff83f)
|
||||
}
|
||||
|
||||
// SetMinute ...
|
||||
func (m *Timer) SetMinute(min int) {
|
||||
m.En1Month4Day5Week3Hour5Min6 = (int32(min) & 0x00003f) | (m.En1Month4Day5Week3Hour5Min6 & 0xffffc0)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
const base = "data/nwife"
|
||||
|
||||
var baseuri = "file:///" + file.BOT_PATH + "/" + base
|
||||
var baseuri = "file:///" + file.BOTPATH + "/" + base
|
||||
|
||||
func init() {
|
||||
err := os.MkdirAll(base, 0755)
|
||||
|
||||
186
plugin_novel/qianbi.go
Normal file
186
plugin_novel/qianbi.go
Normal file
@@ -0,0 +1,186 @@
|
||||
// Package novel 铅笔小说搜索插件
|
||||
package novel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/antchfx/htmlquery"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/control"
|
||||
ub "github.com/FloatTech/ZeroBot-Plugin/utils/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
websiteURL = "https://www.23qb.net"
|
||||
websiteTitle = "铅笔小说"
|
||||
errorTitle = "出现错误!"
|
||||
username = "zerobot"
|
||||
password = "123456"
|
||||
submit = "%26%23160%3B%B5%C7%26%23160%3B%26%23160%3B%C2%BC%26%23160%3B"
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||
loginURL = websiteURL + "/login.php?do=submit&jumpurl=https%3A%2F%2Fwww.23qb.net%2F"
|
||||
searchURL = websiteURL + "/saerch.php"
|
||||
idReg = `/(\d+)/`
|
||||
)
|
||||
|
||||
var (
|
||||
gCurCookieJar *cookiejar.Jar
|
||||
engine = control.Register("novel", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "铅笔小说网搜索\n- 小说[xxx]",
|
||||
})
|
||||
limit = rate.NewManager(time.Minute, 5)
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine.OnRegex("^小说([\u4E00-\u9FA5A-Za-z0-9]{1,25})$").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.GroupID).Acquire() {
|
||||
ctx.SendChain(message.Text("请稍后重试0x0..."))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中......"))
|
||||
login(username, password)
|
||||
searchKey := ctx.State["regex_matched"].([]string)[1]
|
||||
searchHtml := search(searchKey)
|
||||
var m message.Message
|
||||
doc, err := htmlquery.Parse(strings.NewReader(searchHtml))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
htmlTitle := htmlquery.InnerText(htmlquery.FindOne(doc, "/html/head/title"))
|
||||
if htmlTitle == websiteTitle {
|
||||
list, err := htmlquery.QueryAll(doc, "//dl[@id='nr']")
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
for _, v := range list {
|
||||
bookName := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[1]/h3/a[1]"))
|
||||
category := htmlquery.InnerText(htmlquery.FindOne(v, "/dt/span[1]"))
|
||||
author := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[2]/span[1]"))
|
||||
status := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[2]/span[2]"))
|
||||
wordNumbers := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[2]/span[3]"))
|
||||
description := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[3]"))
|
||||
updateTime := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[1]/h3/span[1]"))
|
||||
latestChapter := htmlquery.InnerText(htmlquery.FindOne(v, "/dd[4]/a[1]"))
|
||||
|
||||
reg := regexp.MustCompile(idReg)
|
||||
id := reg.FindStringSubmatch(htmlquery.SelectAttr(htmlquery.FindOne(v, "/dt/a[1]"), "href"))[1]
|
||||
|
||||
webpageURL := websiteURL + "/book/" + id + "/"
|
||||
downloadURL := websiteURL + "/modules/article/txtarticle.php?id=" + id
|
||||
text := fmt.Sprintf("书名:%s\n类型:%s\n作者:%s\n状态:%s\n字数:%s\n简介:%s\n更新时间:%s\n最新章节:%s\n网页链接:%s\n下载地址:%s\n", bookName, category, author, status, wordNumbers, description, updateTime, latestChapter, webpageURL, downloadURL)
|
||||
m = append(m,
|
||||
message.CustomNode(
|
||||
zero.BotConfig.NickName[0],
|
||||
ctx.Event.SelfID,
|
||||
text),
|
||||
)
|
||||
}
|
||||
if id := ctx.SendGroupForwardMessage(
|
||||
ctx.Event.GroupID,
|
||||
m).Get("message_id").Int(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
} else {
|
||||
text := htmlquery.InnerText(htmlquery.FindOne(doc, "//div[@id='tipss']"))
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
text = strings.Replace(text, "本站", websiteURL, -1)
|
||||
ctx.SendChain(message.Text(text))
|
||||
}
|
||||
} else if htmlTitle == errorTitle {
|
||||
ctx.SendChain(message.Text(errorTitle))
|
||||
text := htmlquery.InnerText(htmlquery.FindOne(doc, "//div[@style='text-align: center;padding:10px']"))
|
||||
text = strings.Replace(text, " ", "", -1)
|
||||
ctx.SendChain(message.Text(text))
|
||||
} else {
|
||||
bookName := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:book_name']"), "content")
|
||||
category := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:category']"), "content")
|
||||
author := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:author']"), "content")
|
||||
status := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:status']"), "content")
|
||||
description := htmlquery.InnerText(htmlquery.FindOne(doc, "//div[@id='bookintro']/p"))
|
||||
updateTime := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:update_time']"), "content")
|
||||
latestChapter := htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:latest_chapter_name']"), "content")
|
||||
|
||||
reg := regexp.MustCompile(idReg)
|
||||
id := reg.FindStringSubmatch(htmlquery.SelectAttr(htmlquery.FindOne(doc, "//meta[@property='og:novel:read_url']"), "content"))[1]
|
||||
webpageURL := websiteURL + "/book/" + id + "/"
|
||||
downloadURL := websiteURL + "/modules/article/txtarticle.php?id=" + id
|
||||
text := fmt.Sprintf("书名:%s\n类型:%s\n作者:%s\n状态:%s\n简介:%s\n更新时间:%s\n最新章节:%s\n网页链接:%s\n下载地址:%s\n", bookName, category, author, status, description, updateTime, latestChapter, webpageURL, downloadURL)
|
||||
ctx.SendChain(message.Text(text))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func login(username, password string) {
|
||||
gCurCookieJar, _ = cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
usernameData, err := ub.UTF82GBK(helper.StringToBytes(username))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
usernameGbk := helper.BytesToString(usernameData)
|
||||
passwordData, err := ub.UTF82GBK(helper.StringToBytes(password))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
passwordGbk := helper.BytesToString(passwordData)
|
||||
loginReq, err := http.NewRequest("POST", loginURL, strings.NewReader(fmt.Sprintf("username=%s&password=%s&usecookie=315360000&action=login&submit=%s", url.QueryEscape(usernameGbk), url.QueryEscape(passwordGbk), submit)))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
loginReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
loginReq.Header.Set("User-Agent", ua)
|
||||
loginResp, err := client.Do(loginReq)
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
defer loginResp.Body.Close()
|
||||
}
|
||||
|
||||
func search(searchKey string) (searchHtml string) {
|
||||
searchKeyData, err := ub.UTF82GBK(helper.StringToBytes(searchKey))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
searchKeyGbk := helper.BytesToString(searchKeyData)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
searchReq, err := http.NewRequest("POST", searchURL, strings.NewReader(fmt.Sprintf("searchkey=%s&searchtype=all", url.QueryEscape(searchKeyGbk))))
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
searchReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
searchReq.Header.Set("User-Agent", ua)
|
||||
searchResp, err := client.Do(searchReq)
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
defer searchResp.Body.Close()
|
||||
searchData, err := ioutil.ReadAll(searchResp.Body)
|
||||
if err != nil {
|
||||
log.Errorf("[novel] get response for url=%s got error=%s\n", searchURL, err.Error())
|
||||
}
|
||||
searchData, err = ub.GBK2UTF8(searchData)
|
||||
if err != nil {
|
||||
log.Errorln("[novel]", err)
|
||||
}
|
||||
searchHtml = helper.BytesToString(searchData)
|
||||
return searchHtml
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
bed = "https://codechina.csdn.net/u011570312/senso-ji-omikuji/-/raw/main/%d_%d.jpg"
|
||||
bed = "https://gitcode.net/u011570312/senso-ji-omikuji/-/raw/main/%d_%d.jpg"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -97,15 +97,17 @@ type dataQYK struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
const (
|
||||
qykURL = "http://api.qingyunke.com/api.php"
|
||||
key = "free"
|
||||
appid = "0"
|
||||
)
|
||||
|
||||
// 青云客取消息
|
||||
func getMessage(msg string) (string, error) {
|
||||
qykUrl := "http://api.qingyunke.com/api.php"
|
||||
key := "free"
|
||||
appid := "0"
|
||||
qykUrl = fmt.Sprintf(qykUrl+"?key=%s&appid=%s&msg=%s", key, appid, url.QueryEscape(msg))
|
||||
|
||||
u := fmt.Sprintf(qykURL+"?key=%s&appid=%s&msg=%s", key, appid, url.QueryEscape(msg))
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", qykUrl, nil)
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
datapath = file.BOT_PATH + "/data/saucenao/"
|
||||
datapath = file.BOTPATH + "/data/saucenao/"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
|
||||
@@ -67,17 +67,17 @@ var (
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("setutime", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "涩图\n" +
|
||||
"- 来份[涩图/二次元/风景/车万]\n" +
|
||||
"- 添加[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- 删除[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- >setu status",
|
||||
})
|
||||
go func() {
|
||||
process.SleepAbout1sTo2s()
|
||||
pool = newPools()
|
||||
engine := control.Register("setutime", &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "涩图\n" +
|
||||
"- 来份[涩图/二次元/风景/车万]\n" +
|
||||
"- 添加[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- 删除[涩图/二次元/风景/车万][P站图片ID]\n" +
|
||||
"- >setu status",
|
||||
})
|
||||
engine.OnRegex(`^来份(.*)$`, rule.FirstValueInList(pool.List)).SetBlock(true).SetPriority(20).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if !limit.Load(ctx.Event.UserID).Acquire() {
|
||||
@@ -217,7 +217,7 @@ func (p *imgpool) pop(imgtype string) (illust *pixiv.Illust) {
|
||||
|
||||
func file(i *pixiv.Illust) string {
|
||||
filename := fmt.Sprint(i.Pid)
|
||||
filepath := fileutil.BOT_PATH + `/` + pool.Path + filename
|
||||
filepath := fileutil.BOTPATH + `/` + pool.Path + filename
|
||||
if _, err := os.Stat(filepath + ".jpg"); err == nil || os.IsExist(err) {
|
||||
return `file:///` + filepath + ".jpg"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package plugin_sleep_manage
|
||||
package sleepmanage
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -12,11 +12,10 @@ import (
|
||||
func init() {
|
||||
go func() {
|
||||
defer func() {
|
||||
//recover() //可以打印panic的错误信息
|
||||
if err := recover(); err != nil { //产生了panic异常
|
||||
if err := recover(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}() //别忘了(), 调用此匿名函数
|
||||
}()
|
||||
process.SleepAbout1sTo2s()
|
||||
_ = os.MkdirAll(dbpath, 0755)
|
||||
model.Initialize(dbfile)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package model 睡眠管理数据库
|
||||
package model
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package plugin_sleep_manage
|
||||
// Package sleepmanage 睡眠管理
|
||||
package sleepmanage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
@@ -42,7 +42,9 @@ func init() {
|
||||
defer db.Close()
|
||||
defer cancel()
|
||||
firstStepMessage := db.GetAllFirstCategoryMessage()
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(firstStepMessage))
|
||||
if id := ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(firstStepMessage)); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
// 步骤0,1,2,依次选择3个类别
|
||||
step := 0
|
||||
// 错误次数
|
||||
|
||||
2
run.bat
2
run.bat
@@ -3,5 +3,5 @@ go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go env -w GO111MODULE=auto
|
||||
go mod tidy
|
||||
::go build -ldflags="-s -w" -o ZeroBot-Plugin.exe
|
||||
go run main.go
|
||||
go run main.go main_win.go
|
||||
pause
|
||||
|
||||
29
utils/binary/encode.go
Normal file
29
utils/binary/encode.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// GBK2UTF8 GBK 转 UTF-8
|
||||
func GBK2UTF8(s []byte) ([]byte, error) {
|
||||
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
|
||||
d, e := ioutil.ReadAll(reader)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// UTF82GBK UTF-8 转 GBK
|
||||
func UTF82GBK(s []byte) ([]byte, error) {
|
||||
reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewEncoder())
|
||||
d, e := ioutil.ReadAll(reader)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package file
|
||||
|
||||
import "os"
|
||||
|
||||
// Pwd 获取当前路径
|
||||
func Pwd() (path string) {
|
||||
path, _ = os.Getwd()
|
||||
return
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Pwd 获取当前路径的正斜杠表示
|
||||
func Pwd() string {
|
||||
path, _ := os.Getwd()
|
||||
return strings.ReplaceAll(path, "\\", "/")
|
||||
|
||||
@@ -2,7 +2,8 @@ package file
|
||||
|
||||
import "os"
|
||||
|
||||
var BOT_PATH = Pwd()
|
||||
// BOTPATH BOT当前路径
|
||||
var BOTPATH = Pwd()
|
||||
|
||||
// IsExist 文件/路径存在
|
||||
func IsExist(path string) bool {
|
||||
@@ -10,7 +11,7 @@ func IsExist(path string) bool {
|
||||
return err == nil || os.IsExist(err)
|
||||
}
|
||||
|
||||
// IsExist 文件/路径不存在
|
||||
// IsNotExist 文件/路径不存在
|
||||
func IsNotExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err != nil && os.IsNotExist(err)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
dataurl = "https://codechina.csdn.net/u011570312/ZeroBot-Plugin/-/raw/master/"
|
||||
dataurl = "https://gitcode.net/u011570312/ZeroBot-Plugin/-/raw/master/"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -38,7 +38,7 @@ func GetLazyData(path string, isReturnDataBytes, isDataMustEqual bool) ([]byte,
|
||||
} else {
|
||||
ms, err = registry.Get(path)
|
||||
if err != nil || len(ms) != 16 {
|
||||
logrus.Errorln("[file]获取md5失败,请自行确保下载文件 %s 的正确性:", path, err)
|
||||
logrus.Errorln("[file]获取md5失败,请自行确保下载文件", path, "的正确性:", err)
|
||||
} else {
|
||||
filemd5 = (*[16]byte)(*(*unsafe.Pointer)(unsafe.Pointer(&ms)))
|
||||
logrus.Infoln("[file]从验证服务器获得文件md5:", hex.EncodeToString(filemd5[:]))
|
||||
@@ -82,7 +82,7 @@ func GetLazyData(path string, isReturnDataBytes, isDataMustEqual bool) ([]byte,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(data) <= 0 {
|
||||
if len(data) == 0 {
|
||||
return nil, errors.New("read body len <= 0")
|
||||
}
|
||||
if filemd5 != nil {
|
||||
|
||||
8
utils/math/conv.go
Normal file
8
utils/math/conv.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package math
|
||||
|
||||
import "strconv"
|
||||
|
||||
func Str2Int64(str string) int64 {
|
||||
val, _ := strconv.ParseInt(str, 10, 64)
|
||||
return val
|
||||
}
|
||||
@@ -16,3 +16,11 @@ func Min(a, b int) int {
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Abs 返回绝对值,该函数将被内联
|
||||
func Abs(x int) int {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package process 流程控制相关
|
||||
package process
|
||||
|
||||
import (
|
||||
@@ -5,6 +6,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SleepAbout1sTo2s 随机阻塞等待 1 ~ 2s
|
||||
func SleepAbout1sTo2s() {
|
||||
time.Sleep(time.Second + time.Millisecond*time.Duration(rand.Intn(1000)))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package rule zb 规则扩展
|
||||
package rule
|
||||
|
||||
import zero "github.com/wdvxdr1123/ZeroBot"
|
||||
|
||||
@@ -75,6 +75,7 @@ func (db *Sqlite) Create(table string, objptr interface{}) (err error) {
|
||||
}
|
||||
|
||||
// Insert 插入数据集
|
||||
// 如果 PK 存在会覆盖
|
||||
// 默认结构体的第一个元素为主键
|
||||
// 返回错误
|
||||
func (db *Sqlite) Insert(table string, objptr interface{}) error {
|
||||
@@ -133,7 +134,67 @@ func (db *Sqlite) Insert(table string, objptr interface{}) error {
|
||||
return stmt.Close()
|
||||
}
|
||||
|
||||
// Find 查询数据库
|
||||
// InsertUnique 插入数据集
|
||||
// 如果 PK 存在会报错
|
||||
// 默认结构体的第一个元素为主键
|
||||
// 返回错误
|
||||
func (db *Sqlite) InsertUnique(table string, objptr interface{}) error {
|
||||
rows, err := db.DB.Query("SELECT * FROM " + table + " limit 1;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return rows.Err()
|
||||
}
|
||||
tags, _ := rows.Columns()
|
||||
rows.Close()
|
||||
var (
|
||||
vals = values(objptr)
|
||||
top = len(tags) - 1
|
||||
cmd = []string{}
|
||||
)
|
||||
cmd = append(cmd, "INSERT INTO")
|
||||
cmd = append(cmd, table)
|
||||
for i := range tags {
|
||||
switch i {
|
||||
default:
|
||||
cmd = append(cmd, tags[i])
|
||||
cmd = append(cmd, ",")
|
||||
case 0:
|
||||
cmd = append(cmd, "(")
|
||||
cmd = append(cmd, tags[i])
|
||||
cmd = append(cmd, ",")
|
||||
case top:
|
||||
cmd = append(cmd, tags[i])
|
||||
cmd = append(cmd, ")")
|
||||
}
|
||||
}
|
||||
for i := range tags {
|
||||
switch i {
|
||||
default:
|
||||
cmd = append(cmd, "?")
|
||||
cmd = append(cmd, ",")
|
||||
case 0:
|
||||
cmd = append(cmd, "VALUES (")
|
||||
cmd = append(cmd, "?")
|
||||
cmd = append(cmd, ",")
|
||||
case top:
|
||||
cmd = append(cmd, "?")
|
||||
cmd = append(cmd, ")")
|
||||
}
|
||||
}
|
||||
stmt, err := db.DB.Prepare(strings.Join(cmd, " ") + ";")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(vals...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return stmt.Close()
|
||||
}
|
||||
|
||||
// Find 查询数据库,写入最后一条结果到 objptr
|
||||
// condition 可为"WHERE id = 0"
|
||||
// 默认字段与结构体元素顺序一致
|
||||
// 返回错误
|
||||
@@ -164,6 +225,68 @@ func (db *Sqlite) Find(table string, objptr interface{}, condition string) error
|
||||
return err
|
||||
}
|
||||
|
||||
// CanFind 查询数据库是否有 condition
|
||||
// condition 可为"WHERE id = 0"
|
||||
// 默认字段与结构体元素顺序一致
|
||||
// 返回错误
|
||||
func (db *Sqlite) CanFind(table string, condition string) bool {
|
||||
var cmd = []string{}
|
||||
cmd = append(cmd, "SELECT * FROM")
|
||||
cmd = append(cmd, table)
|
||||
cmd = append(cmd, condition)
|
||||
rows, err := db.DB.Query(strings.Join(cmd, " ") + ";")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return false
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return false
|
||||
}
|
||||
_ = rows.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
// FindFor 查询数据库,用函数 f 遍历结果
|
||||
// condition 可为"WHERE id = 0"
|
||||
// 默认字段与结构体元素顺序一致
|
||||
// 返回错误
|
||||
func (db *Sqlite) FindFor(table string, objptr interface{}, condition string, f func() error) error {
|
||||
var cmd = []string{}
|
||||
cmd = append(cmd, "SELECT * FROM")
|
||||
cmd = append(cmd, table)
|
||||
cmd = append(cmd, condition)
|
||||
rows, err := db.DB.Query(strings.Join(cmd, " ") + ";")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return rows.Err()
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return errors.New("sql.FindFor: null result")
|
||||
}
|
||||
err = rows.Scan(addrs(objptr)...)
|
||||
if err == nil {
|
||||
err = f()
|
||||
}
|
||||
for rows.Next() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rows.Scan(addrs(objptr)...)
|
||||
if err == nil {
|
||||
err = f()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Pick 从 table 随机一行
|
||||
func (db *Sqlite) Pick(table string, objptr interface{}) error {
|
||||
return db.Find(table, objptr, "ORDER BY RANDOM() limit 1")
|
||||
@@ -243,10 +366,10 @@ func (db *Sqlite) Count(table string) (num int, err error) {
|
||||
return num, rows.Err()
|
||||
}
|
||||
if rows.Next() {
|
||||
rows.Scan(&num)
|
||||
err = rows.Scan(&num)
|
||||
}
|
||||
rows.Close()
|
||||
return num, nil
|
||||
return num, err
|
||||
}
|
||||
|
||||
// tags 反射 返回结构体对象的 tag 数组
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// Package web 网络处理相关
|
||||
package web
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ReqWith 使用自定义请求头获取数据
|
||||
func ReqWith(url string, method string, referer string, ua string) (data []byte, err error) {
|
||||
client := &http.Client{}
|
||||
// 提交请求
|
||||
@@ -23,3 +26,19 @@ func ReqWith(url string, method string, referer string, ua string) (data []byte,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetData 获取数据
|
||||
func GetData(url string) (data []byte, err error) {
|
||||
var response *http.Response
|
||||
response, err = http.Get(url)
|
||||
if err == nil {
|
||||
if response.ContentLength <= 0 {
|
||||
err = errors.New("web.GetData: empty body")
|
||||
response.Body.Close()
|
||||
return
|
||||
}
|
||||
data, err = io.ReadAll(response.Body)
|
||||
response.Body.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user