Drei Fehler aus dem ersten Praxistest

Anmelde-Adresse wurde doppelt kodiert
  URLComponents.fragment kodiert beim Setzen erneut, aus %5B wurde
  %255B. Plex antwortete mit „Diese Anfrage konnte nicht abgeschlossen
  werden". Die Adresse wird jetzt von Hand zusammengesetzt.

Verbindungssuche hing bis zu anderthalb Minuten
  probeTimeout war deklariert, aber nirgends angewendet — es galt der
  URLSession-Standard von 60 Sekunden. Zusammen mit der Prüfung Rang
  für Rang kostete eine schweigende lokale Adresse die volle Zeit,
  bevor der direkte Weg überhaupt begann. Jetzt laufen alle Adressen
  gleichzeitig, mit Zeitgrenze, und die Rangordnung entscheidet unter
  den erreichbaren.

Kein Zurück während des Ladens
  Die Kopfzeile mit dem Schließen-Knopf wurde nur im Zustand .playing
  gezeichnet. Bei langsamer Verbindung saß man ohne Ausweg vor einem
  Ladekreis. Sie liegt jetzt als eigene Ebene darüber und erscheint
  auch beim Vorbereiten — samt Titel, damit erkennbar bleibt, worauf
  gewartet wird.

Sechs neue Tests, darunter drei, die die Zeitgrenze der
Verbindungssuche an einer schweigenden Adresse nachstellen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-09-11 17:17:18 +02:00
co-authored by Claude Opus 5
parent 9a69df4635
commit d0a84f35de
9 changed files with 1500 additions and 1237 deletions
@@ -24,17 +24,25 @@ public struct PlexRequest: Sendable, Equatable {
public var path: String
public var query: [URLQueryItem]
public var additionalHeaders: [String: String]
/// Wie lange auf Antwort gewartet wird.
///
/// Der Standardwert von URLSession sind 60 Sekunden. Für einen Server, der
/// nicht antwortet, ist das eine Ewigkeit — und bei der Verbindungssuche
/// summiert es sich über mehrere Adressen.
public var timeout: Duration
public init(
method: Method = .get,
path: String,
query: [URLQueryItem] = [],
additionalHeaders: [String: String] = [:]
additionalHeaders: [String: String] = [:],
timeout: Duration = .seconds(20)
) {
self.method = method
self.path = path
self.query = query
self.additionalHeaders = additionalHeaders
self.timeout = timeout
}
/// Setzt die Anfrage gegen einen Host zusammen.
@@ -57,6 +65,7 @@ public struct PlexRequest: Sendable, Equatable {
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.timeoutInterval = timeout.seconds
for (field, value) in identity.headers {
request.setValue(value, forHTTPHeaderField: field)
}
@@ -69,3 +78,14 @@ public struct PlexRequest: Sendable, Equatable {
return request
}
}
extension Duration {
/// Die Dauer als Gleitkommazahl in Sekunden.
///
/// Foundation und AVFoundation rechnen in `TimeInterval`; `Duration` ist
/// der genauere Typ, den der übrige Code verwendet. Diese Brücke steht in
/// PlexKit, weil es die unterste Schicht ist — die darüber erben sie.
public var seconds: Double {
Double(components.seconds) + Double(components.attoseconds) / 1e18
}
}