feat(web+android): Lyrics-Mitlaufen umschaltbar, echtes Mischen, Wiederholung am Queue-Ende

Lyrics: Schalter "Mitlaufen" im Lyrics-Reiter, Vorgabe AUS. Hervorgehoben wird die
laufende Zeile immer, gescrollt nur bei eingeschaltetem Mitlaufen. Nur bei synchronen
Texten sichtbar. Android speichert den Schluessel einzeln, damit das Speichern im
Einstellungsbildschirm ihn nicht auf die Vorgabe zuruecksetzt.

Mischen (Web): sort(() => Math.random() - 0.5) ist keine Mischung. Gemessen blieb der
erste Titel drei- bis fuenfmal zu oft vorn (18,8 % statt 10 % bei n=10, 0,23 % statt
0,05 % bei n=2000). Ersetzt durch Fisher-Yates in queueMath.mischeListe.

Queue-Ende (Web): ein beendetes <audio> meldet sich als pausiert, die Wiederaufnahme
nach unfreiwilligem Hintergrund-Stop rief play() und spielte den letzten Titel erneut.
Jetzt Abbruch bei audio.ended.

Shuffle (Android): das Mischen macht jetzt der Player (playSongs(liste, -1)), damit die
ungemischte Liste erhalten bleibt — vorher leuchtete das Symbol nicht und "Shuffle aus"
konnte die Albumreihenfolge nicht wiederherstellen.

Radio-Modus (beide): der laufende Titel ist aus der letzten Rueckfallebene ausgenommen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-10-01 17:13:38 +02:00
1 parent ae357b0eb9
commit b6e98463ee
21 files changed
+227 -29

No files matched your search

+11
View File
@@ -816,6 +816,17 @@ button:focus{outline:none}
.lyrics-line{font-size:18px;font-weight:600;line-height:1.85;color:rgba(255,255,255,.22);transition:color .3s,transform .3s,opacity .3s;padding:5px 0;cursor:pointer;text-align:center;transform:scale(1);transform-origin:center center;will-change:transform}
.lyrics-line.past{color:rgba(255,255,255,.45)}
.lyrics-line.active{color:#fff;transform:scale(1.04)}
/* Mitlaufen-Schalter: schwebt unten rechts ueber dem Text, nur im Lyrics-Tab und nur bei
synchronen Zeilen (Klasse .hat-sync setzt das Skript). Aus = gedaempft, an = Akzentfarbe. */
.np-follow{display:none;position:absolute;right:22px;bottom:22px;z-index:3;align-items:center;gap:6px;
background:rgba(0,0,0,.42);border:1px solid rgba(255,255,255,.14);color:rgba(255,255,255,.6);
font-family:var(--font);font-size:11px;font-weight:700;letter-spacing:.3px;text-transform:uppercase;
padding:7px 12px;border-radius:18px;cursor:pointer;backdrop-filter:blur(10px);
transition:color .2s,border-color .2s,background .2s}
.np-overlay.lyrics-mode .np-follow.hat-sync{display:flex}
.np-follow:hover{background:rgba(0,0,0,.6);color:rgba(255,255,255,.85)}
.np-follow.active{color:var(--blue);border-color:color-mix(in srgb,var(--blue) 55%,transparent)}
.np-follow svg{pointer-events:none;flex-shrink:0}
.lyrics-plain{font-size:15px;line-height:1.9;color:rgba(255,255,255,.65);white-space:pre-wrap;text-align:center;padding-top:24px}
.section-count{font-size:11px;font-weight:500;color:var(--text3);background:var(--surface2);padding:2px 8px;border-radius:10px;flex-shrink:0}
.album-partial-badge{position:absolute;bottom:5px;left:5px;background:rgba(0,0,0,.72);color:#fff;font-size:9px;font-weight:700;padding:2px 6px;border-radius:4px;pointer-events:none;z-index:2}