示例#1
0
class Similarity(object):
    """Here the actual similarity computation and lookup happens."""
    def __init__(self):
        data_dir = player_get_data_dir()
        self.db_path = os.path.join(data_dir, "similarity.db")
        self.gaia_db_path = os.path.join(data_dir, "gaia.db")
        self.db_queue = PriorityQueue()
        self._db_wrapper = DatabaseWrapper()
        self._db_wrapper.daemon = True
        self._db_wrapper.set_path(self.db_path)
        self._db_wrapper.set_queue(self.db_queue)
        self._db_wrapper.start()
        self.create_db()
        self.network = LastFMNetwork(api_key=API_KEY)
        self.cache_time = 90
        if GAIA:
            self.gaia_queue = LifoQueue()
            self.gaia_analyser = GaiaAnalysis(self.gaia_db_path,
                                              self.gaia_queue)
            self.gaia_analyser.daemon = True
            self.gaia_analyser.start()

    def execute_sql(self, sql=None, priority=1, command=None):
        """Put sql command on the queue to be executed."""
        if command is None:
            command = SQLCommand(sql)
        self.db_queue.put((priority, command))

    def get_sql_command(self, sql, priority=1):
        """Build a SQLCommand, put it on the queue and return it."""
        command = SQLCommand(sql)
        self.execute_sql(command=command, priority=priority)
        return command

    def remove_track_by_filename(self, filename):
        if not filename:
            return
        if GAIA:
            self.gaia_queue.put((REMOVE, filename))

    def get_ordered_gaia_tracks_by_request(self, filename, number, request):
        start_time = time()
        tracks = self.gaia_analyser.get_tracks(filename,
                                               number,
                                               request=request)
        print("finding gaia matches took %f s" % (time() - start_time, ))
        return tracks

    def get_ordered_gaia_tracks(self, filename, number):
        """Get neighbours for track."""
        start_time = time()
        tracks = self.gaia_analyser.get_tracks(filename, number)
        print("finding gaia matches took %f s" % (time() - start_time, ))
        return tracks

    def get_artist(self, artist_name):
        """Get artist information from the database."""
        sql = ("SELECT * FROM artists WHERE name = ?;", (artist_name, ))
        command = self.get_sql_command(sql, priority=1)
        for row in command.result_queue.get():
            return row
        sql2 = ("INSERT INTO artists (name) VALUES (?);", (artist_name, ))
        command = self.get_sql_command(sql2, priority=0)
        command.result_queue.get()
        command = self.get_sql_command(sql, priority=1)
        for row in command.result_queue.get():
            return row

    def get_track_from_artist_and_title(self, artist_name, title):
        """Get track information from the database."""
        artist_id = self.get_artist(artist_name)[0]
        sql = ("SELECT * FROM tracks WHERE artist = ? AND title = ?;",
               (artist_id, title))
        command = self.get_sql_command(sql, priority=3)
        for row in command.result_queue.get():
            return row
        sql2 = ("INSERT INTO tracks (artist, title) VALUES (?, ?);",
                (artist_id, title))
        command = self.get_sql_command(sql2, priority=2)
        command.result_queue.get()
        command = self.get_sql_command(sql, priority=3)
        for row in command.result_queue.get():
            return row

    def get_similar_tracks(self, track_id):
        """Get similar tracks from the database.

        Sorted by descending match score.

        """
        sql = (
            "SELECT track_2_track.match, artists.name, tracks.title"
            " FROM track_2_track INNER JOIN tracks ON"
            " track_2_track.track2 = tracks.id INNER JOIN artists ON"
            " artists.id = tracks.artist WHERE track_2_track.track1 = ? UNION "
            "SELECT track_2_track.match, artists.name, tracks.title"
            " FROM track_2_track INNER JOIN tracks ON"
            " track_2_track.track1 = tracks.id INNER JOIN artists ON"
            " artists.id = tracks.artist WHERE track_2_track.track2"
            " = ? ORDER BY track_2_track.match DESC;", (track_id, track_id))
        command = self.get_sql_command(sql, priority=0)
        return command.result_queue.get()

    def get_similar_artists(self, artist_id):
        """Get similar artists from the database.

        Sorted by descending match score.

        """
        sql = ("SELECT match, name FROM artist_2_artist INNER JOIN"
               " artists ON artist_2_artist.artist2 = artists.id WHERE"
               " artist_2_artist.artist1 = ? UNION "
               "SELECT match, name FROM artist_2_artist INNER JOIN"
               " artists ON artist_2_artist.artist1 = artists.id WHERE"
               " artist_2_artist.artist2 = ? ORDER BY match DESC;",
               (artist_id, artist_id))
        command = self.get_sql_command(sql, priority=0)
        return command.result_queue.get()

    def get_artist_match(self, artist1, artist2):
        """Get artist match score from database."""
        sql = ("SELECT match FROM artist_2_artist WHERE artist1 = ?"
               " AND artist2 = ?;", (artist1, artist2))
        command = self.get_sql_command(sql, priority=2)
        for row in command.result_queue.get():
            return row[0]
        return 0

    def get_track_match(self, track1, track2):
        """Get track match score from database."""
        sql = (
            "SELECT match FROM track_2_track WHERE track1 = ? AND track2 = ?;",
            (track1, track2))
        command = self.get_sql_command(sql, priority=2)
        for row in command.result_queue.get():
            return row[0]
        return 0

    def update_artist_match(self, artist1, artist2, match):
        """Write match score to the database."""
        self.execute_sql(
            ("UPDATE artist_2_artist SET match = ? WHERE artist1 = ? AND"
             " artist2 = ?;", (match, artist1, artist2)),
            priority=10)

    def update_track_match(self, track1, track2, match):
        """Write match score to the database."""
        self.execute_sql(
            ("UPDATE track_2_track SET match = ? WHERE track1 = ? AND"
             " track2 = ?;", (match, track1, track2)),
            priority=10)

    def insert_artist_match(self, artist1, artist2, match):
        """Write match score to the database."""
        self.execute_sql(
            ("INSERT INTO artist_2_artist (artist1, artist2, match) VALUES"
             " (?, ?, ?);", (artist1, artist2, match)),
            priority=10)

    def insert_track_match(self, track1, track2, match):
        """Write match score to the database."""
        self.execute_sql(
            ("INSERT INTO track_2_track (track1, track2, match) VALUES"
             " (?, ?, ?);", (track1, track2, match)),
            priority=10)

    def update_artist(self, artist_id):
        """Write artist information to the database."""
        self.execute_sql(
            ("UPDATE artists SET updated = DATETIME('now') WHERE id = ?;",
             (artist_id, )),
            priority=10)

    def update_track(self, track_id):
        """Write track information to the database."""
        self.execute_sql(
            ("UPDATE tracks SET updated = DATETIME('now') WHERE id = ?",
             (track_id, )),
            priority=10)

    def update_similar_artists(self, artists_to_update):
        """Write similar artist information to the database."""
        for artist_id, similar in list(artists_to_update.items()):
            for artist in similar:
                row = self.get_artist(artist['artist'])
                if row:
                    id2 = row[0]
                    if self.get_artist_match(artist_id, id2):
                        self.update_artist_match(artist_id, id2,
                                                 artist['score'])
                        continue
                    self.insert_artist_match(artist_id, id2, artist['score'])
            self.update_artist(artist_id)

    def update_similar_tracks(self, tracks_to_update):
        """Write similar track information to the database."""
        for track_id, similar in list(tracks_to_update.items()):
            for track in similar:
                row = self.get_track_from_artist_and_title(
                    track['artist'], track['title'])
                if row:
                    id2 = row[0]
                    if self.get_track_match(track_id, id2):
                        self.update_track_match(track_id, id2, track['score'])
                        continue
                    self.insert_track_match(track_id, id2, track['score'])
            self.update_track(track_id)

    def create_db(self):
        """Set up a database for the artist and track similarity scores."""
        self.execute_sql(
            ('CREATE TABLE IF NOT EXISTS artists (id INTEGER PRIMARY KEY, name'
             ' VARCHAR(100), updated DATE, UNIQUE(name));', ),
            priority=0)
        self.execute_sql(
            ('CREATE TABLE IF NOT EXISTS artist_2_artist (artist1 INTEGER,'
             ' artist2 INTEGER, match INTEGER, UNIQUE(artist1, artist2));', ),
            priority=0)
        self.execute_sql((
            'CREATE TABLE IF NOT EXISTS tracks (id INTEGER PRIMARY KEY, artist'
            ' INTEGER, title VARCHAR(100), updated DATE, '
            'UNIQUE(artist, title));', ),
                         priority=0)
        self.execute_sql(
            ('CREATE TABLE IF NOT EXISTS track_2_track (track1 INTEGER, track2'
             ' INTEGER, match INTEGER, UNIQUE(track1, track2));', ),
            priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS a2aa1x ON artist_2_artist "
             "(artist1);", ),
            priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS a2aa2x ON artist_2_artist "
             "(artist2);", ),
            priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS t2tt1x ON track_2_track (track1);", ),
            priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS t2tt2x ON track_2_track (track2);", ),
            priority=0)

    def delete_orphan_artist(self, artist):
        """Delete artists that have no tracks."""
        sql = ('SELECT artists.id FROM artists WHERE artists.name = ? AND '
               'artists.id NOT IN (SELECT tracks.artist from tracks);',
               (artist, ))
        command = self.get_sql_command(sql, priority=10)
        for row in command.result_queue.get():
            artist_id = row[0]
            self.execute_sql(
                ('DELETE FROM artist_2_artist WHERE artist1 = ? OR artist2 = '
                 '?;', (artist_id, artist_id)),
                priority=10)
            self.execute_sql(
                ('DELETE FROM artists WHERE id = ?', (artist_id, )),
                priority=10)

    def analyze_track(self, filename):
        """Perform gaia analysis of a track."""
        if not filename:
            return
        if GAIA:
            self.gaia_queue.put((ADD, filename))

    def analyze_tracks(self, filenames):
        """Analyze audio files."""
        if not filenames:
            return
        if GAIA:
            for filename in filenames:
                self.gaia_queue.put((ADD, filename))

    def get_similar_tracks_from_lastfm(self,
                                       artist_name,
                                       title,
                                       track_id,
                                       cutoff=0):
        """Get similar tracks."""
        try:
            lastfm_track = self.network.get_track(artist_name, title)
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        tracks_to_update = {}
        results = []
        try:
            for similar in lastfm_track.get_similar():
                match = int(100 * similar.match)
                if match <= cutoff:
                    continue
                item = similar.item
                similar_artist = item.artist.get_name()
                similar_title = item.title
                tracks_to_update.setdefault(track_id, []).append({
                    'score':
                    match,
                    'artist':
                    similar_artist,
                    'title':
                    similar_title
                })
                results.append((match, similar_artist, similar_title))
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        self.update_similar_tracks(tracks_to_update)
        return results

    def get_similar_artists_from_lastfm(self,
                                        artist_name,
                                        artist_id,
                                        cutoff=0):
        """Get similar artists from lastfm."""
        try:
            lastfm_artist = self.network.get_artist(artist_name)
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        artists_to_update = {}
        results = []
        try:
            for similar in lastfm_artist.get_similar():
                match = int(100 * similar.match)
                if match <= cutoff:
                    continue
                name = similar.item.get_name()
                artists_to_update.setdefault(artist_id, []).append({
                    'score':
                    match,
                    'artist':
                    name
                })
                results.append((match, name))
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        self.update_similar_artists(artists_to_update)
        return results

    def get_ordered_similar_tracks(self, artist_name, title):
        """Get similar tracks from last.fm/the database.

        Sorted by descending match score.

        """
        now = datetime.now()
        track = self.get_track_from_artist_and_title(artist_name, title)
        track_id, updated = track[0], track[3]
        if updated:
            updated = datetime(*strptime(updated, "%Y-%m-%d %H:%M:%S")[0:6])
            if updated + timedelta(self.cache_time) > now:
                print("Getting similar tracks from db for: %s - %s" %
                      (artist_name, title))
                return self.get_similar_tracks(track_id)
        return self.get_similar_tracks_from_lastfm(artist_name, title,
                                                   track_id)

    def get_ordered_similar_artists(self, artists):
        """Get similar artists from the database.

        Sorted by descending match score.

        """
        results = []
        now = datetime.now()
        for name in artists:
            artist_name = name
            result = None
            artist = self.get_artist(artist_name)
            artist_id, updated = artist[0], artist[2]
            if updated:
                updated = datetime(
                    *strptime(updated, "%Y-%m-%d %H:%M:%S")[0:6])
                if updated + timedelta(self.cache_time) > now:
                    print("Getting similar artists from db for: %s " %
                          artist_name)
                    result = self.get_similar_artists(artist_id)
            if not result:
                result = self.get_similar_artists_from_lastfm(
                    artist_name, artist_id)
            results.extend(result)
        results.sort(reverse=True)
        return results

    def miximize(self, filenames):
        """Return ideally ordered list of filenames."""
        if not GAIA:
            return []

        return self.gaia_analyser.get_miximized_tracks(filenames)
