diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift index 0a057b6..a3570b7 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift +++ b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift @@ -143,6 +143,10 @@ public struct JellyfinBackend: MediaBackend { switch library.kind { case .movie: items.append(URLQueryItem(name: "IncludeItemTypes", value: "Movie")) case .show: items.append(URLQueryItem(name: "IncludeItemTypes", value: "Series")) + // Gemischter Inhalt: Filme **und** Serien, aber eben nur die. Ohne + // diese Angabe liefert `Recursive` auch jede einzelne Folge, und das + // Raster füllt sich mit Folge 3 von Staffel 2 statt mit Titeln. + case .other: items.append(URLQueryItem(name: "IncludeItemTypes", value: "Movie,Series")) default: break } diff --git a/Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift b/Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift index c7d5c28..d61d650 100644 --- a/Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift +++ b/Packages/FlixyKit/Sources/MediaKit/MediaLibrary.swift @@ -30,8 +30,22 @@ public struct MediaLibrary: Sendable, Equatable, Identifiable { /// /// Musik und Fotos sind bewusst außen vor: sie bräuchten eigene Ansichten /// und eigene Wiedergabe, und eine halbherzige Musikansicht ist schlechter - /// als gar keine. - public var isSupported: Bool { kind == .movie || kind == .show } + /// als gar keine. Live-TV hat einen eigenen Bildschirm und gehört nicht + /// noch einmal in die Mediathekenliste. + /// + /// **`other` zählt dazu.** Hier stand vorher `movie || show`, und alles + /// Übrige fiel wortlos heraus — auch eine Mediathek mit gemischtem + /// Inhalt, die Jellyfin ohne `CollectionType` meldet. Wer Filme und + /// Serien nicht getrennt hat, sah sie nirgends: nicht in der + /// Seitenleiste, nicht auf der Startseite, nirgends eine Meldung. Eine + /// unbekannte Art ist kein Grund, etwas zu verschweigen — sie ist nur + /// ein Grund, nichts über den Inhalt anzunehmen. + public var isSupported: Bool { + switch kind { + case .movie, .show, .other: true + case .music, .photo, .liveTV: false + } + } } /// Eine Reihe auf der Startseite oder in den Suchergebnissen. diff --git a/Tools/JellyfinStub/server.py b/Tools/JellyfinStub/server.py index 720e27f..9ae8382 100644 --- a/Tools/JellyfinStub/server.py +++ b/Tools/JellyfinStub/server.py @@ -66,6 +66,21 @@ def item(key, name, kind, overview, *, resume=None, series=None): "SeriesPrimaryImageTag": "p-" + series[0]}) return d +# Wie viele erfundene Titel die Mediathek zusätzlich führt. +# +# Zum Prüfen des Nachladens: mit einer Handvoll Titeln passt alles auf eine +# Seite, und ob überhaupt eine zweite angefordert wird, sieht man nie. +FUELLUNG = int(os.environ.get("FLIXY_STUB_LIBRARY", "0")) + +def fuellmaterial(kind): + return [ + item(f"fill-{kind}-{n}", f"Titel {n:03d}", kind, "Erfunden, zum Blättern.") + for n in range(1, FUELLUNG + 1) + ] + +# Was an Seiten angefragt wurde — die eigentliche Messung. +PAGE_LOG = [] + def page(items): return {"Items": items, "TotalRecordCount": len(items), "StartIndex": 0} @@ -123,6 +138,10 @@ class Handler(BaseHTTPRequestHandler): "CollectionType": "movies"}, {"Id": "lib-shows", "Name": "Serien", "Type": "CollectionFolder", "CollectionType": "tvshows"}, + # Ohne `CollectionType` — so meldet Jellyfin eine Mediathek + # mit gemischtem Inhalt. Genau die ist vorher wortlos + # herausgefallen. + {"Id": "lib-mixed", "Name": "Gemischtes", "Type": "CollectionFolder"}, ])) if p == f"/Users/{USER_ID}/Items/Latest": return self.reply([item(*t) for t in TITLES[:6]]) @@ -154,7 +173,22 @@ class Handler(BaseHTTPRequestHandler): parent = q.get("ParentId", [""])[0] kind = "Series" if parent == "lib-shows" else "Movie" chosen = [t for t in TITLES if t[2] == kind] or TITLES - return self.reply(page([item(*t) for t in chosen])) + gesamt = [item(*t) for t in chosen] + fuellmaterial(kind) + # **Blättern wie der echte Server.** Vorher kam immer alles auf + # einmal und `TotalRecordCount` war die Länge der Antwort — damit + # sah eine App, die richtig blättert, genauso aus wie eine, die + # es gar nicht versucht. Jetzt steht in der Antwort, wie viele es + # insgesamt gibt, und geliefert wird nur der verlangte Ausschnitt. + start = int(q.get("StartIndex", ["0"])[0]) + grenze = int(q.get("Limit", [str(len(gesamt))])[0]) + ausschnitt = gesamt[start:start + grenze] + PAGE_LOG.append({"start": start, "limit": grenze, + "geliefert": len(ausschnitt), "gesamt": len(gesamt)}) + return self.reply({"Items": ausschnitt, + "TotalRecordCount": len(gesamt), + "StartIndex": start}) + if p == "/__pages": + return self.reply(PAGE_LOG) if p == "/__reports": return self.reply(REPORTS) if p == "/Genres":