287 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package scoresaber
import (
"fmt"
"log"
"strconv"
"strings"
"sync"
"git.lxtend.com/qqbot/constants"
"git.lxtend.com/qqbot/handler"
"git.lxtend.com/qqbot/message"
"git.lxtend.com/qqbot/model"
"git.lxtend.com/qqbot/service/scoresaber"
"git.lxtend.com/qqbot/util"
)
func init() {
handler.RegisterHandler("查ss", getSSProfile, constants.LEVEL_USER)
handler.RegisterHelpInform("查ss", "scoresaber", " 查看您的最新分数")
handler.RegisterHandler("绑定ss", bindSS, constants.LEVEL_USER)
handler.RegisterHelpInform("绑定ss", "scoresaber", "绑定您的scoresaber账号")
handler.RegisterHandler("解绑ss", unbindSS, constants.LEVEL_USER)
handler.RegisterHelpInform("解绑ss", "scoresaber", "解绑您的scoresaber账号")
handler.RegisterHandler("最新ss", getMyRecentScore, constants.LEVEL_USER)
handler.RegisterHelpInform("最新ss", "scoresaber", "查看您的最新游戏记录")
handler.RegisterHandler("截ss", screenshotSS, constants.LEVEL_USER)
handler.RegisterHelpInform("ss+n", "scoresaber", "查看您需要打多少pp才能达到当前区服的第N名")
handler.RegisterFrontMatchHandler("ss+", ssPlusN, constants.LEVEL_USER)
handler.RegisterHelpInform("ss-n", "scoresaber", "查看落后您N名的玩家需要打多少pp才会超过您")
handler.RegisterFrontMatchHandler("ss-", ssPlusN, constants.LEVEL_USER)
}
func ssPlusN(msg model.Message) (reply *model.Reply) {
var (
resultStr strings.Builder
err error
maxRetries = 5 // 最大重试次数
attempts = 0
)
var N int
var isPlus bool
if strings.HasPrefix(msg.RawMsg, "ss+") {
isPlus = true
} else if strings.HasPrefix(msg.RawMsg, "ss-") {
isPlus = false
} else {
return &model.Reply{
ReplyMsg: "请输入ss+或ss-",
ReferOriginMsg: true,
FromMsg: msg,
}
}
if len(msg.RawMsg) > len("ss+") {
N, err = strconv.Atoi(msg.RawMsg[len("ss+"):])
if err != nil || N <= 0 {
return &model.Reply{
ReplyMsg: "请输入一个整数",
ReferOriginMsg: true,
FromMsg: msg,
}
}
}
if !isPlus {
N = -N
}
// 获取当前用户在区中的排名
userIdStr := strconv.Itoa(int(msg.UserId))
userSSID, err := scoresaber.GetSSID(userIdStr)
if err != nil {
return &model.Reply{
ReplyMsg: err.Error(),
ReferOriginMsg: true,
FromMsg: msg,
}
}
var userInfo scoresaber.PlayerData
for attempts < maxRetries {
err = nil
userInfo, err = scoresaber.FetchPlayerData(userSSID)
if err != nil {
break
}
attempts++
}
if err != nil {
return &model.Reply{
ReplyMsg: "获取您的分数时出现问题,请稍后重试。" + err.Error(),
ReferOriginMsg: true,
FromMsg: msg,
}
}
resultStr.WriteString(fmt.Sprintf("您当前的ScoreSaber全区排名为%d", userInfo.CountryRank))
// 获取当前用户所在区对应+N位的玩家列表
leaderboard, err := scoresaber.FetchCountryLeaderboard(userInfo.Country, userInfo.CountryRank-N, userInfo.ID)
if err != nil {
return &model.Reply{
ReplyMsg: "获取排行榜时出现问题,请稍后重试。" + err.Error(),
ReferOriginMsg: true,
FromMsg: msg,
}
}
if userInfo.CountryRank-N <= 0 {
resultStr.WriteString("\n")
if userInfo.CountryRank == 1 {
resultStr.WriteString(fmt.Sprintf("注意:你已经是%s区Top1了。", userInfo.Country))
} else {
resultStr.WriteString(fmt.Sprintf("注意:你最多只需要提升%d名就是%s区Top1了。", userInfo.CountryRank-1, userInfo.Country))
}
}
if userInfo.CountryRank != 1 {
//寻找leaderboard中排名为userInfo.CountryRank-N的玩家
var targetPlayer scoresaber.PlayerData
targetRank := userInfo.CountryRank - N
if targetRank < 0 {
targetRank = 1
}
for _, player := range leaderboard.Players {
if player.CountryRank == targetRank {
targetPlayer = player
break
}
}
resultStr.WriteString("\n")
if isPlus {
resultStr.WriteString(fmt.Sprintf("您只需要再打出%.2fpp就能超越%s达到%s区第%d名。", targetPlayer.PP-userInfo.PP, targetPlayer.Name, userInfo.Country, targetPlayer.CountryRank))
} else {
resultStr.WriteString(fmt.Sprintf("%s区的第%d名是%s对方只需要再打出%.2fpp就能超过你。", userInfo.Country, targetPlayer.CountryRank, targetPlayer.Name, userInfo.PP-targetPlayer.PP))
}
}
return &model.Reply{
ReplyMsg: resultStr.String(),
ReferOriginMsg: true,
FromMsg: msg,
}
}
func getSSProfile(msg model.Message) (reply *model.Reply) {
var (
resultStr string
err error
maxRetries = 5 // 最大重试次数
attempts = 0
noUpdate = false
)
var ssId string
if len(msg.RawMsg) > len("查ss ") {
ssId = strings.Split(msg.RawMsg, " ")[1]
noUpdate = true
}
userIdStr := strconv.Itoa(int(msg.UserId))
for attempts < maxRetries {
err = nil
if ssId == "" {
ssId, err = scoresaber.GetSSID(userIdStr)
}
if err != nil {
return &model.Reply{
ReplyMsg: "您未绑定ss账号输入\"绑定ss [ssId]\"绑定(ssId为您的scoresaber主页链接中的数字部分)",
ReferOriginMsg: true,
FromMsg: msg,
}
}
if !noUpdate {
resultStr, err = scoresaber.SSQuery.GetScore(ssId)
} else {
resultStr, err = scoresaber.SSQuery.GetScoreWithoutUpdate(ssId)
}
if err == nil {
break
}
attempts++
log.Printf("获取分数时出错,第 %d 次重试: %v", attempts, err)
}
// 如果所有尝试都失败,返回适当的错误消息
if err != nil {
resultStr = "获取您的分数时出现问题,请稍后重试。" + err.Error()
}
return &model.Reply{
ReplyMsg: resultStr,
ReferOriginMsg: true,
FromMsg: msg,
}
}
func bindSS(msg model.Message) (reply *model.Reply) {
return &model.Reply{
ReplyMsg: scoresaber.SSQuery.BindSS(strconv.Itoa(int(msg.UserId)), msg.RawMsg[len("绑定ss "):]),
ReferOriginMsg: true,
FromMsg: msg,
}
}
func unbindSS(msg model.Message) (reply *model.Reply) {
return &model.Reply{
ReplyMsg: scoresaber.SSQuery.UnbindSS(strconv.Itoa(int(msg.UserId))),
ReferOriginMsg: true,
FromMsg: msg,
}
}
func getMyRecentScore(msg model.Message) (reply *model.Reply) {
count := 1
scoreMsg := ""
if len(msg.RawMsg) > len("最新ss ") {
var err error
count, err = strconv.Atoi(msg.RawMsg[len("最新ss "):])
if err != nil || count <= 0 {
return &model.Reply{
ReplyMsg: "",
ReferOriginMsg: true,
FromMsg: msg,
}
}
if count > 10 {
count = 10
}
}
var userName string
recordCount := 0
records, err := scoresaber.SSQuery.GetRecentScores(count, strconv.Itoa(int(msg.UserId)))
if err != nil {
return &model.Reply{
ReplyMsg: err.Error(),
ReferOriginMsg: true,
FromMsg: msg,
}
}
coverImageMap := make(map[string]string)
wg := sync.WaitGroup{}
for _, record := range records {
coverImageMap[record.SongHash] = record.CoverImage
wg.Add(1)
go func(songHash string) {
defer wg.Done()
//文件存在则跳过
filePath, err := util.DownloadFile(coverImageMap[songHash], constants.TempDir, true)
if err != nil {
log.Printf("下载图片失败: %v", err)
return
}
newPath, err := util.ResizeImageByMaxHeight(filePath, 20)
if err != nil {
log.Printf("缩放图片失败: %v", err)
}
coverImageMap[songHash] = newPath
}(record.SongHash)
}
wg.Wait()
for _, record := range records {
imageMsg := message.ImageMessage{
Type: "image",
Data: message.ImageMessageData{
File: coverImageMap[record.SongHash],
},
}
scoreMsg += imageMsg.ToCQString() + record.ToString() + "\n"
userName = record.Name
recordCount++
}
if len(scoreMsg) > 0 {
scoreMsg = scoreMsg[:len(scoreMsg)-len("\n")] //去掉最后一个换行符
} else {
return &model.Reply{
ReplyMsg: "无最近游戏记录",
ReferOriginMsg: true,
FromMsg: msg,
}
}
return &model.Reply{
ReplyMsg: "玩家 " + userName + " 的" + strconv.Itoa(recordCount) + "条最近记录为:\n" + scoreMsg,
ReferOriginMsg: true,
FromMsg: msg,
}
}
func screenshotSS(msg model.Message) (reply *model.Reply) {
return &model.Reply{
ReplyMsg: "[CQ:image,file=file:///tmp/qqbot/" + scoresaber.GetSSPicture(strconv.Itoa(int(msg.UserId))) + "]",
ReferOriginMsg: true,
FromMsg: msg,
}
}