From 1bee3a4675a63156eee4f56e8a63be4acd308d53 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Sun, 23 Sep 2018 12:38:42 +0000
Subject: [PATCH] Import trust source

---
 api/funkwhale_api/federation/serializers.py   |  90 ++--
 api/funkwhale_api/music/metadata.py           |  57 ++-
 api/funkwhale_api/music/models.py             |  33 +-
 api/funkwhale_api/music/tasks.py              | 459 +++++++++++-------
 .../management/commands/import_files.py       |  47 +-
 api/requirements/local.txt                    |   1 +
 api/tests/conftest.py                         |   9 +-
 api/tests/federation/test_serializers.py      | 128 +----
 api/tests/music/test.mp3                      | Bin 297745 -> 297745 bytes
 api/tests/music/test_metadata.py              |  62 ++-
 api/tests/music/test_tasks.py                 | 351 +++++++++++---
 api/tests/test_import_audio_file.py           |  35 +-
 dev.yml                                       |   1 +
 .../views/content/libraries/FilesTable.vue    |   4 +
 14 files changed, 860 insertions(+), 417 deletions(-)

diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py
index 99ed708f19..71cd7a8314 100644
--- a/api/funkwhale_api/federation/serializers.py
+++ b/api/funkwhale_api/federation/serializers.py
@@ -4,7 +4,6 @@ import urllib.parse
 
 from django.core.exceptions import ObjectDoesNotExist
 from django.core.paginator import Paginator
-from django.db.models import F, Q
 from rest_framework import serializers
 
 from funkwhale_api.common import utils as funkwhale_utils
@@ -21,6 +20,31 @@ AP_CONTEXT = [
 logger = logging.getLogger(__name__)
 
 
+class LinkSerializer(serializers.Serializer):
+    type = serializers.ChoiceField(choices=["Link"])
+    href = serializers.URLField(max_length=500)
+    mediaType = serializers.CharField()
+
+    def __init__(self, *args, **kwargs):
+        self.allowed_mimetypes = kwargs.pop("allowed_mimetypes", [])
+        super().__init__(*args, **kwargs)
+
+    def validate_mediaType(self, v):
+        if not self.allowed_mimetypes:
+            # no restrictions
+            return v
+        for mt in self.allowed_mimetypes:
+            if mt.endswith("/*"):
+                if v.startswith(mt.replace("*", "")):
+                    return v
+            else:
+                if v == mt:
+                    return v
+        raise serializers.ValidationError(
+            "Invalid mimetype {}. Allowed: {}".format(v, self.allowed_mimetypes)
+        )
+
+
 class ActorSerializer(serializers.Serializer):
     id = serializers.URLField(max_length=500)
     outbox = serializers.URLField(max_length=500)
@@ -626,32 +650,8 @@ class MusicEntitySerializer(serializers.Serializer):
     musicbrainzId = serializers.UUIDField(allow_null=True, required=False)
     name = serializers.CharField(max_length=1000)
 
-    def create(self, validated_data):
-        mbid = validated_data.get("musicbrainzId")
-        candidates = self.model.objects.filter(
-            Q(mbid=mbid) | Q(fid=validated_data["id"])
-        ).order_by(F("fid").desc(nulls_last=True))
-
-        existing = candidates.first()
-        if existing:
-            return existing
-
-        # nothing matching in our database, let's create a new object
-        return self.model.objects.create(**self.get_create_data(validated_data))
-
-    def get_create_data(self, validated_data):
-        return {
-            "mbid": validated_data.get("musicbrainzId"),
-            "fid": validated_data["id"],
-            "name": validated_data["name"],
-            "creation_date": validated_data["published"],
-            "from_activity": self.context.get("activity"),
-        }
-
 
 class ArtistSerializer(MusicEntitySerializer):
-    model = music_models.Artist
-
     def to_representation(self, instance):
         d = {
             "type": "Artist",
@@ -667,9 +667,11 @@ class ArtistSerializer(MusicEntitySerializer):
 
 
 class AlbumSerializer(MusicEntitySerializer):
-    model = music_models.Album
     released = serializers.DateField(allow_null=True, required=False)
     artists = serializers.ListField(child=ArtistSerializer(), min_length=1)
+    cover = LinkSerializer(
+        allowed_mimetypes=["image/*"], allow_null=True, required=False
+    )
 
     def to_representation(self, instance):
         d = {
@@ -688,7 +690,12 @@ class AlbumSerializer(MusicEntitySerializer):
             ],
         }
         if instance.cover:
-            d["cover"] = {"type": "Image", "url": utils.full_url(instance.cover.url)}
+            d["cover"] = {
+                "type": "Link",
+                "href": utils.full_url(instance.cover.url),
+                "mediaType": mimetypes.guess_type(instance.cover.path)[0]
+                or "image/jpeg",
+            }
         if self.context.get("include_ap_context", self.parent is None):
             d["@context"] = AP_CONTEXT
         return d
@@ -711,7 +718,6 @@ class AlbumSerializer(MusicEntitySerializer):
 
 
 class TrackSerializer(MusicEntitySerializer):
-    model = music_models.Track
     position = serializers.IntegerField(min_value=0, allow_null=True, required=False)
     artists = serializers.ListField(child=ArtistSerializer(), min_length=1)
     album = AlbumSerializer()
@@ -738,32 +744,22 @@ class TrackSerializer(MusicEntitySerializer):
             d["@context"] = AP_CONTEXT
         return d
 
-    def get_create_data(self, validated_data):
-        artist_data = validated_data["artists"][0]
-        artist = ArtistSerializer(
-            context={"activity": self.context.get("activity")}
-        ).create(artist_data)
-        album = AlbumSerializer(
-            context={"activity": self.context.get("activity")}
-        ).create(validated_data["album"])
+    def create(self, validated_data):
+        from funkwhale_api.music import tasks as music_tasks
 
-        return {
-            "mbid": validated_data.get("musicbrainzId"),
-            "fid": validated_data["id"],
-            "title": validated_data["name"],
-            "position": validated_data.get("position"),
-            "creation_date": validated_data["published"],
-            "artist": artist,
-            "album": album,
-            "from_activity": self.context.get("activity"),
-        }
+        metadata = music_tasks.federation_audio_track_to_metadata(validated_data)
+        from_activity = self.context.get("activity")
+        if from_activity:
+            metadata["from_activity_id"] = from_activity.pk
+        track = music_tasks.get_track_from_import_metadata(metadata)
+        return track
 
 
 class UploadSerializer(serializers.Serializer):
     type = serializers.ChoiceField(choices=["Audio"])
     id = serializers.URLField(max_length=500)
     library = serializers.URLField(max_length=500)
-    url = serializers.JSONField()
+    url = LinkSerializer(allowed_mimetypes=["audio/*"])
     published = serializers.DateTimeField()
     updated = serializers.DateTimeField(required=False, allow_null=True)
     bitrate = serializers.IntegerField(min_value=0)
diff --git a/api/funkwhale_api/music/metadata.py b/api/funkwhale_api/music/metadata.py
index 4c754ae056..21daf2747c 100644
--- a/api/funkwhale_api/music/metadata.py
+++ b/api/funkwhale_api/music/metadata.py
@@ -93,9 +93,9 @@ def convert_track_number(v):
 class FirstUUIDField(forms.UUIDField):
     def to_python(self, value):
         try:
-            # sometimes, Picard leaves to uuids in the field, separated
-            # by a slash
-            value = value.split("/")[0]
+            # sometimes, Picard leaves two uuids in the field, separated
+            # by a slash or a ;
+            value = value.split(";")[0].split("/")[0].strip()
         except (AttributeError, IndexError, TypeError):
             pass
 
@@ -107,10 +107,18 @@ def get_date(value):
     return datetime.date(parsed.year, parsed.month, parsed.day)
 
 
+def split_and_return_first(separator):
+    def inner(v):
+        return v.split(separator)[0].strip()
+
+    return inner
+
+
 VALIDATION = {
     "musicbrainz_artistid": FirstUUIDField(),
     "musicbrainz_albumid": FirstUUIDField(),
     "musicbrainz_recordingid": FirstUUIDField(),
+    "musicbrainz_albumartistid": FirstUUIDField(),
 }
 
 CONF = {
@@ -123,10 +131,15 @@ CONF = {
             },
             "title": {},
             "artist": {},
+            "album_artist": {
+                "field": "albumartist",
+                "to_application": split_and_return_first(";"),
+            },
             "album": {},
             "date": {"field": "date", "to_application": get_date},
             "musicbrainz_albumid": {},
             "musicbrainz_artistid": {},
+            "musicbrainz_albumartistid": {},
             "musicbrainz_recordingid": {"field": "musicbrainz_trackid"},
         },
     },
@@ -139,10 +152,15 @@ CONF = {
             },
             "title": {},
             "artist": {},
+            "album_artist": {
+                "field": "albumartist",
+                "to_application": split_and_return_first(";"),
+            },
             "album": {},
             "date": {"field": "date", "to_application": get_date},
             "musicbrainz_albumid": {},
             "musicbrainz_artistid": {},
+            "musicbrainz_albumartistid": {},
             "musicbrainz_recordingid": {"field": "musicbrainz_trackid"},
         },
     },
