Fix Deezer download integration: add deezer_dl to all streaming source checks
- Added deezer_dl to 7 hardcoded streaming source username tuples in web_server - Streaming sources now bypass Soulseek filename-matching engine in get_valid_candidates (API search results are already properly matched, no need for P2P filename scoring) - Fixes download progress tracking, completion detection, and candidate filtering for Deezer
This commit is contained in:
parent
9c60040a9b
commit
7eed88c72c
1 changed files with 92 additions and 11 deletions
103
web_server.py
103
web_server.py
|
|
@ -1876,7 +1876,7 @@ def get_cached_transfer_data():
|
|||
all_downloads = run_async(soulseek_client.get_all_downloads())
|
||||
for download in all_downloads:
|
||||
# Only add streaming source downloads (Soulseek ones are already in the lookup)
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi'):
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl'):
|
||||
key = _make_context_key(download.username, download.filename)
|
||||
# Convert DownloadStatus to transfer dict format
|
||||
live_transfers_lookup[key] = {
|
||||
|
|
@ -2203,7 +2203,7 @@ class WebUIDownloadMonitor:
|
|||
all_downloads = run_async(soulseek_client.get_all_downloads())
|
||||
for download in all_downloads:
|
||||
# Only add streaming source downloads (Soulseek ones are already in the lookup from slskd API)
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi'):
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl'):
|
||||
key = _make_context_key(download.username, download.filename)
|
||||
# Convert DownloadStatus to transfer dict format for monitor compatibility
|
||||
live_transfers[key] = {
|
||||
|
|
@ -7188,7 +7188,7 @@ def stream_enhanced_search_track():
|
|||
|
||||
_hybrid_order = config_manager.get('download_source.hybrid_order', [])
|
||||
_hybrid_first = _hybrid_order[0] if _hybrid_order else config_manager.get('download_source.hybrid_primary', 'soulseek')
|
||||
if download_mode in ('youtube', 'tidal', 'qobuz', 'hifi') or (download_mode == 'hybrid' and _hybrid_first in ('youtube', 'tidal', 'qobuz', 'hifi')):
|
||||
if download_mode in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl') or (download_mode == 'hybrid' and _hybrid_first in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl')):
|
||||
# YouTube/Tidal mode: Include artist for better context
|
||||
# Primary query: Artist + Track
|
||||
if artist_name and track_name:
|
||||
|
|
@ -7365,7 +7365,7 @@ def start_download():
|
|||
if download_id:
|
||||
# Register download for post-processing (simple transfer to /Transfer)
|
||||
context_key = _make_context_key(username, filename)
|
||||
is_streaming_source = username in ('youtube', 'tidal', 'qobuz', 'hifi')
|
||||
is_streaming_source = username in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl')
|
||||
with matched_context_lock:
|
||||
matched_downloads_context[context_key] = {
|
||||
'search_result': {
|
||||
|
|
@ -7743,7 +7743,7 @@ def get_download_status():
|
|||
all_streaming_downloads = run_async(soulseek_client.get_all_downloads())
|
||||
|
||||
for download in all_streaming_downloads:
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi'):
|
||||
if download.username in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl'):
|
||||
source_label = download.username.title()
|
||||
# Convert DownloadStatus to transfer format that frontend expects
|
||||
streaming_transfer = {
|
||||
|
|
@ -21956,16 +21956,29 @@ def get_valid_candidates(results, spotify_track, query):
|
|||
Soulseek search results against a Spotify track to find the best, most
|
||||
accurate download candidates.
|
||||
"""
|
||||
if not results:
|
||||
if not results:
|
||||
return []
|
||||
# Uses the existing, powerful matching engine for scoring
|
||||
|
||||
# Streaming sources (YouTube, Tidal, Qobuz, HiFi, Deezer) return structured API results
|
||||
# with proper artist/title metadata — bypass Soulseek filename-parsing matching engine
|
||||
# and trust the search API's results directly
|
||||
_streaming_sources = ("youtube", "tidal", "qobuz", "hifi", "deezer_dl")
|
||||
if results[0].username in _streaming_sources:
|
||||
source_label = results[0].username.replace('_dl', '').title()
|
||||
print(f"🎵 [{source_label}] Streaming source — using API results directly ({len(results)} candidates)")
|
||||
for r in results:
|
||||
r.confidence = 1.0
|
||||
r.version_type = 'original'
|
||||
return results
|
||||
|
||||
# Uses the existing, powerful matching engine for scoring (Soulseek P2P results)
|
||||
_max_q = config_manager.get('soulseek.max_peer_queue', 0) or 0
|
||||
initial_candidates = matching_engine.find_best_slskd_matches_enhanced(spotify_track, results, max_peer_queue=_max_q)
|
||||
if not initial_candidates:
|
||||
return []
|
||||
|
||||
# Skip quality filtering for YouTube/Tidal/Qobuz results (quality is fixed by source, not user-selectable per-result)
|
||||
is_streaming_source = initial_candidates[0].username in ("youtube", "tidal", "qobuz", "hifi") if initial_candidates else False
|
||||
# Skip quality filtering for streaming source results that somehow got here
|
||||
is_streaming_source = initial_candidates[0].username in _streaming_sources if initial_candidates else False
|
||||
|
||||
if is_streaming_source:
|
||||
source_label = initial_candidates[0].username.title()
|
||||
|
|
@ -24472,7 +24485,7 @@ def _try_source_reuse(task_id, batch_id, track):
|
|||
if not source_tracks or not last_source:
|
||||
_sr.info(f"Skipped — no source_tracks or no last_source")
|
||||
return False
|
||||
if last_source.get('username') in ('youtube', 'tidal', 'qobuz', 'hifi'):
|
||||
if last_source.get('username') in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl'):
|
||||
_sr.info(f"Skipped — {last_source.get('username')} source (no folder-based reuse)")
|
||||
return False
|
||||
|
||||
|
|
@ -24574,7 +24587,7 @@ def _store_batch_source(batch_id, username, filename):
|
|||
"""Browse the successful download's folder and store results on the batch for reuse."""
|
||||
_sr = source_reuse_logger
|
||||
_sr.info(f"_store_batch_source called: batch={batch_id}, user={username}, file={filename}")
|
||||
if not batch_id or username in ('youtube', 'tidal', 'qobuz', 'hifi'):
|
||||
if not batch_id or username in ('youtube', 'tidal', 'qobuz', 'hifi', 'deezer_dl'):
|
||||
_sr.info(f"Skipped — no batch_id or streaming source ({username})")
|
||||
return
|
||||
|
||||
|
|
@ -26917,6 +26930,74 @@ def deezer_download_test():
|
|||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
@app.route('/api/deezer-download/test-search', methods=['GET'])
|
||||
def deezer_download_test_search():
|
||||
"""Test Deezer download search (temporary testing endpoint)."""
|
||||
try:
|
||||
query = request.args.get('q', '')
|
||||
if not query:
|
||||
return jsonify({'success': False, 'error': 'No query provided'})
|
||||
|
||||
arl = config_manager.get('deezer_download.arl', '')
|
||||
if not arl:
|
||||
return jsonify({'success': False, 'error': 'No ARL configured'})
|
||||
|
||||
from core.deezer_download_client import DeezerDownloadClient
|
||||
client = DeezerDownloadClient()
|
||||
if not client.is_authenticated():
|
||||
client.reconnect(arl)
|
||||
if not client.is_authenticated():
|
||||
return jsonify({'success': False, 'error': 'Authentication failed'})
|
||||
|
||||
tracks, albums = client._search_sync(query)
|
||||
results = []
|
||||
for t in tracks[:10]:
|
||||
results.append({
|
||||
'title': t.title,
|
||||
'artist': t.artist,
|
||||
'album': t.album,
|
||||
'quality': t.quality,
|
||||
'bitrate': t.bitrate,
|
||||
'duration_ms': t.duration,
|
||||
'size': t.size,
|
||||
'filename': t.filename,
|
||||
})
|
||||
return jsonify({'success': True, 'count': len(tracks), 'results': results})
|
||||
except Exception as e:
|
||||
logger.error(f"Deezer search test failed: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
@app.route('/api/deezer-download/test-download', methods=['POST'])
|
||||
def deezer_download_test_download():
|
||||
"""Test Deezer download of a single track (temporary testing endpoint)."""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
filename = data.get('filename', '')
|
||||
if not filename:
|
||||
return jsonify({'success': False, 'error': 'No filename provided (use track_id||display_name format)'})
|
||||
|
||||
arl = config_manager.get('deezer_download.arl', '')
|
||||
if not arl:
|
||||
return jsonify({'success': False, 'error': 'No ARL configured'})
|
||||
|
||||
from core.deezer_download_client import DeezerDownloadClient
|
||||
client = DeezerDownloadClient()
|
||||
if not client.is_authenticated():
|
||||
client.reconnect(arl)
|
||||
if not client.is_authenticated():
|
||||
return jsonify({'success': False, 'error': 'Authentication failed'})
|
||||
|
||||
download_id = run_async(client.download('deezer_dl', filename))
|
||||
if not download_id:
|
||||
return jsonify({'success': False, 'error': 'Download failed to start'})
|
||||
|
||||
return jsonify({'success': True, 'download_id': download_id, 'message': 'Download started — check logs'})
|
||||
except Exception as e:
|
||||
logger.error(f"Deezer download test failed: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)})
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# TIDAL DOWNLOAD AUTH ENDPOINTS
|
||||
# ===================================================================
|
||||
|
|
|
|||
Loading…
Reference in a new issue