diff --git a/changes/changelog.d/1060.feature b/changes/changelog.d/1060.feature
new file mode 100644
index 0000000000000000000000000000000000000000..245a6be0ce9281b0771c8cb122f10b64c0cc5083
--- /dev/null
+++ b/changes/changelog.d/1060.feature
@@ -0,0 +1 @@
+Added a new radio based on another user listenings (#1060)
diff --git a/front/src/App.vue b/front/src/App.vue
index b572b1bcd0c4263375a205f43a2022b34140adbe..6252198e27e7f6d9b8f86d09d85f480b9d4d21b6 100644
--- a/front/src/App.vue
+++ b/front/src/App.vue
@@ -42,6 +42,7 @@ import { WebSocketBridge } from 'django-channels'
 import GlobalEvents from '@/components/utils/global-events'
 import moment from  'moment'
 import locales from './locales'
+import {getClientOnlyRadio} from '@/radios'
 
 export default {
   name: 'app',
@@ -138,6 +139,11 @@ export default {
       id: 'sidebarPendingReviewRequestCount',
       handler: this.incrementPendingReviewRequestsCountInSidebar
     })
+    this.$store.commit('ui/addWebsocketEventHandler', {
+      eventName: 'Listen',
+      id: 'handleListen',
+      handler: this.handleListen
+    })
   },
   mounted () {
     let self = this
@@ -175,6 +181,10 @@ export default {
       eventName: 'user_request.created',
       id: 'sidebarPendingReviewRequestCount',
     })
