2018-03-28 16:42:28 +00:00
|
|
|
from datetime import timedelta
|
|
|
|
|
2017-12-29 14:56:47 +00:00
|
|
|
from django.db import models
|
2018-03-28 16:42:28 +00:00
|
|
|
from django.utils import timezone
|
2017-12-29 14:56:47 +00:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
2018-03-29 16:14:24 +00:00
|
|
|
from core.behaviors import Disableable, Publishable, Timestampable
|
|
|
|
from .managers import RadioManager, SongManager
|
2017-12-29 14:56:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Album(Disableable, Publishable, Timestampable, models.Model):
|
|
|
|
"""
|
|
|
|
A model for a music album.
|
|
|
|
"""
|
|
|
|
title = models.CharField(_('title'), max_length=255, unique=True)
|
|
|
|
|
2018-01-05 20:18:12 +00:00
|
|
|
sorted_title = models.CharField(_('naturalized title'),
|
|
|
|
db_index=True,
|
|
|
|
editable=False,
|
|
|
|
max_length=255)
|
|
|
|
|
2018-03-29 16:14:24 +00:00
|
|
|
objects = models.Manager()
|
|
|
|
music = RadioManager()
|
|
|
|
|
2018-01-12 21:34:43 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ['sorted_title', ]
|
|
|
|
|
2017-12-29 14:56:47 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.title
|
|
|
|
|
|
|
|
|
|
|
|
class Artist(Disableable, Publishable, Timestampable, models.Model):
|
|
|
|
"""
|
|
|
|
A model for a music artist.
|
|
|
|
"""
|
|
|
|
alias = models.CharField(_('alias'), max_length=127, blank=True)
|
|
|
|
first_name = models.CharField(_('first name'), max_length=127, blank=True)
|
|
|
|
last_name = models.CharField(_('last name'), max_length=127, blank=True)
|
|
|
|
|
2018-01-05 20:18:12 +00:00
|
|
|
sorted_full_name = models.CharField(_('naturalized full name'),
|
|
|
|
db_index=True,
|
|
|
|
editable=False,
|
|
|
|
max_length=255)
|
2018-01-04 21:29:29 +00:00
|
|
|
|
2018-03-29 16:14:24 +00:00
|
|
|
objects = models.Manager()
|
|
|
|
music = RadioManager()
|
|
|
|
|
2018-01-12 21:34:43 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ['sorted_full_name', ]
|
|
|
|
|
2017-12-29 14:56:47 +00:00
|
|
|
@property
|
|
|
|
def full_name(self):
|
2018-03-28 16:42:28 +00:00
|
|
|
"""
|
|
|
|
String representing the artist's full name including an alias, if
|
|
|
|
available.
|
|
|
|
"""
|
|
|
|
if self.alias:
|
|
|
|
if self.first_name or self.last_name:
|
2017-12-29 14:56:47 +00:00
|
|
|
return '{} "{}" {}'.format(self.first_name,
|
|
|
|
self.alias,
|
|
|
|
self.last_name)
|
2018-03-28 16:42:28 +00:00
|
|
|
return self.alias
|
|
|
|
return '{} {}'.format(self.first_name, self.last_name)
|
2017-12-29 14:56:47 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.full_name
|
|
|
|
|
|
|
|
|
|
|
|
class Game(Disableable, Publishable, Timestampable, models.Model):
|
|
|
|
"""
|
|
|
|
A model for a game.
|
|
|
|
"""
|
|
|
|
title = models.CharField(_('title'), max_length=255, unique=True)
|
|
|
|
|
2018-01-05 20:18:12 +00:00
|
|
|
sorted_title = models.CharField(_('naturalized title'),
|
|
|
|
db_index=True,
|
|
|
|
editable=False,
|
|
|
|
max_length=255)
|
|
|
|
|
2018-03-29 16:14:24 +00:00
|
|
|
objects = models.Manager()
|
|
|
|
music = RadioManager()
|
|
|
|
|
2018-01-12 21:34:43 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ['sorted_title', ]
|
|
|
|
|
2017-12-29 14:56:47 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.title
|
|
|
|
|
|
|
|
|
|
|
|
class Song(Disableable, Publishable, Timestampable, models.Model):
|
|
|
|
"""
|
|
|
|
A model for a song.
|
|
|
|
"""
|
|
|
|
JINGLE = 'J'
|
|
|
|
SONG = 'S'
|
|
|
|
TYPE_CHOICES = (
|
|
|
|
(JINGLE, 'Jingle'),
|
|
|
|
(SONG, 'Song'),
|
|
|
|
)
|
|
|
|
album = models.ForeignKey(Album,
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
null=True,
|
|
|
|
blank=True)
|
|
|
|
artists = models.ManyToManyField(Artist)
|
|
|
|
game = models.ForeignKey(Game,
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
null=True,
|
|
|
|
blank=True)
|
|
|
|
song_type = models.CharField(_('song type'),
|
|
|
|
max_length=1,
|
|
|
|
choices=TYPE_CHOICES,
|
|
|
|
default=SONG)
|
|
|
|
title = models.CharField(_('title'), max_length=255)
|
|
|
|
num_played = models.PositiveIntegerField(_('number of times played'),
|
|
|
|
default=0)
|
|
|
|
last_played = models.DateTimeField(_('was last played'),
|
|
|
|
null=True,
|
|
|
|
blank=True,
|
|
|
|
editable=False)
|
|
|
|
length = models.DecimalField(_('song length (in seconds)'),
|
|
|
|
max_digits=8,
|
|
|
|
decimal_places=2,
|
|
|
|
null=True,
|
|
|
|
blank=True)
|
|
|
|
path = models.TextField(_('absolute path to song file'))
|
|
|
|
|
2018-01-05 20:18:12 +00:00
|
|
|
sorted_title = models.CharField(_('naturalized title'),
|
|
|
|
db_index=True,
|
|
|
|
editable=False,
|
|
|
|
max_length=255)
|
|
|
|
|
2017-12-29 14:56:47 +00:00
|
|
|
objects = models.Manager()
|
|
|
|
music = SongManager()
|
|
|
|
|
2018-01-12 21:34:43 +00:00
|
|
|
class Meta:
|
|
|
|
ordering = ['sorted_title', ]
|
|
|
|
|
2018-03-30 15:06:45 +00:00
|
|
|
def _is_jingle(self):
|
|
|
|
"""
|
|
|
|
Is the object a jingle?
|
|
|
|
"""
|
|
|
|
return self.song_type == 'J'
|
|
|
|
_is_jingle.boolean = True
|
|
|
|
is_jingle = property(_is_jingle)
|
|
|
|
|
|
|
|
def _is_song(self):
|
|
|
|
"""
|
|
|
|
Is the object a song?
|
|
|
|
"""
|
|
|
|
return self.song_type == 'S'
|
|
|
|
_is_song.boolean = True
|
|
|
|
is_song = property(_is_song)
|
|
|
|
|
2018-03-30 16:46:21 +00:00
|
|
|
def _is_available(self):
|
|
|
|
"""
|
|
|
|
Is the object both enabled and published?
|
|
|
|
"""
|
|
|
|
return self._is_enabled() and self._is_published()
|
|
|
|
_is_available.boolean = True
|
|
|
|
is_available = property(_is_available)
|
|
|
|
|
2018-03-30 15:06:45 +00:00
|
|
|
def _full_title(self):
|
2018-03-28 16:42:28 +00:00
|
|
|
"""
|
|
|
|
String representing the entire song title, including the game and
|
|
|
|
artists involved.
|
|
|
|
"""
|
2018-03-30 15:06:45 +00:00
|
|
|
if self._is_song():
|
2018-03-29 20:22:15 +00:00
|
|
|
enabled_artists = self.artists.all().filter(disabled=False)
|
|
|
|
all_artists = ', '.join([a.full_name for a in enabled_artists])
|
2018-03-28 16:42:28 +00:00
|
|
|
return '{} - {} [{}]'.format(self.game.title,
|
2017-12-29 14:56:47 +00:00
|
|
|
self.title,
|
|
|
|
all_artists)
|
2018-03-28 16:42:28 +00:00
|
|
|
return self.title
|
2018-03-30 15:06:45 +00:00
|
|
|
full_title = property(_full_title)
|
2018-03-28 16:42:28 +00:00
|
|
|
|
|
|
|
def get_time_until_requestable(self):
|
|
|
|
"""
|
|
|
|
Length of time before a song can be requested again.
|
|
|
|
"""
|
2018-03-30 16:46:21 +00:00
|
|
|
if self._is_song() and self._is_available():
|
2018-03-28 16:42:28 +00:00
|
|
|
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.
|
|
|
|
"""
|
2018-03-30 16:46:21 +00:00
|
|
|
if self._is_song() and self._is_available():
|
2018-03-30 16:35:02 +00:00
|
|
|
if self.last_played:
|
|
|
|
return self.last_played + Song.music.wait_total()
|
|
|
|
return timezone.now()
|
2018-03-28 16:42:28 +00:00
|
|
|
return None
|
|
|
|
|
|
|
|
def _is_requestable(self):
|
|
|
|
"""
|
|
|
|
Can the song be requested or not?
|
|
|
|
"""
|
2018-03-30 16:46:21 +00:00
|
|
|
if self._is_song() and self._is_available():
|
2018-03-28 16:42:28 +00:00
|
|
|
return self.get_date_when_requestable() <= timezone.now()
|
|
|
|
return False
|
|
|
|
_is_requestable.boolean = True
|
|
|
|
is_requestable = property(_is_requestable)
|
2018-01-12 21:34:43 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.title
|