diff --git a/api/funkwhale_api/common/search.py b/api/funkwhale_api/common/search.py
index 5fc6f6804ca4c5e5289fb224c6e9adce503be978..70aecd632f6e77109dc3e8d51e06695acd19d6cf 100644
--- a/api/funkwhale_api/common/search.py
+++ b/api/funkwhale_api/common/search.py
@@ -3,7 +3,7 @@ import re
 from django.db.models import Q
 
 
-QUERY_REGEX = re.compile('(((?P<key>\w+):)?(?P<value>"[^"]+"|[\S]+))')
+QUERY_REGEX = re.compile(r'(((?P<key>\w+):)?(?P<value>"[^"]+"|[\S]+))')
 
 
 def parse_query(query):
diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py
index 43a95047f757514936bfd96207869faaa2c16b2e..a49b55236b0477ecec92d00d9e1466a7c954539b 100644
--- a/api/funkwhale_api/music/models.py
+++ b/api/funkwhale_api/music/models.py
@@ -209,12 +209,7 @@ class AlbumQuerySet(models.QuerySet):
 
     def with_prefetched_tracks_and_playable_uploads(self, actor):
         tracks = Track.objects.with_playable_uploads(actor)
-        return self.prefetch_related(
-            models.Prefetch(
-                'tracks',
-                queryset=tracks,
-            )
-        )
+        return self.prefetch_related(models.Prefetch("tracks", queryset=tracks))
 
 
 class Album(APIModelMixin):
@@ -413,13 +408,9 @@ class TrackQuerySet(models.QuerySet):
             return self.exclude(uploads__in=files).distinct()
 
     def with_playable_uploads(self, actor):
-        uploads = Upload.objects.playable_by(actor).select_related('track')
+        uploads = Upload.objects.playable_by(actor).select_related("track")
         return self.prefetch_related(
-            models.Prefetch(
-                'uploads',
-                queryset=uploads,
-                to_attr='playable_uploads'
-            )
+            models.Prefetch("uploads", queryset=uploads, to_attr="playable_uploads")
         )
 
 
@@ -763,11 +754,13 @@ class Upload(models.Model):
         # we create the version with an empty file, then
         # we'll write to it
         f = ContentFile(b"")
-        version = self.versions.create(mimetype=mimetype, bitrate=self.bitrate or 128000, size=0)
+        version = self.versions.create(
+            mimetype=mimetype, bitrate=self.bitrate or 128000, size=0
+        )
         # we keep the same name, but we update the extension
-        new_name = os.path.splitext(
-            os.path.basename(self.audio_file.name)
-        )[0] + '.{}'.format(format)
+        new_name = os.path.splitext(os.path.basename(self.audio_file.name))[
+            0
+        ] + ".{}".format(format)
         version.audio_file.save(new_name, f)
         utils.transcode_file(
             input=self.audio_file,
@@ -776,18 +769,18 @@ class Upload(models.Model):
             output_format=utils.MIMETYPE_TO_EXTENSION[mimetype],
         )
         version.size = version.audio_file.size
-        version.save(update_fields=['size'])
+        version.save(update_fields=["size"])
 
         return version
 
 
-MIMETYPE_CHOICES = [
-    (mt, ext) for ext, mt in utils.AUDIO_EXTENSIONS_AND_MIMETYPE
-]
+MIMETYPE_CHOICES = [(mt, ext) for ext, mt in utils.AUDIO_EXTENSIONS_AND_MIMETYPE]
 
 
 class UploadVersion(models.Model):
-    upload = models.ForeignKey(Upload, related_name='versions', on_delete=models.CASCADE)
+    upload = models.ForeignKey(
+        Upload, related_name="versions", on_delete=models.CASCADE
+    )
     mimetype = models.CharField(max_length=50, choices=MIMETYPE_CHOICES)
     creation_date = models.DateTimeField(default=timezone.now)
     accessed_date = models.DateTimeField(null=True, blank=True)
