diff --git a/base/static/css/main.css b/base/static/css/main.css
index 80a38b2..74e4488 100644
--- a/base/static/css/main.css
+++ b/base/static/css/main.css
@@ -17,7 +17,7 @@ form a[role="button"] {
width: 100%;
}
-i.owner {
+i.owner, .gold {
color: var(--pico-color-amber-200);
}
@@ -25,7 +25,7 @@ i.owner {
display: none;
}
-a.group {
+a.group, a.running {
text-decoration: none;
}
@@ -77,11 +77,6 @@ article.message {
}
#hero {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
background: radial-gradient(
circle 50vh at calc(100vw - 4rem) 50%,
var(--pico-primary-background),
@@ -90,19 +85,41 @@ article.message {
color-mix(in hsl, var(--pico-primary-background) 30%, var(--pico-background-color)) 60%,
color-mix(in hsl, var(--pico-primary-background) 10%, var(--pico-background-color)) 80%,
var(--pico-background-color));
- display: grid;
- grid-template-rows: 1fr min-content;
- align-items: center;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+ overflow-y: auto;
padding: 4rem;
- .big-logo {
- font-size: 8rem;
+ main {
+ display: contents;
}
-
- h1 {
- font-size: 4rem;
+ section {
+ max-width: 20rem;
}
}
+.full-page {
+ height: 100%;
+ display: grid;
+ grid-template-rows: 1fr;
+ align-items: center;
+ margin-bottom: 4rem;
+
+ &.r {
+ -ms-grid-column-align: end;
+ }
+ .big-logo {
+ font-size: 8rem;
+ }
+
+ h1 {
+ font-size: 4rem;
+ }
+}
+
h1,
h2,
@@ -117,7 +134,7 @@ h6,
i.i {
margin-right: .5em;
}
-i.hl {
+i.hl, .me {
color: var(--pico-primary);
}
@@ -160,10 +177,48 @@ table select {
color: var(--pico-color-sand-300);
}
}
-
.score {
- font-weight: 900;
- color: var(--pico-color-zinc-500);
margin-left: .5em;
}
}
+
+
+.score {
+ font-weight: 900;
+ color: var(--pico-color-zinc-500);
+}
+.correct {
+ .score, i {
+ color: var(--pico-color-lime-200);}
+}
+.wrong {
+ .score, i {
+ color: var(--pico-color-red-500);}
+}
+
+table.results, table.musics {
+ white-space: nowrap;
+}
+.sc i {
+ margin-right: .5em;
+}
+
+@media (width < 576px) {
+ [role="group"] {
+ display: grid;
+ & > :first-child {
+ border-radius: var(--pico-border-radius) var(--pico-border-radius) 0 0 !important;
+ }
+ & > :not(:first-child) {
+ margin-left: 0 !important;
+ margin-top: calc(var(--pico-border-width) * -1);
+ }
+ & > :last-child {
+ border-radius: 0 0 var(--pico-border-radius) var(--pico-border-radius) !important;
+ }
+ }
+}
+
+.brand-name {
+ color: var(--pico-primary);
+}
diff --git a/base/static/favicon/apple-touch-icon.png b/base/static/favicon/apple-touch-icon.png
new file mode 100644
index 0000000..abb8a48
Binary files /dev/null and b/base/static/favicon/apple-touch-icon.png differ
diff --git a/base/static/favicon/favicon-96x96.png b/base/static/favicon/favicon-96x96.png
new file mode 100644
index 0000000..beab288
Binary files /dev/null and b/base/static/favicon/favicon-96x96.png differ
diff --git a/base/static/favicon/favicon.ico b/base/static/favicon/favicon.ico
new file mode 100644
index 0000000..178d60c
Binary files /dev/null and b/base/static/favicon/favicon.ico differ
diff --git a/base/static/favicon/favicon.svg b/base/static/favicon/favicon.svg
new file mode 100644
index 0000000..63c10e0
--- /dev/null
+++ b/base/static/favicon/favicon.svg
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/base/static/favicon/site.webmanifest b/base/static/favicon/site.webmanifest
new file mode 100644
index 0000000..af6d059
--- /dev/null
+++ b/base/static/favicon/site.webmanifest
@@ -0,0 +1,21 @@
+{
+ "name": "MyWebSite",
+ "short_name": "MySite",
+ "icons": [
+ {
+ "src": "/web-app-manifest-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "maskable"
+ },
+ {
+ "src": "/web-app-manifest-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "maskable"
+ }
+ ],
+ "theme_color": "#aa40bf",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/base/static/favicon/web-app-manifest-192x192.png b/base/static/favicon/web-app-manifest-192x192.png
new file mode 100644
index 0000000..f7f97da
Binary files /dev/null and b/base/static/favicon/web-app-manifest-192x192.png differ
diff --git a/base/static/favicon/web-app-manifest-512x512.png b/base/static/favicon/web-app-manifest-512x512.png
new file mode 100644
index 0000000..9e4e381
Binary files /dev/null and b/base/static/favicon/web-app-manifest-512x512.png differ
diff --git a/base/templates/auth/user_form.html b/base/templates/auth/user_form.html
index 20c40a8..c895f16 100644
--- a/base/templates/auth/user_form.html
+++ b/base/templates/auth/user_form.html
@@ -1,6 +1,24 @@
{% extends "base.html" %}
{% load form %}
{% block content %}
-
Créer un compte
- {% form form submit="Créer mon compte" %}
- {% endblock content %}
+ Créer mon compte
+ {% for error in form.non_field_errors %}{{ error }} {% endfor %}
+
+{% endblock content %}
diff --git a/base/templates/base.html b/base/templates/base.html
index 16be674..504228f 100644
--- a/base/templates/base.html
+++ b/base/templates/base.html
@@ -11,7 +11,7 @@
Musik
{% endblock title %}
-
+ {% include "favicon.html" %}
+
+
+
+
+
+
diff --git a/base/templates/footer.html b/base/templates/footer.html
index 52895f6..6c57641 100644
--- a/base/templates/footer.html
+++ b/base/templates/footer.html
@@ -1 +1 @@
-Musik {{ VERSION }} – © Edgar P. Burkhart – Mentions légales
+Musik {{ VERSION }} – © Edgar P. Burkhart – Mentions légales et confidentialité
diff --git a/base/templates/hero.html b/base/templates/hero.html
index 04c2aee..813c011 100644
--- a/base/templates/hero.html
+++ b/base/templates/hero.html
@@ -1,11 +1,25 @@
{% load static %}
-
- Musik
-
- Jouer
-
+
+
+
+
+ Musik Le jeu où ta playlist devient ton arme secrète !
+
+
+ Invite ta bande, ajoute tes sons fétiches, et c’est parti ! Une playlist Youtube apparaît, mélangeant les coups de cœur de tout le monde. Le jeu ? Écoute, devine qui a choisi quoi, et découvre les secrets musicaux de tes potes. Entre pièges, révélations et fous rires, Musik c’est le jeu parfait pour tester vos oreilles… et vos amitiés. Prêt à jouer le DJ incognito ?
+
+
+
{% include "footer.html" %}
diff --git a/base/templates/privacy.html b/base/templates/privacy.html
index 8e78465..1549403 100644
--- a/base/templates/privacy.html
+++ b/base/templates/privacy.html
@@ -16,6 +16,7 @@
Youtube est une marque de Google LLC.
- La suppression des données stockée par le service Musik pour son utilisation peut être demandée par email à Edgar P. Burkhart .
+ Les données saisies dans Musik (groupes créés, listes de musiques) sont conservées jusqu'à demande de suppression. La suppression du compte entraîne la suppression de l'ensemble des données qui y sont liées.
+ La suppression du compte peut être demandée dans les paramètres du compte. La suppression des données est immédiate et définitive.
{% endblock content %}
diff --git a/base/templates/registration/login.html b/base/templates/registration/login.html
index 8bbb8fd..4e0394e 100644
--- a/base/templates/registration/login.html
+++ b/base/templates/registration/login.html
@@ -5,9 +5,9 @@
{% endblock content %}
diff --git a/compose.yaml b/compose.yaml
index 04838ec..a6ee8b3 100644
--- a/compose.yaml
+++ b/compose.yaml
@@ -32,10 +32,12 @@ services:
rabbitmq:
image: rabbitmq
container_name: musik_rabbitmq
+ restart: unless-stopped
postgres:
image: postgres:17
container_name: musik_postgres
+ restart: unless-stopped
env_file: stack.env
volumes:
- /docker/musik/postgres:/var/lib/postgresql/data
diff --git a/game/migrations/0022_musicgameorder_value.py b/game/migrations/0022_musicgameorder_value.py
new file mode 100644
index 0000000..712353c
--- /dev/null
+++ b/game/migrations/0022_musicgameorder_value.py
@@ -0,0 +1,17 @@
+# Generated by Django 5.2.3 on 2025-06-15 12:49
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("game", "0021_alter_musicgameresults_score"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="musicgameorder",
+ name="value",
+ field=models.PositiveIntegerField(default=0),
+ ),
+ ]
diff --git a/game/migrations/0023_alter_musicvideo_options.py b/game/migrations/0023_alter_musicvideo_options.py
new file mode 100644
index 0000000..ee96adb
--- /dev/null
+++ b/game/migrations/0023_alter_musicvideo_options.py
@@ -0,0 +1,16 @@
+# Generated by Django 5.2.3 on 2025-06-15 14:19
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("game", "0022_musicgameorder_value"),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name="musicvideo",
+ options={"ordering": ["blacklisted", "-date_added"]},
+ ),
+ ]
diff --git a/game/models.py b/game/models.py
index bf57c6e..153583f 100644
--- a/game/models.py
+++ b/game/models.py
@@ -1,5 +1,6 @@
from django.contrib.auth.models import User
from django.db import models
+from django.db.models import F
from django.db.models.functions import Lower
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
@@ -65,6 +66,12 @@ class MusicVideo(models.Model):
fields=("yt_id", "owner", "group"), name="unique_music_in_group"
)
]
+ ordering = ["blacklisted", "-date_added"]
+
+
+class GameManager(models.Manager):
+ def playing(self):
+ return self.filter(over=False)
class MusikGame(models.Model):
@@ -76,6 +83,8 @@ class MusikGame(models.Model):
playlist_loading = models.BooleanField(default=False)
over = models.BooleanField(default=False)
+ objects = GameManager()
+
def get_absolute_url(self):
return reverse("game_detail", kwargs={"pk": self.pk})
@@ -90,6 +99,9 @@ def generateYoutubePlaylist(sender, instance, created, **kwargs):
if creds := instance.group.owner.youtubecredentials:
tasks.generate_playlist.delay_on_commit(creds.credentials, instance.pk)
+ else:
+ instance.playlist_loading = False
+ instance.save()
@receiver(post_delete, sender=MusikGame)
@@ -106,6 +118,14 @@ class MusicGameOrder(models.Model):
player = models.ForeignKey(User, on_delete=models.CASCADE)
music_video = models.ForeignKey(MusicVideo, on_delete=models.CASCADE)
order = models.PositiveIntegerField()
+ value = models.PositiveIntegerField(default=0)
+
+ def update_value(self):
+ x = self.musicgameanswer_set.filter(game__player=F("answer")).count()
+ n = self.game.players.count()
+ n = max(3, n)
+ self.value = 1000 * 2 ** (-(x - 2) / (n - 2))
+ self.save()
class Meta:
constraints = [
@@ -117,6 +137,19 @@ class MusicGameOrder(models.Model):
ordering = ["order"]
+class AnswerManager(models.Manager):
+ def score(self, game, player):
+ qs = self.filter(game__game=game, player=player)
+ return (
+ qs.exclude(game__player=player)
+ .filter(game__player=F("answer"))
+ .aggregate(score=models.Sum("game__value", default=0))
+ .get("score")
+ - 500
+ * qs.filter(game__player=player).exclude(game__player=F("answer")).count()
+ )
+
+
class MusicGameAnswer(models.Model):
game = models.ForeignKey(MusicGameOrder, on_delete=models.CASCADE)
player = models.ForeignKey(User, on_delete=models.CASCADE)
@@ -124,6 +157,8 @@ class MusicGameAnswer(models.Model):
User, on_delete=models.SET_NULL, null=True, related_name="+"
)
+ objects = AnswerManager()
+
class Meta:
constraints = [
models.UniqueConstraint(fields=("game", "player"), name="unique_answer"),
diff --git a/game/tasks.py b/game/tasks.py
index 22a7dc0..61937d0 100644
--- a/game/tasks.py
+++ b/game/tasks.py
@@ -18,7 +18,7 @@ def generate_playlist(creds, game_pk):
"description": "Playlist générée par Musik",
},
"status": {
- "privacyStatus": "private",
+ "privacyStatus": "unlisted",
},
},
)
diff --git a/game/templates/game/group_detail.html b/game/templates/game/group_detail.html
index 3812b6e..90e9901 100644
--- a/game/templates/game/group_detail.html
+++ b/game/templates/game/group_detail.html
@@ -12,68 +12,5 @@
{% include "game/include/group_buttons.html" %}
{% include "game/include/group_games.html" %}
{% include "game/include/group_members.html" %}
-
- Mes musiques {{ musics.count }}
-
-
-
- Liste des musiques
-
-
-
-
+ {% include "game/include/group_musics.html" %}
{% endblock content %}
diff --git a/game/templates/game/include/game_results.html b/game/templates/game/include/game_results.html
new file mode 100644
index 0000000..ca2821c
--- /dev/null
+++ b/game/templates/game/include/game_results.html
@@ -0,0 +1,49 @@
+{% load game %}
+{% if musikgame.over %}
+
+ Résultats
+
+
+
+ Résultats
+
+
+
+
+
+
+
+
+
+ Musique
+
+
+ Joueur
+
+ {% for player in musikgame.musicgameresults_set.all %}
+ {{ player.player.username }}
+
+ {% if forloop.first %} {% endif %}
+ {{ player.score }}
+
+ {% endfor %}
+
+
+
+ {% for music in musikgame.musicgameorder_set.all %}
+
+ {{ music.order }}
+
+ {{ music.music_video.title }}
+
+ {{ music.player }}
+ {% for player in musikgame.musicgameresults_set.all %}
+ {% answer player music %}
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+
+{% endif %}
diff --git a/game/templates/game/include/group_games.html b/game/templates/game/include/group_games.html
index 09ad49a..15016fb 100644
--- a/game/templates/game/include/group_games.html
+++ b/game/templates/game/include/group_games.html
@@ -1,5 +1,10 @@
{% load form youtube %}
{% if group.musikgame_set.exists %}
+ {% for game in group.musikgame_set.playing %}
+
+ {{ game.date }}
+
+ {% endfor %}
Parties
diff --git a/game/templates/game/include/group_musics.html b/game/templates/game/include/group_musics.html
new file mode 100644
index 0000000..56117cf
--- /dev/null
+++ b/game/templates/game/include/group_musics.html
@@ -0,0 +1,66 @@
+
+ Mes musiques {{ musics.count }}
+
+
+
+ Liste des musiques
+
+
+
+
diff --git a/game/templates/game/musikgame_answer.html b/game/templates/game/musikgame_answer.html
index 84e055d..f947802 100644
--- a/game/templates/game/musikgame_answer.html
+++ b/game/templates/game/musikgame_answer.html
@@ -21,6 +21,6 @@
{% endfor %}
- {% if not musikgame.over %}Valider mes réponses {% endif %}
+ {% if not musikgame.over %}Sauvegarder mes réponses {% endif %}
{% endblock content %}
diff --git a/game/templates/game/musikgame_detail.html b/game/templates/game/musikgame_detail.html
index 4130ef3..66708c0 100644
--- a/game/templates/game/musikgame_detail.html
+++ b/game/templates/game/musikgame_detail.html
@@ -9,38 +9,38 @@
{% endif %}
{{ musikgame.date }}
- {% if musikgame.playlist or musikgame.playlist_loading %}
-
- {% csrf_token %}
-
+
+ {% csrf_token %}
+
+ {% if musikgame.playlist or musikgame.playlist_loading %}
Playlist
- {% if musikgame.over %}
- Mes réponses
- {% else %}
- Répondre
- {% endif %}
-
- {% if is_leader and not musikgame.over %}
-
-
- Finir la partie
-
-
{% endif %}
-
- {% endif %}
+ {% if musikgame.over %}
+ Mes réponses
+ {% else %}
+ Répondre
+ {% endif %}
+
+ {% if is_leader and not musikgame.over %}
+
+
+ Finir la partie
+
+
+ {% endif %}
+
Joueurs
{% if musikgame.over %}
{% for player in musikgame.musicgameresults_set.all %}
-
+
{{ player.player.username }} {{ player.score }}
{% endfor %}
@@ -63,40 +63,5 @@
{% endfor %}
- {% if musikgame.over %}
-
- Résultats
-
-
-
- Résultats
-
-
-
-
-
-
-
-
- Musique
-
-
- Joueur
-
-
-
-
- {% for music in musikgame.musicgameorder_set.all %}
-
- {{ music.order }}
-
- {{ music.music_video.title }}
-
- {{ music.player }}
-
- {% endfor %}
-
-
-
- {% endif %}
+ {% include "game/include/game_results.html" %}
{% endblock content %}
diff --git a/game/templates/game/musikgame_form.html b/game/templates/game/musikgame_form.html
index 38ed5b6..655723a 100644
--- a/game/templates/game/musikgame_form.html
+++ b/game/templates/game/musikgame_form.html
@@ -5,10 +5,12 @@
{{ group.name }}
- {% if not user.youtubecredentials.credentials %}
- Me connecter au compte Youtube
+ {% if group.owner.youtubecredentials.credentials %}
+ Une playlist sera générée automatiquement sur le compte Youtube de {{ group.owner }} ({{ group.owner.youtubecredentials.title }} ).
+ {% elif user == group.owner %}
+ Connecter mon compte Youtube
{% else %}
- Une playlist sera générée automatiquement sur le compte Youtube {{ user.youtubecredentials.title }} .
+ Aucune playlist Youtube ne sera générée car {{ group.owner }} n'a pas lié son compte Youtube.
{% endif %}
{% form form %}
diff --git a/game/templates/tags/game/answer.html b/game/templates/tags/game/answer.html
new file mode 100644
index 0000000..bfdeba5
--- /dev/null
+++ b/game/templates/tags/game/answer.html
@@ -0,0 +1,16 @@
+{% if empty %}
+
+
+ {{ score }}
+
+{% elif correct %}
+ {{ answer }}
+
+ {{ score }}
+
+{% else %}
+ {{ answer }}
+
+ {{ score }}
+
+{% endif %}
diff --git a/game/templatetags/game.py b/game/templatetags/game.py
new file mode 100644
index 0000000..eec1bd0
--- /dev/null
+++ b/game/templatetags/game.py
@@ -0,0 +1,30 @@
+from django import template
+
+from .. import models
+
+register = template.Library()
+
+
+@register.inclusion_tag("tags/game/answer.html")
+def answer(player, music):
+ res = {
+ "answer": "",
+ "correct": False,
+ "score": 0,
+ "empty": False,
+ }
+
+ answer = models.MusicGameAnswer.objects.filter(
+ player=player.player, game=music
+ ).first()
+ if answer:
+ res["answer"] = answer.answer
+ res["correct"] = answer.answer == music.player
+ if music.player == player.player:
+ res["score"] = 0 if res["correct"] else "−500"
+ else:
+ res["score"] = music.value if res["correct"] else 0
+ else:
+ res["empty"] = True
+
+ return res
diff --git a/game/views.py b/game/views.py
index b96cb2b..45685aa 100644
--- a/game/views.py
+++ b/game/views.py
@@ -9,7 +9,7 @@ from django.contrib.auth.models import User
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import PermissionDenied
from django.db import IntegrityError
-from django.db.models import Count, F, Q
+from django.db.models import Count, Q
from django.shortcuts import get_object_or_404, redirect
from django.views import View
from django.views.generic import TemplateView
@@ -104,28 +104,31 @@ class GroupAddMusicView(MemberFilterMixin, SingleObjectMixin, View):
def post(self, request, pk):
group = self.get_object()
- yt_id = request.POST.get("yt_id")
- if not yt_id:
- messages.add_message(request, messages.ERROR, "Aucun identifiant donné")
- return redirect(group)
- yt_id = utils.parse_musik(yt_id)
+ ids = request.POST.get("yt_id")
+ for yt_id in ids.split():
+ if not yt_id:
+ messages.add_message(request, messages.ERROR, "Aucun identifiant donné")
+ return redirect(group)
+ yt_id = utils.parse_musik(yt_id)
- title = utils.get_yt_title(yt_id)
- if not title:
- messages.add_message(
- request, messages.ERROR, f"Vidéo Youtube invalide : {yt_id}"
- )
- return redirect(group)
- try:
- group.musicvideo_set.create(yt_id=yt_id, title=title, owner=request.user)
- except IntegrityError:
- messages.add_message(
- request, messages.ERROR, f"Vidéo Youtube déjà ajoutée : {yt_id}"
- )
+ title = utils.get_yt_title(yt_id)
+ if not title:
+ messages.add_message(
+ request, messages.ERROR, f"Vidéo Youtube invalide : {yt_id}"
+ )
+ else:
+ try:
+ group.musicvideo_set.create(
+ yt_id=yt_id, title=title, owner=request.user
+ )
+ except IntegrityError:
+ messages.add_message(
+ request, messages.ERROR, f"Vidéo Youtube déjà ajoutée : {yt_id}"
+ )
- messages.add_message(
- request, messages.SUCCESS, f"Vidéo Youtube ajoutée : {yt_id}"
- )
+ messages.add_message(
+ request, messages.SUCCESS, f"Vidéo Youtube ajoutée : {yt_id}"
+ )
return redirect(group)
@@ -136,19 +139,24 @@ class GroupAddMemberView(MemberFilterMixin, SingleObjectMixin, View):
group = self.get_object()
if not group.is_leader(request.user):
raise PermissionDenied()
- username = request.POST.get("username")
- user = User.objects.get(username=username)
- if user == group.owner:
- messages.add_message(
- request, messages.WARNING, f"{user} est le propriétaire du groupe."
- )
- return redirect(group)
- if user in group.members.all():
- messages.add_message(
- request, messages.WARNING, f"{user} est déjà membre du groupe."
- )
+ usernames = request.POST.get("username")
+ for username in usernames.split():
+ user = User.objects.filter(username=username).first()
+ if not user:
+ messages.add_message(
+ request, messages.ERROR, f"{username} n'existe pas."
+ )
+ elif user == group.owner:
+ messages.add_message(
+ request, messages.WARNING, f"{user} est le propriétaire du groupe."
+ )
+ elif user in group.members.all():
+ messages.add_message(
+ request, messages.WARNING, f"{user} est déjà membre du groupe."
+ )
+ else:
+ group.members.add(user)
- group.members.add(user)
return redirect(group)
@@ -319,15 +327,12 @@ class GameCreateView(LoginRequiredMixin, CreateView):
pm_list = list(zip(players, musics))
random.shuffle(pm_list)
for (player, music), order in zip(pm_list, range(1, len(pm_list) + 1)):
- music.blacklisted = True
- music.save()
models.MusicGameOrder.objects.create(
game=form.instance, player=player, music_video=music, order=order
)
- if models.YoutubeCredentials.objects.filter(user=self.request.user).exists():
- form.instance.playlist_loading = True
- form.instance.save()
+ form.instance.playlist_loading = True
+ form.instance.save()
return res
@@ -465,39 +470,23 @@ class GameAnswerView(LoginRequiredMixin, DetailView):
class GameEndView(LoginRequiredMixin, SingleObjectMixin, View):
model = models.MusikGame
+ def get_queryset(self):
+ return super().get_queryset().filter(over=False)
+
def post(self, request, pk):
game = self.get_object()
if not game.group.is_leader(request.user):
raise PermissionDenied()
game.over = True
+ models.MusicVideo.objects.filter(musicgameorder__game=game).update(
+ blacklisted=True
+ )
- value = {}
for go in game.musicgameorder_set.all():
- value[go.pk] = 1000 / (
- 1
- + (
- (go.musicgameanswer_set.filter(game__player=F("answer")).count())
- - 1 / game.players.count()
- )
- ** 2
- )
+ go.update_value()
for player in game.players.all():
- score = sum(
- [
- value[ga.game.pk]
- for ga in player.musicgameanswer_set.filter(game__game=game)
- .exclude(game__player=player)
- .filter(game__player=F("answer"))
- ]
- )
- score -= (
- 500
- * player.musicgameanswer_set.filter(game__game=game)
- .filter(game__player=player)
- .exclude(game__player=F("answer"))
- .count()
- )
+ score = player.musicgameanswer_set.score(game, player)
models.MusicGameResults.objects.create(
game=game, player=player, score=score
)
diff --git a/musik/settings.py b/musik/settings.py
index 230feaf..0f097d7 100644
--- a/musik/settings.py
+++ b/musik/settings.py
@@ -13,7 +13,7 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
import os
from pathlib import Path
-VERSION = "0.3.0"
+VERSION = "0.4.4"
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
diff --git a/pyproject.toml b/pyproject.toml
index f387aef..0be7cd8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "musik"
-version = "0.3.0"
+version = "0.4.4"
description = "Le jeu de Musik."
readme = "README.md"
requires-python = ">=3.12"
diff --git a/uv.lock b/uv.lock
index 3659c92..21e0387 100644
--- a/uv.lock
+++ b/uv.lock
@@ -423,7 +423,7 @@ wheels = [
[[package]]
name = "musik"
-version = "0.3.0"
+version = "0.4.4"
source = { virtual = "." }
dependencies = [
{ name = "celery" },