feat(playlists): confirm before adding songs that are already in the playlist (#329)

Closes #327.

When every selected song is already in the target playlist, the
"Add to Playlist" flow used to silently show an "all skipped" toast.
Users could not tell whether they had hit the wrong target or whether
the action was deliberately ignored, and they had no way to add
duplicates intentionally (e.g. for a song they actually want twice).

New behavior: if every id is a duplicate, ask via the existing
GlobalConfirmModal — "Add anyway" appends them as duplicates,
"Cancel" keeps the previous silent-skip toast.

Mixed cases (some new, some duplicate) and the all-new path are
unchanged. Applied at all three add-to-playlist call sites in the
context menu (single/multi-track, album selection, artist selection).
Strings added to all 8 locales (en, de, es, fr, nl, nb, ru, zh).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Frank Stellmacher
2026-04-26 22:13:13 +02:00
committed by GitHub
parent 9fe81ee6f6
commit e0c53da94d
9 changed files with 122 additions and 49 deletions
+4
View File
@@ -1309,6 +1309,10 @@ export const deTranslation = {
addSuccess: '{{count}} Songs zu {{playlist}} hinzugefügt',
addPartial: '{{added}} hinzugefügt, {{skipped}} übersprungen (Duplikate)',
addAllSkipped: 'Alle übersprungen ({{count}} Duplikate)',
addedAsDuplicates: '{{count}} Songs zu {{playlist}} hinzugefügt (als Duplikate)',
duplicateConfirmTitle: 'Bereits in Playlist',
duplicateConfirmMessage: 'Alle {{count}} Songs sind bereits in "{{playlist}}". Trotzdem als Duplikate hinzufügen?',
duplicateConfirmAction: 'Trotzdem hinzufügen',
addError: 'Fehler beim Hinzufügen von Songs',
createAndAddSuccess: 'Playlist "{{playlist}}" mit {{count}} Songs erstellt',
createError: 'Fehler beim Erstellen der Playlist',
+4
View File
@@ -1315,6 +1315,10 @@ export const enTranslation = {
addSuccess: '{{count}} songs added to {{playlist}}',
addPartial: '{{added}} added, {{skipped}} skipped (duplicates)',
addAllSkipped: 'All skipped ({{count}} duplicates)',
addedAsDuplicates: '{{count}} songs added to {{playlist}} (as duplicates)',
duplicateConfirmTitle: 'Already in playlist',
duplicateConfirmMessage: 'All {{count}} songs are already in "{{playlist}}". Add them again as duplicates?',
duplicateConfirmAction: 'Add anyway',
addError: 'Error adding songs',
createAndAddSuccess: 'Playlist "{{playlist}}" created with {{count}} songs',
createError: 'Error creating playlist',
+4
View File
@@ -1302,6 +1302,10 @@ export const esTranslation = {
addSuccess: '{{count}} canciones agregadas a {{playlist}}',
addPartial: '{{added}} agregadas, {{skipped}} skippeadas por duplicadas',
addAllSkipped: 'Todas skippeadas ({{count}} duplicadas)',
addedAsDuplicates: '{{count}} canciones añadidas a {{playlist}} (como duplicados)',
duplicateConfirmTitle: 'Ya en la lista',
duplicateConfirmMessage: 'Las {{count}} canciones ya están en "{{playlist}}". ¿Añadirlas igualmente como duplicados?',
duplicateConfirmAction: 'Añadir igualmente',
addError: 'Error al agregar canciones',
createAndAddSuccess: 'Lista "{{playlist}}" creada con {{count}} canciones',
createError: 'Error al crear lista',
+4
View File
@@ -1297,6 +1297,10 @@ export const frTranslation = {
addSuccess: '{{count}} morceaux ajoutés à {{playlist}}',
addPartial: '{{added}} ajoutés, {{skipped}} ignorés (doublons)',
addAllSkipped: 'Tous ignorés ({{count}} doublons)',
addedAsDuplicates: '{{count}} morceaux ajoutés à {{playlist}} (en doublons)',
duplicateConfirmTitle: 'Déjà dans la playlist',
duplicateConfirmMessage: 'Les {{count}} morceaux sont déjà dans « {{playlist}} ». Les ajouter quand même en doublons ?',
duplicateConfirmAction: 'Ajouter quand même',
addError: 'Erreur lors de l\'ajout des morceaux',
createAndAddSuccess: 'Playlist "{{playlist}}" créée avec {{count}} morceaux',
createError: 'Erreur lors de la création de la playlist',
+4
View File
@@ -1296,6 +1296,10 @@ export const nbTranslation = {
addSuccess: '{{count}} sanger lagt til i {{playlist}}',
addPartial: '{{added}} lagt til, {{skipped}} hoppet over (duplikater)',
addAllSkipped: 'Alle hoppet over ({{count}} duplikater)',
addedAsDuplicates: '{{count}} sanger lagt til i {{playlist}} (som duplikater)',
duplicateConfirmTitle: 'Allerede i spillelisten',
duplicateConfirmMessage: 'Alle {{count}} sanger finnes allerede i "{{playlist}}". Legg dem til likevel som duplikater?',
duplicateConfirmAction: 'Legg til likevel',
addError: 'Feil ved å legge til sanger',
createAndAddSuccess: 'Spilleliste "{{playlist}}" opprettet med {{count}} sanger',
createError: 'Feil ved oppretting av spilleliste',
+4
View File
@@ -1296,6 +1296,10 @@ export const nlTranslation = {
addSuccess: '{{count}} nummers toegevoegd aan {{playlist}}',
addPartial: '{{added}} toegevoegd, {{skipped}} overgeslagen (duplicaten)',
addAllSkipped: 'Alles overgeslagen ({{count}} duplicaten)',
addedAsDuplicates: '{{count}} nummers toegevoegd aan {{playlist}} (als duplicaten)',
duplicateConfirmTitle: 'Al in afspeellijst',
duplicateConfirmMessage: 'Alle {{count}} nummers staan al in "{{playlist}}". Toch als duplicaten toevoegen?',
duplicateConfirmAction: 'Toch toevoegen',
addError: 'Fout bij toevoegen van nummers',
createAndAddSuccess: 'Playlist "{{playlist}}" aangemaakt met {{count}} nummers',
createError: 'Fout bij aanmaken van playlist',
+4
View File
@@ -1381,6 +1381,10 @@ export const ruTranslation = {
addSuccess: '{{count}} треков добавлено в {{playlist}}',
addPartial: '{{added}} добавлено, {{skipped}} пропущено (дубликаты)',
addAllSkipped: 'Все пропущены ({{count}} дубликатов)',
addedAsDuplicates: '{{count}} треков добавлено в {{playlist}} (как дубликаты)',
duplicateConfirmTitle: 'Уже в плейлисте',
duplicateConfirmMessage: 'Все {{count}} треков уже есть в «{{playlist}}». Всё равно добавить их как дубликаты?',
duplicateConfirmAction: 'Всё равно добавить',
addError: 'Ошибка при добавлении треков',
createAndAddSuccess: 'Плейлист "{{playlist}}" создан с {{count}} треками',
createError: 'Ошибка при создании плейлиста',
+4
View File
@@ -1291,6 +1291,10 @@ export const zhTranslation = {
addSuccess: '{{count}} 首歌曲已添加到 {{playlist}}',
addPartial: '{{added}} 首已添加,{{skipped}} 首跳过(重复)',
addAllSkipped: '全部跳过({{count}} 首重复)',
addedAsDuplicates: '{{count}} 首歌曲已添加到 {{playlist}}(作为重复项)',
duplicateConfirmTitle: '已在播放列表中',
duplicateConfirmMessage: '所有 {{count}} 首歌曲已在 "{{playlist}}" 中。仍要作为重复项添加吗?',
duplicateConfirmAction: '仍要添加',
addError: '添加歌曲时出错',
createAndAddSuccess: '播放列表 "{{playlist}}" 已创建,包含 {{count}} 首歌曲',
createError: '创建播放列表时出错',