Wiedergabe: jeden Parameter streng kodieren, so wie Plex es selbst tut

Die gebaute Adresse anzusehen hat es in einem Blick beantwortet:

    path=/livetv/sessions/0043d829-…        ← meine
    path=%2Flivetv%2Fsessions%2F0043d829-…  ← Plex

Plex' Client schickt alle Parameter durch `qs.stringify`, und das kodiert
alles. `URLComponents` lässt `/`, `:`, `&`, `=`, `+` und Klammern in
Werten stehen. Beim Server kam damit ein Pfad mit echten Schrägstrichen
an — und ein Geräteprofil, das an seinen `&` in zwei Dutzend eigene
Angaben zerfiel. Beides beantwortet er mit einer nackten 400.

Eine Regel für alle Werte, keine Ausnahmen. Damit löst sich nebenbei die
Kodierfrage, die mich mehrere Anläufe gekostet hat: eine Kennung, die
schon `%3A` enthält, wird dabei zu `%253A` — und ist genau einmal
kodiert. Die Sonderbehandlung für `path` und das Profil entfällt, und mit
ihr die Schalter, mit denen ich zwischen falschen Formen hin- und
hergeschaltet habe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-12 15:38:31 +02:00
co-authored by Claude Opus 5
parent ef9fd676c8
commit 44dd794e86
3 changed files with 39 additions and 89 deletions
@@ -500,12 +500,7 @@ extension PlexServer {
// Doppelt kodiert zuerst: der Server dekodiert den Abfragewert
// einmal, bevor er ihn als Pfad liest. Nur so kommt bei ihm
// wieder `plex%3A%2F%2Fepisode%2F…` an statt `plex://episode/…`.
let variants: [(index: Int, profile: Bool, keep: Bool)] = [
(0, true, false),
(-1, true, false),
(0, true, true),
(0, false, false),
]
let variants: [(index: Int, profile: Bool)] = [(0, true), (-1, true), (0, false)]
for variant in variants {
attempts += 1
let outcome = await attemptStream(
@@ -513,7 +508,6 @@ extension PlexServer {
ratingKey: channel.id,
mediaIndex: variant.index,
includeProfile: variant.profile,
keepPathEncoding: variant.keep,
maximumBitrate: maximumBitrate,
session: session
)
@@ -848,7 +842,6 @@ extension PlexServer {
ratingKey: String,
mediaIndex: Int,
includeProfile: Bool,
keepPathEncoding: Bool = true,
minimal: Bool = false,
maximumBitrate: Int?,
session: String
@@ -866,7 +859,6 @@ extension PlexServer {
guard let url = transcodeURL(
for: request,
includeProfile: includeProfile,
keepPathEncoding: keepPathEncoding,
minimal: minimal
) else {
return (nil, ChannelProbe(path: path, result: "Adresse nicht baubar"))
@@ -875,7 +867,6 @@ extension PlexServer {
let outcome = await probeStream(url: url)
let label = "\(path) (mediaIndex \(mediaIndex)"
+ "\(includeProfile ? "" : ", ohne Profil")"
+ "\(keepPathEncoding ? "" : ", doppelt kodiert")"
+ "\(minimal ? ", nur das Nötigste" : "") )"
// Die gebaute Adresse mit in die Spur. Ohne sie diskutiert man über
@@ -1304,21 +1295,17 @@ extension PlexServer {
}
var report: [String] = []
for keepEncoding in [true, false] {
do {
let request = TranscodeRequest(
ratingKey: channel.id,
isLocal: connection.local,
pathOverride: metadataKey
)
guard let url = transcodeURL(
for: request,
keepPathEncoding: keepEncoding
) else { continue }
guard let url = transcodeURL(for: request),
let items = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems
else { return "Adresse nicht baubar" }
guard let items = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems
else { continue }
report.append("--- Entscheider, \(keepEncoding ? "einfach" : "doppelt") kodiert ---")
report.append("--- Entscheider ---")
do {
let data = try await client.send(PlexRequest(
path: "/video/:/transcode/universal/decision",