/ blottertrax / description_provider.py
description_provider.py
1 import musicbrainzngs 2 3 from blottertrax.config import Config 4 from blottertrax.exceptions.description_exception import DescriptionException 5 from blottertrax.helper import templates 6 from blottertrax.helper.array_util import ArrayUtil 7 from blottertrax.value_objects.parsed_submission import ParsedSubmission 8 9 10 class DescriptionProvider: 11 whitelist = ['twitter.com', 'facebook.com', 'instagram.com', 'allmusic.com', 'bandcamp.com', 12 'bandsintown.com', 'discogs.com', 'genius.com', 'rateyourmusic.com', 'last.fm', 13 'soundcloud.com', 'youtube.com', 'www.whosampled.com'] 14 15 def __init__(self): 16 config = Config() 17 18 self.musicbrainz = musicbrainzngs 19 self.musicbrainz.auth(config.MUSICBRAINZ.USER, config.MUSICBRAINZ.PASSWORD) 20 self.musicbrainz.set_useragent("BlotterTrax", "0.1", "https://github.com/martijnboers/BlotterTrax") 21 22 def get_reply(self, parsed_submission: ParsedSubmission) -> str: 23 if parsed_submission.success is False: 24 raise DescriptionException('DescriptionProvider requires the submission title') 25 26 query = '"{}" AND artist:"{}"'.format(parsed_submission.track_title, parsed_submission.artist) 27 result = self.musicbrainz.search_recordings(query=query, limit=1, ) 28 29 if result['recording-count'] == 0: 30 raise DescriptionException('No recordings found for artist') 31 32 recording = result['recording-list'][0] 33 artist = self._get_artist_by_id(recording.get('artist-credit')[0]['artist']['id']) 34 35 album_title = ArrayUtil.safe_list_get(recording, recording['title'], 'release-list', 0, 'title') 36 album_release_date = ArrayUtil.safe_list_get(recording, False, 'release-list', 0, 'date') 37 life_span_begin = ArrayUtil.safe_list_get(artist, '?', 'life-span', 'begin') 38 life_span_end = ArrayUtil.safe_list_get(artist, 'now', 'life-span', 'end') 39 40 has_life_span = life_span_end != 'now' or life_span_begin != '?' 41 has_tags = ArrayUtil.safe_list_get(artist, False, 'tag-list') is not False 42 has_socials = ArrayUtil.safe_list_get(artist, False, 'url-relation-list') is not False 43 44 if has_tags is False and has_socials is False: 45 raise DescriptionException('Neither tags nor socials found, skipping') 46 47 album_release_date = '' if album_release_date is False else '({})'.format(album_release_date) 48 life_span = '' if has_life_span is False else '({} to {})'.format(life_span_begin, life_span_end) 49 tags = ', '.join(map(lambda t: t['name'], artist['tag-list'][:5])) if has_tags else 'none' 50 51 socials = ', '.join( 52 map(self.format_network_to_friendly_name, filter(self.apply_whitelist, artist['url-relation-list'])) 53 ) if has_socials else 'none' 54 55 return templates.musicbrainz_artist_info.strip().format( 56 artist['name'], 57 life_span, 58 album_title, 59 album_release_date, 60 tags, 61 'none' if not socials else socials, 62 artist['id'] 63 ) 64 65 def _get_artist_by_id(self, artist_id: str): 66 return self.musicbrainz.get_artist_by_id( 67 id=artist_id, includes=['tags', 'ratings', 'annotation', 'url-rels', 'user-tags'] 68 )['artist'] 69 70 @staticmethod 71 def apply_whitelist(info) -> bool: 72 for domain in DescriptionProvider.whitelist: 73 if domain in info['target']: 74 return True 75 return False 76 77 @staticmethod 78 def format_network_to_friendly_name(info) -> str: 79 social_network = ['twitter.com', 'facebook.com', 'instagram.com'] 80 link_type = info['type'] 81 target = info['target'] 82 target = target.replace('(', r'\(').replace(')', r'\)') 83 84 if link_type == 'social network': 85 for domain in social_network: 86 if domain in target: 87 link_type = domain.split('.')[0] 88 break 89 return '[{}]({})'.format(link_type, target)