diff --git a/.gitignore b/.gitignore
index fd1ca31..e78eae4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,6 @@ venv/
node_modules/
*.egg-info/
*.egg
+
+db.sqlite3
+instance/settings/settings.py
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fe80aeb..dc52e78 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,14 +9,11 @@ repos:
rev: 23.1.0
hooks:
- id: black
- args:
- - --line-length=79
- - --exclude="""\.git|\.__pycache__|venv|_build|buck-out|build|dist"""
-- repo: https://github.com/PyCQA/flake8.git
- rev: 6.0.0
+- repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.0.292
hooks:
- - id: flake8
- exclude: ^instance/settings/|migrations/
+ - id: ruff
+ args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/PyCQA/docformatter.git
rev: v1.5.1
hooks:
diff --git a/README.md b/README.md
index 7362de1..88fdcd3 100755
--- a/README.md
+++ b/README.md
@@ -1,10 +1,9 @@

-Platform to manage a radio, schedules, website, and so on. We use the power of great tools like Django or Liquidsoap.
+A platform to manage radio schedules, website content, and more. It uses the power of great tools like Django or Liquidsoap.
This project is distributed under GPL version 3. More information in the LICENSE file, except for some files whose license is indicated inside source code.
-
## Features
* **streams**: multiple random music streams when no program is played. We also can specify a time range and frequency for each;
* **diffusions**: generate diffusions time slot for programs that have schedule informations. Check for conflicts and rerun.
@@ -15,7 +14,51 @@ This project is distributed under GPL version 3. More information in the LICENSE
* **cms**: content management system.
-## Scripts
+## Architecture and concepts
+Aircox is divided in two main modules:
+* `aircox`: basics of Aircox (programs, diffusions, sounds, etc. management); interface for managing a website with Aircox elements (playlists, timetable, players on the website);
+* `aircox_streamer`: interact with application to generate audio stream (LiquidSoap);
+
+## Development setup
+Start installing a virtual environment :
+
+```
+virtualenv venv
+source venv/bin/activate
+pip install -r requirements.txt
+pip install -r requirements_tests.txt
+```
+
+Then copy the default settings and initiate the database :
+
+```
+cp instance/settings/sample.py instance/settings/settings.py
+python -c "from django.core.management.utils import get_random_secret_key; print('SECRET_KEY = \"%s\"' % get_random_secret_key())" >> instance/settings/settings.py
+DJANGO_SETTINGS_MODULE=instance.settings.dev ./manage.py migrate
+```
+
+Finally test and run the instance using development settings, and point your browser to http://localhost:8000 :
+
+```
+DJANGO_SETTINGS_MODULE=instance.settings.dev pytest
+DJANGO_SETTINGS_MODULE=instance.settings.dev ./manage.py runserver
+```
+
+Before requesting a merge, enable pre-commit :
+
+```
+pip install pre-commit
+pre-commit install
+```
+
+## Installation
+Running Aircox on production involves:
+* Aircox modules and a running Django project;
+* a supervisor for common tasks (sounds monitoring, stream control, etc.) -- `supervisord`;
+* a wsgi and an HTTP server -- `gunicorn`, `nginx`;
+* a database supported by Django (MySQL, SQLite, PostGresSQL);
+
+### Scripts
Are included various configuration scripts that can be used to ease setup. They
assume that the project is present in `/srv/apps/aircox`:
@@ -27,7 +70,6 @@ The scripts are written with a combination of `cron`, `supervisord`, `nginx`
and `gunicorn` in mind.
-## Installation
### Dependencies
For python dependencies take a peek at the `requirements.txt` file, plus
dependencies specific to Django (e.g. for database: `mysqlclient` for MySql
@@ -62,8 +104,8 @@ pip install -r requirements.txt
```
### Configuration
-You must write a settings.py file in the `instance` directory (you can just
-copy and paste `instance/sample_settings.py`. There still is configuration
+You must write a settings.py file in the `instance/settings` directory (you can just
+copy and paste `instance/settings/sample.py`. There still is configuration
required in this file, check it in for more info.
diff --git a/aircox/admin/episode.py b/aircox/admin/episode.py
index 9061b14..346c169 100644
--- a/aircox/admin/episode.py
+++ b/aircox/admin/episode.py
@@ -18,9 +18,7 @@ class EpisodeAdminForm(ModelForm):
class EpisodeAdmin(SortableAdminBase, PageAdmin):
form = EpisodeAdminForm
list_display = PageAdmin.list_display
- list_filter = tuple(
- f for f in PageAdmin.list_filter if f != "pub_date"
- ) + (
+ list_filter = tuple(f for f in PageAdmin.list_filter if f != "pub_date") + (
"diffusion__start",
"pub_date",
)
diff --git a/aircox/admin/filters.py b/aircox/admin/filters.py
index f14f8e3..1bd2b59 100644
--- a/aircox/admin/filters.py
+++ b/aircox/admin/filters.py
@@ -14,13 +14,9 @@ class DateFieldFilter(filters.FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.field_generic = f"{field_path}__"
- self.date_params = {
- k: v for k, v in params.items() if k.startswith(self.field_generic)
- }
+ self.date_params = {k: v for k, v in params.items() if k.startswith(self.field_generic)}
- exact_lookup = (
- "date" if isinstance(field, models.DateTimeField) else "exact"
- )
+ exact_lookup = "date" if isinstance(field, models.DateTimeField) else "exact"
# links as: (label, param, input_type|None, value)
self.links = [
@@ -29,17 +25,11 @@ class DateFieldFilter(filters.FieldListFilter):
(_("Until"), self.field_generic + "lte", self.input_type),
]
if field.null:
- self.links.insert(
- 0, (_("None"), self.field_generic + "isnull", None, "1")
- )
+ self.links.insert(0, (_("None"), self.field_generic + "isnull", None, "1"))
- self.query_attrs = {
- k: v for k, v in request.GET.items() if k not in self.date_params
- }
+ self.query_attrs = {k: v for k, v in request.GET.items() if k not in self.date_params}
self.query_string = urlencode(self.query_attrs)
- super().__init__(
- field, request, params, model, model_admin, field_path
- )
+ super().__init__(field, request, params, model, model_admin, field_path)
def expected_parameters(self):
return [link[1] for link in self.links]
@@ -59,11 +49,7 @@ class DateFieldFilter(filters.FieldListFilter):
"value": value,
"type": link[2],
"query_attrs": self.query_attrs,
- "query_string": urlencode({link[1]: value})
- + "&"
- + self.query_string
- if value
- else self.query_string,
+ "query_string": urlencode({link[1]: value}) + "&" + self.query_string if value else self.query_string,
}
diff --git a/aircox/admin/page.py b/aircox/admin/page.py
index e8cc4d5..cb227af 100644
--- a/aircox/admin/page.py
+++ b/aircox/admin/page.py
@@ -50,11 +50,7 @@ class BasePageAdmin(admin.ModelAdmin):
change_form_template = "admin/aircox/page_change_form.html"
def cover_thumb(self, obj):
- return (
- mark_safe(''.format(obj.cover.icons["64"]))
- if obj.cover
- else ""
- )
+ return mark_safe('
'.format(obj.cover.icons["64"])) if obj.cover else ""
def get_changeform_initial_data(self, request):
data = super().get_changeform_initial_data(request)
@@ -65,9 +61,7 @@ class BasePageAdmin(admin.ModelAdmin):
def _get_common_context(self, query, extra_context=None):
extra_context = extra_context or {}
parent = query.get("parent", None)
- extra_context["parent"] = (
- None if parent is None else Page.objects.get_subclass(id=parent)
- )
+ extra_context["parent"] = None if parent is None else Page.objects.get_subclass(id=parent)
return extra_context
def render_change_form(self, request, context, *args, **kwargs):
@@ -94,9 +88,7 @@ class PageAdmin(BasePageAdmin):
search_fields = BasePageAdmin.search_fields + ("category__title",)
fieldsets = deepcopy(BasePageAdmin.fieldsets)
- fieldsets[0][1]["fields"].insert(
- fieldsets[0][1]["fields"].index("slug") + 1, "category"
- )
+ fieldsets[0][1]["fields"].insert(fieldsets[0][1]["fields"].index("slug") + 1, "category")
fieldsets[1][1]["fields"] += ("featured", "allow_comments")
diff --git a/aircox/admin/sound.py b/aircox/admin/sound.py
index 77c0dc5..74ea9fb 100644
--- a/aircox/admin/sound.py
+++ b/aircox/admin/sound.py
@@ -38,9 +38,7 @@ class SoundInline(admin.TabularInline):
max_num = 0
def audio(self, obj):
- return mark_safe(
- ''.format(obj.file.url)
- )
+ return mark_safe(''.format(obj.file.url))
audio.short_description = _("Audio")
@@ -86,13 +84,7 @@ class SoundAdmin(SortableAdminBase, admin.ModelAdmin):
def related(self, obj):
# TODO: link to episode or program edit
- return (
- obj.episode.title
- if obj.episode
- else obj.program.title
- if obj.program
- else ""
- )
+ return obj.episode.title if obj.episode else obj.program.title if obj.program else ""
related.short_description = _("Program / Episode")
diff --git a/aircox/admin_site.py b/aircox/admin_site.py
index bfb334f..2abd96e 100644
--- a/aircox/admin_site.py
+++ b/aircox/admin_site.py
@@ -26,21 +26,13 @@ class AdminSite(admin.AdminSite):
context.update(
{
# all programs
- "programs": models.Program.objects.active()
- .values("pk", "title")
- .order_by("title"),
+ "programs": models.Program.objects.active().values("pk", "title").order_by("title"),
# today's diffusions
- "diffusions": models.Diffusion.objects.date()
- .order_by("start")
- .select_related("episode"),
+ "diffusions": models.Diffusion.objects.date().order_by("start").select_related("episode"),
# TODO: only for dashboard
# last comments
- "comments": models.Comment.objects.order_by(
- "-date"
- ).select_related("page")[0:10],
- "latests": models.Page.objects.select_subclasses().order_by(
- "-pub_date"
- )[0:10],
+ "comments": models.Comment.objects.order_by("-date").select_related("page")[0:10],
+ "latests": models.Page.objects.select_subclasses().order_by("-pub_date")[0:10],
}
)
return context
@@ -69,9 +61,7 @@ class AdminSite(admin.AdminSite):
return [(label, reverse(url)) for label, url in self.tools]
def route_view(self, url, view, name, admin_view=True, label=None):
- self.extra_urls.append(
- path(url, self.admin_view(view) if admin_view else view, name=name)
- )
+ self.extra_urls.append(path(url, self.admin_view(view) if admin_view else view, name=name))
if label:
self.tools.append((label, "admin:" + name))
diff --git a/aircox/controllers/diffusion_monitor.py b/aircox/controllers/diffusion_monitor.py
index 9f5ced1..0e2468a 100644
--- a/aircox/controllers/diffusion_monitor.py
+++ b/aircox/controllers/diffusion_monitor.py
@@ -22,9 +22,7 @@ class DiffusionMonitor:
def update(self):
episodes, diffusions = [], []
- for schedule in Schedule.objects.filter(
- program__active=True, initial__isnull=True
- ):
+ for schedule in Schedule.objects.filter(program__active=True, initial__isnull=True):
eps, diffs = schedule.diffusions_of_month(self.date)
if eps:
episodes += eps
diff --git a/aircox/controllers/log_archiver.py b/aircox/controllers/log_archiver.py
index 4460180..9808580 100644
--- a/aircox/controllers/log_archiver.py
+++ b/aircox/controllers/log_archiver.py
@@ -44,9 +44,7 @@ class LogArchiver:
path = self.get_path(station, date)
# FIXME: remove binary mode
with gzip.open(path, "ab") as archive:
- data = yaml.dump(
- [self.serialize(line) for line in logs]
- ).encode("utf8")
+ data = yaml.dump([self.serialize(line) for line in logs]).encode("utf8")
archive.write(data)
if not keep:
@@ -95,10 +93,7 @@ class LogArchiver:
return [
Log(
- diffusion=rel_obj(log, "diffusion"),
- sound=rel_obj(log, "sound"),
- track=rel_obj(log, "track"),
- **log
+ diffusion=rel_obj(log, "diffusion"), sound=rel_obj(log, "sound"), track=rel_obj(log, "track"), **log
)
for log in logs
]
diff --git a/aircox/controllers/playlist_import.py b/aircox/controllers/playlist_import.py
index d0d7441..b2b1a75 100644
--- a/aircox/controllers/playlist_import.py
+++ b/aircox/controllers/playlist_import.py
@@ -50,14 +50,7 @@ class PlaylistImport:
logger.info("start reading csv " + self.path)
self.data = list(
csv.DictReader(
- (
- row
- for row in file
- if not (
- row.startswith("#") or row.startswith("\ufeff#")
- )
- and row.strip()
- ),
+ (row for row in file if not (row.startswith("#") or row.startswith("\ufeff#")) and row.strip()),
fieldnames=settings.IMPORT_PLAYLIST_CSV_COLS,
delimiter=settings.IMPORT_PLAYLIST_CSV_DELIMITER,
quotechar=settings.IMPORT_PLAYLIST_CSV_TEXT_QUOTE,
@@ -70,11 +63,7 @@ class PlaylistImport:
If save is true, save it into the database
"""
if self.track_kwargs.get("sound") is None:
- logger.error(
- "related track's sound is missing. Skip import of "
- + self.path
- + "."
- )
+ logger.error("related track's sound is missing. Skip import of " + self.path + ".")
return
maps = settings.IMPORT_PLAYLIST_CSV_COLS
@@ -87,17 +76,11 @@ class PlaylistImport:
return
try:
timestamp = (
- int(line.get("minutes") or 0) * 60
- + int(line.get("seconds") or 0)
- if has_timestamp
- else None
+ int(line.get("minutes") or 0) * 60 + int(line.get("seconds") or 0) if has_timestamp else None
)
track, created = Track.objects.get_or_create(
- title=line.get("title"),
- artist=line.get("artist"),
- position=index,
- **self.track_kwargs
+ title=line.get("title"), artist=line.get("artist"), position=index, **self.track_kwargs
)
track.timestamp = timestamp
track.info = line.get("info")
diff --git a/aircox/controllers/sound_file.py b/aircox/controllers/sound_file.py
index c2db65a..752da3e 100644
--- a/aircox/controllers/sound_file.py
+++ b/aircox/controllers/sound_file.py
@@ -58,14 +58,7 @@ class SoundFile:
def episode(self):
return self.sound and self.sound.episode
- def sync(
- self,
- sound=None,
- program=None,
- deleted=False,
- keep_deleted=False,
- **kwargs
- ):
+ def sync(self, sound=None, program=None, deleted=False, keep_deleted=False, **kwargs):
"""Update related sound model and save it."""
if deleted:
return self._on_delete(self.path, keep_deleted)
@@ -79,9 +72,7 @@ class SoundFile:
if sound:
created = False
else:
- sound, created = Sound.objects.get_or_create(
- file=self.sound_path, defaults=kwargs
- )
+ sound, created = Sound.objects.get_or_create(file=self.sound_path, defaults=kwargs)
self.sound = sound
self.path_info = self.read_path(self.path)
@@ -172,9 +163,7 @@ class SoundFile:
year, month, day = pi.get("year"), pi.get("month"), pi.get("day")
if pi.get("hour") is not None:
- at = tz.datetime(
- year, month, day, pi.get("hour", 0), pi.get("minute", 0)
- )
+ at = tz.datetime(year, month, day, pi.get("hour", 0), pi.get("minute", 0))
at = tz.make_aware(at)
else:
at = date(year, month, day)
@@ -210,22 +199,10 @@ class SoundFile:
if self.info and self.info.tags:
tags = self.info.tags
title, artist, album, year = tuple(
- t and ", ".join(t)
- for t in (
- tags.get(k)
- for k in ("title", "artist", "album", "year")
- )
- )
- title = (
- title
- or (self.path_info and self.path_info.get("name"))
- or os.path.basename(path_noext)
- )
- info = (
- "{} ({})".format(album, year)
- if album and year
- else album or year or ""
+ t and ", ".join(t) for t in (tags.get(k) for k in ("title", "artist", "album", "year"))
)
+ title = title or (self.path_info and self.path_info.get("name")) or os.path.basename(path_noext)
+ info = "{} ({})".format(album, year) if album and year else album or year or ""
track = Track(
sound=sound,
position=int(tags.get("tracknumber", 0)),
diff --git a/aircox/controllers/sound_monitor.py b/aircox/controllers/sound_monitor.py
index 82e7306..b7116a7 100644
--- a/aircox/controllers/sound_monitor.py
+++ b/aircox/controllers/sound_monitor.py
@@ -155,10 +155,7 @@ class MonitorHandler(PatternMatchingEventHandler):
self.jobs = jobs or {}
self.sync_kw = sync_kw
- patterns = [
- "*/{}/*{}".format(self.subdir, ext)
- for ext in settings.SOUND_FILE_EXT
- ]
+ patterns = ["*/{}/*{}".format(self.subdir, ext) for ext in settings.SOUND_FILE_EXT]
super().__init__(patterns=patterns, ignore_directories=True)
def on_created(self, event):
@@ -202,11 +199,7 @@ class SoundMonitor:
def report(self, program=None, component=None, *content, logger=logging):
content = " ".join([str(c) for c in content])
- logger.info(
- f"{program}: {content}"
- if not component
- else f"{program}, {component}: {content}"
- )
+ logger.info(f"{program}: {content}" if not component else f"{program}, {component}: {content}")
def scan(self, logger=logging):
"""For all programs, scan dirs.
@@ -234,9 +227,7 @@ class SoundMonitor:
dirs.append(program.abspath)
return dirs
- def scan_for_program(
- self, program, subdir, logger=logging, **sound_kwargs
- ):
+ def scan_for_program(self, program, subdir, logger=logging, **sound_kwargs):
"""Scan a given directory that is associated to the given program, and
update sounds information."""
logger.info("- %s/", subdir)
@@ -257,9 +248,7 @@ class SoundMonitor:
sounds.append(sound_file.sound.pk)
# sounds in db & unchecked
- sounds = Sound.objects.filter(file__startswith=subdir).exclude(
- pk__in=sounds
- )
+ sounds = Sound.objects.filter(file__startswith=subdir).exclude(pk__in=sounds)
self.check_sounds(sounds, program=program)
def check_sounds(self, qs, **sync_kwargs):
diff --git a/aircox/controllers/sound_stats.py b/aircox/controllers/sound_stats.py
index 3e2180d..652faf8 100644
--- a/aircox/controllers/sound_stats.py
+++ b/aircox/controllers/sound_stats.py
@@ -38,9 +38,7 @@ class SoxStats:
args += ["trim", str(at), str(length)]
args.append("stats")
- p = subprocess.Popen(
- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
- )
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# sox outputs to stderr (my god WHYYYY)
out_, out = p.communicate()
self.values = self.parse(str(out, encoding="utf-8"))
@@ -94,16 +92,8 @@ class SoundStats:
position += self.sample_length
def check(self, name, min_val, max_val):
- self.good = [
- index
- for index, stats in enumerate(self.stats)
- if min_val <= stats.get(name) <= max_val
- ]
- self.bad = [
- index
- for index, stats in enumerate(self.stats)
- if index not in self.good
- ]
+ self.good = [index for index, stats in enumerate(self.stats) if min_val <= stats.get(name) <= max_val]
+ self.bad = [index for index, stats in enumerate(self.stats) if index not in self.good]
self.resume()
def resume(self):
@@ -120,10 +110,6 @@ class SoundStats:
def _view(self, array):
return [
- "file"
- if index == 0
- else "sample {} (at {} seconds)".format(
- index, (index - 1) * self.sample_length
- )
+ "file" if index == 0 else "sample {} (at {} seconds)".format(index, (index - 1) * self.sample_length)
for index in array
]
diff --git a/aircox/converters.py b/aircox/converters.py
index afc99fb..f8a6492 100644
--- a/aircox/converters.py
+++ b/aircox/converters.py
@@ -35,11 +35,7 @@ class WeekConverter:
return datetime.datetime.strptime(value + "/1", "%G/%V/%u").date()
def to_url(self, value):
- return (
- value
- if isinstance(value, str)
- else "{:04d}/{:02d}".format(*value.isocalendar())
- )
+ return value if isinstance(value, str) else "{:04d}/{:02d}".format(*value.isocalendar())
class DateConverter:
@@ -52,10 +48,4 @@ class DateConverter:
return datetime.date(int(value[0]), int(value[1]), int(value[2]))
def to_url(self, value):
- return (
- value
- if isinstance(value, str)
- else "{:04d}/{:02d}/{:02d}".format(
- value.year, value.month, value.day
- )
- )
+ return value if isinstance(value, str) else "{:04d}/{:02d}/{:02d}".format(value.year, value.month, value.day)
diff --git a/aircox/filters.py b/aircox/filters.py
index 2d584f1..5393876 100644
--- a/aircox/filters.py
+++ b/aircox/filters.py
@@ -19,9 +19,7 @@ class PageFilters(filters.FilterSet):
class EpisodeFilters(PageFilters):
- podcast = filters.BooleanFilter(
- method="podcast_filter", label=_("Podcast")
- )
+ podcast = filters.BooleanFilter(method="podcast_filter", label=_("Podcast"))
class Meta:
model = Episode
diff --git a/aircox/management/commands/archiver.py b/aircox/management/commands/archiver.py
index 42531c0..e6c36ee 100644
--- a/aircox/management/commands/archiver.py
+++ b/aircox/management/commands/archiver.py
@@ -30,8 +30,7 @@ class Command(BaseCommand):
"--age",
type=int,
default=settings.LOGS_ARCHIVES_AGE,
- help="minimal age in days of logs to archive. Default is "
- "settings.LOGS_ARCHIVES_AGE",
+ help="minimal age in days of logs to archive. Default is " "settings.LOGS_ARCHIVES_AGE",
)
group.add_argument(
"-k",
diff --git a/aircox/management/commands/diffusions.py b/aircox/management/commands/diffusions.py
index 3c29234..d9f547e 100755
--- a/aircox/management/commands/diffusions.py
+++ b/aircox/management/commands/diffusions.py
@@ -55,14 +55,11 @@ class Command(BaseCommand):
group.add_argument(
"--next-month",
action="store_true",
- help="set the date to the next month of given date"
- " (if next month from today",
+ help="set the date to the next month of given date" " (if next month from today",
)
def handle(self, *args, **options):
- date = datetime.date(
- year=options["year"], month=options["month"], day=1
- )
+ date = datetime.date(year=options["year"], month=options["month"], day=1)
if options.get("next_month"):
month = options.get("month")
date += tz.timedelta(days=28)
diff --git a/aircox/management/commands/import_playlist.py b/aircox/management/commands/import_playlist.py
index 8a4c501..2c21327 100755
--- a/aircox/management/commands/import_playlist.py
+++ b/aircox/management/commands/import_playlist.py
@@ -51,18 +51,13 @@ class Command(BaseCommand):
def handle(self, path, *args, **options):
# FIXME: absolute/relative path of sounds vs given path
if options.get("sound"):
- sound = Sound.objects.filter(
- file__icontains=options.get("sound")
- ).first()
+ sound = Sound.objects.filter(file__icontains=options.get("sound")).first()
else:
path_, ext = os.path.splitext(path)
sound = Sound.objects.filter(path__icontains=path_).first()
if not sound:
- logger.error(
- "no sound found in the database for the path "
- "{path}".format(path=path)
- )
+ logger.error("no sound found in the database for the path " "{path}".format(path=path))
return
# FIXME: auto get sound.episode if any
diff --git a/aircox/management/commands/sounds_monitor.py b/aircox/management/commands/sounds_monitor.py
index 8c87643..ae17ee4 100755
--- a/aircox/management/commands/sounds_monitor.py
+++ b/aircox/management/commands/sounds_monitor.py
@@ -1,5 +1,4 @@
#! /usr/bin/env python3
-# TODO: SoundMonitor class
"""Monitor sound files; For each program, check for:
@@ -43,8 +42,7 @@ class Command(BaseCommand):
"-q",
"--quality_check",
action="store_true",
- help="Enable quality check using sound_quality_check on all "
- "sounds marqued as not good",
+ help="Enable quality check using sound_quality_check on all " "sounds marqued as not good",
)
parser.add_argument(
"-s",
@@ -57,15 +55,12 @@ class Command(BaseCommand):
"-m",
"--monitor",
action="store_true",
- help="Run in monitor mode, watch for modification in the "
- "filesystem and react in consequence",
+ help="Run in monitor mode, watch for modification in the " "filesystem and react in consequence",
)
def handle(self, *args, **options):
- SoundMonitor()
+ monitor = SoundMonitor()
if options.get("scan"):
- self.scan()
- # if options.get('quality_check'):
- # self.check_quality(check=(not options.get('scan')))
+ monitor.scan()
if options.get("monitor"):
- self.monitor()
+ monitor.monitor()
diff --git a/aircox/management/commands/sounds_quality_check.py b/aircox/management/commands/sounds_quality_check.py
index a69814c..5df11cf 100755
--- a/aircox/management/commands/sounds_quality_check.py
+++ b/aircox/management/commands/sounds_quality_check.py
@@ -28,8 +28,7 @@ class Command(BaseCommand):
"--sample_length",
type=int,
default=120,
- help="size of sample to analyse in seconds. If not set (or 0), "
- "does not analyse by sample",
+ help="size of sample to analyse in seconds. If not set (or 0), " "does not analyse by sample",
)
parser.add_argument(
"-a",
@@ -43,8 +42,7 @@ class Command(BaseCommand):
"--range",
type=float,
nargs=2,
- help="range of minimal and maximal accepted value such as: "
- "--range min max",
+ help="range of minimal and maximal accepted value such as: " "--range min max",
)
parser.add_argument(
"-i",
@@ -64,10 +62,7 @@ class Command(BaseCommand):
raise CommandError("no attribute specified")
# sound analyse and checks
- self.sounds = [
- SoundStats(path, options.get("sample_length"))
- for path in options.get("files")
- ]
+ self.sounds = [SoundStats(path, options.get("sample_length")) for path in options.get("files")]
self.bad = []
self.good = []
for sound in self.sounds:
diff --git a/aircox/migrations/0001_initial.py b/aircox/migrations/0001_initial.py
index 35d509d..2d21996 100644
--- a/aircox/migrations/0001_initial.py
+++ b/aircox/migrations/0001_initial.py
@@ -84,9 +84,7 @@ class Migration(migrations.Migration):
options={
"verbose_name": "Diffusion",
"verbose_name_plural": "Diffusions",
- "permissions": (
- ("programming", "edit the diffusion's planification"),
- ),
+ "permissions": (("programming", "edit the diffusion's planification"),),
},
),
migrations.CreateModel(
@@ -125,22 +123,16 @@ class Migration(migrations.Migration):
),
(
"content",
- ckeditor.fields.RichTextField(
- blank=True, null=True, verbose_name="content"
- ),
+ ckeditor.fields.RichTextField(blank=True, null=True, verbose_name="content"),
),
("pub_date", models.DateTimeField(blank=True, null=True)),
(
"featured",
- models.BooleanField(
- default=False, verbose_name="featured"
- ),
+ models.BooleanField(default=False, verbose_name="featured"),
),
(
"allow_comments",
- models.BooleanField(
- default=True, verbose_name="allow comments"
- ),
+ models.BooleanField(default=True, verbose_name="allow comments"),
),
(
"category",
@@ -458,9 +450,7 @@ class Migration(migrations.Migration):
("name", models.CharField(max_length=64, verbose_name="name")),
(
"slug",
- models.SlugField(
- max_length=64, unique=True, verbose_name="slug"
- ),
+ models.SlugField(max_length=64, unique=True, verbose_name="slug"),
),
(
"path",
@@ -566,9 +556,7 @@ class Migration(migrations.Migration):
),
(
"content",
- ckeditor.fields.RichTextField(
- blank=True, null=True, verbose_name="content"
- ),
+ ckeditor.fields.RichTextField(blank=True, null=True, verbose_name="content"),
),
(
"view",
@@ -949,9 +937,7 @@ class Migration(migrations.Migration):
),
(
"time",
- models.TimeField(
- help_text="start time", verbose_name="time"
- ),
+ models.TimeField(help_text="start time", verbose_name="time"),
),
(
"timezone",
@@ -1643,9 +1629,7 @@ class Migration(migrations.Migration):
),
(
"duration",
- models.TimeField(
- help_text="regular duration", verbose_name="duration"
- ),
+ models.TimeField(help_text="regular duration", verbose_name="duration"),
),
(
"frequency",
diff --git a/aircox/migrations/0004_auto_20200921_2356.py b/aircox/migrations/0004_auto_20200921_2356.py
index 7bdf8b3..59cc9de 100644
--- a/aircox/migrations/0004_auto_20200921_2356.py
+++ b/aircox/migrations/0004_auto_20200921_2356.py
@@ -33,9 +33,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="page",
name="content",
- field=ckeditor_uploader.fields.RichTextUploadingField(
- blank=True, null=True, verbose_name="content"
- ),
+ field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name="content"),
),
migrations.AlterField(
model_name="sound",
@@ -52,8 +50,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="staticpage",
name="content",
- field=ckeditor_uploader.fields.RichTextUploadingField(
- blank=True, null=True, verbose_name="content"
- ),
+ field=ckeditor_uploader.fields.RichTextUploadingField(blank=True, null=True, verbose_name="content"),
),
]
diff --git a/aircox/migrations/0008_alter_diffusion_options_track_album_and_more.py b/aircox/migrations/0008_alter_diffusion_options_track_album_and_more.py
index 8eee35e..2448a08 100644
--- a/aircox/migrations/0008_alter_diffusion_options_track_album_and_more.py
+++ b/aircox/migrations/0008_alter_diffusion_options_track_album_and_more.py
@@ -12,9 +12,7 @@ class Migration(migrations.Migration):
migrations.AlterModelOptions(
name="diffusion",
options={
- "permissions": (
- ("programming", "edit the diffusions' planification"),
- ),
+ "permissions": (("programming", "edit the diffusions' planification"),),
"verbose_name": "Diffusion",
"verbose_name_plural": "Diffusions",
},
@@ -22,9 +20,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="track",
name="album",
- field=models.CharField(
- default="", max_length=128, verbose_name="album"
- ),
+ field=models.CharField(default="", max_length=128, verbose_name="album"),
),
migrations.AlterField(
model_name="schedule",
diff --git a/aircox/migrations/0009_track_year.py b/aircox/migrations/0009_track_year.py
index d1bd0c3..063d8f9 100644
--- a/aircox/migrations/0009_track_year.py
+++ b/aircox/migrations/0009_track_year.py
@@ -12,8 +12,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name="track",
name="year",
- field=models.IntegerField(
- blank=True, null=True, verbose_name="year"
- ),
+ field=models.IntegerField(blank=True, null=True, verbose_name="year"),
),
]
diff --git a/aircox/migrations/0010_alter_track_album.py b/aircox/migrations/0010_alter_track_album.py
index 956875c..b502527 100644
--- a/aircox/migrations/0010_alter_track_album.py
+++ b/aircox/migrations/0010_alter_track_album.py
@@ -12,8 +12,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name="track",
name="album",
- field=models.CharField(
- blank=True, max_length=128, null=True, verbose_name="album"
- ),
+ field=models.CharField(blank=True, max_length=128, null=True, verbose_name="album"),
),
]
diff --git a/aircox/migrations/0011_usersettings.py b/aircox/migrations/0011_usersettings.py
index 2c42c3b..a2c78be 100644
--- a/aircox/migrations/0011_usersettings.py
+++ b/aircox/migrations/0011_usersettings.py
@@ -30,9 +30,7 @@ class Migration(migrations.Migration):
),
(
"playlist_editor_sep",
- models.CharField(
- max_length=16, verbose_name="Playlist Editor Separator"
- ),
+ models.CharField(max_length=16, verbose_name="Playlist Editor Separator"),
),
(
"user",
diff --git a/aircox/migrations/0014_alter_schedule_timezone.py b/aircox/migrations/0014_alter_schedule_timezone.py
new file mode 100644
index 0000000..078c78c
--- /dev/null
+++ b/aircox/migrations/0014_alter_schedule_timezone.py
@@ -0,0 +1,623 @@
+# Generated by Django 4.2.5 on 2023-10-18 07:26
+
+import aircox.models.schedule
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("aircox", "0013_alter_schedule_timezone_alter_station_hosts"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="schedule",
+ name="timezone",
+ field=models.CharField(
+ choices=[
+ ("Africa/Abidjan", "Africa/Abidjan"),
+ ("Africa/Accra", "Africa/Accra"),
+ ("Africa/Addis_Ababa", "Africa/Addis_Ababa"),
+ ("Africa/Algiers", "Africa/Algiers"),
+ ("Africa/Asmara", "Africa/Asmara"),
+ ("Africa/Asmera", "Africa/Asmera"),
+ ("Africa/Bamako", "Africa/Bamako"),
+ ("Africa/Bangui", "Africa/Bangui"),
+ ("Africa/Banjul", "Africa/Banjul"),
+ ("Africa/Bissau", "Africa/Bissau"),
+ ("Africa/Blantyre", "Africa/Blantyre"),
+ ("Africa/Brazzaville", "Africa/Brazzaville"),
+ ("Africa/Bujumbura", "Africa/Bujumbura"),
+ ("Africa/Cairo", "Africa/Cairo"),
+ ("Africa/Casablanca", "Africa/Casablanca"),
+ ("Africa/Ceuta", "Africa/Ceuta"),
+ ("Africa/Conakry", "Africa/Conakry"),
+ ("Africa/Dakar", "Africa/Dakar"),
+ ("Africa/Dar_es_Salaam", "Africa/Dar_es_Salaam"),
+ ("Africa/Djibouti", "Africa/Djibouti"),
+ ("Africa/Douala", "Africa/Douala"),
+ ("Africa/El_Aaiun", "Africa/El_Aaiun"),
+ ("Africa/Freetown", "Africa/Freetown"),
+ ("Africa/Gaborone", "Africa/Gaborone"),
+ ("Africa/Harare", "Africa/Harare"),
+ ("Africa/Johannesburg", "Africa/Johannesburg"),
+ ("Africa/Juba", "Africa/Juba"),
+ ("Africa/Kampala", "Africa/Kampala"),
+ ("Africa/Khartoum", "Africa/Khartoum"),
+ ("Africa/Kigali", "Africa/Kigali"),
+ ("Africa/Kinshasa", "Africa/Kinshasa"),
+ ("Africa/Lagos", "Africa/Lagos"),
+ ("Africa/Libreville", "Africa/Libreville"),
+ ("Africa/Lome", "Africa/Lome"),
+ ("Africa/Luanda", "Africa/Luanda"),
+ ("Africa/Lubumbashi", "Africa/Lubumbashi"),
+ ("Africa/Lusaka", "Africa/Lusaka"),
+ ("Africa/Malabo", "Africa/Malabo"),
+ ("Africa/Maputo", "Africa/Maputo"),
+ ("Africa/Maseru", "Africa/Maseru"),
+ ("Africa/Mbabane", "Africa/Mbabane"),
+ ("Africa/Mogadishu", "Africa/Mogadishu"),
+ ("Africa/Monrovia", "Africa/Monrovia"),
+ ("Africa/Nairobi", "Africa/Nairobi"),
+ ("Africa/Ndjamena", "Africa/Ndjamena"),
+ ("Africa/Niamey", "Africa/Niamey"),
+ ("Africa/Nouakchott", "Africa/Nouakchott"),
+ ("Africa/Ouagadougou", "Africa/Ouagadougou"),
+ ("Africa/Porto-Novo", "Africa/Porto-Novo"),
+ ("Africa/Sao_Tome", "Africa/Sao_Tome"),
+ ("Africa/Timbuktu", "Africa/Timbuktu"),
+ ("Africa/Tripoli", "Africa/Tripoli"),
+ ("Africa/Tunis", "Africa/Tunis"),
+ ("Africa/Windhoek", "Africa/Windhoek"),
+ ("America/Adak", "America/Adak"),
+ ("America/Anchorage", "America/Anchorage"),
+ ("America/Anguilla", "America/Anguilla"),
+ ("America/Antigua", "America/Antigua"),
+ ("America/Araguaina", "America/Araguaina"),
+ ("America/Argentina/Buenos_Aires", "America/Argentina/Buenos_Aires"),
+ ("America/Argentina/Catamarca", "America/Argentina/Catamarca"),
+ ("America/Argentina/ComodRivadavia", "America/Argentina/ComodRivadavia"),
+ ("America/Argentina/Cordoba", "America/Argentina/Cordoba"),
+ ("America/Argentina/Jujuy", "America/Argentina/Jujuy"),
+ ("America/Argentina/La_Rioja", "America/Argentina/La_Rioja"),
+ ("America/Argentina/Mendoza", "America/Argentina/Mendoza"),
+ ("America/Argentina/Rio_Gallegos", "America/Argentina/Rio_Gallegos"),
+ ("America/Argentina/Salta", "America/Argentina/Salta"),
+ ("America/Argentina/San_Juan", "America/Argentina/San_Juan"),
+ ("America/Argentina/San_Luis", "America/Argentina/San_Luis"),
+ ("America/Argentina/Tucuman", "America/Argentina/Tucuman"),
+ ("America/Argentina/Ushuaia", "America/Argentina/Ushuaia"),
+ ("America/Aruba", "America/Aruba"),
+ ("America/Asuncion", "America/Asuncion"),
+ ("America/Atikokan", "America/Atikokan"),
+ ("America/Atka", "America/Atka"),
+ ("America/Bahia", "America/Bahia"),
+ ("America/Bahia_Banderas", "America/Bahia_Banderas"),
+ ("America/Barbados", "America/Barbados"),
+ ("America/Belem", "America/Belem"),
+ ("America/Belize", "America/Belize"),
+ ("America/Blanc-Sablon", "America/Blanc-Sablon"),
+ ("America/Boa_Vista", "America/Boa_Vista"),
+ ("America/Bogota", "America/Bogota"),
+ ("America/Boise", "America/Boise"),
+ ("America/Buenos_Aires", "America/Buenos_Aires"),
+ ("America/Cambridge_Bay", "America/Cambridge_Bay"),
+ ("America/Campo_Grande", "America/Campo_Grande"),
+ ("America/Cancun", "America/Cancun"),
+ ("America/Caracas", "America/Caracas"),
+ ("America/Catamarca", "America/Catamarca"),
+ ("America/Cayenne", "America/Cayenne"),
+ ("America/Cayman", "America/Cayman"),
+ ("America/Chicago", "America/Chicago"),
+ ("America/Chihuahua", "America/Chihuahua"),
+ ("America/Ciudad_Juarez", "America/Ciudad_Juarez"),
+ ("America/Coral_Harbour", "America/Coral_Harbour"),
+ ("America/Cordoba", "America/Cordoba"),
+ ("America/Costa_Rica", "America/Costa_Rica"),
+ ("America/Creston", "America/Creston"),
+ ("America/Cuiaba", "America/Cuiaba"),
+ ("America/Curacao", "America/Curacao"),
+ ("America/Danmarkshavn", "America/Danmarkshavn"),
+ ("America/Dawson", "America/Dawson"),
+ ("America/Dawson_Creek", "America/Dawson_Creek"),
+ ("America/Denver", "America/Denver"),
+ ("America/Detroit", "America/Detroit"),
+ ("America/Dominica", "America/Dominica"),
+ ("America/Edmonton", "America/Edmonton"),
+ ("America/Eirunepe", "America/Eirunepe"),
+ ("America/El_Salvador", "America/El_Salvador"),
+ ("America/Ensenada", "America/Ensenada"),
+ ("America/Fort_Nelson", "America/Fort_Nelson"),
+ ("America/Fort_Wayne", "America/Fort_Wayne"),
+ ("America/Fortaleza", "America/Fortaleza"),
+ ("America/Glace_Bay", "America/Glace_Bay"),
+ ("America/Godthab", "America/Godthab"),
+ ("America/Goose_Bay", "America/Goose_Bay"),
+ ("America/Grand_Turk", "America/Grand_Turk"),
+ ("America/Grenada", "America/Grenada"),
+ ("America/Guadeloupe", "America/Guadeloupe"),
+ ("America/Guatemala", "America/Guatemala"),
+ ("America/Guayaquil", "America/Guayaquil"),
+ ("America/Guyana", "America/Guyana"),
+ ("America/Halifax", "America/Halifax"),
+ ("America/Havana", "America/Havana"),
+ ("America/Hermosillo", "America/Hermosillo"),
+ ("America/Indiana/Indianapolis", "America/Indiana/Indianapolis"),
+ ("America/Indiana/Knox", "America/Indiana/Knox"),
+ ("America/Indiana/Marengo", "America/Indiana/Marengo"),
+ ("America/Indiana/Petersburg", "America/Indiana/Petersburg"),
+ ("America/Indiana/Tell_City", "America/Indiana/Tell_City"),
+ ("America/Indiana/Vevay", "America/Indiana/Vevay"),
+ ("America/Indiana/Vincennes", "America/Indiana/Vincennes"),
+ ("America/Indiana/Winamac", "America/Indiana/Winamac"),
+ ("America/Indianapolis", "America/Indianapolis"),
+ ("America/Inuvik", "America/Inuvik"),
+ ("America/Iqaluit", "America/Iqaluit"),
+ ("America/Jamaica", "America/Jamaica"),
+ ("America/Jujuy", "America/Jujuy"),
+ ("America/Juneau", "America/Juneau"),
+ ("America/Kentucky/Louisville", "America/Kentucky/Louisville"),
+ ("America/Kentucky/Monticello", "America/Kentucky/Monticello"),
+ ("America/Knox_IN", "America/Knox_IN"),
+ ("America/Kralendijk", "America/Kralendijk"),
+ ("America/La_Paz", "America/La_Paz"),
+ ("America/Lima", "America/Lima"),
+ ("America/Los_Angeles", "America/Los_Angeles"),
+ ("America/Louisville", "America/Louisville"),
+ ("America/Lower_Princes", "America/Lower_Princes"),
+ ("America/Maceio", "America/Maceio"),
+ ("America/Managua", "America/Managua"),
+ ("America/Manaus", "America/Manaus"),
+ ("America/Marigot", "America/Marigot"),
+ ("America/Martinique", "America/Martinique"),
+ ("America/Matamoros", "America/Matamoros"),
+ ("America/Mazatlan", "America/Mazatlan"),
+ ("America/Mendoza", "America/Mendoza"),
+ ("America/Menominee", "America/Menominee"),
+ ("America/Merida", "America/Merida"),
+ ("America/Metlakatla", "America/Metlakatla"),
+ ("America/Mexico_City", "America/Mexico_City"),
+ ("America/Miquelon", "America/Miquelon"),
+ ("America/Moncton", "America/Moncton"),
+ ("America/Monterrey", "America/Monterrey"),
+ ("America/Montevideo", "America/Montevideo"),
+ ("America/Montreal", "America/Montreal"),
+ ("America/Montserrat", "America/Montserrat"),
+ ("America/Nassau", "America/Nassau"),
+ ("America/New_York", "America/New_York"),
+ ("America/Nipigon", "America/Nipigon"),
+ ("America/Nome", "America/Nome"),
+ ("America/Noronha", "America/Noronha"),
+ ("America/North_Dakota/Beulah", "America/North_Dakota/Beulah"),
+ ("America/North_Dakota/Center", "America/North_Dakota/Center"),
+ ("America/North_Dakota/New_Salem", "America/North_Dakota/New_Salem"),
+ ("America/Nuuk", "America/Nuuk"),
+ ("America/Ojinaga", "America/Ojinaga"),
+ ("America/Panama", "America/Panama"),
+ ("America/Pangnirtung", "America/Pangnirtung"),
+ ("America/Paramaribo", "America/Paramaribo"),
+ ("America/Phoenix", "America/Phoenix"),
+ ("America/Port-au-Prince", "America/Port-au-Prince"),
+ ("America/Port_of_Spain", "America/Port_of_Spain"),
+ ("America/Porto_Acre", "America/Porto_Acre"),
+ ("America/Porto_Velho", "America/Porto_Velho"),
+ ("America/Puerto_Rico", "America/Puerto_Rico"),
+ ("America/Punta_Arenas", "America/Punta_Arenas"),
+ ("America/Rainy_River", "America/Rainy_River"),
+ ("America/Rankin_Inlet", "America/Rankin_Inlet"),
+ ("America/Recife", "America/Recife"),
+ ("America/Regina", "America/Regina"),
+ ("America/Resolute", "America/Resolute"),
+ ("America/Rio_Branco", "America/Rio_Branco"),
+ ("America/Rosario", "America/Rosario"),
+ ("America/Santa_Isabel", "America/Santa_Isabel"),
+ ("America/Santarem", "America/Santarem"),
+ ("America/Santiago", "America/Santiago"),
+ ("America/Santo_Domingo", "America/Santo_Domingo"),
+ ("America/Sao_Paulo", "America/Sao_Paulo"),
+ ("America/Scoresbysund", "America/Scoresbysund"),
+ ("America/Shiprock", "America/Shiprock"),
+ ("America/Sitka", "America/Sitka"),
+ ("America/St_Barthelemy", "America/St_Barthelemy"),
+ ("America/St_Johns", "America/St_Johns"),
+ ("America/St_Kitts", "America/St_Kitts"),
+ ("America/St_Lucia", "America/St_Lucia"),
+ ("America/St_Thomas", "America/St_Thomas"),
+ ("America/St_Vincent", "America/St_Vincent"),
+ ("America/Swift_Current", "America/Swift_Current"),
+ ("America/Tegucigalpa", "America/Tegucigalpa"),
+ ("America/Thule", "America/Thule"),
+ ("America/Thunder_Bay", "America/Thunder_Bay"),
+ ("America/Tijuana", "America/Tijuana"),
+ ("America/Toronto", "America/Toronto"),
+ ("America/Tortola", "America/Tortola"),
+ ("America/Vancouver", "America/Vancouver"),
+ ("America/Virgin", "America/Virgin"),
+ ("America/Whitehorse", "America/Whitehorse"),
+ ("America/Winnipeg", "America/Winnipeg"),
+ ("America/Yakutat", "America/Yakutat"),
+ ("America/Yellowknife", "America/Yellowknife"),
+ ("Antarctica/Casey", "Antarctica/Casey"),
+ ("Antarctica/Davis", "Antarctica/Davis"),
+ ("Antarctica/DumontDUrville", "Antarctica/DumontDUrville"),
+ ("Antarctica/Macquarie", "Antarctica/Macquarie"),
+ ("Antarctica/Mawson", "Antarctica/Mawson"),
+ ("Antarctica/McMurdo", "Antarctica/McMurdo"),
+ ("Antarctica/Palmer", "Antarctica/Palmer"),
+ ("Antarctica/Rothera", "Antarctica/Rothera"),
+ ("Antarctica/South_Pole", "Antarctica/South_Pole"),
+ ("Antarctica/Syowa", "Antarctica/Syowa"),
+ ("Antarctica/Troll", "Antarctica/Troll"),
+ ("Antarctica/Vostok", "Antarctica/Vostok"),
+ ("Arctic/Longyearbyen", "Arctic/Longyearbyen"),
+ ("Asia/Aden", "Asia/Aden"),
+ ("Asia/Almaty", "Asia/Almaty"),
+ ("Asia/Amman", "Asia/Amman"),
+ ("Asia/Anadyr", "Asia/Anadyr"),
+ ("Asia/Aqtau", "Asia/Aqtau"),
+ ("Asia/Aqtobe", "Asia/Aqtobe"),
+ ("Asia/Ashgabat", "Asia/Ashgabat"),
+ ("Asia/Ashkhabad", "Asia/Ashkhabad"),
+ ("Asia/Atyrau", "Asia/Atyrau"),
+ ("Asia/Baghdad", "Asia/Baghdad"),
+ ("Asia/Bahrain", "Asia/Bahrain"),
+ ("Asia/Baku", "Asia/Baku"),
+ ("Asia/Bangkok", "Asia/Bangkok"),
+ ("Asia/Barnaul", "Asia/Barnaul"),
+ ("Asia/Beirut", "Asia/Beirut"),
+ ("Asia/Bishkek", "Asia/Bishkek"),
+ ("Asia/Brunei", "Asia/Brunei"),
+ ("Asia/Calcutta", "Asia/Calcutta"),
+ ("Asia/Chita", "Asia/Chita"),
+ ("Asia/Choibalsan", "Asia/Choibalsan"),
+ ("Asia/Chongqing", "Asia/Chongqing"),
+ ("Asia/Chungking", "Asia/Chungking"),
+ ("Asia/Colombo", "Asia/Colombo"),
+ ("Asia/Dacca", "Asia/Dacca"),
+ ("Asia/Damascus", "Asia/Damascus"),
+ ("Asia/Dhaka", "Asia/Dhaka"),
+ ("Asia/Dili", "Asia/Dili"),
+ ("Asia/Dubai", "Asia/Dubai"),
+ ("Asia/Dushanbe", "Asia/Dushanbe"),
+ ("Asia/Famagusta", "Asia/Famagusta"),
+ ("Asia/Gaza", "Asia/Gaza"),
+ ("Asia/Harbin", "Asia/Harbin"),
+ ("Asia/Hebron", "Asia/Hebron"),
+ ("Asia/Ho_Chi_Minh", "Asia/Ho_Chi_Minh"),
+ ("Asia/Hong_Kong", "Asia/Hong_Kong"),
+ ("Asia/Hovd", "Asia/Hovd"),
+ ("Asia/Irkutsk", "Asia/Irkutsk"),
+ ("Asia/Istanbul", "Asia/Istanbul"),
+ ("Asia/Jakarta", "Asia/Jakarta"),
+ ("Asia/Jayapura", "Asia/Jayapura"),
+ ("Asia/Jerusalem", "Asia/Jerusalem"),
+ ("Asia/Kabul", "Asia/Kabul"),
+ ("Asia/Kamchatka", "Asia/Kamchatka"),
+ ("Asia/Karachi", "Asia/Karachi"),
+ ("Asia/Kashgar", "Asia/Kashgar"),
+ ("Asia/Kathmandu", "Asia/Kathmandu"),
+ ("Asia/Katmandu", "Asia/Katmandu"),
+ ("Asia/Khandyga", "Asia/Khandyga"),
+ ("Asia/Kolkata", "Asia/Kolkata"),
+ ("Asia/Krasnoyarsk", "Asia/Krasnoyarsk"),
+ ("Asia/Kuala_Lumpur", "Asia/Kuala_Lumpur"),
+ ("Asia/Kuching", "Asia/Kuching"),
+ ("Asia/Kuwait", "Asia/Kuwait"),
+ ("Asia/Macao", "Asia/Macao"),
+ ("Asia/Macau", "Asia/Macau"),
+ ("Asia/Magadan", "Asia/Magadan"),
+ ("Asia/Makassar", "Asia/Makassar"),
+ ("Asia/Manila", "Asia/Manila"),
+ ("Asia/Muscat", "Asia/Muscat"),
+ ("Asia/Nicosia", "Asia/Nicosia"),
+ ("Asia/Novokuznetsk", "Asia/Novokuznetsk"),
+ ("Asia/Novosibirsk", "Asia/Novosibirsk"),
+ ("Asia/Omsk", "Asia/Omsk"),
+ ("Asia/Oral", "Asia/Oral"),
+ ("Asia/Phnom_Penh", "Asia/Phnom_Penh"),
+ ("Asia/Pontianak", "Asia/Pontianak"),
+ ("Asia/Pyongyang", "Asia/Pyongyang"),
+ ("Asia/Qatar", "Asia/Qatar"),
+ ("Asia/Qostanay", "Asia/Qostanay"),
+ ("Asia/Qyzylorda", "Asia/Qyzylorda"),
+ ("Asia/Rangoon", "Asia/Rangoon"),
+ ("Asia/Riyadh", "Asia/Riyadh"),
+ ("Asia/Saigon", "Asia/Saigon"),
+ ("Asia/Sakhalin", "Asia/Sakhalin"),
+ ("Asia/Samarkand", "Asia/Samarkand"),
+ ("Asia/Seoul", "Asia/Seoul"),
+ ("Asia/Shanghai", "Asia/Shanghai"),
+ ("Asia/Singapore", "Asia/Singapore"),
+ ("Asia/Srednekolymsk", "Asia/Srednekolymsk"),
+ ("Asia/Taipei", "Asia/Taipei"),
+ ("Asia/Tashkent", "Asia/Tashkent"),
+ ("Asia/Tbilisi", "Asia/Tbilisi"),
+ ("Asia/Tehran", "Asia/Tehran"),
+ ("Asia/Tel_Aviv", "Asia/Tel_Aviv"),
+ ("Asia/Thimbu", "Asia/Thimbu"),
+ ("Asia/Thimphu", "Asia/Thimphu"),
+ ("Asia/Tokyo", "Asia/Tokyo"),
+ ("Asia/Tomsk", "Asia/Tomsk"),
+ ("Asia/Ujung_Pandang", "Asia/Ujung_Pandang"),
+ ("Asia/Ulaanbaatar", "Asia/Ulaanbaatar"),
+ ("Asia/Ulan_Bator", "Asia/Ulan_Bator"),
+ ("Asia/Urumqi", "Asia/Urumqi"),
+ ("Asia/Ust-Nera", "Asia/Ust-Nera"),
+ ("Asia/Vientiane", "Asia/Vientiane"),
+ ("Asia/Vladivostok", "Asia/Vladivostok"),
+ ("Asia/Yakutsk", "Asia/Yakutsk"),
+ ("Asia/Yangon", "Asia/Yangon"),
+ ("Asia/Yekaterinburg", "Asia/Yekaterinburg"),
+ ("Asia/Yerevan", "Asia/Yerevan"),
+ ("Atlantic/Azores", "Atlantic/Azores"),
+ ("Atlantic/Bermuda", "Atlantic/Bermuda"),
+ ("Atlantic/Canary", "Atlantic/Canary"),
+ ("Atlantic/Cape_Verde", "Atlantic/Cape_Verde"),
+ ("Atlantic/Faeroe", "Atlantic/Faeroe"),
+ ("Atlantic/Faroe", "Atlantic/Faroe"),
+ ("Atlantic/Jan_Mayen", "Atlantic/Jan_Mayen"),
+ ("Atlantic/Madeira", "Atlantic/Madeira"),
+ ("Atlantic/Reykjavik", "Atlantic/Reykjavik"),
+ ("Atlantic/South_Georgia", "Atlantic/South_Georgia"),
+ ("Atlantic/St_Helena", "Atlantic/St_Helena"),
+ ("Atlantic/Stanley", "Atlantic/Stanley"),
+ ("Australia/ACT", "Australia/ACT"),
+ ("Australia/Adelaide", "Australia/Adelaide"),
+ ("Australia/Brisbane", "Australia/Brisbane"),
+ ("Australia/Broken_Hill", "Australia/Broken_Hill"),
+ ("Australia/Canberra", "Australia/Canberra"),
+ ("Australia/Currie", "Australia/Currie"),
+ ("Australia/Darwin", "Australia/Darwin"),
+ ("Australia/Eucla", "Australia/Eucla"),
+ ("Australia/Hobart", "Australia/Hobart"),
+ ("Australia/LHI", "Australia/LHI"),
+ ("Australia/Lindeman", "Australia/Lindeman"),
+ ("Australia/Lord_Howe", "Australia/Lord_Howe"),
+ ("Australia/Melbourne", "Australia/Melbourne"),
+ ("Australia/NSW", "Australia/NSW"),
+ ("Australia/North", "Australia/North"),
+ ("Australia/Perth", "Australia/Perth"),
+ ("Australia/Queensland", "Australia/Queensland"),
+ ("Australia/South", "Australia/South"),
+ ("Australia/Sydney", "Australia/Sydney"),
+ ("Australia/Tasmania", "Australia/Tasmania"),
+ ("Australia/Victoria", "Australia/Victoria"),
+ ("Australia/West", "Australia/West"),
+ ("Australia/Yancowinna", "Australia/Yancowinna"),
+ ("Brazil/Acre", "Brazil/Acre"),
+ ("Brazil/DeNoronha", "Brazil/DeNoronha"),
+ ("Brazil/East", "Brazil/East"),
+ ("Brazil/West", "Brazil/West"),
+ ("CET", "CET"),
+ ("CST6CDT", "CST6CDT"),
+ ("Canada/Atlantic", "Canada/Atlantic"),
+ ("Canada/Central", "Canada/Central"),
+ ("Canada/Eastern", "Canada/Eastern"),
+ ("Canada/Mountain", "Canada/Mountain"),
+ ("Canada/Newfoundland", "Canada/Newfoundland"),
+ ("Canada/Pacific", "Canada/Pacific"),
+ ("Canada/Saskatchewan", "Canada/Saskatchewan"),
+ ("Canada/Yukon", "Canada/Yukon"),
+ ("Chile/Continental", "Chile/Continental"),
+ ("Chile/EasterIsland", "Chile/EasterIsland"),
+ ("Cuba", "Cuba"),
+ ("EET", "EET"),
+ ("EST", "EST"),
+ ("EST5EDT", "EST5EDT"),
+ ("Egypt", "Egypt"),
+ ("Eire", "Eire"),
+ ("Etc/GMT", "Etc/GMT"),
+ ("Etc/GMT+0", "Etc/GMT+0"),
+ ("Etc/GMT+1", "Etc/GMT+1"),
+ ("Etc/GMT+10", "Etc/GMT+10"),
+ ("Etc/GMT+11", "Etc/GMT+11"),
+ ("Etc/GMT+12", "Etc/GMT+12"),
+ ("Etc/GMT+2", "Etc/GMT+2"),
+ ("Etc/GMT+3", "Etc/GMT+3"),
+ ("Etc/GMT+4", "Etc/GMT+4"),
+ ("Etc/GMT+5", "Etc/GMT+5"),
+ ("Etc/GMT+6", "Etc/GMT+6"),
+ ("Etc/GMT+7", "Etc/GMT+7"),
+ ("Etc/GMT+8", "Etc/GMT+8"),
+ ("Etc/GMT+9", "Etc/GMT+9"),
+ ("Etc/GMT-0", "Etc/GMT-0"),
+ ("Etc/GMT-1", "Etc/GMT-1"),
+ ("Etc/GMT-10", "Etc/GMT-10"),
+ ("Etc/GMT-11", "Etc/GMT-11"),
+ ("Etc/GMT-12", "Etc/GMT-12"),
+ ("Etc/GMT-13", "Etc/GMT-13"),
+ ("Etc/GMT-14", "Etc/GMT-14"),
+ ("Etc/GMT-2", "Etc/GMT-2"),
+ ("Etc/GMT-3", "Etc/GMT-3"),
+ ("Etc/GMT-4", "Etc/GMT-4"),
+ ("Etc/GMT-5", "Etc/GMT-5"),
+ ("Etc/GMT-6", "Etc/GMT-6"),
+ ("Etc/GMT-7", "Etc/GMT-7"),
+ ("Etc/GMT-8", "Etc/GMT-8"),
+ ("Etc/GMT-9", "Etc/GMT-9"),
+ ("Etc/GMT0", "Etc/GMT0"),
+ ("Etc/Greenwich", "Etc/Greenwich"),
+ ("Etc/UCT", "Etc/UCT"),
+ ("Etc/UTC", "Etc/UTC"),
+ ("Etc/Universal", "Etc/Universal"),
+ ("Etc/Zulu", "Etc/Zulu"),
+ ("Europe/Amsterdam", "Europe/Amsterdam"),
+ ("Europe/Andorra", "Europe/Andorra"),
+ ("Europe/Astrakhan", "Europe/Astrakhan"),
+ ("Europe/Athens", "Europe/Athens"),
+ ("Europe/Belfast", "Europe/Belfast"),
+ ("Europe/Belgrade", "Europe/Belgrade"),
+ ("Europe/Berlin", "Europe/Berlin"),
+ ("Europe/Bratislava", "Europe/Bratislava"),
+ ("Europe/Brussels", "Europe/Brussels"),
+ ("Europe/Bucharest", "Europe/Bucharest"),
+ ("Europe/Budapest", "Europe/Budapest"),
+ ("Europe/Busingen", "Europe/Busingen"),
+ ("Europe/Chisinau", "Europe/Chisinau"),
+ ("Europe/Copenhagen", "Europe/Copenhagen"),
+ ("Europe/Dublin", "Europe/Dublin"),
+ ("Europe/Gibraltar", "Europe/Gibraltar"),
+ ("Europe/Guernsey", "Europe/Guernsey"),
+ ("Europe/Helsinki", "Europe/Helsinki"),
+ ("Europe/Isle_of_Man", "Europe/Isle_of_Man"),
+ ("Europe/Istanbul", "Europe/Istanbul"),
+ ("Europe/Jersey", "Europe/Jersey"),
+ ("Europe/Kaliningrad", "Europe/Kaliningrad"),
+ ("Europe/Kiev", "Europe/Kiev"),
+ ("Europe/Kirov", "Europe/Kirov"),
+ ("Europe/Kyiv", "Europe/Kyiv"),
+ ("Europe/Lisbon", "Europe/Lisbon"),
+ ("Europe/Ljubljana", "Europe/Ljubljana"),
+ ("Europe/London", "Europe/London"),
+ ("Europe/Luxembourg", "Europe/Luxembourg"),
+ ("Europe/Madrid", "Europe/Madrid"),
+ ("Europe/Malta", "Europe/Malta"),
+ ("Europe/Mariehamn", "Europe/Mariehamn"),
+ ("Europe/Minsk", "Europe/Minsk"),
+ ("Europe/Monaco", "Europe/Monaco"),
+ ("Europe/Moscow", "Europe/Moscow"),
+ ("Europe/Nicosia", "Europe/Nicosia"),
+ ("Europe/Oslo", "Europe/Oslo"),
+ ("Europe/Paris", "Europe/Paris"),
+ ("Europe/Podgorica", "Europe/Podgorica"),
+ ("Europe/Prague", "Europe/Prague"),
+ ("Europe/Riga", "Europe/Riga"),
+ ("Europe/Rome", "Europe/Rome"),
+ ("Europe/Samara", "Europe/Samara"),
+ ("Europe/San_Marino", "Europe/San_Marino"),
+ ("Europe/Sarajevo", "Europe/Sarajevo"),
+ ("Europe/Saratov", "Europe/Saratov"),
+ ("Europe/Simferopol", "Europe/Simferopol"),
+ ("Europe/Skopje", "Europe/Skopje"),
+ ("Europe/Sofia", "Europe/Sofia"),
+ ("Europe/Stockholm", "Europe/Stockholm"),
+ ("Europe/Tallinn", "Europe/Tallinn"),
+ ("Europe/Tirane", "Europe/Tirane"),
+ ("Europe/Tiraspol", "Europe/Tiraspol"),
+ ("Europe/Ulyanovsk", "Europe/Ulyanovsk"),
+ ("Europe/Uzhgorod", "Europe/Uzhgorod"),
+ ("Europe/Vaduz", "Europe/Vaduz"),
+ ("Europe/Vatican", "Europe/Vatican"),
+ ("Europe/Vienna", "Europe/Vienna"),
+ ("Europe/Vilnius", "Europe/Vilnius"),
+ ("Europe/Volgograd", "Europe/Volgograd"),
+ ("Europe/Warsaw", "Europe/Warsaw"),
+ ("Europe/Zagreb", "Europe/Zagreb"),
+ ("Europe/Zaporozhye", "Europe/Zaporozhye"),
+ ("Europe/Zurich", "Europe/Zurich"),
+ ("Factory", "Factory"),
+ ("GB", "GB"),
+ ("GB-Eire", "GB-Eire"),
+ ("GMT", "GMT"),
+ ("GMT+0", "GMT+0"),
+ ("GMT-0", "GMT-0"),
+ ("GMT0", "GMT0"),
+ ("Greenwich", "Greenwich"),
+ ("HST", "HST"),
+ ("Hongkong", "Hongkong"),
+ ("Iceland", "Iceland"),
+ ("Indian/Antananarivo", "Indian/Antananarivo"),
+ ("Indian/Chagos", "Indian/Chagos"),
+ ("Indian/Christmas", "Indian/Christmas"),
+ ("Indian/Cocos", "Indian/Cocos"),
+ ("Indian/Comoro", "Indian/Comoro"),
+ ("Indian/Kerguelen", "Indian/Kerguelen"),
+ ("Indian/Mahe", "Indian/Mahe"),
+ ("Indian/Maldives", "Indian/Maldives"),
+ ("Indian/Mauritius", "Indian/Mauritius"),
+ ("Indian/Mayotte", "Indian/Mayotte"),
+ ("Indian/Reunion", "Indian/Reunion"),
+ ("Iran", "Iran"),
+ ("Israel", "Israel"),
+ ("Jamaica", "Jamaica"),
+ ("Japan", "Japan"),
+ ("Kwajalein", "Kwajalein"),
+ ("Libya", "Libya"),
+ ("MET", "MET"),
+ ("MST", "MST"),
+ ("MST7MDT", "MST7MDT"),
+ ("Mexico/BajaNorte", "Mexico/BajaNorte"),
+ ("Mexico/BajaSur", "Mexico/BajaSur"),
+ ("Mexico/General", "Mexico/General"),
+ ("NZ", "NZ"),
+ ("NZ-CHAT", "NZ-CHAT"),
+ ("Navajo", "Navajo"),
+ ("PRC", "PRC"),
+ ("PST8PDT", "PST8PDT"),
+ ("Pacific/Apia", "Pacific/Apia"),
+ ("Pacific/Auckland", "Pacific/Auckland"),
+ ("Pacific/Bougainville", "Pacific/Bougainville"),
+ ("Pacific/Chatham", "Pacific/Chatham"),
+ ("Pacific/Chuuk", "Pacific/Chuuk"),
+ ("Pacific/Easter", "Pacific/Easter"),
+ ("Pacific/Efate", "Pacific/Efate"),
+ ("Pacific/Enderbury", "Pacific/Enderbury"),
+ ("Pacific/Fakaofo", "Pacific/Fakaofo"),
+ ("Pacific/Fiji", "Pacific/Fiji"),
+ ("Pacific/Funafuti", "Pacific/Funafuti"),
+ ("Pacific/Galapagos", "Pacific/Galapagos"),
+ ("Pacific/Gambier", "Pacific/Gambier"),
+ ("Pacific/Guadalcanal", "Pacific/Guadalcanal"),
+ ("Pacific/Guam", "Pacific/Guam"),
+ ("Pacific/Honolulu", "Pacific/Honolulu"),
+ ("Pacific/Johnston", "Pacific/Johnston"),
+ ("Pacific/Kanton", "Pacific/Kanton"),
+ ("Pacific/Kiritimati", "Pacific/Kiritimati"),
+ ("Pacific/Kosrae", "Pacific/Kosrae"),
+ ("Pacific/Kwajalein", "Pacific/Kwajalein"),
+ ("Pacific/Majuro", "Pacific/Majuro"),
+ ("Pacific/Marquesas", "Pacific/Marquesas"),
+ ("Pacific/Midway", "Pacific/Midway"),
+ ("Pacific/Nauru", "Pacific/Nauru"),
+ ("Pacific/Niue", "Pacific/Niue"),
+ ("Pacific/Norfolk", "Pacific/Norfolk"),
+ ("Pacific/Noumea", "Pacific/Noumea"),
+ ("Pacific/Pago_Pago", "Pacific/Pago_Pago"),
+ ("Pacific/Palau", "Pacific/Palau"),
+ ("Pacific/Pitcairn", "Pacific/Pitcairn"),
+ ("Pacific/Pohnpei", "Pacific/Pohnpei"),
+ ("Pacific/Ponape", "Pacific/Ponape"),
+ ("Pacific/Port_Moresby", "Pacific/Port_Moresby"),
+ ("Pacific/Rarotonga", "Pacific/Rarotonga"),
+ ("Pacific/Saipan", "Pacific/Saipan"),
+ ("Pacific/Samoa", "Pacific/Samoa"),
+ ("Pacific/Tahiti", "Pacific/Tahiti"),
+ ("Pacific/Tarawa", "Pacific/Tarawa"),
+ ("Pacific/Tongatapu", "Pacific/Tongatapu"),
+ ("Pacific/Truk", "Pacific/Truk"),
+ ("Pacific/Wake", "Pacific/Wake"),
+ ("Pacific/Wallis", "Pacific/Wallis"),
+ ("Pacific/Yap", "Pacific/Yap"),
+ ("Poland", "Poland"),
+ ("Portugal", "Portugal"),
+ ("ROC", "ROC"),
+ ("ROK", "ROK"),
+ ("Singapore", "Singapore"),
+ ("Turkey", "Turkey"),
+ ("UCT", "UCT"),
+ ("US/Alaska", "US/Alaska"),
+ ("US/Aleutian", "US/Aleutian"),
+ ("US/Arizona", "US/Arizona"),
+ ("US/Central", "US/Central"),
+ ("US/East-Indiana", "US/East-Indiana"),
+ ("US/Eastern", "US/Eastern"),
+ ("US/Hawaii", "US/Hawaii"),
+ ("US/Indiana-Starke", "US/Indiana-Starke"),
+ ("US/Michigan", "US/Michigan"),
+ ("US/Mountain", "US/Mountain"),
+ ("US/Pacific", "US/Pacific"),
+ ("US/Samoa", "US/Samoa"),
+ ("UTC", "UTC"),
+ ("Universal", "Universal"),
+ ("W-SU", "W-SU"),
+ ("WET", "WET"),
+ ("Zulu", "Zulu"),
+ ("localtime", "localtime"),
+ ],
+ default=aircox.models.schedule.current_timezone_key,
+ help_text="timezone used for the date",
+ max_length=100,
+ verbose_name="timezone",
+ ),
+ ),
+ ]
diff --git a/aircox/models/diffusion.py b/aircox/models/diffusion.py
index 91e4c03..fbbe652 100644
--- a/aircox/models/diffusion.py
+++ b/aircox/models/diffusion.py
@@ -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
@@ -140,9 +130,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(
@@ -200,11 +188,7 @@ 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_today(self):
@@ -214,10 +198,7 @@ class Diffusion(Rerun):
@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).
@@ -227,9 +208,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):
@@ -241,9 +220,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)
@@ -265,8 +242,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()
diff --git a/aircox/models/episode.py b/aircox/models/episode.py
index 1183e2c..3df684d 100644
--- a/aircox/models/episode.py
+++ b/aircox/models/episode.py
@@ -28,10 +28,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)
diff --git a/aircox/models/log.py b/aircox/models/log.py
index c99b808..8d1d3e1 100644
--- a/aircox/models/log.py
+++ b/aircox/models/log.py
@@ -19,11 +19,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())
@@ -33,11 +29,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)
diff --git a/aircox/models/page.py b/aircox/models/page.py
index d541377..56d4811 100644
--- a/aircox/models/page.py
+++ b/aircox/models/page.py
@@ -26,9 +26,7 @@ __all__ = (
)
-headline_re = re.compile(
- r"(
)?" r"(?P
)?" r"(?P