diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart
index 6c8269c..af26cec 100644
--- a/lib/app_sources/html.dart
+++ b/lib/app_sources/html.dart
@@ -1,3 +1,5 @@
+import 'dart:convert';
+
import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart';
@@ -67,6 +69,27 @@ int compareAlphaNumeric(String a, String b) {
return aParts.length.compareTo(bParts.length);
}
+List collectAllStringsFromJSONObject(dynamic obj) {
+ List extractor(dynamic obj) {
+ final results = [];
+ if (obj is String) {
+ results.add(obj);
+ } else if (obj is List) {
+ for (final item in obj) {
+ results.addAll(extractor(item));
+ }
+ } else if (obj is Map) {
+ for (final value in obj.values) {
+ results.addAll(extractor(value));
+ }
+ }
+
+ return results;
+ }
+
+ return extractor(obj);
+}
+
List _splitAlphaNumeric(String s) {
List parts = [];
StringBuffer sb = StringBuffer();
@@ -95,6 +118,13 @@ bool _isNumeric(String s) {
return s.codeUnitAt(0) >= 48 && s.codeUnitAt(0) <= 57;
}
+List> getLinksInLines(String lines) => RegExp(
+ r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
+ .allMatches(lines)
+ .map((match) =>
+ MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
+ .toList();
+
// Given an HTTP response, grab some links according to the common additional settings
// (those that apply to intermediate and final steps)
Future>> grabLinksCommon(
@@ -114,12 +144,21 @@ Future>> grabLinksCommon(
.map((e) => MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value))
.toList();
if (allLinks.isEmpty) {
- allLinks = RegExp(
- r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?')
- .allMatches(res.body)
- .map((match) =>
- MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? ''))
- .toList();
+ allLinks = getLinksInLines(res.body);
+ }
+ if (allLinks.isEmpty) {
+ // Getting desperate
+ try {
+ var jsonStrings = collectAllStringsFromJSONObject(jsonDecode(res.body));
+ allLinks = getLinksInLines(jsonStrings.join('\n'));
+ if (allLinks.isEmpty) {
+ allLinks = getLinksInLines(jsonStrings.map((l) {
+ return ensureAbsoluteUrl(l, res.request!.url);
+ }).join('\n'));
+ }
+ } catch (e) {
+ //
+ }
}
List> links = [];
bool skipSort = additionalSettings['skipSort'] == true;
diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart
index 833f1c7..3fe46be 100644
--- a/lib/providers/apps_provider.dart
+++ b/lib/providers/apps_provider.dart
@@ -7,7 +7,6 @@ import 'dart:io';
import 'dart:math';
import 'package:battery_plus/battery_plus.dart';
import 'package:fluttertoast/fluttertoast.dart';
-import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'dart:typed_data';
@@ -246,9 +245,9 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
var reqHeaders = headers ?? {};
var req = Request('GET', Uri.parse(url));
req.headers.addAll(reqHeaders);
- var client = IOClient(createHttpClient(allowInsecure));
- StreamedResponse response = await client.send(req);
- var resHeaders = response.headers;
+ var headersClient = IOClient(createHttpClient(allowInsecure));
+ StreamedResponse headersResponse = await headersClient.send(req);
+ var resHeaders = headersResponse.headers;
// Use the headers to decide what the file extension is, and
// whether it supports partial downloads (range request), and
@@ -276,21 +275,20 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
rangeFeatureEnabled =
resHeaders['accept-ranges']?.trim().toLowerCase() == 'bytes';
}
+ headersClient.close();
// If you have an existing file that is usable,
// decide whether you can use it (either return full or resume partial)
- var fullContentLength = response.contentLength;
+ var fullContentLength = headersResponse.contentLength;
if (useExisting && downloadedFile.existsSync()) {
var length = downloadedFile.lengthSync();
if (fullContentLength == null || !rangeFeatureEnabled) {
// If there is no content length reported, assume it the existing file is fully downloaded
// Also if the range feature is not supported, don't trust the content length if any (#1542)
- client.close();
return downloadedFile;
} else {
// Check if resume needed/possible
if (length == fullContentLength) {
- client.close();
return downloadedFile;
}
if (length > fullContentLength) {
@@ -330,7 +328,6 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
if (shouldReturn) {
logs?.add(
'Existing partial download completed - not repeating: ${tempDownloadedFile.uri.pathSegments.last}');
- client.close();
return downloadedFile;
} else {
logs?.add(
@@ -346,17 +343,18 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
: null;
int rangeStart = targetFileLength ?? 0;
IOSink? sink;
+ req = Request('GET', Uri.parse(url));
+ req.headers.addAll(reqHeaders);
if (rangeFeatureEnabled && fullContentLength != null && rangeStart > 0) {
- client.close();
- client = IOClient(createHttpClient(allowInsecure));
- req = Request('GET', Uri.parse(url));
- req.headers.addAll(reqHeaders);
- req.headers.addAll({'range': 'bytes=$rangeStart-${fullContentLength - 1}'});
- response = await client.send(req);
+ reqHeaders.addAll({'range': 'bytes=$rangeStart-${fullContentLength - 1}'});
sink = tempDownloadedFile.openWrite(mode: FileMode.writeOnlyAppend);
} else if (tempDownloadedFile.existsSync()) {
tempDownloadedFile.deleteSync(recursive: true);
}
+ var responseWithClient =
+ await sourceRequestStreamResponse('GET', url, reqHeaders, {});
+ HttpClient responseClient = responseWithClient.key;
+ HttpClientResponse response = responseWithClient.value;
sink ??= tempDownloadedFile.openWrite(mode: FileMode.writeOnly);
// Perform the download
@@ -369,7 +367,8 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
const downloadUIUpdateInterval = Duration(milliseconds: 500);
const downloadBufferSize = 32 * 1024; // 32KB
final downloadBuffer = BytesBuilder();
- await response.stream
+ await response
+ .asBroadcastStream()
.map((chunk) {
received += chunk.length;
final now = DateTime.now();
@@ -407,31 +406,15 @@ Future downloadFile(String url, String fileName, bool fileNameHasExt,
}
if (response.statusCode < 200 || response.statusCode > 299) {
tempDownloadedFile.deleteSync(recursive: true);
- throw response.reasonPhrase ?? tr('unexpectedError');
+ throw response.reasonPhrase;
}
if (tempDownloadedFile.existsSync()) {
tempDownloadedFile.renameSync(downloadedFile.path);
}
- client.close();
+ responseClient.close();
return downloadedFile;
}
-Future