Move server code to this repo (#95)

move server code to this repo
This commit is contained in:
Mungai Njoroge
2023-01-13 20:01:52 +03:00
committed by GitHub
parent dd257e919d
commit 198957bcae
318 changed files with 6259 additions and 16797 deletions
+323
View File
@@ -0,0 +1,323 @@
"""
Contains all the artist(s) routes.
"""
from collections import deque
from flask import Blueprint, request
from app.db.store import Store
from app.models import Album, FavType, Track
from app.utils import remove_duplicates
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
artistbp = Blueprint("artist", __name__, url_prefix="/")
class CacheEntry:
"""
The cache entry class for the artists cache.
"""
def __init__(
self, artisthash: str, albumhashes: set[str], tracks: list[Track]
) -> None:
self.albums: list[Album] = []
self.tracks: list[Track] = []
self.artisthash: str = artisthash
self.albumhashes: set[str] = albumhashes
if len(tracks) > 0:
self.tracks: list[Track] = tracks
self.type_checked = False
self.albums_fetched = False
class ArtistsCache:
"""
Holds artist page cache.
"""
artists: deque[CacheEntry] = deque(maxlen=6)
@classmethod
def get_albums_by_artisthash(cls, artisthash: str):
"""
Returns the cached albums for the given artisthash.
"""
for (index, albums) in enumerate(cls.artists):
if albums.artisthash == artisthash:
return (albums.albums, index)
return ([], -1)
@classmethod
def albums_cached(cls, artisthash: str) -> bool:
"""
Returns True if the artist is in the cache.
"""
for entry in cls.artists:
if entry.artisthash == artisthash and len(entry.albums) > 0:
return True
return False
@classmethod
def albums_fetched(cls, artisthash: str):
"""
Checks if the albums have been fetched for the given artisthash.
"""
for entry in cls.artists:
if entry.artisthash == artisthash:
return entry.albums_fetched
@classmethod
def tracks_cached(cls, artisthash: str) -> bool:
"""
Checks if the tracks have been cached for the given artisthash.
"""
for entry in cls.artists:
if entry.artisthash == artisthash and len(entry.tracks) > 0:
return True
return False
@classmethod
def add_entry(cls, artisthash: str, albumhashes: set[str], tracks: list[Track]):
"""
Adds a new entry to the cache.
"""
cls.artists.append(CacheEntry(artisthash, albumhashes, tracks))
@classmethod
def get_tracks(cls, artisthash: str):
"""
Returns the cached tracks for the given artisthash.
"""
entry = [a for a in cls.artists if a.artisthash == artisthash][0]
return entry.tracks
@classmethod
def get_albums(cls, artisthash: str):
"""
Returns the cached albums for the given artisthash.
"""
entry = [a for a in cls.artists if a.artisthash == artisthash][0]
albums = [Store.get_album_by_hash(h) for h in entry.albumhashes]
entry.albums = [album for album in albums if album is not None]
store_albums = Store.get_albums_by_artisthash(artisthash)
all_albums_hash = "-".join([a.albumhash for a in entry.albums])
for album in store_albums:
if album.albumhash not in all_albums_hash:
entry.albums.append(album)
entry.albums_fetched = True
@classmethod
def process_album_type(cls, artisthash: str):
"""
Checks the cached albums type for the given artisthash.
"""
entry = [a for a in cls.artists if a.artisthash == artisthash][0]
for album in entry.albums:
album.check_type()
album_tracks = Store.get_tracks_by_albumhash(album.albumhash)
album_tracks = remove_duplicates(album_tracks)
album.check_is_single(album_tracks)
entry.type_checked = True
def add_albums_to_cache(artisthash: str):
"""
Fetches albums and adds them to the cache.
"""
tracks = Store.get_tracks_by_artist(artisthash)
if len(tracks) == 0:
return False
albumhashes = set(t.albumhash for t in tracks)
ArtistsCache.add_entry(artisthash, albumhashes, [])
return True
# =======================================================
# ===================== ROUTES ==========================
# =======================================================
@artistbp.route("/artist/<artisthash>", methods=["GET"])
def get_artist(artisthash: str):
"""
Get artist data.
"""
limit = request.args.get("limit")
if limit is None:
limit = 6
limit = int(limit)
artist = Store.get_artist_by_hash(artisthash)
if artist is None:
return {"error": "Artist not found"}, 404
tracks_cached = ArtistsCache.tracks_cached(artisthash)
if tracks_cached:
tracks = ArtistsCache.get_tracks(artisthash)
else:
tracks = Store.get_tracks_by_artist(artisthash)
albumhashes = set(t.albumhash for t in tracks)
hashes_from_albums = set(
a.albumhash for a in Store.get_albums_by_artisthash(artisthash)
)
albumhashes = albumhashes.union(hashes_from_albums)
ArtistsCache.add_entry(artisthash, albumhashes, tracks)
tcount = len(tracks)
acount = Store.count_albums_by_artisthash(artisthash)
if acount == 0 and tcount < 10:
limit = tcount
artist.trackcount = tcount
artist.albumcount = acount
artist.duration = sum(t.duration for t in tracks)
artist.is_favorite = favdb.check_is_favorite(artisthash, FavType.artist)
return {"artist": artist, "tracks": tracks[:limit]}
@artistbp.route("/artist/<artisthash>/albums", methods=["GET"])
def get_artist_albums(artisthash: str):
limit = request.args.get("limit")
if limit is None:
limit = 6
return_all = request.args.get("all")
limit = int(limit)
all_albums = []
is_cached = ArtistsCache.albums_cached(artisthash)
if not is_cached:
add_albums_to_cache(artisthash)
albums_fetched = ArtistsCache.albums_fetched(artisthash)
if not albums_fetched:
ArtistsCache.get_albums(artisthash)
all_albums, index = ArtistsCache.get_albums_by_artisthash(artisthash)
if not ArtistsCache.artists[index].type_checked:
ArtistsCache.process_album_type(artisthash)
singles = [a for a in all_albums if a.is_single]
eps = [a for a in all_albums if a.is_EP]
def remove_EPs_and_singles(albums: list[Album]):
albums = [a for a in albums if not a.is_EP]
albums = [a for a in albums if not a.is_single]
return albums
albums = filter(lambda a: artisthash in a.albumartisthash, all_albums)
albums = list(albums)
albums = remove_EPs_and_singles(albums)
appearances = filter(lambda a: artisthash not in a.albumartisthash, all_albums)
appearances = list(appearances)
appearances = remove_EPs_and_singles(appearances)
artist = Store.get_artist_by_hash(artisthash)
if return_all is not None:
limit = len(all_albums)
return {
"artistname": artist.name,
"albums": albums[:limit],
"singles": singles[:limit],
"eps": eps[:limit],
"appearances": appearances[:limit],
}
@artistbp.route("/artist/<artisthash>/tracks", methods=["GET"])
def get_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/<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)
# def get_artist_tracks():
# songs = instances.tracks_instance.find_songs_by_artist(artist)
# return songs
# artist_songs = get_artist_tracks()
# songs = utils.remove_duplicates(artist_songs)
# def get_artist_albums():
# artist_albums = []
# albums_with_count = []
# albums = instances.tracks_instance.find_songs_by_albumartist(artist)
# for song in albums:
# if song["album"] not in artist_albums:
# artist_albums.append(song["album"])
# 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()
# }