307 lines
9.4 KiB
Go
307 lines
9.4 KiB
Go
package beatleader
|
||
|
||
import (
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"strconv"
|
||
"time"
|
||
|
||
"git.lxtend.com/lixiangwuxian/qqbot/service"
|
||
"git.lxtend.com/lixiangwuxian/qqbot/sqlite3"
|
||
"git.lxtend.com/lixiangwuxian/qqbot/util"
|
||
_ "github.com/mattn/go-sqlite3"
|
||
)
|
||
|
||
func init() {
|
||
// 使用GORM自动迁移替代手写SQL
|
||
sqlite3.AutoMigrate(&service.BLData{}, &service.BLRecordData{})
|
||
}
|
||
|
||
var BLQuery = &blQuery{}
|
||
|
||
type blQuery struct {
|
||
}
|
||
|
||
func (bl *blQuery) BindBL(qqId string, blId string) (reply string) {
|
||
db := sqlite3.GetGormDB()
|
||
tx := db.Begin()
|
||
defer tx.Rollback()
|
||
// blId为数字
|
||
if _, isNum := strconv.Atoi(blId); isNum != nil {
|
||
return "blId格式错误,应当为一串数字(是您的beatleader主页链接中的末尾数字部分,一般和您的steamID相同)"
|
||
}
|
||
data, err := FetchPlayerData(blId)
|
||
if data == nil {
|
||
if err != nil {
|
||
return "请求出错,报错如下,如果确定命令没问题可以重新试试:" + err.Error()
|
||
}
|
||
return "未找到玩家,请检查ID后重试"
|
||
}
|
||
//去重
|
||
if rows, err := tx.Select("ssid").Where("qqid = ?", qqId).Find(&service.SSBind{}).Rows(); err == nil {
|
||
if rows.Next() {
|
||
var currentBlId string
|
||
err := rows.Scan(¤tBlId)
|
||
if err != nil {
|
||
log.Print(err)
|
||
}
|
||
rows.Close()
|
||
// 获取当前绑定账号的信息
|
||
if currentData, err := FetchPlayerData(currentBlId); err == nil && currentData != nil {
|
||
return fmt.Sprintf("您已绑定至bl账号:%s,请先输入\"解绑bl\"解绑", currentData.Name)
|
||
}
|
||
return "您已绑定过bl账号,请先输入\"解绑bl\"解绑"
|
||
} else {
|
||
rows.Close()
|
||
}
|
||
}
|
||
if rows, err := tx.Select("ssid").Where("ssid = ?", blId).Find(&service.SSBind{}).Rows(); err == nil {
|
||
if rows.Next() {
|
||
return "该bl账号已绑定至其他用户"
|
||
}
|
||
rows.Close()
|
||
}
|
||
err = tx.Create(&service.SSBind{QQID: qqId, SSID: blId}).Commit().Error
|
||
if err != nil {
|
||
return "绑定失败,请稍后重试:" + err.Error()
|
||
}
|
||
return "和用户名为 " + data.Name + " 的用户绑定成功,同时也绑定了您的scoresaber账号。输入\"查bl\"查看个人数据"
|
||
}
|
||
|
||
func (bl *blQuery) UnbindBL(qqId string) (reply string) {
|
||
db := sqlite3.GetGormDB()
|
||
tx := db.Begin()
|
||
defer tx.Rollback()
|
||
//是否已绑定
|
||
if rows, err := tx.Select("ssid").Where("qqid = ?", qqId).Find(&service.SSBind{}).Rows(); err == nil {
|
||
if !rows.Next() {
|
||
return "您未绑定bl账号,输入\"绑定bl [blId]\"绑定"
|
||
}
|
||
rows.Close()
|
||
}
|
||
err := tx.Delete(&service.SSBind{QQID: qqId}).Commit().Error
|
||
if err != nil {
|
||
return "解绑失败"
|
||
}
|
||
return "解绑成功,重新绑定请输入\"绑定bl [blId]\""
|
||
}
|
||
|
||
func (bl *blQuery) GetScore(qqId string) (currentData *PlayerDataLite, lastData *PlayerDataLite, err error) {
|
||
db := sqlite3.GetGormDB()
|
||
tx := db.Begin()
|
||
defer tx.Rollback()
|
||
|
||
blId, err := getBLID(qqId)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 查询玩家数据
|
||
data, err := FetchPlayerData(blId)
|
||
if data == nil && err == nil {
|
||
return nil, nil, errors.New("查询出错,服务器返回了空数据")
|
||
}
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 构建 PlayerDataLite 结构体
|
||
dataLite := data.ToDataLite()
|
||
|
||
newBLData := service.BLData{
|
||
ID: dataLite.ID,
|
||
Name: dataLite.Name,
|
||
Country: dataLite.Country,
|
||
PP: dataLite.PP,
|
||
Rank: dataLite.Rank,
|
||
CountryRank: dataLite.CountryRank,
|
||
TotalScore: dataLite.TotalScore,
|
||
TotalRankedScore: dataLite.TotalRankedScore,
|
||
AverageRankedAccuracy: dataLite.AverageRankedAccuracy,
|
||
TotalPlayCount: dataLite.TotalPlayCount,
|
||
RankedPlayCount: dataLite.RankedPlayCount,
|
||
ReplaysWatched: dataLite.ReplaysWatched,
|
||
GeneratedTime: time.Now(),
|
||
}
|
||
|
||
// 查询最近的玩家数据
|
||
lastBLData, err := service.GetLatestBLData(dataLite.ID)
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
|
||
currentDataLite := PlayerDataLite{
|
||
ID: dataLite.ID,
|
||
Name: dataLite.Name,
|
||
Country: dataLite.Country,
|
||
PP: dataLite.PP,
|
||
Rank: dataLite.Rank,
|
||
CountryRank: dataLite.CountryRank,
|
||
TotalScore: dataLite.TotalScore,
|
||
TotalRankedScore: dataLite.TotalRankedScore,
|
||
AverageRankedAccuracy: dataLite.AverageRankedAccuracy,
|
||
TotalPlayCount: dataLite.TotalPlayCount,
|
||
RankedPlayCount: dataLite.RankedPlayCount,
|
||
ReplaysWatched: dataLite.ReplaysWatched,
|
||
GeneratedTime: time.Now().Format("2006-01-02 15:04:05.999999999-07:00"),
|
||
}
|
||
|
||
if lastBLData == nil || hasDataChanged(lastBLData, &newBLData) {
|
||
err = tx.Create(&newBLData).Error
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
err = tx.Delete(&service.BLData{ID: dataLite.ID}).Error
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
}
|
||
|
||
// 如果有新的数据,则插入
|
||
if lastBLData == nil || hasDataChanged(lastBLData, &newBLData) {
|
||
//删掉旧数据
|
||
err = tx.Delete(&PlayerDataLite{ID: dataLite.ID}).Error
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
err = tx.Create(&newBLData).Error
|
||
if err != nil {
|
||
log.Print(err)
|
||
return nil, nil, err
|
||
}
|
||
if lastBLData != nil {
|
||
lastDataLite := PlayerDataLite{
|
||
ID: lastBLData.ID,
|
||
Name: lastBLData.Name,
|
||
Country: lastBLData.Country,
|
||
PP: lastBLData.PP,
|
||
Rank: lastBLData.Rank,
|
||
CountryRank: lastBLData.CountryRank,
|
||
TotalScore: lastBLData.TotalScore,
|
||
TotalRankedScore: lastBLData.TotalRankedScore,
|
||
AverageRankedAccuracy: lastBLData.AverageRankedAccuracy,
|
||
TotalPlayCount: lastBLData.TotalPlayCount,
|
||
RankedPlayCount: lastBLData.RankedPlayCount,
|
||
ReplaysWatched: lastBLData.ReplaysWatched,
|
||
GeneratedTime: lastBLData.GeneratedTime.Format("2006-01-02 15:04:05.999999999-07:00"),
|
||
}
|
||
// 返回差异信息
|
||
return ¤tDataLite, &lastDataLite, tx.Commit().Error
|
||
}
|
||
}
|
||
return &dataLite, nil, tx.Commit().Error
|
||
}
|
||
|
||
func hasDataChanged(old *service.BLData, new *service.BLData) bool {
|
||
return old.PP != new.PP || old.Rank != new.Rank || old.CountryRank != new.CountryRank ||
|
||
old.TotalScore != new.TotalScore || old.TotalRankedScore != new.TotalRankedScore
|
||
}
|
||
|
||
func (bl *blQuery) GetScoreWithoutUpdate(qqId string) (currentData *PlayerDataLite, err error) {
|
||
blId, err := getBLID(qqId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 查询玩家数据
|
||
data, err := FetchPlayerData(blId)
|
||
if err != nil {
|
||
return nil, errors.New("查询出错,报错如下" + err.Error())
|
||
}
|
||
if data.ID == "" {
|
||
return nil, errors.New("未找到玩家,请检查ID后重试")
|
||
}
|
||
dataLite := data.ToDataLite()
|
||
// 返回当前数据的字符串表示
|
||
return &dataLite, nil
|
||
}
|
||
|
||
func (bl *blQuery) GetRecentScores(count int, qqId string) ([]RecordDataLite, error) {
|
||
// 查询绑定的 blId
|
||
blId, err := getBLID(qqId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// return records, nil
|
||
playerData, err := FetchPlayerData(blId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
//从线上获取
|
||
historyUrl := "https://api.beatleader.xyz/player/%s/scores?leaderboardContext=general&page=1&sortBy=date&order=desc&includeIO=true&count=%d"
|
||
fullUrl := fmt.Sprintf(historyUrl, blId, count)
|
||
resp, err := http.Get(fullUrl)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
body, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var response struct {
|
||
Data []ScoreData `json:"data"`
|
||
}
|
||
err = json.Unmarshal(body, &response)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
scores := response.Data
|
||
records := make([]RecordDataLite, 0)
|
||
for _, score := range scores {
|
||
dataLite := RecordDataLite{
|
||
ScoreID: score.ID,
|
||
BlID: blId,
|
||
Name: playerData.Name,
|
||
Country: playerData.Country,
|
||
SongName: score.Leaderboard.Song.Name,
|
||
SongSubName: score.Leaderboard.Song.SubName,
|
||
SongAuthorName: score.Leaderboard.Song.Author,
|
||
SongHash: score.Leaderboard.Song.Hash,
|
||
SongId: "",
|
||
CoverImage: score.Leaderboard.Song.CoverImage,
|
||
DifficultyRaw: score.Leaderboard.Difficulty.DifficultyName,
|
||
PP: score.Pp,
|
||
Stars: 0,
|
||
Weight: score.Weight,
|
||
Modifiers: score.Modifiers,
|
||
Multiplier: float64(score.ModifiedScore) / float64(score.BaseScore),
|
||
BadCuts: score.BadCuts,
|
||
Score: score.ModifiedScore,
|
||
Rank: score.Rank,
|
||
MaxScore: int(float64(score.ModifiedScore) / score.Accuracy),
|
||
FullCombo: score.FullCombo,
|
||
DeviceHmd: GetHMDStr(score.HMD),
|
||
DeviceControllerLeft: GetControllerStr(score.Controller),
|
||
DeviceControllerRight: GetControllerStr(score.Controller),
|
||
GeneratedTime: time.Unix(score.Timepost, 0).Format("2006-01-02 15:04:05.999999999-07:00"),
|
||
}
|
||
if score.Leaderboard.Difficulty.Stars != nil {
|
||
dataLite.Stars = *score.Leaderboard.Difficulty.Stars
|
||
}
|
||
records = append(records, dataLite)
|
||
}
|
||
// 获取歌曲ID
|
||
hashs := make([]string, 0)
|
||
for _, record := range records {
|
||
hashs = append(hashs, record.SongHash)
|
||
}
|
||
hashToSongId, err := util.GetSongIdsByHash(hashs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
for i := 0; i < len(records); i++ {
|
||
records[i].SongId = hashToSongId[records[i].SongHash]
|
||
}
|
||
|
||
return records, nil
|
||
}
|