add track to sound when scanning, using file's metadata (add mutagen as dep)

This commit is contained in:
bkfox 2016-11-28 17:09:46 +01:00
parent aa1c21a8c8
commit 0141d5174d
6 changed files with 141 additions and 67 deletions

View File

@ -116,21 +116,30 @@ class SoundInfo:
self.sound = sound
return sound
def find_playlist(self, sound):
def find_playlist(self, sound, use_default = True):
"""
Find a playlist file corresponding to the sound path
Find a playlist file corresponding to the sound path, such as:
my_sound.ogg => my_sound.csv
If use_default is True and there is no playlist find found,
use sound file's metadata.
"""
if sound.tracks.count():
return
import aircox.management.commands.import_playlist \
as import_playlist
# no playlist, try to retrieve metadata
path = os.path.splitext(self.sound.path)[0] + '.csv'
if not os.path.exists(path):
if use_default:
track = sound.file_metadata()
if track:
track.save()
return
old = Track.objects.get_for(object = sound)
if old:
return
# else, import
import_playlist.Importer(sound, path, save=True)
def find_diffusion(self, program, save = True):
@ -326,8 +335,10 @@ class Command(BaseCommand):
if check:
self.check_sounds(sounds)
files = [ sound.path for sound in sounds
if os.path.exists(sound.path) ]
files = [
sound.path for sound in sounds
if os.path.exists(sound.path) and sound.good_quality is None
]
# check quality
logger.info('quality check...',)

View File

