From 14bef1e63d2bef6769b6f313664cf2c617ccb15d Mon Sep 17 00:00:00 2001 From: AdeHub Date: Sun, 14 Jul 2019 19:57:40 +1200 Subject: [PATCH] Use fanart.tv for artist image last.fm no longer allows access to artist images. Get artist image from fanart.tv instead --- data/interfaces/default/index.html | 2 +- headphones/cache.py | 135 +++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 27 deletions(-) diff --git a/data/interfaces/default/index.html b/data/interfaces/default/index.html index 260c0a1a..e7becc61 100644 --- a/data/interfaces/default/index.html +++ b/data/interfaces/default/index.html @@ -36,7 +36,7 @@ "aTargets": [0], "mData":"ArtistID", "mRender": function ( data, type, full ) { - return '
'; + return '
'; } }, { diff --git a/headphones/cache.py b/headphones/cache.py index 0e946677..b81084e0 100644 --- a/headphones/cache.py +++ b/headphones/cache.py @@ -14,11 +14,18 @@ # along with Headphones. If not, see . import os +from six.moves.urllib.parse import urlencode import headphones from headphones import db, helpers, logger, lastfm, request, mb -LASTFM_API_KEY = "690e1ed3bc00bc91804cd8f7fe5ed6d4" +# LASTFM_API_KEY = "690e1ed3bc00bc91804cd8f7fe5ed6d4" +LASTFM_API_KEY = "a1c959f36a912a165d73c4dc5b9520f5" + +FANART_URL = 'https://webservice.fanart.tv/v3/music/' +FANART_PROJECT_KEY = '22b73c9603eba09d0c855f2d2bdba31c' +FANART_CLIENT_KEY = '919b389a18a3f0b2c916090022ab3c7a' + class Cache(object): @@ -96,6 +103,11 @@ class Cache(object): def _is_current(self, filename=None, date=None): if filename: + + # 2019 last.fm no longer allows access to artist images, for now we'll keep the cached artist image if it exists and get new from fanart.tv + if self.id_type == 'artist' and 'fanart' not in filename: + return True + base_filename = os.path.basename(filename) date = base_filename.split('.')[1] @@ -211,20 +223,34 @@ class Cache(object): if ArtistID: self.id_type = 'artist' - data = lastfm.request_lastfm("artist.getinfo", mbid=ArtistID, api_key=LASTFM_API_KEY) + + # 2019 last.fm no longer allows access to artist images, try fanart.tv instead + image_url = None + thumb_url = None + data = request.request_json(FANART_URL + ArtistID, whitelist_status_code=404, + headers={'api-key': FANART_PROJECT_KEY, 'client-key': FANART_CLIENT_KEY}) if not data: return - try: - image_url = data['artist']['image'][-1]['#text'] - except (KeyError, IndexError): - logger.debug('No artist image found') - image_url = None + if data.get('artistthumb'): + image_url = data['artistthumb'][0]['url'] + elif data.get('artistbackground'): + image_url = data['artistbackground'][0]['url'] + elif data.get('hdmusiclogo'): + image_url = data['hdmusiclogo'][0]['url'] - thumb_url = self._get_thumb_url(data) - if not thumb_url: - logger.debug('No artist thumbnail image found') + # fallback to 1st album cover if none of the above + elif 'albums' in data: + for mbid, art in data.get('albums', dict()).items(): + if 'albumcover' in art: + image_url = art['albumcover'][0]['url'] + break + + if image_url: + thumb_url = image_url + else: + logger.debug('No artist image found on fanart.tv for Artist Id: %s', self.id) else: @@ -283,6 +309,7 @@ class Cache(object): """ myDB = db.DBConnection() + fanart = False # Since lastfm uses release ids rather than release group ids for albums, we have to do a artist + album search for albums # Exception is when adding albums manually, then we should use release id @@ -311,15 +338,42 @@ class Cache(object): except KeyError: logger.debug('No artist bio found') self.info_content = None - try: - image_url = data['artist']['image'][-1]['#text'] - except KeyError: - logger.debug('No artist image found') - image_url = None - thumb_url = self._get_thumb_url(data) - if not thumb_url: - logger.debug('No artist thumbnail image found') + # 2019 last.fm no longer allows access to artist images, try fanart.tv instead + image_url = None + thumb_url = None + data = request.request_json(FANART_URL + self.id, whitelist_status_code=404, + headers={'api-key': FANART_PROJECT_KEY, 'client-key': FANART_CLIENT_KEY}) + + if data.get('artistthumb'): + image_url = data['artistthumb'][0]['url'] + elif data.get('artistbackground'): + image_url = data['artistbackground'][0]['url'] + elif data.get('hdmusiclogo'): + image_url = data['hdmusiclogo'][0]['url'] + + # fallback to 1st album cover if none of the above + elif 'albums' in data: + for mbid, art in data.get('albums', dict()).items(): + if 'albumcover' in art: + image_url = art['albumcover'][0]['url'] + break + + # finally, use 1st album cover from last.fm + if image_url: + fanart = True + thumb_url = image_url + else: + dbalbum = myDB.action( + 'SELECT ArtworkURL, ThumbURL FROM albums WHERE ArtworkURL IS NOT NULL AND ArtistID=?', + [self.id]).fetchone() + if dbalbum: + fanart = True + image_url = dbalbum['ArtworkURL'] + thumb_url = dbalbum['ThumbURL'] + + if not image_url: + logger.debug('No artist image found on fanart.tv for Artist Id: %s', self.id) else: dbalbum = myDB.action( @@ -427,7 +481,11 @@ class Cache(object): ext = os.path.splitext(image_url)[1] - artwork_path = os.path.join(self.path_to_art_cache, + if fanart: + artwork_path = os.path.join(self.path_to_art_cache, + self.id + '_fanart_' + '.' + helpers.today() + ext) + else: + artwork_path = os.path.join(self.path_to_art_cache, self.id + '.' + helpers.today() + ext) try: with open(artwork_path, 'wb') as f: @@ -443,7 +501,9 @@ class Cache(object): # as it's missing/outdated. if thumb_url and self.query_type in ['thumb', 'artwork'] and not ( self.thumb_files and self._is_current(self.thumb_files[0])): - artwork = request.request_content(thumb_url, timeout=20) + + if not (self.query_type == 'artwork' and 'fanart' in thumb_url and artwork): + artwork = request.request_content(thumb_url, timeout=20) if artwork: # Make sure the artwork dir exists: @@ -466,11 +526,34 @@ class Cache(object): ext = os.path.splitext(image_url)[1] - thumb_path = os.path.join(self.path_to_art_cache, - 'T_' + self.id + '.' + helpers.today() + ext) + if fanart: + thumb_path = os.path.join(self.path_to_art_cache, + 'T_' + self.id + '_fanart_' +'.' + helpers.today() + ext) + else: + thumb_path = os.path.join(self.path_to_art_cache, + 'T_' + self.id + '.' + helpers.today() + ext) try: - with open(thumb_path, 'wb') as f: - f.write(artwork) + if self.id_type != 'artist': + with open(thumb_path, 'wb') as f: + f.write(artwork) + else: + + # 2019 last.fm no longer allows access to artist images, use the fanart.tv image to create a thumb + artwork_thumb = None + if 'fanart' in thumb_url: + # Create thumb using image resizing service + artwork_path = '{0}?{1}'.format('http://images.weserv.nl/', urlencode({ + 'url': thumb_url.replace('http://', ''), + 'w': 300, + })) + artwork_thumb = request.request_content(artwork_path, timeout=20, whitelist_status_code=404) + + if artwork_thumb: + with open(thumb_path, 'wb') as f: + f.write(artwork_thumb) + else: + with open(thumb_path, 'wb') as f: + f.write(artwork) os.chmod(thumb_path, int(headphones.CONFIG.FILE_PERMISSIONS, 8)) except (OSError, IOError) as e: @@ -486,7 +569,7 @@ def getArtwork(ArtistID=None, AlbumID=None): if not artwork_path: return None - if artwork_path.startswith('http://'): + if artwork_path.startswith(('http://', 'https://')): return artwork_path else: artwork_file = os.path.basename(artwork_path) @@ -500,7 +583,7 @@ def getThumb(ArtistID=None, AlbumID=None): if not artwork_path: return None - if artwork_path.startswith('http://'): + if artwork_path.startswith(('http://', 'https://')): return artwork_path else: thumbnail_file = os.path.basename(artwork_path)