@@ -796,7 +789,7 @@ class UploadVersion(models.Model):
     size = models.IntegerField()
 
     class Meta:
-        unique_together = ('upload', 'mimetype', 'bitrate')
+        unique_together = ("upload", "mimetype", "bitrate")
 
     @property
     def filename(self):
diff --git a/api/funkwhale_api/subsonic/views.py b/api/funkwhale_api/subsonic/views.py
index 343d87881e1f5ed85a74f80753c00e6f5c44a753..8aa9c9dbe893d7d1e0974cfc79def18e6e12f29c 100644
--- a/api/funkwhale_api/subsonic/views.py
+++ b/api/funkwhale_api/subsonic/views.py
@@ -200,8 +200,8 @@ class SubsonicViewSet(viewsets.GenericViewSet):
         if not upload:
             return response.Response(status=404)
 
-        format = data.get('format', 'raw')
-        if format == 'raw':
+        format = data.get("format", "raw")
+        if format == "raw":
             format = None
         return music_views.handle_serve(upload=upload, user=request.user, format=format)
 
diff --git a/api/tests/subsonic/test_views.py b/api/tests/subsonic/test_views.py
index d2269ba5c5d30b8ee75b6b07947453cae7cda34d..c0ae8407362b1fca31573b4b895ed0a58ca5097f 100644
--- a/api/tests/subsonic/test_views.py
+++ b/api/tests/subsonic/test_views.py
@@ -206,14 +206,18 @@ def test_stream(f, db, logged_in_api_client, factories, mocker, queryset_equal_q
     playable_by.assert_called_once_with(music_models.Track.objects.all(), None)
 
 
-@pytest.mark.parametrize("format,expected", [("mp3", 'mp3'), ("raw", None)])
+@pytest.mark.parametrize("format,expected", [("mp3", "mp3"), ("raw", None)])
 def test_stream_format(format, expected, logged_in_api_client, factories, mocker):
     url = reverse("api:subsonic-stream")
-    mocked_serve = mocker.patch.object(music_views, "handle_serve", return_value=Response())
+    mocked_serve = mocker.patch.object(
+        music_views, "handle_serve", return_value=Response()
+    )
     upload = factories["music.Upload"](playable=True)
     response = logged_in_api_client.get(url, {"id": upload.track.pk, "format": format})
 
-    mocked_serve.assert_called_once_with(upload=upload, user=logged_in_api_client.user, format=expected)
+    mocked_serve.assert_called_once_with(
+        upload=upload, user=logged_in_api_client.user, format=expected
+    )
     assert response.status_code == 200
 
 
diff --git a/api/tests/test_import_audio_file.py b/api/tests/test_import_audio_file.py
index ce6aebbc3bcdd980207c22b70bc5615bbe780905..c6b8aea60e59b084edff401d25ff2af163f3f756 100644
--- a/api/tests/test_import_audio_file.py
+++ b/api/tests/test_import_audio_file.py
@@ -134,7 +134,7 @@ def test_import_files_skip_if_path_already_imported(factories, mocker):
     )
 
     call_command(
-        "import_files", str(library.uuid), path, async=False, interactive=False
+        "import_files", str(library.uuid), path, async_=False, interactive=False
     )
     assert library.uploads.count() == 1
 
diff --git a/changes/changelog.d/272.feature b/changes/changelog.d/272.feature
new file mode 100644
index 0000000000000000000000000000000000000000..8a14193704f2ca1b835fc674967036a7a336e6d3
--- /dev/null
+++ b/changes/changelog.d/272.feature
@@ -0,0 +1,13 @@
+Audio transcoding is back! (#272)
+
+
+Audio transcoding is back!
+--------------------------
+
+After removal of our first, buggy transcoding implementation, we're proud to announce
+that this feature is back. It is enabled by default, and can be configured/disabled
+in your instance settings!
+
+This feature works in the browser, with federated/non-federated tracks and using Subsonic clients.
+Transcoded tracks are generated on the fly, and cached for a configurable amount of time,
+to reduce the load on the server.