import {
inhalt, weiterschauen, naechsteFolgen, empfehlungen, saisonal,
type Bibliothek,
} from '../api';
import { leer, fehlerzeile, meldung } from '../util';
import { kachel, alsKachel, angefangenAlsKachel, reihe } from '../card';
import { hero, alsHero, angefangenAlsHero, type Heroeintrag } from '../hero';
import { spieler } from '../spieler';
type Art = 'filme' | 'serien';
/** Die Startseite — waagerechte Reihen, wie bei Plex.
*
* Oben, was angefangen ist. Darunter **je Mediathek eine Reihe** mit dem
* zuletzt Hinzugefügten: wer „Filme" und „Dokumentationen" getrennt angelegt
* hat, hat sie getrennt gemeint, und eine Startseite, die sie wieder
* zusammenwirft, nimmt die Entscheidung zurück.
*
* Eine Reihe ohne Inhalt wird gar nicht erst gezeigt. */
export function startseite(
bibliotheken: Bibliothek[],
oeffnen: (art: Art, id: string) => void,
alleZeigen: (b: Bibliothek) => void,
/** **Wird gebraucht, nicht nur mitgeführt.** Die Startseite wird gemerkt;
* ohne dieses Signal lief der Takt des Aufmachers weiter, während man
* längst woanders war, und seine Zuhörer am Fenster blieben hängen. */
signal?: AbortSignal,
): HTMLElement {
const wurzel = document.createElement('div');
wurzel.innerHTML = '
';
// **Benannt, damit der Spieler sie danach neu bauen kann.** Wer aus dem
// Aufmacher heraus zu Ende schaut, soll die Zeile „Fortsetzen" nicht
// unverändert wiederfinden.
void aufbauen();
async function aufbauen(): Promise {
try {
// **Alles auf einmal anfragen.** Bei fünf Mediatheken wären es sonst
// acht Anfragen nacheinander, und die Startseite baut sich vor den
// Augen des Benutzers Zeile für Zeile auf.
const [weiter, naechste, vorschlag, saison, ...bestaende] = await Promise.all([
weiterschauen(),
naechsteFolgen(),
empfehlungen(24).catch(() => ({ items: [], total: 0 })),
// **Scheitert sie, fehlt eine Reihe und nicht die Startseite.** Ein
// älterer Server kennt den Weg nicht; das darf nicht dazu führen,
// dass gar nichts erscheint.
saisonal(24).catch(() => ({ occasion: null, items: { items: [], total: 0 } })),
...bibliotheken.map(b => inhalt(b, { sort: 'added', take: 24 })),
]);
wurzel.innerHTML = '';
if (bibliotheken.length === 0) {
wurzel.appendChild(leer('Noch keine Mediathek. Lege unter Verwaltung eine an '
+ 'und starte einen Scan.'));
return;
}
// **Der Aufmacher, aus dem, was ohnehin schon geholt wurde.**
// Erst Angefangenes — wer mittendrin ist, will dort weiter —, dann
// Neuzugänge, dann Vorschläge. Titel ohne Hintergrundbild fallen im
// Hero selbst heraus; ohne einen einzigen entfällt er ganz.
const heroTitel: Heroeintrag[] = [];
const schonDa = new Set();
const dazu = (e: Heroeintrag) => {
if (schonDa.has(e.id) || !e.hintergrund) return;
schonDa.add(e.id);
heroTitel.push(e);
};
weiter.items.forEach(e => dazu(angefangenAlsHero(e)));
bibliotheken.forEach((b, i) => {
const art: Art = b.kind === 'Shows' ? 'serien' : 'filme';
bestaende[i]?.items.forEach(e => dazu(alsHero(e as never, art)));
});
vorschlag.items.forEach(e => dazu(alsHero(e, 'filme')));
const aufmacher = hero(heroTitel,
(art, id) => oeffnen(art, id),
e => {
// Ohne Datei gibt es nichts zu starten — dann führt der Knopf
// dorthin, wo man wählen kann.
if (e.dateiId === null) { oeffnen(e.art, e.id); return; }
spieler({
dateiId: e.dateiId,
titelId: e.standId,
name: e.titel,
ab: e.stelle,
laenge: e.laenge,
danach: () => void aufbauen(),
});
},
signal);
if (aufmacher) wurzel.appendChild(aufmacher);
if (weiter.items.length) {
wurzel.appendChild(reihe('Fortsetzen',
weiter.items.map(e => kachel(angefangenAlsKachel(e), oeffnen))));
}
if (naechste.items.length) {
wurzel.appendChild(reihe('Nächste Folge',
naechste.items.map(e => kachel(angefangenAlsKachel(e, 'naechste'), oeffnen))));
}
// **Weit oben, weil sie nur jetzt gilt.** „Zu Halloween" unter den
// Neuzugängen wäre im November verschwunden, ohne dass jemand sie
// gesehen hat. Ohne Anlass oder ohne Treffer kommt `occasion` leer
// zurück — dann steht hier gar keine Reihe statt einer mit
// Überschrift und nichts darunter.
if (saison.occasion && saison.items.items.length) {
wurzel.appendChild(reihe(saison.occasion,
saison.items.items.map(e => kachel(alsKachel(e), oeffnen))));
}
let etwasDa = false;
bibliotheken.forEach((b, i) => {
const seite = bestaende[i];
if (!seite?.items.length) return;
etwasDa = true;
wurzel.appendChild(reihe(
// Plex schreibt den Namen der Mediathek in die Überschrift —
// „Zuletzt in Filme hinzugefügt". Bei mehreren Mediatheken ist das
// der Unterschied zwischen einer Reihe und sieben gleich
// aussehenden.
`Zuletzt in ${b.name} hinzugefügt`,
seite.items.map(e => kachel(alsKachel(e), oeffnen)),
seite.total > seite.items.length
? { text: 'Alle zeigen', tun: () => alleZeigen(b) }
: undefined));
});
if (vorschlag.items.length) {
wurzel.appendChild(reihe('Weil du Ähnliches gesehen hast',
vorschlag.items.map(e => kachel(alsKachel(e), oeffnen))));
}
if (!etwasDa && !weiter.items.length && !naechste.items.length) {
wurzel.appendChild(leer('Noch nichts da. Starte unter Verwaltung einen Scan.'));
}
} catch (fehler) {
wurzel.innerHTML = '';
wurzel.appendChild(fehlerzeile(meldung(fehler)));
}
}
return wurzel;
}