iOS 1.0 RC 2: Plex streams under upload caps, shuffle and album radio stations, Recently Added list, photo covers, crossfade

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-11-06 08:40:37 -08:00
1 parent c0e33b5e3e
commit 2fb8040388
17 files changed
+412 -74

No files matched your search

+26
View File
@@ -317,6 +317,32 @@ final class PlexServer: MediaSource, @unchecked Sendable {
URL(string: base + partKey + "?X-Plex-Token=" + urlEncode(token))
}
/// The part's URL the way Plexamp plays it: first a playback decision for this session, then
/// the file fetched under that session and client. A bare part request has no bitrate, so Plex
/// reads it as unlimited ("Bandwidth exceeded: 2147483647 kbps") and answers 500 whenever
/// Remote Access has an upload limit set.
func streamUrl(_ ratingKey: String, partKey: String) async -> URL? {
let session = UUID().uuidString.lowercased()
if signedIn, let u = try? url("/music/:/transcode/universal/decision", [
("path", "/library/metadata/\(ratingKey)"), ("mediaIndex", 0), ("partIndex", 0),
("protocol", "http"), ("directPlay", 1), ("directStream", 1), ("directStreamAudio", 1),
("hasMDE", 1), ("session", session), ("X-Plex-Session-Identifier", session),
]) {
var req = request(u)
req.setValue(session, forHTTPHeaderField: "X-Plex-Session-Identifier")
req.timeoutInterval = 8
// Best effort: the part URL below still carries the session if this fails.
if let (_, resp) = try? await http.session.data(for: req), let code = (resp as? HTTPURLResponse)?.statusCode, code >= 300 {
Log.shared.error("plex", "stream decision for \(ratingKey): HTTP \(code)")
}
}
guard let u = URL(string: base + partKey) else { return nil }
return u.with([
("X-Plex-Token", token), ("X-Plex-Client-Identifier", settings.clientId), ("X-Plex-Product", Self.product),
("X-Plex-Platform", "iOS"), ("X-Plex-Device", model), ("X-Plex-Session-Identifier", session), ("session", session),
])
}
// ---- plex.tv sign-in ------------------------------------------------------------
func createPin() async throws -> PlexPin {