diff --git a/playlist/models/vote.py b/playlist/models/vote.py
index d05712c..e927613 100644
--- a/playlist/models/vote.py
+++ b/playlist/models/vote.py
@@ -7,3 +7,4 @@ class Vote(models.Model):
track = models.ForeignKey('Track', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
points = models.IntegerField()
+ skipped = models.BooleanField(default=False)
diff --git a/playlist/static/img/download.png b/playlist/static/img/download.png
new file mode 100644
index 0000000..5d96a1b
Binary files /dev/null and b/playlist/static/img/download.png differ
diff --git a/playlist/static/style.css b/playlist/static/style.css
index 5442288..d494e70 100644
--- a/playlist/static/style.css
+++ b/playlist/static/style.css
@@ -457,6 +457,7 @@ input[type="range"]#volume::-webkit-slider-thumb {
.undo-wrapper p {
flex-grow: 1;
padding: 0 5px;
+ text-align: right;
}
.undo {
@@ -465,6 +466,17 @@ input[type="range"]#volume::-webkit-slider-thumb {
background-position: 50% 0;
padding: 32px 0 4px 0;
height: 50px;
+ min-width: 40px;
+}
+
+.skip {
+ background-image: url(img/download.png);
+ background-repeat: no-repeat;
+ background-position: 50% 20%;
+ padding: 32px 0 4px 0;
+ height: 50px;
+ min-width: 40px;
+ margin-left: 5px;
}
.progress-indicator {
diff --git a/playlist/templates/Vote.html b/playlist/templates/Vote.html
index adb2646..327b6d6 100644
--- a/playlist/templates/Vote.html
+++ b/playlist/templates/Vote.html
@@ -41,14 +41,19 @@ Stemmen
>
+
+ {% if not skipped %}
+ {% csrf_token %}
+
+ {% endif %}
+
+
{% if undo %}
-
-
{% csrf_token %}
Je hebt {{undo.track}} een score van {{undo.points}} sterren gegeven!
-
{% endif %}
+
{% else %}
diff --git a/playlist/urls.py b/playlist/urls.py
index 28c8394..f7d4d77 100644
--- a/playlist/urls.py
+++ b/playlist/urls.py
@@ -7,6 +7,7 @@ urlpatterns = [
path('track/', views.NominateView.as_view(), name="nominate"),
path('vote/', views.VoteView.as_view(), name="vote"),
path('vote/undo', views.UndoView.as_view(), name="undo"),
+ path('vote/skip', views.SkipView.as_view(), name="skip"),
path('settings/', views.SettingsView.as_view(), name="settings"),
path('overview/', views.OverView.as_view(), name="overview"),
path('overview/playlist', views.PlaylistListView.as_view(), name="playlist-list"),
diff --git a/playlist/utils.py b/playlist/utils.py
index f0ef518..788beba 100644
--- a/playlist/utils.py
+++ b/playlist/utils.py
@@ -10,11 +10,18 @@ def from_json(cls, json):
return cls.objects.create(**subset)
def get_unvoted(user):
+ """Gets next voting track for user. Returns a pair with track and flag if this was a skipped track"""
votes = set(Vote.objects.filter(user=user).values_list('track_id', flat=True))
tracks = set(Track.objects.filter(banter_done=True).values_list('pk', flat=True))
seed(user.username)
try:
- random_track = choice(list(tracks - votes))
- return Track.objects.get(pk=random_track)
+ queue = list(tracks - votes)
+ skipped = False
+ if not queue:
+ skipped = True
+ queue = list(Vote.objects.filter(user=user).filter(skipped=True).values_list('track_id', flat=True))
+ random_track = choice(queue)
+ choice
+ return (Track.objects.get(pk=random_track), skipped)
except IndexError:
- return None
+ return (None, False)
diff --git a/playlist/views.py b/playlist/views.py
index 79f8aca..c6ae980 100644
--- a/playlist/views.py
+++ b/playlist/views.py
@@ -26,10 +26,10 @@ class AuthView(View):
class VoteView(LoginRequiredMixin, View):
def get(self, request, undo=None):
- track = get_unvoted(request.user)
+ (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})
+ 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:
@@ -40,11 +40,14 @@ class VoteView(LoginRequiredMixin, View):
score = min(max(1, score), 5)
track = Track.objects.get(pk=spotify_id)
try:
- Vote.objects.get(user=request.user, track=track)
+ prevote = Vote.objects.get(user=request.user, track=track)
except Vote.DoesNotExist:
pass
else:
- raise Exception(f"{request.user} already voted for {track}")
+ 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
@@ -186,6 +189,26 @@ class UndoView(LoginRequiredMixin, View):
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()