diff --git a/lib/app_sources/directAPKLink.dart b/lib/app_sources/directAPKLink.dart index d17b3d7..5fc4d3a 100644 --- a/lib/app_sources/directAPKLink.dart +++ b/lib/app_sources/directAPKLink.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:obtainium/app_sources/html.dart'; +import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; @@ -8,12 +9,23 @@ class DirectAPKLink extends AppSource { DirectAPKLink() { name = tr('directAPKLink'); - additionalSourceAppSpecificSettingFormItems = html - .additionalSourceAppSpecificSettingFormItems - .where((element) => element - .where((element) => element.key == 'requestHeader') - .isNotEmpty) - .toList(); + additionalSourceAppSpecificSettingFormItems = [ + ...html.additionalSourceAppSpecificSettingFormItems + .where((element) => element + .where((element) => element.key == 'requestHeader') + .isNotEmpty) + .toList(), + [ + GeneratedFormDropdown( + 'defaultPseudoVersioningMethod', + [ + MapEntry('partialAPKHash', tr('partialAPKHash')), + MapEntry('ETag', 'ETag') + ], + label: tr('defaultPseudoVersioningMethod'), + defaultValue: 'partialAPKHash') + ] + ]; excludeCommonSettingKeys = [ 'versionExtractionRegEx', 'matchGroupToUse', @@ -57,9 +69,8 @@ class DirectAPKLink extends AppSource { additionalSettingsNew[s] = additionalSettings[s]; } } - additionalSettingsNew['defaultPseudoVersioningMethod'] = 'partialAPKHash'; additionalSettingsNew['directAPKLink'] = true; - additionalSettings['versionDetection'] = false; + additionalSettingsNew['versionDetection'] = false; return html.getLatestAPKDetails(standardUrl, additionalSettingsNew); } } diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart index b05dc7f..6c8269c 100644 --- a/lib/app_sources/html.dart +++ b/lib/app_sources/html.dart @@ -263,7 +263,8 @@ class HTML extends AppSource { 'defaultPseudoVersioningMethod', [ MapEntry('partialAPKHash', tr('partialAPKHash')), - MapEntry('APKLinkHash', tr('APKLinkHash')) + MapEntry('APKLinkHash', tr('APKLinkHash')), + MapEntry('ETag', 'ETag') ], label: tr('defaultPseudoVersioningMethod'), defaultValue: 'partialAPKHash') @@ -356,14 +357,24 @@ class HTML extends AppSource { additionalSettings['versionExtractWholePage'] == true ? versionExtractionWholePageString : relDecoded); - version ??= additionalSettings['defaultPseudoVersioningMethod'] == - 'APKLinkHash' - ? rel.hashCode.toString() - : (await checkPartialDownloadHashDynamic(rel, - headers: await getRequestHeaders(additionalSettings, - forAPKDownload: true), - allowInsecure: additionalSettings['allowInsecure'] == true)) - .toString(); + var apkReqHeaders = + await getRequestHeaders(additionalSettings, forAPKDownload: true); + if (version == null && + additionalSettings['defaultPseudoVersioningMethod'] == 'ETag') { + version = await checkETagHeader(rel, + headers: apkReqHeaders, + allowInsecure: additionalSettings['allowInsecure'] == true); + if (version == null) { + throw NoVersionError(); + } + } + version ??= + additionalSettings['defaultPseudoVersioningMethod'] == 'APKLinkHash' + ? rel.hashCode.toString() + : (await checkPartialDownloadHashDynamic(rel, + headers: apkReqHeaders, + allowInsecure: additionalSettings['allowInsecure'] == true)) + .toString(); return APKDetails( version, [rel].map((e) { diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index 940a2b6..fc1a0a2 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -220,6 +220,19 @@ Future checkPartialDownloadHash(String url, int bytesToGrab, return hashListOfLists(bytes); } +Future checkETagHeader(String url, + {Map? headers, bool allowInsecure = false}) async { + // Send the initial request but cancel it as soon as you have the headers + 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; + client.close(); + return resHeaders[HttpHeaders.etagHeader]; +} + Future downloadFile(String url, String fileName, bool fileNameHasExt, Function? onProgress, String destDir, {bool useExisting = true,