/ 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)