Skip to content
Snippets Groups Projects
Commit c8575691 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Can now import OGG files from filesystem

parent 8733eb17
No related branches found
No related tags found
No related merge requests found
...@@ -64,6 +64,7 @@ LOCAL_APPS = ( ...@@ -64,6 +64,7 @@ LOCAL_APPS = (
'funkwhale_api.radios', 'funkwhale_api.radios',
'funkwhale_api.history', 'funkwhale_api.history',
'funkwhale_api.playlists', 'funkwhale_api.playlists',
'funkwhale_api.providers.audiofile',
) )
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
......
import mutagen import mutagen
NODEFAULT = object()
class Metadata(object): class Metadata(object):
ALIASES = { ALIASES = {
...@@ -11,8 +12,14 @@ class Metadata(object): ...@@ -11,8 +12,14 @@ class Metadata(object):
def __init__(self, path): def __init__(self, path):
self._file = mutagen.File(path) self._file = mutagen.File(path)
def get(self, key, single=True): def get(self, key, default=NODEFAULT, single=True):
try:
v = self._file[key] v = self._file[key]
except KeyError:
if default == NODEFAULT:
raise
return default
# Some tags are returned as lists of string # Some tags are returned as lists of string
if single: if single:
return v[0] return v[0]
......
"""
This module is responsible from importing existing audiofiles from the
filesystem into funkwhale.
"""
import os
import datetime
from django.core.files import File
from funkwhale_api.taskapp import celery
from funkwhale_api.music import models, metadata
@celery.app.task(name='audiofile.from_path')
def from_path(path):
data = metadata.Metadata(path)
artist = models.Artist.objects.get_or_create(
name__iexact=data.get('artist'),
defaults={'name': data.get('artist')},
)[0]
release_date = None
try:
year, month, day = data.get('date', None).split('-')
release_date = datetime.date(
int(year), int(month), int(day)
)
except (ValueError, TypeError):
pass
album = models.Album.objects.get_or_create(
title__iexact=data.get('album'),
artist=artist,
defaults={
'title': data.get('album'),
'release_date': release_date,
},
)[0]
position = None
try:
position = int(data.get('tracknumber', None))
except ValueError:
pass
track = models.Track.objects.get_or_create(
title__iexact=data.get('title'),
album=album,
defaults={
'title': data.get('title'),
'position': position,
},
)[0]
if track.files.count() > 0:
raise ValueError('File already exists for track {}'.format(track.pk))
track_file = models.TrackFile(track=track)
track_file.audio_file.save(
os.path.basename(path),
File(open(path, 'rb'))
)
track_file.save()
return track_file
import glob
from django.core.management.base import BaseCommand, CommandError
from funkwhale_api.providers.audiofile import importer
class Command(BaseCommand):
help = 'Import audio files mathinc given glob pattern'
def add_arguments(self, parser):
parser.add_argument('path', type=str)
parser.add_argument(
'--recursive',
action='store_true',
dest='recursive',
default=False,
help='Will match the pattern recursively (including subdirectories)',
)
parser.add_argument(
'--async',
action='store_true',
dest='async',
default=False,
help='Will launch celery tasks for each file to import instead of doing it synchronously and block the CLI',
)
parser.add_argument(
'--noinput', '--no-input', action='store_false', dest='interactive',
help="Do NOT prompt the user for input of any kind.",
)
def handle(self, *args, **options):
# self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))
matching = glob.glob(options['path'], recursive=options['recursive'])
self.stdout.write('This will import {} files matching this pattern: {}'.format(
len(matching), options['path']))
if not matching:
raise CommandError('No file matching pattern, aborting')
if options['interactive']:
message = (
'Are you sure you want to do this?\n\n'
"Type 'yes' to continue, or 'no' to cancel: "
)
if input(''.join(message)) != 'yes':
raise CommandError("Import cancelled.")
message = 'Importing {}...'
if options['async']:
message = 'Launching import for {}...'
for path in matching:
self.stdout.write(message.format(path))
try:
importer.from_path(path)
except Exception as e:
self.stdout.write('Error: {}'.format(e))
message = 'Successfully imported {} tracks'
if options['async']:
message = 'Successfully launched import for {} tracks'
self.stdout.write(message.format(len(matching)))
import os
import datetime
import unittest
from test_plus.test import TestCase
from funkwhale_api.providers.audiofile import importer
DATA_DIR = os.path.dirname(os.path.abspath(__file__))
class TestAudioFile(TestCase):
def test_can_import_single_audio_file(self, *mocks):
metadata = {
'artist': ['Test artist'],
'album': ['Test album'],
'title': ['Test track'],
'tracknumber': ['4'],
'date': ['2012-08-15']
}
with unittest.mock.patch('mutagen.File', return_value=metadata):
track_file = importer.from_path(
os.path.join(DATA_DIR, 'dummy_file.ogg'))
self.assertEqual(
track_file.track.title, metadata['title'][0])
self.assertEqual(
track_file.track.position, 4)
self.assertEqual(
track_file.track.album.title, metadata['album'][0])
self.assertEqual(
track_file.track.album.release_date, datetime.date(2012, 8, 15))
self.assertEqual(
track_file.track.artist.name, metadata['artist'][0])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment