feat(web+backend): Dubletten im Editor aufloesen, Favoriten ueberleben das Umbenennen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
24558497da
commit
8d25bf0404
4 files changed
+239
-5
No files matched your search
@@ -291,6 +291,8 @@ export async function saveMetadata() {
|
||||
if (d.warnings?.length) {
|
||||
status.innerHTML = '⚠ Gespeichert, aber: ' + d.warnings.map(esc).join('<br>⚠ ') +
|
||||
'<br><span style="color:var(--text3)">Datei: ' + esc(d.file || '?') + '</span>';
|
||||
// Liegt derselbe Song doppelt, kann das Aufraeumen hier passieren statt auf der Konsole.
|
||||
if (d.duplicate) _zeigeDublette(status, d.duplicate);
|
||||
toast('⚠ Gespeichert — mit Hinweisen, siehe Fenster');
|
||||
return;
|
||||
}
|
||||
@@ -302,6 +304,71 @@ export async function saveMetadata() {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── DUBLETTE AUFLOESEN ───
|
||||
// Das Verschieben wurde abgelehnt, weil am Ziel schon eine Datei liegt — derselbe Song liegt also
|
||||
// zweimal auf der Platte. Statt den Nutzer zum Dateimanager zu schicken, werden beide Kopien
|
||||
// gegenuebergestellt und die ueberzaehlige zum Loeschen angeboten.
|
||||
const _mb = (n) => (n == null ? '?' : (n / 1048576).toFixed(1) + ' MB');
|
||||
const _sek = (n) => (n == null ? '?' : formatDur(n));
|
||||
|
||||
function _zeigeDublette(status, dub) {
|
||||
const box = document.createElement('div');
|
||||
box.className = 'dublette-box';
|
||||
const zeile = (titel, f) =>
|
||||
`<div class="dublette-datei"><b>${esc(titel)}</b>` +
|
||||
`<div class="dublette-pfad">${esc(f.pfad || '?')}</div>` +
|
||||
`<div class="dublette-meta">${esc(f.artist || '?')} — ${esc(f.titel || '?')} · ` +
|
||||
`${_sek(f.dauer)} · ${_mb(f.groesse)}</div></div>`;
|
||||
box.innerHTML =
|
||||
zeile('Bleibt liegen (richtiger Ordner)', dub.behalten) +
|
||||
zeile('Überzählig (gerade bearbeitet)', dub.ueberzaehlig) +
|
||||
(dub.gleich
|
||||
? '<div class="dublette-urteil ok">Gleiche Länge und gleicher Titel — zwei Kopien desselben Songs.</div>'
|
||||
: '<div class="dublette-urteil warn">Länge oder Titel weichen ab. Das Backend lehnt das Löschen ab, ' +
|
||||
'solange das so ist — bitte erst selbst nachsehen.</div>');
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'btn-danger';
|
||||
btn.textContent = '🗑 Überzählige Kopie löschen';
|
||||
btn.onclick = () => _loescheDublette(btn, status, dub);
|
||||
box.appendChild(btn);
|
||||
status.appendChild(box);
|
||||
}
|
||||
|
||||
async function _loescheDublette(btn, status, dub) {
|
||||
const ok = await showConfirm(
|
||||
'Dublette löschen',
|
||||
`"${dub.ueberzaehlig.pfad}" wird unwiderruflich von der Festplatte gelöscht. ` +
|
||||
`Die Kopie im richtigen Ordner bleibt bestehen.`,
|
||||
'Löschen'
|
||||
);
|
||||
if (!ok) return;
|
||||
btn.disabled = true;
|
||||
btn.textContent = '🗑 Löschen…';
|
||||
try {
|
||||
const r = await fetch(`${S.cfg.backendUrl}/api/resolve-duplicate`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
ndUrl: S.cfg.url, user: S.cfg.user, pass: S.cfg.pass,
|
||||
behalten: dub.behalten.pfad, ueberzaehlig: dub.ueberzaehlig.pfad,
|
||||
}),
|
||||
});
|
||||
const d = await r.json();
|
||||
if (!r.ok) throw new Error(d.error || `HTTP ${r.status}`);
|
||||
invalidateApiCache('getArtists');
|
||||
invalidateRomajiIndex();
|
||||
btn.remove();
|
||||
status.insertAdjacentHTML('beforeend',
|
||||
'<div class="dublette-urteil ok">✅ Gelöscht. Navidrome scannt — danach steht der Song nur noch einmal da.</div>');
|
||||
toast('✅ Dublette gelöscht');
|
||||
} catch (e) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = '🗑 Überzählige Kopie löschen';
|
||||
toast('❌ ' + e.message);
|
||||
status.insertAdjacentHTML('beforeend',
|
||||
'<div class="dublette-urteil warn">' + esc(e.message) + '</div>');
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteSong() {
|
||||
if (!S.cfg.backendUrl) { toast('⚠ Kein Backend konfiguriert'); return; }
|
||||
const s = S.infoSong;
|
||||
|
||||
Reference in new issue
Block a user