+    this.$store.commit('ui/removeWebsocketEventHandler', {
+      eventName: 'Listen',
+      id: 'handleListen',
+    })
     this.disconnect()
   },
   methods: {
@@ -190,6 +200,14 @@ export default {
     incrementPendingReviewRequestsCountInSidebar (event) {
       this.$store.commit('ui/incrementNotifications', {type: 'pendingReviewRequests', value: event.pending_count})
     },
+    handleListen (event) {
+      if (this.$store.state.radios.current && this.$store.state.radios.running) {
+        let current = this.$store.state.radios.current
+        if (current.clientOnly && current.type === 'account') {
+          getClientOnlyRadio(current).handleListen(current, event, this.$store)
+        }
+      }
+    },
     async fetchNodeInfo () {
       let response = await axios.get('instance/nodeinfo/2.0/')
       this.$store.commit('instance/nodeinfo', response.data)
diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue
index 58f76ad073b70a167811cb38f784c6b4fb367bba..1c720d9522b6c7258bd3f4b4a079f9079b066549 100644
--- a/front/src/components/audio/Player.vue
+++ b/front/src/components/audio/Player.vue
@@ -251,6 +251,8 @@ export default {
       progressInterval: null,
       maxPreloaded: 3,
       preloadDelay: 15,
+      listenDelay: 15,
+      listeningRecorded: null,
       soundsCache: [],
       soundId: null,
       playTimeout: null,
@@ -477,6 +479,13 @@ export default {
           this.getSound(toPreload)
           this.nextTrackPreloaded = true
         }
+        if (t > this.listenDelay || d - t < 30) {
+          let onlyTrack = this.$store.state.queue.tracks.length === 1
+          if (this.listeningRecorded != this.currentTrack) {
+            this.listeningRecorded = this.currentTrack
+            this.$store.dispatch('player/trackListened', this.currentTrack)
+          }
+        }
       }
     },
     seek (step) {
diff --git a/front/src/components/audio/track/Widget.vue b/front/src/components/audio/track/Widget.vue
index 6895a8712730b2ad52d5951ae19fda4c788954e0..945db6a167f1e5ae5ef46ae5c102bf32b4cc6b49 100644
--- a/front/src/components/audio/track/Widget.vue
+++ b/front/src/components/audio/track/Widget.vue
@@ -29,7 +29,7 @@
               <tags-list label-classes="tiny" :truncate-size="20" :limit="2" :show-more="false" :tags="object.track.tags"></tags-list>
 
               <div class="extra" v-if="isActivity">
-                <span class="left floated">@{{ object.user.username }}</span>
+                <router-link class="left floated" :to="{name: 'profile.overview', params: {username: object.user.username}}">@{{ object.user.username }}</router-link>
                 <span class="right floated"><human-date :date="object.creation_date" /></span>
               </div>
             </div>
diff --git a/front/src/components/radios/Button.vue b/front/src/components/radios/Button.vue
index f335a6596273838e844f1357f7c9c5503ace7ff7..7e1ff40c50467e3199ea2574955d4785c115da3b 100644
--- a/front/src/components/radios/Button.vue
+++ b/front/src/components/radios/Button.vue
@@ -8,10 +8,12 @@
 
 <script>
 
+import lodash from '@/lodash'
 export default {
   props: {
     customRadioId: {required: false},
     type: {type: String, required: false},
+    clientOnly: {type: Boolean, default: false},
     objectId: {default: null}
   },
   methods: {
@@ -19,7 +21,12 @@ export default {
       if (this.running) {
         this.$store.dispatch('radios/stop')
       } else {
-        this.$store.dispatch('radios/start', {type: this.type, objectId: this.objectId, customRadioId: this.customRadioId})
+        this.$store.dispatch('radios/start', {
+          type: this.type,
+          objectId: this.objectId,
+          customRadioId: this.customRadioId,
+          clientOnly: this.clientOnly,
+        })
       }
     }
   },
@@ -30,7 +37,7 @@ export default {
       if (!state.running) {
         return false
       } else {
-        return current.type === this.type && current.objectId === this.objectId && current.customRadioId === this.customRadioId
+        return current.type === this.type && lodash.isEqual(current.objectId, this.objectId) && current.customRadioId === this.customRadioId
       }
     }
   }
diff --git a/front/src/radios.js b/front/src/radios.js
new file mode 100644
index 0000000000000000000000000000000000000000..b10937fb9f5607e04ed96936dfab9a02f65e0ed8
--- /dev/null
+++ b/front/src/radios.js
@@ -0,0 +1,51 @@
+import axios from "axios"
+import logger from '@/logging'
+
+// import axios from 'axios'
+
+const RADIOS = {
+  // some radios are client side only, so we have to implement the populateQueue
+  // method by hand
+  account: {
+    offset: 1,
+    populateQueue({current, dispatch, playNow}) {
+      let params = {scope: `actor:${current.objectId.fullUsername}`, ordering: '-creation_date', page_size: 1, page: this.offset}
+      axios.get('history/listenings', {params}).then((response) => {
+        let latest = response.data.results[0]
+        if (!latest) {
+          logger.default.error('No more tracks')
+          dispatch('stop')
+        }
+        this.offset += 1
+        let append = dispatch('queue/append', {track: latest.track}, {root: true})
+        if (playNow) {
+          append.then(() => {
+            dispatch('queue/last', null, {root: true})
+          })
+        }
+      }, (error) => {
+        logger.default.error('Error while fetching listenings', error)
+        dispatch('stop')
+      })
+    },
+    stop () {
+      this.offset = 1
+    },
+    handleListen (current, event, store) {
+      // XXX: handle actors from other pods
+      if (event.actor.local_id === current.objectId.username) {
+        axios.get(`tracks/${event.object.local_id}`).then((response) => {
+          if (response.data.uploads.length > 0) {
+            store.dispatch('queue/append', {track: response.data, index: store.state.queue.currentIndex + 1})
+            this.offset += 1
+          }
+        }, (error) => {
+          logger.default.error('Cannot retrieve track info', error)
+        })
+      }
+    }
+  }
+}
+export function getClientOnlyRadio({type}) {
+  return RADIOS[type]
+}
diff --git a/front/src/store/player.js b/front/src/store/player.js
index 14affce90a6b56ea11693d6479991eb82c5848a0..f3dbbb8b79307aeb5a36918ba4f0e9345f93cd11 100644
--- a/front/src/store/player.js
+++ b/front/src/store/player.js
@@ -127,7 +127,6 @@ export default {
       })
     },
     trackEnded ({dispatch, rootState}, track) {
-      dispatch('trackListened', track)
       let queueState = rootState.queue
       if (queueState.currentIndex === queueState.tracks.length - 1) {
         // we've reached last track of queue, trigger a reload
diff --git a/front/src/store/radios.js b/front/src/store/radios.js
index 6eb06566ff21b7533c840e4c0c9974ae551ab8f3..d07ad59cbcf74405c958f44d6b75531c3d280b6d 100644
--- a/front/src/store/radios.js
+++ b/front/src/store/radios.js
@@ -1,6 +1,8 @@
 import axios from 'axios'
 import logger from '@/logging'
 
+import {getClientOnlyRadio} from '@/radios'
+
 export default {
   namespaced: true,
   state: {
@@ -42,11 +44,17 @@ export default {
     }
   },
   actions: {
-    start ({commit, dispatch}, {type, objectId, customRadioId}) {
+    start ({commit, dispatch}, {type, objectId, customRadioId, clientOnly}) {
       var params = {
         radio_type: type,
         related_object_id: objectId,
-        custom_radio: customRadioId
+        custom_radio: customRadioId,
+      }
+      if (clientOnly) {
+        commit('current', {type, objectId, customRadioId, clientOnly})
+        commit('running', true)
+        dispatch('populateQueue', true)
+        return
       }
       return axios.post('radios/sessions/', params).then((response) => {
         logger.default.info('Successfully started radio ', type)
@@ -57,7 +65,10 @@ export default {
         logger.default.error('Error while starting radio', type)
       })
     },
-    stop ({commit}) {
+    stop ({commit, state}) {
+      if (state.current && state.current.clientOnly) {
+        getClientOnlyRadio(state.current).stop()
+      }
       commit('current', null)
       commit('running', false)
     },
@@ -71,6 +82,9 @@ export default {
       var params = {
         session: state.current.session
       }
+      if (state.current.clientOnly) {
+        return getClientOnlyRadio(state.current).populateQueue({current: state.current, dispatch, state, rootState, playNow})
+      }
       return axios.post('radios/tracks/', params).then((response) => {
         logger.default.info('Adding track to queue from radio')
         let append = dispatch('queue/append', {track: response.data.track}, {root: true})
diff --git a/front/src/store/ui.js b/front/src/store/ui.js
index 0c16f2b451b2e93f2c5e5973ffca80cbde409957..5c6ca20de4b142f5e2b75a9f8af6b98d8d54ebf3 100644
--- a/front/src/store/ui.js
+++ b/front/src/store/ui.js
@@ -31,6 +31,7 @@ export default {
       'mutation.updated': {},
       'report.created': {},
       'user_request.created': {},
+      'Listen': {},
     },
     pageTitle: null,
     routePreferences: {
diff --git a/front/src/views/auth/ProfileBase.vue b/front/src/views/auth/ProfileBase.vue
index cb70b66ae788f3d14bec5d220076ba77a62655d0..702d3b870d572902f9328b45db96286402554d4d 100644
--- a/front/src/views/auth/ProfileBase.vue
+++ b/front/src/views/auth/ProfileBase.vue
@@ -43,6 +43,9 @@
               </div>
             </template>
           </h1>
+          <div class="ui center aligned text">
+            <radio-button type="account" :object-id="{username: object.preferred_username, fullUsername: object.full_username}" :client-only="true"></radio-button>
+          </div>
           <div class="ui small hidden divider"></div>
           <div v-if="$store.getters['ui/layoutVersion'] === 'large'">
             <rendered-description
@@ -82,6 +85,7 @@ import { mapState } from "vuex"
 import axios from 'axios'
 
 import ReportMixin from '@/components/mixins/Report'
+import RadioButton from "@/components/radios/Button"
 
 export default {
   mixins: [ReportMixin],
@@ -89,6 +93,9 @@ export default {
     username: {type: String, required: true},
     domain: {type: String, required: false, default: null},
   },
+  components: {
+    RadioButton,
+  },
   data () {
     return {
       object: null,
diff --git a/front/tests/unit/specs/store/player.spec.js b/front/tests/unit/specs/store/player.spec.js
index 13a3fd7630ab7974aa0a6534253ded81433e0003..c3f1c4583f39b28b7df07370dede94128415f3b3 100644
--- a/front/tests/unit/specs/store/player.spec.js
+++ b/front/tests/unit/specs/store/player.spec.js
@@ -136,7 +136,6 @@ describe('store/player', () => {
         payload: {test: 'track'},
         params: {rootState: {queue: {currentIndex: 0, tracks: [1, 2]}}},
         expectedActions: [
-          { type: 'trackListened', payload: {test: 'track'} },
           { type: 'queue/next', payload: null, options: {root: true} }
         ]
       })
@@ -147,7 +146,6 @@ describe('store/player', () => {
         payload: {test: 'track'},
         params: {rootState: {queue: {currentIndex: 1, tracks: [1, 2]}}},
         expectedActions: [
-          { type: 'trackListened', payload: {test: 'track'} },
           { type: 'radios/populateQueue', payload: null, options: {root: true} },
           { type: 'queue/next', payload: null, options: {root: true} }
         ]
diff --git a/front/tests/unit/specs/store/radios.spec.js b/front/tests/unit/specs/store/radios.spec.js
index ff14f6145cd91a2326f01b3967bac82cb1f66797..512b0fc3f4ebb6d4b23703e6f8619ba81e34f479 100644
--- a/front/tests/unit/specs/store/radios.spec.js
+++ b/front/tests/unit/specs/store/radios.spec.js
@@ -58,6 +58,7 @@ describe('store/radios', () => {
     it('stop', () => {
       return testAction({
         action: store.actions.stop,
+        params: {state: {}},
         expectedMutations: [
           { type: 'current', payload: null },
           { type: 'running', payload: false }