api/endpoints/lastfm.py
2025-02-18 14:57:05 -05:00

178 lines
6.6 KiB
Python

import importlib
import traceback
from typing import Optional, Union
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from .constructors import ValidArtistSearchRequest, ValidAlbumDetailRequest,\
ValidTrackInfoRequest, LastFMException
class LastFM(FastAPI):
"""Last.FM Endpoints"""
def __init__(self, app: FastAPI,
util, constants) -> None:
self.app: FastAPI = app
self.util = util
self.constants = constants
self.lastfm = importlib.import_module("utils.lastfm_wrapper").LastFM()
self.endpoints: dict = {
"lastfm/get_artist_by_name": self.artist_by_name_handler,
"lastfm/get_artist_albums": self.artist_album_handler,
"lastfm/get_release": self.release_detail_handler,
"lastfm/get_release_tracklist": self.release_tracklist_handler,
"lastfm/get_track_info": self.track_info_handler,
#tbd
}
for endpoint, handler in self.endpoints.items():
app.add_api_route(f"/{endpoint}", handler, methods=["POST"],
include_in_schema=True)
async def artist_by_name_handler(self, data: ValidArtistSearchRequest) -> JSONResponse:
"""
Get artist info
- **a**: Artist to search
"""
artist: Optional[str] = data.a.strip()
if not artist:
return JSONResponse(content={
'err': True,
'errorText': 'No artist specified',
})
artist_result = await self.lastfm.search_artist(artist=artist)
if not artist_result or "err" in artist_result.keys():
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Search failed (no results?)',
})
return JSONResponse(content={
'success': True,
'result': artist_result,
})
async def artist_album_handler(self, data: ValidArtistSearchRequest) -> JSONResponse:
"""
Get artist's albums/releases
- **a**: Artist to search
"""
artist: str = data.a.strip()
if not artist:
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Invalid request: No artist specified',
})
album_result: Union[dict, list[dict]] = await self.lastfm.get_artist_albums(artist=artist)
if isinstance(album_result, dict):
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'General failure.',
})
album_result_out: list = []
seen_release_titles: list = []
for release in album_result:
release_title: str = release.get('title', 'Unknown')
if release_title.lower() in seen_release_titles:
continue
seen_release_titles.append(release_title.lower())
album_result_out.append(release)
return JSONResponse(content={
'success': True,
'result': album_result_out
})
async def release_detail_handler(self, data: ValidAlbumDetailRequest) -> JSONResponse:
"""
Get details of a particular release by an artist
- **a**: Artist to search
- **release**: Release title to search
"""
artist: str = data.a.strip()
release: str = data.release.strip()
if not artist or not release:
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Invalid request',
})
release_result = await self.lastfm.get_release(artist=artist, album=release)
ret_obj = {
'id': release_result.get('id'),
'artists': release_result.get('artists'),
'title': release_result.get('title'),
'summary': release_result.get('summary'),
'tracks': release_result.get('tracks'),
}
return JSONResponse(content={
'success': True,
'result': ret_obj,
})
async def release_tracklist_handler(self, data: ValidAlbumDetailRequest) -> JSONResponse:
"""
Get track list for a particular release by an artist
- **a**: Artist to search
- **release**: Release title to search
"""
artist: str = data.a.strip()
release: str = data.release.strip()
if not artist or not release:
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Invalid request',
})
tracklist_result: dict = await self.lastfm.get_album_tracklist(artist=artist, album=release)
return JSONResponse(content={
'success': True,
'id': tracklist_result.get('id'),
'artists': tracklist_result.get('artists'),
'title': tracklist_result.get('title'),
'summary': tracklist_result.get('summary'),
'tracks': tracklist_result.get('tracks'),
})
async def track_info_handler(self, data: ValidTrackInfoRequest) -> JSONResponse:
"""
Get track info from Last.FM given an artist/track
- **a**: Artist to search
- **t**: Track title to search
"""
try:
artist: str = data.a
track: str = data.t
if not artist or not track:
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Invalid request'
})
track_info_result: Optional[dict] = await self.lastfm.get_track_info(artist=artist,
track=track)
if not track_info_result:
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'Not found.',
})
if "err" in track_info_result:
raise LastFMException("Unknown error occurred: %s",
track_info_result.get('errorText', '??'))
return JSONResponse(content={
'success': True,
'result': track_info_result
})
except:
traceback.print_exc()
return JSONResponse(status_code=500, content={
'err': True,
'errorText': 'General error',
})