diff --git a/lib/modules/manga/detail/manga_details_view.dart b/lib/modules/manga/detail/manga_details_view.dart index 9bb699e..73b188f 100644 --- a/lib/modules/manga/detail/manga_details_view.dart +++ b/lib/modules/manga/detail/manga_details_view.dart @@ -15,7 +15,6 @@ import 'package:mangayomi/modules/manga/detail/manga_detail_view.dart'; import 'package:mangayomi/modules/manga/detail/providers/state_providers.dart'; import 'package:mangayomi/modules/manga/detail/widgets/chapter_filter_list_tile_widget.dart'; import 'package:mangayomi/modules/more/providers/incognito_mode_state_provider.dart'; -import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/utils/extensions/chapter.dart'; class MangaDetailsView extends ConsumerStatefulWidget { @@ -59,6 +58,9 @@ class _MangaDetailsViewState extends ConsumerState { (q) => q.isMangaEqualTo(widget.manga.isManga!))) .watch(fireImmediately: true), builder: (context, snapshot) { + final isFr = + ref.watch(l10nLocaleStateProvider).languageCode == + "fr"; if (snapshot.hasData && snapshot.data!.isNotEmpty) { final incognitoMode = ref.watch(incognitoModeStateProvider); @@ -68,9 +70,7 @@ class _MangaDetailsViewState extends ConsumerState { .toList() .reversed .toList(); - final isFr = - ref.watch(l10nLocaleStateProvider).languageCode == - "fr"; + if (entries.isNotEmpty && !incognitoMode) { final chap = entries.first.chapter.value!; return CustomFloatingActionBtn( @@ -98,7 +98,20 @@ class _MangaDetailsViewState extends ConsumerState { width: isFr ? 130 : 90, ); } - return const ProgressCenter(); + return CustomFloatingActionBtn( + isExtended: !isExtended, + label: l10n.read, + onPressed: () { + widget.manga.chapters + .toList() + .reversed + .toList() + .last + .pushToReaderView(context); + }, + textWidth: isFr ? 80 : 40, + width: isFr ? 130 : 90, + ); }, ) : Container(); diff --git a/lib/modules/manga/download/providers/download_provider.dart b/lib/modules/manga/download/providers/download_provider.dart index c50eeb6..f88149c 100644 --- a/lib/modules/manga/download/providers/download_provider.dart +++ b/lib/modules/manga/download/providers/download_provider.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:mangayomi/models/page.dart'; +import 'package:mangayomi/modules/more/settings/advanced/providers/native_http_client.dart'; import 'package:mangayomi/services/background_downloader/background_downloader.dart'; import 'package:isar/isar.dart'; import 'package:mangayomi/main.dart'; @@ -20,8 +21,6 @@ import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'download_provider.g.dart'; -FileDownloader _mangaFileDownloader = FileDownloader(isAnime: false); -FileDownloader _animeFileDownloader = FileDownloader(isAnime: true); @riverpod Future> downloadChapter( DownloadChapterRef ref, { @@ -251,7 +250,10 @@ Future> downloadChapter( }); } else { if (isManga) { - await _mangaFileDownloader.downloadBatch( + await FileDownloader( + useNativeHttpClient: + ref.watch(useNativeHttpClientStateProvider)) + .downloadBatch( tasks, batchProgressCallback: (succeeded, failed) async { if (succeeded == tasks.length) { @@ -307,7 +309,7 @@ Future> downloadChapter( }, ); } else { - await _animeFileDownloader.download( + await FileDownloader(useNativeHttpClient: false).download( tasks.first, onProgress: (progress) async { bool isEmpty = isar.downloads diff --git a/lib/services/background_downloader/src/base_downloader.dart b/lib/services/background_downloader/src/base_downloader.dart index bf40818..af23441 100644 --- a/lib/services/background_downloader/src/base_downloader.dart +++ b/lib/services/background_downloader/src/base_downloader.dart @@ -6,8 +6,8 @@ import 'dart:math'; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; -import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader.dart'; -import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_anime.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart'; import 'database.dart'; import 'exceptions.dart'; import 'models.dart'; @@ -100,9 +100,11 @@ abstract base class BaseDownloader { BaseDownloader(); - factory BaseDownloader.instance( - PersistentStorage persistentStorage, Database database, bool isAnime) { - final instance = isAnime ? DesktopDownloaderAnime() : DesktopDownloader(); + factory BaseDownloader.instance(PersistentStorage persistentStorage, + Database database, bool useNativeHttpClient) { + final instance = !useNativeHttpClient + ? DesktopDownloaderHttpClient() + : DesktopDownloaderNativeHttpClient(); instance._storage = persistentStorage; instance.database = database; unawaited(instance.initialize()); diff --git a/lib/services/background_downloader/src/desktop/data_isolate.dart b/lib/services/background_downloader/src/desktop/data_isolate.dart index d410fc2..a64ed72 100644 --- a/lib/services/background_downloader/src/desktop/data_isolate.dart +++ b/lib/services/background_downloader/src/desktop/data_isolate.dart @@ -2,9 +2,10 @@ import 'dart:async'; import 'dart:isolate'; import 'package:http/http.dart' as http; - +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart' + as desktop_downloader_native; import 'package:mangayomi/services/background_downloader/background_downloader.dart'; -import 'desktop_downloader.dart'; import 'download_isolate.dart'; import 'isolate.dart'; @@ -12,8 +13,11 @@ import 'isolate.dart'; /// /// Sends updates via the [sendPort] and can be commanded to cancel via /// the [messagesToIsolate] queue -Future doDataTask(DataTask task, SendPort sendPort) async { - final client = DesktopDownloader.httpClient; +Future doDataTask( + DataTask task, SendPort sendPort, bool useNativeHttpClient) async { + final client = useNativeHttpClient + ? desktop_downloader_native.DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient; var request = http.Request(task.httpRequestMethod, Uri.parse(task.url)); request.headers.addAll(task.headers); if (task.post is String) { diff --git a/lib/services/background_downloader/src/desktop/desktop_downloader_anime.dart b/lib/services/background_downloader/src/desktop/desktop_downloader_http_client.dart similarity index 97% rename from lib/services/background_downloader/src/desktop/desktop_downloader_anime.dart rename to lib/services/background_downloader/src/desktop/desktop_downloader_http_client.dart index 99b891b..b09f965 100644 --- a/lib/services/background_downloader/src/desktop/desktop_downloader_anime.dart +++ b/lib/services/background_downloader/src/desktop/desktop_downloader_http_client.dart @@ -9,7 +9,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/services.dart'; import 'package:http/io_client.dart'; import 'package:logging/logging.dart'; -import 'package:mangayomi/services/http/m_client.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; import '../base_downloader.dart'; @@ -28,26 +27,29 @@ const okResponses = [200, 201, 202, 203, 204, 205, 206]; /// On desktop (MacOS, Linux, Windows) the download and upload are implemented /// in Dart, as there is no native platform equivalent of URLSession or /// WorkManager as there is on iOS and Android -final class DesktopDownloaderAnime extends BaseDownloader { - static final _log = Logger('DesktopDownloaderAnime'); +final class DesktopDownloaderHttpClient extends BaseDownloader { + static final _log = Logger('DesktopDownloaderHttpClient'); static const unlimited = 1 << 20; var maxConcurrent = 10; var maxConcurrentByHost = unlimited; var maxConcurrentByGroup = unlimited; - static final DesktopDownloaderAnime _singleton = DesktopDownloaderAnime._internal(); + static final DesktopDownloaderHttpClient _singleton = + DesktopDownloaderHttpClient._internal(); final _queue = PriorityQueue(); final _running = Queue(); // subset that is running final _resume = {}; final _isolateSendPorts = {}; // isolate SendPort for running task - static var httpClient = MClient.httpClient(); + static var httpClient = IOClient(HttpClient() + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true); static Duration? _requestTimeout; static var _proxy = {}; // 'address' and 'port' static var _bypassTLSCertificateValidation = false; - factory DesktopDownloaderAnime() => _singleton; + factory DesktopDownloaderHttpClient() => _singleton; - DesktopDownloaderAnime._internal(); + DesktopDownloaderHttpClient._internal(); @override Future enqueue(Task task) async { @@ -140,7 +142,7 @@ final class DesktopDownloaderAnime extends BaseDownloader { return; } log.finer('${isResume ? "Resuming" : "Starting"} taskId ${task.taskId}'); - await Isolate.spawn(doTask, (rootIsolateToken, receivePort.sendPort), + await Isolate.spawn(doTask, (rootIsolateToken, receivePort.sendPort, false), onError: errorPort.sendPort); final messagesFromIsolate = StreamQueue(receivePort); final sendPort = await messagesFromIsolate.next as SendPort; diff --git a/lib/services/background_downloader/src/desktop/desktop_downloader.dart b/lib/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart similarity index 97% rename from lib/services/background_downloader/src/desktop/desktop_downloader.dart rename to lib/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart index cce8022..9b97018 100644 --- a/lib/services/background_downloader/src/desktop/desktop_downloader.dart +++ b/lib/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart @@ -28,26 +28,27 @@ const okResponses = [200, 201, 202, 203, 204, 205, 206]; /// On desktop (MacOS, Linux, Windows) the download and upload are implemented /// in Dart, as there is no native platform equivalent of URLSession or /// WorkManager as there is on iOS and Android -final class DesktopDownloader extends BaseDownloader { - static final _log = Logger('DesktopDownloader'); +final class DesktopDownloaderNativeHttpClient extends BaseDownloader { + static final _log = Logger('DesktopDownloaderNativeHttpClient'); static const unlimited = 1 << 20; var maxConcurrent = 10; var maxConcurrentByHost = unlimited; var maxConcurrentByGroup = unlimited; - static final DesktopDownloader _singleton = DesktopDownloader._internal(); + static final DesktopDownloaderNativeHttpClient _singleton = + DesktopDownloaderNativeHttpClient._internal(); final _queue = PriorityQueue(); final _running = Queue(); // subset that is running final _resume = {}; final _isolateSendPorts = {}; // isolate SendPort for running task - static var httpClient = MClient.httpClient(); + static var httpClient = MClient.nativeHttpClient(); static Duration? _requestTimeout; static var _proxy = {}; // 'address' and 'port' static var _bypassTLSCertificateValidation = false; - factory DesktopDownloader() => _singleton; + factory DesktopDownloaderNativeHttpClient() => _singleton; - DesktopDownloader._internal(); + DesktopDownloaderNativeHttpClient._internal(); @override Future enqueue(Task task) async { @@ -140,7 +141,7 @@ final class DesktopDownloader extends BaseDownloader { return; } log.finer('${isResume ? "Resuming" : "Starting"} taskId ${task.taskId}'); - await Isolate.spawn(doTask, (rootIsolateToken, receivePort.sendPort), + await Isolate.spawn(doTask, (rootIsolateToken, receivePort.sendPort, true), onError: errorPort.sendPort); final messagesFromIsolate = StreamQueue(receivePort); final sendPort = await messagesFromIsolate.next as SendPort; @@ -582,7 +583,7 @@ final class DesktopDownloader extends BaseDownloader { (X509Certificate cert, String host, int port) => true; httpClient = IOClient(client); } else { - httpClient = MClient.httpClient(); + httpClient = MClient.nativeHttpClient(); } } diff --git a/lib/services/background_downloader/src/desktop/download_isolate.dart b/lib/services/background_downloader/src/desktop/download_isolate.dart index 60530c9..d49e4c0 100644 --- a/lib/services/background_downloader/src/desktop/download_isolate.dart +++ b/lib/services/background_downloader/src/desktop/download_isolate.dart @@ -6,6 +6,9 @@ import 'dart:isolate'; import 'dart:math'; import 'package:http/http.dart' as http; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart' + as desktop_downloader_native; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; @@ -13,7 +16,6 @@ import '../exceptions.dart'; import '../models.dart'; import '../task.dart'; import '../utils.dart'; -import 'desktop_downloader.dart'; import 'isolate.dart'; var taskRangeStartByte = 0; // Start of the Task's download range @@ -30,7 +32,8 @@ Future doDownloadTask( ResumeData? resumeData, bool isResume, Duration requestTimeout, - SendPort sendPort) async { + SendPort sendPort, + bool useNativeHttpClient) async { // use downloadTask from here on as a 'global' variable in this isolate, // as we may change the filename of the task downloadTask = task; @@ -45,7 +48,9 @@ Future doDownloadTask( final eTag = resumeData?.eTag; isResume = isResume && await determineIfResumeIsPossible(tempFilePath, requiredStartByte); - final client = DesktopDownloader.httpClient; + final client = useNativeHttpClient + ? desktop_downloader_native.DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient; var request = http.Request(downloadTask.httpRequestMethod, Uri.parse(downloadTask.url)); request.headers.addAll(downloadTask.headers); diff --git a/lib/services/background_downloader/src/desktop/isolate.dart b/lib/services/background_downloader/src/desktop/isolate.dart index 71f517c..0a31beb 100644 --- a/lib/services/background_downloader/src/desktop/isolate.dart +++ b/lib/services/background_downloader/src/desktop/isolate.dart @@ -7,6 +7,8 @@ import 'dart:isolate'; import 'dart:math'; import 'package:async/async.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart'; import 'package:mangayomi/services/background_downloader/src/exceptions.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -16,7 +18,6 @@ import 'package:logging/logging.dart'; import '../models.dart'; import '../task.dart'; import 'data_isolate.dart'; -import 'desktop_downloader.dart'; import 'download_isolate.dart'; import 'parallel_download_isolate.dart'; import 'upload_isolate.dart'; @@ -50,8 +51,8 @@ final log = Logger('FileDownloader'); /// /// The first message sent back is a [ReceivePort] that is the command port /// for the isolate. The first command must be the arguments: task and filePath. -Future doTask((RootIsolateToken, SendPort) isolateArguments) async { - final (rootIsolateToken, sendPort) = isolateArguments; +Future doTask((RootIsolateToken, SendPort, bool) isolateArguments) async { + final (rootIsolateToken, sendPort, useNativeHttpClient) = isolateArguments; BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken); final receivePort = ReceivePort(); // send the receive port back to the main Isolate @@ -67,8 +68,11 @@ Future doTask((RootIsolateToken, SendPort) isolateArguments) async { Map proxy, bool bypassTLSCertificateValidation ) = await messagesToIsolate.next; - DesktopDownloader.setHttpClient( - requestTimeout, proxy, bypassTLSCertificateValidation); + useNativeHttpClient + ? DesktopDownloaderNativeHttpClient.setHttpClient( + requestTimeout, proxy, bypassTLSCertificateValidation) + : DesktopDownloaderHttpClient.setHttpClient( + requestTimeout, proxy, bypassTLSCertificateValidation); Logger.root.level = Level.ALL; Logger.root.onRecord.listen((LogRecord rec) { if (kDebugMode) { @@ -95,11 +99,18 @@ Future doTask((RootIsolateToken, SendPort) isolateArguments) async { resumeData, isResume, requestTimeout ?? const Duration(seconds: 60), - sendPort), - DownloadTask() => doDownloadTask(task, filePath, resumeData, isResume, - requestTimeout ?? const Duration(seconds: 60), sendPort), - UploadTask() => doUploadTask(task, filePath, sendPort), - DataTask() => doDataTask(task, sendPort) + sendPort, + useNativeHttpClient), + DownloadTask() => doDownloadTask( + task, + filePath, + resumeData, + isResume, + requestTimeout ?? const Duration(seconds: 60), + sendPort, + useNativeHttpClient), + UploadTask() => doUploadTask(task, filePath, sendPort,useNativeHttpClient), + DataTask() => doDataTask(task, sendPort, useNativeHttpClient) }; } receivePort.close(); diff --git a/lib/services/background_downloader/src/desktop/parallel_download_isolate.dart b/lib/services/background_downloader/src/desktop/parallel_download_isolate.dart index 959f2e1..f57eed2 100644 --- a/lib/services/background_downloader/src/desktop/parallel_download_isolate.dart +++ b/lib/services/background_downloader/src/desktop/parallel_download_isolate.dart @@ -7,13 +7,14 @@ import 'dart:isolate'; import 'dart:math'; import 'package:collection/collection.dart'; - +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart' + as desktop_downloader_native; import '../chunk.dart'; import '../exceptions.dart'; import '../models.dart'; import '../task.dart'; import '../utils.dart'; -import 'desktop_downloader.dart'; import 'download_isolate.dart'; import 'isolate.dart'; @@ -64,11 +65,15 @@ Future doParallelDownloadTask( ResumeData? resumeData, bool isResume, Duration requestTimeout, - SendPort sendPort) async { + SendPort sendPort, + bool useNativeHttpClient) async { parentTask = task; if (!isResume) { // start the download by creating [Chunk]s and enqueuing chunk tasks - final response = await DesktopDownloader.httpClient + final response = await (useNativeHttpClient + ? desktop_downloader_native + .DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient) .head(Uri.parse(task.url), headers: task.headers); responseHeaders = response.headers; responseStatusCode = response.statusCode; diff --git a/lib/services/background_downloader/src/desktop/upload_isolate.dart b/lib/services/background_downloader/src/desktop/upload_isolate.dart index 6f1984c..b8ece4e 100644 --- a/lib/services/background_downloader/src/desktop/upload_isolate.dart +++ b/lib/services/background_downloader/src/desktop/upload_isolate.dart @@ -11,7 +11,9 @@ import 'package:path/path.dart' as p; import '../models.dart'; import '../task.dart'; -import 'desktop_downloader.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart' + as desktop_downloader_native; import 'isolate.dart'; const boundary = '-----background_downloader-akjhfw281onqciyhnIk'; @@ -21,11 +23,11 @@ const lineFeed = '\r\n'; /// /// Sends updates via the [sendPort] and can be commanded to cancel via /// the [messagesToIsolate] queue -Future doUploadTask( - UploadTask task, String filePath, SendPort sendPort) async { +Future doUploadTask(UploadTask task, String filePath, SendPort sendPort, + bool useNativeHttpClient) async { final resultStatus = task.post == 'binary' - ? await binaryUpload(task, filePath, sendPort) - : await multipartUpload(task, filePath, sendPort); + ? await binaryUpload(task, filePath, sendPort, useNativeHttpClient) + : await multipartUpload(task, filePath, sendPort, useNativeHttpClient); processStatusUpdateInIsolate(task, resultStatus, sendPort); } @@ -33,8 +35,8 @@ Future doUploadTask( /// /// Sends updates via the [sendPort] and can be commanded to cancel via /// the [messagesToIsolate] queue -Future binaryUpload( - UploadTask task, String filePath, SendPort sendPort) async { +Future binaryUpload(UploadTask task, String filePath, + SendPort sendPort, bool useNativeHttpClient) async { final inFile = File(filePath); if (!inFile.existsSync()) { logError(task, 'file to upload does not exist: $filePath'); @@ -45,7 +47,9 @@ Future binaryUpload( final fileSize = inFile.lengthSync(); var resultStatus = TaskStatus.failed; try { - final client = DesktopDownloader.httpClient; + final client = useNativeHttpClient + ? desktop_downloader_native.DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient; final request = http.StreamedRequest(task.httpRequestMethod, Uri.parse(task.url)); request.headers.addAll(task.headers); @@ -96,8 +100,8 @@ Future binaryUpload( /// /// Sends updates via the [sendPort] and can be commanded to cancel via /// the [messagesToIsolate] queue -Future multipartUpload( - UploadTask task, String filePath, SendPort sendPort) async { +Future multipartUpload(UploadTask task, String filePath, + SendPort sendPort, bool useNativeHttpClient) async { // field portion of the multipart, all in one string // multiple values should be encoded as '"value1", "value2", ...' final multiValueRegEx = RegExp(r'^(?:"[^"]+"\s*,\s*)+"[^"]+"$'); @@ -152,7 +156,9 @@ Future multipartUpload( var resultStatus = TaskStatus.failed; try { // setup the connection - final client = DesktopDownloader.httpClient; + final client = useNativeHttpClient + ? desktop_downloader_native.DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient; final request = http.StreamedRequest(task.httpRequestMethod, Uri.parse(task.url)); request.contentLength = contentLength; diff --git a/lib/services/background_downloader/src/file_downloader.dart b/lib/services/background_downloader/src/file_downloader.dart index b512df3..2bc2e85 100644 --- a/lib/services/background_downloader/src/file_downloader.dart +++ b/lib/services/background_downloader/src/file_downloader.dart @@ -6,7 +6,9 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'base_downloader.dart'; import 'localstore/localstore.dart'; -import 'desktop/desktop_downloader.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_http_client.dart'; +import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader_native_http_client.dart.dart' + as desktop_downloader_native; /// Provides access to all functions of the plugin in a single place. interface class FileDownloader { @@ -32,19 +34,23 @@ interface class FileDownloader { BaseDownloader get downloaderForTesting => _downloader; factory FileDownloader( - {PersistentStorage? persistentStorage, bool isAnime = false}) { + {PersistentStorage? persistentStorage, + bool useNativeHttpClient = false}) { assert( _singleton == null || persistentStorage == null, 'You can only supply a persistentStorage on the very first call to ' 'FileDownloader()'); _singleton ??= FileDownloader._internal( - persistentStorage ?? LocalStorePersistentStorage(), isAnime); + persistentStorage ?? LocalStorePersistentStorage(), + useNativeHttpClient); return _singleton!; } - FileDownloader._internal(PersistentStorage persistentStorage, bool isAnime) { + FileDownloader._internal( + PersistentStorage persistentStorage, bool useNativeHttpClient) { database = Database(persistentStorage); - _downloader = BaseDownloader.instance(persistentStorage, database, isAnime); + _downloader = BaseDownloader.instance( + persistentStorage, database, useNativeHttpClient); } /// True when initialization is complete and downloader ready for use @@ -773,12 +779,27 @@ interface class FileDownloader { /// the downloader. If not set, the default [http.Client] will be used. /// The request is executed on an Isolate, to ensure minimal interference /// with the main Isolate - Future request(Request request) => compute(_doRequest, ( + Future request(Request request, bool useNativeHttpClient) { + if (useNativeHttpClient) { + return compute(_doRequest, ( request, - DesktopDownloader.requestTimeout, - DesktopDownloader.proxy, - DesktopDownloader.bypassTLSCertificateValidation + desktop_downloader_native + .DesktopDownloaderNativeHttpClient.requestTimeout, + desktop_downloader_native.DesktopDownloaderNativeHttpClient.proxy, + desktop_downloader_native + .DesktopDownloaderNativeHttpClient.bypassTLSCertificateValidation, + true )); + } + + return compute(_doRequest, ( + request, + DesktopDownloaderHttpClient.requestTimeout, + DesktopDownloaderHttpClient.proxy, + DesktopDownloaderHttpClient.bypassTLSCertificateValidation, + false + )); + } /// Move the file represented by the [task] to a shared storage /// [destination] and potentially a [directory] within that destination. If @@ -889,13 +910,26 @@ interface class FileDownloader { /// This function is run on an Isolate to ensure performance on the main /// Isolate is not affected Future _doRequest( - (Request, Duration?, Map, bool) params) async { - final (request, requestTimeout, proxy, bypassTLSCertificateValidation) = - params; + (Request, Duration?, Map, bool, bool) params) async { + final ( + request, + requestTimeout, + proxy, + bypassTLSCertificateValidation, + useNativeHttpClient + ) = params; - DesktopDownloader.setHttpClient( - requestTimeout, proxy, bypassTLSCertificateValidation); - final client = DesktopDownloader.httpClient; + if (useNativeHttpClient) { + desktop_downloader_native.DesktopDownloaderNativeHttpClient.setHttpClient( + requestTimeout, proxy, bypassTLSCertificateValidation); + } else { + DesktopDownloaderHttpClient.setHttpClient( + requestTimeout, proxy, bypassTLSCertificateValidation); + } + + final client = useNativeHttpClient + ? desktop_downloader_native.DesktopDownloaderNativeHttpClient.httpClient + : DesktopDownloaderHttpClient.httpClient; var response = http.Response('', 499, reasonPhrase: 'Not attempted'); // dummy to start with while (request.retriesRemaining >= 0) { diff --git a/lib/services/background_downloader/src/task.dart b/lib/services/background_downloader/src/task.dart index f593577..44a9e18 100644 --- a/lib/services/background_downloader/src/task.dart +++ b/lib/services/background_downloader/src/task.dart @@ -8,11 +8,9 @@ import 'dart:typed_data'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; -import 'package:mangayomi/services/background_downloader/src/desktop/desktop_downloader.dart'; import 'package:mime/mime.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; - import 'file_downloader.dart'; import 'models.dart'; import 'utils.dart'; @@ -669,39 +667,6 @@ final class DownloadTask extends Task { /// /// The suggested filename is obtained by making a HEAD request to the url /// represented by the [DownloadTask], including urlQueryParameters and headers - Future withSuggestedFilename( - {unique = false, - Future Function( - DownloadTask task, Map headers, bool unique) - taskWithFilenameBuilder = taskWithSuggestedFilename}) async { - try { - final response = await DesktopDownloader.httpClient - .head(Uri.parse(url), headers: headers); - if ([200, 201, 202, 203, 204, 205, 206].contains(response.statusCode)) { - return taskWithFilenameBuilder(this, response.headers, unique); - } - } catch (e) { - _log.finer('Error connecting to server'); - } - return taskWithFilenameBuilder(this, {}, unique); - } - - /// Return the expected file size for this task, or -1 if unknown - /// - /// The expected file size is obtained by making a HEAD request to the url - /// represented by the [DownloadTask], including urlQueryParameters and headers - Future expectedFileSize() async { - try { - final response = await DesktopDownloader.httpClient - .head(Uri.parse(url), headers: headers); - if ([200, 201, 202, 203, 204, 205, 206].contains(response.statusCode)) { - return getContentLength(response.headers, this); - } - } catch (e) { - // no content length available - } - return -1; - } /// Constant used with `filename` field to indicate server suggestion requested static const suggestedFilename = '?'; diff --git a/lib/services/http/m_client.dart b/lib/services/http/m_client.dart index 6569101..e9db47a 100644 --- a/lib/services/http/m_client.dart +++ b/lib/services/http/m_client.dart @@ -15,24 +15,27 @@ import 'package:mangayomi/utils/log/log.dart'; class MClient { MClient(); static Client httpClient() { - if ((Platform.isAndroid || Platform.isIOS || Platform.isMacOS) && - (isar.settings.getSync(227)?.useNativeHttpClient ?? false)) { - if (Platform.isAndroid) { - final engine = CronetEngine.build( - enablePublicKeyPinningBypassForLocalTrustAnchors: true, - enableHttp2: true, - enableBrotli: true, - cacheMode: CacheMode.memory, - cacheMaxSize: 5 * 1024 * 1024); - return CronetClient.fromCronetEngine(engine, closeEngine: true); - } - if (Platform.isIOS || Platform.isMacOS) { - final config = URLSessionConfiguration.ephemeralSessionConfiguration() - ..cache = URLCache.withCapacity(memoryCapacity: 5 * 1024 * 1024); - return CupertinoClient.fromSessionConfiguration(config); - } + if (isar.settings.getSync(227)?.useNativeHttpClient ?? false) { + return nativeHttpClient(); } + return IOClient(HttpClient()); + } + static Client nativeHttpClient() { + if (Platform.isAndroid) { + final engine = CronetEngine.build( + enablePublicKeyPinningBypassForLocalTrustAnchors: true, + enableHttp2: true, + enableBrotli: true, + cacheMode: CacheMode.memory, + cacheMaxSize: 5 * 1024 * 1024); + return CronetClient.fromCronetEngine(engine, closeEngine: true); + } + if (Platform.isIOS || Platform.isMacOS) { + final config = URLSessionConfiguration.ephemeralSessionConfiguration() + ..cache = URLCache.withCapacity(memoryCapacity: 5 * 1024 * 1024); + return CupertinoClient.fromSessionConfiguration(config); + } return IOClient(HttpClient()); }