diff --git a/app/api/artist.py b/app/api/artist.py index 002a2df..a183a4b 100644 --- a/app/api/artist.py +++ b/app/api/artist.py @@ -1,6 +1,7 @@ """ Contains all the artist(s) routes. """ +import random from collections import deque from flask import Blueprint, request @@ -9,6 +10,7 @@ from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.store import Store from app.models import Album, FavType, Track from app.utils.remove_duplicates import remove_duplicates +from app.requests.artists import fetch_similar_artists api = Blueprint("artist", __name__, url_prefix="/") @@ -267,61 +269,36 @@ def get_artist_albums(artisthash: str): @api.route("/artist//tracks", methods=["GET"]) -def get_artist_tracks(artisthash: str): +def get_all_artist_tracks(artisthash: str): """ Returns all artists by a given artist. """ tracks = Store.get_tracks_by_artist(artisthash) return {"tracks": tracks} - # artist = Store.get_artist_by_hash(artisthash) - # if artist is None: - # return {"error": "Artist not found"}, 404 - # return {"albums": albums[:limit]} -# @artist_bp.route("/artist/") -# @cache.cached() -# def get_artist_data(artist: str): -# """Returns the artist's data, tracks and albums""" -# artist = urllib.parse.unquote(artist) -# artist_obj = instances.artist_instance.get_artists_by_name(artist) +@api.route("/artist//similar", methods=["GET"]) +def get_similar_artists(artisthash: str): + """ + Returns similar artists. + """ + limit = request.args.get("limit") -# def get_artist_tracks(): -# songs = instances.tracks_instance.find_songs_by_artist(artist) + if limit is None: + limit = 6 -# return songs + limit = int(limit) -# artist_songs = get_artist_tracks() -# songs = utils.remove_duplicates(artist_songs) + artist = Store.get_artist_by_hash(artisthash) -# def get_artist_albums(): -# artist_albums = [] -# albums_with_count = [] + if artist is None: + return {"error": "Artist not found"}, 404 -# albums = instances.tracks_instance.find_songs_by_albumartist(artist) + similar_hashes = fetch_similar_artists(artist.name) + similar = Store.get_artists_by_hashes(similar_hashes) -# for song in albums: -# if song["album"] not in artist_albums: -# artist_albums.append(song["album"]) + if len(similar) > limit: + similar = random.sample(similar, limit) -# for album in artist_albums: -# count = 0 -# length = 0 - -# for song in artist_songs: -# if song["album"] == album: -# count = count + 1 -# length = length + song["length"] - -# album_ = {"title": album, "count": count, "length": length} - -# albums_with_count.append(album_) - -# return albums_with_count - -# return { -# "artist": artist_obj, -# "songs": songs, -# "albums": get_artist_albums() -# } + return {"similar": similar[:limit]} diff --git a/app/db/store.py b/app/db/store.py index 3b440b5..8722133 100644 --- a/app/db/store.py +++ b/app/db/store.py @@ -329,7 +329,7 @@ class Store: @classmethod def get_albums_by_albumartist( - cls, artisthash: str, limit: int, exclude: str + cls, artisthash: str, limit: int, exclude: str ) -> list[Album]: """ Returns N albums by the given albumartist, excluding the specified album. @@ -440,12 +440,21 @@ class Store: @classmethod def get_artist_by_hash(cls, artisthash: str) -> Artist: """ - Returns an artist by its hash. + Returns an artist by its hash.P """ artists = sorted(cls.artists, key=lambda x: x.artisthash) artist = UseBisection(artists, "artisthash", [artisthash])()[0] return artist + @classmethod + def get_artists_by_hashes(cls, artisthashes: list[str]) -> list[Artist]: + """ + Returns artists by their hashes. + """ + artists = sorted(cls.artists, key=lambda x: x.artisthash) + artists = UseBisection(artists, "artisthash", artisthashes)() + return [a for a in artists if a is not None] + @classmethod def artist_exists(cls, artisthash: str) -> bool: """ diff --git a/app/requests/__init__.py b/app/requests/__init__.py new file mode 100644 index 0000000..3ad3e9d --- /dev/null +++ b/app/requests/__init__.py @@ -0,0 +1,3 @@ +""" +All network requests are defined here. +""" diff --git a/app/requests/artists.py b/app/requests/artists.py new file mode 100644 index 0000000..6564211 --- /dev/null +++ b/app/requests/artists.py @@ -0,0 +1,24 @@ +""" +Requests related to artists +""" +import requests + +from app import settings +from app.utils.hashing import create_hash + + +def fetch_similar_artists(name: str): + """ + Fetches similar artists from Last.fm + """ + url = f"https://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist={name}&api_key=" \ + f"{settings.Keys.LASTFM_API_KEY}&format=json&limit=100" + + response = requests.get(url, timeout=10) + response.raise_for_status() + + data = response.json() + artists = data["similarartists"]["artist"] + + for artist in artists: + yield create_hash(artist["name"]) diff --git a/app/settings.py b/app/settings.py index 56cf0fe..ff07760 100644 --- a/app/settings.py +++ b/app/settings.py @@ -125,3 +125,6 @@ class TCOLOR: # credits: https://stackoverflow.com/a/287944 +class Keys: + # get last fm api key from os environment + LASTFM_API_KEY = os.environ.get("LASTFM_API_KEY") diff --git a/app/utils/network.py b/app/utils/network.py index 3682c71..4eaa124 100644 --- a/app/utils/network.py +++ b/app/utils/network.py @@ -26,3 +26,4 @@ def get_ip(): soc.close() return ip_address +