feat: add album artist field to metadata editor

Adds an editable Album-Künstler input to the info modal. Populated from
Navidrome's albumArtist field on open; saved as album_artist tag via
ffmpeg. Explicit value takes precedence; falls back to deriving from
artist (first semicolon segment) when artist is changed without an
explicit albumArtist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-05-23 21:50:45 +02:00
1 parent 4da1fb25e2
commit 3df1990d41
3 files changed
+7 -2

No files matched your search

+4 -2
View File
@@ -516,7 +516,7 @@ app.get('/api/musicbrainz/lookup', async (req, res) => {
// ─── METADATA EDIT ───────────────────────────────────────────────────────────
app.post('/api/edit-metadata', async (req, res) => {
const { ndUrl, user, pass, songId, title, artist, album, year, trackNum, totalTracks,
const { ndUrl, user, pass, songId, title, artist, albumArtist, album, year, trackNum, totalTracks,
discNum, discTotal, genre, artworkBase64, artworkMime, artworkUrl: newArtworkUrl } = req.body;
if (!ndUrl || !user || !pass || !songId) return res.status(400).json({ error: 'ndUrl, user, pass, songId required' });
@@ -583,7 +583,9 @@ app.post('/api/edit-metadata', async (req, res) => {
}
ffArgs.push('-c', 'copy', '-map_metadata', '-1', '-id3v2_version', '3');
if (title) ffArgs.push('-metadata', `title=${title}`);
if (artist) ffArgs.push('-metadata', `artist=${artist}`, '-metadata', `album_artist=${artist.split(';')[0].trim()}`);
if (artist) ffArgs.push('-metadata', `artist=${artist}`);
const resolvedAlbumArtist = albumArtist || (artist ? artist.split(';')[0].trim() : null);
if (resolvedAlbumArtist) ffArgs.push('-metadata', `album_artist=${resolvedAlbumArtist}`);
if (album) ffArgs.push('-metadata', `album=${album}`);
if (year) ffArgs.push('-metadata', `date=${year}`);
if (trackNum) ffArgs.push('-metadata', `track=${totalTracks ? `${trackNum}/${totalTracks}` : String(trackNum)}`);
+1
View File
@@ -917,6 +917,7 @@
<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-Künstler<input class="info-edit-input" id="ie-albumartist" type="text" placeholder="Album-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">
+2
View File
@@ -304,6 +304,7 @@ export function toggleInfoEdit() {
// Populate fields from current song
document.getElementById('ie-title').value = s.title || '';
document.getElementById('ie-artist').value = s.artist || '';
document.getElementById('ie-albumartist').value = s.albumArtist || '';
document.getElementById('ie-album').value = s.album || '';
document.getElementById('ie-genre').value = s.genre || '';
document.getElementById('ie-year').value = s.year || '';
@@ -383,6 +384,7 @@ export async function saveMetadata() {
songId: s.id,
title: document.getElementById('ie-title').value || undefined,
artist: document.getElementById('ie-artist').value || undefined,
albumArtist: document.getElementById('ie-albumartist').value || undefined,
album: document.getElementById('ie-album').value || undefined,
genre: document.getElementById('ie-genre').value || undefined,
year: parseInt(document.getElementById('ie-year').value) || undefined,