feat: 为 BeatLeader 和 ScoreSaber 添加通用歌曲 ID 获取方法

This commit is contained in:
lixiangwuxian
2025-03-08 20:35:53 +08:00
parent 7dbdaed21f
commit 8b4866b4d3
3 changed files with 165 additions and 53 deletions

View File

@@ -2,9 +2,14 @@ package scoresaber
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"strconv"
"strings"
"time"
"git.lxtend.com/qqbot/sqlite3"
@@ -242,6 +247,7 @@ func (ss *ssQuery) SaveRecord(cmdData CommandData) {
SongSubName: cmdData.Leaderboard.SongSubName,
SongAuthorName: cmdData.Leaderboard.SongAuthorName,
SongHash: cmdData.Leaderboard.SongHash,
SongId: "",
CoverImage: cmdData.Leaderboard.CoverImage,
DifficultyRaw: cmdData.Leaderboard.Difficulty.DifficultyRaw,
Stars: cmdData.Leaderboard.Stars,
@@ -298,36 +304,126 @@ func (ss *ssQuery) SaveRecord(cmdData CommandData) {
}
func (ss *ssQuery) GetRecentScores(count int, qqId string) ([]RecordDataLite, error) {
db := sqlite3.GetDB() // 假设 sqlite3.GetDB() 返回 *sqlx.DB
tx, err := db.Beginx()
if err != nil {
log.Print(err)
return nil, errors.New("数据库连接失败,请稍后重试")
}
defer tx.Rollback()
ssId, err := GetSSID(qqId)
if err != nil {
return nil, err
}
// 查询记录
var records []RecordDataLite
err = tx.Select(&records, "SELECT * FROM ssRecordData WHERE ss_id = ? ORDER BY generated_time DESC LIMIT ?", ssId, count)
playerData, err := FetchPlayerData(ssId)
if err != nil {
if err == sql.ErrNoRows {
return nil, errors.New("未查询到数据")
return nil, err
}
historyUrl := "https://scoresaber.com/api/player/%s/scores?page=1&sort=recent"
fullUrl := fmt.Sprintf(historyUrl, ssId)
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 []struct {
Score Score `json:"score"`
Leaderboard Leaderboard `json:"leaderboard"`
} `json:"playerScores"`
}
err = json.Unmarshal(body, &response)
if err != nil {
return nil, err
}
scores := response.Data
records := make([]RecordDataLite, 0)
for k, score := range scores {
if k > count {
break
}
log.Println("查询数据出错:", err)
return nil, errors.New("查询记录失败")
record := RecordDataLite{
ScoreID: score.Score.ID,
SsID: ssId,
Name: playerData.Name,
Country: playerData.Country,
SongName: score.Leaderboard.SongName,
SongSubName: score.Leaderboard.SongSubName,
SongAuthorName: score.Leaderboard.SongAuthorName,
SongHash: score.Leaderboard.SongHash,
SongId: "",
CoverImage: score.Leaderboard.CoverImage,
DifficultyRaw: score.Leaderboard.Difficulty.DifficultyRaw,
Stars: score.Leaderboard.Stars,
PP: score.Score.Pp,
Weight: score.Score.Weight,
Modifiers: score.Score.Modifiers,
Multiplier: score.Score.Multiplier,
Rank: score.Score.Rank,
BadCuts: score.Score.BadCuts,
Score: score.Score.ModifiedScore,
MaxScore: score.Leaderboard.MaxScore,
FullCombo: score.Score.FullCombo,
DeviceHmd: "",
DeviceControllerLeft: "",
DeviceControllerRight: "",
GeneratedTime: score.Score.TimeSet.Format("2006-01-02 15:04:05.999999999-07:00"),
}
// 检查设备信息并设置
if score.Score.DeviceHmd != nil {
record.DeviceHmd = *score.Score.DeviceHmd
}
if score.Score.DeviceControllerLeft != nil {
record.DeviceControllerLeft = *score.Score.DeviceControllerLeft
}
if score.Score.DeviceControllerRight != nil {
record.DeviceControllerRight = *score.Score.DeviceControllerRight
}
records = append(records, record)
}
// 提交事务
err = tx.Commit()
// 获取歌曲ID
hashs := make([]string, 0)
for _, record := range records {
hashs = append(hashs, record.SongHash)
}
hashToSongId, err := GetSongIdsByHash(hashs)
if err != nil {
log.Print(err)
return nil, errors.New("提交事务失败")
return nil, err
}
for i := 0; i < len(records); i++ {
records[i].SongId = hashToSongId[records[i].SongHash]
}
return records, nil
}
func GetSongIdsByHash(hashs []string) (hashToSongId map[string]string, err error) {
//每批最多49个
batchSize := 49
for i := 0; i < len(hashs); i += batchSize {
end := i + batchSize
if end > len(hashs) {
end = len(hashs)
}
batchHashs := hashs[i:end]
queryUrl := "https://api.beatsaver.com/maps/hash/" + strings.Join(batchHashs, ",")
resp, err := http.Get(queryUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var response map[string]struct {
ID string `json:"id"`
}
err = json.Unmarshal(body, &response)
if err != nil {
return nil, err
}
for hash, data := range response {
hashToSongId[hash] = data.ID
}
}
return hashToSongId, nil
}