@ -10,7 +10,7 @@ from django.template.defaultfilters import slugify
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils import timezone as tz
from django.utils.html import strip_tags
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.conf import settings as main_settings
@ -115,6 +115,54 @@ class Nameable(models.Model):
abstract = True
#
# Small common models
#
class Track(Related):
"""
Track of a playlist of an object. The position can either be expressed
as the position in the playlist or as the moment in seconds it started.
"""
# There are no nice solution for M2M relations ship (even without
# through) in django-admin. So we unfortunately need to make one-
# to-one relations and add a position argument
title = models.CharField (
_('title'),
max_length = 128,
)
artist = models.CharField(
_('artist'),
max_length = 128,
)
tags = TaggableManager(
verbose_name=_('tags'),
blank=True,
)
info = models.CharField(
_('information'),
max_length = 128,
blank = True, null = True,
help_text=_('additional informations about this track, such as '
'the version, if is it a remix, features, etc.'),
)
position = models.SmallIntegerField(
default = 0,
help_text=_('position in the playlist'),
)
in_seconds = models.BooleanField(
_('in seconds'),
default = False,
help_text=_('position in the playlist is expressed in seconds')
)
def __str__(self):
return '{self.artist} -- {self.title}'.format(self=self)
class Meta:
verbose_name = _('Track')
verbose_name_plural = _('Tracks')
#
# Station related classes
#
@ -208,8 +256,20 @@ class Station(Nameable):
logs.filter(date__gt = diff.end, date__lt = diff_.start) \
if diff_ else \
logs.filter(date__gt = diff.end)
print(diff.end, *[str(log.date > diff.end) + " " + str(log.date) for log in logs])
# a log can be started before the end of the diffusion and
# still is running => need to add it to the list and change
# the start date
partial_log = logs.filter(
date__gt = diff.start, date__lt = diff.end
).last()
if partial_log:
next_log = logs.filter(pk__gt = partial_log.pk).first()
if not next_log or next_log.date > diff.date:
partial_log.date = diff.end
logs_ = [partial_log] + list(logs_[:count])
# append to list
diff_ = diff
items.extend(logs_)
items.append(diff)
@ -252,6 +312,7 @@ class Station(Nameable):
logs = Log.objects.get_for(model = Track) \
.filter(station = self) \
.order_by('-date')
if date:
logs = logs.filter(date__contains = date)
diffs = Diffusion.objects.get_at(date)
@ -730,6 +791,8 @@ class Diffusion(models.Model):
start = models.DateTimeField( _('start of the diffusion') )
end = models.DateTimeField( _('end of the diffusion') )
tracks = GenericRelation(Track, 'related_id', 'related_type')
@property
def duration(self):
return self.end - self.start
@ -855,10 +918,10 @@ class Sound(Nameable):
blank = True, null = True,
help_text = _('last modification date and time'),
)
good_quality = models.BooleanField(
good_quality = models.NullBooleanField(
_('good quality'),
default = False,
help_text = _('sound\'s quality is okay')
help_text = _('sound\'s quality is okay'),
blank = True, null = True
)
public = models.BooleanField(
_('public'),
@ -866,6 +929,8 @@ class Sound(Nameable):
help_text = _('the sound is accessible to the public')
)
tracks = GenericRelation(Track, 'related_id', 'related_type')
def get_mtime(self):
"""
Get the last modification date from file
@ -891,6 +956,36 @@ class Sound(Nameable):
"""
return os.path.exists(self.path)
def file_metadata(self):
"""
Get metadata from sound file and return a Track object if succeed,
else None.
"""
if not self.file_exists():
return None
import mutagen
meta = mutagen.File(self.path)
def get_meta(key, cast=str):
value = meta.get(key)
return cast(value[0]) if value else None
info = '{} ({})'.format(get_meta('album'), get_meta('year')) \
if 'album' and 'year' in meta else \
get_meta('album') \
if 'album' else \
('year' in meta) and get_meta('year') or ''
track = Track(
related = self,
title = get_meta('title') or self.name,
artist = get_meta('artist') or _('unknown'),
info = info,
position = get_meta('tracknumber', int) or 0,
)
return track
def check_on_file(self):
"""
Check sound file info again'st self, and update informations if
@ -915,7 +1010,7 @@ class Sound(Nameable):
mtime = self.get_mtime()
if self.mtime != mtime:
self.mtime = mtime
self.good_quality = False
self.good_quality = None
logger.info('sound %s: m_time has changed. Reset quality info',
self.path)
return True
@ -965,50 +1060,6 @@ class Sound(Nameable):
verbose_name_plural = _('Sounds')
class Track(Related):
"""
Track of a playlist of an object. The position can either be expressed
as the position in the playlist or as the moment in seconds it started.
"""
# There are no nice solution for M2M relations ship (even without
# through) in django-admin. So we unfortunately need to make one-
# to-one relations and add a position argument
title = models.CharField (
_('title'),
max_length = 128,
)
artist = models.CharField(
_('artist'),
max_length = 128,
)
tags = TaggableManager(
verbose_name=_('tags'),
blank=True,
)
info = models.CharField(
_('information'),
max_length = 128,
blank = True, null = True,
help_text=_('additional informations about this track, such as '
'the version, if is it a remix, features, etc.'),
)
position = models.SmallIntegerField(
default = 0,
help_text=_('position in the playlist'),
)
in_seconds = models.BooleanField(
_('in seconds'),
default = False,
help_text=_('position in the playlist is expressed in seconds')
)
def __str__(self):
return '{self.artist} -- {self.title}'.format(self=self)
class Meta:
verbose_name = _('Track')
verbose_name_plural = _('Tracks')
#
# Controls and audio output
#

View File

@ -40,7 +40,7 @@ def on_air(request):
else:
station = stations.stations.first()
last = station.on_air(count = 1)
last = station.on_air(count = 10)
if not last:
return HttpResponse('')

View File

@ -462,6 +462,7 @@ class DatedListBase(models.Model):
# context dict
return {
'nav_dates': {
'today': today,
'date': date,
'next': next,
'prev': prev,
@ -935,12 +936,14 @@ class SectionLogsList(SectionItem):
print(log, type(log))
if type(log) == aircox.models.Diffusion:
return DiffusionPage.as_item(log)
related = log.related
return ListItem(
title = '{artist} -- {title}'.format(
artist = log.related.artist,
title = log.related.title,
artist = related.artist,
title = related.title,
),
summary = log.related.info,
summary = related.info,
date = log.date,
info = '',
css_class = 'track'

View File

@ -4,6 +4,8 @@
<div class="list date_list">
{% if nav_dates %}
<nav class="nav_dates">
<a href="?date={{ nav_dates.today|date:"Y-m-d" }}" title="{% trans "today" %}"></a>
{% if nav_dates.prev %}
<a href="?date={{ nav_dates.prev|date:"Y-m-d" }}" title="{% trans "previous days" %}"></a>
{% endif %}
@ -11,7 +13,9 @@
{% for day in nav_dates.dates %}
<a onclick="select_tab(this, '.panel[data-date=\'{{day|date:"Y-m-d"}}\']');"
{% if day == nav_dates.date %}selected{% endif %}
class="tab {% if day == nav_dates.date %}today{% endif %}">
class="tab {% if day == nav_dates.date %}today{% endif %}"
title="{{ day|date:"l d F Y" }}"
>
{{ day|date:'D. d' }}
</a>
{% endfor %}

View File

@ -1,9 +1,14 @@
Django>=1.9a1
Django>=1.10.3
django-taggit>=0.18.3
mutagen=1.35.1
watchdog>=0.8.3
wagtail>=1.5.3
Pillow>=3.3.0
django-honeypot>=0.5.0
dateutils>=0.6.6
bleach>=1.4.3
django-htmlmin>=0.10.0
wagtail>=1.5.3
django-overextend>=0.4.2
Pillow>=3.3.0
django-modelcluster=2.0
django-honeypot>=0.5.0
django-jet>=1.0.3