diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..80eddd8 --- /dev/null +++ b/app/main.py @@ -0,0 +1,94 @@ +import secrets +from spotipy.oauth2 import SpotifyOAuth +from dotenv import load_dotenv +import os +from fastapi import FastAPI, Form, Request, Depends +from fastapi.responses import RedirectResponse +from fastapi.middleware.cors import CORSMiddleware +from starlette.middleware.sessions import SessionMiddleware +from session_cache_handler import SessionCacheHandler +from fastapi.templating import Jinja2Templates +from typing import Annotated + +# Jinja2 template engine +templates = Jinja2Templates(directory="templates") + + +load_dotenv("../.env") +CLIENT_SECRET = os.environ.get("CLIENT_SECRET") +CLIENT_ID = os.environ.get("CLIENT_ID") +REDIRECT_URI = os.environ.get("REDIRECT_URI") + +app = FastAPI() # FastAPI instance +# Middlewares +app.add_middleware(SessionMiddleware, secret_key=secrets.token_urlsafe(32)) +# For more info on CORS: https://fastapi.tiangolo.com/tutorial/cors/?h=cors +origins = [ + "http://localhost:3000", + "http://localhost:8000", +] +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +# Dependencies +def get_spotify_oauth(request: Request): + return SpotifyOAuth( + scope="user-library-modify", + client_id=CLIENT_ID, + client_secret=CLIENT_SECRET, + redirect_uri=REDIRECT_URI, + cache_handler=SessionCacheHandler(request.session), + ) + + +@app.get("/") +def index( + auth_manager: Annotated[SpotifyOAuth, Depends(get_spotify_oauth)], request: Request +): + # Check if we have a cached token + is_authenticated = bool(auth_manager.get_cached_token()) + # Render index.html template + return templates.TemplateResponse( + "index.html", {"request": request, "is_authenticated": is_authenticated} + ) + + +@app.get("/login") +def login(auth_manager: Annotated[SpotifyOAuth, Depends(get_spotify_oauth)]): + return RedirectResponse(auth_manager.get_authorize_url()) + + +@app.get("/callback") +async def callback( + auth_manager: Annotated[SpotifyOAuth, Depends(get_spotify_oauth)], request: Request +): + # Authorization code that spotify sends back https://developer.spotify.com/documentation/web-api/tutorials/code-flow + code = request.query_params.get("code") + if not code: + return {"Error": "No code provided"} + + # Exchange code for an access token + token_info = auth_manager.get_access_token(code) + + if not token_info: + return {"Error": "Could not retrieve token"} + + # Finally redirect to the index page + return RedirectResponse("/") + + +@app.post("/playlist") +def playlist(sentence: str = Form(...)): + return {"status": "ok"} + + +# Healthcheck endpoint to make sure the server is running +@app.get("/healthcheck") +def healthcheck(): + return {"status": "ok"} diff --git a/playlistfy.py b/app/playlistfy.py similarity index 68% rename from playlistfy.py rename to app/playlistfy.py index de2a9a3..7e6c5d5 100644 --- a/playlistfy.py +++ b/app/playlistfy.py @@ -1,6 +1,7 @@ import spotipy from dataclasses import dataclass + @dataclass class Playlist: name: str @@ -9,11 +10,15 @@ class Playlist: class Playlistify: - def __init__(self, spotify_client: spotipy.Spotify, playlist_name: str, playlist_description:str): + def __init__( + self, + spotify_client: spotipy.Spotify, + playlist_name: str, + playlist_description: str, + ): self.playlist_name = playlist_name self.playlist_description = playlist_description self.client = spotify_client - def create_playlist(self, sentence: str) -> Playlist: - pass \ No newline at end of file + pass diff --git a/session_cache_handler.py b/app/session_cache_handler.py similarity index 82% rename from session_cache_handler.py rename to app/session_cache_handler.py index f0e533e..054bd73 100644 --- a/session_cache_handler.py +++ b/app/session_cache_handler.py @@ -1,5 +1,6 @@ from spotipy import CacheHandler + class SessionCacheHandler(CacheHandler): def __init__(self, session): self.session = session @@ -8,4 +9,4 @@ def get_cached_token(self): return self.session.get("spotify_token_info") def save_token_to_cache(self, token_info): - self.session["spotify_token_info"] = token_info \ No newline at end of file + self.session["spotify_token_info"] = token_info diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..3b36192 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,43 @@ + + +
+ + + +