示例#2
0
class Similarity(object):

    """Here the actual similarity computation and lookup happens."""

    def __init__(self):
        data_dir = player_get_data_dir()
        self.db_path = os.path.join(data_dir, "similarity.db")
        self.gaia_db_path = os.path.join(data_dir, "gaia.db")
        self.db_queue = PriorityQueue()
        self._db_wrapper = DatabaseWrapper()
        self._db_wrapper.daemon = True
        self._db_wrapper.set_path(self.db_path)
        self._db_wrapper.set_queue(self.db_queue)
        self._db_wrapper.start()
        self.create_db()
        self.network = LastFMNetwork(api_key=API_KEY)
        self.cache_time = 90
        if GAIA:
            self.gaia_queue = LifoQueue()
            self.gaia_analyser = GaiaAnalysis(
                self.gaia_db_path, self.gaia_queue)
            self.gaia_analyser.daemon = True
            self.gaia_analyser.start()

    def execute_sql(self, sql=None, priority=1, command=None):
        """Put sql command on the queue to be executed."""
        if command is None:
            command = SQLCommand(sql)
        self.db_queue.put((priority, command))

    def get_sql_command(self, sql, priority=1):
        """Build a SQLCommand, put it on the queue and return it."""
        command = SQLCommand(sql)
        self.execute_sql(command=command, priority=priority)
        return command

    def remove_track_by_filename(self, filename):
        if not filename:
            return
        if GAIA:
            self.gaia_queue.put((REMOVE, filename))

    def get_ordered_gaia_tracks_by_request(self, filename, number, request):
        start_time = time()
        tracks = self.gaia_analyser.get_tracks(
            filename, number, request=request)
        print("finding gaia matches took %f s" % (time() - start_time,))
        return tracks

    def get_ordered_gaia_tracks(self, filename, number):
        """Get neighbours for track."""
        start_time = time()
        tracks = self.gaia_analyser.get_tracks(filename, number)
        print("finding gaia matches took %f s" % (time() - start_time,))
        return tracks

    def get_artist(self, artist_name):
        """Get artist information from the database."""
        sql = ("SELECT * FROM artists WHERE name = ?;", (artist_name,))
        command = self.get_sql_command(sql, priority=1)
        for row in command.result_queue.get():
            return row
        sql2 = ("INSERT INTO artists (name) VALUES (?);", (artist_name,))
        command = self.get_sql_command(sql2, priority=0)
        command.result_queue.get()
        command = self.get_sql_command(sql, priority=1)
        for row in command.result_queue.get():
            return row

    def get_track_from_artist_and_title(self, artist_name, title):
        """Get track information from the database."""
        artist_id = self.get_artist(artist_name)[0]
        sql = (
            "SELECT * FROM tracks WHERE artist = ? AND title = ?;",
            (artist_id, title))
        command = self.get_sql_command(sql, priority=3)
        for row in command.result_queue.get():
            return row
        sql2 = (
            "INSERT INTO tracks (artist, title) VALUES (?, ?);",
            (artist_id, title))
        command = self.get_sql_command(sql2, priority=2)
        command.result_queue.get()
        command = self.get_sql_command(sql, priority=3)
        for row in command.result_queue.get():
            return row

    def get_similar_tracks(self, track_id):
        """Get similar tracks from the database.

        Sorted by descending match score.

        """
        sql = (
            "SELECT track_2_track.match, artists.name, tracks.title"
            " FROM track_2_track INNER JOIN tracks ON"
            " track_2_track.track2 = tracks.id INNER JOIN artists ON"
            " artists.id = tracks.artist WHERE track_2_track.track1 = ? UNION "
            "SELECT track_2_track.match, artists.name, tracks.title"
            " FROM track_2_track INNER JOIN tracks ON"
            " track_2_track.track1 = tracks.id INNER JOIN artists ON"
            " artists.id = tracks.artist WHERE track_2_track.track2"
            " = ? ORDER BY track_2_track.match DESC;",
            (track_id, track_id))
        command = self.get_sql_command(sql, priority=0)
        return command.result_queue.get()

    def get_similar_artists(self, artist_id):
        """Get similar artists from the database.

        Sorted by descending match score.

        """
        sql = (
            "SELECT match, name FROM artist_2_artist INNER JOIN"
            " artists ON artist_2_artist.artist2 = artists.id WHERE"
            " artist_2_artist.artist1 = ? UNION "
            "SELECT match, name FROM artist_2_artist INNER JOIN"
            " artists ON artist_2_artist.artist1 = artists.id WHERE"
            " artist_2_artist.artist2 = ? ORDER BY match DESC;",
            (artist_id, artist_id))
        command = self.get_sql_command(sql, priority=0)
        return command.result_queue.get()

    def get_artist_match(self, artist1, artist2):
        """Get artist match score from database."""
        sql = (
            "SELECT match FROM artist_2_artist WHERE artist1 = ?"
            " AND artist2 = ?;",
            (artist1, artist2))
        command = self.get_sql_command(sql, priority=2)
        for row in command.result_queue.get():
            return row[0]
        return 0

    def get_track_match(self, track1, track2):
        """Get track match score from database."""
        sql = (
            "SELECT match FROM track_2_track WHERE track1 = ? AND track2 = ?;",
            (track1, track2))
        command = self.get_sql_command(sql, priority=2)
        for row in command.result_queue.get():
            return row[0]
        return 0

    def update_artist_match(self, artist1, artist2, match):
        """Write match score to the database."""
        self.execute_sql((
            "UPDATE artist_2_artist SET match = ? WHERE artist1 = ? AND"
            " artist2 = ?;",
            (match, artist1, artist2)), priority=10)

    def update_track_match(self, track1, track2, match):
        """Write match score to the database."""
        self.execute_sql((
            "UPDATE track_2_track SET match = ? WHERE track1 = ? AND"
            " track2 = ?;",
            (match, track1, track2)), priority=10)

    def insert_artist_match(self, artist1, artist2, match):
        """Write match score to the database."""
        self.execute_sql((
            "INSERT INTO artist_2_artist (artist1, artist2, match) VALUES"
            " (?, ?, ?);",
            (artist1, artist2, match)), priority=10)

    def insert_track_match(self, track1, track2, match):
        """Write match score to the database."""
        self.execute_sql((
            "INSERT INTO track_2_track (track1, track2, match) VALUES"
            " (?, ?, ?);",
            (track1, track2, match)), priority=10)

    def update_artist(self, artist_id):
        """Write artist information to the database."""
        self.execute_sql((
            "UPDATE artists SET updated = DATETIME('now') WHERE id = ?;",
            (artist_id,)), priority=10)

    def update_track(self, track_id):
        """Write track information to the database."""
        self.execute_sql((
            "UPDATE tracks SET updated = DATETIME('now') WHERE id = ?",
            (track_id,)), priority=10)

    def update_similar_artists(self, artists_to_update):
        """Write similar artist information to the database."""
        for artist_id, similar in list(artists_to_update.items()):
            for artist in similar:
                row = self.get_artist(artist['artist'])
                if row:
                    id2 = row[0]
                    if self.get_artist_match(artist_id, id2):
                        self.update_artist_match(
                            artist_id, id2, artist['score'])
                        continue
                    self.insert_artist_match(artist_id, id2, artist['score'])
            self.update_artist(artist_id)

    def update_similar_tracks(self, tracks_to_update):
        """Write similar track information to the database."""
        for track_id, similar in list(tracks_to_update.items()):
            for track in similar:
                row = self.get_track_from_artist_and_title(
                    track['artist'], track['title'])
                if row:
                    id2 = row[0]
                    if self.get_track_match(track_id, id2):
                        self.update_track_match(track_id, id2, track['score'])
                        continue
                    self.insert_track_match(track_id, id2, track['score'])
            self.update_track(track_id)

    def create_db(self):
        """Set up a database for the artist and track similarity scores."""
        self.execute_sql((
            'CREATE TABLE IF NOT EXISTS artists (id INTEGER PRIMARY KEY, name'
            ' VARCHAR(100), updated DATE, UNIQUE(name));',), priority=0)
        self.execute_sql(
            ('CREATE TABLE IF NOT EXISTS artist_2_artist (artist1 INTEGER,'
             ' artist2 INTEGER, match INTEGER, UNIQUE(artist1, artist2));',),
            priority=0)
        self.execute_sql((
            'CREATE TABLE IF NOT EXISTS tracks (id INTEGER PRIMARY KEY, artist'
            ' INTEGER, title VARCHAR(100), updated DATE, '
            'UNIQUE(artist, title));',), priority=0)
        self.execute_sql((
            'CREATE TABLE IF NOT EXISTS track_2_track (track1 INTEGER, track2'
            ' INTEGER, match INTEGER, UNIQUE(track1, track2));',), priority=0)
        self.execute_sql((
            "CREATE INDEX IF NOT EXISTS a2aa1x ON artist_2_artist "
            "(artist1);",), priority=0)
        self.execute_sql((
            "CREATE INDEX IF NOT EXISTS a2aa2x ON artist_2_artist "
            "(artist2);",), priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS t2tt1x ON track_2_track (track1);",),
            priority=0)
        self.execute_sql(
            ("CREATE INDEX IF NOT EXISTS t2tt2x ON track_2_track (track2);",),
            priority=0)

    def delete_orphan_artist(self, artist):
        """Delete artists that have no tracks."""
        sql = (
            'SELECT artists.id FROM artists WHERE artists.name = ? AND '
            'artists.id NOT IN (SELECT tracks.artist from tracks);',
            (artist,))
        command = self.get_sql_command(sql, priority=10)
        for row in command.result_queue.get():
            artist_id = row[0]
            self.execute_sql((
                'DELETE FROM artist_2_artist WHERE artist1 = ? OR artist2 = '
                '?;', (artist_id, artist_id)), priority=10)
            self.execute_sql(
                ('DELETE FROM artists WHERE id = ?', (artist_id,)),
                priority=10)

    def analyze_track(self, filename):
        """Perform gaia analysis of a track."""
        if not filename:
            return
        if GAIA:
            self.gaia_queue.put((ADD, filename))

    def analyze_tracks(self, filenames):
        """Analyze audio files."""
        if not filenames:
            return
        if GAIA:
            for filename in filenames:
                self.gaia_queue.put((ADD, filename))

    def get_similar_tracks_from_lastfm(self, artist_name, title, track_id,
                                       cutoff=0):
        """Get similar tracks."""
        try:
            lastfm_track = self.network.get_track(artist_name, title)
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        tracks_to_update = {}
        results = []
        try:
            for similar in lastfm_track.get_similar():
                match = int(100 * similar.match)
                if match <= cutoff:
                    continue
                item = similar.item
                similar_artist = item.artist.get_name()
                similar_title = item.title
                tracks_to_update.setdefault(track_id, []).append({
                    'score': match,
                    'artist': similar_artist,
                    'title': similar_title})
                results.append((match, similar_artist, similar_title))
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        self.update_similar_tracks(tracks_to_update)
        return results

    def get_similar_artists_from_lastfm(self, artist_name, artist_id,
                                        cutoff=0):
        """Get similar artists from lastfm."""
        try:
            lastfm_artist = self.network.get_artist(artist_name)
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        artists_to_update = {}
        results = []
        try:
            for similar in lastfm_artist.get_similar():
                match = int(100 * similar.match)
                if match <= cutoff:
                    continue
                name = similar.item.get_name()
                artists_to_update.setdefault(artist_id, []).append({
                    'score': match,
                    'artist': name})
                results.append((match, name))
        except (WSError, NetworkError, MalformedResponseError) as e:
            print(e)
            return []
        self.update_similar_artists(artists_to_update)
        return results

    def get_ordered_similar_tracks(self, artist_name, title):
        """Get similar tracks from last.fm/the database.

        Sorted by descending match score.

        """
        now = datetime.now()
        track = self.get_track_from_artist_and_title(
            artist_name, title)
        track_id, updated = track[0], track[3]
        if updated:
            updated = datetime(*strptime(updated, "%Y-%m-%d %H:%M:%S")[0:6])
            if updated + timedelta(self.cache_time) > now:
                print(
                    "Getting similar tracks from db for: %s - %s" % (
                        artist_name, title))
                return self.get_similar_tracks(track_id)
        return self.get_similar_tracks_from_lastfm(
            artist_name, title, track_id)

    def get_ordered_similar_artists(self, artists):
        """Get similar artists from the database.

        Sorted by descending match score.

        """
        results = []
        now = datetime.now()
        for name in artists:
            artist_name = name
            result = None
            artist = self.get_artist(artist_name)
            artist_id, updated = artist[0], artist[2]
            if updated:
                updated = datetime(
                    *strptime(updated, "%Y-%m-%d %H:%M:%S")[0:6])
                if updated + timedelta(self.cache_time) > now:
                    print(
                        "Getting similar artists from db for: %s " %
                        artist_name)
                    result = self.get_similar_artists(artist_id)
            if not result:
                result = self.get_similar_artists_from_lastfm(
                    artist_name, artist_id)
            results.extend(result)
        results.sort(reverse=True)
        return results

    def miximize(self, filenames):
        """Return ideally ordered list of filenames."""
        if not GAIA:
            return []

        return self.gaia_analyser.get_miximized_tracks(filenames)
