Eine Folge ist weder ein Film noch eine Serie

Die App meldete auf der Startseite „Dieser Titel ist auf dem Server nicht
mehr vorhanden" — über eine Folge, die sie selbst gerade anzeigte.

Gemessen im Quelltext: `item(id:)` probiert `/movies/{id}`, dann
`/series/{id}`, und wirft sonst `.notFound`. In „Weiterschauen" steht
eine Folge mit ihrer eigenen Kennung, und einen Endpunkt für eine
einzelne Folge gab es gar nicht. Jetzt gibt es `GET /api/v1/episodes/{id}`
— mit `SeriesId`, denn ohne die Serie fehlen der Folge Titel und Bild.
Im Simulator nachgestellt und nachgeprüft: die Seite steht.

**Zuletzt hinzugefügt.** Die App zeigte „Filme" und „Serien" — den Anfang
der Mediathek in der Reihenfolge der Datenbank, also immer denselben.
Jetzt je Mediathek eine Reihe „Neu in …", sortiert nach Zugang. Die
Kennungen beginnen nun mit `latest`, und daran hängen zwei Einstellungen,
die an einem Flaro-Server deshalb nichts taten: „Gesehenes in Neuzugängen
ausblenden" und „Aufmacher nur aus Neuzugängen".

**Geplante Titel.** `MediaItem` kennt jetzt `availableFrom`. Aufmacher und
Detailseite zeigen statt des Knopfes „Bald ist es soweit" mit dem Termin.
Die Kachel spielte trotzdem los — im Simulator kam der Spieler bis „Wird
vorbereitet …" —, also zählt ein geplanter Titel jetzt wie eine Sammlung:
nichts zu starten, der Tipp führt auf die Seite.

**Und das Bild im Aufmacher.** Bei einer angefangenen Folge stand dort ihr
Standbild statt des Bildes der Serie; wer der Serie eines ausgesucht
hatte, fand ein anderes vor. Die Kachel behält das Standbild — sie zeigt,
wo man steht —, der Aufmacher bekommt `SeriesBackdropImage`.

**Die Punkte im Karussell waren 26 × 3 Pixel.** Von drei Klicks auf
denselben Punkt traf nur der auf der Mittellinie; fünf Pixel daneben
geschah nichts. Der Knopf ist jetzt 27 Pixel hoch, sichtbar bleiben 3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-06 16:06:58 +02:00
co-authored by Claude Opus 5
parent f10fb4c1bc
commit 10a5070e58
17 changed files with 389 additions and 71 deletions
@@ -54,13 +54,12 @@ public actor FlaroBackend: MediaBackend {
}
public func homeRows() async throws(MediaBackendError) -> [MediaRowGroup] {
// **Vier Anfragen, nicht eine.** Flaro hat keinen Endpunkt, der eine
// fertige Startseite liefert, und das ist Absicht: welche Reihen eine
// App zeigt, entscheidet die App. Der Server liefert die Zutaten.
// **Mehrere Anfragen, nicht eine.** Flaro hat keinen Endpunkt, der
// eine fertige Startseite liefert, und das ist Absicht: welche Reihen
// eine App zeigt, entscheidet die App. Der Server liefert die Zutaten.
async let weiter = reihe(pfad: "/api/v1/home/continue")
async let naechste = reihe(pfad: "/api/v1/home/next")
async let filme = seite(pfad: "/api/v1/movies", take: 24, as: Wire.Movie.self)
async let serien = seite(pfad: "/api/v1/series", take: 24, as: Wire.Series.self)
let mediatheken = (try? await libraries()) ?? []
var reihen: [MediaRowGroup] = []
@@ -76,18 +75,46 @@ public actor FlaroBackend: MediaBackend {
title: String(localized: "flaro.row.nextUp", bundle: .module),
items: eintraege))
}
if let gefunden = try? await filme, !gefunden.items.isEmpty {
// **Je Mediathek eine Reihe mit dem zuletzt Hinzugefügten.**
//
// Vorher standen hier zwei Reihen, „Filme" und „Serien", mit dem
// Anfang der Mediathek in der Reihenfolge der Datenbank — also immer
// demselben. Drei Dinge waren damit falsch: es war kein Neuzugang,
// es warf getrennte Mediatheken wieder zusammen, und die Kennungen
// begannen nicht mit `latest`. An dieser Vorsilbe hängen zwei
// Einstellungen — „Gesehenes in Neuzugängen ausblenden" und
// „Aufmacher nur aus Neuzugängen" —, und beide taten an einem
// Flaro-Server deshalb nichts.
for mediathek in mediatheken {
let pfad = mediathek.kind == .show ? "/api/v1/series" : "/api/v1/movies"
let abfrage = [
URLQueryItem(name: "library", value: mediathek.id),
URLQueryItem(name: "sort", value: "added"),
URLQueryItem(name: "take", value: "24"),
]
let titel: [MediaItem]
if mediathek.kind == .show {
guard let seite = try? await client.send(
FlaroRequest(path: pfad, query: abfrage),
as: Wire.Page<Wire.Series>.self) else { continue }
titel = seite.items.map { $0.neutral() }
} else {
guard let seite = try? await client.send(
FlaroRequest(path: pfad, query: abfrage),
as: Wire.Page<Wire.Movie>.self) else { continue }
titel = seite.items.map { $0.neutral() }
}
guard !titel.isEmpty else { continue }
reihen.append(MediaRowGroup(
id: "flaro.movies",
title: String(localized: "flaro.row.movies", bundle: .module),
items: gefunden.items.map { $0.neutral() }))
}
if let gefunden = try? await serien, !gefunden.items.isEmpty {
reihen.append(MediaRowGroup(
id: "flaro.series",
title: String(localized: "flaro.row.series", bundle: .module),
items: gefunden.items.map { $0.neutral() }))
id: "latest.\(mediathek.id)",
title: String(
localized: "flaro.row.latestIn \(mediathek.title)",
bundle: .module),
libraryID: mediathek.id,
items: titel))
}
return reihen
}
@@ -135,6 +162,21 @@ public actor FlaroBackend: MediaBackend {
FlaroRequest(path: "/api/v1/series/\(id)"), as: Wire.Series.self) {
return serie.neutral()
}
// **Und zuletzt eine Folge.**
//
// Sie fehlte, und das war der Grund für „Dieser Titel ist auf dem
// Server nicht mehr vorhanden" direkt von der Startseite: in
// „Weiterschauen" steht eine Folge mit ihrer eigenen Kennung, und die
// ist weder ein Film noch eine Serie.
if let folge = try? await client.send(
FlaroRequest(path: "/api/v1/episodes/\(id)"), as: Wire.Episode.self) {
var serie: Wire.Series?
if let kennung = folge.seriesId {
serie = try? await client.send(
FlaroRequest(path: "/api/v1/series/\(kennung)"), as: Wire.Series.self)
}
return folge.neutral(series: serie)
}
throw .notFound
}