From 75f619102d7275b56e1824e70840acea5fd3d774 Mon Sep 17 00:00:00 2001 From: Xoconoch Date: Tue, 3 Jun 2025 14:39:53 -0600 Subject: [PATCH] debloating --- deezspot/deezloader/__download__.py | 38 ++++-- deezspot/deezloader/__init__.py | 43 ++----- deezspot/deezloader/__utils__.py | 39 ------ deezspot/libutils/others_settings.py | 2 +- deezspot/libutils/utils.py | 25 +++- deezspot/models/preferences.py | 3 +- deezspot/spotloader/__download__.py | 186 +++++++-------------------- deezspot/spotloader/__init__.py | 71 ++++------ 8 files changed, 134 insertions(+), 273 deletions(-) diff --git a/deezspot/deezloader/__download__.py b/deezspot/deezloader/__download__.py index 837edf3..e89d739 100644 --- a/deezspot/deezloader/__download__.py +++ b/deezspot/deezloader/__download__.py @@ -33,6 +33,8 @@ from deezspot.libutils.utils import ( trasform_sync_lyric, create_zip, sanitize_name, + save_cover_image, + __get_dir as get_album_directory, ) from mutagen.flac import FLAC from mutagen.mp3 import MP3 @@ -192,7 +194,6 @@ class EASY_DW: self.__ids = preferences.ids self.__link = preferences.link self.__output_dir = preferences.output_dir - self.__method_save = preferences.method_save self.__not_interface = preferences.not_interface self.__quality_download = preferences.quality_download self.__recursive_quality = preferences.recursive_quality @@ -277,7 +278,6 @@ class EASY_DW: self.__output_dir, self.__song_quality, self.__file_format, - self.__method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks @@ -292,7 +292,6 @@ class EASY_DW: self.__output_dir, self.__song_quality, self.__file_format, - self.__method_save, is_episode=True, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, @@ -915,10 +914,9 @@ class DW_ALBUM: self.__ids = self.__preferences.ids self.__make_zip = self.__preferences.make_zip self.__output_dir = self.__preferences.output_dir - self.__method_save = self.__preferences.method_save - self.__song_metadata = self.__preferences.song_metadata self.__not_interface = self.__preferences.not_interface self.__quality_download = self.__preferences.quality_download + self.__recursive_quality = self.__preferences.recursive_quality self.__song_metadata_items = self.__song_metadata.items() @@ -966,11 +964,11 @@ class DW_ALBUM: infos_dw = API_GW.get_album_data(self.__ids)['data'] md5_image = infos_dw[0]['ALB_PICTURE'] - image = API.choose_img(md5_image) - self.__song_metadata['image'] = image + image_bytes = API.choose_img(md5_image, size="1400x1400") # Fetch highest quality + self.__song_metadata['image'] = image_bytes # Store for tagging if needed, already bytes album = Album(self.__ids) - album.image = image + album.image = image_bytes # Store raw image bytes album.md5_image = md5_image album.nb_tracks = self.__song_metadata['nb_tracks'] album.album_name = self.__song_metadata['album'] @@ -983,7 +981,13 @@ class DW_ALBUM: infos_dw, self.__quality_download ) - # The album_artist for tagging individual tracks will be derived_album_artist_from_contributors + # Determine album base directory once + album_base_directory = get_album_directory( + self.__song_metadata, # Album level metadata + self.__output_dir, + custom_dir_format=self.__preferences.custom_dir_format, + pad_tracks=self.__preferences.pad_tracks + ) total_tracks = len(infos_dw) for a in range(total_tracks): @@ -1074,6 +1078,10 @@ class DW_ALBUM: logger.warning(f"Track not found: {song} :( Details: {track.error_message}. URL: {c_preferences.link if c_preferences else 'N/A'}") tracks.append(track) + # Save album cover image + if album.image and album_base_directory: + save_cover_image(album.image, album_base_directory, "cover.jpg") + if self.__make_zip: song_quality = tracks[0].quality if tracks else 'Unknown' # Pass along custom directory format if set @@ -1083,7 +1091,6 @@ class DW_ALBUM: output_dir=self.__output_dir, song_metadata=self.__song_metadata, song_quality=song_quality, - method_save=self.__method_save, custom_dir_format=custom_dir_format ) album.zip_path = zip_name @@ -1226,7 +1233,6 @@ class DW_EPISODE: self.__preferences = preferences self.__ids = preferences.ids self.__output_dir = preferences.output_dir - self.__method_save = preferences.method_save self.__not_interface = preferences.not_interface self.__quality_download = preferences.quality_download @@ -1335,6 +1341,16 @@ class DW_EPISODE: } Download_JOB.report_progress(progress_data) + # Save cover image for the episode + episode_image_md5 = infos_dw.get('EPISODE_IMAGE_MD5', '') + episode_image_data = None + if episode_image_md5: + episode_image_data = API.choose_img(episode_image_md5, size="1200x1200") + + if episode_image_data: + episode_directory = os.path.dirname(output_path) + save_cover_image(episode_image_data, episode_directory, "cover.jpg") + return episode except Exception as e: diff --git a/deezspot/deezloader/__init__.py b/deezspot/deezloader/__init__.py index 9c7ba7b..36cf24a 100644 --- a/deezspot/deezloader/__init__.py +++ b/deezspot/deezloader/__init__.py @@ -39,7 +39,7 @@ from deezspot.libutils.others_settings import ( stock_recursive_download, stock_not_interface, stock_zip, - method_save, + stock_save_cover, ) from deezspot.libutils.logging_utils import ProgressReporter, logger @@ -97,7 +97,6 @@ class DeeLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -130,7 +129,6 @@ class DeeLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save # New custom formatting preferences: preferences.custom_dir_format = custom_dir_format preferences.custom_track_format = custom_track_format @@ -155,14 +153,14 @@ class DeeLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Album: link_is_valid(link_album) @@ -185,7 +183,6 @@ class DeeLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.make_zip = make_zip # New custom formatting preferences: preferences.custom_dir_format = custom_dir_format @@ -198,6 +195,7 @@ class DeeLogin: preferences.max_retries = max_retries # Audio conversion parameter preferences.convert_to = convert_to + preferences.save_cover = save_cover album = DW_ALBUM(preferences).dw() @@ -211,7 +209,6 @@ class DeeLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -251,7 +248,6 @@ class DeeLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.make_zip = make_zip # New custom formatting preferences: preferences.custom_dir_format = custom_dir_format @@ -276,7 +272,6 @@ class DeeLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -293,7 +288,6 @@ class DeeLogin: track['link'], output_dir, quality_download, recursive_quality, recursive_download, not_interface, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -332,7 +326,6 @@ class DeeLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -351,7 +344,6 @@ class DeeLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -450,7 +442,6 @@ class DeeLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -466,7 +457,7 @@ class DeeLogin: link_dee, output_dir, quality_download, recursive_quality, recursive_download, not_interface, - make_zip, method_save, + make_zip, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -486,7 +477,6 @@ class DeeLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -563,7 +553,6 @@ class DeeLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -618,7 +607,6 @@ class DeeLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -648,7 +636,6 @@ class DeeLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -665,14 +652,14 @@ class DeeLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Episode: link_is_valid(link_episode) @@ -707,16 +694,8 @@ class DeeLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save - # New custom formatting preferences: - preferences.custom_dir_format = custom_dir_format - preferences.custom_track_format = custom_track_format - # Track number padding option - preferences.pad_tracks = pad_tracks - # Retry parameters - preferences.initial_retry_delay = initial_retry_delay - preferences.retry_delay_increase = retry_delay_increase - preferences.max_retries = max_retries + # No convert_to for episode download + preferences.save_cover = save_cover episode = DW_EPISODE(preferences).dw() @@ -730,7 +709,6 @@ class DeeLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, custom_dir_format=None, custom_track_format=None, pad_tracks=True, @@ -773,7 +751,6 @@ class DeeLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -800,7 +777,6 @@ class DeeLogin: recursive_download=recursive_download, not_interface=not_interface, make_zip=make_zip, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, @@ -827,7 +803,6 @@ class DeeLogin: recursive_download=recursive_download, not_interface=not_interface, make_zip=make_zip, - method_save=method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, diff --git a/deezspot/deezloader/__utils__.py b/deezspot/deezloader/__utils__.py index 892aab5..2d45f37 100644 --- a/deezspot/deezloader/__utils__.py +++ b/deezspot/deezloader/__utils__.py @@ -115,45 +115,6 @@ def check_track_md5(infos_dw): logger.error(f"Failed to check track MD5: {str(e)}") raise -def set_path(song_metadata, output_dir, method_save): - """ - Set the output path for a track based on metadata and save method. - - Args: - song_metadata: Track metadata - output_dir: Base output directory - method_save: Save method (e.g., 'artist/album/track') - - Returns: - str: Full output path - """ - try: - # Create base directory if it doesn't exist - os.makedirs(output_dir, exist_ok=True) - - # Build path based on method - if method_save == 'artist/album/track': - path = os.path.join( - output_dir, - song_metadata['artist'], - song_metadata['album'], - f"{song_metadata['music']}.mp3" - ) - else: - path = os.path.join( - output_dir, - f"{song_metadata['artist']} - {song_metadata['music']}.mp3" - ) - - # Create parent directories - os.makedirs(os.path.dirname(path), exist_ok=True) - - return path - - except Exception as e: - logger.error(f"Failed to set path: {str(e)}") - raise - def trasform_sync_lyric(lyrics): """ Transform synchronized lyrics into a standard format. diff --git a/deezspot/libutils/others_settings.py b/deezspot/libutils/others_settings.py index 218e623..c3cd73a 100644 --- a/deezspot/libutils/others_settings.py +++ b/deezspot/libutils/others_settings.py @@ -21,5 +21,5 @@ stock_recursive_quality = False stock_recursive_download = False stock_not_interface = False stock_zip = False -is_thread = False # WARNING FOR TRUE, LOOP ON DEFAULT stock_real_time_dl = True +stock_save_cover = False # Default for saving cover image diff --git a/deezspot/libutils/utils.py b/deezspot/libutils/utils.py index 9b93485..7cbbefb 100644 --- a/deezspot/libutils/utils.py +++ b/deezspot/libutils/utils.py @@ -203,7 +203,6 @@ def set_path( pad_tracks=True ): # Determine the directory for the song - # method_save is removed, __get_dir now only relies on custom_dir_format directory = __get_dir( song_metadata, output_dir, @@ -306,3 +305,27 @@ def trasform_sync_lyric(lyric): arr = (a['line'], int(a['milliseconds'])) sync_array.append(arr) return sync_array + +def save_cover_image(image_data: bytes, directory_path: str, cover_filename: str = "cover.jpg"): + if not image_data: + logger.warning(f"No image data provided to save cover in {directory_path}.") + return + + if not isdir(directory_path): + # This case should ideally be handled by prior directory creation (e.g., __get_dir) + # but as a fallback, we can try to create it or log a warning. + logger.warning(f"Directory {directory_path} does not exist. Attempting to create it for cover image.") + try: + makedirs(directory_path, exist_ok=True) + logger.info(f"Created directory {directory_path} for cover image.") + except OSError as e: + logger.error(f"Failed to create directory {directory_path} for cover: {e}") + return + + cover_path = join(directory_path, cover_filename) + try: + with open(cover_path, "wb") as f: + f.write(image_data) + logger.info(f"Successfully saved cover image to {cover_path}") + except OSError as e: + logger.error(f"Failed to save cover image to {cover_path}: {e}") diff --git a/deezspot/models/preferences.py b/deezspot/models/preferences.py index be68374..8b288a5 100644 --- a/deezspot/models/preferences.py +++ b/deezspot/models/preferences.py @@ -18,4 +18,5 @@ class Preferences: self.pad_tracks = True # Default to padded track numbers (01, 02, etc.) self.initial_retry_delay = 30 # Default initial retry delay in seconds self.retry_delay_increase = 30 # Default increase in delay between retries in seconds - self.max_retries = 5 # Default maximum number of retries per track \ No newline at end of file + self.max_retries = 5 # Default maximum number of retries per track + self.save_cover: bool = False # Option to save a cover.jpg image \ No newline at end of file diff --git a/deezspot/spotloader/__download__.py b/deezspot/spotloader/__download__.py index ff038dc..abdd7b4 100644 --- a/deezspot/spotloader/__download__.py +++ b/deezspot/spotloader/__download__.py @@ -32,6 +32,8 @@ from deezspot.libutils.utils import ( create_zip, request, sanitize_name, + save_cover_image, + __get_dir as get_album_directory, ) from mutagen import File from mutagen.easyid3 import EasyID3 @@ -136,7 +138,6 @@ class EASY_DW: self.__ids = preferences.ids self.__link = preferences.link self.__output_dir = preferences.output_dir - self.__method_save = preferences.method_save self.__song_metadata = preferences.song_metadata self.__not_interface = preferences.not_interface self.__quality_download = preferences.quality_download or "NORMAL" @@ -169,7 +170,6 @@ class EASY_DW: self.__output_dir, self.__song_quality, self.__file_format, - self.__method_save, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks @@ -184,7 +184,6 @@ class EASY_DW: self.__output_dir, self.__song_quality, self.__file_format, - self.__method_save, is_episode=True, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, @@ -1004,29 +1003,37 @@ class EASY_DW: self.__write_episode() # Write metadata tags so subsequent skips work write_tags(self.__c_episode) + + # Save episode cover image if download was successful + if self.__c_episode.success and hasattr(self.__c_episode, 'episode_path') and self.__c_episode.episode_path: + episode_directory = dirname(self.__c_episode.episode_path) + image_url = self.__song_metadata.get('image') + image_bytes = None + if image_url: + try: + image_bytes = request(image_url).content + except Exception as e_img: + logger.warning(f"Failed to fetch cover image for episode {self.__c_episode.tags.get('name', '')}: {e_img}") + if image_bytes: + save_cover_image(image_bytes, episode_directory, "cover.jpg") + return self.__c_episode def download_cli(preferences: Preferences) -> None: __link = preferences.link __output_dir = preferences.output_dir - __method_save = preferences.method_save __not_interface = preferences.not_interface __quality_download = preferences.quality_download __recursive_download = preferences.recursive_download - __recursive_quality = preferences.recursive_quality cmd = f"deez-dw.py -so spo -l \"{__link}\" " if __output_dir: cmd += f"-o {__output_dir} " - if __method_save: - cmd += f"-sa {__method_save} " if __not_interface: cmd += f"-g " if __quality_download: cmd += f"-q {__quality_download} " if __recursive_download: cmd += f"-rd " - if __recursive_quality: - cmd += f"-rq" system(cmd) class DW_TRACK: @@ -1042,11 +1049,6 @@ class DW_TRACK: # it's an intentional skip, not an error return track - def dw2(self) -> Track: - track = EASY_DW(self.__preferences).get_no_dw_track() - download_cli(self.__preferences) - return track - class DW_ALBUM: def __init__( self, @@ -1056,7 +1058,6 @@ class DW_ALBUM: self.__ids = self.__preferences.ids self.__make_zip = self.__preferences.make_zip self.__output_dir = self.__preferences.output_dir - self.__method_save = self.__preferences.method_save self.__song_metadata = self.__preferences.song_metadata self.__not_interface = self.__preferences.not_interface self.__song_metadata_items = self.__song_metadata.items() @@ -1098,11 +1099,12 @@ class DW_ALBUM: "url": f"https://open.spotify.com/album/{album_id}" }) - pic = self.__song_metadata['image'] - image = request(pic).content - self.__song_metadata['image'] = image + pic_url = self.__song_metadata['image'] # This is URL for spotify + image_bytes = request(pic_url).content + self.__song_metadata['image'] = image_bytes # Keep bytes for tagging + album = Album(self.__ids) - album.image = image + album.image = image_bytes # Store raw image bytes for cover saving album.nb_tracks = self.__song_metadata['nb_tracks'] album.album_name = self.__song_metadata['album'] album.upc = self.__song_metadata['upc'] @@ -1110,6 +1112,14 @@ class DW_ALBUM: album.md5_image = self.__ids album.tags = self.__song_metadata + # Determine album base directory once + album_base_directory = get_album_directory( + self.__song_metadata, # Album level metadata + self.__output_dir, + custom_dir_format=self.__preferences.custom_dir_format, + pad_tracks=self.__preferences.pad_tracks + ) + c_song_metadata = {} for key, item in self.__song_metadata_items: if type(item) is not list: @@ -1147,6 +1157,11 @@ class DW_ALBUM: track.error_message = f"An unexpected error occurred: {str(e_generic)}" logger.error(f"Unexpected error downloading track '{song_name}' by '{artist_name}' from album '{album.album_name}'. Reason: {track.error_message}") tracks.append(track) + + # Save album cover image + if album.image and album_base_directory: + save_cover_image(album.image, album_base_directory, "cover.jpg") + if self.__make_zip: song_quality = tracks[0].quality custom_dir_format = getattr(self.__preferences, 'custom_dir_format', None) @@ -1155,7 +1170,6 @@ class DW_ALBUM: output_dir=self.__output_dir, song_metadata=self.__song_metadata, song_quality=song_quality, - method_save=self.__method_save, custom_dir_format=custom_dir_format ) album.zip_path = zip_name @@ -1185,11 +1199,6 @@ class DW_ALBUM: return album - def dw2(self) -> Album: - track = EASY_DW(self.__preferences).get_no_dw_track() - download_cli(self.__preferences) - return track - class DW_PLAYLIST: def __init__( self, @@ -1284,86 +1293,6 @@ class DW_PLAYLIST: return playlist - def dw2(self) -> Playlist: - # Extract playlist metadata for reporting - playlist_name = self.__json_data.get('name', 'Unknown Playlist') - playlist_owner = self.__json_data.get('owner', {}).get('display_name', 'Unknown Owner') - total_tracks = self.__json_data.get('tracks', {}).get('total', 'unknown') - playlist_id = self.__ids - - # Report playlist initializing status - Download_JOB.report_progress({ - "type": "playlist", - "owner": playlist_owner, - "status": "initializing", - "total_tracks": total_tracks, - "name": playlist_name, - "url": f"https://open.spotify.com/playlist/{playlist_id}" - }) - - playlist = Playlist() - tracks = playlist.tracks - for i, c_song_metadata in enumerate(self.__song_metadata): - if type(c_song_metadata) is str: - logger.warning(f"Track not found {c_song_metadata}") - continue - c_preferences = deepcopy(self.__preferences) - c_preferences.ids = c_song_metadata['ids'] - c_preferences.song_metadata = c_song_metadata - c_preferences.json_data = self.__json_data # Pass playlist data for reporting - c_preferences.track_number = i + 1 # Track number in the playlist - - # Even though we're not downloading directly, we still need to set up the track object - track = EASY_DW(c_preferences, parent='playlist').get_no_dw_track() - if not track.success: - song = f"{c_song_metadata['music']} - {c_song_metadata['artist']}" - error_detail = getattr(track, 'error_message', 'Download failed for unspecified reason.') - logger.warning(f"Cannot download '{song}' (CLI mode). Reason: {error_detail} (Link: {track.link or c_preferences.link})") - tracks.append(track) - - # Track-level progress reporting using the standardized format - progress_data = { - "type": "track", - "song": c_song_metadata.get("music", ""), - "artist": c_song_metadata.get("artist", ""), - "status": "progress", - "current_track": i + 1, - "total_tracks": total_tracks, - "parent": { - "type": "playlist", - "name": playlist_name, - "owner": self.__json_data.get('owner', {}).get('display_name', 'unknown'), - "total_tracks": total_tracks, - "url": f"https://open.spotify.com/playlist/{self.__json_data.get('id', '')}" - }, - "url": f"https://open.spotify.com/track/{c_song_metadata['ids']}" - } - Download_JOB.report_progress(progress_data) - download_cli(self.__preferences) - - if self.__make_zip: - playlist_title = self.__json_data['name'] - zip_name = f"{self.__output_dir}/{playlist_title} [playlist {self.__ids}]" - create_zip(tracks, zip_name=zip_name) - playlist.zip_path = zip_name - - # Report playlist done status - playlist_name = self.__json_data.get('name', 'Unknown Playlist') - playlist_owner = self.__json_data.get('owner', {}).get('display_name', 'Unknown Owner') - total_tracks = self.__json_data.get('tracks', {}).get('total', 0) - playlist_id = self.__ids - - Download_JOB.report_progress({ - "type": "playlist", - "owner": playlist_owner, - "status": "done", - "total_tracks": total_tracks, - "name": playlist_name, - "url": f"https://open.spotify.com/playlist/{playlist_id}" - }) - - return playlist - class DW_EPISODE: def __init__( self, @@ -1389,42 +1318,19 @@ class DW_EPISODE: episode = EASY_DW(self.__preferences).download_eps() - # Using standardized episode progress format - progress_data = { - "type": "episode", - "song": self.__preferences.song_metadata.get('name', 'Unknown Episode'), - "artist": self.__preferences.song_metadata.get('show', 'Unknown Show'), - "status": "done" - } - - # Set URL if available - episode_id = self.__preferences.ids - if episode_id: - progress_data["url"] = f"https://open.spotify.com/episode/{episode_id}" - - Download_JOB.report_progress(progress_data) - - return episode + # Save episode cover image if download was successful + if episode.success and hasattr(episode, 'episode_path') and episode.episode_path: + episode_directory = dirname(episode.episode_path) + image_url = self.__preferences.song_metadata.get('image') + image_bytes = None + if image_url: + try: + image_bytes = request(image_url).content + except Exception as e_img: + logger.warning(f"Failed to fetch cover image for episode {episode.tags.get('name', '')}: {e_img}") + if image_bytes: + save_cover_image(image_bytes, episode_directory, "cover.jpg") - def dw2(self) -> Episode: - # Using standardized episode progress format - progress_data = { - "type": "episode", - "song": self.__preferences.song_metadata.get('name', 'Unknown Episode'), - "artist": self.__preferences.song_metadata.get('show', 'Unknown Show'), - "status": "initializing" - } - - # Set URL if available - episode_id = self.__preferences.ids - if episode_id: - progress_data["url"] = f"https://open.spotify.com/episode/{episode_id}" - - Download_JOB.report_progress(progress_data) - - episode = EASY_DW(self.__preferences).get_no_dw_track() - download_cli(self.__preferences) - # Using standardized episode progress format progress_data = { "type": "episode", diff --git a/deezspot/spotloader/__init__.py b/deezspot/spotloader/__init__.py index 8c3cb53..5654a05 100644 --- a/deezspot/spotloader/__init__.py +++ b/deezspot/spotloader/__init__.py @@ -32,8 +32,7 @@ from deezspot.libutils.others_settings import ( stock_recursive_download, stock_not_interface, stock_zip, - method_save, - is_thread, + stock_save_cover, stock_real_time_dl ) from deezspot.libutils.logging_utils import logger, ProgressReporter @@ -90,8 +89,6 @@ class SpoLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, - is_thread=is_thread, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -118,7 +115,6 @@ class SpoLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.is_episode = False preferences.custom_dir_format = custom_dir_format preferences.custom_track_format = custom_track_format @@ -128,10 +124,7 @@ class SpoLogin: preferences.max_retries = max_retries preferences.convert_to = convert_to - if not is_thread: - track = DW_TRACK(preferences).dw() - else: - track = DW_TRACK(preferences).dw2() + track = DW_TRACK(preferences).dw() return track except Exception as e: @@ -147,8 +140,6 @@ class SpoLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, - is_thread=is_thread, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -156,7 +147,8 @@ class SpoLogin: initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Album: try: link_is_valid(link_album) @@ -178,7 +170,6 @@ class SpoLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.make_zip = make_zip preferences.is_episode = False preferences.custom_dir_format = custom_dir_format @@ -188,11 +179,9 @@ class SpoLogin: preferences.retry_delay_increase = retry_delay_increase preferences.max_retries = max_retries preferences.convert_to = convert_to + preferences.save_cover = save_cover - if not is_thread: - album = DW_ALBUM(preferences).dw() - else: - album = DW_ALBUM(preferences).dw2() + album = DW_ALBUM(preferences).dw() return album except Exception as e: @@ -208,8 +197,6 @@ class SpoLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, - is_thread=is_thread, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -217,7 +204,8 @@ class SpoLogin: initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Playlist: try: link_is_valid(link_playlist) @@ -253,7 +241,6 @@ class SpoLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.make_zip = make_zip preferences.is_episode = False preferences.custom_dir_format = custom_dir_format @@ -263,11 +250,9 @@ class SpoLogin: preferences.retry_delay_increase = retry_delay_increase preferences.max_retries = max_retries preferences.convert_to = convert_to + preferences.save_cover = save_cover - if not is_thread: - playlist = DW_PLAYLIST(preferences).dw() - else: - playlist = DW_PLAYLIST(preferences).dw2() + playlist = DW_PLAYLIST(preferences).dw() return playlist except Exception as e: @@ -282,8 +267,6 @@ class SpoLogin: recursive_quality=stock_recursive_quality, recursive_download=stock_recursive_download, not_interface=stock_not_interface, - method_save=method_save, - is_thread=is_thread, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -291,7 +274,8 @@ class SpoLogin: initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Episode: try: link_is_valid(link_episode) @@ -312,7 +296,6 @@ class SpoLogin: preferences.recursive_quality = recursive_quality preferences.recursive_download = recursive_download preferences.not_interface = not_interface - preferences.method_save = method_save preferences.is_episode = True preferences.custom_dir_format = custom_dir_format preferences.custom_track_format = custom_track_format @@ -321,11 +304,9 @@ class SpoLogin: preferences.retry_delay_increase = retry_delay_increase preferences.max_retries = max_retries preferences.convert_to = convert_to + preferences.save_cover = save_cover - if not is_thread: - episode = DW_EPISODE(preferences).dw() - else: - episode = DW_EPISODE(preferences).dw2() + episode = DW_EPISODE(preferences).dw() return episode except Exception as e: @@ -343,8 +324,6 @@ class SpoLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, - is_thread=is_thread, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -382,8 +361,6 @@ class SpoLogin: recursive_download=recursive_download, not_interface=not_interface, make_zip=make_zip, - method_save=method_save, - is_thread=is_thread, real_time_dl=real_time_dl, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, @@ -408,7 +385,6 @@ class SpoLogin: recursive_download=stock_recursive_download, not_interface=stock_not_interface, make_zip=stock_zip, - method_save=method_save, real_time_dl=stock_real_time_dl, custom_dir_format=None, custom_track_format=None, @@ -416,7 +392,8 @@ class SpoLogin: initial_retry_delay=30, retry_delay_increase=30, max_retries=5, - convert_to=None + convert_to=None, + save_cover=stock_save_cover ) -> Smart: try: link_is_valid(link) @@ -439,7 +416,6 @@ class SpoLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, real_time_dl=real_time_dl, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, @@ -462,14 +438,15 @@ class SpoLogin: recursive_download=recursive_download, not_interface=not_interface, make_zip=make_zip, - method_save=method_save, real_time_dl=real_time_dl, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, initial_retry_delay=initial_retry_delay, retry_delay_increase=retry_delay_increase, - max_retries=max_retries + max_retries=max_retries, + convert_to=convert_to, + save_cover=save_cover ) smart.type = "album" smart.album = album @@ -485,14 +462,15 @@ class SpoLogin: recursive_download=recursive_download, not_interface=not_interface, make_zip=make_zip, - method_save=method_save, real_time_dl=real_time_dl, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, initial_retry_delay=initial_retry_delay, retry_delay_increase=retry_delay_increase, - max_retries=max_retries + max_retries=max_retries, + convert_to=convert_to, + save_cover=save_cover ) smart.type = "playlist" smart.playlist = playlist @@ -507,14 +485,15 @@ class SpoLogin: recursive_quality=recursive_quality, recursive_download=recursive_download, not_interface=not_interface, - method_save=method_save, real_time_dl=real_time_dl, custom_dir_format=custom_dir_format, custom_track_format=custom_track_format, pad_tracks=pad_tracks, initial_retry_delay=initial_retry_delay, retry_delay_increase=retry_delay_increase, - max_retries=max_retries + max_retries=max_retries, + convert_to=convert_to, + save_cover=save_cover ) smart.type = "episode" smart.episode = episode