Add API rate and Spotify rate limit info to Copy Debug Info
- Backend: include api_rates (per-service calls/min + Spotify endpoints) and spotify_rate_limit (active, remaining, trigger endpoint) in debug-info - Frontend: format API rates table with service name, cpm, limit, percentage, and Spotify endpoint breakdown. Show bold warning block when rate limited with trigger endpoint, remaining time, and retry-after value
This commit is contained in:
parent
e42fe995d3
commit
0c5bfcae1f
2 changed files with 45 additions and 0 deletions
|
|
@ -4523,6 +4523,28 @@ def get_debug_info():
|
|||
'm3u_export_enabled': config_manager.get('m3u.enabled', False),
|
||||
}
|
||||
|
||||
# API rate monitor — current calls/min per service + Spotify rate limit state
|
||||
try:
|
||||
from core.api_call_tracker import api_call_tracker
|
||||
rates = api_call_tracker.get_all_rates()
|
||||
info['api_rates'] = rates
|
||||
# Spotify rate limit details
|
||||
if spotify_client:
|
||||
rl_info = spotify_client.get_rate_limit_info()
|
||||
if rl_info:
|
||||
info['spotify_rate_limit'] = {
|
||||
'active': True,
|
||||
'remaining_seconds': rl_info.get('remaining_seconds', 0),
|
||||
'retry_after': rl_info.get('retry_after', 0),
|
||||
'endpoint': rl_info.get('endpoint', ''),
|
||||
'expires_at': rl_info.get('expires_at', ''),
|
||||
}
|
||||
else:
|
||||
info['spotify_rate_limit'] = {'active': False}
|
||||
except Exception:
|
||||
info['api_rates'] = {}
|
||||
info['spotify_rate_limit'] = {'active': False}
|
||||
|
||||
# Database size
|
||||
db_path = os.path.join('database', 'music_library.db')
|
||||
if os.path.exists(db_path):
|
||||
|
|
|
|||
|
|
@ -2291,6 +2291,29 @@ function initializeDocsPage() {
|
|||
}
|
||||
text += '\n';
|
||||
|
||||
text += '── API Rates (calls/min) ──\n';
|
||||
if (data.api_rates) {
|
||||
Object.entries(data.api_rates).forEach(([svc, info]) => {
|
||||
const cpm = info.cpm || 0;
|
||||
const limit = info.limit || '?';
|
||||
const pct = limit ? Math.round(cpm / limit * 100) : 0;
|
||||
text += `${svc.padEnd(14)} ${String(cpm).padStart(5)}/min (limit: ${limit}, ${pct}%)`;
|
||||
if (info.endpoints && Object.keys(info.endpoints).length > 0) {
|
||||
text += ` endpoints: ${Object.entries(info.endpoints).map(([e, c]) => `${e}:${c}`).join(', ')}`;
|
||||
}
|
||||
text += '\n';
|
||||
});
|
||||
}
|
||||
if (data.spotify_rate_limit?.active) {
|
||||
const rl = data.spotify_rate_limit;
|
||||
const mins = Math.ceil((rl.remaining_seconds || 0) / 60);
|
||||
text += `\n*** SPOTIFY RATE LIMITED ***\n`;
|
||||
text += `Triggered by: ${rl.endpoint || 'unknown'}\n`;
|
||||
text += `Remaining: ${mins} minutes\n`;
|
||||
text += `Retry-After: ${rl.retry_after || '?'}s\n`;
|
||||
}
|
||||
text += '\n';
|
||||
|
||||
text += `── Logs: ${data.log_source || 'app'}.log (last ${data.recent_logs?.length || 0} lines) ──\n`;
|
||||
if (data.recent_logs?.length) {
|
||||
data.recent_logs.forEach(line => { text += line + '\n'; });
|
||||
|
|
|
|||
Loading…
Reference in a new issue