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

+12 -1
View File
@@ -465,7 +465,7 @@ button:focus{outline:none}
/* ── SONG INFO MODAL ── */
.info-modal{position:fixed;inset:0;background:rgba(0,0,0,.65);backdrop-filter:blur(4px);z-index:400;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .2s}
.info-modal.open{opacity:1;pointer-events:all}
.info-modal .inner{width:min(420px,calc(100vw - 32px));background:var(--surface);border:1px solid var(--border2);border-radius:16px;padding:0;overflow:hidden;box-shadow:0 32px 64px rgba(0,0,0,.7)}
.info-modal .inner{width:min(420px,calc(100vw - 32px));max-height:calc(100vh - 48px);background:var(--surface);border:1px solid var(--border2);border-radius:16px;padding:0;overflow-y:auto;box-shadow:0 32px 64px rgba(0,0,0,.7)}
.info-header{display:flex;gap:16px;padding:20px;background:var(--bg2)}
.info-cover{width:80px;height:80px;border-radius:8px;overflow:hidden;background:var(--surface2);flex-shrink:0}
.info-cover img{width:100%;height:100%;object-fit:cover}
@@ -478,6 +478,17 @@ button:focus{outline:none}
.info-val{color:var(--text);text-align:right;word-break:break-all}
.info-close{display:block;width:calc(100% - 40px);margin:0 20px 20px;padding:11px;border-radius:9px;background:var(--surface2);border:none;font-family:var(--font);font-size:14px;font-weight:600;color:var(--text);cursor:pointer}
.info-close:hover{background:var(--surface)}
.info-edit-toggle{background:none;border:none;color:var(--text2);cursor:pointer;padding:4px;border-radius:6px;display:flex;align-items:center;flex-shrink:0;align-self:flex-start;margin-top:2px}
.info-edit-toggle:hover,.info-edit-toggle.active{color:var(--accent)}
.info-edit-art-row{display:flex;align-items:center;gap:12px;padding:0 20px 12px}
.info-edit-art-wrap{display:flex;flex-direction:column;align-items:center;gap:6px}
.info-edit-art-preview{width:72px;height:72px;border-radius:8px;overflow:hidden;background:var(--surface2);flex-shrink:0}
.info-edit-art-btn{font-size:11px;color:var(--text2);background:var(--surface2);border:none;border-radius:6px;padding:4px 8px;cursor:pointer;display:flex;align-items:center;gap:4px;font-family:var(--font)}
.info-edit-art-btn:hover{color:var(--text)}
.info-edit-fields{display:flex;flex-direction:column;gap:8px;padding:0 20px 4px}
.info-edit-label{display:flex;flex-direction:column;font-size:11px;color:var(--text3);gap:3px;font-weight:500}
.info-edit-input{background:var(--surface2);border:1px solid var(--border2);border-radius:7px;color:var(--text);font-family:var(--font);font-size:13px;padding:7px 10px;outline:none;width:100%;box-sizing:border-box}
.info-edit-input:focus{border-color:var(--accent)}
/* ── BOTTOM NAV (PWA Mobile) ── */