kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
AudioCollection to import job and track file creation
rodzic
4d6e894b62
commit
363acca53d
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.0.3 on 2018-04-05 16:35
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('federation', '0004_followrequest'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='actor',
|
||||||
|
name='followers',
|
||||||
|
field=models.ManyToManyField(related_name='following', through='federation.Follow', to='federation.Actor'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Generated by Django 2.0.3 on 2018-04-05 18:30
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
import django.contrib.postgres.fields.jsonb
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('federation', '0005_actor_followers'),
|
||||||
|
('music', '0022_importbatch_import_request'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='importbatch',
|
||||||
|
name='federation_actor',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='import_batches', to='federation.Actor'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='importbatch',
|
||||||
|
name='federation_source',
|
||||||
|
field=models.URLField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='importjob',
|
||||||
|
name='federation_source',
|
||||||
|
field=models.URLField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='importjob',
|
||||||
|
name='metadata',
|
||||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(default={}),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='importbatch',
|
||||||
|
name='source',
|
||||||
|
field=models.CharField(choices=[('api', 'api'), ('shell', 'shell'), ('federation', 'federation')], default='api', max_length=30),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='importbatch',
|
||||||
|
name='submitted_by',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='imports', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
|
@ -8,6 +8,7 @@ import markdown
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.contrib.postgres.fields import JSONField
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
|
@ -65,6 +66,7 @@ class APIModelMixin(models.Model):
|
||||||
pass
|
pass
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class Artist(APIModelMixin):
|
class Artist(APIModelMixin):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
@ -90,10 +92,19 @@ class Artist(APIModelMixin):
|
||||||
t.append(tag)
|
t.append(tag)
|
||||||
return set(t)
|
return set(t)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create_from_name(cls, name, **kwargs):
|
||||||
|
kwargs.update({'name': name})
|
||||||
|
return cls.objects.get_or_create(
|
||||||
|
name__iexact=name,
|
||||||
|
defaults=kwargs)[0]
|
||||||
|
|
||||||
|
|
||||||
def import_artist(v):
|
def import_artist(v):
|
||||||
a = Artist.get_or_create_from_api(mbid=v[0]['artist']['id'])[0]
|
a = Artist.get_or_create_from_api(mbid=v[0]['artist']['id'])[0]
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
def parse_date(v):
|
def parse_date(v):
|
||||||
if len(v) == 4:
|
if len(v) == 4:
|
||||||
return datetime.date(int(v), 1, 1)
|
return datetime.date(int(v), 1, 1)
|
||||||
|
@ -108,6 +119,7 @@ def import_tracks(instance, cleaned_data, raw_data):
|
||||||
track_cleaned_data['position'] = int(track_data['position'])
|
track_cleaned_data['position'] = int(track_data['position'])
|
||||||
track = importers.load(Track, track_cleaned_data, track_data, Track.import_hooks)
|
track = importers.load(Track, track_cleaned_data, track_data, Track.import_hooks)
|
||||||
|
|
||||||
|
|
||||||
class Album(APIModelMixin):
|
class Album(APIModelMixin):
|
||||||
title = models.CharField(max_length=255)
|
title = models.CharField(max_length=255)
|
||||||
artist = models.ForeignKey(
|
artist = models.ForeignKey(
|
||||||
|
@ -170,6 +182,14 @@ class Album(APIModelMixin):
|
||||||
t.append(tag)
|
t.append(tag)
|
||||||
return set(t)
|
return set(t)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create_from_title(cls, title, **kwargs):
|
||||||
|
kwargs.update({'title': title})
|
||||||
|
return cls.objects.get_or_create(
|
||||||
|
title__iexact=title,
|
||||||
|
defaults=kwargs)[0]
|
||||||
|
|
||||||
|
|
||||||
def import_tags(instance, cleaned_data, raw_data):
|
def import_tags(instance, cleaned_data, raw_data):
|
||||||
MINIMUM_COUNT = 2
|
MINIMUM_COUNT = 2
|
||||||
tags_to_add = []
|
tags_to_add = []
|
||||||
|
@ -182,6 +202,7 @@ def import_tags(instance, cleaned_data, raw_data):
|
||||||
tags_to_add.append(tag_data['name'])
|
tags_to_add.append(tag_data['name'])
|
||||||
instance.tags.add(*tags_to_add)
|
instance.tags.add(*tags_to_add)
|
||||||
|
|
||||||
|
|
||||||
def import_album(v):
|
def import_album(v):
|
||||||
a = Album.get_or_create_from_api(mbid=v[0]['id'])[0]
|
a = Album.get_or_create_from_api(mbid=v[0]['id'])[0]
|
||||||
return a
|
return a
|
||||||
|
@ -366,6 +387,13 @@ class Track(APIModelMixin):
|
||||||
self.mbid)
|
self.mbid)
|
||||||
return settings.FUNKWHALE_URL + '/tracks/{}'.format(self.pk)
|
return settings.FUNKWHALE_URL + '/tracks/{}'.format(self.pk)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create_from_title(cls, title, **kwargs):
|
||||||
|
kwargs.update({'title': title})
|
||||||
|
return cls.objects.get_or_create(
|
||||||
|
title__iexact=title,
|
||||||
|
defaults=kwargs)[0]
|
||||||
|
|
||||||
|
|
||||||
class TrackFile(models.Model):
|
class TrackFile(models.Model):
|
||||||
track = models.ForeignKey(
|
track = models.ForeignKey(
|
||||||
|
@ -420,7 +448,8 @@ IMPORT_STATUS_CHOICES = (
|
||||||
class ImportBatch(models.Model):
|
class ImportBatch(models.Model):
|
||||||
IMPORT_BATCH_SOURCES = [
|
IMPORT_BATCH_SOURCES = [
|
||||||
('api', 'api'),
|
('api', 'api'),
|
||||||
('shell', 'shell')
|
('shell', 'shell'),
|
||||||
|
('federation', 'federation'),
|
||||||
]
|
]
|
||||||
source = models.CharField(
|
source = models.CharField(
|
||||||
max_length=30, default='api', choices=IMPORT_BATCH_SOURCES)
|
max_length=30, default='api', choices=IMPORT_BATCH_SOURCES)
|
||||||
|
@ -428,6 +457,8 @@ class ImportBatch(models.Model):
|
||||||
submitted_by = models.ForeignKey(
|
submitted_by = models.ForeignKey(
|
||||||
'users.User',
|
'users.User',
|
||||||
related_name='imports',
|
related_name='imports',
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
|
choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
|
||||||
|
@ -437,6 +468,16 @@ class ImportBatch(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
federation_source = models.URLField(null=True, blank=True)
|
||||||
|
federation_actor = models.ForeignKey(
|
||||||
|
'federation.Actor',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name='import_batches',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-creation_date']
|
ordering = ['-creation_date']
|
||||||
|
|
||||||
|
@ -464,6 +505,8 @@ class ImportJob(models.Model):
|
||||||
choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
|
choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
|
||||||
audio_file = models.FileField(
|
audio_file = models.FileField(
|
||||||
upload_to='imports/%Y/%m/%d', max_length=255, null=True, blank=True)
|
upload_to='imports/%Y/%m/%d', max_length=255, null=True, blank=True)
|
||||||
|
federation_source = models.URLField(null=True, blank=True)
|
||||||
|
metadata = JSONField(default={})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('id', )
|
ordering = ('id', )
|
||||||
|
|
|
@ -61,6 +61,7 @@ def test_import_job_from_federation_no_musicbrainz(factories):
|
||||||
job.refresh_from_db()
|
job.refresh_from_db()
|
||||||
|
|
||||||
tf = job.track_file
|
tf = job.track_file
|
||||||
|
assert tf.source == job.source
|
||||||
assert tf.track.title == 'Ping'
|
assert tf.track.title == 'Ping'
|
||||||
assert tf.track.artist.name == 'Hello'
|
assert tf.track.artist.name == 'Hello'
|
||||||
assert tf.track.album.title == 'World'
|
assert tf.track.album.title == 'World'
|
||||||
|
@ -82,6 +83,7 @@ def test_import_job_from_federation_musicbrainz_recording(factories, mocker):
|
||||||
job.refresh_from_db()
|
job.refresh_from_db()
|
||||||
|
|
||||||
tf = job.track_file
|
tf = job.track_file
|
||||||
|
assert tf.source == job.source
|
||||||
assert tf.track == t
|
assert tf.track == t
|
||||||
track_from_api.assert_called_once_with(
|
track_from_api.assert_called_once_with(
|
||||||
mbid=tasks.get_mbid(job.metadata['recording'], 'recording'))
|
mbid=tasks.get_mbid(job.metadata['recording'], 'recording'))
|
||||||
|
@ -103,6 +105,7 @@ def test_import_job_from_federation_musicbrainz_release(factories, mocker):
|
||||||
job.refresh_from_db()
|
job.refresh_from_db()
|
||||||
|
|
||||||
tf = job.track_file
|
tf = job.track_file
|
||||||
|
assert tf.source == job.source
|
||||||
assert tf.track.title == 'Ping'
|
assert tf.track.title == 'Ping'
|
||||||
assert tf.track.artist == a.artist
|
assert tf.track.artist == a.artist
|
||||||
assert tf.track.album == a
|
assert tf.track.album == a
|
||||||
|
@ -127,6 +130,7 @@ def test_import_job_from_federation_musicbrainz_artist(factories, mocker):
|
||||||
job.refresh_from_db()
|
job.refresh_from_db()
|
||||||
|
|
||||||
tf = job.track_file
|
tf = job.track_file
|
||||||
|
assert tf.source == job.source
|
||||||
assert tf.track.title == 'Ping'
|
assert tf.track.title == 'Ping'
|
||||||
assert tf.track.artist == a
|
assert tf.track.artist == a
|
||||||
assert tf.track.album.artist == a
|
assert tf.track.album.artist == a
|
||||||
|
|
Ładowanie…
Reference in New Issue