]> kaliko git repositories - mpd-sima.git/blobdiff - sima/client.py
Improved source distribution (add missing data files)
[mpd-sima.git] / sima / client.py
index 2893d9b52cf52bb5a53266ec2bdedc7f0e05ebcd..0a7f754bfdb03dfeb47de52bb16647f1e0409714 100644 (file)
@@ -36,6 +36,7 @@ except ImportError as err:
     sexit(1)
 
 # local import
     sexit(1)
 
 # local import
+from .lib.simastr import SimaStr
 from .lib.player import Player, blacklist
 from .lib.track import Track
 from .lib.meta import Album, Artist
 from .lib.player import Player, blacklist
 from .lib.track import Track
 from .lib.meta import Album, Artist
@@ -50,6 +51,28 @@ class PlayerCommandError(PlayerError):
 
 PlayerUnHandledError = MPDError  # pylint: disable=C0103
 
 
 PlayerUnHandledError = MPDError  # pylint: disable=C0103
 
+def bl_artist(func):
+    def wrapper(*args, **kwargs):
+        cls = args[0]
+        if not args[0].database:
+            return func(*args, **kwargs)
+        result = func(*args, **kwargs)
+        if not result:
+            return
+        names = list()
+        for art in result.names:
+            if cls.database.get_bl_artist(art, add_not=True):
+                cls.log.debug('Blacklisted "{0}"'.format(art))
+                continue
+            names.append(art)
+        if not names:
+            return
+        resp = Artist(name=names.pop(), mbid=result.mbid)
+        for name in names:
+            resp.add_alias(name)
+        return resp
+    return wrapper
+
 
 class PlayerClient(Player):
     """MPD Client
 
 class PlayerClient(Player):
     """MPD Client
@@ -137,8 +160,10 @@ class PlayerClient(Player):
             self.log.info('Player: Initialising cache!')
         self._cache = {
                 'artists': None,
             self.log.info('Player: Initialising cache!')
         self._cache = {
                 'artists': None,
+                'nombid_artists': None,
                 }
         self._cache['artists'] = frozenset(self._client.list('artist'))
                 }
         self._cache['artists'] = frozenset(self._client.list('artist'))
+        self._cache['nombid_artists'] = frozenset(self._client.list('artist', 'musicbrainz_artistid', ''))
 
     @blacklist(track=True)
     def find_track(self, artist, title=None):
 
     @blacklist(track=True)
     def find_track(self, artist, title=None):
@@ -156,6 +181,67 @@ class PlayerClient(Player):
                                         'title', title))
         return list(tracks)
 
                                         'title', title))
         return list(tracks)
 
+    @bl_artist
+    def search_artist(self, artist):
+        """
+        Search artists based on a fuzzy search in the media library
+            >>> art = Artist(name='the beatles', mbid=<UUID4>) # mbid optional
+            >>> bea = player.search_artist(art)
+            >>> print(bea.names)
+            >>> ['The Beatles', 'Beatles', 'the beatles']
+
+        Returns an Artist object
+        """
+        found = False
+        if artist.mbid:
+            # look for exact search w/ musicbrainz_artistid
+            exact_m = self._client.list('artist', 'musicbrainz_artistid', artist.mbid)
+            if exact_m:
+                [artist.add_alias(name) for name in exact_m]
+                found = True
+        else:
+            artist = Artist(name=artist.name)
+        # then complete with fuzzy search on artist with no musicbrainz_artistid
+        if artist.mbid:
+            # we already performed a lookup on artists with mbid set
+            # search through remaining artists
+            artists = self._cache.get('nombid_artists', [])
+        else:
+            artists = self._cache.get('artists', [])
+        match = get_close_matches(artist.name, artists, 50, 0.73)
+        if not match and not found:
+            return
+        if len(match) > 1:
+            self.log.debug('found close match for "%s": %s' %
+                           (artist, '/'.join(match)))
+        # Does not perform fuzzy matching on short and single word strings
+        # Only lowercased comparison
+        if ' ' not in artist.name and len(artist.name) < 8:
+            for fuzz_art in match:
+                # Regular lowered string comparison
+                if artist.name.lower() == fuzz_art.lower():
+                    artist.add_alias(fuzz_art)
+                    return artist
+        fzartist = SimaStr(artist.name)
+        for fuzz_art in match:
+            # Regular lowered string comparison
+            if artist.name.lower() == fuzz_art.lower():
+                found = True
+                artist.add_alias(fuzz_art)
+                if artist.name != fuzz_art:
+                    self.log.debug('"%s" matches "%s".' % (fuzz_art, artist))
+                continue
+            # SimaStr string __eq__ (not regular string comparison here)
+            if fzartist == fuzz_art:
+                found = True
+                artist.add_alias(fuzz_art)
+                self.log.info('"%s" quite probably matches "%s" (SimaStr)' %
+                              (fuzz_art, artist))
+        if found:
+            if artist.aliases:
+                self.log.debug('Found: {}'.format('/'.join(list(artist.names)[:4])))
+            return artist
+
     def fuzzy_find_track(self, artist, title):
         # Retrieve all tracks from artist
         all_tracks = self.find_track(artist, title)
     def fuzzy_find_track(self, artist, title):
         # Retrieve all tracks from artist
         all_tracks = self.find_track(artist, title)
@@ -196,8 +282,9 @@ class PlayerClient(Player):
                album containing at least a single track for artist
         """
         albums = []
                album containing at least a single track for artist
         """
         albums = []
-        for name in artist.aliases:
-            self.log.debug('Searching album for {}'.format(name))
+        for name in artist.names:
+            if len(artist.names) > 1:
+                self.log.debug('Searching album for aliase: "{}"'.format(name))
             kwalbart = {'albumartist':name, 'artist':name}
             for album in self.list('album', 'albumartist', artist):
                 if album and album not in albums:
             kwalbart = {'albumartist':name, 'artist':name}
             for album in self.list('album', 'albumartist', artist):
                 if album and album not in albums: