Merge pull request '#26: mise à jour' (#40) from fix-1.0-26 into develop-1.0

Reviewed-on: rc/aircox#40
This commit is contained in:
Thomas Kairos
2022-03-20 12:31:32 +01:00
95 changed files with 14054 additions and 36412 deletions

View File

@ -7,6 +7,7 @@ import os
import shutil
import pytz
from django.conf import settings as conf
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import F, Q
@ -72,15 +73,18 @@ class Program(Page):
return os.path.join(settings.AIRCOX_PROGRAMS_DIR,
self.slug.replace('-', '_'))
@property
def abspath(self):
""" Return absolute path to program's dir """
return os.path.join(conf.MEDIA_ROOT, self.path)
@property
def archives_path(self):
return os.path.join(self.path, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR)
@property
def excerpts_path(self):
return os.path.join(
self.path, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR
)
return os.path.join(self.path, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR)
def __init__(self, *kargs, **kwargs):
super().__init__(*kargs, **kwargs)
@ -94,6 +98,8 @@ class Program(Page):
Return a Program from the given path. We assume the path has been
given in a previous time by this model (Program.path getter).
"""
if path.startswith(conf.MEDIA_ROOT):
path = path.replace(conf.MEDIA_ROOT + '/', '')
path = path.replace(settings.AIRCOX_PROGRAMS_DIR, '')
while path[0] == '/':
@ -107,10 +113,9 @@ class Program(Page):
Make sur the program's dir exists (and optionally subdir). Return True
if the dir (or subdir) exists.
"""
path = os.path.join(self.path, subdir) if subdir else \
self.path
path = os.path.join(self.abspath, subdir) if subdir else \
self.abspath
os.makedirs(path, exist_ok=True)
return os.path.exists(path)
class Meta:
@ -127,14 +132,15 @@ class Program(Page):
# TODO: move in signals
path_ = getattr(self, '__initial_path', None)
abspath = os.path.join(conf.MEDIA_ROOT, path_)
if path_ is not None and path_ != self.path and \
os.path.exists(path_) and not os.path.exists(self.path):
os.path.exists(abspath) and not os.path.exists(self.abspath):
logger.info('program #%s\'s dir changed to %s - update it.',
self.id, self.title)
shutil.move(path_, self.path)
shutil.move(abspath, self.abspath)
Sound.objects.filter(path__startswith=path_) \
.update(path=Concat('path', Substr(F('path'), len(path_))))
.update(file=Concat('file', Substr(F('file'), len(path_))))
class ProgramChildQuerySet(PageQuerySet):

View File

@ -2,9 +2,10 @@ from enum import IntEnum
import logging
import os
from django.conf import settings as main_settings
from django.conf import settings as conf
from django.db import models
from django.db.models import Q
from django.db.models import Q, Value as V
from django.db.models.functions import Concat
from django.utils import timezone as tz
from django.utils.translation import gettext_lazy as _
@ -47,18 +48,19 @@ class SoundQuerySet(models.QuerySet):
def paths(self, archive=True, order_by=True):
"""
Return paths as a flat list (exclude sound without path).
Return files absolute paths as a flat list (exclude sound without path).
If `order_by` is True, order by path.
"""
if archive:
self = self.archive()
if order_by:
self = self.order_by('path')
return self.filter(path__isnull=False).values_list('path', flat=True)
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)]
def search(self, query):
return self.filter(
Q(name__icontains=query) | Q(path__icontains=query) |
Q(name__icontains=query) | Q(file__icontains=query) |
Q(program__title__icontains=query) |
Q(episode__title__icontains=query)
)
@ -94,21 +96,15 @@ class Sound(models.Model):
position = models.PositiveSmallIntegerField(
_('order'), default=0, help_text=_('position in the playlist'),
)
# FIXME: url() does not use the same directory than here
# should we use FileField for more reliability?
path = models.FilePathField(
_('file'),
path=settings.AIRCOX_PROGRAMS_DIR,
match=r'(' + '|'.join(settings.AIRCOX_SOUND_FILE_EXT)
.replace('.', r'\.') + ')$',
recursive=True, max_length=255,
blank=True, null=True, unique=True,
def _upload_to(self, filename):
subdir = AIRCOX_SOUND_ARCHIVES_SUBDIR if self.type == self.TYPE_ARCHIVE else \
AIRCOX_SOUND_EXCERPTS_SUBDIR
return os.path.join(self.program.path, subdir, filename)
file = models.FileField(
_('file'), upload_to=_upload_to
)
#embed = models.TextField(
# _('embed'),
# blank=True, null=True,
# help_text=_('HTML code to embed a sound from an external plateform'),
#)
duration = models.TimeField(
_('duration'),
blank=True, null=True,
@ -134,8 +130,12 @@ class Sound(models.Model):
verbose_name = _('Sound')
verbose_name_plural = _('Sounds')
@property
def url(self):
return self.file and self.file.url
def __str__(self):
return '/'.join(self.path.split('/')[-3:])
return '/'.join(self.file.path.split('/')[-3:])
def save(self, check=True, *args, **kwargs):
if self.episode is not None and self.program is None:
@ -145,17 +145,12 @@ class Sound(models.Model):
self.__check_name()
super().save(*args, **kwargs)
def url(self):
""" Return an url to the file. """
path = self.path.replace(main_settings.MEDIA_ROOT, '', 1)
return (main_settings.MEDIA_URL + path).replace('//','/')
# TODO: rename get_file_mtime(self)
def get_mtime(self):
"""
Get the last modification date from file
"""
mtime = os.stat(self.path).st_mtime
mtime = os.stat(self.file.path).st_mtime
mtime = tz.datetime.fromtimestamp(mtime)
mtime = mtime.replace(microsecond=0)
return tz.make_aware(mtime, tz.get_current_timezone())
@ -163,7 +158,7 @@ class Sound(models.Model):
def file_exists(self):
""" Return true if the file still exists. """
return os.path.exists(self.path)
return os.path.exists(self.file.path)
def check_on_file(self):
"""
@ -173,7 +168,7 @@ class Sound(models.Model):
if not self.file_exists():
if self.type == self.TYPE_REMOVED:
return
logger.info('sound %s: has been removed', self.path)
logger.info('sound %s: has been removed', self.file.name)
self.type = self.TYPE_REMOVED
return True
@ -183,7 +178,7 @@ class Sound(models.Model):
if self.type == self.TYPE_REMOVED and self.program:
changed = True
self.type = self.TYPE_ARCHIVE \
if self.path.startswith(self.program.archives_path) else \
if self.file.name.startswith(self.program.archives_path) else \
self.TYPE_EXCERPT
# check mtime -> reset quality if changed (assume file changed)
@ -193,15 +188,15 @@ class Sound(models.Model):
self.mtime = mtime
self.is_good_quality = None
logger.info('sound %s: m_time has changed. Reset quality info',
self.path)
self.file.name)
return True
return changed
def __check_name(self):
if not self.name and self.path:
if not self.name and self.file and self.file.name:
# FIXME: later, remove date?
self.name = os.path.basename(self.path)
self.name = os.path.basename(self.file.name)
self.name = os.path.splitext(self.name)[0]
self.name = self.name.replace('_', ' ')