@@ -155,10 +173,12 @@ CONF = {
             },
             "title": {},
             "artist": {},
+            "album_artist": {"field": "albumartist"},
             "album": {},
             "date": {"field": "date", "to_application": get_date},
             "musicbrainz_albumid": {"field": "MusicBrainz Album Id"},
             "musicbrainz_artistid": {"field": "MusicBrainz Artist Id"},
+            "musicbrainz_albumartistid": {"field": "MusicBrainz Album Artist Id"},
             "musicbrainz_recordingid": {"field": "MusicBrainz Track Id"},
         },
     },
@@ -169,10 +189,12 @@ CONF = {
             "track_number": {"field": "TRCK", "to_application": convert_track_number},
             "title": {"field": "TIT2"},
             "artist": {"field": "TPE1"},
+            "album_artist": {"field": "TPE2"},
             "album": {"field": "TALB"},
             "date": {"field": "TDRC", "to_application": get_date},
             "musicbrainz_albumid": {"field": "MusicBrainz Album Id"},
             "musicbrainz_artistid": {"field": "MusicBrainz Artist Id"},
+            "musicbrainz_albumartistid": {"field": "MusicBrainz Album Artist Id"},
             "musicbrainz_recordingid": {
                 "field": "UFID",
                 "getter": get_mp3_recording_id,
@@ -190,10 +212,12 @@ CONF = {
             },
             "title": {},
             "artist": {},
+            "album_artist": {"field": "albumartist"},
             "album": {},
             "date": {"field": "date", "to_application": get_date},
             "musicbrainz_albumid": {},
             "musicbrainz_artistid": {},
+            "musicbrainz_albumartistid": {},
             "musicbrainz_recordingid": {"field": "musicbrainz_trackid"},
             "test": {},
             "pictures": {},
@@ -201,6 +225,19 @@ CONF = {
     },
 }
 
+ALL_FIELDS = [
+    "track_number",
+    "title",
+    "artist",
+    "album_artist",
+    "album",
+    "date",
+    "musicbrainz_albumid",
+    "musicbrainz_artistid",
+    "musicbrainz_albumartistid",
+    "musicbrainz_recordingid",
+]
+
 
 class Metadata(object):
     def __init__(self, path):
@@ -238,6 +275,20 @@ class Metadata(object):
             v = field.to_python(v)
         return v
 
+    def all(self):
+        """
+        Return a dict containing all metadata of the file
+        """
+
+        data = {}
+        for field in ALL_FIELDS:
+            try:
+                data[field] = self.get(field, None)
+            except (TagNotFound, forms.ValidationError):
+                data[field] = None
+
+        return data
+
     def get_picture(self, picture_type="cover_front"):
         ptype = getattr(mutagen.id3.PictureType, picture_type.upper())
         try:
diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py
index 51f1d4286a..55f1c77b8a 100644
--- a/api/funkwhale_api/music/models.py
+++ b/api/funkwhale_api/music/models.py
@@ -1,4 +1,5 @@
 import datetime
+import logging
 import os
 import tempfile
 import uuid
@@ -21,11 +22,14 @@ from versatileimagefield.image_warmer import VersatileImageFieldWarmer
 
 from funkwhale_api import musicbrainz
 from funkwhale_api.common import fields
+from funkwhale_api.common import session
 from funkwhale_api.common import utils as common_utils
 from funkwhale_api.federation import models as federation_models
 from funkwhale_api.federation import utils as federation_utils
 from . import importers, metadata, utils
 
+logger = logging.getLogger(__file__)
+
 
 def empty_dict():
     return {}
@@ -240,14 +244,35 @@ class Album(APIModelMixin):
 
     def get_image(self, data=None):
         if data:
-            f = ContentFile(data["content"])
             extensions = {"image/jpeg": "jpg", "image/png": "png", "image/gif": "gif"}
             extension = extensions.get(data["mimetype"], "jpg")
-            self.cover.save("{}.{}".format(self.uuid, extension), f)
-        else:
+            if data.get("content"):
+                # we have to cover itself
+                f = ContentFile(data["content"])
+            elif data.get("url"):
+                # we can fetch from a url
+                try:
+                    response = session.get_session().get(
+                        data.get("url"),
+                        timeout=3,
+                        verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL,
+                    )
+                    response.raise_for_status()
+                except Exception as e:
+                    logger.warn(
+                        "Cannot download cover at url %s: %s", data.get("url"), e
+                    )
+                    return
+                else:
+                    f = ContentFile(response.content)
+            self.cover.save("{}.{}".format(self.uuid, extension), f, save=False)
+            self.save(update_fields=["cover"])
+            return self.cover.file
+        if self.mbid:
             image_data = musicbrainz.api.images.get_front(str(self.mbid))
             f = ContentFile(image_data)
-            self.cover.save("{0}.jpg".format(self.mbid), f)
+            self.cover.save("{0}.jpg".format(self.mbid), f, save=False)
+            self.save(update_fields=["cover"])
         return self.cover.file
 
     def __str__(self):
diff --git a/api/funkwhale_api/music/tasks.py b/api/funkwhale_api/music/tasks.py
index 61ee155856..0a4c042255 100644
--- a/api/funkwhale_api/music/tasks.py
+++ b/api/funkwhale_api/music/tasks.py
@@ -1,9 +1,10 @@
+import collections
 import logging
 import os
 
 from django.utils import timezone
 from django.db import transaction
-from django.db.models import F
+from django.db.models import F, Q
 from django.dispatch import receiver
 
 from musicbrainzngs import ResponseError
@@ -14,7 +15,6 @@ from funkwhale_api.common import preferences
 from funkwhale_api.federation import activity, actors, routes
 from funkwhale_api.federation import library as lb
 from funkwhale_api.federation import library as federation_serializers
-from funkwhale_api.providers.acoustid import get_acoustid_client
 from funkwhale_api.taskapp import celery
 
 from . import lyrics as lyrics_utils
@@ -26,102 +26,32 @@ from . import serializers
 logger = logging.getLogger(__name__)
 
 
-@celery.app.task(name="acoustid.set_on_upload")
-@celery.require_instance(models.Upload, "upload")
-def set_acoustid_on_upload(upload):
-    client = get_acoustid_client()
-    result = client.get_best_match(upload.audio_file.path)
-
-    def update(id):
-        upload.acoustid_track_id = id
-        upload.save(update_fields=["acoustid_track_id"])
-        return id
-
-    if result:
-        return update(result["id"])
-
-
-def import_track_from_remote(metadata):
-    try:
-        track_mbid = metadata["recording"]["musicbrainz_id"]
-        assert track_mbid  # for null/empty values
-    except (KeyError, AssertionError):
-        pass
-    else:
-        return models.Track.get_or_create_from_api(mbid=track_mbid)[0]
-
-    try:
-        album_mbid = metadata["release"]["musicbrainz_id"]
-        assert album_mbid  # for null/empty values
-    except (KeyError, AssertionError):
-        pass
-    else:
-        album, _ = models.Album.get_or_create_from_api(mbid=album_mbid)
-        return models.Track.get_or_create_from_title(
-            metadata["title"], artist=album.artist, album=album
-        )[0]
-
-    try:
-        artist_mbid = metadata["artist"]["musicbrainz_id"]
-        assert artist_mbid  # for null/empty values
-    except (KeyError, AssertionError):
-        pass
-    else:
-        artist, _ = models.Artist.get_or_create_from_api(mbid=artist_mbid)
-        album, _ = models.Album.get_or_create_from_title(
-            metadata["album_title"], artist=artist
-        )
-        return models.Track.get_or_create_from_title(
-            metadata["title"], artist=artist, album=album
-        )[0]
-
-    # worst case scenario, we have absolutely no way to link to a
-    # musicbrainz resource, we rely on the name/titles
-    artist, _ = models.Artist.get_or_create_from_name(metadata["artist_name"])
-    album, _ = models.Album.get_or_create_from_title(
-        metadata["album_title"], artist=artist
-    )
-    return models.Track.get_or_create_from_title(
-        metadata["title"], artist=artist, album=album
-    )[0]
-
-
-def update_album_cover(album, upload, replace=False):
+def update_album_cover(album, source=None, cover_data=None, replace=False):
     if album.cover and not replace:
         return
 
-    if upload:
-        # maybe the file has a cover embedded?
+    if cover_data:
+        return album.get_image(data=cover_data)
+
+    if source and source.startswith("file://"):
+        # let's look for a cover in the same directory
+        path = os.path.dirname(source.replace("file://", "", 1))
+        logger.info("[Album %s] scanning covers from %s", album.pk, path)
+        cover = get_cover_from_fs(path)
+        if cover:
+            return album.get_image(data=cover)
+    if album.mbid:
         try:
-            metadata = upload.get_metadata()
-        except FileNotFoundError:
-            metadata = None
-        if metadata:
-            cover = metadata.get_picture("cover_front")
-            if cover:
-                # best case scenario, cover is embedded in the track
-                logger.info("[Album %s] Using cover embedded in file", album.pk)
-                return album.get_image(data=cover)
-        if upload.source and upload.source.startswith("file://"):
-            # let's look for a cover in the same directory
-            path = os.path.dirname(upload.source.replace("file://", "", 1))
-            logger.info("[Album %s] scanning covers from %s", album.pk, path)
-            cover = get_cover_from_fs(path)
-            if cover:
-                return album.get_image(data=cover)
-    if not album.mbid:
-        return
-    try:
-        logger.info(
-            "[Album %s] Fetching cover from musicbrainz release %s",
-            album.pk,
-            str(album.mbid),
-        )
-        return album.get_image()
-    except ResponseError as exc:
-        logger.warning(
-            "[Album %s] cannot fetch cover from musicbrainz: %s", album.pk, str(exc)
-        )
+            logger.info(
+                "[Album %s] Fetching cover from musicbrainz release %s",
+                album.pk,
+                str(album.mbid),
+            )
+            return album.get_image()
+        except ResponseError as exc:
+            logger.warning(
+                "[Album %s] cannot fetch cover from musicbrainz: %s", album.pk, str(exc)
+            )
 
 
 IMAGE_TYPES = [("jpg", "image/jpeg"), ("png", "image/png")]
@@ -244,15 +174,15 @@ def scan_library_page(library_scan, page_url):
         scan_library_page.delay(library_scan_id=library_scan.pk, page_url=next_page)
 
 
-def getter(data, *keys):
+def getter(data, *keys, default=None):
     if not data:
-        return
+        return default
     v = data
     for k in keys:
         try:
             v = v[k]
         except KeyError:
-            return
+            return default
 
     return v
 
@@ -269,12 +199,17 @@ def fail_import(upload, error_code):
     upload.import_details = {"error_code": error_code}
     upload.import_date = timezone.now()
     upload.save(update_fields=["import_details", "import_status", "import_date"])
-    signals.upload_import_status_updated.send(
-        old_status=old_status,
-        new_status=upload.import_status,
-        upload=upload,
-        sender=None,
+
+    broadcast = getter(
+        upload.import_metadata, "funkwhale", "config", "broadcast", default=True
     )
+    if broadcast:
+        signals.upload_import_status_updated.send(
+            old_status=old_status,
+            new_status=upload.import_status,
+            upload=upload,
+            sender=None,
+        )
 
 
 @celery.app.task(name="music.process_upload")
@@ -285,22 +220,29 @@ def fail_import(upload, error_code):
     "upload",
 )
 def process_upload(upload):
-    data = upload.import_metadata or {}
+    import_metadata = upload.import_metadata or {}
     old_status = upload.import_status
+    audio_file = upload.get_audio_file()
     try:
-        track = get_track_from_import_metadata(upload.import_metadata or {})
-        if not track and upload.audio_file:
-            # easy ways did not work. Now we have to be smart and use
-            # metadata from the file itself if any
-            track = import_track_data_from_file(upload.audio_file.file, hints=data)
-        if not track and upload.metadata:
-            # we can try to import using federation metadata
-            track = import_track_from_remote(upload.metadata)
+        additional_data = {}
+        if not audio_file:
+            # we can only rely on user proveded data
+            final_metadata = import_metadata
+        else:
+            # we use user provided data and data from the file itself
+            m = metadata.Metadata(audio_file)
+            file_metadata = m.all()
+            final_metadata = collections.ChainMap(
+                additional_data, import_metadata, file_metadata
+            )
+            additional_data["cover_data"] = m.get_picture("cover_front")
+        additional_data["upload_source"] = upload.source
+        track = get_track_from_import_metadata(final_metadata)
     except UploadImportError as e:
         return fail_import(upload, e.code)
     except Exception:
-        fail_import(upload, "unknown_error")
-        raise
+        return fail_import(upload, "unknown_error")
+
     # under some situations, we want to skip the import (
     # for instance if the user already owns the files)
     owned_duplicates = get_owned_duplicates(upload, track)
@@ -342,33 +284,69 @@ def process_upload(upload):
             "bitrate",
         ]
     )
