diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py
index 8d9eb816a192e6f6d5d3b72f04e1c14e4abb4da1..9ccb94e4f283c1187eba38a4e353903af8ac51c3 100644
--- a/api/funkwhale_api/radios/radios.py
+++ b/api/funkwhale_api/radios/radios.py
@@ -1,7 +1,7 @@
 import random
 
 from django.core.exceptions import ValidationError
-from django.db.models import Count
+from django.db import connection
 from rest_framework import serializers
 from taggit.models import Tag
 
@@ -43,8 +43,7 @@ class SessionRadio(SimpleRadio):
         return self.session
 
     def get_queryset(self, **kwargs):
-        qs = Track.objects.annotate(uploads_count=Count("uploads"))
-        return qs.filter(uploads_count__gt=0)
+        return Track.objects.all()
 
     def get_queryset_kwargs(self):
         return {}
@@ -56,6 +55,10 @@ class SessionRadio(SimpleRadio):
             queryset = self.filter_from_session(queryset)
             if kwargs.pop("filter_playable", True):
                 queryset = queryset.playable_by(self.session.user.actor)
+        queryset = self.filter_queryset(queryset)
+        return queryset
+
+    def filter_queryset(self, queryset):
         return queryset
 
     def filter_from_session(self, queryset):
@@ -153,6 +156,74 @@ class TagRadio(RelatedObjectRadio):
         return qs.filter(tags__in=[self.session.related_object])
 
 
+def weighted_choice(choices):
+    total = sum(w for c, w in choices)
+    r = random.uniform(0, total)
+    upto = 0
+    for c, w in choices:
+        if upto + w >= r:
+            return c
+        upto += w
+    assert False, "Shouldn't get here"
+
+
+class NextNotFound(Exception):
+    pass
+
+
+@registry.register(name="similar")
+class SimilarRadio(RelatedObjectRadio):
+    model = Track
+
+    def filter_queryset(self, queryset):
+        queryset = super().filter_queryset(queryset)
+        seeds = list(
+            self.session.session_tracks.all()
+            .values_list("track_id", flat=True)
+            .order_by("-id")[:3]
+        ) + [self.session.related_object.pk]
+        for seed in seeds:
+            try:
+                return queryset.filter(pk=self.find_next_id(queryset, seed))
+            except NextNotFound:
+                continue
+
+        return queryset.none()
+
+    def find_next_id(self, queryset, seed):
+        with connection.cursor() as cursor:
+            query = """
+            SELECT next, count(next) AS c
+            FROM (
+                SELECT
+                    track_id,
+                    creation_date,
+                    LEAD(track_id) OVER (
+                        PARTITION by user_id order by creation_date asc
+                    ) AS next
+                FROM history_listening
+                INNER JOIN users_user ON (users_user.id = user_id)
+                WHERE users_user.privacy_level = 'instance' OR users_user.privacy_level = 'everyone' OR user_id = %s
+                ORDER BY creation_date ASC
+            ) t WHERE track_id = %s AND next != %s GROUP BY next ORDER BY c DESC;
+            """
+            cursor.execute(query, [self.session.user_id, seed, seed])
+            next_candidates = list(cursor.fetchall())
+
+        if not next_candidates:
+            raise NextNotFound()
+
+        matching_tracks = list(
+            queryset.filter(pk__in=[c[0] for c in next_candidates]).values_list(
+                "id", flat=True
+            )
+        )
+        next_candidates = [n for n in next_candidates if n[0] in matching_tracks]
+        if not next_candidates:
+            raise NextNotFound()
+        return weighted_choice(next_candidates)
+
+
 @registry.register(name="artist")
 class ArtistRadio(RelatedObjectRadio):
     model = Artist
diff --git a/api/tests/radios/test_radios.py b/api/tests/radios/test_radios.py
index 7e8f260d0338d2ef71b3b51fb11c5acde917789a..cedb6bd7f856afefe6c9de617a32e70a3b0b83b1 100644
--- a/api/tests/radios/test_radios.py
+++ b/api/tests/radios/test_radios.py
@@ -237,3 +237,20 @@ def test_can_start_less_listened_radio(factories):
 
     for i in range(5):
         assert radio.pick(filter_playable=False) in good_tracks
+
+
+def test_similar_radio_track(factories):
+    user = factories["users.User"]()
+    seed = factories["music.Track"]()
+    radio = radios.SimilarRadio()
+    radio.start_session(user, related_object=seed)
+
+    factories["music.Track"].create_batch(5)
+
+    # one user listened to this track
+    l1 = factories["history.Listening"](track=seed)
+
+    expected_next = factories["music.Track"]()
+    factories["history.Listening"](track=expected_next, user=l1.user)
+
+    assert radio.pick(filter_playable=False) == expected_next
diff --git a/changes/changelog.d/similar-radio.enhancement b/changes/changelog.d/similar-radio.enhancement
new file mode 100644
index 0000000000000000000000000000000000000000..d4c0a58de6adcb2fb789953dc8da9b59d60841a8
--- /dev/null
+++ b/changes/changelog.d/similar-radio.enhancement
@@ -0,0 +1 @@
+[Experimental] Added a new "Similar" radio based on users history (suggested by @gordon)
diff --git a/front/src/components/audio/PlayButton.vue b/front/src/components/audio/PlayButton.vue
index d438a14a02b412156accdf2a45c385defa0e42f3..07cb1f585afee112ade1fc1e64ed484bc7106a07 100644
--- a/front/src/components/audio/PlayButton.vue
+++ b/front/src/components/audio/PlayButton.vue
@@ -15,6 +15,7 @@
         <button class="item basic" ref="add" data-ref="add" :disabled="!playable" @click.stop.prevent="add" :title="labels.addToQueue"><i class="plus icon"></i><translate>Add to queue</translate></button>
         <button class="item basic" ref="addNext" data-ref="addNext" :disabled="!playable" @click.stop.prevent="addNext()" :title="labels.playNext"><i class="step forward icon"></i><translate>Play next</translate></button>
         <button class="item basic" ref="playNow" data-ref="playNow" :disabled="!playable" @click.stop.prevent="addNext(true)" :title="labels.playNow"><i class="play icon"></i><translate>Play now</translate></button>
+        <button v-if="track" class="item basic" :disabled="!playable" @click.stop.prevent="$store.dispatch('radios/start', {type: 'similar', objectId: track.id})" :title="labels.startRadio"><i class="feed icon"></i><translate>Start radio</translate></button>
       </div>
     </div>
   </span>
@@ -62,7 +63,8 @@ export default {
       return {
         playNow: this.$gettext('Play now'),
         addToQueue: this.$gettext('Add to current queue'),
-        playNext: this.$gettext('Play next')
+        playNext: this.$gettext('Play next'),
+        startRadio: this.$gettext('Play similar songs')
       }
     },
     title () {