From ef95ecb415b9cff6a75d879abd2b9003fc5765d0 Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 9 May 2021 00:32:43 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=BE=A4=E7=AE=A1=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E6=8F=90=E9=86=92=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + manager/manager.go | 49 +++++++++++++++++++++ manager/timer.go | 105 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 manager/timer.go diff --git a/README.md b/README.md index 668786ba..38319a48 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ - [x] 退出群聊[群号] - [x] *入群欢迎 - [x] *退群通知 + - [x] 在[月份]月[日期]日的[小时]点[分钟]分时(用[url])提醒大家[消息] + - [x] 在[月份]月[每周or周几]的[小时]点[分钟]分时(用[url])提醒大家[消息] - [ ] 同意入群请求 - [ ] 同意好友请求 - [ ] 撤回[@xxx] [xxx] diff --git a/manager/manager.go b/manager/manager.go index 49256f7e..da1f3f9a 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -230,6 +230,55 @@ func init() { // 插件主体 ctx.SendChain(message.Text("📧 --> " + ctx.State["regex_matched"].([]string)[1])) return }) + // 定时提醒 + zero.OnRegex(`^在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分时(用.+)?提醒大家(.*)`, zero.AdminPermission).SetBlock(true).SetPriority(40). + Handle(func(ctx *zero.Ctx) { + dateStrs := ctx.State["regex_matched"].([]string) + monthStr := []rune(dateStrs[1]) + dayWeekStr := []rune(dateStrs[2]) + hourStr := []rune(dateStrs[3]) + minuteStr := []rune(dateStrs[4]) + urlStr := dateStrs[5] + var ts TimeStamp + ts.month = chineseNum2Int(monthStr) + lenOfDW := len(dayWeekStr) + if lenOfDW == 4 { //包括末尾的"日" + dayWeekStr = []rune{dayWeekStr[0], dayWeekStr[2]} //去除中间的十 + ts.day = chineseNum2Int(dayWeekStr) + } else if dayWeekStr[lenOfDW-1] == rune('日') { //xx日 + dayWeekStr = dayWeekStr[:lenOfDW-1] + ts.day = chineseNum2Int(dayWeekStr) + } else if dayWeekStr[0] == rune('每') { //每周 + ts.week = -1 + } else { //周x + ts.week = chineseNum2Int(dayWeekStr[1:]) + } + if len(hourStr) == 3 { + hourStr = []rune{hourStr[0], hourStr[2]} //去除中间的十 + } + ts.hour = chineseNum2Int(hourStr) + if len(minuteStr) == 3 { + minuteStr = []rune{minuteStr[0], minuteStr[2]} //去除中间的十 + } + ts.minute = chineseNum2Int(minuteStr) + if urlStr != "" { //是图片url + ts.url = urlStr[3:] //utf-8下用为3字节 + if !strings.HasPrefix(ts.url, "http") { + ctx.Send("图片url非法") + return + } + } + ts.alert = dateStrs[6] + ts.enable = true + go timer(ts, func() { + if ts.url == "" { + ctx.SendChain(AtAll(), message.Text(ts.alert)) + } else { + ctx.SendChain(AtAll(), message.Text(ts.alert), ImageNoCache(ts.url)) + } + }) + return + }) // 入群欢迎 zero.OnNotice().SetBlock(false).SetPriority(40). Handle(func(ctx *zero.Ctx) { diff --git a/manager/timer.go b/manager/timer.go new file mode 100644 index 00000000..cf623443 --- /dev/null +++ b/manager/timer.go @@ -0,0 +1,105 @@ +package manager + +import ( + "fmt" + "strconv" + "time" + "unicode" + + "github.com/wdvxdr1123/ZeroBot/message" +) + +type TimeStamp struct { + enable bool + alert string + url string + month int8 + day int8 + week int8 + hour int8 + minute int8 +} + +func timer(ts TimeStamp, onTimeReached func()) { + fmt.Printf("注册计时器: %d月%d日%d周%d:%d触发\n", ts.month, ts.day, ts.week, ts.hour, ts.minute) + judgeHM := func() { + if ts.hour < 0 || ts.hour == int8(time.Now().Hour()) { + if ts.minute < 0 || ts.minute == int8(time.Now().Minute()) { + onTimeReached() + } + } + } + for ts.enable { + if ts.month < 0 || ts.month == int8(time.Now().Month()) { + if ts.day < 0 || ts.day == int8(time.Now().Day()) { + judgeHM() + } else if ts.day == 0 { + if ts.week < 0 || ts.week == int8(time.Now().Weekday()) { + judgeHM() + } + } + } + time.Sleep(time.Minute) + } +} + +//汉字数字转int,仅支持-10~99,最多两位数,其中"每"解释为-1,"每两"为-2,以此类推 +func chineseNum2Int(rs []rune) int8 { + r := -1 + l := len(rs) + mai := rune('每') + if unicode.IsDigit(rs[0]) { //默认可能存在的第二位也为int + r, _ = strconv.Atoi(string(rs)) + } else { + if rs[0] == mai { + if l == 2 { + r = -chineseChar2Int(rs[1]) + } + } else if l == 1 { + r = chineseChar2Int(rs[0]) + } else { + ten := chineseChar2Int(rs[0]) + if ten != 10 { + ten *= 10 + } + ge := chineseChar2Int(rs[1]) + if ge == 10 { + ge = 0 + } + r = ten + ge + } + } + return int8(r) +} + +//处理单个字符的映射0~10 +func chineseChar2Int(c rune) int { + match := []rune("零一二三四五六七八九十") + for i, m := range match { + if c == m { + return i + } + } + return 0 +} + +//@全体成员 +func AtAll() message.MessageSegment { + return message.MessageSegment{ + Type: "at", + Data: map[string]string{ + "qq": "all", + }, + } +} + +//无缓存发送图片 +func ImageNoCache(url string) message.MessageSegment { + return message.MessageSegment{ + Type: "image", + Data: map[string]string{ + "file": url, + "cache": "0", + }, + } +} From 3e9605d484ca7b194990d43209599504509c34cd Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 9 May 2021 11:03:21 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E7=BE=A4=E7=AE=A1=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 2 ++ manager/manager.go | 54 ++++++++++++++----------------------------- manager/timer.go | 57 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 0eea0915..0dedc1a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ data/chat/* data/SetuTime/cache/* main.exe +.DS_Store diff --git a/README.md b/README.md index 38319a48..4e36dd9d 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ - [x] *退群通知 - [x] 在[月份]月[日期]日的[小时]点[分钟]分时(用[url])提醒大家[消息] - [x] 在[月份]月[每周or周几]的[小时]点[分钟]分时(用[url])提醒大家[消息] + - [x] 取消在[月份]月[日期]日的[小时]点[分钟]分的提醒 + - [x] 取消在[月份]月[每周or周几]的[小时]点[分钟]分的提醒 - [ ] 同意入群请求 - [ ] 同意好友请求 - [ ] 撤回[@xxx] [xxx] diff --git a/manager/manager.go b/manager/manager.go index da1f3f9a..3a624a68 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -231,45 +231,10 @@ func init() { // 插件主体 return }) // 定时提醒 - zero.OnRegex(`^在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分时(用.+)?提醒大家(.*)`, zero.AdminPermission).SetBlock(true).SetPriority(40). + zero.OnRegex(`^在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分时(用.+)?提醒大家(.*)`, zero.SuperUserPermission).SetBlock(true).SetPriority(40). Handle(func(ctx *zero.Ctx) { dateStrs := ctx.State["regex_matched"].([]string) - monthStr := []rune(dateStrs[1]) - dayWeekStr := []rune(dateStrs[2]) - hourStr := []rune(dateStrs[3]) - minuteStr := []rune(dateStrs[4]) - urlStr := dateStrs[5] - var ts TimeStamp - ts.month = chineseNum2Int(monthStr) - lenOfDW := len(dayWeekStr) - if lenOfDW == 4 { //包括末尾的"日" - dayWeekStr = []rune{dayWeekStr[0], dayWeekStr[2]} //去除中间的十 - ts.day = chineseNum2Int(dayWeekStr) - } else if dayWeekStr[lenOfDW-1] == rune('日') { //xx日 - dayWeekStr = dayWeekStr[:lenOfDW-1] - ts.day = chineseNum2Int(dayWeekStr) - } else if dayWeekStr[0] == rune('每') { //每周 - ts.week = -1 - } else { //周x - ts.week = chineseNum2Int(dayWeekStr[1:]) - } - if len(hourStr) == 3 { - hourStr = []rune{hourStr[0], hourStr[2]} //去除中间的十 - } - ts.hour = chineseNum2Int(hourStr) - if len(minuteStr) == 3 { - minuteStr = []rune{minuteStr[0], minuteStr[2]} //去除中间的十 - } - ts.minute = chineseNum2Int(minuteStr) - if urlStr != "" { //是图片url - ts.url = urlStr[3:] //utf-8下用为3字节 - if !strings.HasPrefix(ts.url, "http") { - ctx.Send("图片url非法") - return - } - } - ts.alert = dateStrs[6] - ts.enable = true + ts := getFilledTimeStamp(dateStrs, false) go timer(ts, func() { if ts.url == "" { ctx.SendChain(AtAll(), message.Text(ts.alert)) @@ -277,6 +242,21 @@ func init() { // 插件主体 ctx.SendChain(AtAll(), message.Text(ts.alert), ImageNoCache(ts.url)) } }) + ctx.Send("记住了~") + return + }) + // 取消定时 + zero.OnRegex(`^取消在(.{1,2})月(.{1,3}日|每?周.?)的(.{1,3})点(.{1,3})分的提醒`, zero.SuperUserPermission).SetBlock(true).SetPriority(40). + Handle(func(ctx *zero.Ctx) { + dateStrs := ctx.State["regex_matched"].([]string) + ts := getFilledTimeStamp(dateStrs, true) + t, ok := timers[getTimerInfo(&ts)] + if ok { + t.enable = false + ctx.Send("取消成功~") + } else { + ctx.Send("没有这个定时器哦~") + } return }) // 入群欢迎 diff --git a/manager/timer.go b/manager/timer.go index cf623443..ecf0ea97 100644 --- a/manager/timer.go +++ b/manager/timer.go @@ -3,6 +3,7 @@ package manager import ( "fmt" "strconv" + "strings" "time" "unicode" @@ -20,8 +21,13 @@ type TimeStamp struct { minute int8 } +//记录每个定时器以便取消 +var timers = make(map[string]*TimeStamp) + func timer(ts TimeStamp, onTimeReached func()) { - fmt.Printf("注册计时器: %d月%d日%d周%d:%d触发\n", ts.month, ts.day, ts.week, ts.hour, ts.minute) + key := getTimerInfo(&ts) + fmt.Printf("注册计时器: %s\n", key) + timers[key] = &ts judgeHM := func() { if ts.hour < 0 || ts.hour == int8(time.Now().Hour()) { if ts.minute < 0 || ts.minute == int8(time.Now().Minute()) { @@ -43,6 +49,55 @@ func timer(ts TimeStamp, onTimeReached func()) { } } +//获得标准化定时字符串 +func getTimerInfo(ts *TimeStamp) string { + return fmt.Sprintf("%d月%d日%d周%d:%d", ts.month, ts.day, ts.week, ts.hour, ts.minute) +} + +//获得填充好的ts +func getFilledTimeStamp(dateStrs []string, matchDateOnly bool) TimeStamp { + monthStr := []rune(dateStrs[1]) + dayWeekStr := []rune(dateStrs[2]) + hourStr := []rune(dateStrs[3]) + minuteStr := []rune(dateStrs[4]) + + var ts TimeStamp + ts.month = chineseNum2Int(monthStr) + lenOfDW := len(dayWeekStr) + if lenOfDW == 4 { //包括末尾的"日" + dayWeekStr = []rune{dayWeekStr[0], dayWeekStr[2]} //去除中间的十 + ts.day = chineseNum2Int(dayWeekStr) + } else if dayWeekStr[lenOfDW-1] == rune('日') { //xx日 + dayWeekStr = dayWeekStr[:lenOfDW-1] + ts.day = chineseNum2Int(dayWeekStr) + } else if dayWeekStr[0] == rune('每') { //每周 + ts.week = -1 + } else { //周x + ts.week = chineseNum2Int(dayWeekStr[1:]) + } + if len(hourStr) == 3 { + hourStr = []rune{hourStr[0], hourStr[2]} //去除中间的十 + } + ts.hour = chineseNum2Int(hourStr) + if len(minuteStr) == 3 { + minuteStr = []rune{minuteStr[0], minuteStr[2]} //去除中间的十 + } + ts.minute = chineseNum2Int(minuteStr) + if !matchDateOnly { + urlStr := dateStrs[5] + if urlStr != "" { //是图片url + ts.url = urlStr[3:] //utf-8下用为3字节 + if !strings.HasPrefix(ts.url, "http") { + ts.url = "illeagal" + return ts + } + } + ts.alert = dateStrs[6] + ts.enable = true + } + return ts +} + //汉字数字转int,仅支持-10~99,最多两位数,其中"每"解释为-1,"每两"为-2,以此类推 func chineseNum2Int(rs []rune) int8 { r := -1 From 3058badffab6d66a6262505c12442fa735ce72d3 Mon Sep 17 00:00:00 2001 From: fumiama Date: Sun, 9 May 2021 11:07:27 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=8F=96=E6=B6=88=E6=8F=90=E9=86=92?= =?UTF-8?q?=E6=97=B6=E9=81=BF=E5=85=8D=E9=87=8D=E5=A4=8D=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/manager.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manager/manager.go b/manager/manager.go index 3a624a68..025cef23 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -250,9 +250,11 @@ func init() { // 插件主体 Handle(func(ctx *zero.Ctx) { dateStrs := ctx.State["regex_matched"].([]string) ts := getFilledTimeStamp(dateStrs, true) - t, ok := timers[getTimerInfo(&ts)] + ti := getTimerInfo(&ts) + t, ok := timers[ti] if ok { t.enable = false + delete(timers, ti) //避免重复取消 ctx.Send("取消成功~") } else { ctx.Send("没有这个定时器哦~")