-    signals.upload_import_status_updated.send(
-        old_status=old_status,
-        new_status=upload.import_status,
-        upload=upload,
-        sender=None,
+    broadcast = getter(
+        import_metadata, "funkwhale", "config", "broadcast", default=True
     )
-    routes.outbox.dispatch(
-        {"type": "Create", "object": {"type": "Audio"}}, context={"upload": upload}
+    if broadcast:
+        signals.upload_import_status_updated.send(
+            old_status=old_status,
+            new_status=upload.import_status,
+            upload=upload,
+            sender=None,
+        )
+    dispatch_outbox = getter(
+        import_metadata, "funkwhale", "config", "dispatch_outbox", default=True
     )
-    if not track.album.cover:
-        update_album_cover(track.album, upload)
-
+    if dispatch_outbox:
+        routes.outbox.dispatch(
+            {"type": "Create", "object": {"type": "Audio"}}, context={"upload": upload}
+        )
 
-def get_track_from_import_metadata(data):
-    track_mbid = getter(data, "track", "mbid")
-    track_uuid = getter(data, "track", "uuid")
 
-    if track_mbid:
-        # easiest case: there is a MBID provided in the import_metadata
-        return models.Track.get_or_create_from_api(mbid=track_mbid)[0]
-    if track_uuid:
-        # another easy case, we have a reference to a uuid of a track that
-        # already exists in our database
-        try:
-            return models.Track.objects.get(uuid=track_uuid)
-        except models.Track.DoesNotExist:
-            raise UploadImportError(code="track_uuid_not_found")
+def federation_audio_track_to_metadata(payload):
+    """
+    Given a valid payload as returned by federation.serializers.TrackSerializer.validated_data,
+    returns a correct metadata payload for use with get_track_from_import_metadata.
+    """
+    musicbrainz_recordingid = payload.get("musicbrainzId")
+    musicbrainz_artistid = payload["artists"][0].get("musicbrainzId")
+    musicbrainz_albumartistid = payload["album"]["artists"][0].get("musicbrainzId")
+    musicbrainz_albumid = payload["album"].get("musicbrainzId")
+
+    new_data = {
+        "title": payload["name"],
+        "album": payload["album"]["name"],
+        "track_number": payload["position"],
+        "artist": payload["artists"][0]["name"],
+        "album_artist": payload["album"]["artists"][0]["name"],
+        "date": payload["album"].get("released"),
+        # musicbrainz
+        "musicbrainz_recordingid": str(musicbrainz_recordingid)
+        if musicbrainz_recordingid
+        else None,
+        "musicbrainz_artistid": str(musicbrainz_artistid)
+        if musicbrainz_artistid
+        else None,
+        "musicbrainz_albumartistid": str(musicbrainz_albumartistid)
+        if musicbrainz_albumartistid
+        else None,
+        "musicbrainz_albumid": str(musicbrainz_albumid)
+        if musicbrainz_albumid
+        else None,
+        # federation
+        "fid": payload["id"],
+        "artist_fid": payload["artists"][0]["id"],
+        "album_artist_fid": payload["album"]["artists"][0]["id"],
+        "album_fid": payload["album"]["id"],
+        "fdate": payload["published"],
+        "album_fdate": payload["album"]["published"],
+        "album_artist_fdate": payload["album"]["artists"][0]["published"],
+        "artist_fdate": payload["artists"][0]["published"],
+    }
+    cover = payload["album"].get("cover")
+    if cover:
+        new_data["cover_data"] = {"mimetype": cover["mediaType"], "url": cover["href"]}
+    return new_data
 
 
 def get_owned_duplicates(upload, track):
@@ -385,45 +363,191 @@ def get_owned_duplicates(upload, track):
     )
 
 
+def get_best_candidate_or_create(model, query, defaults, sort_fields):
+    """
+    Like queryset.get_or_create() but does not crash if multiple objects
+    are returned on the get() call
+    """
+    candidates = model.objects.filter(query)
+    if candidates:
+
+        return sort_candidates(candidates, sort_fields)[0], False
+
+    return model.objects.create(**defaults), True
+
+
+def sort_candidates(candidates, important_fields):
+    """
+    Given a list of objects and a list of fields,
+    will return a sorted list of those objects by score.
+
+    Score is higher for objects that have a non-empty attribute
+    that is also present in important fields::
+
+        artist1 = Artist(mbid=None, fid=None)
+        artist2 = Artist(mbid="something", fid=None)
+
+        # artist2 has a mbid, so is sorted first
+        assert sort_candidates([artist1, artist2], ['mbid'])[0] == artist2
+
+    Only supports string fields.
+    """
+
+    # map each fields to its score, giving a higher score to first fields
+    fields_scores = {f: i + 1 for i, f in enumerate(sorted(important_fields))}
+    candidates_with_scores = []
+    for candidate in candidates:
+        current_score = 0
+        for field, score in fields_scores.items():
+            v = getattr(candidate, field, "")
+            if v:
+                current_score += score
+
+        candidates_with_scores.append((candidate, current_score))
+
+    return [c for c, s in reversed(sorted(candidates_with_scores, key=lambda v: v[1]))]
+
+
 @transaction.atomic
-def import_track_data_from_file(file, hints={}):
-    data = metadata.Metadata(file)
-    album = None
+def get_track_from_import_metadata(data):
+    track_uuid = getter(data, "funkwhale", "track", "uuid")
+
+    if track_uuid:
+        # easy case, we have a reference to a uuid of a track that
+        # already exists in our database
+        try:
+            track = models.Track.objects.get(uuid=track_uuid)
+        except models.Track.DoesNotExist:
+            raise UploadImportError(code="track_uuid_not_found")
+
+        if not track.album.cover:
+            update_album_cover(
+                track.album,
+                source=data.get("upload_source"),
+                cover_data=data.get("cover_data"),
+            )
+        return track
+
+    from_activity_id = data.get("from_activity_id", None)
     track_mbid = data.get("musicbrainz_recordingid", None)
     album_mbid = data.get("musicbrainz_albumid", None)
+    track_fid = getter(data, "fid")
+
+    query = None
 
     if album_mbid and track_mbid:
-        # to gain performance and avoid additional mb lookups,
-        # we import from the release data, which is already cached
-        return models.Track.get_or_create_from_release(album_mbid, track_mbid)[0]
-    elif track_mbid:
-        return models.Track.get_or_create_from_api(track_mbid)[0]
-    elif album_mbid:
-        album = models.Album.get_or_create_from_api(album_mbid)[0]
-
-    artist = album.artist if album else None
+        query = Q(mbid=track_mbid, album__mbid=album_mbid)
+
+    if track_fid:
+        query = query | Q(fid=track_fid) if query else Q(fid=track_fid)
+
+    if query:
+        # second easy case: we have a (track_mbid, album_mbid) pair or
+        # a federation uuid we can check on
+        try:
+            return sort_candidates(models.Track.objects.filter(query), ["mbid", "fid"])[
+                0
+            ]
+        except IndexError:
+            pass
+
+    # get / create artist and album artist
     artist_mbid = data.get("musicbrainz_artistid", None)
-    if not artist:
-        if artist_mbid:
-            artist = models.Artist.get_or_create_from_api(artist_mbid)[0]
-        else:
-            artist = models.Artist.objects.get_or_create(
-                name__iexact=data.get("artist"), defaults={"name": data.get("artist")}
-            )[0]
-
-    release_date = data.get("date", default=None)
-    if not album:
-        album = models.Album.objects.get_or_create(
-            title__iexact=data.get("album"),
-            artist=artist,
-            defaults={"title": data.get("album"), "release_date": release_date},
+    artist_fid = data.get("artist_fid", None)
+    artist_name = data["artist"]
+    query = Q(name__iexact=artist_name)
+    if artist_mbid:
+        query |= Q(mbid=artist_mbid)
+    if artist_fid:
+        query |= Q(fid=artist_fid)
+    defaults = {
+        "name": artist_name,
+        "mbid": artist_mbid,
+        "fid": artist_fid,
+        "from_activity_id": from_activity_id,
+    }
+    if data.get("artist_fdate"):
+        defaults["creation_date"] = data.get("artist_fdate")
+
+    artist = get_best_candidate_or_create(
+        models.Artist, query, defaults=defaults, sort_fields=["mbid", "fid"]
+    )[0]
+
+    album_artist_name = data.get("album_artist", artist_name)
+    if album_artist_name == artist_name:
+        album_artist = artist
+    else:
+        query = Q(name__iexact=album_artist_name)
+        album_artist_mbid = data.get("musicbrainz_albumartistid", None)
+        album_artist_fid = data.get("album_artist_fid", None)
+        if album_artist_mbid:
+            query |= Q(mbid=album_artist_mbid)
+        if album_artist_fid:
+            query |= Q(fid=album_artist_fid)
+        defaults = {
+            "name": album_artist_name,
+            "mbid": album_artist_mbid,
+            "fid": album_artist_fid,
+            "from_activity_id": from_activity_id,
+        }
+        if data.get("album_artist_fdate"):
+            defaults["creation_date"] = data.get("album_artist_fdate")
+
+        album_artist = get_best_candidate_or_create(
+            models.Artist, query, defaults=defaults, sort_fields=["mbid", "fid"]
         )[0]
-    position = data.get("track_number", default=None)
-    track = models.Track.objects.get_or_create(
-        title__iexact=data.get("title"),
-        album=album,
-        defaults={"title": data.get("title"), "position": position},
+
+    # get / create album
+    album_title = data["album"]
+    album_fid = data.get("album_fid", None)
+    query = Q(title__iexact=album_title, artist=album_artist)
+    if album_mbid:
+        query |= Q(mbid=album_mbid)
+    if album_fid:
+        query |= Q(fid=album_fid)
+    defaults = {
+        "title": album_title,
+        "artist": album_artist,
+        "mbid": album_mbid,
+        "release_date": data.get("date"),
+        "fid": album_fid,
+        "from_activity_id": from_activity_id,
+    }
+    if data.get("album_fdate"):
+        defaults["creation_date"] = data.get("album_fdate")
+
+    album = get_best_candidate_or_create(
+        models.Album, query, defaults=defaults, sort_fields=["mbid", "fid"]
     )[0]
+    if not album.cover:
+        update_album_cover(
+            album, source=data.get("upload_source"), cover_data=data.get("cover_data")
+        )
+
+    # get / create track
+    track_title = data["title"]
+    track_number = data.get("track_number", 1)
+    query = Q(title__iexact=track_title, artist=artist, album=album)
+    if track_mbid:
+        query |= Q(mbid=track_mbid)
+    if track_fid:
+        query |= Q(fid=track_fid)
+    defaults = {
+        "title": track_title,
+        "album": album,
+        "mbid": track_mbid,
+        "artist": artist,
+        "position": track_number,
+        "fid": track_fid,
+        "from_activity_id": from_activity_id,
+    }
+    if data.get("fdate"):
+        defaults["creation_date"] = data.get("fdate")
+
+    track = get_best_candidate_or_create(
+        models.Track, query, defaults=defaults, sort_fields=["mbid", "fid"]
+    )[0]
+
     return track
 
 
@@ -432,6 +556,7 @@ def broadcast_import_status_update_to_owner(old_status, new_status, upload, **kw
     user = upload.library.actor.get_user()
     if not user:
         return
+
     group = "user.{}.imports".format(user.pk)
     channels.group_send(
         group,
diff --git a/api/funkwhale_api/providers/audiofile/management/commands/import_files.py b/api/funkwhale_api/providers/audiofile/management/commands/import_files.py
index bc1c9af0ae..d4917be5e9 100644
--- a/api/funkwhale_api/providers/audiofile/management/commands/import_files.py
+++ b/api/funkwhale_api/providers/audiofile/management/commands/import_files.py
@@ -77,6 +77,29 @@ class Command(BaseCommand):
                 "with their newest version."
             ),
         )
+        parser.add_argument(
+            "--outbox",
+            action="store_true",
+            dest="outbox",
+            default=False,
+            help=(
+                "Use this flag to notify library followers of newly imported files. "
+                "You'll likely want to keep this disabled for CLI imports, especially if"
+                "you plan to import hundreds or thousands of files, as it will cause a lot "
+                "of overhead on your server and on servers you are federating with."
+            ),
+        )
+
+        parser.add_argument(
+            "--broadcast",
+            action="store_true",
+            dest="broadcast",
+            default=False,
+            help=(
+                "Use this flag to enable realtime updates about the import in the UI. "
+                "This causes some overhead, so it's disabled by default."
+            ),
+        )
 
         parser.add_argument(
             "--reference",
@@ -261,6 +284,8 @@ class Command(BaseCommand):
                     async_,
                     options["replace"],
                     options["in_place"],
+                    options["outbox"],
+                    options["broadcast"],
                 )
             except Exception as e:
                 if options["exit_on_failure"]:
@@ -272,11 +297,29 @@ class Command(BaseCommand):
                 errors.append((path, "{} {}".format(e.__class__.__name__, e)))
         return errors
 
-    def create_upload(self, path, reference, library, async_, replace, in_place):
+    def create_upload(
+        self,
+        path,
+        reference,
+        library,
+        async_,
+        replace,
+        in_place,
+        dispatch_outbox,
+        broadcast,
+    ):
         import_handler = tasks.process_upload.delay if async_ else tasks.process_upload
         upload = models.Upload(library=library, import_reference=reference)
         upload.source = "file://" + path
-        upload.import_metadata = {"replace": replace}
+        upload.import_metadata = {
+            "funkwhale": {
+                "config": {
+                    "replace": replace,
+                    "dispatch_outbox": dispatch_outbox,
+                    "broadcast": broadcast,
+                }
+            }
+        }
         if not in_place:
             name = os.path.basename(path)
             with open(path, "rb") as f:
diff --git a/api/requirements/local.txt b/api/requirements/local.txt
index f11f976b8b..c12f1ecb82 100644
--- a/api/requirements/local.txt
+++ b/api/requirements/local.txt
@@ -10,3 +10,4 @@ django-debug-toolbar>=1.9,<1.10
 # improved REPL
 ipdb==0.8.1
 black
+profiling
diff --git a/api/tests/conftest.py b/api/tests/conftest.py
index 1694e5623f..a1688127c4 100644
--- a/api/tests/conftest.py
+++ b/api/tests/conftest.py
@@ -11,7 +11,7 @@ import uuid
 from faker.providers import internet as internet_provider
 import factory
 import pytest
-import requests_mock
+
 from django.contrib.auth.models import AnonymousUser
 from django.core.cache import cache as django_cache
 from django.core.files import uploadedfile
@@ -271,14 +271,13 @@ def media_root(settings):
     shutil.rmtree(tmp_dir)
 
 
-@pytest.fixture
-def r_mock():
+@pytest.fixture(autouse=True)
+def r_mock(requests_mock):
     """
     Returns a requests_mock.mock() object you can use to mock HTTP calls made
     using python-requests
     """
-    with requests_mock.mock() as m:
-        yield m
+    yield requests_mock
 
 
 @pytest.fixture
diff --git a/api/tests/federation/test_serializers.py b/api/tests/federation/test_serializers.py
index 00bb011f25..54e044c312 100644
--- a/api/tests/federation/test_serializers.py
+++ b/api/tests/federation/test_serializers.py
@@ -1,3 +1,4 @@
+import io
 import pytest
 import uuid
 
@@ -588,42 +589,6 @@ def test_music_library_serializer_from_private(factories, mocker):
     )
 
 
-@pytest.mark.parametrize(
-    "model,serializer_class",
-    [
-        ("music.Artist", serializers.ArtistSerializer),
-        ("music.Album", serializers.AlbumSerializer),
-        ("music.Track", serializers.TrackSerializer),
-    ],
-)
-def test_music_entity_serializer_create_existing_mbid(
-    model, serializer_class, factories
-):
-    entity = factories[model]()
-    data = {"musicbrainzId": str(entity.mbid), "id": "https://noop"}
-    serializer = serializer_class()
-
-    assert serializer.create(data) == entity
-
-
-@pytest.mark.parametrize(
-    "model,serializer_class",
-    [
-        ("music.Artist", serializers.ArtistSerializer),
-        ("music.Album", serializers.AlbumSerializer),
-        ("music.Track", serializers.TrackSerializer),
-    ],
-)
-def test_music_entity_serializer_create_existing_fid(
-    model, serializer_class, factories
-):
-    entity = factories[model](fid="https://entity.url")
-    data = {"musicbrainzId": None, "id": "https://entity.url"}
-    serializer = serializer_class()
-
-    assert serializer.create(data) == entity
-
-
 def test_activity_pub_artist_serializer_to_ap(factories):
     artist = factories["music.Artist"]()
     expected = {
@@ -639,30 +604,6 @@ def test_activity_pub_artist_serializer_to_ap(factories):
     assert serializer.data == expected
 
 
-def test_activity_pub_artist_serializer_from_ap(factories):
-    activity = factories["federation.Activity"]()
-
-    published = timezone.now()
-    data = {
-        "type": "Artist",
-        "id": "http://hello.artist",
-        "name": "John Smith",
-        "musicbrainzId": str(uuid.uuid4()),
-        "published": published.isoformat(),
-    }
-    serializer = serializers.ArtistSerializer(data=data, context={"activity": activity})
-
-    assert serializer.is_valid(raise_exception=True)
-
-    artist = serializer.save()
-
-    assert artist.from_activity == activity
-    assert artist.name == data["name"]
-    assert artist.fid == data["id"]
-    assert str(artist.mbid) == data["musicbrainzId"]
-    assert artist.creation_date == published
-
-
 def test_activity_pub_album_serializer_to_ap(factories):
     album = factories["music.Album"]()
 
@@ -671,7 +612,11 @@ def test_activity_pub_album_serializer_to_ap(factories):
         "type": "Album",
         "id": album.fid,
         "name": album.title,
-        "cover": {"type": "Image", "url": utils.full_url(album.cover.url)},
+        "cover": {
+            "type": "Link",
+            "mediaType": "image/jpeg",
+            "href": utils.full_url(album.cover.url),
+        },
         "musicbrainzId": album.mbid,
         "published": album.creation_date.isoformat(),
         "released": album.release_date.isoformat(),
@@ -686,49 +631,6 @@ def test_activity_pub_album_serializer_to_ap(factories):
     assert serializer.data == expected
 
 
-def test_activity_pub_album_serializer_from_ap(factories):
-    activity = factories["federation.Activity"]()
-
-    published = timezone.now()
-    released = timezone.now().date()
-    data = {
-        "type": "Album",
-        "id": "http://hello.album",
-        "name": "Purple album",
-        "musicbrainzId": str(uuid.uuid4()),
-        "published": published.isoformat(),
-        "released": released.isoformat(),
-        "artists": [
-            {
-                "type": "Artist",
-                "id": "http://hello.artist",
-                "name": "John Smith",
-                "musicbrainzId": str(uuid.uuid4()),
-                "published": published.isoformat(),
-            }
-        ],
-    }
-    serializer = serializers.AlbumSerializer(data=data, context={"activity": activity})
-
-    assert serializer.is_valid(raise_exception=True)
-
-    album = serializer.save()
-    artist = album.artist
-
-    assert album.from_activity == activity
-    assert album.title == data["name"]
-    assert album.fid == data["id"]
-    assert str(album.mbid) == data["musicbrainzId"]
-    assert album.creation_date == published
-    assert album.release_date == released
-
-    assert artist.from_activity == activity
-    assert artist.name == data["artists"][0]["name"]
-    assert artist.fid == data["artists"][0]["id"]
-    assert str(artist.mbid) == data["artists"][0]["musicbrainzId"]
-    assert artist.creation_date == published
-
-
 def test_activity_pub_track_serializer_to_ap(factories):
     track = factories["music.Track"]()
     expected = {
@@ -753,7 +655,7 @@ def test_activity_pub_track_serializer_to_ap(factories):
     assert serializer.data == expected
 
 
-def test_activity_pub_track_serializer_from_ap(factories):
+def test_activity_pub_track_serializer_from_ap(factories, r_mock):
     activity = factories["federation.Activity"]()
     published = timezone.now()
     released = timezone.now().date()
@@ -771,6 +673,11 @@ def test_activity_pub_track_serializer_from_ap(factories):
             "musicbrainzId": str(uuid.uuid4()),
             "published": published.isoformat(),
             "released": released.isoformat(),
+            "cover": {
+                "type": "Link",
+                "href": "https://cover.image/test.png",
+                "mediaType": "image/png",
+            },
             "artists": [
                 {
                     "type": "Artist",
@@ -791,12 +698,14 @@ def test_activity_pub_track_serializer_from_ap(factories):
             }
         ],
     }
+    r_mock.get(data["album"]["cover"]["href"], body=io.BytesIO(b"coucou"))
     serializer = serializers.TrackSerializer(data=data, context={"activity": activity})
     assert serializer.is_valid(raise_exception=True)
 
     track = serializer.save()
     album = track.album
     artist = track.artist
+    album_artist = track.album.artist
 
     assert track.from_activity == activity
     assert track.fid == data["id"]
@@ -806,7 +715,8 @@ def test_activity_pub_track_serializer_from_ap(factories):
     assert str(track.mbid) == data["musicbrainzId"]
 
     assert album.from_activity == activity
-
+    assert album.cover.read() == b"coucou"
+    assert album.cover.path.endswith(".png")
     assert album.title == data["album"]["name"]
     assert album.fid == data["album"]["id"]
     assert str(album.mbid) == data["album"]["musicbrainzId"]
@@ -819,6 +729,12 @@ def test_activity_pub_track_serializer_from_ap(factories):
     assert str(artist.mbid) == data["artists"][0]["musicbrainzId"]
     assert artist.creation_date == published
 
+    assert album_artist.from_activity == activity
+    assert album_artist.name == data["album"]["artists"][0]["name"]
+    assert album_artist.fid == data["album"]["artists"][0]["id"]
+    assert str(album_artist.mbid) == data["album"]["artists"][0]["musicbrainzId"]
+    assert album_artist.creation_date == published
+
 
 def test_activity_pub_upload_serializer_from_ap(factories, mocker):
     activity = factories["federation.Activity"]()
diff --git a/api/tests/music/test.mp3 b/api/tests/music/test.mp3
index 8502de71b8284e9f30a397f58401d96fc42dbb17..6c1f52a35f665306af4959bb5ed024d2abea544a 100644
GIT binary patch
delta 24122
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
Q$uF7wus~$`g)SCH0E8@z=Kufz

delta 24097
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
KOux{@;s^i&YNEyf

diff --git a/api/tests/music/test_metadata.py b/api/tests/music/test_metadata.py
index f105b6b7e3..82c991c0b2 100644
--- a/api/tests/music/test_metadata.py
+++ b/api/tests/music/test_metadata.py
@@ -9,21 +9,46 @@ from funkwhale_api.music import metadata
 DATA_DIR = os.path.dirname(os.path.abspath(__file__))
 
 
+def test_get_all_metadata_at_once():
+    path = os.path.join(DATA_DIR, "test.ogg")
+    data = metadata.Metadata(path)
+
+    expected = {
+        "title": "Peer Gynt Suite no. 1, op. 46: I. Morning",
+        "artist": "Edvard Grieg",
+        "album_artist": "Edvard Grieg",
+        "album": "Peer Gynt Suite no. 1, op. 46",
+        "date": datetime.date(2012, 8, 15),
+        "track_number": 1,
+        "musicbrainz_albumid": uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75"),
+        "musicbrainz_recordingid": uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656"),
+        "musicbrainz_artistid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
+        "musicbrainz_albumartistid": uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
+    }
+
+    assert data.all() == expected
+
+
 @pytest.mark.parametrize(
     "field,value",
     [
         ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
         ("artist", "Edvard Grieg"),
+        ("album_artist", "Edvard Grieg"),
         ("album", "Peer Gynt Suite no. 1, op. 46"),
         ("date", datetime.date(2012, 8, 15)),
         ("track_number", 1),
         ("musicbrainz_albumid", uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75")),
         ("musicbrainz_recordingid", uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656")),
         ("musicbrainz_artistid", uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823")),
+        (
+            "musicbrainz_albumartistid",
+            uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
+        ),
     ],
 )
-def test_can_get_metadata_from_opus_file(field, value):
-    path = os.path.join(DATA_DIR, "test.opus")
+def test_can_get_metadata_from_ogg_file(field, value):
+    path = os.path.join(DATA_DIR, "test.ogg")
     data = metadata.Metadata(path)
 
     assert data.get(field) == value
@@ -34,16 +59,21 @@ def test_can_get_metadata_from_opus_file(field, value):
     [
         ("title", "Peer Gynt Suite no. 1, op. 46: I. Morning"),
         ("artist", "Edvard Grieg"),
+        ("album_artist", "Edvard Grieg"),
         ("album", "Peer Gynt Suite no. 1, op. 46"),
         ("date", datetime.date(2012, 8, 15)),
         ("track_number", 1),
         ("musicbrainz_albumid", uuid.UUID("a766da8b-8336-47aa-a3ee-371cc41ccc75")),
         ("musicbrainz_recordingid", uuid.UUID("bd21ac48-46d8-4e78-925f-d9cc2a294656")),
         ("musicbrainz_artistid", uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823")),
+        (
+            "musicbrainz_albumartistid",
+            uuid.UUID("013c8e5b-d72a-4cd3-8dee-6c64d6125823"),
+        ),
     ],
 )
-def test_can_get_metadata_from_ogg_file(field, value):
-    path = os.path.join(DATA_DIR, "test.ogg")
+def test_can_get_metadata_from_opus_file(field, value):
+    path = os.path.join(DATA_DIR, "test.opus")
     data = metadata.Metadata(path)
 
     assert data.get(field) == value
@@ -54,12 +84,17 @@ def test_can_get_metadata_from_ogg_file(field, value):
     [
         ("title", "Drei Kreuze (dass wir hier sind)"),
         ("artist", "Die Toten Hosen"),
+        ("album_artist", "Die Toten Hosen"),
         ("album", "Ballast der Republik"),
         ("date", datetime.date(2012, 5, 4)),
         ("track_number", 1),
         ("musicbrainz_albumid", uuid.UUID("1f0441ad-e609-446d-b355-809c445773cf")),
         ("musicbrainz_recordingid", uuid.UUID("124d0150-8627-46bc-bc14-789a3bc960c8")),
         ("musicbrainz_artistid", uuid.UUID("c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1")),
+        (
+            "musicbrainz_albumartistid",
+            uuid.UUID("c3bc80a6-1f4a-4e17-8cf0-6b1efe8302f1"),
+        ),
     ],
 )
 def test_can_get_metadata_from_ogg_theora_file(field, value):
@@ -73,13 +108,18 @@ def test_can_get_metadata_from_ogg_theora_file(field, value):
     "field,value",
     [
         ("title", "Bend"),
-        ("artist", "Bindrpilot"),
+        ("artist", "Binärpilot"),
+        ("album_artist", "Binärpilot"),
         ("album", "You Can't Stop Da Funk"),
         ("date", datetime.date(2006, 2, 7)),
         ("track_number", 2),
         ("musicbrainz_albumid", uuid.UUID("ce40cdb1-a562-4fd8-a269-9269f98d4124")),
         ("musicbrainz_recordingid", uuid.UUID("f269d497-1cc0-4ae4-a0c4-157ec7d73fcb")),
         ("musicbrainz_artistid", uuid.UUID("9c6bddde-6228-4d9f-ad0d-03f6fcb19e13")),
+        (
+            "musicbrainz_albumartistid",
+            uuid.UUID("9c6bddde-6228-4d9f-ad0d-03f6fcb19e13"),
+        ),
     ],
 )
 def test_can_get_metadata_from_id3_mp3_file(field, value):
@@ -108,12 +148,17 @@ def test_can_get_pictures(name):
     [
         ("title", "999,999"),
         ("artist", "Nine Inch Nails"),
+        ("album_artist", "Nine Inch Nails"),
         ("album", "The Slip"),
         ("date", datetime.date(2008, 5, 5)),
         ("track_number", 1),
         ("musicbrainz_albumid", uuid.UUID("12b57d46-a192-499e-a91f-7da66790a1c1")),
         ("musicbrainz_recordingid", uuid.UUID("30f3f33e-8d0c-4e69-8539-cbd701d18f28")),
         ("musicbrainz_artistid", uuid.UUID("b7ffd2af-418f-4be2-bdd1-22f8b48613da")),
+        (
+            "musicbrainz_albumartistid",
+            uuid.UUID("b7ffd2af-418f-4be2-bdd1-22f8b48613da"),
+        ),
     ],
 )
 def test_can_get_metadata_from_flac_file(field, value):
@@ -133,7 +178,12 @@ def test_can_get_metadata_from_flac_file_not_crash_if_empty():
 
 @pytest.mark.parametrize(
     "field_name",
-    ["musicbrainz_artistid", "musicbrainz_albumid", "musicbrainz_recordingid"],
+    [
+        "musicbrainz_artistid",
+        "musicbrainz_albumid",
+        "musicbrainz_recordingid",
+        "musicbrainz_albumartistid",
+    ],
 )
 def test_mbid_clean_keeps_only_first(field_name):
     u1 = str(uuid.uuid4())
diff --git a/api/tests/music/test_tasks.py b/api/tests/music/test_tasks.py
index c58bce7db1..de5e0310f6 100644
--- a/api/tests/music/test_tasks.py
+++ b/api/tests/music/test_tasks.py
@@ -1,12 +1,14 @@
 import datetime
+import io
 import os
 import pytest
 import uuid
 
 from django.core.paginator import Paginator
+from django.utils import timezone
 
 from funkwhale_api.federation import serializers as federation_serializers
-from funkwhale_api.music import signals, tasks
+from funkwhale_api.music import metadata, signals, tasks
 
 DATA_DIR = os.path.dirname(os.path.abspath(__file__))
 
@@ -16,84 +18,163 @@ DATA_DIR = os.path.dirname(os.path.abspath(__file__))
 
 def test_can_create_track_from_file_metadata_no_mbid(db, mocker):
     metadata = {
-        "artist": ["Test artist"],
-        "album": ["Test album"],
-        "title": ["Test track"],
-        "TRACKNUMBER": ["4"],
-        "date": ["2012-08-15"],
+        "title": "Test track",
+        "artist": "Test artist",
+        "album": "Test album",
+        "date": datetime.date(2012, 8, 15),
+        "track_number": 4,
     }
-    mocker.patch("mutagen.File", return_value=metadata)
-    mocker.patch(
-        "funkwhale_api.music.metadata.Metadata.get_file_type", return_value="OggVorbis"
-    )
-    track = tasks.import_track_data_from_file(os.path.join(DATA_DIR, "dummy_file.ogg"))
+    mocker.patch("funkwhale_api.music.metadata.Metadata.all", return_value=metadata)
+
+    track = tasks.get_track_from_import_metadata(metadata)
 
-    assert track.title == metadata["title"][0]
+    assert track.title == metadata["title"]
     assert track.mbid is None
     assert track.position == 4
-    assert track.album.title == metadata["album"][0]
+    assert track.album.title == metadata["album"]
     assert track.album.mbid is None
     assert track.album.release_date == datetime.date(2012, 8, 15)
-    assert track.artist.name == metadata["artist"][0]
+    assert track.artist.name == metadata["artist"]
     assert track.artist.mbid is None
 
 
 def test_can_create_track_from_file_metadata_mbid(factories, mocker):
-    album = factories["music.Album"]()
-    artist = factories["music.Artist"]()
-    mocker.patch(
-        "funkwhale_api.music.models.Album.get_or_create_from_api",
-        return_value=(album, True),
-    )
+    metadata = {
+        "title": "Test track",
+        "artist": "Test artist",
+        "album_artist": "Test album artist",
+        "album": "Test album",
+        "date": datetime.date(2012, 8, 15),
+        "track_number": 4,
+        "musicbrainz_albumid": "ce40cdb1-a562-4fd8-a269-9269f98d4124",
+        "musicbrainz_recordingid": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb",
+        "musicbrainz_artistid": "9c6bddde-6228-4d9f-ad0d-03f6fcb19e13",
+        "musicbrainz_albumartistid": "9c6bddde-6478-4d9f-ad0d-03f6fcb19e13",
+    }
 
-    album_data = {
-        "release": {
-            "id": album.mbid,
-            "medium-list": [
-                {
-                    "track-list": [
-                        {
-                            "id": "03baca8b-855a-3c05-8f3d-d3235287d84d",
-                            "position": "4",
-                            "number": "4",
-                            "recording": {
-                                "id": "2109e376-132b-40ad-b993-2bb6812e19d4",
-                                "title": "Teen Age Riot",
-                                "artist-credit": [
-                                    {"artist": {"id": artist.mbid, "name": artist.name}}
-                                ],
-                            },
-                        }
-                    ],
-                    "track-count": 1,
-                }
-            ],
-        }
+    mocker.patch("funkwhale_api.music.metadata.Metadata.all", return_value=metadata)
+
+    track = tasks.get_track_from_import_metadata(metadata)
+
+    assert track.title == metadata["title"]
+    assert track.mbid == metadata["musicbrainz_recordingid"]
+    assert track.position == 4
+    assert track.album.title == metadata["album"]
+    assert track.album.mbid == metadata["musicbrainz_albumid"]
+    assert track.album.artist.mbid == metadata["musicbrainz_albumartistid"]
+    assert track.album.artist.name == metadata["album_artist"]
+    assert track.album.release_date == datetime.date(2012, 8, 15)
+    assert track.artist.name == metadata["artist"]
+    assert track.artist.mbid == metadata["musicbrainz_artistid"]
+
+
+def test_can_create_track_from_file_metadata_mbid_existing_album_artist(
+    factories, mocker
+):
+    artist = factories["music.Artist"]()
+    album = factories["music.Album"]()
+    metadata = {
+        "artist": "",
+        "album": "",
+        "title": "Hello",
+        "track_number": 4,
+        "musicbrainz_albumid": album.mbid,
+        "musicbrainz_recordingid": "f269d497-1cc0-4ae4-a0c4-157ec7d73fcb",
+        "musicbrainz_artistid": artist.mbid,
+        "musicbrainz_albumartistid": album.artist.mbid,
     }
-    mocker.patch("funkwhale_api.musicbrainz.api.releases.get", return_value=album_data)
-    track_data = album_data["release"]["medium-list"][0]["track-list"][0]
+
+    mocker.patch("funkwhale_api.music.metadata.Metadata.all", return_value=metadata)
+
+    track = tasks.get_track_from_import_metadata(metadata)
+
+    assert track.title == metadata["title"]
+    assert track.mbid == metadata["musicbrainz_recordingid"]
+    assert track.position == 4
+    assert track.album == album
+    assert track.artist == artist
+
+
+def test_can_create_track_from_file_metadata_fid_existing_album_artist(
+    factories, mocker
+):
+    artist = factories["music.Artist"]()
+    album = factories["music.Album"]()
     metadata = {
-        "musicbrainz_albumid": [album.mbid],
-        "musicbrainz_trackid": [track_data["recording"]["id"]],
+        "artist": "",
+        "album": "",
+        "title": "Hello",
+        "track_number": 4,
+        "fid": "https://hello",
+        "album_fid": album.fid,
+        "artist_fid": artist.fid,
+        "album_artist_fid": album.artist.fid,
     }
-    mocker.patch("mutagen.File", return_value=metadata)
-    mocker.patch(
-        "funkwhale_api.music.metadata.Metadata.get_file_type", return_value="OggVorbis"
-    )
-    track = tasks.import_track_data_from_file(os.path.join(DATA_DIR, "dummy_file.ogg"))
 
-    assert track.title == track_data["recording"]["title"]
-    assert track.mbid == track_data["recording"]["id"]
+    mocker.patch("funkwhale_api.music.metadata.Metadata.all", return_value=metadata)
+
+    track = tasks.get_track_from_import_metadata(metadata)
+
+    assert track.title == metadata["title"]
+    assert track.fid == metadata["fid"]
     assert track.position == 4
     assert track.album == album
     assert track.artist == artist
 
 
-def test_upload_import_mbid(now, factories, temp_signal, mocker):
+def test_can_create_track_from_file_metadata_federation(factories, mocker, r_mock):
+    metadata = {
+        "artist": "Artist",
+        "album": "Album",
+        "album_artist": "Album artist",
+        "title": "Hello",
+        "track_number": 4,
+        "fid": "https://hello",
+        "album_fid": "https://album.fid",
+        "artist_fid": "https://artist.fid",
+        "album_artist_fid": "https://album.artist.fid",
+        "fdate": timezone.now(),
+        "album_fdate": timezone.now(),
+        "album_artist_fdate": timezone.now(),
+        "artist_fdate": timezone.now(),
+        "cover_data": {"url": "https://cover/hello.png", "mimetype": "image/png"},
+    }
+    r_mock.get(metadata["cover_data"]["url"], body=io.BytesIO(b"coucou"))
+    mocker.patch("funkwhale_api.music.metadata.Metadata.all", return_value=metadata)
+
+    track = tasks.get_track_from_import_metadata(metadata)
+
+    assert track.title == metadata["title"]
+    assert track.fid == metadata["fid"]
+    assert track.creation_date == metadata["fdate"]
+    assert track.position == 4
+    assert track.album.cover.read() == b"coucou"
+    assert track.album.cover.path.endswith(".png")
+    assert track.album.fid == metadata["album_fid"]
+    assert track.album.title == metadata["album"]
+    assert track.album.creation_date == metadata["album_fdate"]
+    assert track.album.artist.fid == metadata["album_artist_fid"]
+    assert track.album.artist.name == metadata["album_artist"]
+    assert track.album.artist.creation_date == metadata["album_artist_fdate"]
+    assert track.artist.fid == metadata["artist_fid"]
+    assert track.artist.name == metadata["artist"]
+    assert track.artist.creation_date == metadata["artist_fdate"]
+
+
+def test_sort_candidates(factories):
+    artist1 = factories["music.Artist"].build(fid=None, mbid=None)
+    artist2 = factories["music.Artist"].build(fid=None)
+    artist3 = factories["music.Artist"].build(mbid=None)
+    result = tasks.sort_candidates([artist1, artist2, artist3], ["mbid", "fid"])
+
+    assert result == [artist2, artist3, artist1]
+
+
+def test_upload_import(now, factories, temp_signal, mocker):
     outbox = mocker.patch("funkwhale_api.federation.routes.outbox.dispatch")
     track = factories["music.Track"]()
     upload = factories["music.Upload"](
-        track=None, import_metadata={"track": {"mbid": track.mbid}}
+        track=None, import_metadata={"funkwhale": {"track": {"uuid": str(track.uuid)}}}
     )
 
     with temp_signal(signals.upload_import_status_updated) as handler:
@@ -123,7 +204,29 @@ def test_upload_import_get_audio_data(factories, mocker):
     )
     track = factories["music.Track"]()
     upload = factories["music.Upload"](
-        track=None, import_metadata={"track": {"mbid": track.mbid}}
+        track=None, import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}}
+    )
+
+    tasks.process_upload(upload_id=upload.pk)
+
+    upload.refresh_from_db()
+    assert upload.size == 23
+    assert upload.duration == 42
+    assert upload.bitrate == 66
+
+
+def test_upload_import_in_place(factories, mocker):
+    mocker.patch(
+        "funkwhale_api.music.models.Upload.get_audio_data",
+        return_value={"size": 23, "duration": 42, "bitrate": 66},
+    )
+    track = factories["music.Track"]()
+    path = os.path.join(DATA_DIR, "test.ogg")
+    upload = factories["music.Upload"](
+        track=None,
+        audio_file=None,
+        source="file://{}".format(path),
+        import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}},
     )
 
     tasks.process_upload(upload_id=upload.pk)
@@ -141,13 +244,13 @@ def test_upload_import_skip_existing_track_in_own_library(factories, temp_signal
         track=track,
         import_status="finished",
         library=library,
-        import_metadata={"track": {"mbid": track.mbid}},
+        import_metadata={"funkwhale": {"track": {"uuid": track.mbid}}},
     )
     duplicate = factories["music.Upload"](
         track=track,
         import_status="pending",
         library=library,
-        import_metadata={"track": {"mbid": track.mbid}},
+        import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}},
     )
     with temp_signal(signals.upload_import_status_updated) as handler:
         tasks.process_upload(upload_id=duplicate.pk)
@@ -172,7 +275,7 @@ def test_upload_import_skip_existing_track_in_own_library(factories, temp_signal
 def test_upload_import_track_uuid(now, factories):
     track = factories["music.Track"]()
     upload = factories["music.Upload"](
-        track=None, import_metadata={"track": {"uuid": track.uuid}}
+        track=None, import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}}
     )
 
     tasks.process_upload(upload_id=upload.pk)
@@ -184,9 +287,43 @@ def test_upload_import_track_uuid(now, factories):
     assert upload.import_date == now
 
 
+def test_upload_import_skip_federation(now, factories, mocker):
+    outbox = mocker.patch("funkwhale_api.federation.routes.outbox.dispatch")
+    track = factories["music.Track"]()
+    upload = factories["music.Upload"](
+        track=None,
+        import_metadata={
+            "funkwhale": {
+                "track": {"uuid": track.uuid},
+                "config": {"dispatch_outbox": False},
+            }
+        },
+    )
+
+    tasks.process_upload(upload_id=upload.pk)
+
+    outbox.assert_not_called()
+
+
+def test_upload_import_skip_broadcast(now, factories, mocker):
+    group_send = mocker.patch("funkwhale_api.common.channels.group_send")
+    track = factories["music.Track"]()
+    upload = factories["music.Upload"](
+        library__actor__local=True,
+        track=None,
+        import_metadata={
+            "funkwhale": {"track": {"uuid": track.uuid}, "config": {"broadcast": False}}
+        },
+    )
+
+    tasks.process_upload(upload_id=upload.pk)
+
+    group_send.assert_not_called()
+
+
 def test_upload_import_error(factories, now, temp_signal):
     upload = factories["music.Upload"](
-        import_metadata={"track": {"uuid": uuid.uuid4()}}
+        import_metadata={"funkwhale": {"track": {"uuid": uuid.uuid4()}}}
     )
     with temp_signal(signals.upload_import_status_updated) as handler:
         tasks.process_upload(upload_id=upload.pk)
@@ -209,32 +346,26 @@ def test_upload_import_updates_cover_if_no_cover(factories, mocker, now):
     album = factories["music.Album"](cover="")
     track = factories["music.Track"](album=album)
     upload = factories["music.Upload"](
-        track=None, import_metadata={"track": {"uuid": track.uuid}}
+        track=None, import_metadata={"funkwhale": {"track": {"uuid": track.uuid}}}
     )
     tasks.process_upload(upload_id=upload.pk)
-    mocked_update.assert_called_once_with(album, upload)
+    mocked_update.assert_called_once_with(album, source=None, cover_data=None)
 
 
 def test_update_album_cover_mbid(factories, mocker):
     album = factories["music.Album"](cover="")
 
     mocked_get = mocker.patch("funkwhale_api.music.models.Album.get_image")
-    tasks.update_album_cover(album=album, upload=None)
+    tasks.update_album_cover(album=album)
 
     mocked_get.assert_called_once_with()
 
 
 def test_update_album_cover_file_data(factories, mocker):
     album = factories["music.Album"](cover="", mbid=None)
-    upload = factories["music.Upload"](track__album=album)
 
     mocked_get = mocker.patch("funkwhale_api.music.models.Album.get_image")
-    mocker.patch(
-        "funkwhale_api.music.metadata.Metadata.get_picture",
-        return_value={"hello": "world"},
-    )
-    tasks.update_album_cover(album=album, upload=upload)
-    upload.get_metadata()
+    tasks.update_album_cover(album=album, cover_data={"hello": "world"})
     mocked_get.assert_called_once_with(data={"hello": "world"})
 
 
@@ -245,19 +376,87 @@ def test_update_album_cover_file_cover_separate_file(ext, mimetype, factories, m
     with open(image_path, "rb") as f:
         image_content = f.read()
     album = factories["music.Album"](cover="", mbid=None)
-    upload = factories["music.Upload"](
-        track__album=album, source="file://" + image_path
-    )
 
     mocked_get = mocker.patch("funkwhale_api.music.models.Album.get_image")
     mocker.patch("funkwhale_api.music.metadata.Metadata.get_picture", return_value=None)
-    tasks.update_album_cover(album=album, upload=upload)
-    upload.get_metadata()
+    tasks.update_album_cover(album=album, source="file://" + image_path)
     mocked_get.assert_called_once_with(
         data={"mimetype": mimetype, "content": image_content}
     )
 
 
+def test_federation_audio_track_to_metadata(now):
+    published = now
+    released = now.date()
+    payload = {
+        "type": "Track",
+        "id": "http://hello.track",
+        "musicbrainzId": str(uuid.uuid4()),
+        "name": "Black in back",
+        "position": 5,
+        "published": published.isoformat(),
+        "album": {
+            "published": published.isoformat(),
+            "type": "Album",
+            "id": "http://hello.album",
+            "name": "Purple album",
+            "musicbrainzId": str(uuid.uuid4()),
+            "released": released.isoformat(),
+            "artists": [
+                {
+                    "type": "Artist",
+                    "published": published.isoformat(),
+                    "id": "http://hello.artist",
+                    "name": "John Smith",
+                    "musicbrainzId": str(uuid.uuid4()),
+                }
+            ],
+        },
+        "artists": [
+            {
+                "published": published.isoformat(),
+                "type": "Artist",
+                "id": "http://hello.trackartist",
+                "name": "Bob Smith",
+                "musicbrainzId": str(uuid.uuid4()),
+            }
+        ],
+    }
+    serializer = federation_serializers.TrackSerializer(data=payload)
+    serializer.is_valid(raise_exception=True)
+    expected = {
+        "artist": payload["artists"][0]["name"],
+        "album": payload["album"]["name"],
+        "album_artist": payload["album"]["artists"][0]["name"],
+        "title": payload["name"],
+        "date": released,
+        "track_number": payload["position"],
+        # musicbrainz
+        "musicbrainz_albumid": payload["album"]["musicbrainzId"],
+        "musicbrainz_recordingid": payload["musicbrainzId"],
+        "musicbrainz_artistid": payload["artists"][0]["musicbrainzId"],
+        "musicbrainz_albumartistid": payload["album"]["artists"][0]["musicbrainzId"],
+        # federation
+        "fid": payload["id"],
+        "album_fid": payload["album"]["id"],
+        "artist_fid": payload["artists"][0]["id"],
+        "album_artist_fid": payload["album"]["artists"][0]["id"],
+        "fdate": serializer.validated_data["published"],
+        "artist_fdate": serializer.validated_data["artists"][0]["published"],
+        "album_artist_fdate": serializer.validated_data["album"]["artists"][0][
+            "published"
+        ],
+        "album_fdate": serializer.validated_data["album"]["published"],
+    }
+
+    result = tasks.federation_audio_track_to_metadata(serializer.validated_data)
+    assert result == expected
+
+    # ensure we never forget to test a mandatory field
+    for k in metadata.ALL_FIELDS:
+        assert k in result
+
+
 def test_scan_library_fetches_page_and_calls_scan_page(now, mocker, factories, r_mock):
     scan = factories["music.LibraryScan"]()
     collection_conf = {
diff --git a/api/tests/test_import_audio_file.py b/api/tests/test_import_audio_file.py
index a7b2380ed6..ad4b4be0e7 100644
--- a/api/tests/test_import_audio_file.py
+++ b/api/tests/test_import_audio_file.py
@@ -54,6 +54,39 @@ def test_import_files_stores_proper_data(factories, mocker, now, path):
     assert upload.import_reference == "cli-{}".format(now.isoformat())
     assert upload.import_status == "pending"
     assert upload.source == "file://{}".format(path)
+    assert upload.import_metadata == {
+        "funkwhale": {
+            "config": {"replace": False, "dispatch_outbox": False, "broadcast": False}
+        }
+    }
+
+    mocked_process.assert_called_once_with(upload_id=upload.pk)
+
+
+def test_import_with_outbox_flag(factories, mocker):
+    library = factories["music.Library"](actor__local=True)
+    path = os.path.join(DATA_DIR, "dummy_file.ogg")
+    mocked_process = mocker.patch("funkwhale_api.music.tasks.process_upload")
+    call_command(
+        "import_files", str(library.uuid), path, outbox=True, interactive=False
+    )
+    upload = library.uploads.last()
+
+    assert upload.import_metadata["funkwhale"]["config"]["dispatch_outbox"] is True
+
+    mocked_process.assert_called_once_with(upload_id=upload.pk)
+
+
+def test_import_with_broadcast_flag(factories, mocker):
+    library = factories["music.Library"](actor__local=True)
+    path = os.path.join(DATA_DIR, "dummy_file.ogg")
+    mocked_process = mocker.patch("funkwhale_api.music.tasks.process_upload")
+    call_command(
+        "import_files", str(library.uuid), path, broadcast=True, interactive=False
+    )
+    upload = library.uploads.last()
+
+    assert upload.import_metadata["funkwhale"]["config"]["broadcast"] is True
 
     mocked_process.assert_called_once_with(upload_id=upload.pk)
 
@@ -67,7 +100,7 @@ def test_import_with_replace_flag(factories, mocker):
     )
     upload = library.uploads.last()
 
-    assert upload.import_metadata["replace"] is True
+    assert upload.import_metadata["funkwhale"]["config"]["replace"] is True
 
     mocked_process.assert_called_once_with(upload_id=upload.pk)
 
diff --git a/dev.yml b/dev.yml
index a67085e44b..5ac74424cc 100644
--- a/dev.yml
+++ b/dev.yml
@@ -30,6 +30,7 @@ services:
       - .env.dev
       - .env
     image: postgres
+    command: postgres -c log_min_duration_statement=0
     volumes:
       - "./data/${COMPOSE_PROJECT_NAME-node1}/postgres:/var/lib/postgresql/data"
     networks:
diff --git a/front/src/views/content/libraries/FilesTable.vue b/front/src/views/content/libraries/FilesTable.vue
index c657cc7f9b..ef34b39832 100644
--- a/front/src/views/content/libraries/FilesTable.vue
+++ b/front/src/views/content/libraries/FilesTable.vue
@@ -282,6 +282,7 @@ export default {
     'search.tokens': {
       handler (newValue) {
         this.search.query = compileTokens(newValue)
+        this.page = 1
         this.fetchData()
       },
       deep: true
@@ -290,6 +291,9 @@ export default {
       this.page = 1
       this.fetchData()
     },
+    page: function () {
+      this.fetchData()
+    },
     ordering: function () {
       this.page = 1
       this.fetchData()
-- 
GitLab