diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py
index 329c644ee266adc4360059d45064c09cf274f292..cae99e242685c205ad794efbf5adf696ac7cc32e 100644
--- a/api/funkwhale_api/subsonic/serializers.py
+++ b/api/funkwhale_api/subsonic/serializers.py
@@ -8,6 +8,40 @@ from funkwhale_api.music import models as music_models
 from funkwhale_api.music import utils as music_utils
 
 
+def to_subsonic_date(date):
+    """
+    Subsonic expects this kind of date format: 2012-04-17T19:55:49.000Z
+    """
+
+    if not date:
+        return
+
+    return date.strftime("%Y-%m-%dT%H:%M:%S.000Z")
+
+
+def get_valid_filepart(s):
+    """
+    Return a string suitable for use in a file path. Escape most non-ASCII
+    chars, and truncate the string to a suitable length too.
+    """
+    max_length = 50
+    keepcharacters = " ._()[]-+"
+    final = "".join(
+        c if c.isalnum() or c in keepcharacters else "_" for c in s
+    ).rstrip()
+    return final[:max_length]
+
+
+def get_track_path(track, suffix):
+    artist_part = get_valid_filepart(track.artist.name)
+    album_part = get_valid_filepart(track.album.title)
+    track_part = get_valid_filepart(track.title) + "." + suffix
+    if track.position:
+        track_part = "{} - {}".format(track.position, track_part)
+
+    return "/".join([artist_part, album_part, track_part])
+
+
 def get_artist_data(artist_values):
     return {
         "id": artist_values["id"],
@@ -52,7 +86,7 @@ class GetArtistSerializer(serializers.Serializer):
                 "artistId": artist.id,
                 "name": album.title,
                 "artist": artist.name,
-                "created": album.creation_date,
+                "created": to_subsonic_date(album.creation_date),
                 "songCount": len(album.tracks.all()),
             }
             if album.cover:
@@ -81,8 +115,9 @@ def get_track_data(album, track, upload):
             else "audio/mpeg"
         ),
         "suffix": upload.extension or "",
+        "path": get_track_path(track, upload.extension or "mp3"),
         "duration": upload.duration or 0,
-        "created": track.creation_date,
+        "created": to_subsonic_date(track.creation_date),
         "albumId": album.pk,
         "artistId": album.artist.pk,
         "type": "music",
@@ -104,7 +139,7 @@ def get_album2_data(album):
         "artistId": album.artist.id,
         "name": album.title,
         "artist": album.artist.name,
-        "created": album.creation_date,
+        "created": to_subsonic_date(album.creation_date),
     }
     if album.cover:
         payload["coverArt"] = "al-{}".format(album.id)
@@ -162,7 +197,7 @@ def get_starred_tracks_data(favorites):
         except IndexError:
             continue
         td = get_track_data(t.album, t, uploads)
-        td["starred"] = by_track_id[t.pk].creation_date
+        td["starred"] = to_subsonic_date(by_track_id[t.pk].creation_date)
         data.append(td)
     return data
 
@@ -179,7 +214,7 @@ def get_playlist_data(playlist):
         "public": "false",
         "songCount": playlist._tracks_count,
         "duration": 0,
-        "created": playlist.creation_date,
+        "created": to_subsonic_date(playlist.creation_date),
     }
 
 
@@ -220,8 +255,9 @@ def get_music_directory_data(artist):
             "year": track.album.release_date.year if track.album.release_date else 0,
             "contentType": upload.mimetype,
             "suffix": upload.extension or "",
+            "path": get_track_path(track, upload.extension or "mp3"),
             "duration": upload.duration or 0,
-            "created": track.creation_date,
+            "created": to_subsonic_date(track.creation_date),
             "albumId": album.pk,
             "artistId": artist.pk,
             "parent": artist.id,
@@ -259,7 +295,7 @@ def get_user_detail_data(user):
         "playlistRole": "true",
         "streamRole": "true",
         "jukeboxRole": "true",
-        "folder": [f["id"] for f in get_folders(user)],
+        "folder": [{"value": f["id"]} for f in get_folders(user)],
     }
 
 
diff --git a/api/tests/subsonic/test_serializers.py b/api/tests/subsonic/test_serializers.py
index d6025a90b9bfc158f269a9fe0bfbab6e330ad0b4..4da84ec3502cbacf6aa0e1cbb74307436e7b780d 100644
--- a/api/tests/subsonic/test_serializers.py
+++ b/api/tests/subsonic/test_serializers.py
@@ -1,9 +1,71 @@
+import datetime
 import pytest
 
 from funkwhale_api.music import models as music_models
 from funkwhale_api.subsonic import serializers
 
 
