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

+10 -2
View File
@@ -37,7 +37,7 @@ import {
} from './views/abs.js';
import {
openNowPlaying, closeNowPlaying, switchNpTab, npGoArtist, npGoAlbum,
openNpMenu, closeNpMenu,
openNpMenu, closeNpMenu, toggleLyricsFolgen,
} from './player/nowplaying.js';
import {
openSettings, closeSettings, saveSettings, confirmDisconnect,
@@ -126,6 +126,8 @@ async function startApp() {
const sr = localStorage.getItem('ns_repeat');
if(sr === 'all' || sr === 'one') S.repeat = sr;
if(localStorage.getItem('ns_shuffle') === '1') S.shuffle = true;
// Mitlaufen der Lyrics: Vorgabe AUS, nur ein ausdruecklich gesetztes '1' schaltet es ein.
S.lyricsFolgen = localStorage.getItem('ns_lyrics_folgen') === '1';
_applyShuffleRepeat();
}
@@ -216,6 +218,12 @@ window.addEventListener('load', () => {
// backgrounded (that routes through togglePlay → S._userPaused=true), which used to wrongly
// auto-resume on foreground because _wasPlayingBeforeHide was still true from hide-time.
if(!S.audio.paused) return;
// Am ENDE der Warteschlange nicht fortsetzen. Ein beendetes <audio> ist zwar "paused", aber
// play() spult dann auf Anfang zurueck und spielt denselben Titel NOCH EINMAL. Bei
// ausgeschaltetem Repeat steht nach dem letzten Titel nichts mehr an, trotzdem lief er bei
// jedem Zurueckholen der Seite wieder los — genau das sah wie "der letzte Titel wiederholt
// sich mehrfach" aus, besonders bei Shuffle, wo der Letzte ein beliebiger ist.
if(S.audio.ended) return;
if(s && S.audio.src && _wasPlayingBeforeHide && !S._userPaused) S.audio.play().catch(() => { S._trackChanging = false; });
}
@@ -360,7 +368,7 @@ Object.assign(window, {
toggleStar, dlSongLocal, toggleRadioMode, stopPreview, npToggleStar,
// Now Playing
openNowPlaying, closeNowPlaying, switchNpTab, npGoArtist, npGoAlbum,
openNpMenu, closeNpMenu,
openNpMenu, closeNpMenu, toggleLyricsFolgen,
npSeek: () => {},
// UI / Modals
openSettings, closeSettings, saveSettings, confirmDisconnect, checkBackend,