示例#3
0
class LastFm:
    # You have to have your own unique two values for API_KEY and API_SECRET
    # Obtain yours from http://www.last.fm/api/account for Last.fm
    # API_KEY = '2b532992c84242d372f5c0044d6883e5'
    # API_SECRET = '3c6688ac84deda063a697f5662a93eb0'
    API_KEY = '8fc05a68240dadf4c2430392768053fe'
    API_SECRET = 'bc2d48b14f3e864c6a07bbb6f9a0b690'
    URL_AUTH = 'http://www.last.fm/api/auth/?api_key={}'.format(API_KEY)
    URL_CALLBACK = 'http%3A%2F%2F127.0.0.1%3A5656%2Flastfm%2Fcallback'

    network = None
    LOVE_CUTOFF = 0.97

    def __init__(self, token=''):
        """Always create network"""
        with shelve.open('lastfm') as db:
            session_key = db.get('session_key')

            self.network = LastFMNetwork(
                api_key=self.API_KEY,
                api_secret=self.API_SECRET,
                session_key=session_key,
                token=token
            )

            if token:
                app.logger.info('saving session key: {}'.format(self.network.session_key))
                db['session_key'] = self.network.session_key

    def scrobble(self, history):
        """Scrobble song to lastfm"""
        params = {
            'artist': history.song.artist.name,
            'album': history.song.album.name,
            'title': history.song.name,
            'track_number': history.song.track_number,
            'timestamp': int(history.played_at.timestamp()),
        }
        app.logger.info('scrobbling: {}'.format(params))
        self.network.scrobble(**params)

    def show_some_love(self, songs):
        """Sets track to love or not"""
        app.logger.info('showing some love for {} songs'.format(len(songs)))
        for song in songs:
            db.session.refresh(song)
            network_track = self.network.get_track(song.artist.name, song.name)
            is_loved = song.rating >= self.LOVE_CUTOFF
            app.logger.debug('[{:.0f}%] {} loving {}'.format(
                song.rating * 100, is_loved, network_track))
            if is_loved:
                network_track.love()
            else:
                network_track.unlove()
            # is_loved = network_track.get_userloved()
            # app.logger.debug('found network track {} loved {}'.format(network_track, is_loved))
            # if is_loved:
            #     if song.rating < self.LOVE_CUTOFF:
            #         app.logger.info('lost love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.unlove()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still loving {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                          100))
            # else:
            #     res = network_track.unlove()
            #     app.logger.debug(res)
            #     if song.rating >= self.LOVE_CUTOFF:
            #         app.logger.info('new love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.love()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still no love for {} [{:.0f}%]'.format(network_track,
            #                                                              song.rating * 100))

    def get_user_top_albums(self, user_name, period=None):
        """Get top albums for user"""
        period = period or PERIOD_12MONTHS
        user = self.network.get_user(user_name)
        return user.get_top_albums(period)

    def get_user_playcount(self, user):
        """Get playcount of user"""

    def get_similar_tracks(self, artist, title):
        """Get similar tracks to this song"""
        track = self.network.get_track(artist, title)
        similar = track.get_similar()
        app.logger.info('Found {} similar tracks for {} {}'.format(len(similar), artist, title))
        return similar
