diff --git a/api/config/api_urls.py b/api/config/api_urls.py
index 909dff45ee2de04e5671832f42499e695ec885f8..73df6fc4e90b392f2430feb3c2a2de95bfed928e 100644
--- a/api/config/api_urls.py
+++ b/api/config/api_urls.py
@@ -74,11 +74,6 @@ v1_patterns += [
         include(("funkwhale_api.history.urls", "history"), namespace="history"),
     ),
     url(r"^", include(("funkwhale_api.users.api_urls", "users"), namespace="users"),),
-    # XXX: 1.0: remove this
-    url(
-        r"^users/",
-        include(("funkwhale_api.users.api_urls", "users"), namespace="users-nested"),
-    ),
     url(
         r"^oauth/",
         include(("funkwhale_api.users.oauth.urls", "oauth"), namespace="oauth"),
diff --git a/api/config/routing.py b/api/config/routing.py
index d0858e2432457ad9ae06c81c7ab555b998d595db..ce293ff768dddc7ed9083987d8f3b1daa5963d7f 100644
--- a/api/config/routing.py
+++ b/api/config/routing.py
@@ -2,18 +2,13 @@ from channels.auth import AuthMiddlewareStack
 from channels.routing import ProtocolTypeRouter, URLRouter
 
 from django.conf.urls import url
-from funkwhale_api.common.auth import TokenAuthMiddleware
 from funkwhale_api.instance import consumers
 
 application = ProtocolTypeRouter(
     {
         # Empty for now (http->django views is added by default)
         "websocket": AuthMiddlewareStack(
-            TokenAuthMiddleware(
-                URLRouter(
-                    [url("^api/v1/activity$", consumers.InstanceActivityConsumer)]
-                )
-            )
+            URLRouter([url("^api/v1/activity$", consumers.InstanceActivityConsumer)])
         )
     }
 )
diff --git a/api/config/settings/common.py b/api/config/settings/common.py
index 646345544530e1df9cf783603861dd05ce9c55b4..9f5a551ed3e5b1fdf31be98dd06c4ce13b4d297a 100644
--- a/api/config/settings/common.py
+++ b/api/config/settings/common.py
@@ -169,17 +169,7 @@ os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = env.bool(
     "DJANGO_ALLOW_ASYNC_UNSAFE", default="true"
 )
 
-# XXX: deprecated, see #186
-FEDERATION_ENABLED = env.bool("FEDERATION_ENABLED", default=True)
 FEDERATION_HOSTNAME = env("FEDERATION_HOSTNAME", default=FUNKWHALE_HOSTNAME).lower()
-# XXX: deprecated, see #186
-FEDERATION_COLLECTION_PAGE_SIZE = env.int("FEDERATION_COLLECTION_PAGE_SIZE", default=50)
-# XXX: deprecated, see #186
-FEDERATION_MUSIC_NEEDS_APPROVAL = env.bool(
-    "FEDERATION_MUSIC_NEEDS_APPROVAL", default=True
-)
-# XXX: deprecated, see #186
-FEDERATION_ACTOR_FETCH_DELAY = env.int("FEDERATION_ACTOR_FETCH_DELAY", default=60 * 12)
 FEDERATION_SERVICE_ACTOR_USERNAME = env(
     "FEDERATION_SERVICE_ACTOR_USERNAME", default="service"
 )
@@ -1129,11 +1119,6 @@ Exemples:
 CSRF_USE_SESSIONS = True
 SESSION_ENGINE = "django.contrib.sessions.backends.cache"
 
-# Playlist settings
-# XXX: deprecated, see #186
-PLAYLISTS_MAX_TRACKS = env.int("PLAYLISTS_MAX_TRACKS", default=250)
-
-
 ACCOUNT_USERNAME_BLACKLIST = [
     "funkwhale",
     "library",
@@ -1170,8 +1155,6 @@ EXTERNAL_REQUESTS_TIMEOUT = env.int("EXTERNAL_REQUESTS_TIMEOUT", default=10)
 """
 Default timeout for external requests.
 """
-# XXX: deprecated, see #186
-API_AUTHENTICATION_REQUIRED = env.bool("API_AUTHENTICATION_REQUIRED", True)
 
 MUSIC_DIRECTORY_PATH = env("MUSIC_DIRECTORY_PATH", default=None)
 """
@@ -1285,8 +1268,6 @@ FUNKWHALE_SUPPORT_MESSAGE_DELAY = env.int("FUNKWHALE_SUPPORT_MESSAGE_DELAY", def
 """
 Delay in days after signup before we show the "support Funkwhale" message
 """
-# XXX Stable release: remove
-USE_FULL_TEXT_SEARCH = env.bool("USE_FULL_TEXT_SEARCH", default=True)
 
 MIN_DELAY_BETWEEN_DOWNLOADS_COUNT = env.int(
     "MIN_DELAY_BETWEEN_DOWNLOADS_COUNT", default=60 * 60 * 6
diff --git a/api/funkwhale_api/common/dynamic_preferences_registry.py b/api/funkwhale_api/common/dynamic_preferences_registry.py
index d6dfed78376503387c48247426ee6925772dbdff..6d15fcd8f3fc22aeb66d3a710ec49a5f74e6a95f 100644
--- a/api/funkwhale_api/common/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/common/dynamic_preferences_registry.py
@@ -1,19 +1,15 @@
 from dynamic_preferences import types
 from dynamic_preferences.registries import global_preferences_registry
 
-from funkwhale_api.common import preferences
-
 common = types.Section("common")
 
 
 @global_preferences_registry.register
-class APIAutenticationRequired(
-    preferences.DefaultFromSettingMixin, types.BooleanPreference
-):
+class APIAutenticationRequired(types.BooleanPreference):
     section = common
     name = "api_authentication_required"
     verbose_name = "API Requires authentication"
-    setting = "API_AUTHENTICATION_REQUIRED"
+    default = True
     help_text = (
         "If disabled, anonymous users will be able to query the API"
         "and access music data (as well as other data exposed in the API "
diff --git a/api/funkwhale_api/common/fields.py b/api/funkwhale_api/common/fields.py
index ffc8e5f95d42171542b2cda6e863a9f157026e30..d354c93eb7e213ea1fdb0bd206071f837fd5db92 100644
--- a/api/funkwhale_api/common/fields.py
+++ b/api/funkwhale_api/common/fields.py
@@ -1,6 +1,5 @@
 import django_filters
 from django import forms
-from django.conf import settings
 from django.core.serializers.json import DjangoJSONEncoder
 from django.db import models
 
@@ -40,7 +39,7 @@ class SearchFilter(django_filters.CharFilter):
     def filter(self, qs, value):
         if not value:
             return qs
-        if settings.USE_FULL_TEXT_SEARCH and self.fts_search_fields:
+        if self.fts_search_fields:
             query = search.get_fts_query(
                 value, self.fts_search_fields, model=self.parent.Meta.model
             )
diff --git a/api/funkwhale_api/common/middleware.py b/api/funkwhale_api/common/middleware.py
index b085a18fe84c78b423d33d5603a4887a7ba9f341..4752159106ca2de510f4c8b1ba0fcae32615a4ff 100644
--- a/api/funkwhale_api/common/middleware.py
+++ b/api/funkwhale_api/common/middleware.py
@@ -113,7 +113,7 @@ def get_spa_html(spa_url):
 
 def get_spa_file(spa_url, name):
     if spa_url.startswith("/"):
-        # XXX: spa_url is an absolute path to index.html, on the local disk.
+        # spa_url is an absolute path to index.html, on the local disk.
         # However, we may want to access manifest.json or other files as well, so we
         # strip the filename
         path = os.path.join(os.path.dirname(spa_url), name)
diff --git a/api/funkwhale_api/common/serializers.py b/api/funkwhale_api/common/serializers.py
index 76e698c5f993a036c7c4198911877a0ad2762234..9210c0603c3925d724dc82d79ba5e1c0fae227f8 100644
--- a/api/funkwhale_api/common/serializers.py
+++ b/api/funkwhale_api/common/serializers.py
@@ -299,20 +299,6 @@ class AttachmentSerializer(serializers.Serializer):
         urls["medium_square_crop"] = o.download_url_medium_square_crop
         return urls
 
-    def to_representation(self, o):
-        repr = super().to_representation(o)
-        # XXX: BACKWARD COMPATIBILITY
-        # having the attachment urls in a nested JSON obj is better,
-        # but we can't do this without breaking clients
-        # So we extract the urls and include these in the parent payload
-        repr.update({k: v for k, v in repr["urls"].items() if k != "source"})
-        # also, our legacy images had lots of variations (400x400, 200x200, 50x50)
-        # but we removed some of these, so we emulate these by hand (by redirecting)
-        # to actual, existing attachment variations
-        repr["square_crop"] = repr["medium_square_crop"]
-        repr["small_square_crop"] = repr["medium_square_crop"]
-        return repr
-
     def create(self, validated_data):
         return models.Attachment.objects.create(
             file=validated_data["file"], actor=validated_data["actor"]
diff --git a/api/funkwhale_api/favorites/filters.py b/api/funkwhale_api/favorites/filters.py
index 0b76a4dd04340da3ad62b2391a82dd9e9534dc9e..32c07a646bd80ca5675fc61fc2a45e25c31e8308 100644
--- a/api/funkwhale_api/favorites/filters.py
+++ b/api/funkwhale_api/favorites/filters.py
@@ -13,8 +13,7 @@ class TrackFavoriteFilter(moderation_filters.HiddenContentFilterSet):
 
     class Meta:
         model = models.TrackFavorite
-        # XXX: 1.0 remove the user filter, we have scope=me now
-        fields = ["user"]
+        fields = []
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG[
             "TRACK_FAVORITE"
         ]
diff --git a/api/funkwhale_api/federation/dynamic_preferences_registry.py b/api/funkwhale_api/federation/dynamic_preferences_registry.py
index 6f7d7171958604d7c69558774abbf459fada556f..c696b95781e5f9e941cf27e197ab2c67cc89474f 100644
--- a/api/funkwhale_api/federation/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/federation/dynamic_preferences_registry.py
@@ -1,8 +1,6 @@
 from dynamic_preferences import types
 from dynamic_preferences.registries import global_preferences_registry
 
-from funkwhale_api.common import preferences
-
 federation = types.Section("federation")
 
 
@@ -22,10 +20,10 @@ class MusicCacheDuration(types.IntPreference):
 
 
 @global_preferences_registry.register
-class Enabled(preferences.DefaultFromSettingMixin, types.BooleanPreference):
+class Enabled(types.BooleanPreference):
     section = federation
     name = "enabled"
-    setting = "FEDERATION_ENABLED"
+    default = True
     verbose_name = "Federation enabled"
     help_text = (
         "Use this setting to enable or disable federation logic and API" " globally."
@@ -33,20 +31,20 @@ class Enabled(preferences.DefaultFromSettingMixin, types.BooleanPreference):
 
 
 @global_preferences_registry.register
-class CollectionPageSize(preferences.DefaultFromSettingMixin, types.IntPreference):
+class CollectionPageSize(types.IntPreference):
     section = federation
     name = "collection_page_size"
-    setting = "FEDERATION_COLLECTION_PAGE_SIZE"
+    default = 50
     verbose_name = "Federation collection page size"
     help_text = "How many items to display in ActivityPub collections."
     field_kwargs = {"required": False}
 
 
 @global_preferences_registry.register
-class ActorFetchDelay(preferences.DefaultFromSettingMixin, types.IntPreference):
+class ActorFetchDelay(types.IntPreference):
     section = federation
     name = "actor_fetch_delay"
-    setting = "FEDERATION_ACTOR_FETCH_DELAY"
+    default = 60 * 12
     verbose_name = "Federation actor fetch delay"
     help_text = (
         "How many minutes to wait before refetching actors on "
diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py
index 00d5d1e4d1d155c5de9a62dc9c2ef91f96df9867..9f68a2375d96cf78a801a2f0d6045bfa3588ce03 100644
--- a/api/funkwhale_api/federation/serializers.py
+++ b/api/funkwhale_api/federation/serializers.py
@@ -938,8 +938,6 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer):
         last = common_utils.set_query_parameter(conf["id"], page=paginator.num_pages)
         d = {
             "id": conf["id"],
-            # XXX Stable release: remove the obsolete actor field
-            "actor": conf["actor"].fid,
             "attributedTo": conf["actor"].fid,
             "totalItems": paginator.count,
             "type": conf.get("type", "Collection"),
@@ -1004,9 +1002,8 @@ class LibrarySerializer(PaginatedCollectionSerializer):
             "name": library.name,
             "summary": library.description,
             "page_size": 100,
-            # XXX Stable release: remove the obsolete actor field
-            "actor": library.actor,
             "attributedTo": library.actor,
+            "actor": library.actor,
             "items": library.uploads.for_federation(),
             "type": "Library",
         }
@@ -1108,8 +1105,6 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer):
             ],
         }
         if conf["actor"]:
-            # XXX Stable release: remove the obsolete actor field
-            d["actor"] = conf["actor"].fid
             d["attributedTo"] = conf["actor"].fid
 
         if page.has_previous():
@@ -1297,8 +1292,7 @@ class AlbumSerializer(MusicEntitySerializer):
         child=MultipleSerializer(allowed=[BasicActorSerializer, ArtistSerializer]),
         min_length=1,
     )
-    # XXX: 1.0 rename to image
-    cover = ImageSerializer(
+    image = ImageSerializer(
         allowed_mimetypes=["image/*"],
         allow_null=True,
         required=False,
@@ -1306,7 +1300,7 @@ class AlbumSerializer(MusicEntitySerializer):
     )
     updateable_fields = [
         ("name", "title"),
-        ("cover", "attachment_cover"),
+        ("image", "attachment_cover"),
         ("musicbrainzId", "mbid"),
         ("attributedTo", "attributed_to"),
         ("released", "release_date"),
@@ -1320,7 +1314,7 @@ class AlbumSerializer(MusicEntitySerializer):
             {
                 "released": jsonld.first_val(contexts.FW.released),
                 "artists": jsonld.first_attr(contexts.FW.artists, "@list"),
-                "cover": jsonld.first_obj(contexts.FW.cover),
+                "image": jsonld.first_obj(contexts.AS.image),
             },
         )
 
@@ -1354,11 +1348,6 @@ class AlbumSerializer(MusicEntitySerializer):
             ]
         include_content(d, instance.description)
         if instance.attachment_cover:
-            d["cover"] = {
-                "type": "Link",
-                "href": instance.attachment_cover.download_url_original,
-                "mediaType": instance.attachment_cover.mimetype or "image/jpeg",
-            }
             include_image(d, instance.attachment_cover)
 
         if self.context.get("include_ap_context", self.parent is None):
diff --git a/api/funkwhale_api/federation/utils.py b/api/funkwhale_api/federation/utils.py
index d6a35df281f29ddf20235a9320489997d87a24d0..2bac8daf8fb8dd5e64fc9711e1367360f0ce2651 100644
--- a/api/funkwhale_api/federation/utils.py
+++ b/api/funkwhale_api/federation/utils.py
@@ -218,7 +218,6 @@ def should_redirect_ap_to_html(accept_header, default=True):
         "text/html",
     ]
     no_redirect_headers = [
-        "*/*",  # XXX backward compat with older Funkwhale instances that don't send the Accept header
         "application/json",
         "application/activity+json",
         "application/ld+json",
diff --git a/api/funkwhale_api/moderation/migrations/0006_auto_20200803_1222.py b/api/funkwhale_api/moderation/migrations/0006_auto_20200803_1222.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca1cfc9edd693beec9159fb627c2ebb2bdad35ee
--- /dev/null
+++ b/api/funkwhale_api/moderation/migrations/0006_auto_20200803_1222.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.0.8 on 2020-08-03 12:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('moderation', '0005_auto_20200317_0820'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='userrequest',
+            name='url',
+        ),
+        migrations.AlterField(
+            model_name='userrequest',
+            name='status',
+            field=models.CharField(choices=[('pending', 'Pending'), ('refused', 'Refused'), ('approved', 'Approved')], default='pending', max_length=40),
+        ),
+    ]
diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py
index 1d32a01bd976dfbe028966be5b7a254b5adadbb2..121c0f3ff41842c115b7ee44b7bf1c0520090c5a 100644
--- a/api/funkwhale_api/music/models.py
+++ b/api/funkwhale_api/music/models.py
@@ -20,7 +20,6 @@ from django.db.models.signals import post_save, pre_save
 from django.dispatch import receiver
 from django.urls import reverse
 from django.utils import timezone
-from versatileimagefield.fields import VersatileImageField
 
 from funkwhale_api import musicbrainz
 from funkwhale_api.common import fields
@@ -325,10 +324,6 @@ class Album(APIModelMixin):
     artist = models.ForeignKey(Artist, related_name="albums", on_delete=models.CASCADE)
     release_date = models.DateField(null=True, blank=True, db_index=True)
     release_group_id = models.UUIDField(null=True, blank=True)
-    # XXX: 1.0 clean this uneeded field in favor of attachment_cover
-    cover = VersatileImageField(
-        upload_to="albums/covers/%Y/%m/%d", null=True, blank=True
-    )
     attachment_cover = models.ForeignKey(
         "common.Attachment",
         null=True,
diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py
index c5e4336a6e310e51a642c9a1a7cc751e910cfad2..1dd17b2bffe4d32db71e30050478c608f2ba0b34 100644
--- a/api/funkwhale_api/music/serializers.py
+++ b/api/funkwhale_api/music/serializers.py
@@ -32,10 +32,7 @@ COVER_WRITE_FIELD = common_serializers.RelatedField(
 from funkwhale_api.audio import serializers as audio_serializers  # NOQA
 
 
-class CoverField(
-    common_serializers.NullToEmptDict, common_serializers.AttachmentSerializer
-):
-    # XXX: BACKWARD COMPATIBILITY
+class CoverField(common_serializers.AttachmentSerializer):
     pass
 
 
diff --git a/api/funkwhale_api/music/tasks.py b/api/funkwhale_api/music/tasks.py
index 2e633925b40166dd2715b378ddfb0623827ff719..7f47b402bc5968a8b9a8b6619d0014b93067c5c0 100644
--- a/api/funkwhale_api/music/tasks.py
+++ b/api/funkwhale_api/music/tasks.py
@@ -364,7 +364,7 @@ def federation_audio_track_to_metadata(payload, references):
             "mbid": str(payload["album"]["musicbrainzId"])
             if payload["album"].get("musicbrainzId")
             else None,
-            "cover_data": get_cover(payload["album"], "cover"),
+            "cover_data": get_cover(payload["album"], "image"),
             "release_date": payload["album"].get("released"),
             "tags": [t["name"] for t in payload["album"].get("tags", []) or []],
             "artists": [
@@ -896,8 +896,6 @@ UPDATE_CONFIG = {
 
 @transaction.atomic
 def update_track_metadata(audio_metadata, track):
-    # XXX: implement this to support updating metadata when an imported files
-    # is updated by an outside tool (e.g beets).
     serializer = metadata.TrackMetadataSerializer(data=audio_metadata)
     serializer.is_valid(raise_exception=True)
     new_data = serializer.validated_data
diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py
index 18c2b30aa8b4ff9c4066a24e9e672240beee53d9..0df0d46408ac53e6e56a8c4c444733cf70fa0519 100644
--- a/api/funkwhale_api/music/views.py
+++ b/api/funkwhale_api/music/views.py
@@ -797,20 +797,11 @@ class Search(views.APIView):
         return Response(results, status=200)
 
     def get_tracks(self, query):
-        search_fields = [
-            "mbid",
-            "title__unaccent",
-            "album__title__unaccent",
-            "artist__name__unaccent",
-        ]
-        if settings.USE_FULL_TEXT_SEARCH:
-            query_obj = utils.get_fts_query(
-                query,
-                fts_fields=["body_text", "album__body_text", "artist__body_text"],
-                model=models.Track,
-            )
-        else:
-            query_obj = utils.get_query(query, search_fields)
+        query_obj = utils.get_fts_query(
+            query,
+            fts_fields=["body_text", "album__body_text", "artist__body_text"],
+            model=models.Track,
+        )
         qs = (
             models.Track.objects.all()
             .filter(query_obj)
@@ -828,13 +819,9 @@ class Search(views.APIView):
         return common_utils.order_for_search(qs, "title")[: self.max_results]
 
     def get_albums(self, query):
-        search_fields = ["mbid", "title__unaccent", "artist__name__unaccent"]
-        if settings.USE_FULL_TEXT_SEARCH:
-            query_obj = utils.get_fts_query(
-                query, fts_fields=["body_text", "artist__body_text"], model=models.Album
-            )
-        else:
-            query_obj = utils.get_query(query, search_fields)
+        query_obj = utils.get_fts_query(
+            query, fts_fields=["body_text", "artist__body_text"], model=models.Album
+        )
         qs = (
             models.Album.objects.all()
             .filter(query_obj)
@@ -844,11 +831,7 @@ class Search(views.APIView):
         return common_utils.order_for_search(qs, "title")[: self.max_results]
 
     def get_artists(self, query):
-        search_fields = ["mbid", "name__unaccent"]
-        if settings.USE_FULL_TEXT_SEARCH:
-            query_obj = utils.get_fts_query(query, model=models.Artist)
-        else:
-            query_obj = utils.get_query(query, search_fields)
+        query_obj = utils.get_fts_query(query, model=models.Artist)
         qs = (
             models.Artist.objects.all()
             .filter(query_obj)
diff --git a/api/funkwhale_api/playlists/dynamic_preferences_registry.py b/api/funkwhale_api/playlists/dynamic_preferences_registry.py
index 5a2043452bc734841c85e7dde2c7f31ba0c20cab..ee1a33dea96ee1319e15d7a22e03d28ffc6dc23f 100644
--- a/api/funkwhale_api/playlists/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/playlists/dynamic_preferences_registry.py
@@ -1,16 +1,14 @@
 from dynamic_preferences import types
 from dynamic_preferences.registries import global_preferences_registry
 
-from funkwhale_api.common import preferences
-
 playlists = types.Section("playlists")
 
 
 @global_preferences_registry.register
-class MaxTracks(preferences.DefaultFromSettingMixin, types.IntegerPreference):
+class MaxTracks(types.IntegerPreference):
     show_in_api = True
     section = playlists
     name = "max_tracks"
+    default = 250
     verbose_name = "Max tracks per playlist"
-    setting = "PLAYLISTS_MAX_TRACKS"
     field_kwargs = {"required": False}
diff --git a/api/funkwhale_api/playlists/filters.py b/api/funkwhale_api/playlists/filters.py
index e12813b38d17cbf4c46080ae111f619149f68916..5270eee802cdbc16ce818a69d392866c3742ccba 100644
--- a/api/funkwhale_api/playlists/filters.py
+++ b/api/funkwhale_api/playlists/filters.py
@@ -31,7 +31,6 @@ class PlaylistFilter(filters.FilterSet):
     class Meta:
         model = models.Playlist
         fields = {
-            "user": ["exact"],
             "name": ["exact", "icontains"],
         }
 
diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py
index a20dbc9373fbbe5c27bab988a70cd5eb40b34819..b227a545d18260197654cf7572429535d502feca 100644
--- a/api/funkwhale_api/playlists/models.py
+++ b/api/funkwhale_api/playlists/models.py
@@ -227,7 +227,6 @@ class PlaylistTrack(models.Model):
 
     class Meta:
         ordering = ("-playlist", "index")
-        unique_together = ("playlist", "index")
 
     def delete(self, *args, **kwargs):
         playlist = self.playlist
diff --git a/api/funkwhale_api/radios/migrations/0005_auto_20200803_1222.py b/api/funkwhale_api/radios/migrations/0005_auto_20200803_1222.py
new file mode 100644
index 0000000000000000000000000000000000000000..8e4cd6770db266edadd089c93cf1776a6d0bc4f3
--- /dev/null
+++ b/api/funkwhale_api/radios/migrations/0005_auto_20200803_1222.py
@@ -0,0 +1,20 @@
+# Generated by Django 3.0.8 on 2020-08-03 12:22
+
+import django.contrib.postgres.fields.jsonb
+import django.core.serializers.json
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('radios', '0004_auto_20180107_1813'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='radio',
+            name='config',
+            field=django.contrib.postgres.fields.jsonb.JSONField(encoder=django.core.serializers.json.DjangoJSONEncoder),
+        ),
+    ]
diff --git a/api/funkwhale_api/tags/migrations/0002_auto_20200803_1222.py b/api/funkwhale_api/tags/migrations/0002_auto_20200803_1222.py
new file mode 100644
index 0000000000000000000000000000000000000000..382f24b4c7ca53eeb97c1433fe0c8d34f98f3b21
--- /dev/null
+++ b/api/funkwhale_api/tags/migrations/0002_auto_20200803_1222.py
@@ -0,0 +1,25 @@
+# Generated by Django 3.0.8 on 2020-08-03 12:22
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('tags', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='taggeditem',
+            name='content_type',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='contenttypes.ContentType', verbose_name='Content type'),
+        ),
+        migrations.AlterField(
+            model_name='taggeditem',
+            name='tag',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tagged_items', to='tags.Tag'),
+        ),
+    ]
diff --git a/api/tests/channels/test_auth.py b/api/tests/channels/test_auth.py
deleted file mode 100644
index 505bef1c0761cd972f40f7b4cf09e14cd1fcb627..0000000000000000000000000000000000000000
--- a/api/tests/channels/test_auth.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import pytest
-from rest_framework_jwt.settings import api_settings
-
-from funkwhale_api.common.auth import TokenAuthMiddleware
-
-jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
-jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
-
-
-@pytest.mark.parametrize("query_string", [b"token=wrong", b""])
-def test_header_anonymous(query_string, factories):
-    def callback(scope):
-        assert scope["user"].is_anonymous
-
-    scope = {"query_string": query_string}
-    consumer = TokenAuthMiddleware(callback)
-    consumer(scope)
-
-
-def test_header_correct_token(factories):
-    user = factories["users.User"]()
-    payload = jwt_payload_handler(user)
-    token = jwt_encode_handler(payload)
-
-    def callback(scope):
-        assert scope["user"] == user
-
-    scope = {"query_string": "token={}".format(token).encode("utf-8")}
-    consumer = TokenAuthMiddleware(callback)
-    consumer(scope)
diff --git a/api/tests/common/test_routers.py b/api/tests/common/test_routers.py
index 3bd5c4e47f5f823ef75e5d07fd9ce9514d67ab4f..5d1710f09f276aaf19e798fdff39bddd22d781d6 100644
--- a/api/tests/common/test_routers.py
+++ b/api/tests/common/test_routers.py
@@ -17,7 +17,7 @@ from django import urls
         "/api/v1/auth/registration/account-confirm-email/key",
         "/api/v1/history/listenings",
         "/api/v1/radios/sessions",
-        "/api/v1/users/users/me",
+        "/api/v1/users/me",
         "/api/v1/federation/follows/library",
         "/api/v1/manage/accounts",
         "/api/v1/oauth/apps",
diff --git a/api/tests/common/test_serializers.py b/api/tests/common/test_serializers.py
index 8fdb21edbaa98e556a84fcbe2bd67aecd176d5f9..1d23efb66140d01231a26745c6df4b84f617574b 100644
--- a/api/tests/common/test_serializers.py
+++ b/api/tests/common/test_serializers.py
@@ -201,15 +201,6 @@ def test_attachment_serializer_existing_file(factories, to_api_date):
                 attachment.file.crop["200x200"].url
             ),
         },
-        # XXX: BACKWARD COMPATIBILITY
-        "original": federation_utils.full_url(attachment.file.url),
-        "medium_square_crop": federation_utils.full_url(
-            attachment.file.crop["200x200"].url
-        ),
-        "small_square_crop": federation_utils.full_url(
-            attachment.file.crop["200x200"].url
-        ),
-        "square_crop": federation_utils.full_url(attachment.file.crop["200x200"].url),
     }
 
     serializer = serializers.AttachmentSerializer(attachment)
@@ -237,17 +228,6 @@ def test_attachment_serializer_remote_file(factories, to_api_date):
                 proxy_url + "?next=medium_square_crop"
             ),
         },
-        # XXX: BACKWARD COMPATIBILITY
-        "original": federation_utils.full_url(proxy_url + "?next=original"),
-        "medium_square_crop": federation_utils.full_url(
-            proxy_url + "?next=medium_square_crop"
-        ),
-        "square_crop": federation_utils.full_url(
-            proxy_url + "?next=medium_square_crop"
-        ),
-        "small_square_crop": federation_utils.full_url(
-            proxy_url + "?next=medium_square_crop"
-        ),
     }
 
     serializer = serializers.AttachmentSerializer(attachment)
diff --git a/api/tests/favorites/test_favorites.py b/api/tests/favorites/test_favorites.py
index 48d1857c62540fb1cef2a892c1386013085a7544..06d4caa61ded48aa46eb6c0da398dac54e9f2c55 100644
--- a/api/tests/favorites/test_favorites.py
+++ b/api/tests/favorites/test_favorites.py
@@ -20,10 +20,11 @@ def test_user_can_get_his_favorites(
     api_request, factories, logged_in_api_client, client
 ):
     request = api_request.get("/")
+    logged_in_api_client.user.create_actor()
     favorite = factories["favorites.TrackFavorite"](user=logged_in_api_client.user)
     factories["favorites.TrackFavorite"]()
     url = reverse("api:v1:favorites:tracks-list")
-    response = logged_in_api_client.get(url, {"user": logged_in_api_client.user.pk})
+    response = logged_in_api_client.get(url, {"scope": "me"})
     expected = [
         serializers.UserTrackFavoriteSerializer(
             favorite, context={"request": request}
diff --git a/api/tests/federation/test_serializers.py b/api/tests/federation/test_serializers.py
index addf74b4a65132972eb9717deed66f40107035c4..6617ba07d62fe0f0913a0503023ee85c8a414a87 100644
--- a/api/tests/federation/test_serializers.py
+++ b/api/tests/federation/test_serializers.py
@@ -388,7 +388,6 @@ def test_paginated_collection_serializer(factories):
         "@context": jsonld.get_default_context(),
         "type": "Collection",
         "id": conf["id"],
-        "actor": actor.fid,
         "attributedTo": actor.fid,
         "totalItems": len(uploads),
         "current": conf["id"] + "?page=1",
@@ -486,7 +485,6 @@ def test_collection_page_serializer(factories):
         "@context": jsonld.get_default_context(),
         "type": "CollectionPage",
         "id": conf["id"] + "?page=2",
-        "actor": actor.fid,
         "attributedTo": actor.fid,
         "totalItems": len(uploads),
         "partOf": conf["id"],
@@ -521,7 +519,6 @@ def test_music_library_serializer_to_ap(factories):
         "id": library.fid,
         "name": library.name,
         "summary": library.description,
-        "actor": library.actor.fid,
         "attributedTo": library.actor.fid,
         "totalItems": 0,
         "current": library.fid + "?page=1",
@@ -764,11 +761,6 @@ def test_activity_pub_album_serializer_to_ap(factories):
         "type": "Album",
         "id": album.fid,
         "name": album.title,
-        "cover": {
-            "type": "Link",
-            "mediaType": "image/jpeg",
-            "href": utils.full_url(album.attachment_cover.file.url),
-        },
         "image": {
             "type": "Image",
             "mediaType": "image/jpeg",
@@ -815,7 +807,7 @@ def test_activity_pub_album_serializer_from_ap_create(factories, faker, now):
         "type": "Album",
         "id": "https://album.example",
         "name": faker.sentence(),
-        "cover": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()},
+        "image": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()},
         "musicbrainzId": faker.uuid4(),
         "published": now.isoformat(),
         "released": released.isoformat(),
@@ -839,8 +831,8 @@ def test_activity_pub_album_serializer_from_ap_create(factories, faker, now):
     assert str(album.mbid) == payload["musicbrainzId"]
     assert album.release_date == released
     assert album.artist == artist
-    assert album.attachment_cover.url == payload["cover"]["href"]
-    assert album.attachment_cover.mimetype == payload["cover"]["mediaType"]
+    assert album.attachment_cover.url == payload["image"]["href"]
+    assert album.attachment_cover.mimetype == payload["image"]["mediaType"]
     assert sorted(album.tagged_items.values_list("tag__name", flat=True)) == [
         "Punk",
         "Rock",
@@ -879,7 +871,7 @@ def test_activity_pub_album_serializer_from_ap_update(factories, faker):
         "type": "Album",
         "id": album.fid,
         "name": faker.sentence(),
-        "cover": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()},
+        "image": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()},
         "musicbrainzId": faker.uuid4(),
         "published": album.creation_date.isoformat(),
         "released": released.isoformat(),
@@ -904,8 +896,8 @@ def test_activity_pub_album_serializer_from_ap_update(factories, faker):
     assert album.title == payload["name"]
     assert str(album.mbid) == payload["musicbrainzId"]
     assert album.release_date == released
-    assert album.attachment_cover.url == payload["cover"]["href"]
-    assert album.attachment_cover.mimetype == payload["cover"]["mediaType"]
+    assert album.attachment_cover.url == payload["image"]["href"]
+    assert album.attachment_cover.mimetype == payload["image"]["mediaType"]
     assert sorted(album.tagged_items.values_list("tag__name", flat=True)) == [
         "Punk",
         "Rock",
@@ -996,7 +988,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
             "content": "Album summary",
             "mediaType": "text/markdown",
             "attributedTo": album_attributed_to.fid,
-            "cover": {
+            "image": {
                 "type": "Link",
                 "href": "https://cover.image/test.png",
                 "mediaType": "image/png",
@@ -1066,8 +1058,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
     assert track.attachment_cover.mimetype == data["image"]["mediaType"]
 
     assert album.from_activity == activity
-    assert album.attachment_cover.url == data["album"]["cover"]["href"]
-    assert album.attachment_cover.mimetype == data["album"]["cover"]["mediaType"]
+    assert album.attachment_cover.url == data["album"]["image"]["href"]
+    assert album.attachment_cover.mimetype == data["album"]["image"]["mediaType"]
     assert album.title == data["album"]["name"]
     assert album.fid == data["album"]["id"]
     assert str(album.mbid) == data["album"]["musicbrainzId"]
@@ -1196,7 +1188,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock):
                 "musicbrainzId": str(uuid.uuid4()),
                 "published": published.isoformat(),
                 "released": released.isoformat(),
-                "cover": {
+                "image": {
                     "type": "Link",
                     "href": "https://cover.image/test.png",
                     "mediaType": "image/png",
@@ -1222,7 +1214,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock):
             ],
         },
     }
-    r_mock.get(data["track"]["album"]["cover"]["href"], body=io.BytesIO(b"coucou"))
+    r_mock.get(data["track"]["album"]["image"]["href"], body=io.BytesIO(b"coucou"))
 
     serializer = serializers.UploadSerializer(data=data, context={"activity": activity})
     assert serializer.is_valid(raise_exception=True)
@@ -1266,7 +1258,7 @@ def test_activity_pub_upload_serializer_from_ap_update(factories, mocker, now, r
         "library": library.fid,
         "track": serializers.TrackSerializer(upload.track).data,
     }
-    r_mock.get(data["track"]["album"]["cover"]["href"], body=io.BytesIO(b"coucou"))
+    r_mock.get(data["track"]["album"]["image"]["url"], body=io.BytesIO(b"coucou"))
 
     serializer = serializers.UploadSerializer(upload, data=data)
     assert serializer.is_valid(raise_exception=True)
@@ -1628,7 +1620,6 @@ def test_channel_actor_outbox_serializer(factories):
         "@context": jsonld.get_default_context(),
         "type": "OrderedCollection",
         "id": channel.actor.outbox_url,
-        "actor": channel.actor.fid,
         "attributedTo": channel.actor.fid,
         "totalItems": len(uploads),
         "first": channel.actor.outbox_url + "?page=1",
diff --git a/api/tests/federation/test_views.py b/api/tests/federation/test_views.py
index f6528bab2a23152836f01d05db47839e6da5d388..8b3ec872511c845a3c2eb0e9872fb8cfc73a8783 100644
--- a/api/tests/federation/test_views.py
+++ b/api/tests/federation/test_views.py
@@ -384,11 +384,6 @@ def test_music_upload_detail_private_approved_follow(
         ("text/html,application/xhtml+xml", True, True),
         ("text/html,application/json", True, True),
         ("", True, False),
-        (
-            "*/*",
-            True,
-            False,
-        ),  # XXX: compat with older versions of Funkwhale that miss the Accept header
         (None, True, False),
         ("application/json", True, False),
         ("application/activity+json", True, False),
diff --git a/api/tests/music/test_serializers.py b/api/tests/music/test_serializers.py
index 1fb5ac120d0ce55dde5a9c526e4cc33dd97f0a69..802f7169c2b907bf55ddcbb1c5c026391eba4eaa 100644
--- a/api/tests/music/test_serializers.py
+++ b/api/tests/music/test_serializers.py
@@ -196,15 +196,6 @@ def test_album_serializer(factories, to_api_date):
     assert serializer.data == expected
 
 
-def test_album_serializer_empty_cover(factories, to_api_date):
-    # XXX: BACKWARD COMPATIBILITY
-    album = factories["music.Album"](attachment_cover=None)
-
-    serializer = serializers.AlbumSerializer(album)
-
-    assert serializer.data["cover"] == {}
-
-
 def test_track_serializer(factories, to_api_date):
     actor = factories["federation.Actor"]()
     upload = factories["music.Upload"](
diff --git a/api/tests/music/test_tasks.py b/api/tests/music/test_tasks.py
index edb937d81eb28c07d5d0f740651881983418aaa8..573f04f1f0de0b22be0584a63fdeee6426271a3c 100644
--- a/api/tests/music/test_tasks.py
+++ b/api/tests/music/test_tasks.py
@@ -660,7 +660,7 @@ def test_federation_audio_track_to_metadata(now, mocker):
                     },
                 }
             ],
-            "cover": {
+            "image": {
                 "type": "Link",
                 "href": "http://cover.test",
                 "mediaType": "image/png",
@@ -713,8 +713,8 @@ def test_federation_audio_track_to_metadata(now, mocker):
             "tags": ["AlbumTag"],
             "description": {"content_type": "text/plain", "text": "album desc"},
             "cover_data": {
-                "mimetype": serializer.validated_data["album"]["cover"]["mediaType"],
-                "url": serializer.validated_data["album"]["cover"]["href"],
+                "mimetype": serializer.validated_data["album"]["image"]["mediaType"],
+                "url": serializer.validated_data["album"]["image"]["href"],
             },
             "artists": [
                 {
diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py
index 7e96f46c049ba72a3201fca72c8062320f52b076..81988a6b38d9b82d1f06172be32620e980bbba89 100644
--- a/api/tests/music/test_views.py
+++ b/api/tests/music/test_views.py
@@ -1307,9 +1307,7 @@ def test_get_upload_audio_metadata(logged_in_api_client, factories):
     assert response.data == serializer.validated_data
 
 
-@pytest.mark.parametrize("use_fts", [True, False])
-def test_search_get(use_fts, settings, logged_in_api_client, factories):
-    settings.USE_FULL_TEXT_SEARCH = use_fts
+def test_search_get(logged_in_api_client, factories):
     artist = factories["music.Artist"](name="Foo Fighters")
     album = factories["music.Album"](title="Foo Bar")
     track = factories["music.Track"](title="Foo Baz")
@@ -1332,8 +1330,7 @@ def test_search_get(use_fts, settings, logged_in_api_client, factories):
     assert response.data == expected
 
 
-def test_search_get_fts_advanced(settings, logged_in_api_client, factories):
-    settings.USE_FULL_TEXT_SEARCH = True
+def test_search_get_fts_advanced(logged_in_api_client, factories):
     artist1 = factories["music.Artist"](name="Foo Bighters")
     artist2 = factories["music.Artist"](name="Bar Fighter")
     factories["music.Artist"]()
@@ -1353,8 +1350,7 @@ def test_search_get_fts_advanced(settings, logged_in_api_client, factories):
     assert response.data == expected
 
 
-def test_search_get_fts_stop_words(settings, logged_in_api_client, factories):
-    settings.USE_FULL_TEXT_SEARCH = True
+def test_search_get_fts_stop_words(logged_in_api_client, factories):
     artist = factories["music.Artist"](name="she")
     factories["music.Artist"](name="something else")
 
diff --git a/docs/api/definitions.yml b/docs/api/definitions.yml
index 249eb7a754cfb81d97af0ab12b7bcca57a9d1aff..71b9893c9f6c10c425eb46cb15506e06dffc126a 100644
--- a/docs/api/definitions.yml
+++ b/docs/api/definitions.yml
@@ -720,7 +720,7 @@ User:
       type: "string"
       example: "Alice Kingsley"
     avatar:
-      $ref: "#/Avatar"
+      $ref: "#/Attachment"
 
 Me:
   type: "object"
@@ -767,30 +767,8 @@ Me:
                 via request headers isn't possible.
 
                 The token expires after 3 days by default.
-Avatar:
-  type: "object"
-  properties:
-    original:
-      type: "string"
-      format: "uri"
-      description: "Original image URL"
-      example: "http://yourinstance/media/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996.jpg"
-    square_crop:
-      type: "string"
-      format: "uri"
-      description: "400x400 thumbnail URL"
-      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-400x400-70.jpg"
-    small_square_crop:
-      type: "string"
-      format: "uri"
-      description: "50x50 thumbnail URL"
-      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-50x50-70.jpg"
-    medium_square_crop:
-      type: "string"
-      format: "uri"
-      description: "200x200 thumbnail URL"
-      example: "http://yourinstance/media/__sized__/users/avatars/92/49/60/b3c-4736-43b3-bb5c-ed7a99ac6996-crop-c0-5__0-5-200x200-70.jpg"
-QuotaStatus:
+
+                QuotaStatus:
   type: "object"
   properties:
     max:
diff --git a/docs/swagger.yml b/docs/swagger.yml
index 0c3a0b1d98598d9929b0c4a12133ae2506a13a1a..4da3a52b47166ea98a0f9ccda9bca779eba67a90 100644
--- a/docs/swagger.yml
+++ b/docs/swagger.yml
@@ -296,7 +296,7 @@ paths:
       responses:
         200:
           $ref: "#/responses/200"
-  /api/v1/users/users/me/:
+  /api/v1/users/me/:
     get:
       summary: Retrive profile information
       description: |
diff --git a/front/src/EmbedFrame.vue b/front/src/EmbedFrame.vue
index 67dc02303618afd72665918f31cd859cea0f5598..93d04d5e7ba05ea7f3b4e2c2623e23c9725d71ec 100644
--- a/front/src/EmbedFrame.vue
+++ b/front/src/EmbedFrame.vue
@@ -337,7 +337,7 @@ export default {
     },
     getCover(albumCover) {
       if (albumCover) {
-        return albumCover.medium_square_crop
+        return albumCover.urls.medium_square_crop
       }
     },
     getSources (uploads) {
diff --git a/front/src/components/Queue.vue b/front/src/components/Queue.vue
index 4df47954e83752f1580bea300570e3212ca13797..8966c889c6f982243f10512d18dd5e186dfc3b9a 100644
--- a/front/src/components/Queue.vue
+++ b/front/src/components/Queue.vue
@@ -6,8 +6,8 @@
           <div class="ui six wide column current-track">
             <div class="ui basic segment" id="player">
               <template v-if="currentTrack">
-                <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)">
-                <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)">
+                <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)">
+                <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)">
                 <img class="ui image" alt="" v-else src="../assets/audio/default-cover.png">
                 <h1 class="ui header">
                   <div class="content ellipsis">
@@ -159,8 +159,8 @@
                     <i class="grip lines icon"></i>
                   </td>
                   <td class="image-cell" @click="$store.dispatch('queue/currentIndex', index)">
-                    <img class="ui mini image" alt="" v-if="track.cover && track.cover.original" :src="$store.getters['instance/absoluteUrl'](track.cover.medium_square_crop)">
-                    <img class="ui mini image" alt="" v-else-if="track.album && track.album.cover && track.album.cover.original" :src="$store.getters['instance/absoluteUrl'](track.album.cover.medium_square_crop)">
+                    <img class="ui mini image" alt="" v-if="track.cover && track.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](track.cover.urls.medium_square_crop)">
+                    <img class="ui mini image" alt="" v-else-if="track.album && track.album.cover && track.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)">
                     <img class="ui mini image" alt="" v-else src="../assets/audio/default-cover.png">
                   </td>
                   <td colspan="3" @click="$store.dispatch('queue/currentIndex', index)">
diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue
index e41035687223ee90e4e5027448e604ec3fecab9c..5b176d6c73bf32b90625c8420169a5eacdfd4e7d 100644
--- a/front/src/components/Sidebar.vue
+++ b/front/src/components/Sidebar.vue
@@ -78,7 +78,7 @@
         </router-link>
         <div class="item">
           <div class="ui user-dropdown dropdown" >
-            <img class="ui avatar image" alt="" v-if="$store.state.auth.profile.avatar && $store.state.auth.profile.avatar.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.square_crop)" />
+            <img class="ui avatar image" alt="" v-if="$store.state.auth.profile.avatar && $store.state.auth.profile.avatar.urls.square_crop" :src="$store.getters['instance/absoluteUrl']($store.state.auth.profile.avatar.urls.square_crop)" />
             <actor-avatar v-else :actor="{preferred_username: $store.state.auth.username, full_username: $store.state.auth.username}" />
             <div class="menu">
               <router-link class="item" :to="{name: 'profile.overview', params: {username: $store.state.auth.username}}"><translate translate-context="*/*/*/Noun">Profile</translate></router-link>
diff --git a/front/src/components/audio/ArtistLabel.vue b/front/src/components/audio/ArtistLabel.vue
index a5e98c2577bfda60ca900a83b84768ef2995ccaf..659d0884f689b4abf4448c3cb2faa14cd38820ec 100644
--- a/front/src/components/audio/ArtistLabel.vue
+++ b/front/src/components/audio/ArtistLabel.vue
@@ -1,6 +1,6 @@
 <template>
   <router-link class="artist-label ui image label" :to="route">
-    <img :class="[{circular: artist.content_category != 'podcast'}]" alt="" v-if="artist.cover && artist.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](artist.cover.small_square_crop)" />
+    <img alt="" :class="[{circular: artist.content_category != 'podcast'}]" v-if="artist.cover && artist.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](artist.cover.urls.medium_square_crop)" />
     <i :class="[artist.content_category != 'podcast' ? 'circular' : 'bordered', 'inverted violet users icon']" v-else />
     {{ artist.name }}
   </router-link>
diff --git a/front/src/components/audio/ChannelCard.vue b/front/src/components/audio/ChannelCard.vue
index d51123068624171092f2ff3646e35c9656b603a6..78cc14c443cf8d696702ee96adb45af94f8578c6 100644
--- a/front/src/components/audio/ChannelCard.vue
+++ b/front/src/components/audio/ChannelCard.vue
@@ -60,7 +60,7 @@ export default {
   computed: {
     imageUrl () {
       if (this.object.artist.cover) {
-        return this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.medium_square_crop)
+        return this.$store.getters['instance/absoluteUrl'](this.object.artist.cover.urls.medium_square_crop)
       }
     },
     urlId () {
diff --git a/front/src/components/audio/ChannelEntryCard.vue b/front/src/components/audio/ChannelEntryCard.vue
index 39c8eb62e3987f5bf0fd54cb90cdbc16c357f74d..5430b81f7d5d20e231f4e98b9b609ef65bdb9f0f 100644
--- a/front/src/components/audio/ChannelEntryCard.vue
+++ b/front/src/components/audio/ChannelEntryCard.vue
@@ -7,8 +7,8 @@
       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})"
       alt=""
       class="channel-image image"
-      v-if="cover && cover.original"
-      v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)">
+      v-if="cover && cover.urls.original"
+      v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)">
     <span
       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})"
       class="channel-image image"
@@ -17,8 +17,8 @@
       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})"
       alt=""
       class="channel-image image"
-      v-else-if="entry.album && entry.album.cover && entry.album.cover.original"
-      v-lazy="$store.getters['instance/absoluteUrl'](entry.album.cover.square_crop)">
+      v-else-if="entry.album && entry.album.cover && entry.album.cover.urls.original"
+      v-lazy="$store.getters['instance/absoluteUrl'](entry.album.cover.urls.square_crop)">
     <img
       @click="$router.push({name: 'library.tracks.detail', params: {id: entry.id}})"
       alt=""
diff --git a/front/src/components/audio/ChannelSerieCard.vue b/front/src/components/audio/ChannelSerieCard.vue
index bc6fccad643c4a7feab431e371b7918c19a5d2eb..55466e202f9cf825e7e116ca4e5a697279a2a876 100644
--- a/front/src/components/audio/ChannelSerieCard.vue
+++ b/front/src/components/audio/ChannelSerieCard.vue
@@ -1,10 +1,10 @@
 <template>
   <div class="channel-serie-card">
     <div class="two-images">
-      <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-if="cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)">
-      <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png">
-      <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-if="cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)">
-      <img @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png">
+      <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-if="cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)">
+      <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-else src="../../assets/audio/default-cover.png">
+      <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-if="cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)">
+      <img alt="" @click="$router.push({name: 'library.albums.detail', params: {id: serie.id}})" class="channel-image" v-else src="../../assets/audio/default-cover.png">
     </div>
     <div class="content ellipsis">
       <strong>
diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue
index d6e5e95da94672a059da94918098f20b750b2e94..b9f0f660427d0033121ac3acfc0f1c30fe7fdedd 100644
--- a/front/src/components/audio/Player.vue
+++ b/front/src/components/audio/Player.vue
@@ -10,9 +10,9 @@
 
         <div class="controls track-controls queue-not-focused desktop-and-up">
           <div class="ui tiny image" @click.stop.prevent="$router.push({name: 'library.tracks.detail', params: {id: currentTrack.id }})">
-            <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)">
-            <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)">
-            <img v-else src="../../assets/audio/default-cover.png" alt="">
+            <img alt="" ref="cover" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)">
+            <img alt="" ref="cover" v-else-if="currentTrack.album && currentTrack.album.cover.urls && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)">
+            <img alt="" v-else src="../../assets/audio/default-cover.png">
           </div>
           <div @click.stop.prevent="" class="middle aligned content ellipsis">
             <strong>
@@ -30,9 +30,9 @@
         </div>
         <div class="controls track-controls queue-not-focused tablet-and-below">
           <div class="ui tiny image">
-            <img ref="cover" alt="" v-if="currentTrack.cover && currentTrack.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.medium_square_crop)">
-            <img ref="cover" alt="" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.medium_square_crop)">
-            <img v-else src="../../assets/audio/default-cover.png" alt="">
+            <img alt="" ref="cover" v-if="currentTrack.cover && currentTrack.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.cover.urls.medium_square_crop)">
+            <img alt="" ref="cover" v-else-if="currentTrack.album && currentTrack.album.cover && currentTrack.album.cover.urls.original" :src="$store.getters['instance/absoluteUrl'](currentTrack.album.cover.urls.medium_square_crop)">
+            <img alt="" v-else src="../../assets/audio/default-cover.png">
           </div>
           <div class="middle aligned content ellipsis">
             <strong>
@@ -738,12 +738,12 @@ export default {
           if (this.currentTrack.album) {
             metadata.album = this.currentTrack.album.title
             metadata.artwork = [
-              { src: this.currentTrack.album.cover.original, sizes: '96x96',   type: 'image/png' },
-              { src: this.currentTrack.album.cover.original, sizes: '128x128', type: 'image/png' },
-              { src: this.currentTrack.album.cover.original, sizes: '192x192', type: 'image/png' },
-              { src: this.currentTrack.album.cover.original, sizes: '256x256', type: 'image/png' },
-              { src: this.currentTrack.album.cover.original, sizes: '384x384', type: 'image/png' },
-              { src: this.currentTrack.album.cover.original, sizes: '512x512', type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '96x96',   type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '128x128', type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '192x192', type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '256x256', type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '384x384', type: 'image/png' },
+              { src: this.currentTrack.album.cover.urls.original, sizes: '512x512', type: 'image/png' },
             ]
           }
           navigator.mediaSession.metadata = new MediaMetadata(metadata);
diff --git a/front/src/components/audio/album/Card.vue b/front/src/components/audio/album/Card.vue
index 9655f75aaadd305c2080ad38dc207d5dfb58ac27..aafa2e4a439b31a2cc586a22fb0ac10287e2c784 100644
--- a/front/src/components/audio/album/Card.vue
+++ b/front/src/components/audio/album/Card.vue
@@ -2,7 +2,7 @@
   <div class="card app-card component-album-card">
     <div
       @click="$router.push({name: 'library.albums.detail', params: {id: album.id}})"
-      :class="['ui', 'head-image', 'image', {'default-cover': !album.cover.original}]" v-lazy:background-image="imageUrl">
+      :class="['ui', 'head-image', 'image', {'default-cover': !album.cover || !album.cover.urls.original}]" v-lazy:background-image="imageUrl">
       <play-button :icon-only="true" :is-playable="album.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :album="album"></play-button>
     </div>
     <div class="content">
@@ -38,8 +38,8 @@ export default {
   },
   computed: {
     imageUrl () {
-      if (this.album.cover.original) {
-        return this.$store.getters['instance/absoluteUrl'](this.album.cover.medium_square_crop)
+      if (this.album.cover && this.album.cover.urls.original) {
+        return this.$store.getters['instance/absoluteUrl'](this.album.cover.urls.medium_square_crop)
       }
     }
   }
diff --git a/front/src/components/audio/artist/Card.vue b/front/src/components/audio/artist/Card.vue
index 813a1183ee140d6e8ce7f78163654ed50031de7d..46533fed9345d5b4f7d2c5cb0e3ded8c4808937d 100644
--- a/front/src/components/audio/artist/Card.vue
+++ b/front/src/components/audio/artist/Card.vue
@@ -2,7 +2,7 @@
   <div class="app-card card">
     <div
       @click="$router.push({name: 'library.artists.detail', params: {id: artist.id}})"
-      :class="['ui', 'head-image', 'circular', 'image', {'default-cover': !cover.original}]" v-lazy:background-image="imageUrl">
+      :class="['ui', 'head-image', 'circular', 'image', {'default-cover': !cover || !cover.urls.original}]" v-lazy:background-image="imageUrl">
       <play-button :icon-only="true" :is-playable="artist.is_playable" :button-classes="['ui', 'circular', 'large', 'vibrant', 'icon', 'button']" :artist="artist"></play-button>
     </div>
     <div class="content">
@@ -40,19 +40,19 @@ export default {
   computed: {
     imageUrl () {
       let cover = this.cover
-      if (cover.original) {
-        return this.$store.getters['instance/absoluteUrl'](cover.medium_square_crop)
+      if (cover && cover.urls.original) {
+        return this.$store.getters['instance/absoluteUrl'](cover.urls.medium_square_crop)
       }
     },
     cover () {
-      if (this.artist.cover && this.artist.cover.original) {
+      if (this.artist.cover && this.artist.cover.urls.original) {
         return this.artist.cover
       }
       return this.artist.albums.map((a) => {
         return a.cover
       }).filter((c) => {
-        return c && c.original
-      })[0] || {}
+        return c && c.urls.original
+      })[0]
     },
   }
 }
diff --git a/front/src/components/audio/track/Row.vue b/front/src/components/audio/track/Row.vue
index 94463a22bd95975f58104c26afcb7b946677508d..66363ea5fa666632a83ea0e060e291e25a0d4f3d 100644
--- a/front/src/components/audio/track/Row.vue
+++ b/front/src/components/audio/track/Row.vue
@@ -4,8 +4,8 @@
       <play-button :class="['basic', {vibrant: currentTrack && isPlaying && track.id === currentTrack.id}, 'icon']" :discrete="true" :is-playable="playable" :track="track"></play-button>
     </td>
     <td>
-      <img class="ui mini image" alt="" v-if="track.album && track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.small_square_crop)">
-      <img class="ui mini image" alt="" v-else src="../../../assets/audio/default-cover.png">
+      <img alt="" class="ui mini image" v-if="track.album && track.album.cover && track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](track.album.cover.urls.medium_square_crop)">
+      <img alt="" class="ui mini image" v-else src="../../../assets/audio/default-cover.png">
     </td>
     <td colspan="6">
       <router-link class="track" :to="{name: 'library.tracks.detail', params: {id: track.id }}">
diff --git a/front/src/components/audio/track/Widget.vue b/front/src/components/audio/track/Widget.vue
index 0afe4f512a5848c51f539468774e42f6c6b7d1c8..4092d054d55dccdd621f9aecc64bda47145b44bc 100644
--- a/front/src/components/audio/track/Widget.vue
+++ b/front/src/components/audio/track/Widget.vue
@@ -7,7 +7,7 @@
     <div v-if="count > 0" class="ui divided unstackable items">
       <div :class="['item', itemClasses]" v-for="object in objects" :key="object.id">
         <div class="ui tiny image">
-          <img alt="" v-if="object.track.album && object.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.medium_square_crop)">
+          <img alt="" v-if="object.track.album && object.track.album.cover" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)">
           <img alt="" v-else src="../../../assets/audio/default-cover.png">
           <play-button class="play-overlay" :icon-only="true" :button-classes="['ui', 'circular', 'tiny', 'vibrant', 'icon', 'button']" :track="object.track"></play-button>
         </div>
diff --git a/front/src/components/auth/Settings.vue b/front/src/components/auth/Settings.vue
index 41c60fc44cfe1bef0a72d55a082fa84147486a60..94f033dfe20c301d7bda035694a72e7a5452f582 100644
--- a/front/src/components/auth/Settings.vue
+++ b/front/src/components/auth/Settings.vue
@@ -416,12 +416,12 @@ export default {
       this.settings.errors = []
       let self = this
       let payload = this.settingsValues
-      let url = `users/users/${this.$store.state.auth.username}/`
+      let url = `users/${this.$store.state.auth.username}/`
       return axios.patch(url, payload).then(
         response => {
           logger.default.info("Updated settings successfully")
           self.settings.success = true
-          return axios.get("users/users/me/").then(response => {
+          return axios.get("users/me/").then(response => {
             self.$store.dispatch("auth/updateProfile", response.data)
           })
         },
@@ -487,7 +487,7 @@ export default {
       this.avatarErrors = []
       let self = this
       axios
-        .patch(`users/users/${this.$store.state.auth.username}/`, {avatar: uuid})
+        .patch(`users/${this.$store.state.auth.username}/`, {avatar: uuid})
         .then(
           response => {
             this.isLoadingAvatar = false
@@ -538,7 +538,7 @@ export default {
         confirm: true,
         password: this.password,
       }
-      axios.delete(`users/users/me/`, {data: payload})
+      axios.delete(`users/me/`, {data: payload})
         .then(
           response => {
             self.isDeletingAccount = false
diff --git a/front/src/components/auth/SubsonicTokenForm.vue b/front/src/components/auth/SubsonicTokenForm.vue
index 74622f1fa8c395db0e0e0547e01c77411c5fe28d..b724d31fbaf9d8278e8f130b0e3d5e0843fd092e 100644
--- a/front/src/components/auth/SubsonicTokenForm.vue
+++ b/front/src/components/auth/SubsonicTokenForm.vue
@@ -87,7 +87,7 @@ export default {
       this.errors = []
       this.isLoading = true
       let self = this
-      let url = `users/users/${this.$store.state.auth.username}/subsonic-token/`
+      let url = `users/${this.$store.state.auth.username}/subsonic-token/`
       return axios.get(url).then(response => {
         self.token = response.data['subsonic_api_token']
         self.isLoading = false
@@ -102,7 +102,7 @@ export default {
       this.errors = []
       this.isLoading = true
       let self = this
-      let url = `users/users/${this.$store.state.auth.username}/subsonic-token/`
+      let url = `users/${this.$store.state.auth.username}/subsonic-token/`
       return axios.post(url, {}).then(response => {
         self.showToken = true
         self.token = response.data['subsonic_api_token']
@@ -119,7 +119,7 @@ export default {
       this.errors = []
       this.isLoading = true
       let self = this
-      let url = `users/users/${this.$store.state.auth.username}/subsonic-token/`
+      let url = `users/${this.$store.state.auth.username}/subsonic-token/`
       return axios.delete(url).then(response => {
         self.isLoading = false
         self.token = null
diff --git a/front/src/components/channels/UploadForm.vue b/front/src/components/channels/UploadForm.vue
index f4b405b140b62f77649667b555161489fdd4594e..f40fe11791f88c676331d96b1158eeeb67882335 100644
--- a/front/src/components/channels/UploadForm.vue
+++ b/front/src/components/channels/UploadForm.vue
@@ -347,7 +347,7 @@ export default {
     },
     fetchQuota () {
       let self = this
-      axios.get('users/users/me/').then((response) => {
+      axios.get('users/me/').then((response) => {
         self.quotaStatus = response.data.quota_status
       })
     },
@@ -391,8 +391,8 @@ export default {
             value: c.uuid,
             selected: self.channel && self.channel.uuid === c.uuid,
           }
-          if (c.artist.cover && c.artist.cover.small_square_crop) {
-            let coverUrl = self.$store.getters['instance/absoluteUrl'](c.artist.cover.small_square_crop)
+          if (c.artist.cover && c.artist.cover.urls.medium_square_crop) {
+            let coverUrl = self.$store.getters['instance/absoluteUrl'](c.artist.cover.urls.medium_square_crop)
             d.image = coverUrl
             if (c.artist.content_category === 'podcast') {
               d.imageClass = 'ui image'
diff --git a/front/src/components/common/ActorAvatar.vue b/front/src/components/common/ActorAvatar.vue
index 441d10b7d5139148275f944781f51ec3a259f535..742271ab4baa65d712cb197ca4f9fd948e48275e 100644
--- a/front/src/components/common/ActorAvatar.vue
+++ b/front/src/components/common/ActorAvatar.vue
@@ -1,5 +1,5 @@
 <template>
-  <img alt="" v-if="actor.icon && actor.icon.original" :src="actor.icon.small_square_crop" class="ui avatar circular image" />
+  <img alt="" v-if="actor.icon && actor.icon.urls.original" :src="actor.icon.urls.medium_square_crop" class="ui avatar circular image" />
   <span v-else :style="defaultAvatarStyle" class="ui avatar circular label">{{ actor.preferred_username[0]}}</span>
 </template>
 
diff --git a/front/src/components/common/UserLink.vue b/front/src/components/common/UserLink.vue
index b2bf821c699a9b543a71c5460ee8ca0e12d01336..6a372e20b3afcf2efc984f7047cb30a1937adda4 100644
--- a/front/src/components/common/UserLink.vue
+++ b/front/src/components/common/UserLink.vue
@@ -4,8 +4,8 @@
       <img
         class="ui tiny circular avatar"
         alt=""
-        v-if="user.avatar && user.avatar.small_square_crop"
-        v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.small_square_crop)" />
+        v-if="user.avatar && user.avatar.urls.medium_square_crop"
+        v-lazy="$store.getters['instance/absoluteUrl'](user.avatar.urls.medium_square_crop)" />
       <span v-else :style="defaultAvatarStyle" class="ui circular label">{{ user.username[0]}}</span>
       &nbsp;
     </template>
diff --git a/front/src/components/library/AlbumBase.vue b/front/src/components/library/AlbumBase.vue
index 33e09896598a2ab9816a30c067d54b8c5ecca306..e50f5914930caabec02bd8ae177d008551413059 100644
--- a/front/src/components/library/AlbumBase.vue
+++ b/front/src/components/library/AlbumBase.vue
@@ -11,10 +11,10 @@
               <div class="ui two column grid" v-if="isSerie">
                 <div class="column">
                   <div class="large two-images">
-                    <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
-                    <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png">
-                    <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
-                    <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png">
+                    <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
+                    <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png">
+                    <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
+                    <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png">
                   </div>
                 </div>
                 <div class="ui column right aligned">
@@ -53,8 +53,8 @@
               </header>
             </div>
             <div v-else class="ui center aligned text padded basic segment">
-              <img class="channel-image" alt="" v-if="object.cover && object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
-              <img class="channel-image" alt="" v-else src="../../assets/audio/default-cover.png">
+              <img alt="" class="channel-image" v-if="object.cover && object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
+              <img alt="" class="channel-image" v-else src="../../assets/audio/default-cover.png">
               <div class="ui hidden divider"></div>
               <header>
                 <h2 class="ui header" :title="object.title">
diff --git a/front/src/components/library/ArtistBase.vue b/front/src/components/library/ArtistBase.vue
index 87769b4ff2df65f0c437ac108d5be9eef425de8d..22038a88845f73f871e09d8e38e20d671a59fb77 100644
--- a/front/src/components/library/ArtistBase.vue
+++ b/front/src/components/library/ArtistBase.vue
@@ -235,12 +235,12 @@ export default {
       )
     },
     cover() {
-      if (this.object.cover && this.object.cover.original) {
+      if (this.object.cover && this.object.cover.urls.original) {
         return this.object.cover
       }
       return this.object.albums
         .filter(album => {
-          return album.cover && album.cover.original
+          return album.cover && album.cover.urls.original
         })
         .map(album => {
           return album.cover
@@ -253,12 +253,12 @@ export default {
       })
     },
     headerStyle() {
-      if (!this.cover || !this.cover.original) {
+      if (!this.cover || !this.cover.urls.original) {
         return ""
       }
       return (
         "background-image: url(" +
-        this.$store.getters["instance/absoluteUrl"](this.cover.original) +
+        this.$store.getters["instance/absoluteUrl"](this.cover.urls.original) +
         ")"
       )
     },
diff --git a/front/src/components/library/FileUpload.vue b/front/src/components/library/FileUpload.vue
index 6d7ac605e1b7c231863ea373b290ece9a6e5d0e4..1782f0c188948be4cc14c8389af9d46ca3126c81 100644
--- a/front/src/components/library/FileUpload.vue
+++ b/front/src/components/library/FileUpload.vue
@@ -274,7 +274,7 @@ export default {
     fetchQuota () {
       let self = this
       self.isLoadingQuota = true
-      axios.get('users/users/me/').then((response) => {
+      axios.get('users/me/').then((response) => {
         self.quotaStatus = response.data.quota_status
         self.isLoadingQuota = false
       })
diff --git a/front/src/components/library/TrackBase.vue b/front/src/components/library/TrackBase.vue
index 6410942ba1ac1ab0ee918ecb30f0efd5cccb5438..48637abad369d25cfedf02a5bcbf6043fd48159a 100644
--- a/front/src/components/library/TrackBase.vue
+++ b/front/src/components/library/TrackBase.vue
@@ -264,12 +264,12 @@ export default {
       return route.href
     },
     headerStyle() {
-      if (!this.cover || !this.cover.original) {
+      if (!this.cover || !this.cover.urls.original) {
         return ""
       }
       return (
         "background-image: url(" +
-        this.$store.getters["instance/absoluteUrl"](this.cover.original) +
+        this.$store.getters["instance/absoluteUrl"](this.cover.urls.original) +
         ")"
       )
     },
diff --git a/front/src/components/library/TrackDetail.vue b/front/src/components/library/TrackDetail.vue
index 62ac9a9e9e4b8af038e335611457bbb9217d7e3a..73015e41cf66ffe98354e3565d62afad4c16a58d 100644
--- a/front/src/components/library/TrackDetail.vue
+++ b/front/src/components/library/TrackDetail.vue
@@ -4,7 +4,7 @@
     <section class="ui vertical stripe segment">
       <div class="ui stackable grid row container">
         <div class="six wide column">
-          <img class="image" alt="" v-if="cover && cover.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.square_crop)">
+          <img alt="" class="image" v-if="cover && cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](cover.urls.square_crop)">
           <template v-if="upload">
             <h3 class="ui header">
               <translate key="1" v-if="track.artist.content_category === 'music'" translate-context="Content/*/*">Track Details</translate>
@@ -223,7 +223,7 @@ export default {
       return this.licenseData
     },
     cover () {
-      if (this.track.cover && this.track.cover.original) {
+      if (this.track.cover && this.track.cover.urls.original) {
         return this.track.cover
       }
       if (this.track.album && this.track.album.cover) {
diff --git a/front/src/components/playlists/Editor.vue b/front/src/components/playlists/Editor.vue
index 06c10f95709e7c392425d9c6d01ca4889edb3fd9..acde6f4d2244dcd958efbfe83f7ce2dd5cc66139 100644
--- a/front/src/components/playlists/Editor.vue
+++ b/front/src/components/playlists/Editor.vue
@@ -64,7 +64,7 @@
               <tr v-for="(plt, index) in plts" :key="`${index}-${plt.track.id}`">
                 <td class="left aligned">{{ plt.index + 1}}</td>
                 <td class="center aligned">
-                  <img alt="" class="ui mini image" v-if="plt.track.album && plt.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](plt.track.album.cover.small_square_crop)">
+                  <img alt="" class="ui mini image" v-if="plt.track.album && plt.track.album.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](plt.track.album.cover.urls.medium_square_crop)">
                   <img alt="" class="ui mini image" v-else src="../../assets/audio/default-cover.png">
                 </td>
                 <td colspan="4">
diff --git a/front/src/store/auth.js b/front/src/store/auth.js
index 05cbf293d153f5c5db7d9f21a09e54b879703df2..c8dfdc86cfc28d8ea2661629cd8131cb7a347e38 100644
--- a/front/src/store/auth.js
+++ b/front/src/store/auth.js
@@ -182,7 +182,7 @@ export default {
     fetchProfile ({commit, dispatch, state}) {
 
       return new Promise((resolve, reject) => {
-        axios.get('users/users/me/').then((response) => {
+        axios.get('users/me/').then((response) => {
           logger.default.info('Successfully fetched user profile')
           dispatch('ui/initSettings', response.data.settings, { root: true })
           dispatch('updateProfile', response.data).then(() => {
diff --git a/front/src/store/playlists.js b/front/src/store/playlists.js
index 60f8771ac994e2773760c2a3f4600c4d29e131f6..6c91208dc93254a3b354996afa6af7008a4e4c27 100644
--- a/front/src/store/playlists.js
+++ b/front/src/store/playlists.js
@@ -33,7 +33,7 @@ export default {
       let playlists = []
       let url = 'playlists/'
       while (url != null) {
-        let response = await axios.get(url, {params: {user: userId}})
+        let response = await axios.get(url, {params: {scope: "me"}})
         playlists = [...playlists, ...response.data.results]
         url = response.data.next
 
diff --git a/front/src/views/Notifications.vue b/front/src/views/Notifications.vue
index ab2de0038b39a9fead91c267627171bb486eeb04..84315af9f663ede4371222da47bdfed7300471be 100644
--- a/front/src/views/Notifications.vue
+++ b/front/src/views/Notifications.vue
@@ -167,7 +167,7 @@ export default {
       }
       payload[field] = newDisplayDate
       let self = this
-      axios.patch(`users/users/${this.$store.state.auth.username}/`, payload).then((response) => {
+      axios.patch(`users/${this.$store.state.auth.username}/`, payload).then((response) => {
         self.$store.commit('auth/profilePartialUpdate', response.data)
       })
     },
diff --git a/front/src/views/admin/ChannelDetail.vue b/front/src/views/admin/ChannelDetail.vue
index 4183f76b5bddb13dbf1549cb61e64366a47aa73f..d9c4e151f8b14637bd20a8a506fefa08bd4fa897 100644
--- a/front/src/views/admin/ChannelDetail.vue
+++ b/front/src/views/admin/ChannelDetail.vue
@@ -9,7 +9,7 @@
           <div class="ui column">
             <div class="segment-content">
               <h2 class="ui header">
-                <img alt="" v-if="object.artist.cover && object.artist.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.artist.cover.square_crop)">
+                <img alt="" v-if="object.artist.cover && object.artist.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.artist.cover.urls.square_crop)">
                 <img alt="" v-else src="../../assets/audio/default-cover.png">
                 <div class="content">
                   {{ object.artist.name | truncate(100) }}
diff --git a/front/src/views/admin/library/AlbumDetail.vue b/front/src/views/admin/library/AlbumDetail.vue
index 2aea60cd0b6198e89e6a2c23b33e0361912a9701..f9700c3ef0fcfb7cba9d1b188fc45be745a0c9e0 100644
--- a/front/src/views/admin/library/AlbumDetail.vue
+++ b/front/src/views/admin/library/AlbumDetail.vue
@@ -9,7 +9,7 @@
           <div class="ui column">
             <div class="segment-content">
               <h2 class="ui header">
-                <img alt="" v-if="object.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
+                <img alt="" v-if="object.cover.urls.original" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
                 <img alt="" v-else src="../../../assets/audio/default-cover.png">
                 <div class="content">
                   {{ object.title | truncate(100) }}
diff --git a/front/src/views/admin/library/ArtistDetail.vue b/front/src/views/admin/library/ArtistDetail.vue
index cd887e529670913fe96f8bda0b3e75bd87a66000..785cb3d22acf3f008f92f0d98bc444e9a474a0c1 100644
--- a/front/src/views/admin/library/ArtistDetail.vue
+++ b/front/src/views/admin/library/ArtistDetail.vue
@@ -9,7 +9,7 @@
           <div class="ui column">
             <div class="segment-content">
               <h2 class="ui header">
-                <img alt="" v-if="object.cover && object.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
+                <img alt="" v-if="object.cover && object.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
                 <img alt="" v-else src="../../../assets/audio/default-cover.png">
                 <div class="content">
                   {{ object.name | truncate(100) }}
diff --git a/front/src/views/admin/library/TrackDetail.vue b/front/src/views/admin/library/TrackDetail.vue
index 40517a30408c17a108ae0d745d41192db67732e3..066041f693d59989bfd639d456990a04dfd7599a 100644
--- a/front/src/views/admin/library/TrackDetail.vue
+++ b/front/src/views/admin/library/TrackDetail.vue
@@ -9,7 +9,7 @@
           <div class="ui column">
             <div class="segment-content">
               <h2 class="ui header">
-                <img alt="" v-if="object.cover && object.cover.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.square_crop)">
+                <img alt="" v-if="object.cover && object.cover.urls.square_crop" v-lazy="$store.getters['instance/absoluteUrl'](object.cover.urls.square_crop)">
                 <img alt="" v-else src="../../../assets/audio/default-cover.png">
                 <div class="content">
                   {{ object.title | truncate(100) }}
diff --git a/front/src/views/auth/ProfileBase.vue b/front/src/views/auth/ProfileBase.vue
index 751fa4017ccb647c2bf0f0c369d783c30262075e..d378f743b3bb9fb4a262e907f9a29000b78e731b 100644
--- a/front/src/views/auth/ProfileBase.vue
+++ b/front/src/views/auth/ProfileBase.vue
@@ -27,7 +27,7 @@
           </div>
           <h1 class="ui center aligned icon header">
             <i v-if="!object.icon" class="circular inverted user success icon"></i>
-            <img alt="" class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](object.icon.square_crop)" />
+            <img alt="" class="ui big circular image" v-else v-lazy="$store.getters['instance/absoluteUrl'](object.icon.urls.square_crop)" />
             <div class="ellispsis content">
               <div class="ui very small hidden divider"></div>
               <span>{{ displayName }}</span>
@@ -49,7 +49,7 @@
               @updated="$emit('updated', $event)"
               :content="object.summary"
               :field-name="'summary'"
-              :update-url="`users/users/${$store.state.auth.username}/`"
+              :update-url="`users/${$store.state.auth.username}/`"
               :can-update="$store.state.auth.authenticated && object.full_username === $store.state.auth.fullUsername"></rendered-description>
           </div>
         </div>
diff --git a/front/src/views/auth/ProfileOverview.vue b/front/src/views/auth/ProfileOverview.vue
index bd61d63af3084a7572ffccb77b5f1457b87b5da7..7bd38bbf84a98a7423e5dc30f1832f3c43df6b60 100644
--- a/front/src/views/auth/ProfileOverview.vue
+++ b/front/src/views/auth/ProfileOverview.vue
@@ -5,7 +5,7 @@
         @updated="$emit('updated', $event)"
         :content="object.summary"
         :field-name="'summary'"
-        :update-url="`users/users/${$store.state.auth.username}/`"
+        :update-url="`users/${$store.state.auth.username}/`"
         :can-update="$store.state.auth.authenticated && object.full_username === $store.state.auth.fullUsername"></rendered-description>
       <div class="ui hidden divider"></div>
     </div>
diff --git a/front/src/views/channels/DetailBase.vue b/front/src/views/channels/DetailBase.vue
index e531518170fbc7c4e202cd971bb2053312a4d424..6ab5395cd46117407be2a0e17672f6025e93a290 100644
--- a/front/src/views/channels/DetailBase.vue
+++ b/front/src/views/channels/DetailBase.vue
@@ -9,7 +9,7 @@
           <div class="seven wide column">
             <div class="ui two column grid">
               <div class="column">
-                <img alt="" class="huge channel-image" v-if="object.artist.cover" :src="$store.getters['instance/absoluteUrl'](object.artist.cover.medium_square_crop)">
+                <img alt="" class="huge channel-image" v-if="object.artist.cover" :src="$store.getters['instance/absoluteUrl'](object.artist.cover.urls.medium_square_crop)">
                 <i v-else class="huge circular inverted users violet icon"></i>
               </div>
               <div class="ui column right aligned">
diff --git a/front/src/views/content/libraries/Quota.vue b/front/src/views/content/libraries/Quota.vue
index 2a6f2f200eba73ec490c46479558f7b4ce96ff0e..ada8351ea903dff3d4a020103aeebe436a20f261 100644
--- a/front/src/views/content/libraries/Quota.vue
+++ b/front/src/views/content/libraries/Quota.vue
@@ -114,7 +114,7 @@ export default {
     fetch () {
       let self = this
       self.isLoading = true
-      axios.get('users/users/me/').then((response) => {
+      axios.get('users/me/').then((response) => {
         self.quotaStatus = response.data.quota_status
         self.isLoading = false
       })
diff --git a/front/tests/unit/specs/store/auth.spec.js b/front/tests/unit/specs/store/auth.spec.js
index 3de563df3efe2e41067a2d68ba0d8acbfd60d75e..ee08c0061cd07847dfbb168a8704adb5972e8d05 100644
--- a/front/tests/unit/specs/store/auth.spec.js
+++ b/front/tests/unit/specs/store/auth.spec.js
@@ -146,7 +146,7 @@ describe('store/auth', () => {
           admin: true
         }
       }
-      moxios.stubRequest('users/users/me/', {
+      moxios.stubRequest('users/me/', {
         status: 200,
         response: profile
       })