Die App wartete auf eine fertige Datei, statt zu streamen
Gleichzeitig im Web und in der App auf Abspielen getippt: das Web lief,
die App lud dreissig Sekunden. Das war keine Ladezeit, sondern die Zeit,
die der Server braucht, um den ganzen Film einmal durchzuschreiben.
`preparePlayback` kannte nur `/files/{id}/download`. Muss die Datei
umgepackt werden, fragte es im Sekundentakt nach, bis die vollständige
MP4 auf der Platte lag — Grenze zehn Minuten. Der Endpunkt, den das Web
benutzt, ist am Server längst da; die App wusste nur nichts davon.
Jetzt zuerst `/files/{id}/stream`. Das erste Stück ist beim Umpacken in
deutlich unter einer Sekunde da. Der alte Weg bleibt als Rückfall: er ist
langsam, kommt aber ohne Sitzung aus, und eine späte Wiedergabe ist
besser als keine.
**Der Strom beginnt dort, wo man weiterschauen wollte**, und zählt
trotzdem ab null. Ohne das mitzurechnen stünde bei „Fortsetzen ab 1:32"
eine Null auf der Uhr — und genau die ginge als Fortschritt an den
Server. Also: die Zeit der Engine plus Vorlauf ist die Zeit des Films,
und der Spieler springt nicht noch einmal dorthin, wo der Server schon
steht.
**Ein Sprung aus dem Strom heraus baut ihn neu auf.** Die Abspielliste
wächst von der Einstiegsstelle vorwärts; davor und dahinter gibt es
nichts, und ein Sprung ins Leere liesse den Spieler mit einem Kreisel
stehen. Innerhalb des Erzeugten springt er weiterhin selbst — dafür eine
neue Sitzung zu starten hiesse, Sekunden zu warten, um fünf Sekunden
zurückzugehen.
**Und die Sitzung wird geschlossen.** `endPlayback` war eine leere
Methode; das passte, solange es keine Sitzung gab. Mit dem Strom läuft
sonst ein ffmpeg weiter und schreibt den Film zu Ende, während längst
niemand mehr zusieht.
Die Laufzeit kommt weiter aus den Metadaten und nicht aus der Engine:
eine wachsende Liste meldet anfangs ein paar Sekunden, und als Filmlänge
genommen stünde der Regler sofort am Ende.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4a5576f939
commit
1bcf6f12e5
@@ -178,6 +178,40 @@ enum Wire {
|
||||
|
||||
// --- Was hinausgeht --------------------------------------------------
|
||||
|
||||
/// Was das Gerät kann und was gewünscht ist.
|
||||
///
|
||||
/// **Ohne Codec-Angaben nimmt der Server Apples Profil an**, und das ist
|
||||
/// hier genau richtig: dieses Gerät *ist* Apple. Eine eigene Liste wäre
|
||||
/// eine zweite Wahrheit neben der, die der Server ohnehin pflegt.
|
||||
struct StreamRequest: Encodable, Sendable {
|
||||
var height: Int?
|
||||
var audioStream: Int?
|
||||
var startSeconds: Double
|
||||
var transcode: Bool
|
||||
}
|
||||
|
||||
struct Stromspur: Decodable, Sendable {
|
||||
let index: Int
|
||||
let label: String
|
||||
let language: String?
|
||||
let isDefault: Bool
|
||||
}
|
||||
|
||||
struct Stromauskunft: Decodable, Sendable {
|
||||
let sessionId: String
|
||||
let url: String
|
||||
/// Dieselbe Wiedergabe mit Untertitelspuren — fehlt bei Direktwiedergabe.
|
||||
let masterUrl: String?
|
||||
/// „direct", „remux" oder „transcode".
|
||||
let method: String
|
||||
/// Ab welcher Sekunde des Films dieser Strom beginnt.
|
||||
let startSeconds: Double
|
||||
let height: Int?
|
||||
let audioStream: Int?
|
||||
let audioStreams: [Stromspur]
|
||||
let subtitleStreams: [Stromspur]
|
||||
}
|
||||
|
||||
struct LoginRequest: Encodable, Sendable {
|
||||
let userName: String
|
||||
let password: String
|
||||
|
||||
Reference in New Issue
Block a user