feat(web+android): Wiedergabe fortsetzen und Streitpunkte im Duell (2.4)
Wiedergabe fortsetzen: Im Web ueberlebten Warteschlange und letzter Titel bereits, die POSITION im Titel aber nicht — beim Neuladen begann der Song von vorn. Android sicherte nur den letzten Song ohne Warteschlange. Beide merken sich jetzt Warteschlange, Listenposition und Sekunde. Web schreibt gedrosselt (alle 5 s) waehrend der Wiedergabe und sicher beim Pausieren, Wegwischen und Tabwechsel — pagehide/visibilitychange statt beforeunload, das am Handy unzuverlaessig feuert. Android sichert bei jedem Titelwechsel und beim Pausieren und stellt nach dem Verbinden wieder her: vorbereitet, aber NICHT abgespielt, wer die App oeffnet will nicht ueberfallen werden. Laeuft schon etwas (Android Auto), passiert nichts. Zwei Feinheiten: lag die Position im letzten Rest des Titels, faengt er von vorn an, statt zwei Sekunden Abspann zu spielen; und gespeichert werden nur Song-Ids, weil Titel und Cover sich durch Metadaten-Bearbeitung aendern koennen — verschwundene Titel werden beim Wiederherstellen uebersprungen. Streitpunkte im Duell: Gemeinsame Kuenstler nach groesstem Ungleichgewicht statt nach Summe, mit Kraefteverhaeltnis-Balken. Mindestens vier gemeinsame Plays und 50 % Unwucht, sonst gilt ein einzelner Play gegen null schon als Streit. Web und Android mit identischen Schwellen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
92c3d96936
commit
65fa950043
8 files changed
+217
-2
No files matched your search
@@ -135,6 +135,7 @@ function _renderCompare(body, d) {
|
||||
body.innerHTML = `<div class="cmp-body">
|
||||
<div class="cmp-wide">${_scoreboard(d, b, urteil)}</div>
|
||||
<div class="cmp-wide">${_totals(d)}</div>
|
||||
<div>${_streitpunkte(d)}</div>
|
||||
<div>${_sharedArtists(d.sharedArtists)}</div>
|
||||
<div>${_sharedTracks(d.sharedTracks)}</div>
|
||||
<div class="cmp-wide">${_uniqueCols(d)}</div>
|
||||
@@ -177,6 +178,38 @@ function _h(t) {
|
||||
|
||||
// Shared artist row: a centered name with each side's play count on its flank + a
|
||||
// mirrored bar so you can see who plays them more.
|
||||
// Streitpunkte: gemeinsame Künstler, bei denen die Zählerstände am weitesten auseinanderliegen.
|
||||
// Umgekehrt zu "Gemeinsame Künstler", das nach Summe sortiert und damit zeigt, worin ihr euch einig
|
||||
// seid. Sortiert wird nach relativem Ungleichgewicht, sonst stünden nur die meistgehörten oben.
|
||||
function _streitpunkte(d) {
|
||||
const items = (d.sharedArtists || [])
|
||||
.map(a => {
|
||||
const summe = a.playsA + a.playsB;
|
||||
return { ...a, unwucht: summe ? Math.abs(a.playsA - a.playsB) / summe : 0, summe };
|
||||
})
|
||||
// Ein einzelner Play gegen null ist kein Streit, sondern Zufall — Mindestmasse verlangen.
|
||||
.filter(a => a.summe >= 4 && a.unwucht >= 0.5)
|
||||
.sort((x, y) => (y.unwucht - x.unwucht) || (y.summe - x.summe))
|
||||
.slice(0, 8);
|
||||
if (!items.length) return `${_h('Streitpunkte')}${_info('Ihr hört gemeinsame Künstler erstaunlich ausgewogen.')}`;
|
||||
const rows = items.map(a => {
|
||||
const anteilA = Math.round((a.playsA / a.summe) * 100);
|
||||
const nav = a.artistId ? `data-nav-type="artist" data-nav-id="${esc(a.artistId)}" data-nav-name="${esc(a.name)}" style="cursor:pointer"` : '';
|
||||
return `<div ${nav} style="padding:7px 0">
|
||||
<div style="display:flex;justify-content:space-between;gap:8px;font-size:13px;margin-bottom:4px">
|
||||
<span class="cmp-num">${a.playsA}</span>
|
||||
<span style="font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(a.name)}</span>
|
||||
<span class="cmp-num">${a.playsB}</span>
|
||||
</div>
|
||||
<div style="display:flex;height:6px;border-radius:3px;overflow:hidden;background:var(--surface2)">
|
||||
<div style="width:${anteilA}%;background:var(--accent)"></div>
|
||||
<div style="width:${100 - anteilA}%;background:var(--accent);opacity:.35"></div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
return `${_h('Streitpunkte')}<div>${rows}</div>`;
|
||||
}
|
||||
|
||||
function _sharedArtists(items) {
|
||||
if (!items?.length) return `${_h('Gemeinsame Künstler')}${_info('Keine gemeinsamen Künstler in diesem Zeitraum.')}`;
|
||||
const max = Math.max(...items.map(a => Math.max(a.playsA, a.playsB)), 1);
|
||||
|
||||
Reference in new issue
Block a user