diff --git a/front/src/components/audio/PlayButton.vue b/front/src/components/audio/PlayButton.vue
index dcb1c507e121441aa9712aaca403f8dcc5759861..521a66f8715d0fce86e569ea1c2daa41e20630f6 100644
--- a/front/src/components/audio/PlayButton.vue
+++ b/front/src/components/audio/PlayButton.vue
@@ -79,10 +79,14 @@ export default {
         return true
       }
       if (this.track) {
-        return this.track.is_playable
+        return this.track.uploads && this.track.uploads.length > 0
+      } else if (this.artist) {
+        return this.albums.filter((a) => {
+          return a.is_playable === true
+        }).length > 0
       } else if (this.tracks) {
         return this.tracks.filter((t) => {
-          return t.is_playable
+          return t.uploads && t.uploads.length > 0
         }).length > 0
       }
       return false
@@ -139,7 +143,7 @@ export default {
           self.isLoading = false
         }, 250)
         return tracks.filter(e => {
-          return e.is_playable === true
+          return e.uploads && e.uploads.length > 0
         })
       })
     },
diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue
index 1d622f33055ab9e7d0165fda1bc9781aa01da046..80c54bbb2d9ad0f41174894e1a13611fee28250d 100644
--- a/front/src/components/audio/Player.vue
+++ b/front/src/components/audio/Player.vue
@@ -4,6 +4,7 @@
       <audio-track
         ref="currentAudio"
         v-if="currentTrack"
+        @errored="handleError"
         :is-current="true"
         :start-time="$store.state.player.currentTime"
         :autoplay="$store.state.player.playing"
@@ -41,13 +42,13 @@
           </div>
         </div>
       </div>
-      <div class="progress-area" v-if="currentTrack">
+      <div class="progress-area" v-if="currentTrack && !errored">
         <div class="ui grid">
           <div class="left floated four wide column">
             <p class="timer start" @click="updateProgress(0)">{{currentTimeFormatted}}</p>
           </div>
 
-          <div class="right floated four wide column">
+          <div v-if="!isLoadingAudio" class="right floated four wide column">
             <p class="timer total">{{durationFormatted}}</p>
           </div>
         </div>
@@ -59,7 +60,18 @@
           <div class="bar" :data-percent="progress" :style="{ 'width': progress + '%' }"></div>
         </div>
       </div>
-
+      <div class="ui small warning message" v-if="currentTrack && errored">
+        <div class="header">
+          <translate>We cannot load this track</translate>
+        </div>
+        <p v-if="hasNext && playing && $store.state.player.errorCount < $store.state.player.maxConsecutiveErrors">
+          <translate>The next track will play automatically in a few seconds...</translate>
+          <i class="loading spinner icon"></i>
+        </p>
+        <p>
+          <translate>You may have a connectivity issue.</translate>
+        </p>
+      </div>
       <div class="two wide column controls ui grid">
         <a
           href
@@ -299,6 +311,10 @@ export default {
       }
       let image = this.$refs.cover
       this.ambiantColors = ColorThief.prototype.getPalette(image, 4).slice(0, 4)
