Fix: Support both numeric and hash song IDs for leaderboard

This commit is contained in:
2026-01-17 19:56:41 +08:00
parent 3f7ff13ef7
commit 9935d70e31
5 changed files with 20 additions and 15 deletions

9
app.py
View File

@@ -858,7 +858,6 @@ def route_api_leaderboard_submit():
return jsonify({'status': 'ok', 'message': 'score_submitted'}) return jsonify({'status': 'ok', 'message': 'score_submitted'})
@app.route(basedir + 'api/leaderboard/get') @app.route(basedir + 'api/leaderboard/get')
def route_api_leaderboard_get(): def route_api_leaderboard_get():
song_id = request.args.get('song_id', None) song_id = request.args.get('song_id', None)
@@ -867,10 +866,13 @@ def route_api_leaderboard_get():
if not song_id or not difficulty: if not song_id or not difficulty:
return abort(400) return abort(400)
# Accept both numeric IDs and hash strings
# Try to convert to int if possible, otherwise use as string
try: try:
song_id = int(song_id) song_id = int(song_id)
except: except (ValueError, TypeError):
return abort(400) # Keep as string (hash ID)
pass
# Validate difficulty # Validate difficulty
valid_difficulties = ['easy', 'normal', 'hard', 'oni', 'ura'] valid_difficulties = ['easy', 'normal', 'hard', 'oni', 'ura']
@@ -901,6 +903,7 @@ def route_api_leaderboard_get():
return jsonify({'status': 'ok', 'leaderboard': leaderboard, 'month': current_month}) return jsonify({'status': 'ok', 'leaderboard': leaderboard, 'month': current_month})
@app.route(basedir + 'privacy') @app.route(basedir + 'privacy')
def route_api_privacy(): def route_api_privacy():
last_modified = time.strftime('%d %B %Y', time.gmtime(os.path.getmtime('templates/privacy.txt'))) last_modified = time.strftime('%d %B %Y', time.gmtime(os.path.getmtime('templates/privacy.txt')))

View File

@@ -77,17 +77,18 @@ class Leaderboard {
} }
async fetchLeaderboard() { async fetchLeaderboard() {
// Validate songId is a valid number // Validate songId exists
if (!this.songId || isNaN(parseInt(this.songId))) { if (!this.songId) {
console.error("Invalid song ID for leaderboard:", this.songId) console.error("Missing song ID for leaderboard")
this.leaderboardData = [] this.leaderboardData = []
return return
} }
try { try {
var response = await loader.ajax( var response = await loader.ajax(
`${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${parseInt(this.songId)}&difficulty=${this.difficulty}` `${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${encodeURIComponent(this.songId)}&difficulty=${this.difficulty}`
) )
var data = JSON.parse(response) var data = JSON.parse(response)
if (data.status === "ok") { if (data.status === "ok") {
this.leaderboardData = data.leaderboard || [] this.leaderboardData = data.leaderboard || []

View File

@@ -958,11 +958,12 @@ class Scoresheet {
} }
submitToLeaderboard(songId, difficulty, scoreObj) { submitToLeaderboard(songId, difficulty, scoreObj) {
// Only submit if user is logged in and song has valid numeric ID // Only submit if user is logged in and song has an ID
if (!account.loggedIn || !songId || isNaN(parseInt(songId))) { if (!account.loggedIn || !songId) {
return return
} }
var self = this var self = this
loader.getCsrfToken().then(token => { loader.getCsrfToken().then(token => {
var request = new XMLHttpRequest() var request = new XMLHttpRequest()
@@ -984,7 +985,7 @@ class Scoresheet {
} }
request.send(JSON.stringify({ request.send(JSON.stringify({
song_id: parseInt(songId), song_id: songId,
difficulty: difficulty, difficulty: difficulty,
score: scoreObj score: scoreObj
})) }))

View File

@@ -3336,12 +3336,11 @@ class SongSelect {
} }
toLeaderboard() { toLeaderboard() {
var songId = this.songs[this.selectedSong].id var songId = this.songs[this.selectedSong].id
// Only allow leaderboard for server songs with numeric IDs // Allow leaderboard for any song with an ID (numeric or hash)
if (!songId || typeof songId !== 'number' || isNaN(songId)) { if (!songId) {
// Show alert for custom/local songs
alert("排行榜仅支持服务器歌曲\nLeaderboard only available for server songs")
return return
} }
// Default to first available difficulty if not in a valid difficulty selection // Default to first available difficulty if not in a valid difficulty selection
var selectedDiff = this.selectedDiff - this.diffOptions.length var selectedDiff = this.selectedDiff - this.diffOptions.length
if (selectedDiff < 0) { if (selectedDiff < 0) {

View File

@@ -85,9 +85,10 @@ leaderboard_submit = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'song_id': {'type': 'number'}, 'song_id': {'type': ['number', 'string']},
'difficulty': {'type': 'string'}, 'difficulty': {'type': 'string'},
'score': {'type': 'object'} 'score': {'type': 'object'}
}, },
'required': ['song_id', 'difficulty', 'score'] 'required': ['song_id', 'difficulty', 'score']
} }