Files
muzak/playlist/views.py
T
2024-07-20 09:52:50 +02:00

281 lines
11 KiB
Python

from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Avg
from django.urls import reverse
import re
import os
from datetime import UTC, datetime
from collections import OrderedDict
from dotenv import load_dotenv
from .models import Track, Artist, Album, Vote, Background, Profile, Playlist
from .utils import from_json, get_unvoted
from .spotify import spt
from .tasks import get_banter, get_and_dither_image
load_dotenv()
class AuthView(View):
def get(self, request):
if request.user.is_authenticated:
return HttpResponseRedirect('/vote/')
else:
return TemplateResponse(request, "Login.html", {})
class VoteView(LoginRequiredMixin, View):
def get(self, request, undo=None):
(track, skipped) = get_unvoted(request.user)
if track and not track.album.image:
get_and_dither_image(track.album.image_url, track.album, "image")
return TemplateResponse(request, "Vote.html", {"track": track, "undo": undo, "skipped": skipped})
def post(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
try:
if not profile.can_vote:
raise Exception(f"{request.user} tried to vote after closing for {track}")
spotify_id = self.request.POST['spotify_id']
score = int(self.request.POST['vote'])
score = min(max(1, score), 5)
track = Track.objects.get(pk=spotify_id)
try:
prevote = Vote.objects.get(user=request.user, track=track)
except Vote.DoesNotExist:
pass
else:
if not prevote.skipped:
raise Exception(f"{request.user} already voted for {track}")
else:
prevote.delete()
vote = Vote.objects.create(track=track, user=request.user, points=score)
(profile,_) = Profile.objects.get_or_create(user=request.user)
profile.last_voted = track
profile.save()
return self.get(request, undo=vote)
except Exception as e:
print(e)
class NominateView(LoginRequiredMixin, View):
def get(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
profile.update_quota()
return TemplateResponse(request, "Nominate.html", {'end_time': os.getenv('DATE_NOM_END')})
def post(self, request):
(profile,_) = Profile.objects.get_or_create(user=request.user)
if not profile.can_nominate[0]:
return TemplateResponse(request, "Nominate.html", {"message_type": "error", "message": "Nee nee nee, dat gaan we dus even niet doen."})
try:
spotify_link = self.request.POST['spotify_link']
# Short url?
if re.match(r"^https:\/\/spotify.link.*", spotify_link):
spotify_link = spt.unshort(spotify_link)
m = re.match(r"^https:\/\/open.spotify.com\/track\/([a-zA-Z0-9]+)\??", spotify_link)
spotify_id = m.group(1)
except:
return TemplateResponse(request, "Nominate.html", {"message_type": "error", "message": "Geef een geldige spotify link op!"})
try:
track = Track.all_tracks.get(pk=spotify_id)
if track.old:
track.old = False
track.save()
return TemplateResponse(request, "Nominate.html", {
"message_type": "warning",
"message": "Hey een klassieker.",
"message_title": str(track)
})
return TemplateResponse(request, "Nominate.html", {
"message_type": "error",
"message_title": str(track),
"message": "Deze is al genomineerd dit jaar, probeer eens iets anders.",
})
except Track.DoesNotExist:
try:
json = spt.get_song_info(spotify_id)
except Exception as e:
print(e)
return TemplateResponse(request, "Nominate.html", {"message_type": "error", "message": "Fout bij het ophalen van het liedje."})
# Album artists
album_artists = []
for artist in json["album"]["artists"]:
album_artists.append(from_json(Artist, artist))
del json["album"]["artists"]
# Album
album = from_json(Album, json["album"])
album.image_url = json["album"]["images"][0]["url"]
album.save()
del json["album"]
for artist in album_artists:
album.artists.add(artist)
# Track artists
track_artists = []
for artist in json["artists"]:
track_artists.append(from_json(Artist, artist))
del json["artists"]
# Track
track = from_json(Track, json)
for artist in track_artists:
track.artists.add(artist)
track.save()
dup = track.is_duplicate_of()
if dup:
track.delete()
return TemplateResponse(request, "Nominate.html", {
"message_type": "error",
"message": "Die hadden we al knul.",
"message_title": str(dup)
})
track.album = album
track.save()
get_banter.delay(track.id)
profile.quota -= 1
profile.save()
return TemplateResponse(request, "Nominate.html", {"message_type": "nominated", "message_title": str(track), "message": "Genomineerd!"})
class SettingsView(LoginRequiredMixin, View):
def get(self, request):
backgrounds = Background.objects.all()
(profile,created) = Profile.objects.get_or_create(user=request.user)
context = {
"backgrounds": backgrounds,
"currentBackground": (profile.background.id if profile.background else 1)
}
spt_token = profile.get_or_update_spt()
if spt_token:
context["sptDisplayName"] = spt.get_profile(spt_token).get('display_name')
return TemplateResponse(request, "Settings.html", context)
def post(self, request):
try:
bg = request.POST.get('background', None)
unlink_spotify = request.POST.get('unlink-spotify', None)
(profile,_) = Profile.objects.get_or_create(user=request.user)
if bg:
bg = Background.objects.get(pk=request.POST['background'])
profile.background = bg
if unlink_spotify:
print("unlink spt")
profile.unlink_spt()
profile.save()
except:
pass
finally:
return self.get(request)
class UndoView(LoginRequiredMixin, View):
def get(self, request):
return HttpResponseRedirect('/vote/')
def post(self, request):
spotify_id = self.request.POST['spotify_id']
track = Track.objects.get(pk=spotify_id)
(profile,_) = Profile.objects.get_or_create(user=request.user)
if profile.last_voted != track:
raise Exception(f"{request.user} is not allowed to undo vote for {track}")
vote = None
try:
vote = Vote.objects.get(user=request.user, track=track)
except Vote.DoesNotExist:
raise Exception(f"{request.user} did not vote for {track}")
profile.last_voted = None
profile.save()
vote.delete()
return HttpResponseRedirect('/vote/')
class SkipView(LoginRequiredMixin, View):
def get(self, request):
return HttpResponseRedirect('/vote/')
def post(self, request):
spotify_id = self.request.POST['spotify_id']
track = Track.objects.get(pk=spotify_id)
(profile,_) = Profile.objects.get_or_create(user=request.user)
if not profile.can_vote:
raise Exception(f"{request.user} tried to vote after closing for {track}")
vote = None
try:
vote = Vote.objects.get(user=request.user, track=track)
except Vote.DoesNotExist:
pass
profile.last_voted = None
profile.save()
vote = Vote.objects.create(track=track, user=request.user, points=0, skipped=True)
profile.save()
return self.get(request)
class OverView(LoginRequiredMixin, View):
def get(self, request):
votes = Vote.objects.select_related().distinct()
artists = {}
for vote in votes:
for artist in vote.track.artists.all():
if not artists.get(artist.name):
artists[artist.name] = {}
for artist in vote.track.album.artists.all():
if not artists.get(artist.name):
artists[artist.name] = {}
if not artists[artist.name].get(vote.track.album.name):
artists[artist.name][vote.track.album.name] = []
artists[artist.name][vote.track.album.name] += [vote.track]
artists_ordered = OrderedDict(sorted(artists.items()))
context = {
"artists": artists_ordered
}
return TemplateResponse(request, "Overview.html", context)
class PlaylistListView(LoginRequiredMixin, View):
def get(self, request, count=None):
context = {
"playlists": Playlist.objects.all()
}
return TemplateResponse(request, "PlaylistList.html", context)
def post(self, request):
name = self.request.POST.get('name', None)
if name:
new_playlist = Playlist(name=name)
return TemplateResponse(request, "PlaylistList.html")
return self.get(request, count=count)
class PlaylistDetailView(LoginRequiredMixin, View):
def get(self, request, count=None):
context = {}
if count:
#tracks = Track.objects.order_by('score')[count]
tracks = Track.objects.annotate(average_points=Avg('vote__points')).order_by('-average_points')[:count]
context["tracks"] = tracks
return TemplateResponse(request, "PlaylistDetail.html", context)
def post(self, request):
try:
count = int(self.request.POST['count'])
return self.get(request, count=count)
except Exception as e:
print(e)
return self.get(request)
class SpotifyView(LoginRequiredMixin, View):
def get(self, request):
url = spt.get_oauth_redirect()
return HttpResponseRedirect(url)
class SpotifyCallbackView(LoginRequiredMixin, View):
def get(self, request):
error = self.request.GET.get('error')
code = self.request.GET.get('code')
if error:
return TemplateResponse(request, "Settings.html", {"message": "Je moet wel accepteren"})
elif code:
(profile,_) = Profile.objects.get_or_create(user=request.user)
profile.init_spt(code)
return HttpResponseRedirect(reverse('settings'))
else:
url = spt.get_oauth_redirect()
return HttpResponseRedirect(url)