Added spotify_metadata support for albums
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
@@ -277,6 +276,32 @@ class EASY_DW:
|
|||||||
# Maintain legacy attribute expected elsewhere
|
# Maintain legacy attribute expected elsewhere
|
||||||
self.__song_metadata = self.__song_metadata_dict
|
self.__song_metadata = self.__song_metadata_dict
|
||||||
self.__download_type = "track"
|
self.__download_type = "track"
|
||||||
|
# Backfill missing album fields when using Spotify minimal track objects
|
||||||
|
try:
|
||||||
|
if use_spotify and 'album' not in self.__song_metadata_dict and getattr(preferences, 'spotify_album_obj', None):
|
||||||
|
spo_album = preferences.spotify_album_obj
|
||||||
|
# Basic album fields
|
||||||
|
self.__song_metadata_dict['album'] = getattr(spo_album, 'title', '')
|
||||||
|
if getattr(spo_album, 'artists', None):
|
||||||
|
self.__song_metadata_dict['ar_album'] = artist_separator.join([getattr(a, 'name', '') for a in spo_album.artists])
|
||||||
|
self.__song_metadata_dict['nb_tracks'] = getattr(spo_album, 'total_tracks', 0)
|
||||||
|
# Total discs if available
|
||||||
|
if hasattr(spo_album, 'total_discs') and getattr(spo_album, 'total_discs'):
|
||||||
|
self.__song_metadata_dict['nb_discs'] = getattr(spo_album, 'total_discs')
|
||||||
|
# Year from release date
|
||||||
|
from deezspot.libutils.metadata_converter import _format_release_date, _get_best_image_url
|
||||||
|
self.__song_metadata_dict['year'] = _format_release_date(getattr(spo_album, 'release_date', None), 'spotify')
|
||||||
|
# IDs
|
||||||
|
if getattr(spo_album, 'ids', None):
|
||||||
|
self.__song_metadata_dict['upc'] = getattr(spo_album.ids, 'upc', None)
|
||||||
|
self.__song_metadata_dict['album_id'] = getattr(spo_album.ids, 'spotify', None)
|
||||||
|
# Prefer Spotify album image
|
||||||
|
if getattr(spo_album, 'images', None):
|
||||||
|
img_url = _get_best_image_url(spo_album.images, 'spotify')
|
||||||
|
if img_url:
|
||||||
|
self.__song_metadata_dict['image'] = img_url
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
self.__c_quality = qualities[self.__quality_download]
|
self.__c_quality = qualities[self.__quality_download]
|
||||||
self.__fallback_ids = self.__ids
|
self.__fallback_ids = self.__ids
|
||||||
@@ -1120,6 +1145,9 @@ class DW_ALBUM:
|
|||||||
album_obj: albumCbObject = self.__preferences.song_metadata
|
album_obj: albumCbObject = self.__preferences.song_metadata
|
||||||
self.__song_metadata = self._album_object_to_dict(album_obj)
|
self.__song_metadata = self._album_object_to_dict(album_obj)
|
||||||
self.__song_metadata['artist_separator'] = getattr(self.__preferences, 'artist_separator', '; ')
|
self.__song_metadata['artist_separator'] = getattr(self.__preferences, 'artist_separator', '; ')
|
||||||
|
# New: Spotify metadata context for album-level tagging
|
||||||
|
self.__use_spotify = getattr(self.__preferences, 'spotify_metadata', False)
|
||||||
|
self.__spotify_album_obj = getattr(self.__preferences, 'spotify_album_obj', None)
|
||||||
|
|
||||||
def dw(self) -> Album:
|
def dw(self) -> Album:
|
||||||
from deezspot.deezloader.deegw_api import API_GW
|
from deezspot.deezloader.deegw_api import API_GW
|
||||||
@@ -1132,12 +1160,33 @@ class DW_ALBUM:
|
|||||||
md5_image = infos_dw[0]['ALB_PICTURE']
|
md5_image = infos_dw[0]['ALB_PICTURE']
|
||||||
image_bytes = API.choose_img(md5_image, size="1400x1400")
|
image_bytes = API.choose_img(md5_image, size="1400x1400")
|
||||||
|
|
||||||
# Convert album object to dictionary for legacy functions
|
# Choose album_dict source: Spotify if requested and available, else Deezer
|
||||||
|
artist_separator = getattr(self.__preferences, 'artist_separator', '; ')
|
||||||
|
if self.__use_spotify and self.__spotify_album_obj:
|
||||||
|
album_dict = album_object_to_dict(self.__spotify_album_obj, source_type='spotify', artist_separator=artist_separator)
|
||||||
|
else:
|
||||||
album_dict = self._album_object_to_dict(album_obj)
|
album_dict = self._album_object_to_dict(album_obj)
|
||||||
|
# Prefer Spotify image if requested and available
|
||||||
|
if self.__use_spotify and self.__spotify_album_obj and getattr(self.__spotify_album_obj, 'images', None):
|
||||||
|
from deezspot.libutils.metadata_converter import _get_best_image_url
|
||||||
|
spo_img_url = _get_best_image_url(self.__spotify_album_obj.images, 'spotify')
|
||||||
|
if spo_img_url:
|
||||||
|
album_dict['image'] = spo_img_url
|
||||||
|
else:
|
||||||
|
album_dict['image'] = image_bytes
|
||||||
|
else:
|
||||||
album_dict['image'] = image_bytes
|
album_dict['image'] = image_bytes
|
||||||
|
|
||||||
album = Album(self.__ids)
|
album = Album(self.__ids)
|
||||||
album.image = image_bytes
|
# album.image should be raw bytes; fetch URL if needed
|
||||||
|
if isinstance(album_dict['image'], bytes):
|
||||||
|
album.image = album_dict['image']
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
from deezspot.libutils.taggers import fetch_and_process_image
|
||||||
|
album.image = fetch_and_process_image(album_dict['image']) or API.choose_img(md5_image, size="1400x1400")
|
||||||
|
except Exception:
|
||||||
|
album.image = API.choose_img(md5_image, size="1400x1400")
|
||||||
album.md5_image = md5_image
|
album.md5_image = md5_image
|
||||||
album.nb_tracks = album_obj.total_tracks
|
album.nb_tracks = album_obj.total_tracks
|
||||||
album.album_name = album_obj.title
|
album.album_name = album_obj.title
|
||||||
@@ -1159,6 +1208,20 @@ class DW_ALBUM:
|
|||||||
save_cover_image(album.image, album_base_directory, "cover.jpg")
|
save_cover_image(album.image, album_base_directory, "cover.jpg")
|
||||||
|
|
||||||
total_tracks = len(infos_dw)
|
total_tracks = len(infos_dw)
|
||||||
|
# If spotify album metadata is requested and available, build a map of spotify track objects by ISRC or index
|
||||||
|
spotify_tracks_by_isrc = {}
|
||||||
|
spotify_tracks_in_order = []
|
||||||
|
if self.__use_spotify and self.__spotify_album_obj and getattr(self.__spotify_album_obj, 'tracks', None):
|
||||||
|
# The spotify album object contains trackAlbumObjects with ids (including isrc)
|
||||||
|
for spo_track in self.__spotify_album_obj.tracks:
|
||||||
|
spotify_tracks_in_order.append(spo_track)
|
||||||
|
try:
|
||||||
|
isrc_val = getattr(spo_track.ids, 'isrc', None)
|
||||||
|
if isrc_val:
|
||||||
|
spotify_tracks_by_isrc[isrc_val.upper()] = spo_track
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
for a, album_track_obj in enumerate(album_obj.tracks):
|
for a, album_track_obj in enumerate(album_obj.tracks):
|
||||||
c_infos_dw_item = infos_dw[a]
|
c_infos_dw_item = infos_dw[a]
|
||||||
|
|
||||||
@@ -1197,6 +1260,25 @@ class DW_ALBUM:
|
|||||||
c_preferences.track_number = a + 1 # For progress reporting only
|
c_preferences.track_number = a + 1 # For progress reporting only
|
||||||
c_preferences.total_tracks = total_tracks
|
c_preferences.total_tracks = total_tracks
|
||||||
c_preferences.link = f"https://deezer.com/track/{c_preferences.ids}"
|
c_preferences.link = f"https://deezer.com/track/{c_preferences.ids}"
|
||||||
|
# Inject Spotify per-track object if available without extra API calls
|
||||||
|
if self.__use_spotify and spotify_tracks_in_order:
|
||||||
|
spo_track_for_tag = None
|
||||||
|
# Prefer ISRC matching if possible
|
||||||
|
deezer_isrc = None
|
||||||
|
try:
|
||||||
|
deezer_isrc = c_infos_dw_item.get('ISRC') or c_infos_dw_item.get('isrc')
|
||||||
|
deezer_isrc = deezer_isrc.upper() if isinstance(deezer_isrc, str) else None
|
||||||
|
except Exception:
|
||||||
|
deezer_isrc = None
|
||||||
|
if deezer_isrc and deezer_isrc in spotify_tracks_by_isrc:
|
||||||
|
spo_track_for_tag = spotify_tracks_by_isrc[deezer_isrc]
|
||||||
|
else:
|
||||||
|
# Fallback to index position
|
||||||
|
if a < len(spotify_tracks_in_order):
|
||||||
|
spo_track_for_tag = spotify_tracks_in_order[a]
|
||||||
|
if spo_track_for_tag:
|
||||||
|
c_preferences.spotify_metadata = True
|
||||||
|
c_preferences.spotify_track_obj = spo_track_for_tag
|
||||||
|
|
||||||
current_track_object = EASY_DW(c_infos_dw_item, c_preferences, parent='album').easy_dw()
|
current_track_object = EASY_DW(c_infos_dw_item, c_preferences, parent='album').easy_dw()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -251,7 +251,9 @@ class DeeLogin:
|
|||||||
save_cover=stock_save_cover,
|
save_cover=stock_save_cover,
|
||||||
market=stock_market,
|
market=stock_market,
|
||||||
playlist_context=None,
|
playlist_context=None,
|
||||||
artist_separator: str = "; "
|
artist_separator: str = "; ",
|
||||||
|
spotify_metadata: bool = False,
|
||||||
|
spotify_album_obj=None
|
||||||
) -> Album:
|
) -> Album:
|
||||||
|
|
||||||
link_is_valid(link_album)
|
link_is_valid(link_album)
|
||||||
@@ -299,6 +301,8 @@ class DeeLogin:
|
|||||||
preferences.save_cover = save_cover
|
preferences.save_cover = save_cover
|
||||||
preferences.market = market
|
preferences.market = market
|
||||||
preferences.artist_separator = artist_separator
|
preferences.artist_separator = artist_separator
|
||||||
|
preferences.spotify_metadata = bool(spotify_metadata)
|
||||||
|
preferences.spotify_album_obj = spotify_album_obj
|
||||||
|
|
||||||
if playlist_context:
|
if playlist_context:
|
||||||
preferences.json_data = playlist_context['json_data']
|
preferences.json_data = playlist_context['json_data']
|
||||||
@@ -637,11 +641,24 @@ class DeeLogin:
|
|||||||
save_cover=stock_save_cover,
|
save_cover=stock_save_cover,
|
||||||
market=stock_market,
|
market=stock_market,
|
||||||
playlist_context=None,
|
playlist_context=None,
|
||||||
artist_separator: str = "; "
|
artist_separator: str = "; ",
|
||||||
|
spotify_metadata: bool = False
|
||||||
) -> Album:
|
) -> Album:
|
||||||
|
|
||||||
link_dee = self.convert_spoty_to_dee_link_album(link_album)
|
link_dee = self.convert_spoty_to_dee_link_album(link_album)
|
||||||
|
|
||||||
|
spotify_album_obj = None
|
||||||
|
if spotify_metadata:
|
||||||
|
try:
|
||||||
|
# Fetch full Spotify album with tracks once and convert to albumObject
|
||||||
|
from deezspot.spotloader.__spo_api__ import tracking_album as spo_tracking_album
|
||||||
|
spo_ids = get_ids(link_album)
|
||||||
|
spotify_album_json = Spo.get_album(spo_ids)
|
||||||
|
if spotify_album_json:
|
||||||
|
spotify_album_obj = spo_tracking_album(spotify_album_json)
|
||||||
|
except Exception:
|
||||||
|
spotify_album_obj = None
|
||||||
|
|
||||||
album = self.download_albumdee(
|
album = self.download_albumdee(
|
||||||
link_dee, output_dir,
|
link_dee, output_dir,
|
||||||
quality_download, recursive_quality,
|
quality_download, recursive_quality,
|
||||||
@@ -658,7 +675,9 @@ class DeeLogin:
|
|||||||
save_cover=save_cover,
|
save_cover=save_cover,
|
||||||
market=market,
|
market=market,
|
||||||
playlist_context=playlist_context,
|
playlist_context=playlist_context,
|
||||||
artist_separator=artist_separator
|
artist_separator=artist_separator,
|
||||||
|
spotify_metadata=spotify_metadata,
|
||||||
|
spotify_album_obj=spotify_album_obj
|
||||||
)
|
)
|
||||||
|
|
||||||
return album
|
return album
|
||||||
|
|||||||
@@ -27,3 +27,5 @@ class Preferences:
|
|||||||
self.spotify_metadata: bool = False
|
self.spotify_metadata: bool = False
|
||||||
# New: optional Spotify trackObject to use when spotify_metadata is True
|
# New: optional Spotify trackObject to use when spotify_metadata is True
|
||||||
self.spotify_track_obj = None
|
self.spotify_track_obj = None
|
||||||
|
# New: optional Spotify albumObject (from spotloader tracking_album) for album-level spotify_metadata
|
||||||
|
self.spotify_album_obj = None
|
||||||
Reference in New Issue
Block a user