mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-06 15:20:22 +00:00
Compare commits
15 Commits
v1.3.1-bet
...
v1.3.1-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea56c7d0d2 | ||
|
|
0cbe43df97 | ||
|
|
1f941d883a | ||
|
|
f5b3e423fb | ||
|
|
6c7f81ca55 | ||
|
|
3911b5ed82 | ||
|
|
f38f3ab69c | ||
|
|
846db6f063 | ||
|
|
ff068a05b0 | ||
|
|
051b7dd182 | ||
|
|
11870aeed6 | ||
|
|
9bcff82d9c | ||
|
|
309efe8cd8 | ||
|
|
bf54789f0f | ||
|
|
01e527abdb |
@@ -66,6 +66,11 @@ zerobot [-h] [-t token] [-u url] [-n nickname] [-p prefix] [-d|w] [-g 监听地
|
||||
- [x] /服务列表
|
||||
- [x] /服务详情
|
||||
- [x] @Bot 插件冲突检测 (会在本群发送一条消息并在约 1s 后撤回以检测其它同类 bot 中已启用的插件并禁用)
|
||||
- **定时指令触发器** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/job"`
|
||||
- [x] 记录在"cron"触发的指令
|
||||
- [x] 取消在"cron"触发的指令
|
||||
- [x] 查看所有触发指令
|
||||
- [x] 查看在"cron"触发的指令
|
||||
- **聊天** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/chat"`
|
||||
- [x] [BOT名字]
|
||||
- [x] [戳一戳BOT]
|
||||
|
||||
2
data
2
data
Submodule data updated: 9dccdda436...e084d72e9d
8
go.mod
8
go.mod
@@ -3,15 +3,15 @@ module github.com/FloatTech/ZeroBot-Plugin
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220304041505-1de3dbdc8423
|
||||
github.com/FloatTech/sqlite v0.2.0
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220304041409-6607dccd2a10
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220307053346-aa76aec4b635
|
||||
github.com/FloatTech/sqlite v0.2.1
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220307063102-42185420359d
|
||||
github.com/antchfx/htmlquery v1.2.4
|
||||
github.com/corona10/goimagehash v1.0.3
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
github.com/fumiama/go-base16384 v1.3.0
|
||||
github.com/fumiama/go-registry v0.1.0
|
||||
github.com/fumiama/go-registry v0.1.1
|
||||
github.com/fumiama/gofastTEA v0.0.9
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/sqlite3 v1.14.6
|
||||
|
||||
16
go.sum
16
go.sum
@@ -1,10 +1,11 @@
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220304041505-1de3dbdc8423 h1:onMyoXqhCkloE/EnaOuqfkjqsJW1/gyse7bpnnG2ujs=
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220304041505-1de3dbdc8423/go.mod h1:hA4AT+9WqEvg+T+wwFtz8LF+gM86eA9eA7L+Zhscp4Q=
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220307053346-aa76aec4b635 h1:T7J1wLvSqn8PvkM7X98dgbafW+zG1l0LdX664HbrG0U=
|
||||
github.com/FloatTech/AnimeAPI v1.3.1-0.20220307053346-aa76aec4b635/go.mod h1:ZNhcnGEchvEjd09WbpLMlmxlmYy4trtLYEAJHRAoKaw=
|
||||
github.com/FloatTech/bot-manager v1.0.0/go.mod h1:8YYRJ16oroGHQGD2En0oVnmcKJkxR9O/jd5BPSfWfOQ=
|
||||
github.com/FloatTech/sqlite v0.2.0 h1:x3uls/hExXH1+bbaNLkvilce6ATtWlDx4IqoxBW/bv8=
|
||||
github.com/FloatTech/sqlite v0.2.0/go.mod h1:xIDWIvpOFl8AXmZm0FC8t3PZjiR6ZutytCpBv2EWCns=
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220304041409-6607dccd2a10 h1:akteVs9gqHzPZuX1gvRiT/1HoSGD9DcO/kWrcWG/7p0=
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220304041409-6607dccd2a10/go.mod h1:ts1Srsgp6iZlvo3K/7Q2NtwQyD1/AzG4EaPxRitR0S4=
|
||||
github.com/FloatTech/sqlite v0.2.1 h1:9t6Me48XJJCIoPy4nLRvcdhcVKfT0c2lilp7SEKROG8=
|
||||
github.com/FloatTech/sqlite v0.2.1/go.mod h1:6NfHRzqOo9RWeMJEoAQVuo51Omd5LFNxCNQhMF02/9U=
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220307053255-29a0c0203693/go.mod h1:1nzt5KFkggpZaqkW0faY3y0X/qeMKTodqWc8wbVYhoY=
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220307063102-42185420359d h1:G5rXr46dJnpVbU2jN5XevX3lhh2TQ+DkSk1n1TLS82o=
|
||||
github.com/FloatTech/zbputils v1.3.1-0.20220307063102-42185420359d/go.mod h1:nW53pKNJVrbYzSGr89CBuM1vZv/hnQnV8dJSp+NCeAA=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc h1:AAx50/fb/xS4lvsdQg+bFbGvqSDhyV1MF+p2PLCamZ0=
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc/go.mod h1:OMmITAib6POA37xCichWM0aRnoVpSMZO1rB/G01wrr0=
|
||||
@@ -35,8 +36,9 @@ github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
||||
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
||||
github.com/fumiama/go-base16384 v1.3.0 h1:J5Xtwh/3alGJt/z/0IFralo5UQA89iFWQqbxj5ZQZi8=
|
||||
github.com/fumiama/go-base16384 v1.3.0/go.mod h1:RGA715p34BiLoZvPRtaxuo2q25Kq9jFsgUsJb8dwy14=
|
||||
github.com/fumiama/go-registry v0.1.0 h1:CIzQN9wOZKIokALyYkNIpPQ7bpzmirDua77S2BicdVE=
|
||||
github.com/fumiama/go-registry v0.1.0/go.mod h1:iJT3DVgH7KXpJZs6waXEjnWtJPUBBGhF+ByJIMRfngk=
|
||||
github.com/fumiama/go-registry v0.1.1 h1:cmCRizjXHFW2ApwUHCXi8wKLJ6Gtt4GrShJlamGPbVI=
|
||||
github.com/fumiama/go-registry v0.1.1/go.mod h1:iJT3DVgH7KXpJZs6waXEjnWtJPUBBGhF+ByJIMRfngk=
|
||||
github.com/fumiama/gofastTEA v0.0.9 h1:adaWz+014vMShnLUNWIHLBs0Yv6JNUohcaXZNtct5J0=
|
||||
github.com/fumiama/gofastTEA v0.0.9/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||
|
||||
42
kanban/banner.go
Normal file
42
kanban/banner.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package kanban
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fumiama/go-registry"
|
||||
)
|
||||
|
||||
var (
|
||||
info = [...]string{
|
||||
"* OneBot + ZeroBot + Golang",
|
||||
"* Version 1.3.1 - 2022-03-07 13:40:58 +0800 CST",
|
||||
"* Copyright © 2020 - 2022 FloatTech. All Rights Reserved.",
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
}
|
||||
Banner = strings.Join(info[:], "\n")
|
||||
reg = registry.NewRegReader("reilia.westeurope.cloudapp.azure.com:32664", "fumiama")
|
||||
)
|
||||
|
||||
func PrintBanner() {
|
||||
fmt.Print(
|
||||
"\n======================[ZeroBot-Plugin]======================",
|
||||
"\n", Banner, "\n",
|
||||
"----------------------[ZeroBot-公告栏]----------------------",
|
||||
"\n", Kanban(), "\n",
|
||||
"============================================================\n\n",
|
||||
)
|
||||
}
|
||||
|
||||
func Kanban() string {
|
||||
err := reg.Connect()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
defer reg.Close()
|
||||
text, err := reg.Get("ZeroBot-Plugin/kanban")
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return text
|
||||
}
|
||||
5
kanban/init.go
Normal file
5
kanban/init.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package kanban
|
||||
|
||||
func init() {
|
||||
PrintBanner()
|
||||
}
|
||||
50
main.go
50
main.go
@@ -5,9 +5,10 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 在最前打印 banner
|
||||
|
||||
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
|
||||
// ----------------------插件优先级按顺序从高到低---------------------- //
|
||||
// //
|
||||
@@ -76,6 +77,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/job" // 定时指令触发器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
|
||||
@@ -139,8 +141,7 @@ import (
|
||||
// //
|
||||
// //
|
||||
// -----------------------以下为内置依赖,勿动------------------------ //
|
||||
"github.com/FloatTech/zbputils/control/order"
|
||||
"github.com/fumiama/go-registry"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/driver"
|
||||
@@ -149,19 +150,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
contents = []string{
|
||||
"* OneBot + ZeroBot + Golang",
|
||||
"* Version 1.3.0 - 2022-02-09 14:31:34 +0800 CST",
|
||||
"* Copyright © 2020 - 2021 FloatTech. All Rights Reserved.",
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin",
|
||||
}
|
||||
nicks = []string{"ATRI", "atri", "亚托莉", "アトリ"}
|
||||
banner = strings.Join(contents, "\n")
|
||||
token *string
|
||||
url *string
|
||||
adana *string
|
||||
prefix *string
|
||||
reg = registry.NewRegReader("reilia.westeurope.cloudapp.azure.com:32664", "fumiama")
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -182,7 +175,7 @@ func init() {
|
||||
|
||||
flag.Parse()
|
||||
if *h {
|
||||
printBanner()
|
||||
kanban.PrintBanner()
|
||||
fmt.Println("Usage:")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
@@ -199,43 +192,18 @@ func init() {
|
||||
// webctrl.InitGui(*g)
|
||||
}
|
||||
|
||||
func printBanner() {
|
||||
fmt.Print(
|
||||
"\n======================[ZeroBot-Plugin]======================",
|
||||
"\n", banner, "\n",
|
||||
"----------------------[ZeroBot-公告栏]----------------------",
|
||||
"\n", getKanban(), "\n",
|
||||
"============================================================\n",
|
||||
)
|
||||
}
|
||||
|
||||
func getKanban() string {
|
||||
err := reg.Connect()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
defer reg.Close()
|
||||
text, err := reg.Get("ZeroBot-Plugin/kanban")
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func main() {
|
||||
order.Wait()
|
||||
printBanner()
|
||||
rand.Seed(time.Now().UnixNano()) // 全局 seed,其他插件无需再 seed
|
||||
// 帮助
|
||||
zero.OnFullMatchGroup([]string{"/help", ".help", "菜单"}, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(banner, "\n可发送\"/服务列表\"查看 bot 功能"))
|
||||
ctx.SendChain(message.Text(kanban.Banner, "\n可发送\"/服务列表\"查看 bot 功能"))
|
||||
})
|
||||
zero.OnFullMatch("查看zbp公告", zero.OnlyToMe, zero.AdminPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text(getKanban()))
|
||||
ctx.SendChain(message.Text(kanban.Kanban()))
|
||||
})
|
||||
zero.RunAndBlock(
|
||||
zero.Run(
|
||||
zero.Config{
|
||||
NickName: append([]string{*adana}, nicks...),
|
||||
CommandPrefix: *prefix,
|
||||
@@ -245,4 +213,6 @@ func main() {
|
||||
Driver: []zero.Driver{driver.NewWebSocketClient(*url, *token)},
|
||||
},
|
||||
)
|
||||
process.GlobalInitMutex.Unlock()
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -155,12 +155,12 @@ func reply(ctx *zero.Ctx, class int, dhash string, comment string) error {
|
||||
}
|
||||
} else {
|
||||
send = func(msg interface{}) int64 {
|
||||
return int64(ctx.SendGroupForwardMessage(ctx.Event.GroupID, message.Message{
|
||||
return ctx.SendGroupForwardMessage(ctx.Event.GroupID, message.Message{
|
||||
ctxext.FakeSenderForwardNode(ctx, append(
|
||||
msg.(message.Message),
|
||||
message.Text(comment))...,
|
||||
),
|
||||
}).Get("message_id").Int())
|
||||
}).Get("message_id").Int()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := en.DataFolder()
|
||||
dbfile := dbpath + "push.db"
|
||||
defer order.DoneOnExit()()
|
||||
bdb = initialize(dbfile)
|
||||
log.Println("[bilibilipush]加载bilibilipush数据库")
|
||||
}()
|
||||
|
||||
@@ -23,7 +23,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := engine.DataFolder()
|
||||
db.DBPath = dbpath + "bookreview.db"
|
||||
defer order.DoneOnExit()()
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = file.GetLazyData(db.DBPath, false, true)
|
||||
err := db.Create("bookreview", &book{})
|
||||
|
||||
@@ -21,7 +21,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := en.DataFolder()
|
||||
db.DBPath = dbpath + "cxh.db"
|
||||
defer order.DoneOnExit()()
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = file.GetLazyData(db.DBPath, false, true)
|
||||
err := db.Create("pinyin", &pinyin{})
|
||||
|
||||
@@ -26,7 +26,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := engine.DataFolder()
|
||||
db.DBPath = dbpath + "cp.db"
|
||||
defer order.DoneOnExit()()
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = file.GetLazyData(db.DBPath, false, true)
|
||||
err := db.Create("cp_story", &cpstory{})
|
||||
|
||||
@@ -29,7 +29,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := engine.DataFolder()
|
||||
db.DBPath = dbpath + "curse.db"
|
||||
defer order.DoneOnExit()()
|
||||
_, err := file.GetLazyData(db.DBPath, false, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -26,7 +26,6 @@ func init() {
|
||||
go func() {
|
||||
datapath := engine.DataFolder()
|
||||
dbfile := datapath + "text.db"
|
||||
defer order.DoneOnExit()()
|
||||
data.LoadText(dbfile)
|
||||
}()
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ func init() {
|
||||
PublicDataFolder: "Fortune",
|
||||
})
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
for i, s := range table {
|
||||
index[s] = uint8(i)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := en.DataFolder()
|
||||
db.DBPath = dbpath + "jokes.db"
|
||||
defer order.DoneOnExit()()
|
||||
_, err := file.GetLazyData(db.DBPath, false, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -32,7 +32,6 @@ func init() {
|
||||
go func() {
|
||||
dbpath := engine.DataFolder()
|
||||
db.DBPath = dbpath + "pics.db"
|
||||
defer order.DoneOnExit()()
|
||||
_, _ = file.GetLazyData(db.DBPath, false, false)
|
||||
err := db.Create("picture", &picture{})
|
||||
if err != nil {
|
||||
|
||||
191
plugin/job/main.go
Normal file
191
plugin/job/main.go
Normal file
@@ -0,0 +1,191 @@
|
||||
// Package job 定时指令触发器
|
||||
package job
|
||||
|
||||
import (
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/control/order"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/process"
|
||||
"github.com/FloatTech/zbputils/vevent"
|
||||
"github.com/fumiama/cron"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/rate"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
lo map[int64]vevent.Loop
|
||||
entries map[int64]cron.EntryID // id entryid
|
||||
mu sync.Mutex
|
||||
limit = rate.NewLimiter(time.Second*2, 1)
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("job", order.AcquirePrio(), &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "定时指令触发器\n- 记录在\"cron\"触发的指令\n- 取消在\"cron\"触发的指令\n- 查看所有触发指令\n- 查看在\"cron\"触发的指令",
|
||||
PrivateDataFolder: "job",
|
||||
})
|
||||
db.DBPath = en.DataFolder() + "job.db"
|
||||
err := db.Open()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
process.GlobalInitMutex.Lock()
|
||||
process.SleepAbout1sTo2s()
|
||||
lo = make(map[int64]vevent.Loop, len(zero.BotConfig.Driver))
|
||||
entries = map[int64]cron.EntryID{}
|
||||
for _, drv := range zero.BotConfig.Driver {
|
||||
id := drv.SelfID()
|
||||
ids := strconv.FormatInt(id, 36)
|
||||
c := &cmd{}
|
||||
lo[id] = vevent.NewLoop(id)
|
||||
err := db.Create(ids, c)
|
||||
logrus.Infoln("[job]创建表", ids)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
db.FindFor(ids, c, "", func() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
eid, err := process.CronTab.AddFunc(c.Cron, inject(id, []byte(c.Cmd)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entries[c.ID] = eid
|
||||
return nil
|
||||
})
|
||||
}
|
||||
logrus.Infoln("[job]本地环回初始化完成")
|
||||
process.GlobalInitMutex.Unlock()
|
||||
}()
|
||||
en.OnRegex(`^记录在"(.*)"触发的指令$`, ctxext.UserOrGrpAdmin, islonotnil, func(ctx *zero.Ctx) bool {
|
||||
ctx.SendChain(message.Text("您的下一条指令将被记录,在", ctx.State["regex_matched"].([]string)[1], "时触发"))
|
||||
select {
|
||||
case <-time.After(time.Second * 120):
|
||||
ctx.SendChain(message.Text("指令记录超时"))
|
||||
return false
|
||||
case e := <-zero.NewFutureEvent("message", 0, false, zero.CheckUser(ctx.Event.UserID)).Next():
|
||||
ctx.State["job_raw_event"] = e.RawEvent.Raw
|
||||
return true
|
||||
}
|
||||
}).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
cron := ctx.State["regex_matched"].([]string)[1]
|
||||
command := ctx.State["job_raw_event"].(string)
|
||||
c := &cmd{
|
||||
ID: idof(cron, command),
|
||||
Cron: cron,
|
||||
Cmd: command,
|
||||
}
|
||||
err := addcmd(ctx.Event.SelfID, c)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
en.OnRegex(`^取消在"(.*)"触发的指令$`, ctxext.UserOrGrpAdmin, islonotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
cron := ctx.State["regex_matched"].([]string)[1]
|
||||
err := rmcmd(ctx.Event.SelfID, cron)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
en.OnFullMatch("查看所有触发指令", zero.SuperUserPermission, islonotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
c := &cmd{}
|
||||
ids := strconv.FormatInt(ctx.Event.SelfID, 36)
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
n, err := db.Count(ids)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
lst := make([]string, 0, n)
|
||||
err = db.FindFor(ids, c, "GROUP BY cron", func() error {
|
||||
lst = append(lst, c.Cron+"\n")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(lst))
|
||||
})
|
||||
en.OnRegex(`^查看在"(.*)"触发的指令$`, zero.SuperUserPermission, islonotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
c := &cmd{}
|
||||
ids := strconv.FormatInt(ctx.Event.SelfID, 36)
|
||||
cron := ctx.State["regex_matched"].([]string)[1]
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
n, err := db.Count(ids)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
lst := make([]string, 0, n)
|
||||
err = db.FindFor(ids, c, "WHERE cron='"+cron+"'", func() error {
|
||||
lst = append(lst, c.Cmd+"\n")
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(lst))
|
||||
})
|
||||
}
|
||||
|
||||
func islonotnil(ctx *zero.Ctx) bool {
|
||||
return len(lo) > 0
|
||||
}
|
||||
|
||||
func inject(bot int64, response []byte) func() {
|
||||
return func() {
|
||||
if limit.Acquire() {
|
||||
lo[bot].Echo(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func idof(cron, cmd string) int64 {
|
||||
return int64(crc64.Checksum(binary.StringToBytes(cron+cmd), crc64.MakeTable(crc64.ISO)))
|
||||
}
|
||||
|
||||
func addcmd(bot int64, c *cmd) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
eid, err := process.CronTab.AddFunc(c.Cron, inject(bot, []byte(c.Cmd)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entries[c.ID] = eid
|
||||
return db.Insert(strconv.FormatInt(bot, 36), c)
|
||||
}
|
||||
|
||||
func rmcmd(bot int64, cron string) error {
|
||||
c := &cmd{}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
bots := strconv.FormatInt(bot, 36)
|
||||
err := db.FindFor(bots, c, "WHERE cron='"+cron+"'", func() error {
|
||||
eid, ok := entries[c.ID]
|
||||
if ok {
|
||||
process.CronTab.Remove(eid)
|
||||
delete(entries, c.ID)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
db.Del(bots, "WHERE cron='"+cron+"'")
|
||||
return err
|
||||
}
|
||||
11
plugin/job/model.go
Normal file
11
plugin/job/model.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package job
|
||||
|
||||
import sql "github.com/FloatTech/sqlite"
|
||||
|
||||
type cmd struct {
|
||||
ID int64 `db:"id"`
|
||||
Cron string `db:"cron"`
|
||||
Cmd string `db:"cmd"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
@@ -66,7 +66,6 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
db.DBPath = engine.DataFolder() + "config.db"
|
||||
clock = timer.NewClock(db)
|
||||
err := db.Create("welcome", &welcome{})
|
||||
|
||||
@@ -33,7 +33,6 @@ func init() { // 插件主体
|
||||
go func() {
|
||||
dbpath := engine.DataFolder()
|
||||
db.DBPath = dbpath + "kuji.db"
|
||||
defer order.DoneOnExit()()
|
||||
_, _ = file.GetLazyData(db.DBPath, false, true)
|
||||
err := db.Create("kuji", &kuji{})
|
||||
if err != nil {
|
||||
|
||||
@@ -23,7 +23,6 @@ func init() {
|
||||
go func() {
|
||||
datapath := en.DataFolder()
|
||||
jsonfile := datapath + "rate.json"
|
||||
defer order.DoneOnExit()()
|
||||
area := make(rate, 226)
|
||||
err := load(&area, jsonfile)
|
||||
if err != nil {
|
||||
|
||||
@@ -43,7 +43,6 @@ func init() {
|
||||
})
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
os.RemoveAll(cachePath)
|
||||
err := os.MkdirAll(cachePath, 0755)
|
||||
if err != nil {
|
||||
|
||||
@@ -62,7 +62,6 @@ func init() { // 插件主体
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
// 如果数据库不存在则下载
|
||||
pool.db.DBPath = engine.DataFolder() + "SetuTime.db"
|
||||
_, _ = fileutil.GetLazyData(pool.db.DBPath, false, false)
|
||||
|
||||
@@ -23,7 +23,6 @@ func init() {
|
||||
PublicDataFolder: "Chat",
|
||||
})
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
data, err := file.GetLazyData(engine.DataFolder()+"kimoi.json", true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -44,7 +44,6 @@ func init() {
|
||||
dbfile := engine.DataFolder() + "vtb.db"
|
||||
storePath := engine.DataFolder() + "store/"
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
err := os.MkdirAll(storePath, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
package wordle
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
goBinary "encoding/binary"
|
||||
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
)
|
||||
|
||||
type wordpack [3]byte
|
||||
|
||||
/*
|
||||
func pack(word string) (w wordpack) {
|
||||
if len(word) != 5 {
|
||||
panic("word must be 5 letters")
|
||||
}
|
||||
r := []rune(word)
|
||||
for i := range r {
|
||||
if r[i] < 'k' { // 0-9
|
||||
r[i] -= 'a' - '0'
|
||||
} else {
|
||||
r[i] -= 10
|
||||
}
|
||||
}
|
||||
word = string(r)
|
||||
n, err := strconv.ParseUint(word, 26, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wt := binary.SelectWriter()
|
||||
wt.WriteUInt32LE(uint32(n))
|
||||
copy(w[:], wt.Bytes())
|
||||
binary.PutWriter(wt)
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
func (w wordpack) String() (word string) {
|
||||
wt := binary.SelectWriter()
|
||||
_, _ = wt.Write(w[:])
|
||||
_ = wt.WriteByte(0)
|
||||
n := goBinary.LittleEndian.Uint32(wt.Bytes())
|
||||
binary.PutWriter(wt)
|
||||
word = strconv.FormatUint(uint64(n), 26)
|
||||
for len(word) < 5 {
|
||||
word = "0" + word
|
||||
}
|
||||
r := []rune(word)
|
||||
for i := range r {
|
||||
if r[i] < 'a' { // 0-9
|
||||
r[i] += 'a' - '0'
|
||||
} else {
|
||||
r[i] += 10
|
||||
}
|
||||
}
|
||||
word = string(r)
|
||||
return
|
||||
}
|
||||
|
||||
func loadwords(data []byte) (wordpacks []wordpack) {
|
||||
(*slice)(unsafe.Pointer(&wordpacks)).data = (*slice)(unsafe.Pointer(&data)).data
|
||||
(*slice)(unsafe.Pointer(&wordpacks)).len = len(data) / 3
|
||||
(*slice)(unsafe.Pointer(&wordpacks)).cap = (*slice)(unsafe.Pointer(&data)).cap / 3
|
||||
return
|
||||
}
|
||||
|
||||
// slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type slice struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package wordle
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"sort"
|
||||
@@ -40,8 +41,19 @@ var colors = [...]color.RGBA{
|
||||
{219, 219, 219, 255},
|
||||
}
|
||||
|
||||
var words []string
|
||||
var questions []string
|
||||
var classdict = map[string]int{
|
||||
"": 5,
|
||||
"五阶": 5,
|
||||
"六阶": 6,
|
||||
"七阶": 7,
|
||||
}
|
||||
|
||||
type dictionary map[int]struct {
|
||||
dict []string
|
||||
cet4 []string
|
||||
}
|
||||
|
||||
var words = make(dictionary)
|
||||
|
||||
func init() {
|
||||
en := control.Register("wordle", order.AcquirePrio(), &control.Options{
|
||||
@@ -61,47 +73,50 @@ func init() {
|
||||
}),
|
||||
))
|
||||
go func() {
|
||||
questionsdata, err := file.GetLazyData(en.DataFolder()+"questions.bin", true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
for i := 5; i <= 7; i++ {
|
||||
dc, err := file.GetLazyData(fmt.Sprintf("%scet-4_%d.txt", en.DataFolder(), i), true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c := strings.Split(string(dc), "\n")
|
||||
sort.Strings(c)
|
||||
dd, err := file.GetLazyData(fmt.Sprintf("%sdict_%d.txt", en.DataFolder(), i), true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
d := strings.Split(string(dd), "\n")
|
||||
sort.Strings(d)
|
||||
words[i] = struct {
|
||||
dict []string
|
||||
cet4 []string
|
||||
}{d, c}
|
||||
}
|
||||
questionspacks := loadwords(questionsdata)
|
||||
questions = make([]string, len(questionspacks))
|
||||
for i := range questionspacks {
|
||||
questions[i] = questionspacks[i].String()
|
||||
}
|
||||
wordsdata, err := file.GetLazyData(en.DataFolder()+"words.bin", true, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
wordpacks := loadwords(wordsdata)
|
||||
words = make([]string, len(wordpacks))
|
||||
for i := range wordpacks {
|
||||
words[i] = wordpacks[i].String()
|
||||
}
|
||||
sort.Strings(words)
|
||||
}()
|
||||
en.OnRegex(`(个人|团队)猜单词`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
en.OnRegex(`(个人|团队)(五阶|六阶|七阶)?猜单词`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
target := questions[rand.Intn(len(questions))]
|
||||
class := classdict[ctx.State["regex_matched"].([]string)[2]]
|
||||
target := words[class].cet4[rand.Intn(len(words[class].cet4))]
|
||||
game := newWordleGame(target)
|
||||
_, img, cl, _ := game("")
|
||||
typ := ctx.State["regex_matched"].([]string)[1]
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.ImageBytes(img),
|
||||
message.Text("你有6次机会猜出单词,单词长度为5,请发送单词"),
|
||||
message.Text("你有", class+1, "次机会猜出单词,单词长度为", class, ",请发送单词"),
|
||||
),
|
||||
)
|
||||
cl()
|
||||
var next *zero.FutureEvent
|
||||
if typ == "个人" {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`), zero.OnlyGroup, zero.CheckUser(ctx.Event.UserID))
|
||||
if ctx.State["regex_matched"].([]string)[1] == "个人" {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([A-Z]|[a-z]){%d}$`, class)),
|
||||
zero.OnlyGroup, zero.CheckUser(ctx.Event.UserID))
|
||||
} else {
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`), zero.OnlyGroup, zero.CheckGroup(ctx.Event.GroupID))
|
||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([A-Z]|[a-z]){%d}$`, class)),
|
||||
zero.OnlyGroup, zero.CheckGroup(ctx.Event.GroupID))
|
||||
}
|
||||
var win bool
|
||||
var err error
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 120):
|
||||
@@ -111,7 +126,7 @@ func init() {
|
||||
),
|
||||
)
|
||||
return
|
||||
case e := <-next.Next():
|
||||
case e := <-recv:
|
||||
win, img, cl, err = game(e.Message.String())
|
||||
switch {
|
||||
case win:
|
||||
@@ -158,6 +173,7 @@ func init() {
|
||||
}
|
||||
|
||||
func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
var class = len(target)
|
||||
record := make([]string, 0, len(target)+1)
|
||||
return func(s string) (win bool, data []byte, cl func(), err error) {
|
||||
if s != "" {
|
||||
@@ -169,8 +185,8 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
err = errLengthNotEnough
|
||||
return
|
||||
}
|
||||
i := sort.SearchStrings(words, s)
|
||||
if i >= len(words) || words[i] != s {
|
||||
i := sort.SearchStrings(words[class].dict, s)
|
||||
if i >= len(words[class].dict) || words[class].dict[i] != s {
|
||||
err = errUnknownWord
|
||||
return
|
||||
}
|
||||
@@ -181,13 +197,14 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||
}
|
||||
}
|
||||
var side = 20
|
||||
ctx := gg.NewContext((side+2)*5+26, (side+2)*6+26)
|
||||
var space = 10
|
||||
ctx := gg.NewContext((side+4)*class+space*2-4, (side+4)*(class+1)+space*2-4)
|
||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||
ctx.Clear()
|
||||
for i := 0; i < len(target)+1; i++ {
|
||||
for j := 0; j < len(target); j++ {
|
||||
for i := 0; i < class+1; i++ {
|
||||
for j := 0; j < class; j++ {
|
||||
if len(record) > i {
|
||||
ctx.DrawRectangle(float64(10+j*(side+4)), float64(10+i*(side+4)), float64(side), float64(side))
|
||||
ctx.DrawRectangle(float64(space+j*(side+4)), float64(space+i*(side+4)), float64(side), float64(side))
|
||||
switch {
|
||||
case record[i][j] == target[j]:
|
||||
ctx.SetColor(colors[match])
|
||||
|
||||
@@ -20,7 +20,6 @@ func init() {
|
||||
})
|
||||
dbfile := engine.DataFolder() + "ymgal.db"
|
||||
go func() {
|
||||
defer order.DoneOnExit()()
|
||||
_, _ = file.GetLazyData(dbfile, false, false)
|
||||
gdb = initialize(dbfile)
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user