Der Server lieferte nichts — drei Angaben fehlten in der Adresse
Am echten Server gemessen, nachdem der erste Versuch mit „Fehler 500" abgelehnt wurde. Drei Befunde, alle reproduziert: **`deviceId` und `playSessionId` fehlten.** Ohne sie antwortet Jellyfin 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**: `compressedDownloadURL` hatte sie nie. „In 480p herunterladen" war damit die ganze Zeit folgenlos — ein Fehler, der älter ist als alles von heute. **Die Sitzungskennung muss je Auftrag neu sein.** Zuerst hatte ich sie an die Titelkennung gehängt, damit ein Wiederholversuch dieselbe Sitzung bleibt. Zwei Anfragen unter derselben Kennung hielt der Server aber für dieselbe Sitzung und antwortete der zweiten mit einer leeren Datei. Jetzt eine UUID beim Anlegen des Auftrags — eindeutig je Download, gleich über alle Wiederholversuche, weil die Adresse gespeichert ist. **`subtitleCodec=mov_text` muss dabeistehen.** Das war der Fehler 500. Mit `subtitleMethod=Embed` allein lehnt der Server ab; derselbe Aufruf ohne Untertitel liefert 61 MB, mit Untertitel und `mov_text` 42 MB samt Spur. MP4 kennt kein SubRip — wer den Untertitel hineinlegen will, muss sagen, als was. Nachgewiesen im Simulator gegen den echten Server: „100,0 MB / 917,3 MB · 6,1 MB/s · noch 2 Min · 11 %". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a432592271
commit
6b6bc6ad02
@@ -420,14 +420,43 @@ public func isInLocalNetwork() async -> Bool {
|
|||||||
if let subtitleStreamIndex {
|
if let subtitleStreamIndex {
|
||||||
query.append(URLQueryItem(name: "subtitleStreamIndex", value: String(subtitleStreamIndex)))
|
query.append(URLQueryItem(name: "subtitleStreamIndex", value: String(subtitleStreamIndex)))
|
||||||
query.append(URLQueryItem(name: "subtitleMethod", value: "Embed"))
|
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(
|
return client.url(
|
||||||
path: "/Videos/\(itemID)/stream.mp4",
|
path: "/Videos/\(itemID)/stream.mp4",
|
||||||
query: query,
|
query: query + Self.transcodeSession(itemID: itemID, deviceID: client.deviceID),
|
||||||
includingToken: account.token
|
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.
|
/// Eine verkleinerte Fassung zum Herunterladen.
|
||||||
///
|
///
|
||||||
/// **Fortlaufendes MP4, nicht HLS.** Zum Abspielen liefert Jellyfin eine
|
/// **Fortlaufendes MP4, nicht HLS.** Zum Abspielen liefert Jellyfin eine
|
||||||
@@ -469,7 +498,7 @@ public func isInLocalNetwork() async -> Bool {
|
|||||||
|
|
||||||
return client.url(
|
return client.url(
|
||||||
path: "/Videos/\(itemID)/stream.mp4",
|
path: "/Videos/\(itemID)/stream.mp4",
|
||||||
query: query,
|
query: query + Self.transcodeSession(itemID: itemID, deviceID: client.deviceID),
|
||||||
includingToken: account.token
|
includingToken: account.token
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user