feat: keep Japanese in main tags, romaji in sort tags + frontend toggle
- Downloads now store original Japanese in TITLE/ARTIST/ALBUM tags so Apple Music, iTunes, YTM etc. all see the authentic original text - Sort tags (TITLESORT/ARTISTSORT/ALBUMSORT) written with romaji for apps that use them for sorting/display - iTunes-resolved English artist name used for ARTISTSORT and folder names when available (more accurate than kuromoji for known artists) - rawArtist parameter added to downloadTrack so YTM search query uses the original Japanese channel name (fixes wrong song downloads) - spotify.js: artistName preserved as original; itunesArtistName stored separately so the Spotify importer shows Japanese titles - romaji index now includes titleRomaji/artistRomaji/albumRomaji fields - Frontend: showRomaji setting (Settings > Bibliothek) — when on, player bar, now-playing, queue, and song lists all show romaji via index lookup - refreshDisplayMode() updates all live UI when the toggle is saved Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
f1eabf7099
commit
1aff19e319
10 files changed
+140
-55
No files matched your search
@@ -373,7 +373,7 @@ app.post('/api/download', async (req, res) => {
|
||||
log(jobId, `📋 Album aus Spotify: "${meta.album}"`);
|
||||
}
|
||||
const finalArtist = meta.itunesArtistName || artist;
|
||||
const result = await downloadTrack({ jobId, artist: finalArtist, title, ...meta, sourceUrl: sourceUrl || sp.sourceUrl || undefined });
|
||||
const result = await downloadTrack({ jobId, artist: finalArtist, rawArtist: artist, title, ...meta, sourceUrl: sourceUrl || sp.sourceUrl || undefined });
|
||||
if (result?.skipped) {
|
||||
updateJob(jobId, { status: 'done', progress: 100, message: 'Bereits vorhanden – übersprungen', skipped: true });
|
||||
} else {
|
||||
@@ -447,10 +447,13 @@ app.post('/api/download', async (req, res) => {
|
||||
log(jobId, `📋 iTunes: "${trackArtist} – ${trackTitle}"`);
|
||||
itunes = await lookupItunesTrackMeta(searchArtist, trackTitle);
|
||||
}
|
||||
const resolvedArtist = itunes.itunesArtistName || trackArtist;
|
||||
// Prefer iTunes-resolved name (from server lookup or frontend enrichment) for sort tags / folders.
|
||||
// trackArtist stays as rawArtist for main tags and YTM search.
|
||||
const resolvedArtist = itunes.itunesArtistName || track.itunesArtistName || trackArtist;
|
||||
return downloadTrack({
|
||||
jobId,
|
||||
artist: resolvedArtist,
|
||||
artist: resolvedArtist, // iTunes English name → used for sort tags + folder names
|
||||
rawArtist: trackArtist, // original Spotify/Japanese name → used for main tag + YTM search
|
||||
albumArtist: resolvedArtist,
|
||||
title: trackTitle,
|
||||
album: itunes.album || track.collectionName || track.album || '',
|
||||
@@ -689,11 +692,18 @@ app.post('/api/edit-metadata', async (req, res) => {
|
||||
ffArgs.push('-map', '0:v?'); // '?' = optional, no error if file has no cover
|
||||
}
|
||||
ffArgs.push('-c', 'copy', '-map_metadata', '-1', '-id3v2_version', '3');
|
||||
if (romajiTitle) ffArgs.push('-metadata', `title=${romajiTitle}`);
|
||||
if (romajiArtist) ffArgs.push('-metadata', `artist=${romajiArtist}`);
|
||||
const resolvedAlbumArtist = romajiAlbumArtist || (romajiArtist ? romajiArtist.split(';')[0].trim() : null);
|
||||
if (resolvedAlbumArtist) ffArgs.push('-metadata', `album_artist=${resolvedAlbumArtist}`);
|
||||
if (romajiAlbum) ffArgs.push('-metadata', `album=${romajiAlbum}`);
|
||||
// Main tags: store original user input (may be Japanese — Apple Music / other apps see authentic text)
|
||||
if (title) ffArgs.push('-metadata', `title=${title}`);
|
||||
if (normalArtist) ffArgs.push('-metadata', `artist=${normalArtist}`);
|
||||
const resolvedAlbumArtist = normalAlbumArtist || (normalArtist ? normalArtist.split(';')[0].trim() : null);
|
||||
if (resolvedAlbumArtist) ffArgs.push('-metadata', `album_artist=${resolvedAlbumArtist}`);
|
||||
if (album) ffArgs.push('-metadata', `album=${album}`);
|
||||
// Sort tags: romaji versions for apps that use them for sorting / display
|
||||
if (romajiTitle && romajiTitle !== title) ffArgs.push('-metadata', `TITLESORT=${romajiTitle}`);
|
||||
if (romajiArtist && romajiArtist !== normalArtist) ffArgs.push('-metadata', `ARTISTSORT=${romajiArtist}`);
|
||||
const resolvedRomajiAA = romajiAlbumArtist || (romajiArtist ? romajiArtist.split(';')[0].trim() : null);
|
||||
if (resolvedRomajiAA && resolvedRomajiAA !== resolvedAlbumArtist) ffArgs.push('-metadata', `ALBUMARTISTSORT=${resolvedRomajiAA}`);
|
||||
if (romajiAlbum && romajiAlbum !== album) ffArgs.push('-metadata', `ALBUMSORT=${romajiAlbum}`);
|
||||
if (year) ffArgs.push('-metadata', `date=${year}`);
|
||||
if (trackNum) ffArgs.push('-metadata', `track=${totalTracks ? `${trackNum}/${totalTracks}` : String(trackNum)}`);
|
||||
if (totalTracks) ffArgs.push('-metadata', `totaltracks=${String(totalTracks)}`);
|
||||
|
||||
Reference in new issue
Block a user