From 7fc08809f0289ebff229819b02d10e5631d6dee1 Mon Sep 17 00:00:00 2001 From: Bryan Malyn Date: Sat, 25 Jun 2022 14:00:08 -0500 Subject: [PATCH] Add FlaskSessionCacheHandler (#833) Updated examples/app.py Updated CHANGELOG.md and appropriate docs. --- CHANGELOG.md | 1 + docs/index.rst | 1 + examples/app.py | 38 ++++++++++++-------------------------- spotipy/cache_handler.py | 26 ++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f328ff27..1b27c955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `market` parameter to `album` and `albums` to address ([#753](https://github.com/plamere/spotipy/issues/753) * Added 'show_featured_artists.py' to 'examples'. * Expanded contribution and license sections of the documentation. +* Added `FlaskSessionCacheHandler`, a cache handler that stores the token info in a flask session. ### Fixed diff --git a/docs/index.rst b/docs/index.rst index c4917954..c9622921 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -235,6 +235,7 @@ The following handlers are available and defined in the URL above. - ``CacheFileHandler`` - ``MemoryCacheHandler`` - ``DjangoSessionCacheHandler`` + - ``FlaskSessionCacheHandler`` - ``RedisCacheHandler`` Feel free to contribute new cache handlers to the repo. diff --git a/examples/app.py b/examples/app.py index aa6ad19a..f177fc39 100644 --- a/examples/app.py +++ b/examples/app.py @@ -27,7 +27,6 @@ from flask import Flask, session, request, redirect from flask_session import Session import spotipy -import uuid app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(64) @@ -35,57 +34,44 @@ app.config['SESSION_FILE_DIR'] = './.flask_session/' Session(app) -caches_folder = './.spotify_caches/' -if not os.path.exists(caches_folder): - os.makedirs(caches_folder) - -def session_cache_path(): - return caches_folder + session.get('uuid') @app.route('/') def index(): - if not session.get('uuid'): - # Step 1. Visitor is unknown, give random ID - session['uuid'] = str(uuid.uuid4()) - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private', - cache_handler=cache_handler, - show_dialog=True) + cache_handler=cache_handler, + show_dialog=True) if request.args.get("code"): - # Step 3. Being redirected from Spotify auth page + # Step 2. Being redirected from Spotify auth page auth_manager.get_access_token(request.args.get("code")) return redirect('/') if not auth_manager.validate_token(cache_handler.get_cached_token()): - # Step 2. Display sign in link when no token + # Step 1. Display sign in link when no token auth_url = auth_manager.get_authorize_url() return f'

Sign in

' - # Step 4. Signed in, display data + # Step 3. Signed in, display data spotify = spotipy.Spotify(auth_manager=auth_manager) return f'

Hi {spotify.me()["display_name"]}, ' \ f'[sign out]

' \ f'my playlists | ' \ f'currently playing | ' \ - f'me' \ + f'me' \ + @app.route('/sign_out') def sign_out(): - try: - # Remove the CACHE file (.cache-test) so that a new user can authorize. - os.remove(session_cache_path()) - session.clear() - except OSError as e: - print ("Error: %s - %s." % (e.filename, e.strerror)) + session.pop("token_info", None) return redirect('/') @app.route('/playlists') def playlists(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') @@ -96,7 +82,7 @@ def playlists(): @app.route('/currently_playing') def currently_playing(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') @@ -109,7 +95,7 @@ def currently_playing(): @app.route('/current_user') def current_user(): - cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) + cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) if not auth_manager.validate_token(cache_handler.get_cached_token()): return redirect('/') diff --git a/spotipy/cache_handler.py b/spotipy/cache_handler.py index cd4567fa..2645f25b 100644 --- a/spotipy/cache_handler.py +++ b/spotipy/cache_handler.py @@ -2,6 +2,7 @@ 'CacheHandler', 'CacheFileHandler', 'DjangoSessionCacheHandler', + 'FlaskSessionCacheHandler', 'MemoryCacheHandler', 'RedisCacheHandler'] @@ -147,6 +148,31 @@ def save_token_to_cache(self, token_info): logger.warning("Error saving token to cache: " + str(e)) +class FlaskSessionCacheHandler(CacheHandler): + """ + A cache handler that stores the token info in the session framework + provided by flask. + """ + + def __init__(self, session): + self.session = session + + def get_cached_token(self): + token_info = None + try: + token_info = self.session["token_info"] + except KeyError: + logger.debug("Token not found in the session") + + return token_info + + def save_token_to_cache(self, token_info): + try: + self.session["token_info"] = token_info + except Exception as e: + logger.warning("Error saving token to cache: " + str(e)) + + class RedisCacheHandler(CacheHandler): """ A cache handler that stores the token info in the Redis.