From ee6ac746e21ad39b5c323b0423d486933c5357d6 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:32:20 +0100 Subject: [PATCH 1/5] feat: add platform-default Seerr HTTP client factory --- lib/util/seerr_http_client.dart | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lib/util/seerr_http_client.dart diff --git a/lib/util/seerr_http_client.dart b/lib/util/seerr_http_client.dart new file mode 100644 index 000000000..29bf93bc8 --- /dev/null +++ b/lib/util/seerr_http_client.dart @@ -0,0 +1,3 @@ +import 'package:http/http.dart' as http; + +http.Client createSeerrHttpClient() => http.Client(); From 43e86313d444ef7fa04445f23af69bf939a1b7c9 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:32:59 +0100 Subject: [PATCH 2/5] feat: add web-specific Seerr HTTP client with withCredentials support --- lib/util/seerr_http_client_web.dart | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/util/seerr_http_client_web.dart diff --git a/lib/util/seerr_http_client_web.dart b/lib/util/seerr_http_client_web.dart new file mode 100644 index 000000000..c7c8b9ab0 --- /dev/null +++ b/lib/util/seerr_http_client_web.dart @@ -0,0 +1,6 @@ +import 'package:http/browser_client.dart'; +import 'package:http/http.dart' as http; + +http.Client createSeerrHttpClient() { + return BrowserClient()..withCredentials = true; +} From ddbdc317a2bfd57f687e22287a637d2da04f9fe5 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:33:43 +0100 Subject: [PATCH 3/5] feat: use platform-aware HTTP client and handle browser-managed cookies in Seerr API --- lib/providers/seerr_api_provider.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/providers/seerr_api_provider.dart b/lib/providers/seerr_api_provider.dart index da963c0c9..d1cf607cf 100644 --- a/lib/providers/seerr_api_provider.dart +++ b/lib/providers/seerr_api_provider.dart @@ -11,6 +11,8 @@ import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/seerr/seerr_chopper_service.dart'; import 'package:fladder/seerr/seerr_json_converter.dart'; import 'package:fladder/util/fladder_config.dart'; +import 'package:fladder/util/seerr_http_client.dart' + if (dart.library.html) 'package:fladder/util/seerr_http_client_web.dart'; part 'seerr_api_provider.g.dart'; @@ -21,6 +23,7 @@ class SeerrApi extends _$SeerrApi { ref.watch(userProvider.select((u) => u?.seerrCredentials)); final chopperClient = ChopperClient( + client: createSeerrHttpClient(), converter: const SeerrJsonConverter(), interceptors: [ SeerrRequest(ref), @@ -89,7 +92,8 @@ class SeerrRequest implements Interceptor { Map _authHeaders({required String apiKey, required String cookie}) { if (apiKey.isNotEmpty) return {'X-Api-Key': apiKey}; - if (cookie.isNotEmpty) return {'Cookie': cookie}; + if (cookie.isNotEmpty && cookie != kBrowserManagedCookie) return {'Cookie': cookie}; + if (cookie == kBrowserManagedCookie) return const {}; return const {}; } From cc1341809629342f01aaa0066ceeacf8e3bb8420 Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:34:24 +0100 Subject: [PATCH 4/5] feat: return browser-managed cookie sentinel on web when set-cookie header is absent --- lib/providers/seerr_service_provider.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/providers/seerr_service_provider.dart b/lib/providers/seerr_service_provider.dart index 48e244bcc..0e1df7c15 100644 --- a/lib/providers/seerr_service_provider.dart +++ b/lib/providers/seerr_service_provider.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:chopper/chopper.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fladder/models/items/images_models.dart'; @@ -11,6 +12,7 @@ import 'package:fladder/seerr/seerr_chopper_service.dart'; import 'package:fladder/seerr/seerr_models.dart'; const tmbdUrl = 'https://image.tmdb.org/t/p/original'; +const kBrowserManagedCookie = '__browser_managed__'; class SeerrService { SeerrService(this.ref, this._api); @@ -697,7 +699,9 @@ class SeerrService { String? _extractSessionCookie(Response response) { final setCookie = response.base.headers['set-cookie']; - if (setCookie == null || setCookie.isEmpty) return null; + if (setCookie == null || setCookie.isEmpty) { + return kIsWeb ? kBrowserManagedCookie : null; + } return setCookie.split(';').first.trim(); } } From 31f1ef9dac0b40737696be1715f232784f968bcb Mon Sep 17 00:00:00 2001 From: v3DJG6GL <72495210+v3DJG6GL@users.noreply.github.com> Date: Tue, 10 Mar 2026 01:51:23 +0100 Subject: [PATCH 5/5] style: fix linting issues --- lib/providers/seerr_service_provider.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/providers/seerr_service_provider.dart b/lib/providers/seerr_service_provider.dart index 0e1df7c15..292c7ee2e 100644 --- a/lib/providers/seerr_service_provider.dart +++ b/lib/providers/seerr_service_provider.dart @@ -634,7 +634,8 @@ class SeerrService { SeerrDashboardPosterModel? posterFromDiscoverItem(SeerrDiscoverItem item) => _posterFromDiscoverItem(item); - Future authenticateLocal({required String email, required String password, Map? headers}) async { + Future authenticateLocal( + {required String email, required String password, Map? headers}) async { final response = await _api.authenticateLocal( SeerrAuthLocalBody(email: email, password: password), headers: headers, @@ -649,14 +650,16 @@ class SeerrService { return cookie; } - Future authenticateJellyfin({required String username, required String password, Map? headers}) async { + Future authenticateJellyfin( + {required String username, required String password, Map? headers}) async { final response = await _authenticateJellyfin(username: username, password: password, headers: headers); return _requireSessionCookie(response, label: 'Jellyfin'); } Future logout() async => await _api.logout(); - Future> _authenticateJellyfin({required String username, required String password, Map? headers}) async { + Future> _authenticateJellyfin( + {required String username, required String password, Map? headers}) async { var response = await _api.authenticateJellyfin( SeerrAuthJellyfinBody(username: username, password: password), headers: headers,