示例#4
0
class LastFm:
    # You have to have your own unique two values for API_KEY and API_SECRET
    # Obtain yours from http://www.last.fm/api/account for Last.fm
    # API_KEY = '2b532992c84242d372f5c0044d6883e5'
    # API_SECRET = '3c6688ac84deda063a697f5662a93eb0'
    API_KEY = '8fc05a68240dadf4c2430392768053fe'
    API_SECRET = 'bc2d48b14f3e864c6a07bbb6f9a0b690'
    URL_AUTH = 'http://www.last.fm/api/auth/?api_key={}'.format(API_KEY)
    URL_CALLBACK = 'http%3A%2F%2F127.0.0.1%3A5656%2Flastfm%2Fcallback'

    network = None
    LOVE_CUTOFF = 0.97

    def __init__(self, token=''):
        """Always create network"""
        with shelve.open('lastfm') as db:
            session_key = db.get('session_key')

            self.network = LastFMNetwork(api_key=self.API_KEY,
                                         api_secret=self.API_SECRET,
                                         session_key=session_key,
                                         token=token)

            if token:
                app.logger.info('saving session key: {}'.format(
                    self.network.session_key))
                db['session_key'] = self.network.session_key

    def scrobble(self, history):
        """Scrobble song to lastfm"""
        params = {
            'artist': history.song.artist.name,
            'album': history.song.album.name,
            'title': history.song.name,
            'track_number': history.song.track_number,
            'timestamp': int(history.played_at.timestamp()),
        }
        app.logger.info('scrobbling: {}'.format(params))
        self.network.scrobble(**params)

    def show_some_love(self, songs):
        """Sets track to love or not"""
        app.logger.info('showing some love for {} songs'.format(len(songs)))
        for song in songs:
            db.session.refresh(song)
            network_track = self.network.get_track(song.artist.name, song.name)
            is_loved = song.rating >= self.LOVE_CUTOFF
            app.logger.debug('[{:.0f}%] {} loving {}'.format(
                song.rating * 100, is_loved, network_track))
            if is_loved:
                network_track.love()
            else:
                network_track.unlove()
            # is_loved = network_track.get_userloved()
            # app.logger.debug('found network track {} loved {}'.format(network_track, is_loved))
            # if is_loved:
            #     if song.rating < self.LOVE_CUTOFF:
            #         app.logger.info('lost love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.unlove()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still loving {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                          100))
            # else:
            #     res = network_track.unlove()
            #     app.logger.debug(res)
            #     if song.rating >= self.LOVE_CUTOFF:
            #         app.logger.info('new love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.love()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still no love for {} [{:.0f}%]'.format(network_track,
            #                                                              song.rating * 100))

    def get_user_top_albums(self, user_name, period=None):
        """Get top albums for user"""
        period = period or PERIOD_12MONTHS
        user = self.network.get_user(user_name)
        return user.get_top_albums(period)

    def get_user_playcount(self, user):
        """Get playcount of user"""

    def get_similar_tracks(self, artist, title):
        """Get similar tracks to this song"""
        track = self.network.get_track(artist, title)
        similar = track.get_similar()
        app.logger.info('Found {} similar tracks for {} {}'.format(
            len(similar), artist, title))
        return similar