Heruntergeladen heisst nicht: ohne Angaben
Bei einer lokalen Datei kehrte der Spieler zurück, sobald sie lief — und liess `item` leer. Daran hing mehr als der Titel: keine Marken, also kein „Intro überspringen"; keine Nachbarfolgen, also keine Knöpfe zum Blättern. Nur bei Heruntergeladenem, und darum sah es so lange nach einem Fehler in der Erkennung aus. Jetzt werden die Angaben nachgeholt, während das Bild schon läuft. Dazu, was derselbe Weg betrifft: der Spieler sagt „Staffel 1 · Folge 6" statt „S1 E6" — der Folgenname wird an einer Stelle gebaut, nicht an dreien. Im Abspann einer Serie stehen zwei Knöpfe statt einem, weil der Abspann zwei Fragen stellt. Und die Abdrücke, mit denen der Tonabgleich geprüft wird, sind jetzt echte: zwei Aufnahmen desselben dreissigsekündigen Stücks, verschiedene Bitraten, durch fpcalc gedreht. Vorher war jede Prüfung mit erfundenen Zahlen bestanden — und genau deshalb war nie belegt, dass der Abgleich an echten Daten etwas findet. Er findet: 17,8–51,0 s und 72,7–105,9 s, bei 20–50 und 75–105. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
afa78f9ee0
commit
fbd865e93b
+57
-29
@@ -178,7 +178,18 @@ export type Spieleranfrage = {
|
||||
dateiId: string;
|
||||
/** Die Kennung des Titels — dorthin geht der Fortschritt. */
|
||||
titelId: string;
|
||||
/** Wie der Titel heisst — bei einem Film reicht das.
|
||||
*
|
||||
* **Bei einer Folge nicht.** Dort braucht die Zeile über dem Spieler
|
||||
* Serie, Staffel, Nummer und Folgentitel, und jede Startstelle hat sie
|
||||
* anders zusammengesetzt: mal „S1 E6 · Name", mal nur „Wiedergabe", mal
|
||||
* bloss den Serienamen. Deshalb kommen die Teile jetzt einzeln, und die
|
||||
* Zeile entsteht genau einmal — hier. */
|
||||
name: string;
|
||||
serie?: string | null;
|
||||
staffel?: number | null;
|
||||
folge?: number | null;
|
||||
folgentitel?: string | null;
|
||||
/** Ab welcher Sekunde des Films. */
|
||||
ab: number;
|
||||
/** Wie lang der Film ist. **Aus der Mediathek, nicht aus dem Strom** — der
|
||||
@@ -274,7 +285,9 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
kopf.className = 'pl-kopf';
|
||||
const name = document.createElement('span');
|
||||
name.className = 'pl-titel';
|
||||
name.textContent = anfrage.name;
|
||||
name.textContent = anfrage.staffel != null || anfrage.folge != null
|
||||
? folgenname(anfrage.serie, anfrage.staffel, anfrage.folge, anfrage.folgentitel)
|
||||
: anfrage.name;
|
||||
|
||||
const kopfknoepfe = document.createElement('div');
|
||||
kopfknoepfe.className = 'pl-gruppe';
|
||||
@@ -370,10 +383,13 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
// die Leiste gar nicht, und ein Knopf, von dem niemand weiss, dass es ihn
|
||||
// gibt, ist keiner. Als eigene Schicht über dem Bild bleibt er sichtbar,
|
||||
// solange die Marke läuft.
|
||||
const ueberspringen = document.createElement('button');
|
||||
ueberspringen.className = 'btn btn-primary pl-ueberspringen hidden';
|
||||
// **Zwei Knöpfe, nicht einer.** Im Abspann einer Serie gibt es zwei
|
||||
// vernünftige Antworten — weiterschauen oder den Abspann überspringen —
|
||||
// und welche gemeint ist, weiss nur der Zuschauer.
|
||||
const markenreihe = document.createElement('div');
|
||||
markenreihe.className = 'pl-marken hidden';
|
||||
|
||||
schicht.append(video, dreher, mitte, kopf, bedienung, ueberspringen, meldungsfeld, kleinleiste);
|
||||
schicht.append(video, dreher, mitte, kopf, bedienung, markenreihe, meldungsfeld, kleinleiste);
|
||||
document.body.appendChild(schicht);
|
||||
document.body.classList.add('pl-offen');
|
||||
|
||||
@@ -606,13 +622,6 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
//
|
||||
// Jetzt stehen sie dort, wo man hinsieht: links und rechts vom Knopf, den
|
||||
// man drückt.
|
||||
/** Wie die Serie heisst — für die Zeile über dem Spieler.
|
||||
*
|
||||
* Aus dem übergebenen Namen gewonnen: wer den Spieler startet, kennt sie,
|
||||
* der Folgenvertrag nennt sie nicht. Steht dort nichts Brauchbares,
|
||||
* bleibt die Zeile eben ohne Serie. */
|
||||
const serienname = anfrage.name.includes(' · ') ? anfrage.name.split(' · ')[0] : null;
|
||||
|
||||
/** Die Nachbarfolgen, sobald der Server sie genannt hat. */
|
||||
let vorige: Folge | null = null;
|
||||
let naechste: Folge | null = null;
|
||||
@@ -702,7 +711,12 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
spieler({
|
||||
dateiId: datei.id,
|
||||
titelId: ziel.id,
|
||||
name: folgenname(serienname, ziel.season, ziel.episode, ziel.title),
|
||||
// Die Serie bleibt dieselbe; sie steht schon im laufenden Wunsch.
|
||||
name: ziel.title ?? '',
|
||||
serie: anfrage.serie,
|
||||
staffel: ziel.season,
|
||||
folge: ziel.episode,
|
||||
folgentitel: ziel.title,
|
||||
ab: stelle,
|
||||
laenge: datei.durationSeconds,
|
||||
tonspur: ton,
|
||||
@@ -778,31 +792,45 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
* **Keine eigene Uhr.** Die Zeit wird ohnehin bei jedem Fortschreiten
|
||||
* nachgeführt; ein zweiter Zeitgeber dafür liefe neben dem ersten her und
|
||||
* wäre eine zweite Stelle, an der etwas hängen bleibt. */
|
||||
/** Was gerade zu tun ist, als ein oder zwei Knöpfe.
|
||||
*
|
||||
* **Neu gezeichnet nur, wenn sich etwas ändert.** `zeitAuffrischen` läuft
|
||||
* mehrmals je Sekunde; die Knöpfe jedesmal neu zu bauen hiesse, einen
|
||||
* Klick mitten im Drücken zu verlieren.
|
||||
*/
|
||||
let markenstandJetzt = '';
|
||||
|
||||
function markenstand(jetzt: number): void {
|
||||
const drin = marken.find(m => jetzt >= m.startSeconds && jetzt < m.endSeconds);
|
||||
ueberspringen.classList.toggle('hidden', !drin);
|
||||
if (!drin) return;
|
||||
|
||||
// **Beim Abspann einer Serie ist „überspringen" die falsche Frage.**
|
||||
//
|
||||
// Was man dort will, ist die nächste Folge — ans Ende dieser zu
|
||||
// springen bringt niemanden weiter. Bei einem Film gibt es nichts
|
||||
// danach; dort heisst es, ihn zu beenden, und der Server hakt ihn
|
||||
// beim Melden der Stelle ohnehin ab.
|
||||
const abspann = drin.kind === 'credits';
|
||||
const abspann = drin?.kind === 'credits';
|
||||
const weiter = abspann && naechste?.files[0] != null;
|
||||
const kennung = `${drin?.startSeconds ?? ''}|${weiter}`;
|
||||
|
||||
const text = !abspann ? 'Intro überspringen'
|
||||
: weiter ? 'Nächste Folge'
|
||||
: 'Abspann überspringen';
|
||||
if (ueberspringen.textContent !== text) ueberspringen.textContent = text;
|
||||
markenreihe.classList.toggle('hidden', !drin);
|
||||
if (!drin || kennung === markenstandJetzt) return;
|
||||
markenstandJetzt = kennung;
|
||||
markenreihe.replaceChildren();
|
||||
|
||||
ueberspringen.onclick = e => {
|
||||
// **Im Abspann einer Serie zuerst die nächste Folge.** Das ist, was man
|
||||
// dort will; „überspringen" steht daneben für den, der den Abspann
|
||||
// sehen wollte und es sich anders überlegt.
|
||||
if (weiter) {
|
||||
const w = knopf('Nächste Folge', 'btn btn-primary');
|
||||
w.onclick = e => { e.stopPropagation(); folgeWechseln(naechste); };
|
||||
markenreihe.appendChild(w);
|
||||
}
|
||||
|
||||
const u = knopf(
|
||||
abspann ? 'Abspann überspringen' : 'Intro überspringen',
|
||||
weiter ? 'btn' : 'btn btn-primary');
|
||||
u.onclick = e => {
|
||||
e.stopPropagation();
|
||||
if (weiter) { folgeWechseln(naechste); return; }
|
||||
if (abspann) { void beenden(); return; }
|
||||
// Bei einem Film und bei der letzten Folge heisst „überspringen"
|
||||
// Schluss: ans Ende zu spulen liesse ein stehendes Bild zurück.
|
||||
if (abspann && !weiter) { void beenden(); return; }
|
||||
void springen(drin.endSeconds);
|
||||
};
|
||||
markenreihe.appendChild(u);
|
||||
}
|
||||
|
||||
/** Ans Ende springen und zumachen — für den Abspann ohne Nachfolger.
|
||||
|
||||
Reference in New Issue
Block a user