forked from rc/aircox
Feat: packaging (#127)
- Add configuration files for packaging - Precommit now uses ruff Co-authored-by: bkfox <thomas bkfox net> Reviewed-on: rc/aircox#127
This commit is contained in:
@ -19,11 +19,7 @@ __all__ = ("Diffusion", "DiffusionQuerySet")
|
||||
class DiffusionQuerySet(RerunQuerySet):
|
||||
def episode(self, episode=None, id=None):
|
||||
"""Diffusions for this episode."""
|
||||
return (
|
||||
self.filter(episode=episode)
|
||||
if id is None
|
||||
else self.filter(episode__id=id)
|
||||
)
|
||||
return self.filter(episode=episode) if id is None else self.filter(episode__id=id)
|
||||
|
||||
def on_air(self):
|
||||
"""On air diffusions."""
|
||||
@ -40,9 +36,7 @@ class DiffusionQuerySet(RerunQuerySet):
|
||||
"""Diffusions occuring date."""
|
||||
date = date or datetime.date.today()
|
||||
start = tz.make_aware(tz.datetime.combine(date, datetime.time()))
|
||||
end = tz.make_aware(
|
||||
tz.datetime.combine(date, datetime.time(23, 59, 59, 999))
|
||||
)
|
||||
end = tz.make_aware(tz.datetime.combine(date, datetime.time(23, 59, 59, 999)))
|
||||
# start = tz.get_current_timezone().localize(start)
|
||||
# end = tz.get_current_timezone().localize(end)
|
||||
qs = self.filter(start__range=(start, end))
|
||||
@ -50,11 +44,7 @@ class DiffusionQuerySet(RerunQuerySet):
|
||||
|
||||
def at(self, date, order=True):
|
||||
"""Return diffusions at specified date or datetime."""
|
||||
return (
|
||||
self.now(date, order)
|
||||
if isinstance(date, tz.datetime)
|
||||
else self.date(date, order)
|
||||
)
|
||||
return self.now(date, order) if isinstance(date, tz.datetime) else self.date(date, order)
|
||||
|
||||
def after(self, date=None):
|
||||
"""Return a queryset of diffusions that happen after the given date
|
||||
@ -142,9 +132,7 @@ class Diffusion(Rerun):
|
||||
class Meta:
|
||||
verbose_name = _("Diffusion")
|
||||
verbose_name_plural = _("Diffusions")
|
||||
permissions = (
|
||||
("programming", _("edit the diffusions' planification")),
|
||||
)
|
||||
permissions = (("programming", _("edit the diffusions' planification")),)
|
||||
|
||||
def __str__(self):
|
||||
str_ = "{episode} - {date}".format(
|
||||
@ -202,19 +190,12 @@ class Diffusion(Rerun):
|
||||
def is_now(self):
|
||||
"""True if diffusion is currently running."""
|
||||
now = tz.now()
|
||||
return (
|
||||
self.type == self.TYPE_ON_AIR
|
||||
and self.start <= now
|
||||
and self.end >= now
|
||||
)
|
||||
return self.type == self.TYPE_ON_AIR and self.start <= now and self.end >= now
|
||||
|
||||
@property
|
||||
def is_live(self):
|
||||
"""True if Diffusion is live (False if there are sounds files)."""
|
||||
return (
|
||||
self.type == self.TYPE_ON_AIR
|
||||
and not self.episode.sound_set.archive().count()
|
||||
)
|
||||
return self.type == self.TYPE_ON_AIR and not self.episode.sound_set.archive().count()
|
||||
|
||||
def get_playlist(self, **types):
|
||||
"""Returns sounds as a playlist (list of *local* archive file path).
|
||||
@ -224,9 +205,7 @@ class Diffusion(Rerun):
|
||||
from .sound import Sound
|
||||
|
||||
return list(
|
||||
self.get_sounds(**types)
|
||||
.filter(path__isnull=False, type=Sound.TYPE_ARCHIVE)
|
||||
.values_list("path", flat=True)
|
||||
self.get_sounds(**types).filter(path__isnull=False, type=Sound.TYPE_ARCHIVE).values_list("path", flat=True)
|
||||
)
|
||||
|
||||
def get_sounds(self, **types):
|
||||
@ -238,9 +217,7 @@ class Diffusion(Rerun):
|
||||
from .sound import Sound
|
||||
|
||||
sounds = (self.initial or self).sound_set.order_by("type", "path")
|
||||
_in = [
|
||||
getattr(Sound.Type, name) for name, value in types.items() if value
|
||||
]
|
||||
_in = [getattr(Sound.Type, name) for name, value in types.items() if value]
|
||||
|
||||
return sounds.filter(type__in=_in)
|
||||
|
||||
@ -262,8 +239,7 @@ class Diffusion(Rerun):
|
||||
# .filter(conflict_with=True)
|
||||
return (
|
||||
Diffusion.objects.filter(
|
||||
Q(start__lt=self.start, end__gt=self.start)
|
||||
| Q(start__gt=self.start, start__lt=self.end)
|
||||
Q(start__lt=self.start, end__gt=self.start) | Q(start__gt=self.start, start__lt=self.end)
|
||||
)
|
||||
.exclude(pk=self.pk)
|
||||
.distinct()
|
||||
|
@ -24,10 +24,7 @@ class Episode(Page):
|
||||
"""Return serialized data about podcasts."""
|
||||
from ..serializers import PodcastSerializer
|
||||
|
||||
podcasts = [
|
||||
PodcastSerializer(s).data
|
||||
for s in self.sound_set.public().order_by("type")
|
||||
]
|
||||
podcasts = [PodcastSerializer(s).data for s in self.sound_set.public().order_by("type")]
|
||||
if self.cover:
|
||||
options = {"size": (128, 128), "crop": "scale"}
|
||||
cover = get_thumbnailer(self.cover).get_thumbnail(options).url
|
||||
@ -76,6 +73,4 @@ class Episode(Page):
|
||||
if title is None
|
||||
else title
|
||||
)
|
||||
return super().get_init_kwargs_from(
|
||||
page, title=title, program=page, **kwargs
|
||||
)
|
||||
return super().get_init_kwargs_from(page, title=title, program=page, **kwargs)
|
||||
|
@ -18,11 +18,7 @@ __all__ = ("Log", "LogQuerySet")
|
||||
|
||||
class LogQuerySet(models.QuerySet):
|
||||
def station(self, station=None, id=None):
|
||||
return (
|
||||
self.filter(station=station)
|
||||
if id is None
|
||||
else self.filter(station_id=id)
|
||||
)
|
||||
return self.filter(station=station) if id is None else self.filter(station_id=id)
|
||||
|
||||
def date(self, date):
|
||||
start = tz.datetime.combine(date, datetime.time())
|
||||
@ -32,11 +28,7 @@ class LogQuerySet(models.QuerySet):
|
||||
# return self.filter(date__date=date)
|
||||
|
||||
def after(self, date):
|
||||
return (
|
||||
self.filter(date__gte=date)
|
||||
if isinstance(date, tz.datetime)
|
||||
else self.filter(date__date__gte=date)
|
||||
)
|
||||
return self.filter(date__gte=date) if isinstance(date, tz.datetime) else self.filter(date__date__gte=date)
|
||||
|
||||
def on_air(self):
|
||||
return self.filter(type=Log.TYPE_ON_AIR)
|
||||
|
@ -25,9 +25,7 @@ __all__ = (
|
||||
)
|
||||
|
||||
|
||||
headline_re = re.compile(
|
||||
r"(<p>)?" r"(?P<headline>[^\n]{1,140}(\n|[^\.]*?\.))" r"(</p>)?"
|
||||
)
|
||||
headline_re = re.compile(r"(<p>)?" r"(?P<headline>[^\n]{1,140}(\n|[^\.]*?\.))" r"(</p>)?")
|
||||
|
||||
|
||||
class Category(models.Model):
|
||||
@ -54,17 +52,11 @@ class BasePageQuerySet(InheritanceQuerySet):
|
||||
|
||||
def parent(self, parent=None, id=None):
|
||||
"""Return pages having this parent."""
|
||||
return (
|
||||
self.filter(parent=parent)
|
||||
if id is None
|
||||
else self.filter(parent__id=id)
|
||||
)
|
||||
return self.filter(parent=parent) if id is None else self.filter(parent__id=id)
|
||||
|
||||
def search(self, q, search_content=True):
|
||||
if search_content:
|
||||
return self.filter(
|
||||
models.Q(title__icontains=q) | models.Q(content__icontains=q)
|
||||
)
|
||||
return self.filter(models.Q(title__icontains=q) | models.Q(content__icontains=q))
|
||||
return self.filter(title__icontains=q)
|
||||
|
||||
|
||||
@ -89,9 +81,7 @@ class BasePage(models.Model):
|
||||
related_name="child_set",
|
||||
)
|
||||
title = models.CharField(max_length=100)
|
||||
slug = models.SlugField(
|
||||
_("slug"), max_length=120, blank=True, unique=True, db_index=True
|
||||
)
|
||||
slug = models.SlugField(_("slug"), max_length=120, blank=True, unique=True, db_index=True)
|
||||
status = models.PositiveSmallIntegerField(
|
||||
_("status"),
|
||||
default=STATUS_DRAFT,
|
||||
@ -132,11 +122,7 @@ class BasePage(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return (
|
||||
reverse(self.detail_url_name, kwargs={"slug": self.slug})
|
||||
if self.is_published
|
||||
else "#"
|
||||
)
|
||||
return reverse(self.detail_url_name, kwargs={"slug": self.slug}) if self.is_published else "#"
|
||||
|
||||
@property
|
||||
def is_draft(self):
|
||||
@ -177,9 +163,7 @@ class BasePage(models.Model):
|
||||
|
||||
class PageQuerySet(BasePageQuerySet):
|
||||
def published(self):
|
||||
return self.filter(
|
||||
status=Page.STATUS_PUBLISHED, pub_date__lte=tz.now()
|
||||
)
|
||||
return self.filter(status=Page.STATUS_PUBLISHED, pub_date__lte=tz.now())
|
||||
|
||||
|
||||
class Page(BasePage):
|
||||
@ -193,9 +177,7 @@ class Page(BasePage):
|
||||
null=True,
|
||||
db_index=True,
|
||||
)
|
||||
pub_date = models.DateTimeField(
|
||||
_("publication date"), blank=True, null=True, db_index=True
|
||||
)
|
||||
pub_date = models.DateTimeField(_("publication date"), blank=True, null=True, db_index=True)
|
||||
featured = models.BooleanField(
|
||||
_("featured"),
|
||||
default=False,
|
||||
@ -296,9 +278,7 @@ class Comment(models.Model):
|
||||
class NavItem(models.Model):
|
||||
"""Navigation menu items."""
|
||||
|
||||
station = models.ForeignKey(
|
||||
Station, models.CASCADE, verbose_name=_("station")
|
||||
)
|
||||
station = models.ForeignKey(Station, models.CASCADE, verbose_name=_("station"))
|
||||
menu = models.SlugField(_("menu"), max_length=24)
|
||||
order = models.PositiveSmallIntegerField(_("order"))
|
||||
text = models.CharField(_("title"), max_length=64)
|
||||
@ -318,13 +298,7 @@ class NavItem(models.Model):
|
||||
ordering = ("order", "pk")
|
||||
|
||||
def get_url(self):
|
||||
return (
|
||||
self.url
|
||||
if self.url
|
||||
else self.page.get_absolute_url()
|
||||
if self.page
|
||||
else None
|
||||
)
|
||||
return self.url if self.url else self.page.get_absolute_url() if self.page else None
|
||||
|
||||
def render(self, request, css_class="", active_class=""):
|
||||
url = self.get_url()
|
||||
@ -336,6 +310,4 @@ class NavItem(models.Model):
|
||||
elif not css_class:
|
||||
return format_html('<a href="{}">{}</a>', url, self.text)
|
||||
else:
|
||||
return format_html(
|
||||
'<a href="{}" class="{}">{}</a>', url, css_class, self.text
|
||||
)
|
||||
return format_html('<a href="{}" class="{}">{}</a>', url, css_class, self.text)
|
||||
|
@ -47,9 +47,7 @@ class Program(Page):
|
||||
"""
|
||||
|
||||
# explicit foreign key in order to avoid related name clashes
|
||||
station = models.ForeignKey(
|
||||
Station, models.CASCADE, verbose_name=_("station")
|
||||
)
|
||||
station = models.ForeignKey(Station, models.CASCADE, verbose_name=_("station"))
|
||||
active = models.BooleanField(
|
||||
_("active"),
|
||||
default=True,
|
||||
@ -126,12 +124,7 @@ class Program(Page):
|
||||
# TODO: move in signals
|
||||
path_ = getattr(self, "__initial_path", None)
|
||||
abspath = path_ and os.path.join(conf.MEDIA_ROOT, path_)
|
||||
if (
|
||||
path_ is not None
|
||||
and path_ != self.path
|
||||
and os.path.exists(abspath)
|
||||
and not os.path.exists(self.abspath)
|
||||
):
|
||||
if path_ is not None and path_ != self.path and os.path.exists(abspath) and not os.path.exists(self.abspath):
|
||||
logger.info(
|
||||
"program #%s's dir changed to %s - update it.",
|
||||
self.id,
|
||||
@ -139,9 +132,7 @@ class Program(Page):
|
||||
)
|
||||
|
||||
shutil.move(abspath, self.abspath)
|
||||
Sound.objects.filter(path__startswith=path_).update(
|
||||
file=Concat("file", Substr(F("file"), len(path_)))
|
||||
)
|
||||
Sound.objects.filter(path__startswith=path_).update(file=Concat("file", Substr(F("file"), len(path_))))
|
||||
|
||||
|
||||
class ProgramChildQuerySet(PageQuerySet):
|
||||
|
@ -15,18 +15,10 @@ class RerunQuerySet(models.QuerySet):
|
||||
"""Queryset for Rerun (sub)classes."""
|
||||
|
||||
def station(self, station=None, id=None):
|
||||
return (
|
||||
self.filter(program__station=station)
|
||||
if id is None
|
||||
else self.filter(program__station__id=id)
|
||||
)
|
||||
return self.filter(program__station=station) if id is None else self.filter(program__station__id=id)
|
||||
|
||||
def program(self, program=None, id=None):
|
||||
return (
|
||||
self.filter(program=program)
|
||||
if id is None
|
||||
else self.filter(program__id=id)
|
||||
)
|
||||
return self.filter(program=program) if id is None else self.filter(program__id=id)
|
||||
|
||||
def rerun(self):
|
||||
return self.filter(initial__isnull=False)
|
||||
@ -78,14 +70,8 @@ class Rerun(models.Model):
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if (
|
||||
hasattr(self, "start")
|
||||
and self.initial is not None
|
||||
and self.initial.start >= self.start
|
||||
):
|
||||
raise ValidationError(
|
||||
{"initial": _("rerun must happen after original")}
|
||||
)
|
||||
if hasattr(self, "start") and self.initial is not None and self.initial.start >= self.start:
|
||||
raise ValidationError({"initial": _("rerun must happen after original")})
|
||||
|
||||
def save_rerun(self):
|
||||
self.program = self.initial.program
|
||||
|
@ -102,11 +102,7 @@ class Schedule(Rerun):
|
||||
"""Return frequency formated for display."""
|
||||
from django.template.defaultfilters import date
|
||||
|
||||
return (
|
||||
self._get_FIELD_display(self._meta.get_field("frequency"))
|
||||
.format(day=date(self.date, "l"))
|
||||
.capitalize()
|
||||
)
|
||||
return self._get_FIELD_display(self._meta.get_field("frequency")).format(day=date(self.date, "l")).capitalize()
|
||||
|
||||
def normalize(self, date):
|
||||
"""Return a datetime set to schedule's time for the provided date,
|
||||
@ -124,9 +120,7 @@ class Schedule(Rerun):
|
||||
|
||||
# last of the month
|
||||
if freq == Schedule.Frequency.last:
|
||||
date = date.replace(
|
||||
day=calendar.monthrange(date.year, date.month)[1]
|
||||
)
|
||||
date = date.replace(day=calendar.monthrange(date.year, date.month)[1])
|
||||
date_wday = date.weekday()
|
||||
|
||||
# end of month before the wanted weekday: move one week back
|
||||
@ -138,9 +132,7 @@ class Schedule(Rerun):
|
||||
# move to the first day of the month that matches the schedule's
|
||||
# weekday. Check on SO#3284452 for the formula
|
||||
date_wday, month = date.weekday(), date.month
|
||||
date += tz.timedelta(
|
||||
days=(7 if date_wday > sched_wday else 0) - date_wday + sched_wday
|
||||
)
|
||||
date += tz.timedelta(days=(7 if date_wday > sched_wday else 0) - date_wday + sched_wday)
|
||||
|
||||
if freq == Schedule.Frequency.one_on_two:
|
||||
# - adjust date with modulo 14 (= 2 weeks in days)
|
||||
@ -149,11 +141,7 @@ class Schedule(Rerun):
|
||||
date += tz.timedelta(days=7)
|
||||
dates = (date + tz.timedelta(days=14 * i) for i in range(0, 3))
|
||||
else:
|
||||
dates = (
|
||||
date + tz.timedelta(days=7 * week)
|
||||
for week in range(0, 5)
|
||||
if freq & (0b1 << week)
|
||||
)
|
||||
dates = (date + tz.timedelta(days=7 * week) for week in range(0, 5) if freq & (0b1 << week))
|
||||
|
||||
return [self.normalize(date) for date in dates if date.month == month]
|
||||
|
||||
@ -166,29 +154,22 @@ class Schedule(Rerun):
|
||||
from .diffusion import Diffusion
|
||||
from .episode import Episode
|
||||
|
||||
if (
|
||||
self.initial is not None
|
||||
or self.frequency == Schedule.Frequency.ponctual
|
||||
):
|
||||
if self.initial is not None or self.frequency == Schedule.Frequency.ponctual:
|
||||
return [], []
|
||||
|
||||
# dates for self and reruns as (date, initial)
|
||||
reruns = [
|
||||
(rerun, rerun.date - self.date) for rerun in self.rerun_set.all()
|
||||
]
|
||||
reruns = [(rerun, rerun.date - self.date) for rerun in self.rerun_set.all()]
|
||||
|
||||
dates = {date: None for date in self.dates_of_month(date)}
|
||||
dates.update(
|
||||
(rerun.normalize(date.date() + delta), date)
|
||||
for date in list(dates.keys())
|
||||
for rerun, delta in reruns
|
||||
(rerun.normalize(date.date() + delta), date) for date in list(dates.keys()) for rerun, delta in reruns
|
||||
)
|
||||
|
||||
# remove dates corresponding to existing diffusions
|
||||
saved = set(
|
||||
Diffusion.objects.filter(
|
||||
start__in=dates.keys(), program=self.program, schedule=self
|
||||
).values_list("start", flat=True)
|
||||
Diffusion.objects.filter(start__in=dates.keys(), program=self.program, schedule=self).values_list(
|
||||
"start", flat=True
|
||||
)
|
||||
)
|
||||
|
||||
# make diffs
|
||||
|
@ -32,9 +32,7 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
|
||||
group, created = Group.objects.get_or_create(name=group_name)
|
||||
if created and permissions:
|
||||
for codename in permissions:
|
||||
permission = Permission.objects.filter(
|
||||
codename=codename
|
||||
).first()
|
||||
permission = Permission.objects.filter(codename=codename).first()
|
||||
if permission:
|
||||
group.permissions.add(permission)
|
||||
group.save()
|
||||
@ -44,9 +42,7 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
|
||||
@receiver(signals.post_save, sender=Page)
|
||||
def page_post_save(sender, instance, created, *args, **kwargs):
|
||||
if not created and instance.cover:
|
||||
Page.objects.filter(parent=instance, cover__isnull=True).update(
|
||||
cover=instance.cover
|
||||
)
|
||||
Page.objects.filter(parent=instance, cover__isnull=True).update(cover=instance.cover)
|
||||
|
||||
|
||||
@receiver(signals.post_save, sender=Program)
|
||||
@ -54,15 +50,11 @@ def program_post_save(sender, instance, created, *args, **kwargs):
|
||||
"""Clean-up later diffusions when a program becomes inactive."""
|
||||
if not instance.active:
|
||||
Diffusion.objects.program(instance).after(tz.now()).delete()
|
||||
Episode.objects.parent(instance).filter(
|
||||
diffusion__isnull=True
|
||||
).delete()
|
||||
Episode.objects.parent(instance).filter(diffusion__isnull=True).delete()
|
||||
|
||||
cover = getattr(instance, "__initial_cover", None)
|
||||
if cover is None and instance.cover is not None:
|
||||
Episode.objects.parent(instance).filter(cover__isnull=True).update(
|
||||
cover=instance.cover
|
||||
)
|
||||
Episode.objects.parent(instance).filter(cover__isnull=True).update(cover=instance.cover)
|
||||
|
||||
|
||||
@receiver(signals.pre_save, sender=Schedule)
|
||||
@ -77,8 +69,7 @@ def schedule_post_save(sender, instance, created, *args, **kwargs):
|
||||
corresponding diffusions accordingly."""
|
||||
initial = getattr(instance, "_initial", None)
|
||||
if not initial or (
|
||||
(instance.time, instance.duration, instance.timezone)
|
||||
== (initial.time, initial.duration, initial.timezone)
|
||||
(instance.time, instance.duration, instance.timezone) == (initial.time, initial.duration, initial.timezone)
|
||||
):
|
||||
return
|
||||
|
||||
@ -97,13 +88,9 @@ def schedule_post_save(sender, instance, created, *args, **kwargs):
|
||||
def schedule_pre_delete(sender, instance, *args, **kwargs):
|
||||
"""Delete later corresponding diffusion to a changed schedule."""
|
||||
Diffusion.objects.filter(schedule=instance).after(tz.now()).delete()
|
||||
Episode.objects.filter(
|
||||
diffusion__isnull=True, content__isnull=True, sound__isnull=True
|
||||
).delete()
|
||||
Episode.objects.filter(diffusion__isnull=True, content__isnull=True, sound__isnull=True).delete()
|
||||
|
||||
|
||||
@receiver(signals.post_delete, sender=Diffusion)
|
||||
def diffusion_post_delete(sender, instance, *args, **kwargs):
|
||||
Episode.objects.filter(
|
||||
diffusion__isnull=True, content__isnull=True, sound__isnull=True
|
||||
).delete()
|
||||
Episode.objects.filter(diffusion__isnull=True, content__isnull=True, sound__isnull=True).delete()
|
||||
|
@ -50,9 +50,7 @@ class SoundQuerySet(models.QuerySet):
|
||||
def path(self, paths):
|
||||
if isinstance(paths, str):
|
||||
return self.filter(file=paths.replace(conf.MEDIA_ROOT + "/", ""))
|
||||
return self.filter(
|
||||
file__in=(p.replace(conf.MEDIA_ROOT + "/", "") for p in paths)
|
||||
)
|
||||
return self.filter(file__in=(p.replace(conf.MEDIA_ROOT + "/", "") for p in paths))
|
||||
|
||||
def playlist(self, archive=True, order_by=True):
|
||||
"""Return files absolute paths as a flat list (exclude sound without
|
||||
@ -66,9 +64,7 @@ class SoundQuerySet(models.QuerySet):
|
||||
self = self.order_by("file")
|
||||
return [
|
||||
os.path.join(conf.MEDIA_ROOT, file)
|
||||
for file in self.filter(file__isnull=False).values_list(
|
||||
"file", flat=True
|
||||
)
|
||||
for file in self.filter(file__isnull=False).values_list("file", flat=True)
|
||||
]
|
||||
|
||||
def search(self, query):
|
||||
@ -122,11 +118,7 @@ class Sound(models.Model):
|
||||
)
|
||||
|
||||
def _upload_to(self, filename):
|
||||
subdir = (
|
||||
settings.SOUND_ARCHIVES_SUBDIR
|
||||
if self.type == self.TYPE_ARCHIVE
|
||||
else settings.SOUND_EXCERPTS_SUBDIR
|
||||
)
|
||||
subdir = settings.SOUND_ARCHIVES_SUBDIR if self.type == self.TYPE_ARCHIVE else settings.SOUND_EXCERPTS_SUBDIR
|
||||
return os.path.join(self.program.path, subdir, filename)
|
||||
|
||||
file = models.FileField(
|
||||
@ -161,10 +153,7 @@ class Sound(models.Model):
|
||||
)
|
||||
is_downloadable = models.BooleanField(
|
||||
_("downloadable"),
|
||||
help_text=_(
|
||||
"whether it can be publicly downloaded by visitors (sound must be "
|
||||
"public)"
|
||||
),
|
||||
help_text=_("whether it can be publicly downloaded by visitors (sound must be " "public)"),
|
||||
default=False,
|
||||
)
|
||||
|
||||
@ -224,9 +213,7 @@ class Sound(models.Model):
|
||||
if self.type == self.TYPE_REMOVED and self.program:
|
||||
changed = True
|
||||
self.type = (
|
||||
self.TYPE_ARCHIVE
|
||||
if self.file.name.startswith(self.program.archives_path)
|
||||
else self.TYPE_EXCERPT
|
||||
self.TYPE_ARCHIVE if self.file.name.startswith(self.program.archives_path) else self.TYPE_EXCERPT
|
||||
)
|
||||
|
||||
# check mtime -> reset quality if changed (assume file changed)
|
||||
@ -299,8 +286,7 @@ class Track(models.Model):
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text=_(
|
||||
"additional informations about this track, such as "
|
||||
"the version, if is it a remix, features, etc."
|
||||
"additional informations about this track, such as " "the version, if is it a remix, features, etc."
|
||||
),
|
||||
)
|
||||
|
||||
@ -310,13 +296,9 @@ class Track(models.Model):
|
||||
ordering = ("position",)
|
||||
|
||||
def __str__(self):
|
||||
return "{self.artist} -- {self.title} -- {self.position}".format(
|
||||
self=self
|
||||
)
|
||||
return "{self.artist} -- {self.title} -- {self.position}".format(self=self)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if (self.sound is None and self.episode is None) or (
|
||||
self.sound is not None and self.episode is not None
|
||||
):
|
||||
if (self.sound is None and self.episode is None) or (self.sound is not None and self.episode is not None):
|
||||
raise ValueError("sound XOR episode is required")
|
||||
super().save(*args, **kwargs)
|
||||
|
@ -67,9 +67,7 @@ class Station(models.Model):
|
||||
max_length=2048,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"Audio streams urls used by station's player. One url " "a line."
|
||||
),
|
||||
help_text=_("Audio streams urls used by station's player. One url " "a line."),
|
||||
)
|
||||
default_cover = FilerImageField(
|
||||
on_delete=models.SET_NULL,
|
||||
@ -153,16 +151,10 @@ class Port(models.Model):
|
||||
(TYPE_FILE, _("file")),
|
||||
)
|
||||
|
||||
station = models.ForeignKey(
|
||||
Station, models.CASCADE, verbose_name=_("station")
|
||||
)
|
||||
direction = models.SmallIntegerField(
|
||||
_("direction"), choices=DIRECTION_CHOICES
|
||||
)
|
||||
station = models.ForeignKey(Station, models.CASCADE, verbose_name=_("station"))
|
||||
direction = models.SmallIntegerField(_("direction"), choices=DIRECTION_CHOICES)
|
||||
type = models.SmallIntegerField(_("type"), choices=TYPE_CHOICES)
|
||||
active = models.BooleanField(
|
||||
_("active"), default=True, help_text=_("this port is active")
|
||||
)
|
||||
active = models.BooleanField(_("active"), default=True, help_text=_("this port is active"))
|
||||
settings = models.TextField(
|
||||
_("port settings"),
|
||||
help_text=_(
|
||||
@ -193,8 +185,6 @@ class Port(models.Model):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.is_valid_type():
|
||||
raise ValueError(
|
||||
"port type is not allowed with the given port direction"
|
||||
)
|
||||
raise ValueError("port type is not allowed with the given port direction")
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
@ -15,6 +15,4 @@ class UserSettings(models.Model):
|
||||
related_name="aircox_settings",
|
||||
)
|
||||
playlist_editor_columns = models.JSONField(_("Playlist Editor Columns"))
|
||||
playlist_editor_sep = models.CharField(
|
||||
_("Playlist Editor Separator"), max_length=16
|
||||
)
|
||||
playlist_editor_sep = models.CharField(_("Playlist Editor Separator"), max_length=16)
|
||||
|
Reference in New Issue
Block a user