fix(plex): tolerate account-API schema drift in profile and switch parsing

Around July 3 plex.tv started returning the profile language-list fields
(defaultAudioLanguages, defaultSubtitleLanguages, mediaReviewsLanguages)
as comma-separated strings instead of arrays. The generated cast threw on
the successful 201 /switch response, dropping the freshly minted Home
user token: every rebind failed, the binder retried a /switch mint every
1-2s, and the app sat permanently in offline mode even after re-signing
in. Accounts without language prefs set were unaffected, which is why
the breakage looked sporadic.

Parse the language lists with a CSV-aware coercion, and make
UserSwitchResponse.fromJson strict only about authToken: decorative
fields now coerce tolerantly and a broken profile blob falls back to
defaults, so account-API drift can never brick token minting again.

close #1488
This commit is contained in:
edde746
2026-07-05 06:23:34 +02:00
parent 6e83aeda88
commit 96510f8aac
9 changed files with 546 additions and 57 deletions
+19
View File
@@ -63,6 +63,25 @@ List<String>? flexibleStringList(Object? v) {
return result.isEmpty ? null : result;
}
/// Coerce a comma-separated String ("en,sv"), a bare String, a List of
/// Strings, or null into `List<String>?`. Since ~July 2026 the Plex account
/// API (clients.plex.tv `/api/v2/user` and `/home/users/{uuid}/switch`)
/// returns the profile language-list fields as CSV strings instead of arrays
/// (#1488) — this tolerates both shapes. Parts are trimmed and empties
/// dropped; an empty result (or null input) yields `null`. CSV-splitting
/// sibling of [flexibleStringList], kept separate so that caller's strings
/// (Fribb IMDb ids) stay verbatim.
List<String>? flexibleCsvStringList(Object? v) {
final strings = flexibleStringList(v);
if (strings == null) return null;
final result = [
for (final s in strings)
for (final part in s.split(','))
if (part.trim().isNotEmpty) part.trim(),
];
return result.isEmpty ? null : result;
}
List<String>? stringListFromRaw(Object? raw, {String? mapKey, bool stringify = false, bool nullIfEmpty = false}) {
if (raw is! List) return null;
final result = <String>[];