From afe88172ecab19eaf3c3a3c3844905401263f06a Mon Sep 17 00:00:00 2001 From: Xoconoch Date: Mon, 11 Aug 2025 08:32:54 -0600 Subject: [PATCH] Add final_path and download_quality to callback objects --- deezspot/deezloader/__download__.py | 22 +++++++++++++++--- deezspot/deezloader/__init__.py | 9 ++++---- deezspot/libutils/progress_reporter.py | 27 ++++++++++++++++++---- deezspot/models/callback/callbacks.py | 7 ++++++ deezspot/spotloader/__download__.py | 31 ++++++++++++++++++++++++-- docs/callback_examples.md | 9 ++++++-- 6 files changed, 90 insertions(+), 15 deletions(-) diff --git a/deezspot/deezloader/__download__.py b/deezspot/deezloader/__download__.py index b1d831a..f05708f 100644 --- a/deezspot/deezloader/__download__.py +++ b/deezspot/deezloader/__download__.py @@ -477,13 +477,26 @@ class EASY_DW: if self.__c_track.success : parent_obj, current_track_val, total_tracks_val = self._get_parent_context() - done_status = doneObject(ids=self.__track_obj.ids, convert_to=self.__convert_to) + # Compute final path and quality label for Deezer + final_path_val = getattr(self.__c_track, 'song_path', None) + # Deezer quality is directly the selected key or final file format + dz_quality_key = self.__quality_download + download_quality_val = dz_quality_key if dz_quality_key else (self.__c_track.file_format.upper().lstrip('.') if getattr(self.__c_track, 'file_format', None) else None) + + done_status = doneObject( + ids=self.__track_obj.ids, + convert_to=self.__convert_to, + final_path=final_path_val, + download_quality=download_quality_val + ) if self.__parent is None: summary = summaryObject( successful_tracks=[self.__track_obj], - total_successful=1 + total_successful=1, ) + summary.final_path = final_path_val + summary.download_quality = download_quality_val done_status.summary = summary callback_obj = trackCallbackObject( @@ -1287,7 +1300,7 @@ class DW_PLAYLIST: zip_name = f"{self.__output_dir}/{playlist_obj.title} [playlist {self.__ids}]" create_zip(tracks, zip_name=zip_name) playlist.zip_path = zip_name - + summary_obj = summaryObject( successful_tracks=successful_tracks_cb, skipped_tracks=skipped_tracks_cb, @@ -1297,6 +1310,9 @@ class DW_PLAYLIST: total_failed=len(failed_tracks_cb) ) + # Attach m3u path to summary + summary_obj.m3u_path = m3u_path + status_obj_done = doneObject(ids=playlist_obj.ids, summary=summary_obj) callback_obj_done = playlistCallbackObject(playlist=playlist_obj, status_info=status_obj_done) report_progress( diff --git a/deezspot/deezloader/__init__.py b/deezspot/deezloader/__init__.py index 463df56..cad1831 100644 --- a/deezspot/deezloader/__init__.py +++ b/deezspot/deezloader/__init__.py @@ -871,6 +871,9 @@ class DeeLogin: f"but only {processed_count} were processed. This might indicate that not all pages of tracks were retrieved from Spotify." ) + from deezspot.libutils.write_m3u import write_tracks_to_m3u + m3u_path = write_tracks_to_m3u(output_dir, playlist_obj.title, tracks) + summary_obj = summaryObject( successful_tracks=successful_tracks_cb, skipped_tracks=skipped_tracks_cb, @@ -879,14 +882,12 @@ class DeeLogin: total_skipped=len(skipped_tracks_cb), total_failed=len(failed_tracks_cb) ) - + # Include m3u path in summary and callback + summary_obj.m3u_path = m3u_path status_obj_done = doneObject(ids=playlist_obj.ids, summary=summary_obj) callback_obj_done = playlistCallbackObject(playlist=playlist_obj, status_info=status_obj_done) report_progress(reporter=self.progress_reporter, callback_obj=callback_obj_done) - from deezspot.libutils.write_m3u import write_tracks_to_m3u - m3u_path = write_tracks_to_m3u(output_dir, playlist_obj.title, tracks) - if make_zip: zip_name = f"{output_dir}/playlist_{sanitize_name(playlist_obj.title)}.zip" create_zip(tracks, zip_name=zip_name) diff --git a/deezspot/libutils/progress_reporter.py b/deezspot/libutils/progress_reporter.py index a10ecea..68b6858 100644 --- a/deezspot/libutils/progress_reporter.py +++ b/deezspot/libutils/progress_reporter.py @@ -236,7 +236,10 @@ def report_track_done( summary: Optional[summaryObject] = None, parent_obj: Optional[Any] = None, current_track: Optional[int] = None, - total_tracks: Optional[int] = None + total_tracks: Optional[int] = None, + *, + final_path: Optional[str] = None, + download_quality: Optional[str] = None ) -> None: """ Report track completion status. @@ -248,12 +251,16 @@ def report_track_done( parent_obj: Parent object (album/playlist) if applicable current_track: Current track number for progress total_tracks: Total tracks for progress + final_path: Final filesystem path of the produced file + download_quality: String label of the used download quality (e.g., OGG_160, OGG_320 or FLAC/MP3_320) """ status_obj = doneObject( ids=getattr(track_obj, 'ids', None), summary=summary, convert_to=getattr(preferences, 'convert_to', None), - bitrate=getattr(preferences, 'bitrate', None) + bitrate=getattr(preferences, 'bitrate', None), + final_path=final_path, + download_quality=download_quality ) callback_obj = trackCallbackObject( @@ -315,14 +322,17 @@ def report_playlist_initializing(playlist_obj: Any) -> None: report_progress(reporter=reporter, callback_obj=callback_obj) -def report_playlist_done(playlist_obj: Any, summary: summaryObject) -> None: +def report_playlist_done(playlist_obj: Any, summary: summaryObject, *, m3u_path: Optional[str] = None) -> None: """ Report playlist completion status. Args: playlist_obj: Playlist object that completed summary: Summary of track download results + m3u_path: Final path of the generated m3u file, if any """ + if m3u_path: + summary.m3u_path = m3u_path status_obj = doneObject(ids=getattr(playlist_obj, 'ids', None), summary=summary) callback_obj = playlistCallbackObject(playlist=playlist_obj, status_info=status_obj) @@ -363,7 +373,16 @@ def report_track_status( elif status_type == 'error': report_track_error(track_obj, kwargs.get('error', 'Unknown'), preferences, parent_obj, current_track, total_tracks) elif status_type == 'done': - report_track_done(track_obj, preferences, kwargs.get('summary'), parent_obj, current_track, total_tracks) + report_track_done( + track_obj, + preferences, + kwargs.get('summary'), + parent_obj, + current_track, + total_tracks, + final_path=kwargs.get('final_path'), + download_quality=kwargs.get('download_quality') + ) elif status_type == 'realtime': report_track_realtime_progress(track_obj, kwargs.get('time_elapsed', 0), kwargs.get('progress', 0), preferences, parent_obj, current_track, total_tracks) \ No newline at end of file diff --git a/deezspot/models/callback/callbacks.py b/deezspot/models/callback/callbacks.py index 241879c..3014d44 100644 --- a/deezspot/models/callback/callbacks.py +++ b/deezspot/models/callback/callbacks.py @@ -70,6 +70,10 @@ class summaryObject: total_successful: int = 0 total_skipped: int = 0 total_failed: int = 0 + # Extended info + m3u_path: Optional[str] = None + final_path: Optional[str] = None + download_quality: Optional[str] = None @dataclass @@ -77,6 +81,9 @@ class doneObject(BaseStatusObject): """Status object for 'done' state.""" status: str = "done" summary: Optional[summaryObject] = None + # Extended info for final artifact + final_path: Optional[str] = None + download_quality: Optional[str] = None @dataclass diff --git a/deezspot/spotloader/__download__.py b/deezspot/spotloader/__download__.py index 3b251e4..7e5ad56 100644 --- a/deezspot/spotloader/__download__.py +++ b/deezspot/spotloader/__download__.py @@ -674,15 +674,41 @@ class EASY_DW: total_skipped=len(skipped_track_list), total_failed=0 ) + # Enrich summary with final path and quality + try: + final_path_val = getattr(self.__c_track, 'song_path', None) + except Exception: + final_path_val = None + quality_key_single = self.__quality_download + sp_quality_map_single = { + 'NORMAL': 'OGG_96', + 'HIGH': 'OGG_160', + 'VERY_HIGH': 'OGG_320' + } + summary_obj.final_path = final_path_val + summary_obj.download_quality = sp_quality_map_single.get(quality_key_single, 'OGG') # Report track done status + # Compute final path and quality label + final_path_val = getattr(self.__c_track, 'song_path', None) + # Map Spotify quality to OGG bitrate label + quality_key = self.__quality_download if hasattr(self, '_EASY_DW__quality_download') else getattr(self, '_EASY_DW__quality_download', None) + quality_key = self.__quality_download if quality_key is None else quality_key + sp_quality_map = { + 'NORMAL': 'OGG_96', + 'HIGH': 'OGG_160', + 'VERY_HIGH': 'OGG_320' + } + download_quality_val = sp_quality_map.get(quality_key, 'OGG') report_track_done( track_obj=track_obj, preferences=self.__preferences, summary=summary_obj, parent_obj=parent_obj, current_track=current_track_val, - total_tracks=total_tracks_val + total_tracks=total_tracks_val, + final_path=final_path_val, + download_quality=download_quality_val ) if hasattr(self, '_EASY_DW__c_track') and self.__c_track and self.__c_track.success: @@ -1184,7 +1210,8 @@ class DW_PLAYLIST: total_failed=len(failed_tracks_cb) ) - report_playlist_done(playlist_obj_for_cb, summary_obj) + # Include m3u path in summary and callback + report_playlist_done(playlist_obj_for_cb, summary_obj, m3u_path=m3u_path) return playlist diff --git a/docs/callback_examples.md b/docs/callback_examples.md index ac86051..0a4cf9b 100644 --- a/docs/callback_examples.md +++ b/docs/callback_examples.md @@ -566,7 +566,9 @@ Indicates that the track has been processed successfully. "spotify": "4u7EnebtmKWzANvK9IClu8" }, "convert_to": "flac", - "bitrate": "1411" + "bitrate": "1411", + "final_path": "/music/Queen/A Night at the Opera/07. Bohemian Rhapsody.flac", + "download_quality": "OGG_320" }, "current_track": 1, "total_tracks": 1, @@ -574,6 +576,8 @@ Indicates that the track has been processed successfully. } ``` +Note: When a single-track operation is performed (not part of an album/playlist), the `summary` field may be populated. In that case, it can also include `final_path` and `download_quality` as additional convenience fields mirroring `status_info`. + ## `albumCallbackObject` Examples An `albumCallbackObject` provides status updates for a whole album. @@ -882,7 +886,8 @@ The `done` status for a playlist includes a summary of all track operations. ], "total_successful": 1, "total_skipped": 0, - "total_failed": 1 + "total_failed": 1, + "m3u_path": "/playlists/Classic Rock Anthems.m3u" }, "ids": { "spotify": "37i9dQZF1DX1rVvRgjX59F"