Drop old per-service enrichment routes after registry cutover
Followup to the enrichment-bubble registry consolidation. The
dashboard polling + click handlers all hit
/api/enrichment/<service>/{status,pause,resume} now, so the 30
hand-rolled per-service routes in web_server.py have zero callers
and can come out:
/api/musicbrainz/{status,pause,resume}
/api/audiodb/{status,pause,resume}
/api/discogs/{status,pause,resume}
/api/deezer/{status,pause,resume}
/api/spotify-enrichment/{status,pause,resume}
/api/itunes-enrichment/{status,pause,resume}
/api/lastfm-enrichment/{status,pause,resume}
/api/genius-enrichment/{status,pause,resume}
/api/tidal-enrichment/{status,pause,resume}
/api/qobuz-enrichment/{status,pause,resume}
Worker init blocks stay (they still construct the workers + persist
pause state). Section comment headers are preserved with a one-line
note pointing readers at the new generic blueprint.
Test fixtures in tests/conftest.py and
tests/metadata/test_enrichment_events.py also updated to use the
new URL paths so they reflect production reality. They were
synthetic stubs that never depended on the production routes —
purely cosmetic alignment.
Net: ~510 lines deleted from web_server.py. Full pytest 1541
passed; ruff clean.
This commit is contained in:
parent
3a7a2260b2
commit
7e32618f86
4 changed files with 48 additions and 535 deletions
|
|
@ -313,11 +313,11 @@ ENRICHMENT_WORKERS = [
|
|||
]
|
||||
|
||||
ENRICHMENT_ENDPOINTS = {
|
||||
'musicbrainz': '/api/musicbrainz/status',
|
||||
'audiodb': '/api/audiodb/status',
|
||||
'deezer': '/api/deezer/status',
|
||||
'spotify-enrichment': '/api/spotify-enrichment/status',
|
||||
'itunes-enrichment': '/api/itunes-enrichment/status',
|
||||
'musicbrainz': '/api/enrichment/musicbrainz/status',
|
||||
'audiodb': '/api/enrichment/audiodb/status',
|
||||
'deezer': '/api/enrichment/deezer/status',
|
||||
'spotify-enrichment': '/api/enrichment/spotify/status',
|
||||
'itunes-enrichment': '/api/enrichment/itunes/status',
|
||||
'hydrabase': '/api/hydrabase-worker/status',
|
||||
'repair': '/api/repair/status',
|
||||
}
|
||||
|
|
@ -576,23 +576,23 @@ def test_app():
|
|||
|
||||
# --- Phase 3 HTTP endpoints (enrichment workers) ---
|
||||
|
||||
@app.route('/api/musicbrainz/status')
|
||||
@app.route('/api/enrichment/musicbrainz/status')
|
||||
def musicbrainz_status():
|
||||
return jsonify(_build_enrichment_status('musicbrainz'))
|
||||
|
||||
@app.route('/api/audiodb/status')
|
||||
@app.route('/api/enrichment/audiodb/status')
|
||||
def audiodb_status():
|
||||
return jsonify(_build_enrichment_status('audiodb'))
|
||||
|
||||
@app.route('/api/deezer/status')
|
||||
@app.route('/api/enrichment/deezer/status')
|
||||
def deezer_status():
|
||||
return jsonify(_build_enrichment_status('deezer'))
|
||||
|
||||
@app.route('/api/spotify-enrichment/status')
|
||||
@app.route('/api/enrichment/spotify/status')
|
||||
def spotify_enrichment_status():
|
||||
return jsonify(_build_enrichment_status('spotify-enrichment'))
|
||||
|
||||
@app.route('/api/itunes-enrichment/status')
|
||||
@app.route('/api/enrichment/itunes/status')
|
||||
def itunes_enrichment_status():
|
||||
return jsonify(_build_enrichment_status('itunes-enrichment'))
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ WORKERS = [
|
|||
|
||||
# Endpoint URLs keyed by worker name
|
||||
ENDPOINTS = {
|
||||
'musicbrainz': '/api/musicbrainz/status',
|
||||
'audiodb': '/api/audiodb/status',
|
||||
'deezer': '/api/deezer/status',
|
||||
'spotify-enrichment': '/api/spotify-enrichment/status',
|
||||
'itunes-enrichment': '/api/itunes-enrichment/status',
|
||||
'musicbrainz': '/api/enrichment/musicbrainz/status',
|
||||
'audiodb': '/api/enrichment/audiodb/status',
|
||||
'deezer': '/api/enrichment/deezer/status',
|
||||
'spotify-enrichment': '/api/enrichment/spotify/status',
|
||||
'itunes-enrichment': '/api/enrichment/itunes/status',
|
||||
'hydrabase': '/api/hydrabase-worker/status',
|
||||
'repair': '/api/repair/status',
|
||||
}
|
||||
|
|
|
|||
550
web_server.py
550
web_server.py
|
|
@ -32248,57 +32248,9 @@ except Exception as e:
|
|||
logger.error(f"MusicBrainz worker initialization failed: {e}")
|
||||
mb_worker = None
|
||||
|
||||
# --- MusicBrainz API Endpoints ---
|
||||
|
||||
@app.route('/api/musicbrainz/status', methods=['GET'])
|
||||
def musicbrainz_status():
|
||||
"""Get MusicBrainz enrichment status for UI polling"""
|
||||
try:
|
||||
if mb_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = mb_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting MusicBrainz status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/musicbrainz/pause', methods=['POST'])
|
||||
def musicbrainz_pause():
|
||||
"""Pause MusicBrainz enrichment worker (finishes current match first)"""
|
||||
try:
|
||||
if mb_worker is None:
|
||||
return jsonify({'error': 'MusicBrainz worker not initialized'}), 400
|
||||
|
||||
mb_worker.pause()
|
||||
config_manager.set('musicbrainz_enrichment_paused', True)
|
||||
logger.info("MusicBrainz worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing MusicBrainz worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/musicbrainz/resume', methods=['POST'])
|
||||
def musicbrainz_resume():
|
||||
"""Resume MusicBrainz enrichment worker"""
|
||||
try:
|
||||
if mb_worker is None:
|
||||
return jsonify({'error': 'MusicBrainz worker not initialized'}), 400
|
||||
|
||||
mb_worker.resume()
|
||||
config_manager.set('musicbrainz_enrichment_paused', False)
|
||||
logger.info("MusicBrainz worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming MusicBrainz worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# MusicBrainz status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint registered in core/enrichment/api.py
|
||||
# under /api/enrichment/musicbrainz/{status,pause,resume}.
|
||||
|
||||
# ================================================================================================
|
||||
# END MUSICBRAINZ INTEGRATION
|
||||
|
|
@ -32325,57 +32277,8 @@ except Exception as e:
|
|||
logger.error(f"AudioDB worker initialization failed: {e}")
|
||||
audiodb_worker = None
|
||||
|
||||
# --- AudioDB API Endpoints ---
|
||||
|
||||
@app.route('/api/audiodb/status', methods=['GET'])
|
||||
def audiodb_status():
|
||||
"""Get AudioDB enrichment status for UI polling"""
|
||||
try:
|
||||
if audiodb_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = audiodb_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting AudioDB status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/audiodb/pause', methods=['POST'])
|
||||
def audiodb_pause():
|
||||
"""Pause AudioDB enrichment worker"""
|
||||
try:
|
||||
if audiodb_worker is None:
|
||||
return jsonify({'error': 'AudioDB worker not initialized'}), 400
|
||||
|
||||
audiodb_worker.pause()
|
||||
config_manager.set('audiodb_enrichment_paused', True)
|
||||
logger.info("AudioDB worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing AudioDB worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/audiodb/resume', methods=['POST'])
|
||||
def audiodb_resume():
|
||||
"""Resume AudioDB enrichment worker"""
|
||||
try:
|
||||
if audiodb_worker is None:
|
||||
return jsonify({'error': 'AudioDB worker not initialized'}), 400
|
||||
|
||||
audiodb_worker.resume()
|
||||
config_manager.set('audiodb_enrichment_paused', False)
|
||||
logger.info("AudioDB worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming AudioDB worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# AudioDB status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/audiodb/{status,pause,resume}.
|
||||
|
||||
# ================================================================================================
|
||||
# END AUDIODB INTEGRATION
|
||||
|
|
@ -32398,47 +32301,8 @@ except Exception as e:
|
|||
logger.error(f"Discogs worker initialization failed: {e}")
|
||||
discogs_worker = None
|
||||
|
||||
# --- Discogs API Endpoints ---
|
||||
|
||||
@app.route('/api/discogs/status', methods=['GET'])
|
||||
def discogs_status():
|
||||
"""Get Discogs enrichment status for UI polling"""
|
||||
try:
|
||||
if discogs_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False, 'running': False, 'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
}), 200
|
||||
return jsonify(discogs_worker.get_stats()), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/discogs/pause', methods=['POST'])
|
||||
def discogs_pause():
|
||||
"""Pause Discogs enrichment worker"""
|
||||
try:
|
||||
if discogs_worker is None:
|
||||
return jsonify({'error': 'Discogs worker not initialized'}), 400
|
||||
discogs_worker.pause()
|
||||
config_manager.set('discogs_enrichment_paused', True)
|
||||
logger.info("Discogs worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/discogs/resume', methods=['POST'])
|
||||
def discogs_resume():
|
||||
"""Resume Discogs enrichment worker"""
|
||||
try:
|
||||
if discogs_worker is None:
|
||||
return jsonify({'error': 'Discogs worker not initialized'}), 400
|
||||
discogs_worker.resume()
|
||||
config_manager.set('discogs_enrichment_paused', False)
|
||||
logger.info("Discogs worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Discogs status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/discogs/{status,pause,resume}.
|
||||
|
||||
# ================================================================================================
|
||||
# DEEZER ENRICHMENT INTEGRATION
|
||||
|
|
@ -32460,57 +32324,8 @@ except Exception as e:
|
|||
logger.error(f"Deezer worker initialization failed: {e}")
|
||||
deezer_worker = None
|
||||
|
||||
# --- Deezer API Endpoints ---
|
||||
|
||||
@app.route('/api/deezer/status', methods=['GET'])
|
||||
def deezer_status():
|
||||
"""Get Deezer enrichment status for UI polling"""
|
||||
try:
|
||||
if deezer_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = deezer_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Deezer status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/deezer/pause', methods=['POST'])
|
||||
def deezer_pause():
|
||||
"""Pause Deezer enrichment worker"""
|
||||
try:
|
||||
if deezer_worker is None:
|
||||
return jsonify({'error': 'Deezer worker not initialized'}), 400
|
||||
|
||||
deezer_worker.pause()
|
||||
config_manager.set('deezer_enrichment_paused', True)
|
||||
logger.info("Deezer worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Deezer worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/deezer/resume', methods=['POST'])
|
||||
def deezer_resume():
|
||||
"""Resume Deezer enrichment worker"""
|
||||
try:
|
||||
if deezer_worker is None:
|
||||
return jsonify({'error': 'Deezer worker not initialized'}), 400
|
||||
|
||||
deezer_worker.resume()
|
||||
config_manager.set('deezer_enrichment_paused', False)
|
||||
logger.info("Deezer worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Deezer worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Deezer status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/deezer/{status,pause,resume}.
|
||||
|
||||
# ================================================================================================
|
||||
# END DEEZER INTEGRATION
|
||||
|
|
@ -32569,66 +32384,10 @@ def get_rate_monitor_history(service_key):
|
|||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
# --- Spotify API Endpoints ---
|
||||
|
||||
@app.route('/api/spotify-enrichment/status', methods=['GET'])
|
||||
def spotify_enrichment_status():
|
||||
"""Get Spotify enrichment status for UI polling"""
|
||||
try:
|
||||
if spotify_enrichment_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = spotify_enrichment_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Spotify enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/spotify-enrichment/pause', methods=['POST'])
|
||||
def spotify_enrichment_pause():
|
||||
"""Pause Spotify enrichment worker"""
|
||||
try:
|
||||
if spotify_enrichment_worker is None:
|
||||
return jsonify({'error': 'Spotify enrichment worker not initialized'}), 400
|
||||
|
||||
spotify_enrichment_worker.pause()
|
||||
config_manager.set('spotify_enrichment_paused', True)
|
||||
# Drop any auto-pause marker so the post-download resume loop won't
|
||||
# override this explicit user pause.
|
||||
_download_auto_paused.discard('spotify-enrichment')
|
||||
logger.info("Spotify enrichment worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Spotify enrichment worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/spotify-enrichment/resume', methods=['POST'])
|
||||
def spotify_enrichment_resume():
|
||||
"""Resume Spotify enrichment worker"""
|
||||
try:
|
||||
if spotify_enrichment_worker is None:
|
||||
return jsonify({'error': 'Spotify enrichment worker not initialized'}), 400
|
||||
|
||||
# Block resume while Spotify is rate limited
|
||||
if _spotify_rate_limited():
|
||||
return jsonify({'error': 'Cannot resume while Spotify is rate limited', 'rate_limited': True}), 429
|
||||
|
||||
spotify_enrichment_worker.resume()
|
||||
config_manager.set('spotify_enrichment_paused', False)
|
||||
_download_auto_paused.discard('spotify-enrichment')
|
||||
_download_yield_override.add('spotify-enrichment') # User override — don't re-pause during this download session
|
||||
logger.info("Spotify enrichment worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Spotify enrichment worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Spotify status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/spotify/{status,pause,resume}.
|
||||
# The rate-limit guard, auto-pause token cleanup, and yield-override behavior
|
||||
# are encoded on the EnrichmentService descriptor (see core/enrichment/services.py).
|
||||
|
||||
# ================================================================================================
|
||||
# END SPOTIFY ENRICHMENT INTEGRATION
|
||||
|
|
@ -32655,57 +32414,8 @@ except Exception as e:
|
|||
logger.error(f"iTunes enrichment worker initialization failed: {e}")
|
||||
itunes_enrichment_worker = None
|
||||
|
||||
# --- iTunes API Endpoints ---
|
||||
|
||||
@app.route('/api/itunes-enrichment/status', methods=['GET'])
|
||||
def itunes_enrichment_status():
|
||||
"""Get iTunes enrichment status for UI polling"""
|
||||
try:
|
||||
if itunes_enrichment_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = itunes_enrichment_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting iTunes enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/itunes-enrichment/pause', methods=['POST'])
|
||||
def itunes_enrichment_pause():
|
||||
"""Pause iTunes enrichment worker"""
|
||||
try:
|
||||
if itunes_enrichment_worker is None:
|
||||
return jsonify({'error': 'iTunes enrichment worker not initialized'}), 400
|
||||
|
||||
itunes_enrichment_worker.pause()
|
||||
config_manager.set('itunes_enrichment_paused', True)
|
||||
logger.info("iTunes enrichment worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing iTunes enrichment worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/itunes-enrichment/resume', methods=['POST'])
|
||||
def itunes_enrichment_resume():
|
||||
"""Resume iTunes enrichment worker"""
|
||||
try:
|
||||
if itunes_enrichment_worker is None:
|
||||
return jsonify({'error': 'iTunes enrichment worker not initialized'}), 400
|
||||
|
||||
itunes_enrichment_worker.resume()
|
||||
config_manager.set('itunes_enrichment_paused', False)
|
||||
logger.info("iTunes enrichment worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming iTunes enrichment worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# iTunes status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/itunes/{status,pause,resume}.
|
||||
|
||||
# ================================================================================================
|
||||
# END ITUNES ENRICHMENT INTEGRATION
|
||||
|
|
@ -32731,62 +32441,10 @@ except Exception as e:
|
|||
logger.error(f"Last.fm worker initialization failed: {e}")
|
||||
lastfm_worker = None
|
||||
|
||||
# --- Last.fm API Endpoints ---
|
||||
|
||||
@app.route('/api/lastfm-enrichment/status', methods=['GET'])
|
||||
def lastfm_enrichment_status():
|
||||
"""Get Last.fm enrichment status for UI polling"""
|
||||
try:
|
||||
if lastfm_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = lastfm_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Last.fm enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/lastfm-enrichment/pause', methods=['POST'])
|
||||
def lastfm_enrichment_pause():
|
||||
"""Pause Last.fm enrichment worker"""
|
||||
try:
|
||||
if lastfm_worker is None:
|
||||
return jsonify({'error': 'Last.fm worker not initialized'}), 400
|
||||
|
||||
lastfm_worker.pause()
|
||||
config_manager.set('lastfm_enrichment_paused', True)
|
||||
# Drop any auto-pause marker so the post-download resume loop won't
|
||||
# override this explicit user pause.
|
||||
_download_auto_paused.discard('lastfm-enrichment')
|
||||
logger.info("Last.fm worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Last.fm worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/lastfm-enrichment/resume', methods=['POST'])
|
||||
def lastfm_enrichment_resume():
|
||||
"""Resume Last.fm enrichment worker"""
|
||||
try:
|
||||
if lastfm_worker is None:
|
||||
return jsonify({'error': 'Last.fm worker not initialized'}), 400
|
||||
|
||||
lastfm_worker.resume()
|
||||
config_manager.set('lastfm_enrichment_paused', False)
|
||||
_download_auto_paused.discard('lastfm-enrichment')
|
||||
_download_yield_override.add('lastfm-enrichment') # User override — don't re-pause during this download session
|
||||
logger.info("Last.fm worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Last.fm worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Last.fm status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/lastfm/{status,pause,resume}.
|
||||
# The auto-pause token cleanup + yield-override behavior is encoded on the
|
||||
# EnrichmentService descriptor (see core/enrichment/services.py).
|
||||
|
||||
@app.route('/api/artist/<artist_id>/lastfm-top-tracks', methods=['GET'])
|
||||
def get_artist_lastfm_top_tracks(artist_id):
|
||||
|
|
@ -32879,60 +32537,10 @@ except Exception as e:
|
|||
|
||||
# --- Genius API Endpoints ---
|
||||
|
||||
@app.route('/api/genius-enrichment/status', methods=['GET'])
|
||||
def genius_enrichment_status():
|
||||
"""Get Genius enrichment status for UI polling"""
|
||||
try:
|
||||
if genius_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = genius_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Genius enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/genius-enrichment/pause', methods=['POST'])
|
||||
def genius_enrichment_pause():
|
||||
"""Pause Genius enrichment worker"""
|
||||
try:
|
||||
if genius_worker is None:
|
||||
return jsonify({'error': 'Genius worker not initialized'}), 400
|
||||
|
||||
genius_worker.pause()
|
||||
config_manager.set('genius_enrichment_paused', True)
|
||||
# Drop any auto-pause marker so the post-download resume loop won't
|
||||
# override this explicit user pause.
|
||||
_download_auto_paused.discard('genius-enrichment')
|
||||
logger.info("Genius worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Genius worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/genius-enrichment/resume', methods=['POST'])
|
||||
def genius_enrichment_resume():
|
||||
"""Resume Genius enrichment worker"""
|
||||
try:
|
||||
if genius_worker is None:
|
||||
return jsonify({'error': 'Genius worker not initialized'}), 400
|
||||
|
||||
genius_worker.resume()
|
||||
config_manager.set('genius_enrichment_paused', False)
|
||||
_download_auto_paused.discard('genius-enrichment')
|
||||
_download_yield_override.add('genius-enrichment') # User override — don't re-pause during this download session
|
||||
logger.info("Genius worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Genius worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Genius status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/genius/{status,pause,resume}.
|
||||
# The auto-pause token cleanup + yield-override behavior is encoded on the
|
||||
# EnrichmentService descriptor (see core/enrichment/services.py).
|
||||
|
||||
# ================================================================================================
|
||||
# END GENIUS ENRICHMENT INTEGRATION
|
||||
|
|
@ -32957,58 +32565,10 @@ except Exception as e:
|
|||
logger.error(f"Tidal worker initialization failed: {e}")
|
||||
tidal_enrichment_worker = None
|
||||
|
||||
# --- Tidal Enrichment API Endpoints ---
|
||||
|
||||
@app.route('/api/tidal-enrichment/status', methods=['GET'])
|
||||
def tidal_enrichment_status():
|
||||
"""Get Tidal enrichment status for UI polling"""
|
||||
try:
|
||||
if tidal_enrichment_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'authenticated': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = tidal_enrichment_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Tidal enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/tidal-enrichment/pause', methods=['POST'])
|
||||
def tidal_enrichment_pause():
|
||||
"""Pause Tidal enrichment worker"""
|
||||
try:
|
||||
if tidal_enrichment_worker is None:
|
||||
return jsonify({'error': 'Tidal worker not initialized'}), 400
|
||||
|
||||
tidal_enrichment_worker.pause()
|
||||
config_manager.set('tidal_enrichment_paused', True)
|
||||
logger.info("Tidal worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Tidal worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/tidal-enrichment/resume', methods=['POST'])
|
||||
def tidal_enrichment_resume():
|
||||
"""Resume Tidal enrichment worker"""
|
||||
try:
|
||||
if tidal_enrichment_worker is None:
|
||||
return jsonify({'error': 'Tidal worker not initialized'}), 400
|
||||
|
||||
tidal_enrichment_worker.resume()
|
||||
config_manager.set('tidal_enrichment_paused', False)
|
||||
logger.info("Tidal worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Tidal worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Tidal status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/tidal/{status,pause,resume}.
|
||||
# The 'authenticated': False fallback field is encoded on the
|
||||
# EnrichmentService descriptor (see core/enrichment/services.py).
|
||||
|
||||
# ================================================================================================
|
||||
# QOBUZ ENRICHMENT WORKER
|
||||
|
|
@ -33043,58 +32603,10 @@ _init_service_search(
|
|||
audiodb_worker_obj=audiodb_worker,
|
||||
)
|
||||
|
||||
# --- Qobuz Enrichment API Endpoints ---
|
||||
|
||||
@app.route('/api/qobuz-enrichment/status', methods=['GET'])
|
||||
def qobuz_enrichment_status():
|
||||
"""Get Qobuz enrichment status for UI polling"""
|
||||
try:
|
||||
if qobuz_enrichment_worker is None:
|
||||
return jsonify({
|
||||
'enabled': False,
|
||||
'running': False,
|
||||
'paused': False,
|
||||
'authenticated': False,
|
||||
'current_item': None,
|
||||
'stats': {'matched': 0, 'not_found': 0, 'pending': 0, 'errors': 0},
|
||||
'progress': {}
|
||||
}), 200
|
||||
|
||||
status = qobuz_enrichment_worker.get_stats()
|
||||
return jsonify(status), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting Qobuz enrichment status: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/qobuz-enrichment/pause', methods=['POST'])
|
||||
def qobuz_enrichment_pause():
|
||||
"""Pause Qobuz enrichment worker"""
|
||||
try:
|
||||
if qobuz_enrichment_worker is None:
|
||||
return jsonify({'error': 'Qobuz worker not initialized'}), 400
|
||||
|
||||
qobuz_enrichment_worker.pause()
|
||||
config_manager.set('qobuz_enrichment_paused', True)
|
||||
logger.info("Qobuz worker paused via UI")
|
||||
return jsonify({'status': 'paused'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error pausing Qobuz worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/qobuz-enrichment/resume', methods=['POST'])
|
||||
def qobuz_enrichment_resume():
|
||||
"""Resume Qobuz enrichment worker"""
|
||||
try:
|
||||
if qobuz_enrichment_worker is None:
|
||||
return jsonify({'error': 'Qobuz worker not initialized'}), 400
|
||||
|
||||
qobuz_enrichment_worker.resume()
|
||||
config_manager.set('qobuz_enrichment_paused', False)
|
||||
logger.info("Qobuz worker resumed via UI")
|
||||
return jsonify({'status': 'running'}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error resuming Qobuz worker: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
# Qobuz status / pause / resume routes are now served by the
|
||||
# generic enrichment blueprint at /api/enrichment/qobuz/{status,pause,resume}.
|
||||
# The 'authenticated': False fallback field is encoded on the
|
||||
# EnrichmentService descriptor (see core/enrichment/services.py).
|
||||
|
||||
# ================================================================================================
|
||||
# END TIDAL/QOBUZ ENRICHMENT INTEGRATION
|
||||
|
|
|
|||
|
|
@ -3445,7 +3445,8 @@ const WHATS_NEW = {
|
|||
// --- post-2.4.1 dev work — entries hidden by _getLatestWhatsNewVersion until the build version bumps ---
|
||||
{ date: 'Unreleased — 2.4.2 dev cycle' },
|
||||
{ title: 'Sidebar Library Button Shows Artist Breadcrumb', desc: 'when you open an artist detail page (from library, search, or the global search popover), the sidebar Library button now lights up and rewrites its label to "Library / Artist Name" — long names truncate with an ellipsis and the full name shows on hover. revertes to plain "Library" when you leave. purely visual, no functionality change.', page: 'library' },
|
||||
{ title: 'Enrichment Bubble Routes Consolidated', desc: 'internal — every dashboard enrichment bubble (musicbrainz, spotify, itunes, deezer, discogs, audiodb, lastfm, genius, tidal, qobuz) used to hit its own per-service status / pause / resume route in web_server.py. unified them under a single registry-driven endpoint set: /api/enrichment/<service>/<action>. spotify\'s rate-limit guard, lastfm/genius yield-override behavior, and tidal/qobuz extra status fields are encoded as data on the registry. 27 new tests cover the registry behavior. old per-service routes still respond as fallback during the soak — they get deleted in a follow-up patch.' },
|
||||
{ title: 'Enrichment Bubble Routes Consolidated', desc: 'internal — every dashboard enrichment bubble (musicbrainz, spotify, itunes, deezer, discogs, audiodb, lastfm, genius, tidal, qobuz) used to hit its own per-service status / pause / resume route in web_server.py. unified them under a single registry-driven endpoint set: /api/enrichment/<service>/<action>. spotify\'s rate-limit guard, lastfm/genius yield-override behavior, and tidal/qobuz extra status fields are encoded as data on the registry. 27 new tests cover the registry behavior.' },
|
||||
{ title: 'Drop Old Per-Service Enrichment Routes', desc: 'internal — followup to the registry consolidation. now that the dashboard has cut over to /api/enrichment/<service>/<action>, deleted the 30 hand-rolled per-service routes from web_server.py (musicbrainz/audiodb/discogs/deezer/spotify/itunes/lastfm/genius/tidal/qobuz status+pause+resume). ~510 lines gone from the monolith, no behavior change.' },
|
||||
],
|
||||
'2.4.1': [
|
||||
// --- May 1, 2026 — patch release ---
|
||||
|
|
|
|||
Loading…
Reference in a new issue