From e0ecc948697c778996ba1f62b302ae6663159534 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Fri, 28 Nov 2025 23:33:32 +0100 Subject: [PATCH 1/6] remove redundant calls trimLeft() and trimRight() after trim() do nothing --- .../manga/detail/providers/update_manga_detail_providers.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart index d19d088e..82740fdd 100644 --- a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart +++ b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart @@ -171,7 +171,7 @@ Future updateMangaDetail( extension DefaultValueExtension on String? { String? trimmedOrDefault(String? defaultValue) { - if (this?.trim().trimLeft().trimRight().isNotEmpty ?? false) { + if (this?.trim().isNotEmpty ?? false) { return this!.trim().trimLeft().trimRight(); } return defaultValue; From 5c34dcab9a9538397b91abd0c54070d2dcc61650 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Fri, 28 Nov 2025 23:59:37 +0100 Subject: [PATCH 2/6] Start Cloudflare resolution after app starts - Defer the Cloudflare resolution webserver until after runApp(). - await said function --- lib/main.dart | 2 +- lib/services/http/m_client.dart | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index eba2e17c..d343066f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -50,7 +50,6 @@ DiscordRPC? discordRpc; WebViewEnvironment? webViewEnvironment; String? customDns; void main(List args) async { - cfResolutionWebviewServer(); WidgetsFlutterBinding.ensureInitialized(); if (Platform.isLinux && runWebViewTitleBarWidget(args)) return; MediaKit.ensureInitialized(); @@ -93,6 +92,7 @@ Future _postLaunchInit(StorageProvider storage) async { await discordRpc?.initialize(); } await storage.deleteBtDirectory(); + await cfResolutionWebviewServer(); } class MyApp extends ConsumerStatefulWidget { diff --git a/lib/services/http/m_client.dart b/lib/services/http/m_client.dart index dd68ca1d..5f95c732 100644 --- a/lib/services/http/m_client.dart +++ b/lib/services/http/m_client.dart @@ -292,7 +292,9 @@ class ResolveCloudFlareChallenge extends RetryPolicy { } int cfPort = 0; -void cfResolutionWebviewServer() async { + +/// Cloudflare Resolution Webview Server +Future cfResolutionWebviewServer() async { final server = await HttpServer.bind(InternetAddress.loopbackIPv4, cfPort); cfPort = server.port; From 5fdbf530cb4e9b218ae80e693443af069a0e87af Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sat, 29 Nov 2025 00:18:13 +0100 Subject: [PATCH 3/6] stopCfResolutionWebviewServer() Stop the cf server on app exit --- lib/main.dart | 1 + lib/services/http/m_client.dart | 46 ++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index d343066f..7b142608 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -157,6 +157,7 @@ class _MyAppState extends ConsumerState { void dispose() { _linkSubscription?.cancel(); discordRpc?.destroy(); + stopCfResolutionWebviewServer(); AppLogger.dispose(); super.dispose(); } diff --git a/lib/services/http/m_client.dart b/lib/services/http/m_client.dart index 5f95c732..0fb3c1e1 100644 --- a/lib/services/http/m_client.dart +++ b/lib/services/http/m_client.dart @@ -292,22 +292,44 @@ class ResolveCloudFlareChallenge extends RetryPolicy { } int cfPort = 0; +HttpServer? _cfServer; /// Cloudflare Resolution Webview Server Future cfResolutionWebviewServer() async { - final server = await HttpServer.bind(InternetAddress.loopbackIPv4, cfPort); - cfPort = server.port; + try { + _cfServer = await HttpServer.bind(InternetAddress.loopbackIPv4, cfPort); + cfPort = _cfServer!.port; + _cfServer!.listen( + (HttpRequest request) { + if (request.method == 'POST' && request.uri.path == '/resolve_cf') { + _handleResolveCf(request); + } else { + request.response + ..statusCode = HttpStatus.notFound + ..write('Not Found') + ..close(); + } + }, + onError: (e, st) { + debugPrint("CF server listener error: $e\n$st"); + }, + cancelOnError: false, + ); + } catch (e, st) { + debugPrint("Couldn't start Cloudflare Resolution Webview Server: $e\n$st"); + botToast("Couldn't start Cloudflare Resolution Webview Server."); + } +} - server.listen((HttpRequest request) { - if (request.method == 'POST' && request.uri.path == '/resolve_cf') { - _handleResolveCf(request); - } else { - request.response - ..statusCode = HttpStatus.notFound - ..write('Not Found') - ..close(); - } - }); +Future stopCfResolutionWebviewServer() async { + final server = _cfServer; + if (server == null) return; + try { + await server.close(force: true); + } finally { + _cfServer = null; + cfPort = 0; + } } void _handleResolveCf(HttpRequest request) async { From 33152fc035be3156f32a7eb687edde9ec23476f1 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:31:22 +0100 Subject: [PATCH 4/6] Fix ProviderDisposedException [ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Cannot use the Ref of totalChapterCacheSizeStateProvider after it has been disposed. This typically happens if: - A provider rebuilt, but the previous "build" was still pending and is still performing operations. You should therefore either use `ref.onDispose` to cancel pending work, or check `ref.mounted` after async gaps or anything that could invalidate the provider. - You tried to use Ref inside `onDispose` or other life-cycles. This is not supported, as the provider is already being disposed. #0 Ref._throwIfInvalidUsage (package:riverpod/src/core/ref.dart:220:7) ref.dart:220 #1 AnyNotifier.state= (package:riverpod/src/core/provider/notifier_provider.dart:91:9) notifier_provider.dart:91 #2 TotalChapterCacheSizeState.build. (package:mangayomi/modules/more/data_and_storage/providers/storage_usage.dart:17:42) storage_usage.dart:17 #3 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:948:45) future_impl.dart:948 #4 Future._propagateToListeners (dart:async/future_impl.dart:977:13) future_impl.dart:977 #5 Future._completeWithValue (dart:async/future_impl.dart:720:5) future_impl.dart:720 --- lib/main.dart | 2 ++ .../more/data_and_storage/providers/storage_usage.dart | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 7b142608..8abd4ff2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -119,6 +119,8 @@ class _MyAppState extends ConsumerState { WidgetsBinding.instance.addPostFrameCallback((_) { if (ref.read(clearChapterCacheOnAppLaunchStateProvider)) { + // Watch before calling clearcache to keep it alive, so that _getTotalDiskSpace completes safely + ref.watch(totalChapterCacheSizeStateProvider); ref .read(totalChapterCacheSizeStateProvider.notifier) .clearCache(showToast: false); diff --git a/lib/modules/more/data_and_storage/providers/storage_usage.dart b/lib/modules/more/data_and_storage/providers/storage_usage.dart index 663d5b65..fa8fc1eb 100644 --- a/lib/modules/more/data_and_storage/providers/storage_usage.dart +++ b/lib/modules/more/data_and_storage/providers/storage_usage.dart @@ -14,7 +14,10 @@ part 'storage_usage.g.dart'; class TotalChapterCacheSizeState extends _$TotalChapterCacheSizeState { @override String build() { - _getTotalDiskSpace().then((value) => state = _formatBytes(value)); + _getTotalDiskSpace().then((value) { + if (!ref.mounted) return; + state = _formatBytes(value); + }); return "0.00 B"; } From c7e648a6d9e2477b494831ec6f792e625b6709a0 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sat, 29 Nov 2025 01:36:34 +0100 Subject: [PATCH 5/6] remove redundant calls --- .../detail/providers/update_manga_detail_providers.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart index 82740fdd..d78ce051 100644 --- a/lib/modules/manga/detail/providers/update_manga_detail_providers.dart +++ b/lib/modules/manga/detail/providers/update_manga_detail_providers.dart @@ -35,7 +35,7 @@ Future updateMangaDetail( final genre = getManga.genre - ?.map((e) => e.toString().trim().trimLeft().trimRight()) + ?.map((e) => e.toString().trim()) .toList() .toSet() .toList() ?? @@ -80,7 +80,7 @@ Future updateMangaDetail( for (var i = 0; i < newChapsIndex; i++) { final chapter = Chapter( name: chaps[i].name!, - url: chaps[i].url!.trim().trimLeft().trimRight(), + url: chaps[i].url!.trim(), dateUpload: chaps[i].dateUpload == null ? DateTime.now().millisecondsSinceEpoch.toString() : chaps[i].dateUpload.toString(), @@ -172,7 +172,7 @@ Future updateMangaDetail( extension DefaultValueExtension on String? { String? trimmedOrDefault(String? defaultValue) { if (this?.trim().isNotEmpty ?? false) { - return this!.trim().trimLeft().trimRight(); + return this!.trim(); } return defaultValue; } From 30c74423ad80e5eedc9ddabaf56df35789faba71 Mon Sep 17 00:00:00 2001 From: NBA2K1 <78034913+NBA2K1@users.noreply.github.com> Date: Sat, 29 Nov 2025 02:57:25 +0100 Subject: [PATCH 6/6] dispose in correct order --- lib/modules/anime/anime_player_view.dart | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/modules/anime/anime_player_view.dart b/lib/modules/anime/anime_player_view.dart index 6fbfe08a..28cc93f7 100644 --- a/lib/modules/anime/anime_player_view.dart +++ b/lib/modules/anime/anime_player_view.dart @@ -964,30 +964,31 @@ mp.register_script_message('call_button_${button.id}_long', button${button.id}lo @override void dispose() { _currentPosition.removeListener(_updateRpcTimestamp); + _subDelayController.removeListener(_onSubDelayChanged); + _subSpeedController.removeListener(_onSubSpeedChanged); WidgetsBinding.instance.removeObserver(this); _setCurrentPosition(true); - _player.dispose(); + _player.stop(); + _completed.cancel(); _currentPositionSub.cancel(); _currentTotalDurationSub.cancel(); - _completed.cancel(); + _currentPosition.dispose(); + _currentTotalDuration.dispose(); _video.dispose(); _playbackSpeed.dispose(); _isDoubleSpeed.dispose(); - _currentTotalDuration.dispose(); _showFitLabel.dispose(); _isCompleted.dispose(); _tempPosition.dispose(); _fit.dispose(); - if (!_isDesktop) { - _setLandscapeMode(false); - } _skipPhase.dispose(); - discordRpc?.showIdleText(); - discordRpc?.showOriginalTimestamp(); - _currentPosition.dispose(); _subDelayController.dispose(); _subSpeedController.dispose(); + if (!_isDesktop) _setLandscapeMode(false); + discordRpc?.showIdleText(); + discordRpc?.showOriginalTimestamp(); _streamController.keepAliveLink?.close(); + _player.dispose(); super.dispose(); }