aircox-radiocampus/aircox/management/commands/import_playlist.py
2016-10-10 15:04:15 +02:00

143 lines
4.6 KiB
Python

"""
Import one or more playlist for the given sound. Attach it to the sound
or to the related Diffusion if wanted.
Playlists are in CSV format, where columns are separated with a
'{settings.AIRCOX_IMPORT_PLAYLIST_CSV_DELIMITER}'. Text quote is
{settings.AIRCOX_IMPORT_PLAYLIST_CSV_TEXT_QUOTE}.
The order of the elements is: {settings.AIRCOX_IMPORT_PLAYLIST_CSV_COLS}
If 'minutes' or 'seconds' are given, position will be expressed as timed
position, instead of position in playlist.
"""
import os
import csv
import logging
from argparse import RawTextHelpFormatter
from django.core.management.base import BaseCommand, CommandError
from django.contrib.contenttypes.models import ContentType
from aircox.models import *
import aircox.settings as settings
__doc__ = __doc__.format(settings = settings)
logger = logging.getLogger('aircox.tools')
class Importer:
data = None
tracks = None
def __init__(self, related = None, path = None, save = False):
if path:
self.read(path)
if related:
self.make_playlist(related, save)
def reset(self):
self.data = None
self.tracks = None
def read(self, path):
if not os.path.exists(path):
return True
with open(path, 'r') as file:
self.data = list(csv.reader(
file,
delimiter = settings.AIRCOX_IMPORT_PLAYLIST_CSV_DELIMITER,
quotechar = settings.AIRCOX_IMPORT_PLAYLIST_CSV_TEXT_QUOTE,
))
def __get(self, line, field, default = None):
maps = settings.AIRCOX_IMPORT_PLAYLIST_CSV_COLS
if field not in maps:
return default
index = maps.index(field)
return line[index] if index < len(line) else default
def make_playlist(self, related, save = False):
"""
Make a playlist from the read data, and return it. If save is
true, save it into the database
"""
maps = settings.AIRCOX_IMPORT_PLAYLIST_CSV_COLS
tracks = []
in_seconds = ('minutes' or 'seconds') in maps
for index, line in enumerate(self.data):
position = \
int(self.__get(line, 'minutes', 0)) * 60 + \
int(self.__get(line, 'seconds', 0)) \
if in_seconds else index
track, created = Track.objects.get_or_create(
related_type = ContentType.objects.get_for_model(related),
related_id = related.pk,
title = self.__get(line, 'title'),
artist = self.__get(line, 'artist'),
position = position,
)
track.in_seconds = in_seconds
track.info = self.__get(line, 'info')
tags = self.__get(line, 'tags')
if tags:
track.tags.add(*tags.split(','))
if save:
track.save()
tracks.append(track)
self.tracks = tracks
return tracks
class Command (BaseCommand):
help= __doc__
def add_arguments (self, parser):
parser.formatter_class=RawTextHelpFormatter
now = tz.datetime.today()
parser.add_argument(
'path', metavar='PATH', type=str,
help='path of the input playlist to read'
)
parser.add_argument(
'--sound', '-s', type=str,
help='generate a playlist for the sound of the given path. '
'If not given, try to match a sound with the same path.'
)
parser.add_argument(
'--diffusion', '-d', action='store_true',
help='try to get the diffusion relative to the sound if it exists'
)
def handle (self, path, *args, **options):
# FIXME: absolute/relative path of sounds vs given path
if options.get('sound'):
related = Sound.objects.filter(
path__icontains = options.get('sound')
).first()
else:
path, ext = os.path.splitext(options.get('path'))
related = Sound.objects.filter(path__icontains = path).first()
if not related:
logger.error('no sound found in the database for the path ' \
'{path}'.format(path=path))
return -1
if options.get('diffusion') and related.diffusion:
related = related.diffusion
importer = Importer(related = related, path = path, save = True)
for track in importer.tracks:
logger.info('imported track at {pos}: {title}, by '
'{artist}'.format(
pos = track.position,
title = track.title, artist = track.artist
)
)