-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat:添加签到功能,引入分数机制 * feat:修lint * fix:加宽 * fix:修lint和加锁 * fix:解决冲突 * fix:二次判断
- Loading branch information
1 parent
d8991ec
commit 2ed25c6
Showing
8 changed files
with
377 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package score | ||
|
||
import ( | ||
"github.com/FloatTech/ZeroBot-Plugin/utils/process" | ||
log "github.com/sirupsen/logrus" | ||
"os" | ||
) | ||
|
||
const ( | ||
cachePath = dbpath + "cache/" | ||
dbpath = "data/Score/" | ||
dbfile = dbpath + "score.db" | ||
) | ||
|
||
// SDB 得分数据库 | ||
var SDB *DB | ||
|
||
// 加载数据库 | ||
func init() { | ||
go func() { | ||
process.SleepAbout1sTo2s() | ||
_ = os.MkdirAll(dbpath, 0755) | ||
os.RemoveAll(cachePath) | ||
_ = os.MkdirAll(cachePath, 0755) | ||
SDB = Initialize(dbfile) | ||
log.Println("[score]加载score数据库") | ||
}() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package score | ||
|
||
import ( | ||
"github.com/jinzhu/gorm" | ||
_ "github.com/logoove/sqlite" // import sql | ||
"os" | ||
"time" | ||
) | ||
|
||
// DB 分数数据库 | ||
type DB gorm.DB | ||
|
||
// Score 分数结构体 | ||
type Score struct { | ||
UID int64 `gorm:"column:uid;primary_key"` | ||
Score int `gorm:"column:score;default:0"` | ||
} | ||
|
||
// TableName ... | ||
func (Score) TableName() string { | ||
return "score" | ||
} | ||
|
||
// SignIn 签到结构体 | ||
type SignIn struct { | ||
UID int64 `gorm:"column:uid;primary_key"` | ||
Count int `gorm:"column:count;default:0"` | ||
UpdatedAt time.Time | ||
} | ||
|
||
// TableName ... | ||
func (SignIn) TableName() string { | ||
return "sign_in" | ||
} | ||
|
||
// Initialize 初始化ScoreDB数据库 | ||
func Initialize(dbpath string) *DB { | ||
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(&Score{}).AutoMigrate(&SignIn{}) | ||
return (*DB)(gdb) | ||
} | ||
|
||
// Open ... | ||
func Open(dbpath string) (*DB, error) { | ||
db, err := gorm.Open("sqlite3", dbpath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return (*DB)(db), nil | ||
} | ||
|
||
// Close ... | ||
func (sdb *DB) Close() error { | ||
db := (*gorm.DB)(sdb) | ||
return db.Close() | ||
} | ||
|
||
// GetScoreByUID 取得分数 | ||
func (sdb *DB) GetScoreByUID(uid int64) (s Score) { | ||
db := (*gorm.DB)(sdb) | ||
db.Debug().Model(&Score{}).FirstOrCreate(&s, "uid = ? ", uid) | ||
return s | ||
} | ||
|
||
// InsertOrUpdateScoreByUID 插入或更新分数 | ||
func (sdb *DB) InsertOrUpdateScoreByUID(uid int64, score int) (err error) { | ||
db := (*gorm.DB)(sdb) | ||
s := Score{ | ||
UID: uid, | ||
Score: score, | ||
} | ||
if err = db.Debug().Model(&Score{}).First(&s, "uid = ? ", uid).Error; err != nil { | ||
// error handling... | ||
if gorm.IsRecordNotFoundError(err) { | ||
db.Debug().Model(&Score{}).Create(&s) // newUser not user | ||
} | ||
} else { | ||
err = db.Debug().Model(&Score{}).Where("uid = ? ", uid).Update( | ||
map[string]interface{}{ | ||
"score": score, | ||
}).Error | ||
} | ||
return | ||
} | ||
|
||
// GetSignInByUID 取得签到次数 | ||
func (sdb *DB) GetSignInByUID(uid int64) (si SignIn) { | ||
db := (*gorm.DB)(sdb) | ||
db.Debug().Model(&SignIn{}).FirstOrCreate(&si, "uid = ? ", uid) | ||
return si | ||
} | ||
|
||
// InsertOrUpdateSignInCountByUID 插入或更新签到次数 | ||
func (sdb *DB) InsertOrUpdateSignInCountByUID(uid int64, count int) (err error) { | ||
db := (*gorm.DB)(sdb) | ||
si := SignIn{ | ||
UID: uid, | ||
Count: count, | ||
} | ||
if err = db.Debug().Model(&SignIn{}).First(&si, "uid = ? ", uid).Error; err != nil { | ||
// error handling... | ||
if gorm.IsRecordNotFoundError(err) { | ||
db.Debug().Model(&SignIn{}).Create(&si) // newUser not user | ||
} | ||
} else { | ||
err = db.Debug().Model(&SignIn{}).Where("uid = ? ", uid).Update( | ||
map[string]interface{}{ | ||
"count": count, | ||
}).Error | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// Package score 签到,答题得分 | ||
package score | ||
|
||
import ( | ||
"fmt" | ||
"github.com/FloatTech/ZeroBot-Plugin/control" | ||
"github.com/FloatTech/ZeroBot-Plugin/utils/ctxext" | ||
"github.com/FloatTech/ZeroBot-Plugin/utils/file" | ||
"github.com/FloatTech/ZeroBot-Plugin/utils/txt2img" | ||
"github.com/FloatTech/ZeroBot-Plugin/utils/web" | ||
"github.com/fogleman/gg" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/tidwall/gjson" | ||
zero "github.com/wdvxdr1123/ZeroBot" | ||
"github.com/wdvxdr1123/ZeroBot/message" | ||
"github.com/wdvxdr1123/ZeroBot/utils/helper" | ||
"os" | ||
"strconv" | ||
"sync" | ||
"time" | ||
) | ||
|
||
const ( | ||
prio = 5 | ||
backgroundURL = "https://iw233.cn/API/pc.php?type=json" | ||
referer = "https://iw233.cn/main.html" | ||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" | ||
signinMax = 1 | ||
// ScoreMax 分数上限定为120 | ||
ScoreMax = 120 | ||
) | ||
|
||
var ( | ||
engine = control.Register("score", &control.Options{ | ||
DisableOnDefault: false, | ||
Help: "签到得分\n- 签到\n- 获得签到背景[@xxx]|获得签到背景", | ||
}) | ||
levelArray = [...]int{0, 1, 2, 5, 10, 20, 35, 55, 75, 100, 120} | ||
// 下载锁 | ||
mu sync.Mutex | ||
) | ||
|
||
func init() { | ||
engine.OnFullMatch("签到").SetBlock(true).SetPriority(prio). | ||
Handle(func(ctx *zero.Ctx) { | ||
uid := ctx.Event.UserID | ||
now := time.Now() | ||
today := now.Format("20060102") | ||
si := SDB.GetSignInByUID(uid) | ||
picFile := cachePath + strconv.FormatInt(uid, 10) + today + ".png" | ||
if file.IsNotExist(picFile) { | ||
mu.Lock() | ||
initPic(picFile) | ||
mu.Unlock() | ||
} | ||
siUpdateTimeStr := si.UpdatedAt.Format("20060102") | ||
if siUpdateTimeStr != today { | ||
if err := SDB.InsertOrUpdateSignInCountByUID(uid, 0); err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
} | ||
if si.Count >= signinMax && siUpdateTimeStr == today { | ||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("今天你已经签到过了!")) | ||
return | ||
} | ||
if err := SDB.InsertOrUpdateSignInCountByUID(uid, si.Count+1); err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
back, err := gg.LoadImage(picFile) | ||
if err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
canvas := gg.NewContext(back.Bounds().Size().X, int(float64(back.Bounds().Size().Y)*1.7)) | ||
canvas.SetRGB(1, 1, 1) | ||
canvas.Clear() | ||
canvas.DrawImage(back, 0, 0) | ||
|
||
monthWord := now.Format("01/02") | ||
hourWord := getHourWord(now) | ||
if err = canvas.LoadFontFace(txt2img.BoldFontFile, float64(back.Bounds().Size().X)*0.1); err != nil { | ||
log.Println("[score]:", err) | ||
} | ||
canvas.SetRGB(0, 0, 0) | ||
canvas.DrawString(hourWord, float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.2) | ||
canvas.DrawString(monthWord, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*1.2) | ||
nickName := ctxext.CardOrNickName(ctx, uid) | ||
if err = canvas.LoadFontFace(txt2img.FontFile, float64(back.Bounds().Size().X)*0.04); err != nil { | ||
log.Println("[score]:", err) | ||
} | ||
add := 1 | ||
canvas.DrawString(nickName+fmt.Sprintf(" 小熊饼干+%d", add), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.3) | ||
score := SDB.GetScoreByUID(uid).Score | ||
score += add | ||
if score > ScoreMax { | ||
score = ScoreMax | ||
ctx.SendChain(message.At(uid), message.Text("你获得的小熊饼干已经达到上限")) | ||
} | ||
if err := SDB.InsertOrUpdateScoreByUID(uid, score); err != nil { | ||
log.Println("[score]:", err) | ||
} | ||
level := getLevel(score) | ||
canvas.DrawString("当前小熊饼干:"+strconv.FormatInt(int64(score), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.4) | ||
canvas.DrawString("LEVEL:"+strconv.FormatInt(int64(level), 10), float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.5) | ||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6, float64(back.Bounds().Size().Y)*0.1) | ||
canvas.SetRGB255(150, 150, 150) | ||
canvas.Fill() | ||
var nextLevelScore int | ||
if level < 10 { | ||
nextLevelScore = levelArray[level+1] | ||
} else { | ||
nextLevelScore = ScoreMax | ||
} | ||
canvas.SetRGB255(0, 0, 0) | ||
canvas.DrawRectangle(float64(back.Bounds().Size().X)*0.1, float64(back.Bounds().Size().Y)*1.55, float64(back.Bounds().Size().X)*0.6*float64(score)/float64(nextLevelScore), float64(back.Bounds().Size().Y)*0.1) | ||
canvas.SetRGB255(102, 102, 102) | ||
canvas.Fill() | ||
canvas.DrawString(fmt.Sprintf("%d/%d", score, nextLevelScore), float64(back.Bounds().Size().X)*0.75, float64(back.Bounds().Size().Y)*1.62) | ||
canvasBase64, err := txt2img.CanvasToBase64(canvas) | ||
if err != nil { | ||
log.Println("[score]:", err) | ||
} | ||
ctx.SendChain(message.Image("base64://" + helper.BytesToString(canvasBase64))) | ||
}) | ||
engine.OnPrefix("获得签到背景", zero.OnlyGroup).SetBlock(true).SetPriority(20). | ||
Handle(func(ctx *zero.Ctx) { | ||
param := ctx.State["args"].(string) | ||
var uidStr string | ||
if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" { | ||
uidStr = ctx.Event.Message[1].Data["qq"] | ||
} else if param == "" { | ||
uidStr = strconv.FormatInt(ctx.Event.UserID, 10) | ||
} | ||
picFile := cachePath + uidStr + time.Now().Format("20060102") + ".png" | ||
if file.IsNotExist(picFile) { | ||
mu.Lock() | ||
initPic(picFile) | ||
mu.Unlock() | ||
} | ||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + picFile)) | ||
}) | ||
} | ||
|
||
func getHourWord(t time.Time) string { | ||
switch { | ||
case 6 <= t.Hour() && t.Hour() < 12: | ||
return "早上好" | ||
case 12 <= t.Hour() && t.Hour() < 14: | ||
return "中午好" | ||
case 14 <= t.Hour() && t.Hour() < 19: | ||
return "下午好" | ||
case 19 <= t.Hour() && t.Hour() < 24: | ||
return "晚上好" | ||
case 0 <= t.Hour() && t.Hour() < 6: | ||
return "凌晨好" | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
func getLevel(count int) int { | ||
for k, v := range levelArray { | ||
if count == v { | ||
return k | ||
} else if count < v { | ||
return k - 1 | ||
} | ||
} | ||
return -1 | ||
} | ||
|
||
func initPic(picFile string) { | ||
if file.IsNotExist(picFile) { | ||
data, err := web.ReqWith(backgroundURL, "GET", referer, ua) | ||
if err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
picURL := gjson.Get(string(data), "pic").String() | ||
data, err = web.ReqWith(picURL, "GET", "", ua) | ||
if err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
err = os.WriteFile(picFile, data, 0666) | ||
if err != nil { | ||
log.Errorln("[score]:", err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.