+    },
+    handleError ({sound, error}) {
+      this.$store.commit('player/isLoadingAudio', false)
+      this.$store.dispatch('player/trackErrored')
     }
   },
   computed: {
@@ -310,6 +326,7 @@ export default {
       looping: state => state.player.looping,
       duration: state => state.player.duration,
       bufferProgress: state => state.player.bufferProgress,
+      errored: state => state.player.errored,
       queue: state => state.queue
     }),
     ...mapGetters({
diff --git a/front/src/components/audio/Track.vue b/front/src/components/audio/Track.vue
index 32eb62722da88bddb40cdca68dae137059f18b59..c847d4de1a69f3f6cd1e6937e580d8ddf23332da 100644
--- a/front/src/components/audio/Track.vue
+++ b/front/src/components/audio/Track.vue
@@ -46,12 +46,17 @@ export default {
       onload: function () {
         self.$store.commit('player/isLoadingAudio', false)
         self.$store.commit('player/resetErrorCount')
+        self.$store.commit('player/errored', false)
         self.$store.commit('player/duration', self.sound.duration())
         let node = self.sound._sounds[0]._node;
         node.addEventListener('progress', () => {
           self.updateBuffer(node)
         })
-      }
+      },
+      onloaderror: function (sound, error) {
+        console.log('Error while playing:', sound, error)
+        self.$emit('errored', {sound, error})
+      },
     })
     if (this.autoplay) {
       self.$store.commit('player/isLoadingAudio', true)
@@ -73,14 +78,23 @@ export default {
       looping: state => state.player.looping
     }),
     srcs: function () {
-      // let file = this.track.files[0]
-      // if (!file) {
-      //   this.$store.dispatch('player/trackErrored')
-      //   return []
-      // }
-      let sources = [
-        {type: 'mp3', url: this.$store.getters['instance/absoluteUrl'](this.track.listen_url)}
-      ]
+      let sources = this.track.uploads.map(u => {
+        return {
+          type: u.extension,
+          url: this.$store.getters['instance/absoluteUrl'](u.listen_url),
+        }
+      })
+      // We always add a transcoded MP3 src at the end
+      // because transcoding is expensive, but we want browsers that do
+      // not support other codecs to be able to play it :)
+      sources.push({
+        type: 'mp3',
+        url: url.updateQueryString(
+          this.$store.getters['instance/absoluteUrl'](this.track.listen_url),
+          'to',
+          'mp3'
+        )
+      })
       if (this.$store.state.auth.authenticated) {
         // we need to send the token directly in url
         // so authentication can be checked by the backend
diff --git a/front/src/components/audio/track/Row.vue b/front/src/components/audio/track/Row.vue
index b17cf117073190f767e82894de09d12106712d47..fd8b2daaf134473aff45cef895b104bc3a7f6ba7 100644
--- a/front/src/components/audio/track/Row.vue
+++ b/front/src/components/audio/track/Row.vue
@@ -34,8 +34,8 @@
         {{ track.album.title }}
       </router-link>
     </td>
-    <td colspan="4" v-if="track.duration">
-      {{ time.parse(track.duration) }}
+    <td colspan="4" v-if="track.uploads && track.uploads.length > 0">
+      {{ time.parse(track.uploads[0].duration) }}
     </td>
     <td colspan="4" v-else>
       <translate>N/A</translate>
diff --git a/front/src/components/library/Track.vue b/front/src/components/library/Track.vue
index 483ff66739f582b3facd15237879c9321ae1c841..ddccda397352bc578999608489f153519f332fe8 100644
--- a/front/src/components/library/Track.vue
+++ b/front/src/components/library/Track.vue
@@ -44,13 +44,13 @@
             <i class="external icon"></i>
             <translate>View on MusicBrainz</translate>
           </a>
-          <a v-if="track.is_playable" :href="downloadUrl" target="_blank" class="ui button">
+          <a v-if="upload" :href="downloadUrl" target="_blank" class="ui button">
             <i class="download icon"></i>
             <translate>Download</translate>
           </a>
         </div>
       </div>
-      <div class="ui vertical stripe center aligned segment">
+      <div class="ui vertical stripe center aligned segment" v-if="upload">
         <h2 class="ui header"><translate>Track information</translate></h2>
         <table class="ui very basic collapsing celled center aligned table">
           <tbody>
@@ -58,8 +58,8 @@
               <td>
                 <translate>Duration</translate>
               </td>
-              <td v-if="track.duration">
-                {{ time.parse(track.duration) }}
+              <td v-if="upload.duration">
+                {{ time.parse(upload.duration) }}
               </td>
               <td v-else>
                 <translate>N/A</translate>
@@ -69,8 +69,8 @@
               <td>
                 <translate>Size</translate>
               </td>
-              <td v-if="track.size">
-                {{ track.size | humanSize }}
+              <td v-if="upload.size">
+                {{ upload.size | humanSize }}
               </td>
               <td v-else>
                 <translate>N/A</translate>
@@ -80,8 +80,8 @@
               <td>
                 <translate>Bitrate</translate>
               </td>
-              <td v-if="track.bitrate">
-                {{ track.bitrate | humanSize }}/s
+              <td v-if="upload.bitrate">
+                {{ upload.bitrate | humanSize }}/s
               </td>
               <td v-else>
                 <translate>N/A</translate>
@@ -91,8 +91,8 @@
               <td>
                 <translate>Type</translate>
               </td>
-              <td v-if="track.mimetype">
-                {{ track.mimetype }}
+              <td v-if="upload.extension">
+                {{ upload.extension }}
               </td>
               <td v-else>
                 <translate>N/A</translate>
@@ -195,6 +195,11 @@ export default {
         title: this.$gettext('Track')
       }
     },
+    upload () {
+      if (this.track.uploads) {
+        return this.track.uploads[0]
+      }
+    },
     wikipediaUrl () {
       return 'https://en.wikipedia.org/w/index.php?search=' + encodeURI(this.track.title + ' ' + this.track.artist.name)
     },
@@ -204,7 +209,7 @@ export default {
       }
     },
     downloadUrl () {
-      let u = this.$store.getters['instance/absoluteUrl'](this.track.listen_url)
+      let u = this.$store.getters['instance/absoluteUrl'](this.upload.listen_url)
       if (this.$store.state.auth.authenticated) {
         u = url.updateQueryString(u, 'jwt', encodeURI(this.$store.state.auth.token))
       }
diff --git a/front/src/store/index.js b/front/src/store/index.js
index 051e89b39e11291f7b303056399faa56e8abed15..0b8eb3321c27b00d8c31498ad602de7f9617c49a 100644
--- a/front/src/store/index.js
+++ b/front/src/store/index.js
@@ -79,6 +79,7 @@ export default new Vuex.Store({
                 id: track.id,
                 title: track.title,
                 mbid: track.mbid,
+                uploads: track.uploads,
                 listen_url: track.listen_url,
                 album: {
                   id: track.album.id,
diff --git a/front/src/store/player.js b/front/src/store/player.js
index 08492541ea6380645b16ab39402a3200e692c1a4..fac17368d10377b959fb98520f242eb2f77f4aa2 100644
--- a/front/src/store/player.js
+++ b/front/src/store/player.js
@@ -95,10 +95,19 @@ export default {
     incrementVolume ({commit, state}, value) {
       commit('volume', state.volume + value)
     },
-    stop (context) {
+    stop ({commit}) {
+      commit('errored', false)
+      commit('resetErrorCount')
     },
-    togglePlay ({commit, state}) {
+    togglePlay ({commit, state, dispatch}) {
       commit('playing', !state.playing)
+      if (state.errored && state.errorCount < state.maxConsecutiveErrors) {
+        setTimeout(() => {
+          if (state.playing) {
+            dispatch('queue/next', null, {root: true})
+          }
+        }, 3000)
+      }
     },
     trackListened ({commit, rootState}, track) {
       if (!rootState.auth.authenticated) {
@@ -121,7 +130,13 @@ export default {
     trackErrored ({commit, dispatch, state}) {
       commit('errored', true)
       commit('incrementErrorCount')
-      dispatch('queue/next', null, {root: true})
+      if (state.errorCount < state.maxConsecutiveErrors) {
+        setTimeout(() => {
+          if (state.playing) {
+            dispatch('queue/next', null, {root: true})
+          }
+        }, 3000)
+      }
     },
     updateProgress ({commit}, t) {
       commit('currentTime', t)
diff --git a/front/src/store/queue.js b/front/src/store/queue.js
index b6edb2242a3d09092baacf3b5b3af817bc9695dd..81403b11fa6d77d2e5332a77ed12ba3023d3f00e 100644
--- a/front/src/store/queue.js
+++ b/front/src/store/queue.js
@@ -142,7 +142,6 @@ export default {
       commit('ended', false)
       commit('player/currentTime', 0, {root: true})
       commit('player/playing', true, {root: true})
-      commit('player/errored', false, {root: true})
       commit('currentIndex', index)
       if (state.tracks.length - index <= 2 && rootState.radios.running) {
         dispatch('radios/populateQueue', null, {root: true})
diff --git a/front/tests/unit/specs/store/queue.spec.js b/front/tests/unit/specs/store/queue.spec.js
index 373f4938e034864d65db318ba82a550fdcc012c4..282a4f02633758d878f7a89106844b6981fcccfd 100644
--- a/front/tests/unit/specs/store/queue.spec.js
+++ b/front/tests/unit/specs/store/queue.spec.js
@@ -267,7 +267,6 @@ describe('store/queue', () => {
           { type: 'ended', payload: false },
           { type: 'player/currentTime', payload: 0, options: {root: true} },
           { type: 'player/playing', payload: true, options: {root: true} },
-          { type: 'player/errored', payload: false, options: {root: true} },
           { type: 'currentIndex', payload: 1 }
         ]
       })
@@ -281,7 +280,6 @@ describe('store/queue', () => {
           { type: 'ended', payload: false },
           { type: 'player/currentTime', payload: 0, options: {root: true} },
           { type: 'player/playing', payload: true, options: {root: true} },
-          { type: 'player/errored', payload: false, options: {root: true} },
           { type: 'currentIndex', payload: 1 }
         ]
       })
@@ -295,7 +293,6 @@ describe('store/queue', () => {
           { type: 'ended', payload: false },
           { type: 'player/currentTime', payload: 0, options: {root: true} },
           { type: 'player/playing', payload: true, options: {root: true} },
-          { type: 'player/errored', payload: false, options: {root: true} },
           { type: 'currentIndex', payload: 1 }
         ],
         expectedActions: [