spotify.py
spotify.py copied to clipboard
Example with an async http server
Do you see an interest having examples with an async http server for authentication part ?
I struggle to have a working example with sanic but work is in progress.
Here is an example I wrote:
#!/usr/bin/env python3
from aiohttp import web
import os
import spotify
CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
REDIRECT_URI = os.environ['REDIRECT_URI']
async def auth(request):
async with spotify.Client(CLIENT_ID, CLIENT_SECRET) as client:
url = client.oauth2_url(
redirect_uri=REDIRECT_URI,
scopes=['user-library-read'],
)
return web.HTTPFound(url)
async def callback(request):
async with spotify.Client(CLIENT_ID, CLIENT_SECRET) as client:
user = await spotify.User.from_code(
client=client,
code=request.query['code'],
redirect_uri=REDIRECT_URI,
)
tracks = await user.library.get_all_tracks()
return web.HTTPFound(repr(tracks))
app = web.Application()
app.add_routes([
web.get('/', auth),
web.get('/callback', callback),
])
if __name__ == '__main__':
web.run_app(app)
Actually I wouldn't recommend that @frafra spotify.Client
is made to me created once and carried around for the lifetime of the program. So creating and destroying instances on every route handler is a very expensive thing to do.
I'd suggesting using the contextvars module:
import asyncio
from contextvars import ContextVar
from aiohttp.web import AppRunner, TCPSite
CLIENT: ContextVar("spotify_client")
async def callback(request):
client = CLIENT.get()
user = await spotify.User.from_code(
client=client,
code=request.query['code'],
redirect_uri=REDIRECT_URI,
)
tracks = await user.library.get_all_tracks()
return web.HTTPFound(repr(tracks))
async def main() -> None:
async with spotify.Client(CLIENT_ID, CLIENT_SECRET) as client:
CLIENT.set(client)
runner = AppRunner(app)
await runner.setup()
site = TCPSite(runner, 'localhost', 8080)
await site.start()
if __name__ == "__main__":
asyncio.run(main())
Using ContextVar
is a good suggestion indeed :-)
The code looks incomplete to me now, as the auth
part with the initial request and scopes is missing.
@frafra It was my intention that the codeblock I posted be combined with your one haha
would anyone like to PR this in themselves? Don't worry if not, I can add this is either way :)