feat: metadata editor with MusicBrainz autofill + cover art upload

- Info modal gets an edit pencil button that switches to edit form
- Editable fields: title, artist, album, genre, year, track#, disc#, total tracks
- Cover art: upload your own image or auto-fetch from Cover Art Archive via MusicBrainz
- MusicBrainz button queries /api/musicbrainz/lookup and autofills all fields
- Save POSTs to /api/edit-metadata which rewrites tags via ffmpeg and triggers Navidrome rescan
- Backend: GET /api/musicbrainz/lookup + POST /api/edit-metadata endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-23 19:22:11 +02:00
1 parent 1a44f8bd73
commit 5559857c15
6 files changed
+345 -12

No files matched your search

+45 -3
View File
@@ -868,10 +868,52 @@
<div class="inner">
<div class="info-header">
<div class="info-cover" id="info-cover"><div class="no-art" style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:32px">🎵</div></div>
<div><div class="info-top-title" id="info-top-title">—</div><div class="info-top-sub" id="info-top-sub">—</div></div>
<div style="flex:1;min-width:0"><div class="info-top-title" id="info-top-title">—</div><div class="info-top-sub" id="info-top-sub">—</div></div>
<button class="info-edit-toggle" id="info-edit-toggle" onclick="toggleInfoEdit()" title="Bearbeiten">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
</button>
</div>
<!-- VIEW MODE -->
<div id="info-view-mode">
<div class="info-rows" id="info-rows"></div>
<button class="info-close" onclick="closeInfoModal()">Schließen</button>
</div>
<!-- EDIT MODE -->
<div id="info-edit-mode" style="display:none">
<div class="info-edit-art-row">
<div class="info-edit-art-wrap">
<div class="info-cover info-edit-art-preview" id="info-edit-art-preview"></div>
<button class="info-edit-art-btn" onclick="document.getElementById('info-art-file').click()" title="Bild hochladen">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
Upload
</button>
<input type="file" id="info-art-file" accept="image/*" style="display:none" onchange="onInfoArtFile(this)">
</div>
<button class="btn-outline blue" style="font-size:11px;padding:6px 10px;height:fit-content" onclick="autofillMusicBrainz()">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right:4px"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
MusicBrainz
</button>
</div>
<div class="info-edit-fields">
<label class="info-edit-label">Titel<input class="info-edit-input" id="ie-title" type="text" placeholder="Titel"></label>
<label class="info-edit-label">Künstler<input class="info-edit-input" id="ie-artist" type="text" placeholder="Künstler (mit ; trennen)"></label>
<label class="info-edit-label">Album<input class="info-edit-input" id="ie-album" type="text" placeholder="Album"></label>
<label class="info-edit-label">Genre<input class="info-edit-input" id="ie-genre" type="text" placeholder="Genre"></label>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
<label class="info-edit-label">Jahr<input class="info-edit-input" id="ie-year" type="number" placeholder="2024" min="1900" max="2099"></label>
<label class="info-edit-label">Track #<input class="info-edit-input" id="ie-track" type="number" placeholder="1" min="1"></label>
<label class="info-edit-label">Disc #<input class="info-edit-input" id="ie-disc" type="number" placeholder="1" min="1"></label>
<label class="info-edit-label">Tracks ges.<input class="info-edit-input" id="ie-totaltracks" type="number" placeholder="12" min="1"></label>
</div>
</div>
<div id="info-edit-status" style="font-size:12px;color:var(--text3);padding:0 20px 8px;min-height:18px"></div>
<div style="display:flex;gap:8px;padding:0 20px 20px">
<button class="info-close" style="flex:1;margin:0" onclick="toggleInfoEdit()">Abbrechen</button>
<button class="info-close" style="flex:1;margin:0;background:var(--accent);color:#fff" onclick="saveMetadata()">Speichern</button>
</div>
</div>
<div class="info-rows" id="info-rows"></div>
<button class="info-close" onclick="closeInfoModal()">Schließen</button>
</div>
</div>