mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-25 03:43:46 +02:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			39b76a41cf
			...
			experiment
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ab43856b90 | 
| @@ -45,7 +45,7 @@ class APKCombo extends AppSource { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var html = parse(res.body); | ||||
|     var html = parse(res.data); | ||||
|     return html | ||||
|         .querySelectorAll('#variants-tab > div > ul > li') | ||||
|         .map((e) { | ||||
| @@ -96,7 +96,7 @@ class APKCombo extends AppSource { | ||||
|     if (preres.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(preres); | ||||
|     } | ||||
|     var res = parse(preres.body); | ||||
|     var res = parse(preres.data); | ||||
|     String? version = res.querySelector('div.version')?.text.trim(); | ||||
|     if (version == null) { | ||||
|       throw NoVersionError(); | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -62,7 +62,7 @@ class APKMirror extends AppSource { | ||||
|             : null; | ||||
|     Response res = await sourceRequest('$standardUrl/feed', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var items = parse(res.body).querySelectorAll('item'); | ||||
|       var items = parse(res.data).querySelectorAll('item'); | ||||
|       dynamic targetRelease; | ||||
|       for (int i = 0; i < items.length; i++) { | ||||
|         if (!fallbackToOlderReleases && i > 0) break; | ||||
|   | ||||
| @@ -61,8 +61,8 @@ class APKPure extends AppSource { | ||||
|     var res = await sourceRequest('$standardUrl/download', additionalSettings); | ||||
|     var resChangelog = await sourceRequest(standardUrl, additionalSettings); | ||||
|     if (res.statusCode == 200 && resChangelog.statusCode == 200) { | ||||
|       var html = parse(res.body); | ||||
|       var htmlChangelog = parse(resChangelog.body); | ||||
|       var html = parse(res.data); | ||||
|       var htmlChangelog = parse(resChangelog.data); | ||||
|       String? version = html.querySelector('span.info-sdk span')?.text.trim(); | ||||
|       if (version == null) { | ||||
|         throw NoVersionError(); | ||||
|   | ||||
| @@ -38,10 +38,10 @@ class Aptoide extends AppSource { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var idMatch = RegExp('"app":{"id":[0-9]+').firstMatch(res.body); | ||||
|     var idMatch = RegExp('"app":{"id":[0-9]+').firstMatch(res.data); | ||||
|     String? id; | ||||
|     if (idMatch != null) { | ||||
|       id = res.body.substring(idMatch.start + 12, idMatch.end); | ||||
|       id = res.data.substring(idMatch.start + 12, idMatch.end); | ||||
|     } else { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
| @@ -50,7 +50,7 @@ class Aptoide extends AppSource { | ||||
|     if (res2.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     return jsonDecode(res2.body)?['nodes']?['meta']?['data']; | ||||
|     return jsonDecode(res2.data)?['nodes']?['meta']?['data']; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/app_sources/gitlab.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| @@ -82,7 +82,7 @@ class FDroid extends AppSource { | ||||
|         var res = await sourceRequest( | ||||
|             'https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/$appId.yml', | ||||
|             additionalSettings); | ||||
|         var lines = res.body.split('\n'); | ||||
|         var lines = res.data.split('\n'); | ||||
|         var authorLines = lines.where((l) => l.startsWith('AuthorName: ')); | ||||
|         if (authorLines.isNotEmpty) { | ||||
|           details.names.author = | ||||
| @@ -112,7 +112,7 @@ class FDroid extends AppSource { | ||||
|             details.changeLog = (await sourceRequest( | ||||
|                     details.changeLog!.replaceFirst('/blob/', '/raw/'), | ||||
|                     additionalSettings)) | ||||
|                 .body; | ||||
|                 .data; | ||||
|           } | ||||
|         } | ||||
|       } catch (e) { | ||||
| @@ -132,7 +132,7 @@ class FDroid extends AppSource { | ||||
|         'https://search.${hosts[0]}/?q=${Uri.encodeQueryComponent(query)}', {}); | ||||
|     if (res.statusCode == 200) { | ||||
|       Map<String, List<String>> urlsWithDescriptions = {}; | ||||
|       parse(res.body).querySelectorAll('.package-header').forEach((e) { | ||||
|       parse(res.data).querySelectorAll('.package-header').forEach((e) { | ||||
|         String? url = e.attributes['href']; | ||||
|         if (url != null) { | ||||
|           try { | ||||
| @@ -172,7 +172,7 @@ class FDroid extends AppSource { | ||||
|             ? additionalSettings['apkFilterRegEx'] | ||||
|             : null; | ||||
|     if (res.statusCode == 200) { | ||||
|       var response = jsonDecode(res.body); | ||||
|       var response = jsonDecode(res.data); | ||||
|       List<dynamic> releases = response['packages'] ?? []; | ||||
|       if (apkFilterRegEx != null) { | ||||
|         releases = releases.where((rel) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -61,9 +61,10 @@ class FDroidRepo extends AppSource { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
|     url = removeQueryParamsFromUrl(standardizeUrl(url)); | ||||
|     var res = await sourceRequestWithURLVariants(url, {}); | ||||
|     var ress = await sourceRequestWithURLVariants(url, {}); | ||||
|     var res = ress.value; | ||||
|     if (res.statusCode == 200) { | ||||
|       var body = parse(res.body); | ||||
|       var body = parse(res.data); | ||||
|       Map<String, List<String>> results = {}; | ||||
|       body.querySelectorAll('application').toList().forEach((app) { | ||||
|         String appId = app.attributes['id']!; | ||||
| @@ -74,7 +75,7 @@ class FDroidRepo extends AppSource { | ||||
|             appName.contains(query) || | ||||
|             appDesc.contains(query)) { | ||||
|           results[ | ||||
|               '${res.request!.url.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}?appId=$appId'] = [ | ||||
|               '${ress.value.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}?appId=$appId'] = [ | ||||
|             appName, | ||||
|             appDesc | ||||
|           ]; | ||||
| @@ -107,24 +108,24 @@ class FDroidRepo extends AppSource { | ||||
|     return app; | ||||
|   } | ||||
|  | ||||
|   Future<Response> sourceRequestWithURLVariants( | ||||
|   Future<MapEntry<String, Response>> sourceRequestWithURLVariants( | ||||
|     String url, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     var res = await sourceRequest( | ||||
|         '$url${url.endsWith('/index.xml') ? '' : '/index.xml'}', | ||||
|         additionalSettings); | ||||
|     var finalUrl = '$url${url.endsWith('/index.xml') ? '' : '/index.xml'}'; | ||||
|     var res = await sourceRequest(finalUrl, additionalSettings); | ||||
|     if (res.statusCode != 200) { | ||||
|       var base = url.endsWith('/index.xml') | ||||
|           ? url.split('/').reversed.toList().sublist(1).reversed.join('/') | ||||
|           : url; | ||||
|       res = await sourceRequest('$base/repo/index.xml', additionalSettings); | ||||
|       finalUrl = '$base/repo/index.xml'; | ||||
|       res = await sourceRequest(finalUrl, additionalSettings); | ||||
|       if (res.statusCode != 200) { | ||||
|         res = await sourceRequest( | ||||
|             '$base/fdroid/repo/index.xml', additionalSettings); | ||||
|         finalUrl = '$base/fdroid/repo/index.xml'; | ||||
|         res = await sourceRequest(finalUrl, additionalSettings); | ||||
|       } | ||||
|     } | ||||
|     return res; | ||||
|     return MapEntry(finalUrl, res); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
| @@ -142,10 +143,11 @@ class FDroidRepo extends AppSource { | ||||
|     if (appIdOrName == null) { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
|     var res = | ||||
|     var ress = | ||||
|         await sourceRequestWithURLVariants(standardUrl, additionalSettings); | ||||
|     var res = ress.value; | ||||
|     if (res.statusCode == 200) { | ||||
|       var body = parse(res.body); | ||||
|       var body = parse(res.data); | ||||
|       var foundApps = body.querySelectorAll('application').where((element) { | ||||
|         return element.attributes['id'] == appIdOrName; | ||||
|       }).toList(); | ||||
| @@ -193,7 +195,7 @@ class FDroidRepo extends AppSource { | ||||
|       } | ||||
|       List<String> apkUrls = latestVersionReleases | ||||
|           .map((e) => | ||||
|               '${res.request!.url.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}/${e.querySelector('apkname')!.innerHtml}') | ||||
|               '${ress.value.toString().split('/').reversed.toList().sublist(1).reversed.join('/')}/${e.querySelector('apkname')!.innerHtml}') | ||||
|           .toList(); | ||||
|       return APKDetails(latestVersion, getApkUrlsFromUrls(apkUrls), | ||||
|           AppNames(authorName, appName), | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import 'dart:convert'; | ||||
| import 'dart:io'; | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/html.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| @@ -112,12 +112,12 @@ class GitHub extends AppSource { | ||||
|     ]; | ||||
|     for (var path in possibleBuildGradleLocations) { | ||||
|       try { | ||||
|         var res = await sourceRequest( | ||||
|             '${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/contents/$path', | ||||
|             additionalSettings); | ||||
|         var finalUrl = | ||||
|             '${await convertStandardUrlToAPIUrl(standardUrl, additionalSettings)}/contents/$path'; | ||||
|         var res = await sourceRequest(finalUrl, additionalSettings); | ||||
|         if (res.statusCode == 200) { | ||||
|           try { | ||||
|             var body = jsonDecode(res.body); | ||||
|             var body = jsonDecode(res.data); | ||||
|             var trimmedLines = utf8 | ||||
|                 .decode(base64 | ||||
|                     .decode(body['content'].toString().split('\n').join(''))) | ||||
| @@ -143,7 +143,7 @@ class GitHub extends AppSource { | ||||
|             } | ||||
|           } catch (err) { | ||||
|             LogsProvider().add( | ||||
|                 'Error parsing build.gradle from ${res.request!.url.toString()}: ${err.toString()}'); | ||||
|                 'Error parsing build.gradle from $finalUrl: ${err.toString()}'); | ||||
|           } | ||||
|         } | ||||
|       } catch (err) { | ||||
| @@ -256,11 +256,11 @@ class GitHub extends AppSource { | ||||
|         } | ||||
|         throw getObtainiumHttpError(res); | ||||
|       } | ||||
|       latestRelease = jsonDecode(res.body); | ||||
|       latestRelease = jsonDecode(res.data); | ||||
|     } | ||||
|     Response res = await sourceRequest(requestUrl, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var releases = jsonDecode(res.body) as List<dynamic>; | ||||
|       var releases = jsonDecode(res.data) as List<dynamic>; | ||||
|       if (latestRelease != null) { | ||||
|         var latestTag = latestRelease['tag_name'] ?? latestRelease['name']; | ||||
|         if (releases | ||||
| @@ -466,7 +466,7 @@ class GitHub extends AppSource { | ||||
|           ? int.parse(querySettings['minStarCount']) | ||||
|           : 0; | ||||
|       Map<String, List<String>> urlsWithDescriptions = {}; | ||||
|       for (var e in (jsonDecode(res.body)[rootProp] as List<dynamic>)) { | ||||
|       for (var e in (jsonDecode(res.data)[rootProp] as List<dynamic>)) { | ||||
|         if ((e['stargazers_count'] ?? e['stars_count'] ?? 0) >= minStarCount) { | ||||
|           urlsWithDescriptions.addAll({ | ||||
|             e['html_url'] as String: [ | ||||
| @@ -500,11 +500,13 @@ class GitHub extends AppSource { | ||||
|   } | ||||
|  | ||||
|   rateLimitErrorCheck(Response res) { | ||||
|     if (res.headers['x-ratelimit-remaining'] == '0') { | ||||
|     String? rateLimitHeader; | ||||
|     if (res.headers.map['x-ratelimit-remaining']?.isNotEmpty == true) { | ||||
|       rateLimitHeader = res.headers.map['x-ratelimit-remaining']![0]; | ||||
|     } | ||||
|     if (rateLimitHeader == '0') { | ||||
|       throw RateLimitError( | ||||
|           (int.parse(res.headers['x-ratelimit-reset'] ?? '1800000000') / | ||||
|                   60000000) | ||||
|               .round()); | ||||
|           (int.parse(rateLimitHeader ?? '1800000000') / 60000000).round()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import 'dart:convert'; | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/settings_provider.dart'; | ||||
| @@ -81,7 +81,7 @@ class GitLab extends AppSource { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var json = jsonDecode(res.body) as List<dynamic>; | ||||
|     var json = jsonDecode(res.data) as List<dynamic>; | ||||
|     Map<String, List<String>> results = {}; | ||||
|     for (var element in json) { | ||||
|       results['https://${hosts[0]}/${element['path_with_namespace']}'] = [ | ||||
| @@ -131,7 +131,7 @@ class GitLab extends AppSource { | ||||
|  | ||||
|     // Extract .apk details from received data | ||||
|     Iterable<APKDetails> apkDetailsList = []; | ||||
|     var json = jsonDecode(res.body) as List<dynamic>; | ||||
|     var json = jsonDecode(res.data) as List<dynamic>; | ||||
|     apkDetailsList = json.map((e) { | ||||
|       var apkUrlsFromAssets = (e['assets']?['links'] as List<dynamic>? ?? []) | ||||
|           .map((e) { | ||||
| @@ -152,9 +152,8 @@ class GitLab extends AppSource { | ||||
|       var apkUrlsSet = apkUrlsFromAssets.toSet(); | ||||
|       apkUrlsSet.addAll(uploadedAPKsFromDescription); | ||||
|       var releaseDateString = e['released_at'] ?? e['created_at']; | ||||
|       DateTime? releaseDate = releaseDateString != null | ||||
|           ? DateTime.parse(releaseDateString) | ||||
|           : null; | ||||
|       DateTime? releaseDate = | ||||
|           releaseDateString != null ? DateTime.parse(releaseDateString) : null; | ||||
|       return APKDetails( | ||||
|           e['tag_name'] ?? e['name'], | ||||
|           getApkUrlsFromUrls(apkUrlsSet.toList()), | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/apps_provider.dart'; | ||||
| @@ -213,11 +213,11 @@ class HTML extends AppSource { | ||||
|   // Given an HTTP response, grab some links according to the common additional settings | ||||
|   // (those that apply to intermediate and final steps) | ||||
|   Future<List<MapEntry<String, String>>> grabLinksCommon( | ||||
|       Response res, Map<String, dynamic> additionalSettings) async { | ||||
|       Response res, Uri url, Map<String, dynamic> additionalSettings) async { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var html = parse(res.body); | ||||
|     var html = parse(res.data); | ||||
|     List<MapEntry<String, String>> allLinks = html | ||||
|         .querySelectorAll('a') | ||||
|         .map((element) => MapEntry( | ||||
| @@ -226,13 +226,12 @@ class HTML extends AppSource { | ||||
|                 ? element.text | ||||
|                 : (element.attributes['href'] ?? '').split('/').last)) | ||||
|         .where((element) => element.key.isNotEmpty) | ||||
|         .map((e) => | ||||
|             MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value)) | ||||
|         .map((e) => MapEntry(ensureAbsoluteUrl(e.key, url), e.value)) | ||||
|         .toList(); | ||||
|     if (allLinks.isEmpty) { | ||||
|       allLinks = RegExp( | ||||
|               r'(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?') | ||||
|           .allMatches(res.body) | ||||
|           .allMatches(res.data) | ||||
|           .map((match) => | ||||
|               MapEntry(match.group(0)!, match.group(0)?.split('/').last ?? '')) | ||||
|           .toList(); | ||||
| @@ -285,6 +284,7 @@ class HTML extends AppSource { | ||||
|     for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) { | ||||
|       var intLinks = await grabLinksCommon( | ||||
|           await sourceRequest(currentUrl, additionalSettings), | ||||
|           Uri.parse(currentUrl), | ||||
|           additionalSettings['intermediateLink'][i]); | ||||
|       if (intLinks.isEmpty) { | ||||
|         throw NoReleasesError(); | ||||
| @@ -298,8 +298,9 @@ class HTML extends AppSource { | ||||
|     if (additionalSettings['directAPKLink'] != true) { | ||||
|       Response res = await sourceRequest(currentUrl, additionalSettings); | ||||
|       versionExtractionWholePageString = | ||||
|           res.body.split('\r\n').join('\n').split('\n').join('\\n'); | ||||
|       links = await grabLinksCommon(res, additionalSettings); | ||||
|           res.data.split('\r\n').join('\n').split('\n').join('\\n'); | ||||
|       links = | ||||
|           await grabLinksCommon(res, Uri.parse(currentUrl), additionalSettings); | ||||
|       links = filterApks(links, additionalSettings['apkFilterRegEx'], | ||||
|           additionalSettings['invertAPKFilter']); | ||||
|       if (links.isEmpty) { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -57,8 +57,8 @@ class HuaweiAppGallery extends AppSource { | ||||
|       {Map<String, dynamic> additionalSettings = const {}}) async { | ||||
|     String dlUrl = getDlUrl(standardUrl); | ||||
|     Response res = await requestAppdlRedirect(dlUrl, additionalSettings); | ||||
|     return res.headers['location'] != null | ||||
|         ? appIdFromRedirectDlUrl(res.headers['location']!) | ||||
|     return res.headers.map['location']?.isNotEmpty == true | ||||
|         ? appIdFromRedirectDlUrl(res.headers.map['location']![0]) | ||||
|         : null; | ||||
|   } | ||||
|  | ||||
| @@ -72,9 +72,12 @@ class HuaweiAppGallery extends AppSource { | ||||
|     if (res.headers['location'] == null) { | ||||
|       throw NoReleasesError(); | ||||
|     } | ||||
|     String appId = appIdFromRedirectDlUrl(res.headers['location']!); | ||||
|     var relDateStr = | ||||
|         res.headers['location']?.split('?')[0].split('.').reversed.toList()[1]; | ||||
|     String appId = appIdFromRedirectDlUrl(res.headers.map['location']![0]); | ||||
|     var relDateStr = res.headers.map['location']?[0] | ||||
|         .split('?')[0] | ||||
|         .split('.') | ||||
|         .reversed | ||||
|         .toList()[1]; | ||||
|     var relDateStrAdj = relDateStr?.split(''); | ||||
|     var tempLen = relDateStrAdj?.length ?? 0; | ||||
|     var i = 2; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -33,7 +33,7 @@ class Jenkins extends AppSource { | ||||
|     Response res = await sourceRequest( | ||||
|         '$standardUrl/lastSuccessfulBuild/api/json', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var json = jsonDecode(res.body); | ||||
|       var json = jsonDecode(res.data); | ||||
|       var releaseDate = json['timestamp'] == null | ||||
|           ? null | ||||
|           : DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int); | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -33,7 +33,7 @@ class Mullvad extends AppSource { | ||||
|     Response res = await sourceRequest( | ||||
|         '$standardUrl/en/download/android', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var versions = parse(res.body) | ||||
|       var versions = parse(res.data) | ||||
|           .querySelectorAll('p') | ||||
|           .map((e) => e.innerHtml) | ||||
|           .where((p) => p.contains('Latest version: ')) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -83,7 +83,7 @@ class NeutronCode extends AppSource { | ||||
|   ) async { | ||||
|     Response res = await sourceRequest(standardUrl, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var http = parse(res.body); | ||||
|       var http = parse(res.data); | ||||
|       var name = http.querySelector('.pd-title')?.innerHtml; | ||||
|       var filename = http.querySelector('.pd-filename .pd-float')?.innerHtml; | ||||
|       if (filename == null) { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'dart:convert'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -21,7 +21,7 @@ class Signal extends AppSource { | ||||
|     Response res = await sourceRequest( | ||||
|         'https://updates.${hosts[0]}/android/latest.json', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var json = jsonDecode(res.body); | ||||
|       var json = jsonDecode(res.data); | ||||
|       String? apkUrl = json['url']; | ||||
|       List<String> apkUrls = apkUrl == null ? [] : [apkUrl]; | ||||
|       String? version = json['versionName']; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -49,7 +49,7 @@ class SourceForge extends AppSource { | ||||
|         '${standardUri.origin}/${standardUri.pathSegments.sublist(0, 2).join('/')}/rss?path=/', | ||||
|         additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var parsedHtml = parse(res.body); | ||||
|       var parsedHtml = parse(res.data); | ||||
|       var allDownloadLinks = parsedHtml | ||||
|           .querySelectorAll('guid') | ||||
|           .map((e) => e.innerHtml) | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/html.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -55,7 +55,7 @@ class SourceHut extends AppSource { | ||||
|     Response res = | ||||
|         await sourceRequest('$standardUrl/refs/rss.xml', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var parsedHtml = parse(res.body); | ||||
|       var parsedHtml = parse(res.data); | ||||
|       List<APKDetails> apkDetailsList = []; | ||||
|       int ind = 0; | ||||
|  | ||||
| @@ -85,7 +85,7 @@ class SourceHut extends AppSource { | ||||
|         var res2 = await sourceRequest(releasePage, additionalSettings); | ||||
|         List<MapEntry<String, String>> apkUrls = []; | ||||
|         if (res2.statusCode == 200) { | ||||
|           apkUrls = getApkUrlsFromUrls(parse(res2.body) | ||||
|           apkUrls = getApkUrlsFromUrls(parse(res2.data) | ||||
|               .querySelectorAll('a') | ||||
|               .map((e) => e.attributes['href'] ?? '') | ||||
|               .where((e) => e.toLowerCase().endsWith('.apk')) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| @@ -38,7 +38,7 @@ class SteamMobile extends AppSource { | ||||
|       } | ||||
|       String apkInURLRegexPattern = | ||||
|           '/$apkNamePrefix-([0-9]+\\.)*[0-9]+\\.apk\$'; | ||||
|       var links = parse(res.body) | ||||
|       var links = parse(res.data) | ||||
|           .querySelectorAll('a') | ||||
|           .map((e) => e.attributes['href'] ?? '') | ||||
|           .where((e) => RegExp('https://.*$apkInURLRegexPattern').hasMatch(e)) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -23,7 +23,7 @@ class TelegramApp extends AppSource { | ||||
|     Response res = | ||||
|         await sourceRequest('https://t.me/s/TAndroidAPK', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var http = parse(res.body); | ||||
|       var http = parse(res.data); | ||||
|       var messages = | ||||
|           http.querySelectorAll('.tgme_widget_message_text.js-message_text'); | ||||
|       var version = messages.isNotEmpty | ||||
|   | ||||
| @@ -37,7 +37,7 @@ class Uptodown extends AppSource { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var html = parse(res.body); | ||||
|     var html = parse(res.data); | ||||
|     String? version = html.querySelector('div.version')?.innerHtml; | ||||
|     String? apkUrl = | ||||
|         '${standardUrl.split('/').reversed.toList().sublist(1).reversed.join('/')}/post-download'; | ||||
| @@ -94,7 +94,7 @@ class Uptodown extends AppSource { | ||||
|     if (res.statusCode != 200) { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|     var html = parse(res.body); | ||||
|     var html = parse(res.data); | ||||
|     var finalUrlKey = | ||||
|         html.querySelector('.post-download')?.attributes['data-url']; | ||||
|     if (finalUrlKey == null) { | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/main.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| class VLC extends AppSource { | ||||
| @@ -29,7 +30,7 @@ class VLC extends AppSource { | ||||
|       String standardUrl, Map<String, dynamic> additionalSettings) async { | ||||
|     Response res = await sourceRequest(dwUrlBase, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwLinks = parse(res.body) | ||||
|       var dwLinks = parse(res.data) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => element.attributes['href'] != 'last/') | ||||
|           .map((e) => e.attributes['href']?.split('/')[0]) | ||||
| @@ -49,11 +50,11 @@ class VLC extends AppSource { | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     Response res = await get( | ||||
|         Uri.parse('https://www.videolan.org/vlc/download-android.html')); | ||||
|     Response res = | ||||
|         await dio.get('https://www.videolan.org/vlc/download-android.html'); | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwUrlBase = 'get.videolan.org/vlc-android'; | ||||
|       var dwLinks = parse(res.body) | ||||
|       var dwLinks = parse(res.data) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => | ||||
|               element.attributes['href']?.contains(dwUrlBase) ?? false) | ||||
| @@ -84,14 +85,14 @@ class VLC extends AppSource { | ||||
|     Response res = await sourceRequest(apkUrl, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       String? apkUrl = | ||||
|           parse(res.body).querySelector('#alt_link')?.attributes['href']; | ||||
|           parse(res.data).querySelector('#alt_link')?.attributes['href']; | ||||
|       if (apkUrl == null) { | ||||
|         throw NoAPKError(); | ||||
|       } | ||||
|       return apkUrl; | ||||
|     } else if (res.statusCode == 500 && | ||||
|         res.body.toLowerCase().indexOf('mirror') > 0) { | ||||
|       var html = parse(res.body); | ||||
|         res.data.toLowerCase().indexOf('mirror') > 0) { | ||||
|       var html = parse(res.data); | ||||
|       var err = ''; | ||||
|       html.body?.nodes.forEach((element) { | ||||
|         if (element.text != null) { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| @@ -20,7 +20,7 @@ class WhatsApp extends AppSource { | ||||
|     Response res = | ||||
|         await sourceRequest('$standardUrl/android', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var targetLinks = parse(res.body) | ||||
|       var targetLinks = parse(res.data) | ||||
|           .querySelectorAll('a') | ||||
|           .map((e) => e.attributes['href'] ?? '') | ||||
|           .where((e) => e.isNotEmpty) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:easy_localization/src/easy_localization_controller.dart'; | ||||
| // ignore: implementation_imports | ||||
| import 'package:easy_localization/src/localization.dart'; | ||||
| import 'package:dio/dio.dart'; | ||||
|  | ||||
| List<MapEntry<Locale, String>> supportedLocales = const [ | ||||
|   MapEntry(Locale('en'), 'English'), | ||||
| @@ -46,6 +47,9 @@ var fdroid = false; | ||||
|  | ||||
| final globalNavigatorKey = GlobalKey<NavigatorState>(); | ||||
|  | ||||
| final dio = Dio(BaseOptions( | ||||
|     responseType: ResponseType.plain, receiveDataWhenStatusError: true)); | ||||
|  | ||||
| Future<void> loadTranslations() async { | ||||
|   // See easy_localization/issues/210 | ||||
|   await EasyLocalizationController.initEasyLocation(); | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/github.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/main.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| class GitHubStars implements MassAppUrlSource { | ||||
| @@ -15,13 +16,12 @@ class GitHubStars implements MassAppUrlSource { | ||||
|  | ||||
|   Future<Map<String, List<String>>> getOnePageOfUserStarredUrlsWithDescriptions( | ||||
|       String username, int page) async { | ||||
|     Response res = await get( | ||||
|         Uri.parse( | ||||
|             'https://api.github.com/users/$username/starred?per_page=100&page=$page'), | ||||
|         headers: await GitHub().getRequestHeaders({})); | ||||
|     Response res = await dio.get( | ||||
|         'https://api.github.com/users/$username/starred?per_page=100&page=$page', | ||||
|         options: Options(headers: await GitHub().getRequestHeaders({}))); | ||||
|     if (res.statusCode == 200) { | ||||
|       Map<String, List<String>> urlsWithDescriptions = {}; | ||||
|       for (var e in (jsonDecode(res.body) as List<dynamic>)) { | ||||
|       for (var e in (jsonDecode(res.data) as List<dynamic>)) { | ||||
|         urlsWithDescriptions.addAll({ | ||||
|           e['html_url'] as String: [ | ||||
|             e['full_name'] as String, | ||||
|   | ||||
| @@ -5,14 +5,15 @@ import 'dart:async'; | ||||
| import 'dart:convert'; | ||||
| import 'dart:io'; | ||||
| import 'dart:math'; | ||||
| import 'package:http/http.dart' as http; | ||||
| import 'package:crypto/crypto.dart'; | ||||
| import 'package:http/http.dart' as http; | ||||
|  | ||||
| import 'package:android_intent_plus/flag.dart'; | ||||
| import 'package:android_package_installer/android_package_installer.dart'; | ||||
| import 'package:android_package_manager/android_package_manager.dart'; | ||||
| import 'package:connectivity_plus/connectivity_plus.dart'; | ||||
| import 'package:device_info_plus/device_info_plus.dart'; | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| @@ -28,7 +29,6 @@ import 'package:provider/provider.dart'; | ||||
| import 'package:path_provider/path_provider.dart'; | ||||
| import 'package:flutter_fgbg/flutter_fgbg.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:android_intent_plus/android_intent.dart'; | ||||
| import 'package:flutter_archive/flutter_archive.dart'; | ||||
| import 'package:shared_storage/shared_storage.dart' as saf; | ||||
| @@ -146,10 +146,10 @@ Future<File> downloadFileWithRetry( | ||||
|     Map<String, String>? headers, | ||||
|     int retries = 3}) async { | ||||
|   try { | ||||
|     return await downloadFile(url, fileNameNoExt, onProgress, destDir, | ||||
|     return await downloadApk(url, fileNameNoExt, onProgress, destDir, | ||||
|         useExisting: useExisting, headers: headers); | ||||
|   } catch (e) { | ||||
|     if (retries > 0 && e is ClientException) { | ||||
|     if (retries > 0 && e is DioException) { | ||||
|       await Future.delayed(const Duration(seconds: 5)); | ||||
|       return await downloadFileWithRetry( | ||||
|           url, fileNameNoExt, onProgress, destDir, | ||||
| @@ -183,9 +183,162 @@ Future<String> checkPartialDownloadHashDynamic(String url, | ||||
|   throw NoVersionError(); | ||||
| } | ||||
|  | ||||
| Future<File> downloadApk( | ||||
|     String url, String fileNameNoExt, Function? onProgress, String destDir, | ||||
|     {bool useExisting = true, Map<String, String>? headers}) async { | ||||
|   var resHeaders = await getHeaders(url, headers: headers); | ||||
|  | ||||
|   String ext = resHeaders['content-disposition']?.split('.').last ?? 'apk'; | ||||
|   if (ext.endsWith('"') || ext.endsWith("other")) { | ||||
|     ext = ext.substring(0, ext.length - 1); | ||||
|   } | ||||
|   if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { | ||||
|     ext = 'apk'; | ||||
|   } | ||||
|   File file = File('$destDir/$fileNameNoExt.$ext'); | ||||
|  | ||||
|   final contentLength = await getContentLengthIfRangeSupported(resHeaders); | ||||
|  | ||||
|   if (useExisting && file.existsSync()) { | ||||
|     var length = file.lengthSync(); | ||||
|     if (contentLength == null) { | ||||
|       return file; | ||||
|     } else { | ||||
|       if (length == contentLength) { | ||||
|         return file; | ||||
|       } | ||||
|       if (length > contentLength) { | ||||
|         useExisting = false; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   double progress = -1; | ||||
|  | ||||
|   try { | ||||
|     if (contentLength == null) { | ||||
|       Response response = await dio.download( | ||||
|         url, | ||||
|         file.path, | ||||
|         options: Options(headers: headers), | ||||
|         onReceiveProgress: (count, total) { | ||||
|           progress = (total > 0 ? count / total * 100 : 30); | ||||
|           if (onProgress != null) { | ||||
|             onProgress(progress); | ||||
|           } | ||||
|         }, | ||||
|       ); | ||||
|       if ((response.statusCode ?? 200) < 200 || | ||||
|           (response.statusCode ?? 200) > 299) { | ||||
|         throw response.statusMessage ?? tr('unexpectedError'); | ||||
|       } | ||||
|     } else { | ||||
|       var targetFileLength = | ||||
|           useExisting && file.existsSync() ? file.lengthSync() : null; | ||||
|       int bufferSize = 1024 * 1024; // 1 Megabyte | ||||
|       final sink = file.openWrite( | ||||
|         mode: useExisting ? FileMode.writeOnlyAppend : FileMode.writeOnly, | ||||
|       ); | ||||
|       int rangeStart = targetFileLength ?? 0; | ||||
|       int rangeEnd = min( | ||||
|         rangeStart + bufferSize - 1, | ||||
|         contentLength - 1, | ||||
|       ); | ||||
|       if (onProgress != null) { | ||||
|         progress = ((rangeStart / contentLength) * 100); | ||||
|         onProgress(progress); | ||||
|       } | ||||
|       while (true) { | ||||
|         var headersCurrent = headers ?? {}; | ||||
|         headersCurrent['range'] = 'bytes=$rangeStart-$rangeEnd'; | ||||
|         Response response = await dio.get( | ||||
|           url, | ||||
|           onReceiveProgress: (count, total) { | ||||
|             if (onProgress != null) { | ||||
|               final newProgress = | ||||
|                   (((rangeStart + count) / contentLength) * 100); | ||||
|               if (newProgress != progress) { | ||||
|                 progress = newProgress; | ||||
|                 onProgress(progress); | ||||
|               } | ||||
|             } | ||||
|           }, | ||||
|           options: Options( | ||||
|             headers: headersCurrent, | ||||
|             responseType: ResponseType.bytes, | ||||
|           ), | ||||
|         ); | ||||
|  | ||||
|         if ((response.statusCode ?? 200) < 200 || | ||||
|             (response.statusCode ?? 200) > 299) { | ||||
|           throw response.statusMessage ?? tr('unexpectedError'); | ||||
|         } | ||||
|  | ||||
|         final Uint8List data = response.data; | ||||
|         sink.add(data); | ||||
|         if (rangeEnd == contentLength - 1) { | ||||
|           break; | ||||
|         } | ||||
|         rangeStart = rangeEnd + 1; | ||||
|         rangeEnd = min( | ||||
|           rangeStart + bufferSize - 1, | ||||
|           contentLength - 1, | ||||
|         ); | ||||
|       } | ||||
|       await sink.flush(); | ||||
|       await sink.close(); | ||||
|     } | ||||
|   } finally { | ||||
|     if (onProgress != null) { | ||||
|       onProgress(null); | ||||
|     } | ||||
|   } | ||||
|   return file; | ||||
| } | ||||
|  | ||||
| Future<int?> getContentLengthIfRangeSupported( | ||||
|     Map<String, String> headers) async { | ||||
|   try { | ||||
|     int? contentLength; | ||||
|     { | ||||
|       var contentLengthHeaderValue = headers['content-length']; | ||||
|       if (contentLengthHeaderValue?.isNotEmpty == true) { | ||||
|         contentLength = int.tryParse(contentLengthHeaderValue!); | ||||
|       } | ||||
|     } | ||||
|     bool rangeFeatureEnabled = false; | ||||
|     if (headers['accept-ranges']?.isNotEmpty == true) { | ||||
|       rangeFeatureEnabled = | ||||
|           headers['accept-ranges']!.trim().toLowerCase() == 'bytes'; | ||||
|     } | ||||
|     if (!rangeFeatureEnabled) { | ||||
|       contentLength = null; | ||||
|     } | ||||
|     return contentLength; | ||||
|   } catch (e) { | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
|  | ||||
| Future<Map<String, String>> getHeaders(String url, | ||||
|     {Map<String, String>? headers}) async { | ||||
|   var req = http.Request('GET', Uri.parse(url)); | ||||
|   if (headers != null) { | ||||
|     req.headers.addAll(headers); | ||||
|   } | ||||
|   var client = http.Client(); | ||||
|   var response = await client.send(req); | ||||
|   if (response.statusCode < 200 || response.statusCode > 299) { | ||||
|     throw ObtainiumError(response.reasonPhrase ?? tr('unexpectedError')); | ||||
|   } | ||||
|   var returnHeaders = response.headers; | ||||
|   client.close(); | ||||
|   return returnHeaders; | ||||
| } | ||||
|  | ||||
| Future<String> checkPartialDownloadHash(String url, int bytesToGrab, | ||||
|     {Map<String, String>? headers}) async { | ||||
|   var req = Request('GET', Uri.parse(url)); | ||||
|   var req = http.Request('GET', Uri.parse(url)); | ||||
|   if (headers != null) { | ||||
|     req.headers.addAll(headers); | ||||
|   } | ||||
| @@ -199,58 +352,41 @@ Future<String> checkPartialDownloadHash(String url, int bytesToGrab, | ||||
|   return hashListOfLists(bytes); | ||||
| } | ||||
|  | ||||
| Future<File> downloadFile( | ||||
|     String url, String fileNameNoExt, Function? onProgress, String destDir, | ||||
|     {bool useExisting = true, Map<String, String>? headers}) async { | ||||
|   var req = Request('GET', Uri.parse(url)); | ||||
|   if (headers != null) { | ||||
|     req.headers.addAll(headers); | ||||
|   } | ||||
|   var client = http.Client(); | ||||
|   StreamedResponse response = await client.send(req); | ||||
|   String ext = | ||||
|       response.headers['content-disposition']?.split('.').last ?? 'apk'; | ||||
|   if (ext.endsWith('"') || ext.endsWith("other")) { | ||||
|     ext = ext.substring(0, ext.length - 1); | ||||
|   } | ||||
|   if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { | ||||
|     ext = 'apk'; | ||||
|   } | ||||
|   File downloadedFile = File('$destDir/$fileNameNoExt.$ext'); | ||||
|   if (!(downloadedFile.existsSync() && useExisting)) { | ||||
|     File tempDownloadedFile = File('${downloadedFile.path}.part'); | ||||
|     if (tempDownloadedFile.existsSync()) { | ||||
|       tempDownloadedFile.deleteSync(recursive: true); | ||||
|     } | ||||
|     var length = response.contentLength; | ||||
|     var received = 0; | ||||
|     double? progress; | ||||
|     var sink = tempDownloadedFile.openWrite(); | ||||
|     await response.stream.map((s) { | ||||
|       received += s.length; | ||||
|       progress = (length != null ? received / length * 100 : 30); | ||||
|       if (onProgress != null) { | ||||
|         onProgress(progress); | ||||
|       } | ||||
|       return s; | ||||
|     }).pipe(sink); | ||||
|     await sink.close(); | ||||
|     progress = null; | ||||
|     if (onProgress != null) { | ||||
|       onProgress(progress); | ||||
|     } | ||||
|     if (response.statusCode != 200) { | ||||
|       tempDownloadedFile.deleteSync(recursive: true); | ||||
|       throw response.reasonPhrase ?? tr('unexpectedError'); | ||||
|     } | ||||
|     if (tempDownloadedFile.existsSync()) { | ||||
|       tempDownloadedFile.renameSync(downloadedFile.path); | ||||
|     } | ||||
|   } else { | ||||
|     client.close(); | ||||
|   } | ||||
|   return downloadedFile; | ||||
| } | ||||
| // Future<File> downloadFile( | ||||
| //     String url, String fileNameNoExt, Function? onProgress, String destDir, | ||||
| //     {bool useExisting = true, Map<String, String>? headers}) async { | ||||
| //   var resHead = await dio.head(url); | ||||
| //   String ext = | ||||
| //       resHead.headers.map['content-disposition']?[0].split('.').last ?? 'apk'; | ||||
| //   if (ext.endsWith('"') || ext.endsWith("other")) { | ||||
| //     ext = ext.substring(0, ext.length - 1); | ||||
| //   } | ||||
| //   if (url.toLowerCase().endsWith('.apk') && ext != 'apk') { | ||||
| //     ext = 'apk'; | ||||
| //   } | ||||
| //   File downloadedFile = File('$destDir/$fileNameNoExt.$ext'); | ||||
| //   if (!(downloadedFile.existsSync() && useExisting)) { | ||||
| //     double? progress; | ||||
| //     var response = await dio.download( | ||||
| //       url, | ||||
| //       downloadedFile.path, | ||||
| //       options: Options(headers: headers), | ||||
| //       onReceiveProgress: (count, total) { | ||||
| //         progress = (total > 0 ? count / total * 100 : 30); | ||||
| //         if (onProgress != null) { | ||||
| //           onProgress(progress); | ||||
| //         } | ||||
| //       }, | ||||
| //     ); | ||||
| //     if (onProgress != null) { | ||||
| //       onProgress(null); | ||||
| //     } | ||||
| //     if (response.statusCode != 200) { | ||||
| //       throw response.statusMessage ?? tr('unexpectedError'); | ||||
| //     } | ||||
| //   } | ||||
| //   return downloadedFile; | ||||
| // } | ||||
|  | ||||
| Future<PackageInfo?> getInstalledInfo(String? packageName, | ||||
|     {bool printErr = true}) async { | ||||
| @@ -1621,7 +1757,7 @@ Future<void> bgUpdateCheck(String taskId, Map<String, dynamic>? params) async { | ||||
|             // Next task interval is based on the error with the longest retry time | ||||
|             int minRetryIntervalForThisApp = err is RateLimitError | ||||
|                 ? (err.remainingMinutes * 60) | ||||
|                 : e is ClientException | ||||
|                 : e is DioException | ||||
|                     ? (15 * 60) | ||||
|                     : (toCheckApp.value + 1); | ||||
|             if (minRetryIntervalForThisApp > maxRetryWaitSeconds) { | ||||
|   | ||||
| @@ -4,9 +4,9 @@ | ||||
| import 'dart:convert'; | ||||
|  | ||||
| import 'package:device_info_plus/device_info_plus.dart'; | ||||
| import 'package:dio/dio.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:html/dom.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/app_sources/apkmirror.dart'; | ||||
| import 'package:obtainium/app_sources/apkpure.dart'; | ||||
| import 'package:obtainium/app_sources/aptoide.dart'; | ||||
| @@ -31,6 +31,7 @@ import 'package:obtainium/app_sources/vlc.dart'; | ||||
| import 'package:obtainium/app_sources/whatsapp.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/main.dart'; | ||||
| import 'package:obtainium/mass_app_sources/githubstars.dart'; | ||||
| import 'package:obtainium/providers/settings_provider.dart'; | ||||
|  | ||||
| @@ -442,16 +443,9 @@ abstract class AppSource { | ||||
|       String url, Map<String, dynamic> additionalSettings, | ||||
|       {bool followRedirects = true}) async { | ||||
|     var requestHeaders = await getRequestHeaders(additionalSettings); | ||||
|     if (requestHeaders != null || followRedirects == false) { | ||||
|       var req = Request('GET', Uri.parse(url)); | ||||
|       req.followRedirects = followRedirects; | ||||
|       if (requestHeaders != null) { | ||||
|         req.headers.addAll(requestHeaders); | ||||
|       } | ||||
|       return Response.fromStream(await Client().send(req)); | ||||
|     } else { | ||||
|       return get(Uri.parse(url)); | ||||
|     } | ||||
|     return await dio.get(url, | ||||
|         options: | ||||
|             Options(headers: requestHeaders, followRedirects: followRedirects)); | ||||
|   } | ||||
|  | ||||
|   String sourceSpecificStandardizeURL(String url) { | ||||
| @@ -618,10 +612,10 @@ abstract class AppSource { | ||||
| } | ||||
|  | ||||
| ObtainiumError getObtainiumHttpError(Response res) { | ||||
|   return ObtainiumError((res.reasonPhrase != null && | ||||
|           res.reasonPhrase != null && | ||||
|           res.reasonPhrase!.isNotEmpty) | ||||
|       ? res.reasonPhrase! | ||||
|   return ObtainiumError((res.statusMessage != null && | ||||
|           res.statusMessage != null && | ||||
|           res.statusMessage!.isNotEmpty) | ||||
|       ? res.statusMessage! | ||||
|       : tr('errorWithHttpStatusCode', args: [res.statusCode.toString()])); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -202,6 +202,14 @@ packages: | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "7.0.0" | ||||
|   dio: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: dio | ||||
|       sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "5.4.1" | ||||
|   dynamic_color: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|   | ||||
| @@ -68,6 +68,7 @@ dependencies: | ||||
|   crypto: ^3.0.3 | ||||
|   app_links: ^3.5.0 | ||||
|   background_fetch: ^1.2.1 | ||||
|   dio: ^5.4.1 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user