diff --git a/savepointradio/radio/managers.py b/savepointradio/radio/managers.py index f71bbbb..635067d 100644 --- a/savepointradio/radio/managers.py +++ b/savepointradio/radio/managers.py @@ -1,6 +1,7 @@ from datetime import timedelta -from decimal import * +from decimal import getcontext, Decimal, ROUND_UP +from django.apps import apps from django.db import models from django.utils import timezone @@ -17,9 +18,15 @@ class SongManager(models.Manager): Custom object manager for filtering out common behaviors for a playlist. """ def get_queryset(self): + """ + Return customized default QuerySet for Songs. + """ return SongQuerySet(self.model, using=self._db) def available(self): + """ + Songs that are currently published and are enabled. + """ return self.get_queryset().songs().enabled().published() def playlist_length(self): @@ -34,16 +41,33 @@ class SongManager(models.Manager): based on the replay ratio set in the application settings. """ wait = self.playlist_length() * Decimal(get_setting('replay_ratio')) - return wait.quantize(Decimal('.01'), rounding=ROUND_UP) + 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() - timedelta(seconds=float(self.wait_total())) + 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().filter( - models.Q(last_played__lt=self.datetime_from_wait()) | - models.Q(last_played__isnull=True) + models.Q(last_played__lt=self.datetime_from_wait()) | + models.Q(last_played__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 + SongRequest = apps.get_model(app_label='profiles', + model_name='SongRequest') + requests = SongRequest.music.unplayed().values_list('song__id', + flat=True) + return self.playable().exclude(id__in=requests) diff --git a/savepointradio/radio/models.py b/savepointradio/radio/models.py index 147e628..8303473 100644 --- a/savepointradio/radio/models.py +++ b/savepointradio/radio/models.py @@ -1,4 +1,7 @@ +from datetime import timedelta + from django.db import models +from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from core.behaviors import Timestampable @@ -42,15 +45,17 @@ class Artist(Disableable, Publishable, Timestampable, models.Model): @property def full_name(self): - if not self.alias: - return '{} {}'.format(self.first_name, self.last_name) - else: - if not self.first_name or not self.last_name: - return self.alias - else: + """ + String representing the artist's full name including an alias, if + available. + """ + if self.alias: + if self.first_name or self.last_name: return '{} "{}" {}'.format(self.first_name, self.alias, self.last_name) + return self.alias + return '{} {}'.format(self.first_name, self.last_name) def __str__(self): return self.full_name @@ -124,13 +129,48 @@ class Song(Disableable, Publishable, Timestampable, models.Model): @property def full_title(self): - if self.song_type == 'J': - return self.title - else: + """ + String representing the entire song title, including the game and + artists involved. + """ + if self.song_type == 'S': all_artists = ', '.join([a.full_name for a in self.artists.all()]) - return '{} - {} ({})'.format(self.game.title, + return '{} - {} [{}]'.format(self.game.title, self.title, all_artists) + return self.title + + def get_time_until_requestable(self): + """ + Length of time before a song can be requested again. + """ + if self.song_type == 'S': + if self.last_played: + allowed_datetime = Song.music.datetime_from_wait() + remaining_wait = self.last_played - allowed_datetime + if remaining_wait.total_seconds() > 0: + return remaining_wait + return timedelta(seconds=0) + return timedelta(seconds=0) + return None + + def get_date_when_requestable(self): + """ + Datetime when a song can be requested again. + """ + if self.song_type == 'S': + return self.last_played + Song.music.wait_total() + return None + + def _is_requestable(self): + """ + Can the song be requested or not? + """ + if self.song_type == 'S': + return self.get_date_when_requestable() <= timezone.now() + return False + _is_requestable.boolean = True + is_requestable = property(_is_requestable) def __str__(self): return self.title