Fix: Support both numeric and hash song IDs for leaderboard
This commit is contained in:
9
app.py
9
app.py
@@ -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')))
|
||||||
|
|||||||
@@ -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 || []
|
||||||
|
|||||||
@@ -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
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user