diff --git a/README.md b/README.md index 648bf53..ea52c19 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Currently supported App sources: - [SourceForge](https://sourceforge.net/) - [SourceHut](https://git.sr.ht/) - Other - General: - - [APKPure](https://apkpure.com/) + - [APKPure](https://apkpure.net/) - [Aptoide](https://aptoide.com/) - [Uptodown](https://uptodown.com/) - [APKMirror](https://apkmirror.com/) (Track-Only) diff --git a/lib/app_sources/apkcombo.dart b/lib/app_sources/apkcombo.dart index 802373c..afcaf7f 100644 --- a/lib/app_sources/apkcombo.dart +++ b/lib/app_sources/apkcombo.dart @@ -5,17 +5,18 @@ import 'package:obtainium/providers/source_provider.dart'; class APKCombo extends AppSource { APKCombo() { - host = 'apkcombo.com'; + hosts = ['apkcombo.com']; } @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/+[^/]+/+[^/]+'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+[^/]+'); var match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override @@ -32,7 +33,7 @@ class APKCombo extends AppSource { "User-Agent": "curl/8.0.1", "Accept": "*/*", "Connection": "keep-alive", - "Host": "$host" + "Host": hosts[0] }; } diff --git a/lib/app_sources/apkmirror.dart b/lib/app_sources/apkmirror.dart index 0bb35ac..1bfa8d0 100644 --- a/lib/app_sources/apkmirror.dart +++ b/lib/app_sources/apkmirror.dart @@ -9,7 +9,7 @@ import 'package:obtainium/providers/source_provider.dart'; class APKMirror extends AppSource { APKMirror() { - host = 'apkmirror.com'; + hosts = ['apkmirror.com']; enforceTrackOnly = true; additionalSourceAppSpecificSettingFormItems = [ @@ -33,12 +33,12 @@ class APKMirror extends AppSource { @override String sourceSpecificStandardizeURL(String url) { RegExp standardUrlRegEx = - RegExp('^https?://(www\\.)?$host/apk/[^/]+/[^/]+'); + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/apk/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/apkpure.dart b/lib/app_sources/apkpure.dart index 0fe3548..e145b28 100644 --- a/lib/app_sources/apkpure.dart +++ b/lib/app_sources/apkpure.dart @@ -20,7 +20,7 @@ parseDateTimeMMMddCommayyyy(String? dateString) { class APKPure extends AppSource { APKPure() { - host = 'apkpure.com'; + hosts = ['apkpure.net', 'apkpure.com']; allowSubDomains = true; naiveStandardVersionDetection = true; } @@ -28,18 +28,18 @@ class APKPure extends AppSource { @override String sourceSpecificStandardizeURL(String url) { RegExp standardUrlRegExB = - RegExp('^https?://m.$host/+[^/]+/+[^/]+(/+[^/]+)?'); + RegExp('^https?://m.${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?'); RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); if (match != null) { - url = 'https://$host${Uri.parse(url).path}'; + url = 'https://${getSourceRegex(hosts)}${Uri.parse(url).path}'; } - RegExp standardUrlRegExA = - RegExp('^https?://(www\\.)?$host/+[^/]+/+[^/]+(/+[^/]+)?'); + RegExp standardUrlRegExA = RegExp( + '^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+[^/]+(/+[^/]+)?'); match = standardUrlRegExA.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/aptoide.dart b/lib/app_sources/aptoide.dart index ea162df..58470d5 100644 --- a/lib/app_sources/aptoide.dart +++ b/lib/app_sources/aptoide.dart @@ -6,7 +6,7 @@ import 'package:obtainium/providers/source_provider.dart'; class Aptoide extends AppSource { Aptoide() { - host = 'aptoide.com'; + hosts = ['aptoide.com']; name = 'Aptoide'; allowSubDomains = true; naiveStandardVersionDetection = true; @@ -14,12 +14,13 @@ class Aptoide extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://([^\\.]+\\.){2,}$host'); + RegExp standardUrlRegEx = + RegExp('^https?://([^\\.]+\\.){2,}${getSourceRegex(hosts)}'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/codeberg.dart b/lib/app_sources/codeberg.dart index 44a7bdf..9e9b7b6 100644 --- a/lib/app_sources/codeberg.dart +++ b/lib/app_sources/codeberg.dart @@ -5,7 +5,7 @@ import 'package:obtainium/providers/source_provider.dart'; class Codeberg extends AppSource { GitHub gh = GitHub(); Codeberg() { - host = 'codeberg.org'; + hosts = ['codeberg.org']; additionalSourceAppSpecificSettingFormItems = gh.additionalSourceAppSpecificSettingFormItems; @@ -16,12 +16,13 @@ class Codeberg extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override @@ -35,7 +36,7 @@ class Codeberg extends AppSource { ) async { return await gh.getLatestAPKDetailsCommon2(standardUrl, additionalSettings, (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); } @@ -50,7 +51,7 @@ class Codeberg extends AppSource { {Map querySettings = const {}}) async { return gh.searchCommon( 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', querySettings: querySettings); } diff --git a/lib/app_sources/fdroid.dart b/lib/app_sources/fdroid.dart index a9e1707..f3a38bd 100644 --- a/lib/app_sources/fdroid.dart +++ b/lib/app_sources/fdroid.dart @@ -9,7 +9,7 @@ import 'package:obtainium/providers/source_provider.dart'; class FDroid extends AppSource { FDroid() { - host = 'f-droid.org'; + hosts = ['f-droid.org']; name = tr('fdroid'); naiveStandardVersionDetection = true; canSearch = true; @@ -37,20 +37,20 @@ class FDroid extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegExB = - RegExp('^https?://(www\\.)?$host/+[^/]+/+packages/+[^/]+'); + RegExp standardUrlRegExB = RegExp( + '^https?://(www\\.)?${getSourceRegex(hosts)}/+[^/]+/+packages/+[^/]+'); RegExpMatch? match = standardUrlRegExB.firstMatch(url.toLowerCase()); if (match != null) { 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('^https?://(www\\.)?$host/+packages/+[^/]+'); + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/+packages/+[^/]+'); match = standardUrlRegExA.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override @@ -117,7 +117,7 @@ class FDroid extends AppSource { Future>> search(String query, {Map querySettings = const {}}) async { Response res = await sourceRequest( - 'https://search.$host/?q=${Uri.encodeQueryComponent(query)}'); + 'https://search.${hosts[0]}/?q=${Uri.encodeQueryComponent(query)}'); if (res.statusCode == 200) { Map> urlsWithDescriptions = {}; parse(res.body).querySelectorAll('.package-header').forEach((e) { diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index 754de12..26d71a2 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -14,7 +14,7 @@ import 'package:url_launcher/url_launcher_string.dart'; class GitHub extends AppSource { GitHub() { - host = 'github.com'; + hosts = ['github.com']; appIdInferIsOptional = true; sourceConfigSettingFormItems = [ @@ -149,12 +149,13 @@ class GitHub extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override @@ -203,11 +204,11 @@ class GitHub extends AppSource { } Future getAPIHost(Map additionalSettings) async => - 'https://api.$host'; + 'https://api.${hosts[0]}'; Future convertStandardUrlToAPIUrl( String standardUrl, Map additionalSettings) async => - '${await getAPIHost(additionalSettings)}/repos${standardUrl.substring('https://$host'.length)}'; + '${await getAPIHost(additionalSettings)}/repos${standardUrl.substring('https://${hosts[0]}'.length)}'; @override String? changeLogPageFromStandardUrl(String standardUrl) => diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index a0e8f14..a9ecac2 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -13,7 +13,7 @@ import 'package:url_launcher/url_launcher_string.dart'; class GitLab extends AppSource { GitLab() { - host = 'gitlab.com'; + hosts = ['gitlab.com']; canSearch = true; sourceConfigSettingFormItems = [ @@ -52,12 +52,13 @@ class GitLab extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } Future getPATIfAny(Map additionalSettings) async { @@ -81,7 +82,7 @@ class GitLab extends AppSource { Future>> search(String query, {Map querySettings = const {}}) async { 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); if (res.statusCode != 200) { throw getObtainiumHttpError(res); @@ -89,7 +90,7 @@ class GitLab extends AppSource { var json = jsonDecode(res.body) as List; Map> results = {}; 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['description'] ?? tr('noDescription') ]; @@ -113,7 +114,7 @@ class GitLab extends AppSource { if (PAT != null) { var names = GitHub().getAppNames(standardUrl); 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) { throw getObtainiumHttpError(res); } diff --git a/lib/app_sources/huaweiappgallery.dart b/lib/app_sources/huaweiappgallery.dart index a073d2a..b4f7605 100644 --- a/lib/app_sources/huaweiappgallery.dart +++ b/lib/app_sources/huaweiappgallery.dart @@ -6,23 +6,24 @@ import 'package:obtainium/providers/source_provider.dart'; class HuaweiAppGallery extends AppSource { HuaweiAppGallery() { name = 'Huawei AppGallery'; - host = 'appgallery.huawei.com'; + hosts = ['appgallery.huawei.com']; overrideVersionDetectionFormDefault('releaseDateAsVersion', disableStandard: true); } @override 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()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } 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 { Response res = await sourceRequest(dlUrl, followRedirects: false); diff --git a/lib/app_sources/izzyondroid.dart b/lib/app_sources/izzyondroid.dart index dd301b3..75a9d59 100644 --- a/lib/app_sources/izzyondroid.dart +++ b/lib/app_sources/izzyondroid.dart @@ -6,7 +6,7 @@ class IzzyOnDroid extends AppSource { late FDroid fd; IzzyOnDroid() { - host = 'izzysoft.de'; + hosts = ['izzysoft.de']; fd = FDroid(); additionalSourceAppSpecificSettingFormItems = fd.additionalSourceAppSpecificSettingFormItems; @@ -15,17 +15,18 @@ class IzzyOnDroid extends AppSource { @override 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()); if (match == null) { - RegExp standardUrlRegExB = - RegExp('^https?://apt.$host/fdroid/index/apk/[^/]+'); + RegExp standardUrlRegExB = RegExp( + '^https?://apt.${getSourceRegex(hosts)}/fdroid/index/apk/[^/]+'); match = standardUrlRegExB.firstMatch(url.toLowerCase()); } if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/jenkins.dart b/lib/app_sources/jenkins.dart index 9e5af8d..d816cfc 100644 --- a/lib/app_sources/jenkins.dart +++ b/lib/app_sources/jenkins.dart @@ -16,7 +16,7 @@ class Jenkins extends AppSource { if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/mullvad.dart b/lib/app_sources/mullvad.dart index ff9cefb..ddba4f1 100644 --- a/lib/app_sources/mullvad.dart +++ b/lib/app_sources/mullvad.dart @@ -6,17 +6,18 @@ import 'package:obtainium/providers/source_provider.dart'; class Mullvad extends AppSource { Mullvad() { - host = 'mullvad.net'; + hosts = ['mullvad.net']; } @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/neutroncode.dart b/lib/app_sources/neutroncode.dart index 9ce0fdd..29c1d64 100644 --- a/lib/app_sources/neutroncode.dart +++ b/lib/app_sources/neutroncode.dart @@ -5,18 +5,18 @@ import 'package:obtainium/providers/source_provider.dart'; class NeutronCode extends AppSource { NeutronCode() { - host = 'neutroncode.com'; + hosts = ['neutroncode.com']; } @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = - RegExp('^https?://(www\\.)?$host/downloads/file/[^/]+'); + RegExp standardUrlRegEx = RegExp( + '^https?://(www\\.)?${getSourceRegex(hosts)}/downloads/file/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override @@ -92,7 +92,7 @@ class NeutronCode extends AppSource { if (version == null) { throw NoVersionError(); } - String? apkUrl = 'https://$host/download/$filename'; + String? apkUrl = 'https://${hosts[0]}/download/$filename'; var dateStringOriginal = http.querySelector('.pd-date-txt')?.nextElementSibling?.innerHtml; var dateString = dateStringOriginal != null diff --git a/lib/app_sources/signal.dart b/lib/app_sources/signal.dart index f7bda25..2e79f2d 100644 --- a/lib/app_sources/signal.dart +++ b/lib/app_sources/signal.dart @@ -5,12 +5,12 @@ import 'package:obtainium/providers/source_provider.dart'; class Signal extends AppSource { Signal() { - host = 'signal.org'; + hosts = ['signal.org']; } @override String sourceSpecificStandardizeURL(String url) { - return 'https://$host'; + return 'https://${hosts[0]}'; } @override @@ -19,7 +19,7 @@ class Signal extends AppSource { Map additionalSettings, ) async { Response res = - await sourceRequest('https://updates.$host/android/latest.json'); + await sourceRequest('https://updates.${hosts[0]}/android/latest.json'); if (res.statusCode == 200) { var json = jsonDecode(res.body); String? apkUrl = json['url']; diff --git a/lib/app_sources/sourceforge.dart b/lib/app_sources/sourceforge.dart index 885a9cc..af64065 100644 --- a/lib/app_sources/sourceforge.dart +++ b/lib/app_sources/sourceforge.dart @@ -5,24 +5,25 @@ import 'package:obtainium/providers/source_provider.dart'; class SourceForge extends AppSource { SourceForge() { - host = 'sourceforge.net'; + hosts = ['sourceforge.net']; } @override 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()); if (match != null) { 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('^https?://(www\\.)?$host/projects/[^/]+'); + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/projects/[^/]+'); match = standardUrlRegExA.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/sourcehut.dart b/lib/app_sources/sourcehut.dart index 05b9959..3bae7db 100644 --- a/lib/app_sources/sourcehut.dart +++ b/lib/app_sources/sourcehut.dart @@ -8,7 +8,7 @@ import 'package:easy_localization/easy_localization.dart'; class SourceHut extends AppSource { SourceHut() { - host = 'git.sr.ht'; + hosts = ['git.sr.ht']; additionalSourceAppSpecificSettingFormItems = [ [ @@ -20,12 +20,13 @@ class SourceHut extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://(www\\.)?$host/[^/]+/[^/]+'); + RegExp standardUrlRegEx = + RegExp('^https?://(www\\.)?${getSourceRegex(hosts)}/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return url.substring(0, match.end); + return match.group(0)!; } @override diff --git a/lib/app_sources/steammobile.dart b/lib/app_sources/steammobile.dart index 65c518b..9185518 100644 --- a/lib/app_sources/steammobile.dart +++ b/lib/app_sources/steammobile.dart @@ -7,7 +7,7 @@ import 'package:obtainium/providers/source_provider.dart'; class SteamMobile extends AppSource { SteamMobile() { - host = 'store.steampowered.com'; + hosts = ['store.steampowered.com']; name = tr('steam'); additionalSourceAppSpecificSettingFormItems = [ [ @@ -21,7 +21,7 @@ class SteamMobile extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - return 'https://$host'; + return 'https://${hosts[0]}'; } @override @@ -29,7 +29,7 @@ class SteamMobile extends AppSource { String standardUrl, Map additionalSettings, ) async { - Response res = await sourceRequest('https://$host/mobile'); + Response res = await sourceRequest('https://${hosts[0]}/mobile'); if (res.statusCode == 200) { var apkNamePrefix = additionalSettings['app'] as String?; if (apkNamePrefix == null) { diff --git a/lib/app_sources/telegramapp.dart b/lib/app_sources/telegramapp.dart index 44042e0..b514af4 100644 --- a/lib/app_sources/telegramapp.dart +++ b/lib/app_sources/telegramapp.dart @@ -6,13 +6,13 @@ import 'package:obtainium/providers/source_provider.dart'; class TelegramApp extends AppSource { TelegramApp() { - host = 'telegram.org'; + hosts = ['telegram.org']; name = 'Telegram ${tr('app')}'; } @override String sourceSpecificStandardizeURL(String url) { - return 'https://$host'; + return 'https://${hosts[0]}'; } @override diff --git a/lib/app_sources/uptodown.dart b/lib/app_sources/uptodown.dart index 7a0b41d..0cc6089 100644 --- a/lib/app_sources/uptodown.dart +++ b/lib/app_sources/uptodown.dart @@ -6,19 +6,20 @@ import 'package:obtainium/providers/source_provider.dart'; class Uptodown extends AppSource { Uptodown() { - host = 'uptodown.com'; + hosts = ['uptodown.com']; allowSubDomains = true; naiveStandardVersionDetection = true; } @override String sourceSpecificStandardizeURL(String url) { - RegExp standardUrlRegEx = RegExp('^https?://([^\\.]+\\.){2,}$host'); + RegExp standardUrlRegEx = + RegExp('^https?://([^\\.]+\\.){2,}${getSourceRegex(hosts)}'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { throw InvalidURLError(name); } - return '${url.substring(0, match.end)}/android/download'; + return '${match.group(0)!}/android/download'; } @override @@ -94,6 +95,6 @@ class Uptodown extends AppSource { if (finalUrlKey == null) { throw NoAPKError(); } - return 'https://dw.$host/dwn/$finalUrlKey'; + return 'https://dw.${hosts[0]}/dwn/$finalUrlKey'; } } diff --git a/lib/app_sources/vlc.dart b/lib/app_sources/vlc.dart index 091411a..40a42ec 100644 --- a/lib/app_sources/vlc.dart +++ b/lib/app_sources/vlc.dart @@ -7,9 +7,9 @@ import 'package:obtainium/providers/source_provider.dart'; class VLC extends AppSource { VLC() { - host = 'videolan.org'; + hosts = ['videolan.org']; } - get dwUrlBase => 'https://get.$host/vlc-android/'; + get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/'; @override Future?> getRequestHeaders( @@ -21,7 +21,7 @@ class VLC extends AppSource { @override String sourceSpecificStandardizeURL(String url) { - return 'https://$host'; + return 'https://${hosts[0]}'; } Future getLatestVersion(String standardUrl) async { diff --git a/lib/app_sources/whatsapp.dart b/lib/app_sources/whatsapp.dart index 702b52a..ed0fdb1 100644 --- a/lib/app_sources/whatsapp.dart +++ b/lib/app_sources/whatsapp.dart @@ -5,14 +5,14 @@ import 'package:obtainium/providers/source_provider.dart'; class WhatsApp extends AppSource { WhatsApp() { - host = 'whatsapp.com'; + hosts = ['whatsapp.com']; overrideVersionDetectionFormDefault('noVersionDetection', disableStandard: true, disableRelDate: true); } @override String sourceSpecificStandardizeURL(String url) { - return 'https://$host'; + return 'https://${hosts[0]}'; } @override diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index 6c4b9a3..41deae2 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -59,7 +59,9 @@ class AddAppPageState extends State { if (updateUrlInput) { urlInputKey++; } - var prevHost = pickedSource?.host; + var prevHost = pickedSource?.hosts.isNotEmpty == true + ? pickedSource?.hosts[0] + : null; try { var naturalSource = valid ? sourceProvider.getSource(userInput) : null; @@ -77,7 +79,7 @@ class AddAppPageState extends State { overrideSource: pickedSourceOverride) : null; if (pickedSource.runtimeType != source.runtimeType || - (prevHost != null && prevHost != source?.host)) { + (prevHost != null && prevHost != source?.hosts[0])) { pickedSource = source; additionalSettings = source != null ? getDefaultValuesFromFormItems( @@ -508,16 +510,16 @@ class AddAppPageState extends State { height: 16, ), ...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); } : null, child: Text( '${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', style: TextStyle( - decoration: e.host != null + decoration: e.hosts.isNotEmpty ? TextDecoration.underline : TextDecoration.none, fontStyle: FontStyle.italic), diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index 2605089..18a61dd 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -199,10 +199,11 @@ class _ImportExportPageState extends State { ...source.searchQuerySettingFormItems.map((e) => [e]), [ GeneratedFormTextField('url', - label: source.host != null + label: source.hosts.isNotEmpty ? tr('overrideSource') : plural('url', 1).substring(2), - defaultValue: source.host ?? '', + defaultValue: + source.hosts.isNotEmpty ? source.hosts[0] : '', required: true) ], ], @@ -212,7 +213,7 @@ class _ImportExportPageState extends State { setState(() { importInProgress = true; }); - if (values['url'] != source.host) { + if (values['url'] != source.hosts[0]) { source = sourceProvider.getSource(values['url'], overrideSource: source.runtimeType.toString()); } diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 3935f9c..c649fb7 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -14,7 +14,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:shared_preferences/shared_preferences.dart'; 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'; enum InstallMethodSettings { normal, shizuku, root } diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index aef2e00..f60da70 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -366,8 +366,12 @@ List> getApkUrlsFromUrls(List urls) => return MapEntry(apkSegs.isNotEmpty ? apkSegs.last : segments.last, e); }).toList(); +getSourceRegex(List hosts) { + return '(${hosts.join('|').replaceAll('.', '\\.')})'; +} + abstract class AppSource { - String? host; + List hosts = []; bool hostChanged = false; late String name; bool enforceTrackOnly = false; @@ -697,14 +701,14 @@ class SourceProvider { throw UnsupportedURLError(); } var res = srcs.first; - res.host = Uri.parse(url).host; + res.hosts = [Uri.parse(url).host]; res.hostChanged = true; return srcs.first; } AppSource? source; - for (var s in sources.where((element) => element.host != null)) { + for (var s in sources.where((element) => element.hosts.isNotEmpty)) { if (RegExp( - '://${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}${s.host}(/|\\z)?') + '://${s.allowSubDomains ? '([^\\.]+\\.)*' : '(www\\.)?'}(${getSourceRegex(s.hosts)})(/|\\z)?') .hasMatch(url)) { source = s; break; @@ -712,7 +716,7 @@ class SourceProvider { } if (source == null) { for (var s in sources.where( - (element) => element.host == null && !element.neverAutoSelect)) { + (element) => element.hosts.isEmpty && !element.neverAutoSelect)) { try { s.sourceSpecificStandardizeURL(url); source = s;