+@pytest.mark.parametrize(
+    "date, expected",
+    [
+        (datetime.datetime(2017, 1, 12, 9, 53, 12, 1890), "2017-01-12T09:53:12.000Z"),
+        (None, None),
+    ],
+)
+def test_to_subsonic_date(date, expected):
+    assert serializers.to_subsonic_date(date) == expected
+
+
+@pytest.mark.parametrize(
+    "input, expected",
+    [
+        ("AC/DC", "AC_DC"),
+        ("AC-DC", "AC-DC"),
+        ("A" * 100, "A" * 50),
+        ("Album (2019)", "Album (2019)"),
+        ("Haven't", "Haven_t"),
+    ],
+)
+def test_get_valid_filepart(input, expected):
+    assert serializers.get_valid_filepart(input) == expected
+
+
+@pytest.mark.parametrize(
+    "factory_kwargs, suffix, expected",
+    [
+        (
+            {
+                "artist__name": "Hello",
+                "album__title": "World",
+                "title": "foo",
+                "position": None,
+            },
+            "mp3",
+            "Hello/World/foo.mp3",
+        ),
+        (
+            {
+                "artist__name": "AC/DC",
+                "album__title": "escape/my",
+                "title": "sla/sh",
+                "position": 12,
+            },
+            "ogg",
+            "/".join(
+                [
+                    serializers.get_valid_filepart("AC/DC"),
+                    serializers.get_valid_filepart("escape/my"),
+                ]
+            )
+            + "/12 - {}.ogg".format(serializers.get_valid_filepart("sla/sh")),
+        ),
+    ],
+)
+def test_get_track_path(factory_kwargs, suffix, expected, factories):
+    track = factories["music.Track"](**factory_kwargs)
+    assert serializers.get_track_path(track, suffix) == expected
+
+
 def test_get_artists_serializer(factories):
     artist1 = factories["music.Artist"](name="eliot")
     artist2 = factories["music.Artist"](name="Ellena")
@@ -54,7 +116,7 @@ def test_get_artist_serializer(factories):
                 "name": album.title,
                 "artist": artist.name,
                 "songCount": len(tracks),
-                "created": album.creation_date,
+                "created": serializers.to_subsonic_date(album.creation_date),
                 "year": album.release_date.year,
             }
         ],
@@ -96,7 +158,7 @@ def test_get_album_serializer(factories):
         "name": album.title,
         "artist": artist.name,
         "songCount": 1,
-        "created": album.creation_date,
+        "created": serializers.to_subsonic_date(album.creation_date),
         "year": album.release_date.year,
         "coverArt": "al-{}".format(album.id),
         "song": [
@@ -112,10 +174,11 @@ def test_get_album_serializer(factories):
                 "year": track.album.release_date.year,
                 "contentType": upload.mimetype,
                 "suffix": upload.extension or "",
+                "path": serializers.get_track_path(track, upload.extension),
                 "bitrate": 42,
                 "duration": 43,
                 "size": 44,
-                "created": track.creation_date,
+                "created": serializers.to_subsonic_date(track.creation_date),
                 "albumId": album.pk,
                 "artistId": artist.pk,
                 "type": "music",
@@ -133,7 +196,7 @@ def test_starred_tracks2_serializer(factories):
     upload = factories["music.Upload"](track=track)
     favorite = factories["favorites.TrackFavorite"](track=track)
     expected = [serializers.get_track_data(album, track, upload)]
-    expected[0]["starred"] = favorite.creation_date
+    expected[0]["starred"] = serializers.to_subsonic_date(favorite.creation_date)
     data = serializers.get_starred_tracks_data([favorite])
     assert data == expected
 
@@ -162,7 +225,7 @@ def test_playlist_serializer(factories):
         "public": "false",
         "songCount": 1,
         "duration": 0,
-        "created": playlist.creation_date,
+        "created": serializers.to_subsonic_date(playlist.creation_date),
     }
     qs = playlist.__class__.objects.with_tracks_count()
     data = serializers.get_playlist_data(qs.first())
@@ -181,7 +244,7 @@ def test_playlist_detail_serializer(factories):
         "public": "false",
         "songCount": 1,
         "duration": 0,
-        "created": playlist.creation_date,
+        "created": serializers.to_subsonic_date(playlist.creation_date),
         "entry": [serializers.get_track_data(plt.track.album, plt.track, upload)],
     }
     qs = playlist.__class__.objects.with_tracks_count()
@@ -210,10 +273,11 @@ def test_directory_serializer_artist(factories):
                 "year": track.album.release_date.year,
                 "contentType": upload.mimetype,
                 "suffix": upload.extension or "",
+                "path": serializers.get_track_path(track, upload.extension),
                 "bitrate": 42,
                 "duration": 43,
                 "size": 44,
-                "created": track.creation_date,
+                "created": serializers.to_subsonic_date(track.creation_date),
                 "albumId": album.pk,
                 "artistId": artist.pk,
                 "parent": artist.pk,
diff --git a/api/tests/subsonic/test_views.py b/api/tests/subsonic/test_views.py
index d58cc3932c61a4763db228716e7a418f417a3432..4f22b96ee6a291276d9703d9a87af57a81e391a4 100644
--- a/api/tests/subsonic/test_views.py
+++ b/api/tests/subsonic/test_views.py
@@ -762,7 +762,8 @@ def test_get_user(f, db, logged_in_api_client, factories):
             "coverArtRole": "false",
             "shareRole": "false",
             "folder": [
-                f["id"] for f in serializers.get_folders(logged_in_api_client.user)
+                {"value": f["id"]}
+                for f in serializers.get_folders(logged_in_api_client.user)
             ],
         }
     }