diff --git a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift index d392c94..a6010e9 100644 --- a/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift +++ b/Packages/FlixyKit/Sources/JellyfinKit/JellyfinBackend.swift @@ -420,14 +420,43 @@ public func isInLocalNetwork() async -> Bool { if let subtitleStreamIndex { query.append(URLQueryItem(name: "subtitleStreamIndex", value: String(subtitleStreamIndex))) query.append(URLQueryItem(name: "subtitleMethod", value: "Embed")) + // **`mov_text`, und zwar ausdrücklich.** Ohne diese Zeile + // antwortet der Server mit `500`. Gemessen an einem echten + // Jellyfin: derselbe Aufruf ohne Untertitel liefert 61 MB, mit + // Untertitel und ohne Kodierer-Angabe einen Fehler, mit + // `mov_text` 42 MB samt Spur. MP4 kennt kein SubRip; wer den + // Untertitel hineinlegen will, muss sagen, als was. + query.append(URLQueryItem(name: "subtitleCodec", value: "mov_text")) } return client.url( path: "/Videos/\(itemID)/stream.mp4", - query: query, + query: query + Self.transcodeSession(itemID: itemID, deviceID: client.deviceID), includingToken: account.token ) } + /// Wer fragt, und für welche Sitzung. + /// + /// **Ohne diese zwei Angaben liefert der Server gar nichts.** Gemessen an + /// einem echten Jellyfin: dieselbe Adresse ohne sie antwortet mit `200` + /// und `Content-Length: 0` — kein Fehler, keine Datei, nichts. Mit ihnen + /// kamen in fünfzehn Sekunden 66 MB. + /// + /// Das betraf auch die verkleinerten Fassungen: die hatten sie nie, und + /// damit war „in 480p herunterladen" die ganze Zeit folgenlos. + /// + /// Die Sitzungskennung ist je Auftrag neu, nicht je Titel. Zwei Anfragen + /// unter derselben Kennung hielt der Server für dieselbe Sitzung und + /// antwortete der zweiten mit einer leeren Datei. Gebaut wird die Adresse + /// einmal beim Anlegen des Auftrags; ein Wiederholversuch nimmt dieselbe + /// und bleibt damit dieselbe Sitzung. + private static func transcodeSession(itemID: String, deviceID: String) -> [URLQueryItem] { + [ + URLQueryItem(name: "deviceId", value: deviceID), + URLQueryItem(name: "playSessionId", value: "flixy-\(UUID().uuidString)"), + ] + } + /// Eine verkleinerte Fassung zum Herunterladen. /// /// **Fortlaufendes MP4, nicht HLS.** Zum Abspielen liefert Jellyfin eine @@ -469,7 +498,7 @@ public func isInLocalNetwork() async -> Bool { return client.url( path: "/Videos/\(itemID)/stream.mp4", - query: query, + query: query + Self.transcodeSession(itemID: itemID, deviceID: client.deviceID), includingToken: account.token ) }