This commit is contained in:
afkarxyz
2025-05-11 18:31:28 +07:00
parent 60d20cbebe
commit 9b6b43c0a4
2 changed files with 92 additions and 103 deletions
+59 -82
View File
@@ -6,6 +6,7 @@ import requests
import re import re
from packaging import version from packaging import version
import json import json
import asyncio
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit,
@@ -17,7 +18,7 @@ from PyQt6.QtCore import Qt, QThread, pyqtSignal, QUrl, QTimer, QTime, QSettings
from PyQt6.QtGui import QIcon, QTextCursor, QDesktopServices, QPixmap, QBrush from PyQt6.QtGui import QIcon, QTextCursor, QDesktopServices, QPixmap, QBrush
from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from getMetadata import get_filtered_data, parse_uri, SpotifyInvalidUrlException from getMetadata import get_filtered_data, parse_uri, SpotifyInvalidUrlException, get_raw_spotify_data
from getTracks import TrackDownloader from getTracks import TrackDownloader
import SquidWTF import SquidWTF
@@ -88,17 +89,15 @@ class DownloadWorker(QThread):
try: try:
downloader = TrackDownloader(self.use_fallback, self.timeout) downloader = TrackDownloader(self.use_fallback, self.timeout)
def progress_update(current, total): def progress_update_lucida(current, total, current_overall_progress):
if total > 0: if total > 0:
percent = (current / total) * 100 percent = (current / total) * 100
current_mb = current / (1024 * 1024) current_mb = current / (1024 * 1024)
total_mb = total / (1024 * 1024) total_mb = total / (1024 * 1024)
self.progress.emit(f"Download progress: {percent:.2f}% ({current_mb:.2f}MB/{total_mb:.2f}MB)", self.progress.emit(f"Download progress: {percent:.2f}% ({current_mb:.2f}MB/{total_mb:.2f}MB)",
int(percent)) current_overall_progress)
else: else:
self.progress.emit(f"Processing metadata...", 0) self.progress.emit(f"Processing metadata...", current_overall_progress)
downloader.set_progress_callback(progress_update)
total_tracks = len(self.tracks) total_tracks = len(self.tracks)
@@ -110,12 +109,15 @@ class DownloadWorker(QThread):
if self.is_stopped: if self.is_stopped:
return return
current_overall_progress = int((i / total_tracks) * 100)
next_overall_progress = int(((i + 1) / total_tracks) * 100)
self.progress.emit(f"Starting download ({i+1}/{total_tracks}): {track.title} - {track.artists}", self.progress.emit(f"Starting download ({i+1}/{total_tracks}): {track.title} - {track.artists}",
int((i) / total_tracks * 100)) current_overall_progress)
try: try:
track_id = track.id track_id = track.id
self.progress.emit(f"Getting track info for ID: {track_id} from {self.service}", 0) self.progress.emit(f"Getting track info for ID: {track_id} from {self.service}", current_overall_progress)
if self.is_playlist and self.use_album_subfolders: if self.is_playlist and self.use_album_subfolders:
album_folder = re.sub(r'[<>:"/\\|?*]', '_', track.album) album_folder = re.sub(r'[<>:"/\\|?*]', '_', track.album)
@@ -125,83 +127,68 @@ class DownloadWorker(QThread):
track_outpath = self.outpath track_outpath = self.outpath
if self.service == "qobuz": if self.service == "qobuz":
self.progress.emit(f"Getting track metadata for: {track.title} - {track.artists}", 0) self.progress.emit(f"Getting track metadata for: {track.title} - {track.artists}", current_overall_progress)
isrc = None isrc = None
try: try:
from getMetadata import get_raw_spotify_data, parse_uri
track_url = track.external_urls track_url = track.external_urls
self.progress.emit(f"Fetching Spotify metadata for ISRC...", current_overall_progress)
self.progress.emit(f"Fetching Spotify metadata for ISRC...", 0)
raw_data = get_raw_spotify_data(track_url) raw_data = get_raw_spotify_data(track_url)
if raw_data and "external_ids" in raw_data and "isrc" in raw_data["external_ids"]: if raw_data and "external_ids" in raw_data and "isrc" in raw_data["external_ids"]:
isrc = raw_data["external_ids"]["isrc"] isrc = raw_data["external_ids"]["isrc"]
self.progress.emit(f"Found ISRC from Spotify: {isrc}", 0) self.progress.emit(f"Found ISRC from Spotify: {isrc}", current_overall_progress)
except Exception as e: except Exception as e:
self.progress.emit(f"Could not get ISRC from Spotify raw data: {str(e)}", 0) self.progress.emit(f"Could not get ISRC from Spotify raw data: {str(e)}", current_overall_progress)
if not isrc: if not isrc:
self.progress.emit(f"No ISRC found, searching by title and artist", 0) self.progress.emit(f"No ISRC found, searching by title and artist", current_overall_progress)
search_query = f"{track.title} {track.artists}" search_query = f"{track.title} {track.artists}"
try: try:
self.progress.emit(f"Searching Qobuz for: {search_query}", 0) self.progress.emit(f"Searching Qobuz for: {search_query}", current_overall_progress)
qobuz_track_info = SquidWTF.search_track(track.title, track.artists, strict_match=True, region=self.qobuz_region) qobuz_track_info = SquidWTF.search_track(track.title, track.artists, strict_match=True, region=self.qobuz_region)
if qobuz_track_info: if qobuz_track_info:
qobuz_track_id = qobuz_track_info["id"] qobuz_track_id = qobuz_track_info["id"]
self.progress.emit(f"Found track on Qobuz by title search: {qobuz_track_info['title']} - {qobuz_track_info['performer']['name']}", 0) self.progress.emit(f"Found track on Qobuz by title search: {qobuz_track_info['title']} - {qobuz_track_info['performer']['name']}", current_overall_progress)
found_artist = qobuz_track_info['performer']['name'].lower() found_artist = qobuz_track_info['performer']['name'].lower()
expected_artist = track.artists.lower() expected_artist = track.artists.lower()
if expected_artist not in found_artist and found_artist not in expected_artist: if expected_artist not in found_artist and found_artist not in expected_artist:
self.progress.emit(f"Warning: Artist mismatch! Expected: {track.artists}, Found: {qobuz_track_info['performer']['name']}", 0) self.progress.emit(f"Warning: Artist mismatch! Expected: {track.artists}, Found: {qobuz_track_info['performer']['name']}", current_overall_progress)
raise Exception(f"Artist mismatch: Expected '{track.artists}', found '{qobuz_track_info['performer']['name']}'") raise Exception(f"Artist mismatch: Expected '{track.artists}', found '{qobuz_track_info['performer']['name']}'")
else: else:
raise Exception(f"Could not find track on Qobuz: {track.title} - {track.artists}") raise Exception(f"Could not find track on Qobuz: {track.title} - {track.artists}")
except Exception as e: except Exception as e:
self.progress.emit(f"Search by title failed: {str(e)}", 0) self.progress.emit(f"Search by title failed: {str(e)}", current_overall_progress)
raise Exception(f"Could not find track on Qobuz: {track.title} - {track.artists}") raise Exception(f"Could not find track on Qobuz: {track.title} - {track.artists}")
else: else:
self.progress.emit(f"Searching Qobuz with ISRC: {isrc}", 0) self.progress.emit(f"Searching Qobuz with ISRC: {isrc}", current_overall_progress)
qobuz_track_info = SquidWTF.get_track_info(isrc, region=self.qobuz_region) qobuz_track_info = SquidWTF.get_track_info(isrc, region=self.qobuz_region)
qobuz_track_id = qobuz_track_info["id"] qobuz_track_id = qobuz_track_info["id"]
self.progress.emit(f"Found track on Qobuz: {qobuz_track_info['title']} - {qobuz_track_info['performer']['name']}", 0) self.progress.emit(f"Found track on Qobuz: {qobuz_track_info['title']} - {qobuz_track_info['performer']['name']}", current_overall_progress)
found_artist = qobuz_track_info['performer']['name'].lower() found_artist = qobuz_track_info['performer']['name'].lower()
expected_artist = track.artists.lower() expected_artist = track.artists.lower()
if expected_artist not in found_artist and found_artist not in expected_artist: if expected_artist not in found_artist and found_artist not in expected_artist:
self.progress.emit(f"Warning: Artist mismatch! Expected: {track.artists}, Found: {qobuz_track_info['performer']['name']}", 0) self.progress.emit(f"Warning: Artist mismatch! Expected: {track.artists}, Found: {qobuz_track_info['performer']['name']}", current_overall_progress)
download_url = SquidWTF.get_download_url(qobuz_track_id, region=self.qobuz_region) download_url = SquidWTF.get_download_url(qobuz_track_id, region=self.qobuz_region)
os.makedirs(track_outpath, exist_ok=True) os.makedirs(track_outpath, exist_ok=True)
temp_filename = os.path.join(track_outpath, f"temp_{qobuz_track_id}.flac") temp_filename = os.path.join(track_outpath, f"temp_{qobuz_track_id}.flac")
self.progress.emit(f"Downloading from Qobuz...", current_overall_progress)
self.progress.emit(f"Downloading from Qobuz...", 0) def progress_callback_qobuz(current, total):
def progress_callback(current, total):
if total > 0: if total > 0:
percent = (current / total) * 100 percent = (current / total) * 100
current_mb = current / (1024 * 1024) current_mb = current / (1024 * 1024)
total_mb = total / (1024 * 1024) total_mb = total / (1024 * 1024)
self.progress.emit(f"Download progress: {percent:.2f}% ({current_mb:.2f}MB/{total_mb:.2f}MB)", self.progress.emit(f"Download progress: {percent:.2f}% ({current_mb:.2f}MB/{total_mb:.2f}MB)",
int(percent)) current_overall_progress)
try: try:
SquidWTF.download_file(download_url, temp_filename, progress_callback) SquidWTF.download_file(download_url, temp_filename, progress_callback_qobuz)
if not os.path.exists(temp_filename) or os.path.getsize(temp_filename) == 0: if not os.path.exists(temp_filename) or os.path.getsize(temp_filename) == 0:
raise Exception(f"Downloaded file is empty or does not exist: {temp_filename}") raise Exception(f"Downloaded file is empty or does not exist: {temp_filename}")
self.progress.emit(f"Embedding metadata...", 0) self.progress.emit(f"Embedding metadata...", current_overall_progress)
SquidWTF.embed_metadata(temp_filename, qobuz_track_info) SquidWTF.embed_metadata(temp_filename, qobuz_track_info)
if (self.is_album or (self.is_playlist and self.use_album_subfolders)) and self.use_track_numbers: if (self.is_album or (self.is_playlist and self.use_album_subfolders)) and self.use_track_numbers:
@@ -217,25 +204,28 @@ class DownloadWorker(QThread):
os.rename(temp_filename, new_filepath) os.rename(temp_filename, new_filepath)
downloaded_file = new_filepath downloaded_file = new_filepath
self.progress.emit(f"File renamed to: {new_filename}", 0) self.progress.emit(f"File renamed to: {new_filename}", current_overall_progress)
except Exception as e: except Exception as e:
self.progress.emit(f"Error during download or processing: {str(e)}", 0) self.progress.emit(f"Error during download or processing: {str(e)}", current_overall_progress)
if os.path.exists(temp_filename): if os.path.exists(temp_filename):
try: try:
os.remove(temp_filename) os.remove(temp_filename)
self.progress.emit(f"Removed incomplete download file", 0) self.progress.emit(f"Removed incomplete download file", current_overall_progress)
except: except:
pass pass
raise Exception(f"Failed to download or process file: {str(e)}") raise Exception(f"Failed to download or process file: {str(e)}")
else: else:
import asyncio
metadata = asyncio.run(downloader.get_track_info(track_id, self.service)) metadata = asyncio.run(downloader.get_track_info(track_id, self.service))
self.progress.emit(f"Track info received, starting download process", 0) self.progress.emit(f"Track info received, starting download process", current_overall_progress)
is_paused_callback = lambda: self.is_paused is_paused_callback = lambda: self.is_paused
is_stopped_callback = lambda: self.is_stopped is_stopped_callback = lambda: self.is_stopped
downloader.set_progress_callback(
lambda current, total: progress_update_lucida(current, total, current_overall_progress)
)
downloaded_file = downloader.download( downloaded_file = downloader.download(
metadata, metadata,
track_outpath, track_outpath,
@@ -255,14 +245,14 @@ class DownloadWorker(QThread):
if os.path.exists(new_filepath): if os.path.exists(new_filepath):
os.remove(new_filepath) os.remove(new_filepath)
os.rename(downloaded_file, new_filepath) os.rename(downloaded_file, new_filepath)
self.progress.emit(f"File renamed to: {new_filename}", 0) self.progress.emit(f"File renamed to: {new_filename}", current_overall_progress)
self.progress.emit(f"Successfully downloaded: {track.title} - {track.artists}", self.progress.emit(f"Successfully downloaded: {track.title} - {track.artists}",
int((i + 1) / total_tracks * 100)) next_overall_progress)
except Exception as e: except Exception as e:
self.failed_tracks.append((track.title, track.artists, str(e))) self.failed_tracks.append((track.title, track.artists, str(e)))
self.progress.emit(f"Failed to download: {track.title} - {track.artists}\nError: {str(e)}", self.progress.emit(f"Failed to download: {track.title} - {track.artists}\nError: {str(e)}",
int((i + 1) / total_tracks * 100)) next_overall_progress)
continue continue
if not self.is_stopped: if not self.is_stopped:
@@ -344,17 +334,14 @@ class ServiceStatusChecker(QThread):
services_status['tidal'] = current_services.get('tidal', 0) > 0 services_status['tidal'] = current_services.get('tidal', 0) > 0
services_status['deezer'] = current_services.get('deezer', 0) > 0 services_status['deezer'] = current_services.get('deezer', 0) > 0
print("Lucida services status check successful") except json.JSONDecodeError:
except json.JSONDecodeError as e: pass
print(f"Lucida API returned invalid JSON: {e}") except Exception:
except Exception as e: pass
print(f"Error processing Lucida API response: {str(e)}") except requests.exceptions.RequestException:
else: pass
print(f"Lucida API returned status code: {response.status_code}") except Exception:
except requests.exceptions.RequestException as e: pass
print(f"Error connecting to Lucida API: {str(e)}")
except Exception as e:
print(f"Unexpected error checking Lucida services: {str(e)}")
eu_online = False eu_online = False
us_online = False us_online = False
@@ -362,16 +349,14 @@ class ServiceStatusChecker(QThread):
try: try:
eu_response = requests.get("https://eu.qobuz.squid.wtf", timeout=5) eu_response = requests.get("https://eu.qobuz.squid.wtf", timeout=5)
eu_online = eu_response.status_code in [200, 304] eu_online = eu_response.status_code in [200, 304]
print(f"SquidWTF (Qobuz EU) status check: {eu_response.status_code} - {'Online' if eu_online else 'Offline'}") except Exception:
except Exception as e: pass
print(f"Error checking EU Qobuz region: {str(e)}")
try: try:
us_response = requests.get("https://us.qobuz.squid.wtf", timeout=5) us_response = requests.get("https://us.qobuz.squid.wtf", timeout=5)
us_online = us_response.status_code in [200, 304] us_online = us_response.status_code in [200, 304]
print(f"SquidWTF (Qobuz US) status check: {us_response.status_code} - {'Online' if us_online else 'Offline'}") except Exception:
except Exception as e: pass
print(f"Error checking US Qobuz region: {str(e)}")
services_status['qobuz'] = eu_online or us_online services_status['qobuz'] = eu_online or us_online
@@ -520,12 +505,9 @@ class QobuzRegionComboBox(QComboBox):
try: try:
response = requests.get(region['url'], timeout=5) response = requests.get(region['url'], timeout=5)
regions_status[region['id']] = response.status_code in [200, 304] regions_status[region['id']] = response.status_code in [200, 304]
print(f"SquidWTF ({region['name']}) status check: {response.status_code} - {'Online' if regions_status[region['id']] else 'Offline'}") except requests.exceptions.RequestException:
except requests.exceptions.RequestException as e:
print(f"Error connecting to SquidWTF API ({region['name']}): {str(e)}")
regions_status[region['id']] = False regions_status[region['id']] = False
except Exception as e: except Exception:
print(f"Unexpected error checking SquidWTF ({region['name']}): {str(e)}")
regions_status[region['id']] = False regions_status[region['id']] = False
self.regions_status = regions_status self.regions_status = regions_status
@@ -601,8 +583,8 @@ class SpotiFLACGUI(QWidget):
if result == QDialog.DialogCode.Accepted: if result == QDialog.DialogCode.Accepted:
QDesktopServices.openUrl(QUrl("https://github.com/afkarxyz/SpotiFLAC/releases")) QDesktopServices.openUrl(QUrl("https://github.com/afkarxyz/SpotiFLAC/releases"))
except Exception as e: except Exception:
print(f"Error checking for updates: {e}") pass
@staticmethod @staticmethod
def format_duration(ms): def format_duration(ms):
@@ -1076,6 +1058,7 @@ class SpotiFLACGUI(QWidget):
def save_qobuz_region_setting(self): def save_qobuz_region_setting(self):
region = self.qobuz_region_dropdown.currentData() region = self.qobuz_region_dropdown.currentData()
self.qobuz_region = region
self.settings.setValue('qobuz_region', region) self.settings.setValue('qobuz_region', region)
self.settings.sync() self.settings.sync()
self.log_output.append(f"Qobuz region setting saved: {self.qobuz_region_dropdown.currentText()}") self.log_output.append(f"Qobuz region setting saved: {self.qobuz_region_dropdown.currentText()}")
@@ -1355,7 +1338,7 @@ class SpotiFLACGUI(QWidget):
def start_download_worker(self, tracks_to_download, outpath): def start_download_worker(self, tracks_to_download, outpath):
service = self.service_dropdown.currentData() service = self.service_dropdown.currentData()
qobuz_region = self.qobuz_region_dropdown.currentData() if service == "qobuz" else "us" qobuz_region_val = self.qobuz_region_dropdown.currentData() if service == "qobuz" else self.qobuz_region
self.worker = DownloadWorker( self.worker = DownloadWorker(
tracks_to_download, tracks_to_download,
@@ -1370,7 +1353,7 @@ class SpotiFLACGUI(QWidget):
self.use_fallback, self.use_fallback,
service, service,
self.timeout_value, self.timeout_value,
qobuz_region=qobuz_region qobuz_region=qobuz_region_val
) )
self.worker.finished.connect(self.on_download_finished) self.worker.finished.connect(self.on_download_finished)
self.worker.progress.connect(self.update_progress) self.worker.progress.connect(self.update_progress)
@@ -1391,17 +1374,12 @@ class SpotiFLACGUI(QWidget):
def update_progress(self, message, percentage): def update_progress(self, message, percentage):
if "Download progress:" in message or "Processing metadata..." in message: if "Download progress:" in message or "Processing metadata..." in message:
current_text = self.log_output.toPlainText() current_text = self.log_output.toPlainText()
if current_text: if current_text:
lines = current_text.split('\n') lines = current_text.split('\n')
if lines and ("Download progress:" in lines[-1] or "Processing metadata..." in lines[-1]):
if "Download progress:" in lines[-1] or "Processing metadata..." in lines[-1]:
lines[-1] = message lines[-1] = message
new_text = '\n'.join(lines) new_text = '\n'.join(lines)
self.log_output.setPlainText(new_text) self.log_output.setPlainText(new_text)
self.log_output.moveCursor(QTextCursor.MoveOperation.End) self.log_output.moveCursor(QTextCursor.MoveOperation.End)
else: else:
self.log_output.append(message) self.log_output.append(message)
@@ -1410,8 +1388,7 @@ class SpotiFLACGUI(QWidget):
else: else:
self.log_output.append(message) self.log_output.append(message)
if percentage > 0: self.progress_bar.setValue(percentage)
self.progress_bar.setValue(percentage)
def stop_download(self): def stop_download(self):
if hasattr(self, 'worker'): if hasattr(self, 'worker'):
+33 -21
View File
@@ -4,8 +4,20 @@ from datetime import datetime
import sys import sys
import os import os
def _safe_print(*args, **kwargs):
if sys.stdout:
print(*args, **kwargs)
def _safe_stdout_write(data_to_write):
if sys.stdout:
sys.stdout.write(data_to_write)
def _safe_flush():
if sys.stdout:
sys.stdout.flush()
def get_track_info(isrc, region="us"): def get_track_info(isrc, region="us"):
print(f"Search: {isrc}") _safe_print(f"Search: {isrc}")
base_url = f"https://{region}.qobuz.squid.wtf" base_url = f"https://{region}.qobuz.squid.wtf"
url = f"{base_url}/api/get-music?q={isrc}&offset=0" url = f"{base_url}/api/get-music?q={isrc}&offset=0"
response = requests.get(url) response = requests.get(url)
@@ -16,7 +28,7 @@ def get_track_info(isrc, region="us"):
tracks = data["data"]["tracks"]["items"] tracks = data["data"]["tracks"]["items"]
if not tracks: if not tracks:
print(f"Not Found: {isrc}") _safe_print(f"Not Found: {isrc}")
raise Exception(f"No tracks found for ISRC: {isrc}") raise Exception(f"No tracks found for ISRC: {isrc}")
track = None track = None
@@ -26,14 +38,14 @@ def get_track_info(isrc, region="us"):
break break
if not track: if not track:
print(f"Not Found: {isrc}") _safe_print(f"Not Found: {isrc}")
raise Exception(f"No track with matching ISRC: {isrc}") raise Exception(f"No track with matching ISRC: {isrc}")
print(f"Found: {track['title']} - {track['performer']['name']}") _safe_print(f"Found: {track['title']} - {track['performer']['name']}")
return track return track
def search_track(title, artist, strict_match=False, region="us"): def search_track(title, artist, strict_match=False, region="us"):
print(f"Search by title/artist: {title} - {artist}") _safe_print(f"Search by title/artist: {title} - {artist}")
search_query = f"{title} {artist}".replace("feat.", "").replace("ft.", "") search_query = f"{title} {artist}".replace("feat.", "").replace("ft.", "")
@@ -47,7 +59,7 @@ def search_track(title, artist, strict_match=False, region="us"):
tracks = data["data"]["tracks"]["items"] tracks = data["data"]["tracks"]["items"]
if not tracks: if not tracks:
print(f"Not Found: {title} - {artist}") _safe_print(f"Not Found: {title} - {artist}")
raise Exception(f"No tracks found for: {title} - {artist}") raise Exception(f"No tracks found for: {title} - {artist}")
best_match = None best_match = None
@@ -60,7 +72,7 @@ def search_track(title, artist, strict_match=False, region="us"):
if title_lower == item_title and (artist_lower in item_artist or item_artist in artist_lower): if title_lower == item_title and (artist_lower in item_artist or item_artist in artist_lower):
best_match = item best_match = item
print(f"Found exact title match with artist: {item['title']} - {item['performer']['name']}") _safe_print(f"Found exact title match with artist: {item['title']} - {item['performer']['name']}")
break break
if not best_match and not strict_match: if not best_match and not strict_match:
@@ -70,24 +82,24 @@ def search_track(title, artist, strict_match=False, region="us"):
if title_lower in item_title and (artist_lower in item_artist or item_artist in artist_lower): if title_lower in item_title and (artist_lower in item_artist or item_artist in artist_lower):
best_match = item best_match = item
print(f"Found partial match: {item['title']} - {item['performer']['name']}") _safe_print(f"Found partial match: {item['title']} - {item['performer']['name']}")
break break
if strict_match and best_match: if strict_match and best_match:
item_artist = best_match["performer"]["name"].lower() item_artist = best_match["performer"]["name"].lower()
if artist_lower not in item_artist and item_artist not in artist_lower: if artist_lower not in item_artist and item_artist not in artist_lower:
print(f"Artist mismatch in strict mode: Expected '{artist}', found '{best_match['performer']['name']}'") _safe_print(f"Artist mismatch in strict mode: Expected '{artist}', found '{best_match['performer']['name']}'")
best_match = None best_match = None
if not best_match and not strict_match and tracks: if not best_match and not strict_match and tracks:
best_match = tracks[0] best_match = tracks[0]
print(f"No good match, using first result: {best_match['title']} - {best_match['performer']['name']}") _safe_print(f"No good match, using first result: {best_match['title']} - {best_match['performer']['name']}")
if not best_match: if not best_match:
print(f"Not Found: {title} - {artist}") _safe_print(f"Not Found: {title} - {artist}")
raise Exception(f"No suitable track found for: {title} - {artist}") raise Exception(f"No suitable track found for: {title} - {artist}")
print(f"Found by title search: {best_match['title']} - {best_match['performer']['name']}") _safe_print(f"Found by title search: {best_match['title']} - {best_match['performer']['name']}")
return best_match return best_match
def get_download_url(track_id, region="us"): def get_download_url(track_id, region="us"):
@@ -106,7 +118,7 @@ def download_file(url, filename, progress_callback=None):
if directory and not os.path.exists(directory): if directory and not os.path.exists(directory):
try: try:
os.makedirs(directory, exist_ok=True) os.makedirs(directory, exist_ok=True)
print(f"Created directory: {directory}") _safe_print(f"Created directory: {directory}")
except Exception as e: except Exception as e:
raise Exception(f"Failed to create directory {directory}: {str(e)}") raise Exception(f"Failed to create directory {directory}: {str(e)}")
@@ -135,11 +147,11 @@ def download_file(url, filename, progress_callback=None):
progress_callback(downloaded, total_size) progress_callback(downloaded, total_size)
elif total_size > 0: elif total_size > 0:
progress = (downloaded / total_size) * 100 progress = (downloaded / total_size) * 100
sys.stdout.write(f"\rProgress Download: {progress:.1f}%") _safe_stdout_write(f"\rProgress Download: {progress:.1f}%")
sys.stdout.flush() _safe_flush()
if total_size > 0: if total_size > 0 and not progress_callback:
sys.stdout.write("\n") _safe_stdout_write("\n")
if not os.path.exists(filename) or os.path.getsize(filename) == 0: if not os.path.exists(filename) or os.path.getsize(filename) == 0:
raise Exception(f"Download failed: File {filename} is empty or does not exist") raise Exception(f"Download failed: File {filename} is empty or does not exist")
@@ -149,7 +161,7 @@ def download_file(url, filename, progress_callback=None):
if os.path.exists(filename): if os.path.exists(filename):
try: try:
os.remove(filename) os.remove(filename)
print(f"Removed incomplete file: {filename}") _safe_print(f"Removed incomplete file: {filename}")
except: except:
pass pass
raise Exception(f"Download failed: {str(e)}") raise Exception(f"Download failed: {str(e)}")
@@ -159,7 +171,7 @@ def embed_metadata(filename, track_info):
raise Exception(f"Cannot embed metadata: File {filename} does not exist") raise Exception(f"Cannot embed metadata: File {filename} does not exist")
try: try:
print("Embedding Tags...") _safe_print("Embedding Tags...")
audio = FLAC(filename) audio = FLAC(filename)
audio.clear() audio.clear()
@@ -190,7 +202,7 @@ def embed_metadata(filename, track_info):
audio.add_picture(picture) audio.add_picture(picture)
except Exception as e: except Exception as e:
print(f"Warning: Could not add cover image: {str(e)}") _safe_print(f"Warning: Could not add cover image: {str(e)}")
audio.save() audio.save()
except Exception as e: except Exception as e:
@@ -206,7 +218,7 @@ def download_cover_image(url):
def main(): def main():
try: try:
isrc = "USUM72409273" isrc = "USQX92500261"
region = "us" region = "us"
track_info = get_track_info(isrc, region) track_info = get_track_info(isrc, region)