Index: src/views/pages/admin-audio.ejs
===================================================================
--- src/views/pages/admin-audio.ejs	(revision 2306abdfb3a163d47caa1823506ffc4c8471ba3e)
+++ src/views/pages/admin-audio.ejs	(revision 4d1aefb82ba603538d5016a9dfbb387a9b269872)
@@ -1,5 +1,5 @@
 <div class="container ax-page">
 
-  <p><a href="/admin" class="btn">&larr; <%= t('nav.admin') %></a></p>
+  <p><a href="/admin" class="btn">&larr; <%= t('nav.admin') %></a> <a href="/admin/playlists" class="btn">🎵 <%= t('admin.b_playlists') %></a></p>
   <header class="ax-header">
     <div>
Index: src/views/partials/track-editor.ejs
===================================================================
--- src/views/partials/track-editor.ejs	(revision 2306abdfb3a163d47caa1823506ffc4c8471ba3e)
+++ src/views/partials/track-editor.ejs	(revision 4d1aefb82ba603538d5016a9dfbb387a9b269872)
@@ -440,4 +440,13 @@
 
             <div class="te-field">
+              <span>Audiobestand</span>
+              <div class="te-cover-btn-row">
+                <input type="file" id="te-audio-file" accept="audio/*,.mp3,.wav,.m4a,.flac,.ogg,.aac" hidden>
+                <button type="button" class="te-cover-btn" id="te-audio-pick">${track.stream_url ? '🔁 Vervang audiobestand' : '🎵 Audiobestand kiezen'}</button>
+                <span class="te-cover-status" id="te-audio-status"></span>
+              </div>
+            </div>
+
+            <div class="te-field">
               <span>Cover</span>
               <div class="te-cover-row">
@@ -636,4 +645,30 @@
     }
 
+    // ── Replace the audio file of this track ──────────────────
+    const aPick = $('#te-audio-pick');
+    const aFile = $('#te-audio-file');
+    const aStatus = $('#te-audio-status');
+    if (aPick && aFile) {
+      aPick.addEventListener('click', () => aFile.click());
+      aFile.addEventListener('change', async (e) => {
+        const f = e.target.files && e.target.files[0];
+        aFile.value = '';
+        if (!f) return;
+        aStatus.textContent = '⏳ Converteren… (kan even duren)'; aStatus.className = 'te-cover-status';
+        aPick.disabled = true;
+        try {
+          const fd = new FormData();
+          fd.append('audio', f);
+          const j = await api('POST', '/admin/audio/api/' + encodeURIComponent(id) + '/replace-audio', fd);
+          if (!j.ok) throw new Error(j.error || 'mislukt');
+          aStatus.textContent = '✓ Vervangen'; aStatus.className = 'te-cover-status is-ok';
+          track.stream_url = j.stream_url || track.stream_url;
+          if (j.duration) { const d = $('#te-duration'); if (d) d.value = j.duration; }
+        } catch (err) {
+          aStatus.textContent = 'Mislukt: ' + err.message; aStatus.className = 'te-cover-status is-error';
+        } finally { aPick.disabled = false; }
+      });
+    }
+
     // ── Insert © symbol into the credit field ─────────────────
     const copyrBtn = $('#te-credit-copyr');
