mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 21:43:29 +01:00 
			
		
		
		
	Multi-host support + add '.net' host to APKPure source (#1250)
This commit is contained in:
		| @@ -21,7 +21,7 @@ Currently supported App sources: | |||||||
|   - [SourceForge](https://sourceforge.net/) |   - [SourceForge](https://sourceforge.net/) | ||||||
|   - [SourceHut](https://git.sr.ht/) |   - [SourceHut](https://git.sr.ht/) | ||||||
| - Other - General: | - Other - General: | ||||||
|   - [APKPure](https://apkpure.com/) |   - [APKPure](https://apkpure.net/) | ||||||
|   - [Aptoide](https://aptoide.com/) |   - [Aptoide](https://aptoide.com/) | ||||||
|   - [Uptodown](https://uptodown.com/) |   - [Uptodown](https://uptodown.com/) | ||||||
|   - [APKMirror](https://apkmirror.com/) (Track-Only) |   - [APKMirror](https://apkmirror.com/) (Track-Only) | ||||||
|   | |||||||
| @@ -5,17 +5,18 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class APKCombo extends AppSource { | class APKCombo extends AppSource { | ||||||
|   APKCombo() { |   APKCombo() { | ||||||
|     host = 'apkcombo.com'; |     hosts = ['apkcombo.com']; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/+[^/]+/+[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+[^/]+'); | ||||||
|     var match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     var match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -32,7 +33,7 @@ class APKCombo extends AppSource { | |||||||
|       "User-Agent": "curl/8.0.1", |       "User-Agent": "curl/8.0.1", | ||||||
|       "Accept": "*/*", |       "Accept": "*/*", | ||||||
|       "Connection": "keep-alive", |       "Connection": "keep-alive", | ||||||
|       "Host": "$host" |       "Host": hosts[0] | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class APKMirror extends AppSource { | class APKMirror extends AppSource { | ||||||
|   APKMirror() { |   APKMirror() { | ||||||
|     host = 'apkmirror.com'; |     hosts = ['apkmirror.com']; | ||||||
|     enforceTrackOnly = true; |     enforceTrackOnly = true; | ||||||
|  |  | ||||||
|     additionalSourceAppSpecificSettingFormItems = [ |     additionalSourceAppSpecificSettingFormItems = [ | ||||||
| @@ -33,12 +33,12 @@ class APKMirror extends AppSource { | |||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = |     RegExp standardUrlRegEx = | ||||||
|         RegExp('^https?://(www\\.)?$host/apk/[^/]+/[^/]+'); |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/apk/[^/]+/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ parseDateTimeMMMddCommayyyy(String? dateString) { | |||||||
|  |  | ||||||
| class APKPure extends AppSource { | class APKPure extends AppSource { | ||||||
|   APKPure() { |   APKPure() { | ||||||
|     host = 'apkpure.com'; |     hosts = ['apkpure.net', 'apkpure.com']; | ||||||
|     allowSubDomains = true; |     allowSubDomains = true; | ||||||
|     naiveStandardVersionDetection = true; |     naiveStandardVersionDetection = true; | ||||||
|   } |   } | ||||||
| @@ -28,18 +28,18 @@ class APKPure extends AppSource { | |||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegExB = |     RegExp standardUrlRegExB = | ||||||
|         RegExp('^https?://m.$host/+[^/]+/+[^/]+(/+[^/]+)?'); |         RegExp('^https?://m.${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?'); | ||||||
|     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); | ||||||
|     if (match != null) { |     if (match != null) { | ||||||
|       url = 'https://$host${Uri.parse(url).path}'; |       url = 'https://${getSourceRegex(hosts)}${Uri.parse(url).path}'; | ||||||
|     } |     } | ||||||
|     RegExp standardUrlRegExA = |     RegExp standardUrlRegExA = RegExp( | ||||||
|         RegExp('^https?://(www\\.)?$host/+[^/]+/+[^/]+(/+[^/]+)?'); |         '^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?'); | ||||||
|     match = standardUrlRegExA.firstMatch(url.toLowerCase()); |     match = standardUrlRegExA.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class Aptoide extends AppSource { | class Aptoide extends AppSource { | ||||||
|   Aptoide() { |   Aptoide() { | ||||||
|     host = 'aptoide.com'; |     hosts = ['aptoide.com']; | ||||||
|     name = 'Aptoide'; |     name = 'Aptoide'; | ||||||
|     allowSubDomains = true; |     allowSubDomains = true; | ||||||
|     naiveStandardVersionDetection = true; |     naiveStandardVersionDetection = true; | ||||||
| @@ -14,12 +14,13 @@ class Aptoide extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://([^\\.]+\\.){2,}$host'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://([^\\.]+\\.){2,}${getSourceRegex(hosts)}'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
| class Codeberg extends AppSource { | class Codeberg extends AppSource { | ||||||
|   GitHub gh = GitHub(); |   GitHub gh = GitHub(); | ||||||
|   Codeberg() { |   Codeberg() { | ||||||
|     host = 'codeberg.org'; |     hosts = ['codeberg.org']; | ||||||
|  |  | ||||||
|     additionalSourceAppSpecificSettingFormItems = |     additionalSourceAppSpecificSettingFormItems = | ||||||
|         gh.additionalSourceAppSpecificSettingFormItems; |         gh.additionalSourceAppSpecificSettingFormItems; | ||||||
| @@ -16,12 +16,13 @@ class Codeberg extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -35,7 +36,7 @@ class Codeberg extends AppSource { | |||||||
|   ) async { |   ) async { | ||||||
|     return await gh.getLatestAPKDetailsCommon2(standardUrl, additionalSettings, |     return await gh.getLatestAPKDetailsCommon2(standardUrl, additionalSettings, | ||||||
|         (bool useTagUrl) async { |         (bool useTagUrl) async { | ||||||
|       return 'https://$host/api/v1/repos${standardUrl.substring('https://$host'.length)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100'; |       return 'https://${hosts[0]}/api/v1/repos${standardUrl.substring('https://${hosts[0]}'.length)}/${useTagUrl ? 'tags' : 'releases'}?per_page=100'; | ||||||
|     }, null); |     }, null); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -50,7 +51,7 @@ class Codeberg extends AppSource { | |||||||
|       {Map<String, dynamic> querySettings = const {}}) async { |       {Map<String, dynamic> querySettings = const {}}) async { | ||||||
|     return gh.searchCommon( |     return gh.searchCommon( | ||||||
|         query, |         query, | ||||||
|         'https://$host/api/v1/repos/search?q=${Uri.encodeQueryComponent(query)}&limit=100', |         'https://${hosts[0]}/api/v1/repos/search?q=${Uri.encodeQueryComponent(query)}&limit=100', | ||||||
|         'data', |         'data', | ||||||
|         querySettings: querySettings); |         querySettings: querySettings); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class FDroid extends AppSource { | class FDroid extends AppSource { | ||||||
|   FDroid() { |   FDroid() { | ||||||
|     host = 'f-droid.org'; |     hosts = ['f-droid.org']; | ||||||
|     name = tr('fdroid'); |     name = tr('fdroid'); | ||||||
|     naiveStandardVersionDetection = true; |     naiveStandardVersionDetection = true; | ||||||
|     canSearch = true; |     canSearch = true; | ||||||
| @@ -37,20 +37,20 @@ class FDroid extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegExB = |     RegExp standardUrlRegExB = RegExp( | ||||||
|         RegExp('^https?://(www\\.)?$host/+[^/]+/+packages/+[^/]+'); |         '^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+packages/+[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); | ||||||
|     if (match != null) { |     if (match != null) { | ||||||
|       url = |       url = | ||||||
|           'https://${Uri.parse(url.substring(0, match.end)).host}/packages/${Uri.parse(url).pathSegments.last}'; |           'https://${Uri.parse(match.group(0)!).host}/packages/${Uri.parse(url).pathSegments.last}'; | ||||||
|     } |     } | ||||||
|     RegExp standardUrlRegExA = |     RegExp standardUrlRegExA = | ||||||
|         RegExp('^https?://(www\\.)?$host/+packages/+[^/]+'); |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/+packages/+[^/]+'); | ||||||
|     match = standardUrlRegExA.firstMatch(url.toLowerCase()); |     match = standardUrlRegExA.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -117,7 +117,7 @@ class FDroid extends AppSource { | |||||||
|   Future<Map<String, List<String>>> search(String query, |   Future<Map<String, List<String>>> search(String query, | ||||||
|       {Map<String, dynamic> querySettings = const {}}) async { |       {Map<String, dynamic> querySettings = const {}}) async { | ||||||
|     Response res = await sourceRequest( |     Response res = await sourceRequest( | ||||||
|         'https://search.$host/?q=${Uri.encodeQueryComponent(query)}'); |         'https://search.${hosts[0]}/?q=${Uri.encodeQueryComponent(query)}'); | ||||||
|     if (res.statusCode == 200) { |     if (res.statusCode == 200) { | ||||||
|       Map<String, List<String>> urlsWithDescriptions = {}; |       Map<String, List<String>> urlsWithDescriptions = {}; | ||||||
|       parse(res.body).querySelectorAll('.package-header').forEach((e) { |       parse(res.body).querySelectorAll('.package-header').forEach((e) { | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ import 'package:url_launcher/url_launcher_string.dart'; | |||||||
|  |  | ||||||
| class GitHub extends AppSource { | class GitHub extends AppSource { | ||||||
|   GitHub() { |   GitHub() { | ||||||
|     host = 'github.com'; |     hosts = ['github.com']; | ||||||
|     appIdInferIsOptional = true; |     appIdInferIsOptional = true; | ||||||
|  |  | ||||||
|     sourceConfigSettingFormItems = [ |     sourceConfigSettingFormItems = [ | ||||||
| @@ -149,12 +149,13 @@ class GitHub extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -203,11 +204,11 @@ class GitHub extends AppSource { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<String> getAPIHost(Map<String, dynamic> additionalSettings) async => |   Future<String> getAPIHost(Map<String, dynamic> additionalSettings) async => | ||||||
|       'https://api.$host'; |       'https://api.${hosts[0]}'; | ||||||
|  |  | ||||||
|   Future<String> convertStandardUrlToAPIUrl( |   Future<String> convertStandardUrlToAPIUrl( | ||||||
|           String standardUrl, Map<String, dynamic> additionalSettings) async => |           String standardUrl, Map<String, dynamic> additionalSettings) async => | ||||||
|       '${await getAPIHost(additionalSettings)}/repos${standardUrl.substring('https://$host'.length)}'; |       '${await getAPIHost(additionalSettings)}/repos${standardUrl.substring('https://${hosts[0]}'.length)}'; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String? changeLogPageFromStandardUrl(String standardUrl) => |   String? changeLogPageFromStandardUrl(String standardUrl) => | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ import 'package:url_launcher/url_launcher_string.dart'; | |||||||
|  |  | ||||||
| class GitLab extends AppSource { | class GitLab extends AppSource { | ||||||
|   GitLab() { |   GitLab() { | ||||||
|     host = 'gitlab.com'; |     hosts = ['gitlab.com']; | ||||||
|     canSearch = true; |     canSearch = true; | ||||||
|  |  | ||||||
|     sourceConfigSettingFormItems = [ |     sourceConfigSettingFormItems = [ | ||||||
| @@ -52,12 +52,13 @@ class GitLab extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<String?> getPATIfAny(Map<String, dynamic> additionalSettings) async { |   Future<String?> getPATIfAny(Map<String, dynamic> additionalSettings) async { | ||||||
| @@ -81,7 +82,7 @@ class GitLab extends AppSource { | |||||||
|   Future<Map<String, List<String>>> search(String query, |   Future<Map<String, List<String>>> search(String query, | ||||||
|       {Map<String, dynamic> querySettings = const {}}) async { |       {Map<String, dynamic> querySettings = const {}}) async { | ||||||
|     var url = |     var url = | ||||||
|         'https://$host/api/v4/projects?search=${Uri.encodeQueryComponent(query)}'; |         'https://${hosts[0]}/api/v4/projects?search=${Uri.encodeQueryComponent(query)}'; | ||||||
|     var res = await sourceRequest(url); |     var res = await sourceRequest(url); | ||||||
|     if (res.statusCode != 200) { |     if (res.statusCode != 200) { | ||||||
|       throw getObtainiumHttpError(res); |       throw getObtainiumHttpError(res); | ||||||
| @@ -89,7 +90,7 @@ class GitLab extends AppSource { | |||||||
|     var json = jsonDecode(res.body) as List<dynamic>; |     var json = jsonDecode(res.body) as List<dynamic>; | ||||||
|     Map<String, List<String>> results = {}; |     Map<String, List<String>> results = {}; | ||||||
|     for (var element in json) { |     for (var element in json) { | ||||||
|       results['https://$host/${element['path_with_namespace']}'] = [ |       results['https://${hosts[0]}/${element['path_with_namespace']}'] = [ | ||||||
|         element['name_with_namespace'], |         element['name_with_namespace'], | ||||||
|         element['description'] ?? tr('noDescription') |         element['description'] ?? tr('noDescription') | ||||||
|       ]; |       ]; | ||||||
| @@ -113,7 +114,7 @@ class GitLab extends AppSource { | |||||||
|     if (PAT != null) { |     if (PAT != null) { | ||||||
|       var names = GitHub().getAppNames(standardUrl); |       var names = GitHub().getAppNames(standardUrl); | ||||||
|       Response res = await sourceRequest( |       Response res = await sourceRequest( | ||||||
|           'https://$host/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT'); |           'https://${hosts[0]}/api/v4/projects/${names.author}%2F${names.name}/releases?private_token=$PAT'); | ||||||
|       if (res.statusCode != 200) { |       if (res.statusCode != 200) { | ||||||
|         throw getObtainiumHttpError(res); |         throw getObtainiumHttpError(res); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -6,23 +6,24 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
| class HuaweiAppGallery extends AppSource { | class HuaweiAppGallery extends AppSource { | ||||||
|   HuaweiAppGallery() { |   HuaweiAppGallery() { | ||||||
|     name = 'Huawei AppGallery'; |     name = 'Huawei AppGallery'; | ||||||
|     host = 'appgallery.huawei.com'; |     hosts = ['appgallery.huawei.com']; | ||||||
|     overrideVersionDetectionFormDefault('releaseDateAsVersion', |     overrideVersionDetectionFormDefault('releaseDateAsVersion', | ||||||
|         disableStandard: true); |         disableStandard: true); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/app/[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/app/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getDlUrl(String standardUrl) => |   getDlUrl(String standardUrl) => | ||||||
|       'https://${host!.replaceAll('appgallery.', 'appgallery.cloud.')}/appdl/${standardUrl.split('/').last}'; |       'https://${hosts[0].replaceAll('appgallery.', 'appgallery.cloud.')}/appdl/${standardUrl.split('/').last}'; | ||||||
|  |  | ||||||
|   requestAppdlRedirect(String dlUrl) async { |   requestAppdlRedirect(String dlUrl) async { | ||||||
|     Response res = await sourceRequest(dlUrl, followRedirects: false); |     Response res = await sourceRequest(dlUrl, followRedirects: false); | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ class IzzyOnDroid extends AppSource { | |||||||
|   late FDroid fd; |   late FDroid fd; | ||||||
|  |  | ||||||
|   IzzyOnDroid() { |   IzzyOnDroid() { | ||||||
|     host = 'izzysoft.de'; |     hosts = ['izzysoft.de']; | ||||||
|     fd = FDroid(); |     fd = FDroid(); | ||||||
|     additionalSourceAppSpecificSettingFormItems = |     additionalSourceAppSpecificSettingFormItems = | ||||||
|         fd.additionalSourceAppSpecificSettingFormItems; |         fd.additionalSourceAppSpecificSettingFormItems; | ||||||
| @@ -15,17 +15,18 @@ class IzzyOnDroid extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegExA = RegExp('^https?://android.$host/repo/apk/[^/]+'); |     RegExp standardUrlRegExA = | ||||||
|  |         RegExp('^https?://android.${getSourceRegex(hosts)}/repo/apk/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegExA.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegExA.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       RegExp standardUrlRegExB = |       RegExp standardUrlRegExB = RegExp( | ||||||
|           RegExp('^https?://apt.$host/fdroid/index/apk/[^/]+'); |           '^https?://apt.${getSourceRegex(hosts)}/fdroid/index/apk/[^/]+'); | ||||||
|       match = standardUrlRegExB.firstMatch(url.toLowerCase()); |       match = standardUrlRegExB.firstMatch(url.toLowerCase()); | ||||||
|     } |     } | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ class Jenkins extends AppSource { | |||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -6,17 +6,18 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class Mullvad extends AppSource { | class Mullvad extends AppSource { | ||||||
|   Mullvad() { |   Mullvad() { | ||||||
|     host = 'mullvad.net'; |     hosts = ['mullvad.net']; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -5,18 +5,18 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class NeutronCode extends AppSource { | class NeutronCode extends AppSource { | ||||||
|   NeutronCode() { |   NeutronCode() { | ||||||
|     host = 'neutroncode.com'; |     hosts = ['neutroncode.com']; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = |     RegExp standardUrlRegEx = RegExp( | ||||||
|         RegExp('^https?://(www\\.)?$host/downloads/file/[^/]+'); |         '^https?://(www\\.)?${getSourceRegex(hosts)}/downloads/file/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -92,7 +92,7 @@ class NeutronCode extends AppSource { | |||||||
|       if (version == null) { |       if (version == null) { | ||||||
|         throw NoVersionError(); |         throw NoVersionError(); | ||||||
|       } |       } | ||||||
|       String? apkUrl = 'https://$host/download/$filename'; |       String? apkUrl = 'https://${hosts[0]}/download/$filename'; | ||||||
|       var dateStringOriginal = |       var dateStringOriginal = | ||||||
|           http.querySelector('.pd-date-txt')?.nextElementSibling?.innerHtml; |           http.querySelector('.pd-date-txt')?.nextElementSibling?.innerHtml; | ||||||
|       var dateString = dateStringOriginal != null |       var dateString = dateStringOriginal != null | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class Signal extends AppSource { | class Signal extends AppSource { | ||||||
|   Signal() { |   Signal() { | ||||||
|     host = 'signal.org'; |     hosts = ['signal.org']; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     return 'https://$host'; |     return 'https://${hosts[0]}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -19,7 +19,7 @@ class Signal extends AppSource { | |||||||
|     Map<String, dynamic> additionalSettings, |     Map<String, dynamic> additionalSettings, | ||||||
|   ) async { |   ) async { | ||||||
|     Response res = |     Response res = | ||||||
|         await sourceRequest('https://updates.$host/android/latest.json'); |         await sourceRequest('https://updates.${hosts[0]}/android/latest.json'); | ||||||
|     if (res.statusCode == 200) { |     if (res.statusCode == 200) { | ||||||
|       var json = jsonDecode(res.body); |       var json = jsonDecode(res.body); | ||||||
|       String? apkUrl = json['url']; |       String? apkUrl = json['url']; | ||||||
|   | |||||||
| @@ -5,24 +5,25 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class SourceForge extends AppSource { | class SourceForge extends AppSource { | ||||||
|   SourceForge() { |   SourceForge() { | ||||||
|     host = 'sourceforge.net'; |     hosts = ['sourceforge.net']; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegExB = RegExp('^https?://(www\\.)?$host/p/[^/]+'); |     RegExp standardUrlRegExB = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/p/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); | ||||||
|     if (match != null) { |     if (match != null) { | ||||||
|       url = |       url = | ||||||
|           'https://${Uri.parse(url.substring(0, match.end)).host}/projects/${url.substring(Uri.parse(url.substring(0, match.end)).host.length + '/projects/'.length + 1)}'; |           'https://${Uri.parse(match.group(0)!).host}/projects/${url.substring(Uri.parse(match.group(0)!).host.length + '/projects/'.length + 1)}'; | ||||||
|     } |     } | ||||||
|     RegExp standardUrlRegExA = |     RegExp standardUrlRegExA = | ||||||
|         RegExp('^https?://(www\\.)?$host/projects/[^/]+'); |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/projects/[^/]+'); | ||||||
|     match = standardUrlRegExA.firstMatch(url.toLowerCase()); |     match = standardUrlRegExA.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import 'package:easy_localization/easy_localization.dart'; | |||||||
|  |  | ||||||
| class SourceHut extends AppSource { | class SourceHut extends AppSource { | ||||||
|   SourceHut() { |   SourceHut() { | ||||||
|     host = 'git.sr.ht'; |     hosts = ['git.sr.ht']; | ||||||
|  |  | ||||||
|     additionalSourceAppSpecificSettingFormItems = [ |     additionalSourceAppSpecificSettingFormItems = [ | ||||||
|       [ |       [ | ||||||
| @@ -20,12 +20,13 @@ class SourceHut extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return url.substring(0, match.end); |     return match.group(0)!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class SteamMobile extends AppSource { | class SteamMobile extends AppSource { | ||||||
|   SteamMobile() { |   SteamMobile() { | ||||||
|     host = 'store.steampowered.com'; |     hosts = ['store.steampowered.com']; | ||||||
|     name = tr('steam'); |     name = tr('steam'); | ||||||
|     additionalSourceAppSpecificSettingFormItems = [ |     additionalSourceAppSpecificSettingFormItems = [ | ||||||
|       [ |       [ | ||||||
| @@ -21,7 +21,7 @@ class SteamMobile extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     return 'https://$host'; |     return 'https://${hosts[0]}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -29,7 +29,7 @@ class SteamMobile extends AppSource { | |||||||
|     String standardUrl, |     String standardUrl, | ||||||
|     Map<String, dynamic> additionalSettings, |     Map<String, dynamic> additionalSettings, | ||||||
|   ) async { |   ) async { | ||||||
|     Response res = await sourceRequest('https://$host/mobile'); |     Response res = await sourceRequest('https://${hosts[0]}/mobile'); | ||||||
|     if (res.statusCode == 200) { |     if (res.statusCode == 200) { | ||||||
|       var apkNamePrefix = additionalSettings['app'] as String?; |       var apkNamePrefix = additionalSettings['app'] as String?; | ||||||
|       if (apkNamePrefix == null) { |       if (apkNamePrefix == null) { | ||||||
|   | |||||||
| @@ -6,13 +6,13 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class TelegramApp extends AppSource { | class TelegramApp extends AppSource { | ||||||
|   TelegramApp() { |   TelegramApp() { | ||||||
|     host = 'telegram.org'; |     hosts = ['telegram.org']; | ||||||
|     name = 'Telegram ${tr('app')}'; |     name = 'Telegram ${tr('app')}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     return 'https://$host'; |     return 'https://${hosts[0]}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -6,19 +6,20 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class Uptodown extends AppSource { | class Uptodown extends AppSource { | ||||||
|   Uptodown() { |   Uptodown() { | ||||||
|     host = 'uptodown.com'; |     hosts = ['uptodown.com']; | ||||||
|     allowSubDomains = true; |     allowSubDomains = true; | ||||||
|     naiveStandardVersionDetection = true; |     naiveStandardVersionDetection = true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     RegExp standardUrlRegEx = RegExp('^https?://([^\\.]+\\.){2,}$host'); |     RegExp standardUrlRegEx = | ||||||
|  |         RegExp('^https?://([^\\.]+\\.){2,}${getSourceRegex(hosts)}'); | ||||||
|     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); |     RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); | ||||||
|     if (match == null) { |     if (match == null) { | ||||||
|       throw InvalidURLError(name); |       throw InvalidURLError(name); | ||||||
|     } |     } | ||||||
|     return '${url.substring(0, match.end)}/android/download'; |     return '${match.group(0)!}/android/download'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -94,6 +95,6 @@ class Uptodown extends AppSource { | |||||||
|     if (finalUrlKey == null) { |     if (finalUrlKey == null) { | ||||||
|       throw NoAPKError(); |       throw NoAPKError(); | ||||||
|     } |     } | ||||||
|     return 'https://dw.$host/dwn/$finalUrlKey'; |     return 'https://dw.${hosts[0]}/dwn/$finalUrlKey'; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,9 +7,9 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class VLC extends AppSource { | class VLC extends AppSource { | ||||||
|   VLC() { |   VLC() { | ||||||
|     host = 'videolan.org'; |     hosts = ['videolan.org']; | ||||||
|   } |   } | ||||||
|   get dwUrlBase => 'https://get.$host/vlc-android/'; |   get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/'; | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Future<Map<String, String>?> getRequestHeaders( |   Future<Map<String, String>?> getRequestHeaders( | ||||||
| @@ -21,7 +21,7 @@ class VLC extends AppSource { | |||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     return 'https://$host'; |     return 'https://${hosts[0]}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Future<String?> getLatestVersion(String standardUrl) async { |   Future<String?> getLatestVersion(String standardUrl) async { | ||||||
|   | |||||||
| @@ -5,14 +5,14 @@ import 'package:obtainium/providers/source_provider.dart'; | |||||||
|  |  | ||||||
| class WhatsApp extends AppSource { | class WhatsApp extends AppSource { | ||||||
|   WhatsApp() { |   WhatsApp() { | ||||||
|     host = 'whatsapp.com'; |     hosts = ['whatsapp.com']; | ||||||
|     overrideVersionDetectionFormDefault('noVersionDetection', |     overrideVersionDetectionFormDefault('noVersionDetection', | ||||||
|         disableStandard: true, disableRelDate: true); |         disableStandard: true, disableRelDate: true); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   String sourceSpecificStandardizeURL(String url) { |   String sourceSpecificStandardizeURL(String url) { | ||||||
|     return 'https://$host'; |     return 'https://${hosts[0]}'; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -59,7 +59,9 @@ class AddAppPageState extends State<AddAppPage> { | |||||||
|         if (updateUrlInput) { |         if (updateUrlInput) { | ||||||
|           urlInputKey++; |           urlInputKey++; | ||||||
|         } |         } | ||||||
|         var prevHost = pickedSource?.host; |         var prevHost = pickedSource?.hosts.isNotEmpty == true | ||||||
|  |             ? pickedSource?.hosts[0] | ||||||
|  |             : null; | ||||||
|         try { |         try { | ||||||
|           var naturalSource = |           var naturalSource = | ||||||
|               valid ? sourceProvider.getSource(userInput) : null; |               valid ? sourceProvider.getSource(userInput) : null; | ||||||
| @@ -77,7 +79,7 @@ class AddAppPageState extends State<AddAppPage> { | |||||||
|                 overrideSource: pickedSourceOverride) |                 overrideSource: pickedSourceOverride) | ||||||
|             : null; |             : null; | ||||||
|         if (pickedSource.runtimeType != source.runtimeType || |         if (pickedSource.runtimeType != source.runtimeType || | ||||||
|             (prevHost != null && prevHost != source?.host)) { |             (prevHost != null && prevHost != source?.hosts[0])) { | ||||||
|           pickedSource = source; |           pickedSource = source; | ||||||
|           additionalSettings = source != null |           additionalSettings = source != null | ||||||
|               ? getDefaultValuesFromFormItems( |               ? getDefaultValuesFromFormItems( | ||||||
| @@ -508,16 +510,16 @@ class AddAppPageState extends State<AddAppPage> { | |||||||
|                 height: 16, |                 height: 16, | ||||||
|               ), |               ), | ||||||
|               ...sourceProvider.sources.map((e) => GestureDetector( |               ...sourceProvider.sources.map((e) => GestureDetector( | ||||||
|                   onTap: e.host != null |                   onTap: e.hosts.isNotEmpty | ||||||
|                       ? () { |                       ? () { | ||||||
|                           launchUrlString('https://${e.host}', |                           launchUrlString('https://${e.hosts[0]}', | ||||||
|                               mode: LaunchMode.externalApplication); |                               mode: LaunchMode.externalApplication); | ||||||
|                         } |                         } | ||||||
|                       : null, |                       : null, | ||||||
|                   child: Text( |                   child: Text( | ||||||
|                     '${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', |                     '${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', | ||||||
|                     style: TextStyle( |                     style: TextStyle( | ||||||
|                         decoration: e.host != null |                         decoration: e.hosts.isNotEmpty | ||||||
|                             ? TextDecoration.underline |                             ? TextDecoration.underline | ||||||
|                             : TextDecoration.none, |                             : TextDecoration.none, | ||||||
|                         fontStyle: FontStyle.italic), |                         fontStyle: FontStyle.italic), | ||||||
|   | |||||||
| @@ -199,10 +199,11 @@ class _ImportExportPageState extends State<ImportExportPage> { | |||||||
|                   ...source.searchQuerySettingFormItems.map((e) => [e]), |                   ...source.searchQuerySettingFormItems.map((e) => [e]), | ||||||
|                   [ |                   [ | ||||||
|                     GeneratedFormTextField('url', |                     GeneratedFormTextField('url', | ||||||
|                         label: source.host != null |                         label: source.hosts.isNotEmpty | ||||||
|                             ? tr('overrideSource') |                             ? tr('overrideSource') | ||||||
|                             : plural('url', 1).substring(2), |                             : plural('url', 1).substring(2), | ||||||
|                         defaultValue: source.host ?? '', |                         defaultValue: | ||||||
|  |                             source.hosts.isNotEmpty ? source.hosts[0] : '', | ||||||
|                         required: true) |                         required: true) | ||||||
|                   ], |                   ], | ||||||
|                 ], |                 ], | ||||||
| @@ -212,7 +213,7 @@ class _ImportExportPageState extends State<ImportExportPage> { | |||||||
|           setState(() { |           setState(() { | ||||||
|             importInProgress = true; |             importInProgress = true; | ||||||
|           }); |           }); | ||||||
|           if (values['url'] != source.host) { |           if (values['url'] != source.hosts[0]) { | ||||||
|             source = sourceProvider.getSource(values['url'], |             source = sourceProvider.getSource(values['url'], | ||||||
|                 overrideSource: source.runtimeType.toString()); |                 overrideSource: source.runtimeType.toString()); | ||||||
|           } |           } | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ import 'package:permission_handler/permission_handler.dart'; | |||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
| import 'package:shared_storage/shared_storage.dart' as saf; | import 'package:shared_storage/shared_storage.dart' as saf; | ||||||
|  |  | ||||||
| String obtainiumTempId = 'imranr98_obtainium_${GitHub().host}'; | String obtainiumTempId = 'imranr98_obtainium_${GitHub().hosts[0]}'; | ||||||
| String obtainiumId = 'dev.imranr.obtainium'; | String obtainiumId = 'dev.imranr.obtainium'; | ||||||
|  |  | ||||||
| enum InstallMethodSettings { normal, shizuku, root } | enum InstallMethodSettings { normal, shizuku, root } | ||||||
|   | |||||||
| @@ -366,8 +366,12 @@ List<MapEntry<String, String>> getApkUrlsFromUrls(List<String> urls) => | |||||||
|       return MapEntry(apkSegs.isNotEmpty ? apkSegs.last : segments.last, e); |       return MapEntry(apkSegs.isNotEmpty ? apkSegs.last : segments.last, e); | ||||||
|     }).toList(); |     }).toList(); | ||||||
|  |  | ||||||
|  | getSourceRegex(List<String> hosts) { | ||||||
|  |   return '(${hosts.join('|').replaceAll('.', '\\.')})'; | ||||||
|  | } | ||||||
|  |  | ||||||
| abstract class AppSource { | abstract class AppSource { | ||||||
|   String? host; |   List<String> hosts = []; | ||||||
|   bool hostChanged = false; |   bool hostChanged = false; | ||||||
|   late String name; |   late String name; | ||||||
|   bool enforceTrackOnly = false; |   bool enforceTrackOnly = false; | ||||||
| @@ -697,14 +701,14 @@ class SourceProvider { | |||||||
|         throw UnsupportedURLError(); |         throw UnsupportedURLError(); | ||||||
|       } |       } | ||||||
|       var res = srcs.first; |       var res = srcs.first; | ||||||
|       res.host = Uri.parse(url).host; |       res.hosts = [Uri.parse(url).host]; | ||||||
|       res.hostChanged = true; |       res.hostChanged = true; | ||||||
|       return srcs.first; |       return srcs.first; | ||||||
|     } |     } | ||||||
|     AppSource? source; |     AppSource? source; | ||||||
|     for (var s in sources.where((element) => element.host != null)) { |     for (var s in sources.where((element) => element.hosts.isNotEmpty)) { | ||||||
|       if (RegExp( |       if (RegExp( | ||||||
|               '://${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}${s.host}(/|\\z)?') |               '://${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}(${getSourceRegex(s.hosts)})(/|\\z)?') | ||||||
|           .hasMatch(url)) { |           .hasMatch(url)) { | ||||||
|         source = s; |         source = s; | ||||||
|         break; |         break; | ||||||
| @@ -712,7 +716,7 @@ class SourceProvider { | |||||||
|     } |     } | ||||||
|     if (source == null) { |     if (source == null) { | ||||||
|       for (var s in sources.where( |       for (var s in sources.where( | ||||||
|           (element) => element.host == null && !element.neverAutoSelect)) { |           (element) => element.hosts.isEmpty && !element.neverAutoSelect)) { | ||||||
|         try { |         try { | ||||||
|           s.sourceSpecificStandardizeURL(url); |           s.sourceSpecificStandardizeURL(url); | ||||||
|           source = s; |           source = s; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user