201 lines
6.7 KiB
Python
201 lines
6.7 KiB
Python
import os
|
|
import json
|
|
import base64
|
|
from dotenv import load_dotenv
|
|
from requests import Request, post
|
|
from rest_framework.views import APIView
|
|
from rest_framework import status, generics
|
|
from rest_framework.response import Response
|
|
from django.shortcuts import redirect
|
|
from .util import is_spotify_authenticated, update_or_create_user_tokens, spotify_api_request, play_song, pause_song
|
|
from api.models import Room
|
|
from .models import SpotifyToken
|
|
from .serializers import TokenSerializer
|
|
|
|
load_dotenv()
|
|
|
|
if os.getenv('Docker'):
|
|
REACT_PORT = os.getenv('REACT_PORT')
|
|
API_PORT = os.getenv('API_PORT')
|
|
WEBSITE = 'https://gxnet.cc'
|
|
REDIRECT_URI = 'https://gxnet.cc/spotify/redirect'
|
|
else:
|
|
REACT_PORT = 5173
|
|
API_PORT = 8000
|
|
REDIRECT_URI = f'http://127.0.0.1:{API_PORT}/spotify/redirect'
|
|
|
|
CLIENT_ID = os.getenv('CLIENT_ID')
|
|
CLIENT_SECRET = os.getenv('CLIENT_SECRET')
|
|
|
|
|
|
class AuthURL(APIView):
|
|
def get(self, request):
|
|
if not request.session.exists(request.session.session_key):
|
|
request.session.create()
|
|
orig_sid = request.session.session_key
|
|
|
|
room_code = request.GET.get('state')
|
|
state_obj = {"room": room_code, "sid": orig_sid}
|
|
state = base64.urlsafe_b64encode(json.dumps(state_obj).encode()).decode()
|
|
|
|
scopes = 'user-read-playback-state user-modify-playback-state user-read-currently-playing'
|
|
url = (
|
|
Request(
|
|
'GET',
|
|
'https://accounts.spotify.com/authorize',
|
|
params={
|
|
'scope': scopes,
|
|
'response_type': 'code',
|
|
'client_id': CLIENT_ID,
|
|
'redirect_uri': REDIRECT_URI,
|
|
'state': state,
|
|
},
|
|
)
|
|
.prepare()
|
|
.url
|
|
)
|
|
|
|
# sanity debug
|
|
print('🎧client_id:', CLIENT_ID)
|
|
print('🎧 orig_sid:', orig_sid)
|
|
print(' 🎧url:', url)
|
|
|
|
return Response({'url': url}, status=status.HTTP_200_OK)
|
|
|
|
|
|
# https://developer-assets.spotifycdn.com/images/documentation/web-api/auth-code-flow.png
|
|
def spotify_callback(request):
|
|
code = request.GET.get('code')
|
|
raw_state = request.GET.get("state") or ""
|
|
state = json.loads(base64.urlsafe_b64decode(raw_state).decode())
|
|
error = request.GET.get('error')
|
|
|
|
room_code = state.get("room") # <- plain string
|
|
orig_sid = state.get("sid")
|
|
|
|
response = post(
|
|
'https://accounts.spotify.com/api/token',
|
|
data={
|
|
'grant_type': 'authorization_code',
|
|
'code': code,
|
|
'redirect_uri': REDIRECT_URI,
|
|
'client_id': CLIENT_ID,
|
|
'client_secret': CLIENT_SECRET,
|
|
},
|
|
).json()
|
|
|
|
access_token = response.get('access_token')
|
|
token_type = response.get('token_type')
|
|
refresh_token = response.get('refresh_token')
|
|
expires_in = response.get('expires_in')
|
|
error = response.get('error')
|
|
|
|
if not request.session.exists(request.session.session_key):
|
|
request.session.create()
|
|
cur_sid = request.session.session_key
|
|
|
|
# if session changed, rebind room host
|
|
room = Room.objects.filter(code=room_code, host=orig_sid).first()
|
|
if room and cur_sid != orig_sid:
|
|
room.host = cur_sid
|
|
room.save(update_fields=["host"])
|
|
|
|
update_or_create_user_tokens(request.session.session_key, access_token, token_type, expires_in, refresh_token)
|
|
|
|
if room_code:
|
|
request.session['room_code'] = room_code
|
|
|
|
print('🎧### On spotify Callback() ## 🎧')
|
|
print("Host:", request.get_host())
|
|
print("Cookies:", request.COOKIES)
|
|
print("Session key:", request.session.session_key)
|
|
print('room_code REDIRECT:', room_code)
|
|
|
|
if WEBSITE:
|
|
target = f'{WEBSITE}/room/{room_code}?code={room_code}&auth=done'
|
|
else:
|
|
target = f'http://127.0.0.1:{REACT_PORT}/room/{room_code}?code={room_code}&auth=done'
|
|
|
|
return redirect(target)
|
|
|
|
|
|
class IsAuthenticated(APIView):
|
|
def get(self, request):
|
|
is_auth = is_spotify_authenticated(self.request.session.session_key)
|
|
return Response({'status': is_auth, 'message': '🎧'})
|
|
|
|
|
|
class CurrentSong(APIView):
|
|
def get(self, request):
|
|
room_code = self.request.session.get('room_code')
|
|
print('DEBUG ; room_code:', room_code)
|
|
|
|
room = Room.objects.filter(code=room_code).first()
|
|
if room:
|
|
host = room.host
|
|
|
|
else:
|
|
return Response({'message': 'not a room'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
endpoint = 'player/currently-playing'
|
|
response = spotify_api_request(host, endpoint)
|
|
|
|
if 'error' in response or 'item' not in response:
|
|
return Response({'error': 'error response from spotify'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
else:
|
|
item = response.get('item')
|
|
duration = item.get('duration_ms')
|
|
progress = response.get('progress_ms')
|
|
album_cover = item.get('album').get('images')[0].get('url')
|
|
is_playing = response.get('is_playing')
|
|
song_id = item.get('id')
|
|
|
|
artist_string = ""
|
|
|
|
for i, artist in enumerate(item.get('artists')):
|
|
if i > 0:
|
|
artist_string += ", "
|
|
name = artist.get('name')
|
|
artist_string += name
|
|
|
|
song = {
|
|
'title': item.get('name'),
|
|
'artist': artist_string,
|
|
'duration': duration,
|
|
'time': progress,
|
|
'image_url': album_cover,
|
|
'is_playing': is_playing,
|
|
'votes': 0,
|
|
'id': song_id,
|
|
}
|
|
|
|
return Response(song, status=status.HTTP_200_OK)
|
|
|
|
|
|
class SpotifyList(generics.ListAPIView):
|
|
queryset = SpotifyToken.objects.all()
|
|
serializer_class = TokenSerializer
|
|
|
|
|
|
class PauseSong(APIView):
|
|
def put(self, request):
|
|
room_code = self.request.session.get('room_code')
|
|
room = Room.objects.filter(code=room_code)[0]
|
|
|
|
if self.request.session.session_key == room.host or room.guest_can_pause:
|
|
upstream_response = pause_song(room.host)
|
|
return Response(upstream_response, status=status.HTTP_200_OK)
|
|
return Response({'Not allowed': 'you are not the host'}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
|
|
class PlaySong(APIView):
|
|
def put(self, request):
|
|
room_code = self.request.session.get('room_code')
|
|
room = Room.objects.filter(code=room_code)[0]
|
|
|
|
if self.request.session.session_key == room.host or room.guest_can_pause:
|
|
upstream_response = play_song(room.host)
|
|
return Response(upstream_response, status=status.HTTP_200_OK)
|
|
return Response({'Not allowed': 'you are not the host'}, status=status.HTTP_403_FORBIDDEN)
|