''' Django Model Managers for the Radio application. ''' from datetime import timedelta from decimal import getcontext, Decimal, ROUND_UP from random import randint from django.apps import apps from django.db import models from django.utils import timezone from core.utils import get_setting from .querysets import RadioQuerySet, SongQuerySet # Set decimal precision getcontext().prec = 16 class RadioManager(models.Manager): ''' Custom object manager for filtering out common behaviors for radio objects. ''' def get_queryset(self): ''' Return customized default QuerySet. ''' return RadioQuerySet(self.model, using=self._db) def disabled(self): ''' Radio objects that are marked as disabled. ''' return self.get_queryset().disabled() def enabled(self): ''' Radio objects that are marked as enabled. ''' return self.get_queryset().enabled() def published(self): ''' Radio objects that are marked as published. ''' return self.get_queryset().published() def unpublished(self): ''' Radio objects that are marked as unpublished. ''' return self.get_queryset().unpublished() def available(self): ''' Radio objects that are enabled and published. ''' return self.enabled().published() class SongManager(RadioManager): ''' Custom object manager for filtering out common behaviors for Song objects. ''' def get_queryset(self): ''' Return customized default QuerySet for Songs. ''' return SongQuerySet(self.model, using=self._db) def available_jingles(self): ''' Jingles that are currently published and are enabled. ''' return self.available().jingles() def available_songs(self): ''' Songs that are currently published and are enabled. ''' return self.available().songs() def playlist_length(self): ''' Total length of available songs in the playlist (in seconds). ''' a_songs = self.available_songs() length = a_songs.aggregate( total_time=models.Sum('active_store__length') ) return length['total_time'] def wait_total(self, adjusted_ratio=0.0): ''' Default length in seconds before a song can be played again. This is based on the replay ratio set in the application settings. ''' total_ratio = get_setting('replay_ratio') + adjusted_ratio wait = self.playlist_length() * Decimal(total_ratio) wait = wait.quantize(Decimal('.01'), rounding=ROUND_UP) return timedelta(seconds=float(wait)) def datetime_from_wait(self): ''' Datetime of now minus the default wait time for played songs. ''' return timezone.now() - self.wait_total() def playable(self): ''' Songs that are playable because they are available (enabled & published) and they have not been played within the default wait time (or at all). ''' return self.available_songs().filter( models.Q(next_play__lt=timezone.now()) | models.Q(next_play__isnull=True) ) def requestable(self): ''' Songs that can be placed in the request queue for playback. ''' # Import SongRequest here to get rid of circular dependencies song_request = apps.get_model(app_label='profiles', model_name='SongRequest') requests = song_request.music.unplayed().values_list('song__id', flat=True) return self.playable().exclude(id__in=requests) def get_random_requestable_song(self): ''' Pick a random requestable song and return it. ''' return self.requestable()[randint(0, self.requestable().count() - 1)] def get_random_jingle(self): ''' Pick a random jingle and return it. ''' random_index = randint(0, self.available_jingles().count() - 1) return self.available_jingles()[random_index]