from django.db import models from django.db.models import Q, Max from django.conf import settings from songs.models import Song from django.utils import timezone class Playlist(models.Model): def __str__(self): return 'Playlist #' + str(self.id) class PlaylistSong(models.Model): playlist = models.ForeignKey( Playlist, on_delete=models.SET_NULL, blank=True, null=True ) song = models.ForeignKey( Song, on_delete=models.SET_NULL, blank=True, null=True ) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, blank=True, null=True ) played_at = models.DateTimeField(blank=True, null=True) # 0: Queued. # 1: Playing. # 2: Played. # 3: Cancelled. state = models.IntegerField(default=0, db_index=True) def move_up(self): other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__lt=self.id)\ .order_by('-id').first() self.switch_order(other_song) def move_down(self): other_song = PlaylistSong.objects.filter(playlist=self.playlist, id__gt=self.id).order_by('id').first() self.switch_order(other_song) def switch_order(self, other_song): old_id = self.id self.id = other_song.id other_song.id = old_id self.save() other_song.save() def __str__(self): return 'Playlist #' + str(self.playlist_id) + ': ' + str(self.song) class Queue(models.Model): class Meta: permissions = ( ('can_skip', 'Can skip the currently playing song'), ('can_move', 'Can move all songs in the queue'), ('can_cancel', 'Can cancel all songs in the queue'), ('can_control_volume', 'Can control the volume of Marietje'), ) name = models.TextField() playlist = models.ForeignKey( Playlist, on_delete=models.SET_NULL, blank=True, null=True, ) random_playlist = models.ForeignKey( Playlist, on_delete=models.SET_NULL, blank=True, null=True, related_name='random_playlist_set' ) started_at = models.DateTimeField(blank=True, null=True) songs = None player_token = models.TextField(blank=True, null=True) def get_songs(self): if self.songs is None: self.fill_random_queue() self.songs = PlaylistSong.objects\ .filter(Q(playlist=self.playlist_id) | Q(playlist_id=self.random_playlist_id), Q(state=0) | Q(state=1))\ .order_by('-state', 'playlist_id', 'id')\ .select_related('song', 'user') return self.songs def current_song(self): songs = self.get_songs() if len(songs) < 1: return None song = songs[0] if song.state != 1: song.state = 1 song.save() return song def queue(self): songs = self.get_songs() if len(songs) < 2: return [] return songs[1:] def request(self, song, user): playlist_songs = PlaylistSong.objects.filter(playlist=self.playlist, state=0).order_by('id') seconds_in_a_row = 0 for playlist_song in playlist_songs: if playlist_song.user != user: seconds_in_a_row = 0 else: seconds_in_a_row += playlist_song.song.duration now = timezone.now() if not user.is_superuser: if settings.LIMIT_ALWAYS: if seconds_in_a_row > settings.MAX_MINUTES_IN_A_ROW * 60: return False else: if seconds_in_a_row > 0 and \ seconds_in_a_row + song.duration > settings.MAX_MINUTES_IN_A_ROW * 60 and \ settings.LIMIT_HOURS[0] <= now.hour < settings.LIMIT_HOURS[1]: return False playlist_song = PlaylistSong(playlist=self.playlist, song=song, user=user) playlist_song.save() return True def fill_random_queue(self): song_count = PlaylistSong.objects.filter(playlist_id=self.random_playlist_id, state=0).count() while song_count < 5: song = Song.objects.filter(deleted=False).order_by('?').first() if song is None: return playlist_song = PlaylistSong(playlist=self.random_playlist, song=song, user=None) playlist_song.save() song_count += 1 def __str__(self): return self.name class QueueCommand(models.Model): queue = models.ForeignKey( Queue, on_delete=models.CASCADE, ) command = models.TextField() executed = models.BooleanField(default=False)