i dont have time for this
This commit is contained in:
@@ -6,7 +6,6 @@ from deezspot.deezloader import DeeLogin
|
||||
from pathlib import Path
|
||||
|
||||
def download_album(
|
||||
service,
|
||||
url,
|
||||
main,
|
||||
fallback=None,
|
||||
@@ -22,8 +21,24 @@ def download_album(
|
||||
progress_callback=None
|
||||
):
|
||||
try:
|
||||
# DEBUG: Print parameters
|
||||
print(f"DEBUG: album.py received - service={service}, main={main}, fallback={fallback}")
|
||||
# Detect URL source (Spotify or Deezer) from URL
|
||||
is_spotify_url = 'open.spotify.com' in url.lower()
|
||||
is_deezer_url = 'deezer.com' in url.lower()
|
||||
|
||||
# Determine service exclusively from URL
|
||||
if is_spotify_url:
|
||||
service = 'spotify'
|
||||
elif is_deezer_url:
|
||||
service = 'deezer'
|
||||
else:
|
||||
# If URL can't be detected, raise an error
|
||||
error_msg = "Invalid URL: Must be from open.spotify.com or deezer.com"
|
||||
print(f"ERROR: {error_msg}")
|
||||
raise ValueError(error_msg)
|
||||
|
||||
print(f"DEBUG: album.py - URL detection: is_spotify_url={is_spotify_url}, is_deezer_url={is_deezer_url}")
|
||||
print(f"DEBUG: album.py - Service determined from URL: {service}")
|
||||
print(f"DEBUG: album.py - Credentials: main={main}, fallback={fallback}")
|
||||
|
||||
# Load Spotify client credentials if available
|
||||
spotify_client_id = None
|
||||
@@ -49,6 +64,8 @@ def download_album(
|
||||
except Exception as e:
|
||||
print(f"Error loading Spotify search credentials: {e}")
|
||||
|
||||
# For Spotify URLs: check if fallback is enabled, if so use the fallback logic,
|
||||
# otherwise download directly from Spotify
|
||||
if service == 'spotify':
|
||||
if fallback:
|
||||
if quality is None:
|
||||
@@ -186,6 +203,7 @@ def download_album(
|
||||
max_retries=max_retries
|
||||
)
|
||||
print(f"DEBUG: Album download completed successfully using Spotify main")
|
||||
# For Deezer URLs: download directly from Deezer
|
||||
elif service == 'deezer':
|
||||
if quality is None:
|
||||
quality = 'FLAC'
|
||||
|
||||
@@ -87,6 +87,16 @@ def download_artist_albums(url, album_type="album,single,compilation", request_a
|
||||
|
||||
logger.info(f"Fetching artist info for ID: {artist_id}")
|
||||
|
||||
# Detect URL source (only Spotify is supported for artists)
|
||||
is_spotify_url = 'open.spotify.com' in url.lower()
|
||||
is_deezer_url = 'deezer.com' in url.lower()
|
||||
|
||||
# Artist functionality only works with Spotify URLs currently
|
||||
if not is_spotify_url:
|
||||
error_msg = "Invalid URL: Artist functionality only supports open.spotify.com URLs"
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
# Get artist info with albums
|
||||
artist_data = get_spotify_info(artist_id, "artist")
|
||||
|
||||
@@ -152,8 +162,7 @@ def download_artist_albums(url, album_type="album,single,compilation", request_a
|
||||
"name": album_name,
|
||||
"artist": album_artist,
|
||||
"type": "album",
|
||||
"service": "spotify",
|
||||
# Add reference to parent artist request if needed
|
||||
# URL source will be automatically detected in the download functions
|
||||
"parent_artist_url": url,
|
||||
"parent_request_type": "artist"
|
||||
}
|
||||
@@ -162,7 +171,6 @@ def download_artist_albums(url, album_type="album,single,compilation", request_a
|
||||
task_data = {
|
||||
"download_type": "album",
|
||||
"type": "album", # Type for the download task
|
||||
"service": "spotify", # Default to Spotify since we're using Spotify API
|
||||
"url": album_url, # Important: use the album URL, not artist URL
|
||||
"retry_url": album_url, # Use album URL for retry logic, not artist URL
|
||||
"name": album_name,
|
||||
|
||||
@@ -120,9 +120,6 @@ class CeleryDownloadQueueManager:
|
||||
# Extract original request or use empty dict
|
||||
original_request = task.get("orig_request", task.get("original_request", {}))
|
||||
|
||||
# Determine service (spotify or deezer) from config or request
|
||||
service = original_request.get("service", config_params.get("service", "spotify"))
|
||||
|
||||
# Debug retry_url if present
|
||||
if "retry_url" in task:
|
||||
logger.debug(f"Task has retry_url: {task['retry_url']}")
|
||||
@@ -133,21 +130,20 @@ class CeleryDownloadQueueManager:
|
||||
"type": task.get("type", download_type),
|
||||
"name": task.get("name", ""),
|
||||
"artist": task.get("artist", ""),
|
||||
"service": service,
|
||||
"url": task.get("url", ""),
|
||||
|
||||
# Preserve retry_url if present
|
||||
"retry_url": task.get("retry_url", ""),
|
||||
|
||||
# Use config values but allow override from request
|
||||
"main": original_request.get("main",
|
||||
config_params['spotify'] if service == 'spotify' else config_params['deezer']),
|
||||
# Use main account from config
|
||||
"main": original_request.get("main", config_params['deezer']),
|
||||
|
||||
# Set fallback if enabled in config
|
||||
"fallback": original_request.get("fallback",
|
||||
config_params['spotify'] if config_params['fallback'] and service == 'spotify' else None),
|
||||
config_params['spotify'] if config_params['fallback'] else None),
|
||||
|
||||
"quality": original_request.get("quality",
|
||||
config_params['spotifyQuality'] if service == 'spotify' else config_params['deezerQuality']),
|
||||
# Use default quality settings
|
||||
"quality": original_request.get("quality", config_params['deezerQuality']),
|
||||
|
||||
"fall_quality": original_request.get("fall_quality", config_params['spotifyQuality']),
|
||||
|
||||
|
||||
@@ -893,12 +893,11 @@ def download_track(self, **task_data):
|
||||
custom_track_format = task_data.get("custom_track_format", config_params.get("customTrackFormat", "%tracknum%. %music%"))
|
||||
pad_tracks = task_data.get("pad_tracks", config_params.get("tracknum_padding", True))
|
||||
|
||||
# Execute the download
|
||||
# Execute the download - service is now determined from URL
|
||||
download_track_func(
|
||||
service=service,
|
||||
url=url,
|
||||
main=main,
|
||||
fallback=fallback,
|
||||
fallback=fallback if fallback_enabled else None,
|
||||
quality=quality,
|
||||
fall_quality=fall_quality,
|
||||
real_time=real_time,
|
||||
@@ -961,12 +960,11 @@ def download_album(self, **task_data):
|
||||
custom_track_format = task_data.get("custom_track_format", config_params.get("customTrackFormat", "%tracknum%. %music%"))
|
||||
pad_tracks = task_data.get("pad_tracks", config_params.get("tracknum_padding", True))
|
||||
|
||||
# Execute the download
|
||||
# Execute the download - service is now determined from URL
|
||||
download_album_func(
|
||||
service=service,
|
||||
url=url,
|
||||
main=main,
|
||||
fallback=fallback,
|
||||
fallback=fallback if fallback_enabled else None,
|
||||
quality=quality,
|
||||
fall_quality=fall_quality,
|
||||
real_time=real_time,
|
||||
@@ -1034,12 +1032,11 @@ def download_playlist(self, **task_data):
|
||||
retry_delay_increase = task_data.get("retry_delay_increase", config_params.get("retry_delay_increase", 5))
|
||||
max_retries = task_data.get("max_retries", config_params.get("maxRetries", 3))
|
||||
|
||||
# Execute the download
|
||||
# Execute the download - service is now determined from URL
|
||||
download_playlist_func(
|
||||
service=service,
|
||||
url=url,
|
||||
main=main,
|
||||
fallback=fallback,
|
||||
fallback=fallback if fallback_enabled else None,
|
||||
quality=quality,
|
||||
fall_quality=fall_quality,
|
||||
real_time=real_time,
|
||||
|
||||
@@ -6,7 +6,6 @@ from deezspot.deezloader import DeeLogin
|
||||
from pathlib import Path
|
||||
|
||||
def download_playlist(
|
||||
service,
|
||||
url,
|
||||
main,
|
||||
fallback=None,
|
||||
@@ -22,8 +21,24 @@ def download_playlist(
|
||||
progress_callback=None,
|
||||
):
|
||||
try:
|
||||
# DEBUG: Print parameters
|
||||
print(f"DEBUG: playlist.py received - service={service}, main={main}, fallback={fallback}")
|
||||
# Detect URL source (Spotify or Deezer) from URL
|
||||
is_spotify_url = 'open.spotify.com' in url.lower()
|
||||
is_deezer_url = 'deezer.com' in url.lower()
|
||||
|
||||
# Determine service exclusively from URL
|
||||
if is_spotify_url:
|
||||
service = 'spotify'
|
||||
elif is_deezer_url:
|
||||
service = 'deezer'
|
||||
else:
|
||||
# If URL can't be detected, raise an error
|
||||
error_msg = "Invalid URL: Must be from open.spotify.com or deezer.com"
|
||||
print(f"ERROR: {error_msg}")
|
||||
raise ValueError(error_msg)
|
||||
|
||||
print(f"DEBUG: playlist.py - URL detection: is_spotify_url={is_spotify_url}, is_deezer_url={is_deezer_url}")
|
||||
print(f"DEBUG: playlist.py - Service determined from URL: {service}")
|
||||
print(f"DEBUG: playlist.py - Credentials: main={main}, fallback={fallback}")
|
||||
|
||||
# Load Spotify client credentials if available
|
||||
spotify_client_id = None
|
||||
@@ -49,6 +64,8 @@ def download_playlist(
|
||||
except Exception as e:
|
||||
print(f"Error loading Spotify search credentials: {e}")
|
||||
|
||||
# For Spotify URLs: check if fallback is enabled, if so use the fallback logic,
|
||||
# otherwise download directly from Spotify
|
||||
if service == 'spotify':
|
||||
if fallback:
|
||||
if quality is None:
|
||||
@@ -181,6 +198,7 @@ def download_playlist(
|
||||
max_retries=max_retries
|
||||
)
|
||||
print(f"DEBUG: Playlist download completed successfully using Spotify main")
|
||||
# For Deezer URLs: download directly from Deezer
|
||||
elif service == 'deezer':
|
||||
if quality is None:
|
||||
quality = 'FLAC'
|
||||
|
||||
@@ -6,7 +6,6 @@ from deezspot.deezloader import DeeLogin
|
||||
from pathlib import Path
|
||||
|
||||
def download_track(
|
||||
service,
|
||||
url,
|
||||
main,
|
||||
fallback=None,
|
||||
@@ -22,8 +21,24 @@ def download_track(
|
||||
progress_callback=None
|
||||
):
|
||||
try:
|
||||
# DEBUG: Print parameters
|
||||
print(f"DEBUG: track.py received - service={service}, main={main}, fallback={fallback}")
|
||||
# Detect URL source (Spotify or Deezer) from URL
|
||||
is_spotify_url = 'open.spotify.com' in url.lower()
|
||||
is_deezer_url = 'deezer.com' in url.lower()
|
||||
|
||||
# Determine service exclusively from URL
|
||||
if is_spotify_url:
|
||||
service = 'spotify'
|
||||
elif is_deezer_url:
|
||||
service = 'deezer'
|
||||
else:
|
||||
# If URL can't be detected, raise an error
|
||||
error_msg = "Invalid URL: Must be from open.spotify.com or deezer.com"
|
||||
print(f"ERROR: {error_msg}")
|
||||
raise ValueError(error_msg)
|
||||
|
||||
print(f"DEBUG: track.py - URL detection: is_spotify_url={is_spotify_url}, is_deezer_url={is_deezer_url}")
|
||||
print(f"DEBUG: track.py - Service determined from URL: {service}")
|
||||
print(f"DEBUG: track.py - Credentials: main={main}, fallback={fallback}")
|
||||
|
||||
# Load Spotify client credentials if available
|
||||
spotify_client_id = None
|
||||
@@ -49,6 +64,8 @@ def download_track(
|
||||
except Exception as e:
|
||||
print(f"Error loading Spotify search credentials: {e}")
|
||||
|
||||
# For Spotify URLs: check if fallback is enabled, if so use the fallback logic,
|
||||
# otherwise download directly from Spotify
|
||||
if service == 'spotify':
|
||||
if fallback:
|
||||
if quality is None:
|
||||
@@ -166,6 +183,7 @@ def download_track(
|
||||
retry_delay_increase=retry_delay_increase,
|
||||
max_retries=max_retries
|
||||
)
|
||||
# For Deezer URLs: download directly from Deezer
|
||||
elif service == 'deezer':
|
||||
if quality is None:
|
||||
quality = 'FLAC'
|
||||
|
||||
@@ -551,6 +551,9 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
<div class="queue-item-status">
|
||||
<div class="log" id="log-${queueId}-${prgFile}">${defaultMessage}</div>
|
||||
|
||||
<!-- Error details container (hidden by default) -->
|
||||
<div class="error-details" id="error-details-${queueId}-${prgFile}" style="display: none;"></div>
|
||||
|
||||
<div class="progress-container">
|
||||
<!-- Track-level progress bar for single track or current track in multi-track items -->
|
||||
<div class="track-progress-bar-container" id="track-progress-container-${queueId}-${prgFile}">
|
||||
@@ -620,13 +623,80 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
break;
|
||||
case 'error':
|
||||
entry.element.classList.add('error');
|
||||
// Show detailed error information in the error-details container if available
|
||||
if (entry.lastStatus && entry.element) {
|
||||
const errorDetailsContainer = entry.element.querySelector(`#error-details-${entry.uniqueId}-${entry.prgFile}`);
|
||||
if (errorDetailsContainer) {
|
||||
// Format the error details
|
||||
let errorDetailsHTML = '';
|
||||
|
||||
// Add error message
|
||||
errorDetailsHTML += `<div class="error-message">${entry.lastStatus.error || entry.lastStatus.message || 'Unknown error'}</div>`;
|
||||
|
||||
// Add parent information if available
|
||||
if (entry.lastStatus.parent) {
|
||||
const parent = entry.lastStatus.parent;
|
||||
let parentInfo = '';
|
||||
|
||||
if (parent.type === 'album') {
|
||||
parentInfo = `<div class="parent-info">From album: "${parent.title}" by ${parent.artist || 'Unknown artist'}</div>`;
|
||||
} else if (parent.type === 'playlist') {
|
||||
parentInfo = `<div class="parent-info">From playlist: "${parent.name}" by ${parent.owner || 'Unknown creator'}</div>`;
|
||||
}
|
||||
|
||||
if (parentInfo) {
|
||||
errorDetailsHTML += parentInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Add source URL if available
|
||||
if (entry.lastStatus.url) {
|
||||
errorDetailsHTML += `<div class="error-url">Source: <a href="${entry.lastStatus.url}" target="_blank" rel="noopener noreferrer">${entry.lastStatus.url}</a></div>`;
|
||||
}
|
||||
|
||||
// Add retry button if this error can be retried
|
||||
if (entry.lastStatus.can_retry !== false && (!entry.retryCount || entry.retryCount < this.MAX_RETRIES)) {
|
||||
errorDetailsHTML += `<button class="retry-btn" data-queueid="${entry.uniqueId}">Retry Download</button>`;
|
||||
}
|
||||
|
||||
// Display the error details
|
||||
errorDetailsContainer.innerHTML = errorDetailsHTML;
|
||||
errorDetailsContainer.style.display = 'block';
|
||||
|
||||
// Add event listener to retry button if present
|
||||
const retryBtn = errorDetailsContainer.querySelector('.retry-btn');
|
||||
if (retryBtn) {
|
||||
retryBtn.addEventListener('click', (e) => {
|
||||
const queueId = e.target.getAttribute('data-queueid');
|
||||
if (queueId) {
|
||||
const logElement = entry.element.querySelector('.log');
|
||||
this.retryDownload(queueId, logElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'complete':
|
||||
case 'done':
|
||||
entry.element.classList.add('complete');
|
||||
// Hide error details if present
|
||||
if (entry.element) {
|
||||
const errorDetailsContainer = entry.element.querySelector(`#error-details-${entry.uniqueId}-${entry.prgFile}`);
|
||||
if (errorDetailsContainer) {
|
||||
errorDetailsContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'cancelled':
|
||||
entry.element.classList.add('cancelled');
|
||||
// Hide error details if present
|
||||
if (entry.element) {
|
||||
const errorDetailsContainer = entry.element.querySelector(`#error-details-${entry.uniqueId}-${entry.prgFile}`);
|
||||
if (errorDetailsContainer) {
|
||||
errorDetailsContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1081,7 +1151,15 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
return `${trackName}${artist ? ` by ${artist}` : ''} was skipped: ${data.reason || 'Unknown reason'}`;
|
||||
|
||||
case 'error':
|
||||
// Enhanced error message handling using the new format
|
||||
let errorMsg = `Error: ${data.error || data.message || 'Unknown error'}`;
|
||||
|
||||
// Add position information for tracks in collections
|
||||
if (data.current_track && data.total_tracks) {
|
||||
errorMsg = `Error on track ${data.current_track}/${data.total_tracks}: ${data.error || data.message || 'Unknown error'}`;
|
||||
}
|
||||
|
||||
// Add retry information if available
|
||||
if (data.retry_count !== undefined) {
|
||||
errorMsg += ` (Attempt ${data.retry_count}/${this.MAX_RETRIES})`;
|
||||
} else if (data.can_retry !== undefined) {
|
||||
@@ -1091,6 +1169,21 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
errorMsg += ` (Max retries reached)`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add parent information if this is a track with a parent
|
||||
if (data.type === 'track' && data.parent) {
|
||||
if (data.parent.type === 'album') {
|
||||
errorMsg += `\nFrom album: "${data.parent.title}" by ${data.parent.artist || 'Unknown artist'}`;
|
||||
} else if (data.parent.type === 'playlist') {
|
||||
errorMsg += `\nFrom playlist: "${data.parent.name}" by ${data.parent.owner || 'Unknown creator'}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add URL for troubleshooting if available
|
||||
if (data.url) {
|
||||
errorMsg += `\nSource: ${data.url}`;
|
||||
}
|
||||
|
||||
return errorMsg;
|
||||
|
||||
case 'retrying':
|
||||
@@ -1168,8 +1261,30 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
entry.isRetrying = true;
|
||||
logElement.textContent = 'Retrying download...';
|
||||
|
||||
// Determine if we should use parent information for retry
|
||||
let useParent = false;
|
||||
let parentType = null;
|
||||
let parentUrl = null;
|
||||
|
||||
// Check if we have parent information in the lastStatus
|
||||
if (entry.lastStatus && entry.lastStatus.parent) {
|
||||
const parent = entry.lastStatus.parent;
|
||||
if (parent.type && parent.url) {
|
||||
useParent = true;
|
||||
parentType = parent.type;
|
||||
parentUrl = parent.url;
|
||||
console.log(`Using parent info for retry: ${parentType} with URL: ${parentUrl}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Find a retry URL from various possible sources
|
||||
const getRetryUrl = () => {
|
||||
// If using parent, return parent URL
|
||||
if (useParent && parentUrl) {
|
||||
return parentUrl;
|
||||
}
|
||||
|
||||
// Otherwise use the standard fallback options
|
||||
if (entry.requestUrl) return entry.requestUrl;
|
||||
|
||||
// If we have lastStatus with original_request, check there
|
||||
@@ -1200,10 +1315,12 @@ createQueueItem(item, type, prgFile, queueId) {
|
||||
// Close any existing polling interval
|
||||
this.clearPollingInterval(queueId);
|
||||
|
||||
console.log(`Retrying download for ${entry.type} with URL: ${retryUrl}`);
|
||||
// Determine which type to use for the API endpoint
|
||||
const apiType = useParent ? parentType : entry.type;
|
||||
console.log(`Retrying download using type: ${apiType} with URL: ${retryUrl}`);
|
||||
|
||||
// Build the API URL based on the entry's type
|
||||
const apiUrl = `/api/${entry.type}/download?url=${encodeURIComponent(retryUrl)}`;
|
||||
// Build the API URL based on the determined type
|
||||
const apiUrl = `/api/${apiType}/download?url=${encodeURIComponent(retryUrl)}`;
|
||||
|
||||
// Add name and artist if available for better progress display
|
||||
let fullRetryUrl = apiUrl;
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<option value="%music%">%music% - Track title</option>
|
||||
<option value="%artist%">%artist% - Track artist</option>
|
||||
<option value="%album%">%album% - Album name</option>
|
||||
<option value="%album_artist%">%album_artist% - Album artist</option>
|
||||
<option value="%ar_album%">%ar_album% - Album artist</option>
|
||||
<option value="%tracknum%">%tracknum% - Track number</option>
|
||||
<option value="%year%">%year% - Year of release</option>
|
||||
</optgroup>
|
||||
@@ -169,7 +169,7 @@
|
||||
<option value="%music%">%music% - Track title</option>
|
||||
<option value="%artist%">%artist% - Track artist</option>
|
||||
<option value="%album%">%album% - Album name</option>
|
||||
<option value="%album_artist%">%album_artist% - Album artist</option>
|
||||
<option value="%ar_album%">%ar_album% - Album artist</option>
|
||||
<option value="%tracknum%">%tracknum% - Track number</option>
|
||||
<option value="%year%">%year% - Year of release</option>
|
||||
</optgroup>
|
||||
|
||||
Reference in New Issue
Block a user