diff --git a/README.md b/README.md index 691dae1..42a63b9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Currently supported App sources: - [Signal](https://signal.org/) - [SourceForge](https://sourceforge.net/) - [APKMirror](https://apkmirror.com/) (Track-Only) +- Third Party F-Droid Repos (URLs ending with `/fdroid/repo`) ## Limitations - App installs happen asynchronously and the success/failure of an install cannot be determined directly. This results in install statuses and versions sometimes being out of sync with the OS until the next launch or until the problem is manually corrected. diff --git a/assets/translations/en.json b/assets/translations/en.json index 77af562..9456b96 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -20,7 +20,7 @@ "githubPATLabel": "GitHub Personal Access Token (Increases Rate Limit)", "githubPATHint": "PAT must be in this format: username:token", "githubPATFormat": "username:token", - "githubPATLinkText": "'About GitHub PATs", + "githubPATLinkText": "About GitHub PATs", "includePrereleases": "Include prereleases", "fallbackToOlderReleases": "Fallback to older releases", "filterReleaseTitlesByRegEx": "Filter Release Titles by Regular Expression", @@ -179,7 +179,11 @@ "lastUpdateCheckX": "Last Update Check: {}", "remove": "Remove", "removeAppQuestion": "Remove App?", - "yesMarkUpdated": "'Yes, Mark as Updated", + "yesMarkUpdated": "Yes, Mark as Updated", + "fdroid": "F-Droid", + "appId": "App ID", + "reposHaveMultipleApps": "Repos may contain multiple Apps", + "fdroidThirdPartyRepo": "F-Droid Third-Party Repo", "tooManyRequestsTryAgainInMinutes": { "one": "Too many requests (rate limited) - try again in {} minute", "other": "Too many requests (rate limited) - try again in {} minutes" diff --git a/assets/translations/it.json b/assets/translations/it.json index 2423a71..ef6b41d 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -179,7 +179,11 @@ "lastUpdateCheckX": "Ultimo controllo degli aggiornamenti: {}", "remove": "Rimuovi", "removeAppQuestion": "Rimuovere App?", - "yesMarkUpdated": "'Sì, contrassegna come aggiornato", + "yesMarkUpdated": "Sì, contrassegna come aggiornato", + "fdroid": "F-Droid", + "appId": "App ID", + "reposHaveMultipleApps": "Repos may contain multiple Apps", + "fdroidThirdPartyRepo": "F-Droid Third-Party Repo", "tooManyRequestsTryAgainInMinutes": { "one": "Troppe richieste (traffico limitato) - riprova tra {} minuto", "other": "Troppe richieste (traffico limitato) - riprova tra {} minuti" diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 1603ded..0afdd9e 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -20,7 +20,7 @@ "githubPATLabel": "GitHub 个人访问令牌 (提高 API 限制)", "githubPATHint": "个人访问令牌必须为: username:token 形式", "githubPATFormat": "username:token", - "githubPATLinkText": "'关于 GitHub 个人访问令牌", + "githubPATLinkText": "关于 GitHub 个人访问令牌", "includePrereleases": "包含预发布版", "fallbackToOlderReleases": "回落到旧版", "filterReleaseTitlesByRegEx": "通过正则表达式过滤发布标题", @@ -179,7 +179,11 @@ "lastUpdateCheckX": "Last Update Check: {}", "remove": "Remove", "removeAppQuestion": "Remove App?", - "yesMarkUpdated": "'Yes, Mark as Updated", + "yesMarkUpdated": "Yes, Mark as Updated", + "fdroid": "F-Droid", + "appId": "App ID", + "reposHaveMultipleApps": "Repos may contain multiple Apps", + "fdroidThirdPartyRepo": "F-Droid Third-Party Repo", "tooManyRequestsTryAgainInMinutes": { "one": "请求过多 (API 限制) - 在 {} 分钟后重试", "other": "请求过多 (API 限制) - 在 {} 分钟后重试" diff --git a/lib/app_sources/apkmirror.dart b/lib/app_sources/apkmirror.dart index 66053bd..1372d16 100644 --- a/lib/app_sources/apkmirror.dart +++ b/lib/app_sources/apkmirror.dart @@ -14,7 +14,7 @@ class APKMirror extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host/apk/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -43,13 +43,12 @@ class APKMirror extends AppSource { if (version == null || version.isEmpty) { throw NoVersionError(); } - return APKDetails(version, []); + return APKDetails(version, [], getAppNames(standardUrl)); } else { throw NoReleasesError(); } } - @override AppNames getAppNames(String standardUrl) { String temp = standardUrl.substring(standardUrl.indexOf('://') + 3); List names = temp.substring(temp.indexOf('/') + 1).split('/'); diff --git a/lib/app_sources/fdroid.dart b/lib/app_sources/fdroid.dart index cc526ea..8b7af89 100644 --- a/lib/app_sources/fdroid.dart +++ b/lib/app_sources/fdroid.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +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'; @@ -7,6 +8,7 @@ import 'package:obtainium/providers/source_provider.dart'; class FDroid extends AppSource { FDroid() { host = 'f-droid.org'; + name = tr('fdroid'); } @override @@ -20,7 +22,7 @@ class FDroid extends AppSource { RegExp standardUrlRegExA = RegExp('^https?://$host/+packages/+[^/]+'); match = standardUrlRegExA.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -29,12 +31,13 @@ class FDroid extends AppSource { String? changeLogPageFromStandardUrl(String standardUrl) => null; @override - String? tryInferringAppId(String standardUrl) { + String? tryInferringAppId(String standardUrl, + {List additionalData = const []}) { return Uri.parse(standardUrl).pathSegments.last; } APKDetails getAPKUrlsFromFDroidPackagesAPIResponse( - Response res, String apkUrlPrefix) { + Response res, String apkUrlPrefix, String standardUrl) { if (res.statusCode == 200) { List releases = jsonDecode(res.body)['packages'] ?? []; if (releases.isEmpty) { @@ -48,7 +51,8 @@ class FDroid extends AppSource { .where((element) => element['versionName'] == latestVersion) .map((e) => '${apkUrlPrefix}_${e['versionCode']}.apk') .toList(); - return APKDetails(latestVersion, apkUrls); + return APKDetails(latestVersion, apkUrls, + AppNames(name, Uri.parse(standardUrl).pathSegments.last)); } else { throw NoReleasesError(); } @@ -61,11 +65,7 @@ class FDroid extends AppSource { String? appId = tryInferringAppId(standardUrl); return getAPKUrlsFromFDroidPackagesAPIResponse( await get(Uri.parse('https://f-droid.org/api/v1/packages/$appId')), - 'https://f-droid.org/repo/$appId'); - } - - @override - AppNames getAppNames(String standardUrl) { - return AppNames('F-Droid', Uri.parse(standardUrl).pathSegments.last); + 'https://f-droid.org/repo/$appId', + standardUrl); } } diff --git a/lib/app_sources/fdroidRepo.dart b/lib/app_sources/fdroidRepo.dart new file mode 100644 index 0000000..fa43feb --- /dev/null +++ b/lib/app_sources/fdroidRepo.dart @@ -0,0 +1,81 @@ +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'; + +class FDroidRepo extends AppSource { + FDroidRepo() { + name = tr('fdroidThirdPartyRepo'); + + additionalSourceAppSpecificFormItems = [ + [ + GeneratedFormItem( + label: tr('appId'), + hint: tr('reposHaveMultipleApps'), + required: true, + key: 'appId') + ] + ]; + } + + @override + String standardizeURL(String url) { + RegExp standardUrlRegExp = + RegExp('^https?://.+/fdroid/(repo(/|\\?)|repo\$)'); + RegExpMatch? match = standardUrlRegExp.firstMatch(url.toLowerCase()); + if (match == null) { + throw InvalidURLError(name); + } + return url.substring(0, match.end); + } + + @override + String? tryInferringAppId(String standardUrl, + {List additionalData = const []}) { + return findGeneratedFormValueByKey( + additionalSourceAppSpecificFormItems + .reduce((value, element) => [...value, ...element]), + additionalData, + 'appId'); + } + + @override + Future getLatestAPKDetails( + String standardUrl, List additionalData, + {bool trackOnly = false}) async { + String? appId = + tryInferringAppId(standardUrl, additionalData: additionalData); + if (appId == null) { + throw NoReleasesError(); + } + var res = await get(Uri.parse('$standardUrl/index.xml')); + if (res.statusCode == 200) { + var body = parse(res.body); + var foundApps = body + .querySelectorAll('application') + .where((element) => element.attributes['id'] == appId) + .toList(); + if (foundApps.isEmpty) { + throw NoReleasesError(); + } + var authorName = body.querySelector('repo')?.attributes['name'] ?? name; + var appName = foundApps[0].querySelector('name')?.innerHtml ?? appId; + var releases = foundApps[0].querySelectorAll('package'); + String? latestVersion = releases[0].querySelector('version')?.innerHtml; + if (latestVersion == null) { + throw NoVersionError(); + } + List apkUrls = releases + .where((element) => + element.querySelector('version')?.innerHtml == latestVersion && + element.querySelector('apkname') != null) + .map((e) => '$standardUrl/${e.querySelector('apkname')!.innerHtml}') + .toList(); + return APKDetails(latestVersion, apkUrls, AppNames(authorName, appName)); + } else { + throw NoReleasesError(); + } + } +} diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index 5f821bf..3fdbf4a 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -90,7 +90,7 @@ class GitHub extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -162,14 +162,14 @@ class GitHub extends AppSource { if (version == null) { throw NoVersionError(); } - return APKDetails(version, targetRelease['apkUrls'] as List); + return APKDetails(version, targetRelease['apkUrls'] as List, + getAppNames(standardUrl)); } else { rateLimitErrorCheck(res); throw getObtainiumHttpError(res); } } - @override AppNames getAppNames(String standardUrl) { String temp = standardUrl.substring(standardUrl.indexOf('://') + 3); List names = temp.substring(temp.indexOf('/') + 1).split('/'); diff --git a/lib/app_sources/gitlab.dart b/lib/app_sources/gitlab.dart index aa83b8d..6c2f5ab 100644 --- a/lib/app_sources/gitlab.dart +++ b/lib/app_sources/gitlab.dart @@ -14,7 +14,7 @@ class GitLab extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host/[^/]+/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -56,15 +56,9 @@ class GitLab extends AppSource { if (version == null) { throw NoVersionError(); } - return APKDetails(version, apkUrls); + return APKDetails(version, apkUrls, GitHub().getAppNames(standardUrl)); } else { throw NoReleasesError(); } } - - @override - AppNames getAppNames(String standardUrl) { - // Same as GitHub - return GitHub().getAppNames(standardUrl); - } } diff --git a/lib/app_sources/izzyondroid.dart b/lib/app_sources/izzyondroid.dart index f2321f8..13ea4bd 100644 --- a/lib/app_sources/izzyondroid.dart +++ b/lib/app_sources/izzyondroid.dart @@ -13,7 +13,7 @@ class IzzyOnDroid extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host/repo/apk/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -22,7 +22,8 @@ class IzzyOnDroid extends AppSource { String? changeLogPageFromStandardUrl(String standardUrl) => null; @override - String? tryInferringAppId(String standardUrl) { + String? tryInferringAppId(String standardUrl, + {List additionalData = const []}) { return FDroid().tryInferringAppId(standardUrl); } @@ -34,11 +35,7 @@ class IzzyOnDroid extends AppSource { return FDroid().getAPKUrlsFromFDroidPackagesAPIResponse( await get( Uri.parse('https://apt.izzysoft.de/fdroid/api/v1/packages/$appId')), - 'https://android.izzysoft.de/frepo/$appId'); - } - - @override - AppNames getAppNames(String standardUrl) { - return AppNames('IzzyOnDroid', Uri.parse(standardUrl).pathSegments.last); + 'https://android.izzysoft.de/frepo/$appId', + standardUrl); } } diff --git a/lib/app_sources/mullvad.dart b/lib/app_sources/mullvad.dart index bece54b..353e460 100644 --- a/lib/app_sources/mullvad.dart +++ b/lib/app_sources/mullvad.dart @@ -13,7 +13,7 @@ class Mullvad extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -38,14 +38,11 @@ class Mullvad extends AppSource { throw NoVersionError(); } return APKDetails( - version, ['https://mullvad.net/download/app/apk/latest']); + version, + ['https://mullvad.net/download/app/apk/latest'], + AppNames(name, 'Mullvad-VPN')); } else { throw NoReleasesError(); } } - - @override - AppNames getAppNames(String standardUrl) { - return AppNames('Mullvad-VPN', 'Mullvad-VPN'); - } } diff --git a/lib/app_sources/signal.dart b/lib/app_sources/signal.dart index 088e9a5..517a7df 100644 --- a/lib/app_sources/signal.dart +++ b/lib/app_sources/signal.dart @@ -30,12 +30,9 @@ class Signal extends AppSource { if (version == null) { throw NoVersionError(); } - return APKDetails(version, apkUrls); + return APKDetails(version, apkUrls, AppNames(name, 'Signal')); } else { throw NoReleasesError(); } } - - @override - AppNames getAppNames(String standardUrl) => AppNames('Signal', 'Signal'); } diff --git a/lib/app_sources/sourceforge.dart b/lib/app_sources/sourceforge.dart index 43438d8..6961ea8 100644 --- a/lib/app_sources/sourceforge.dart +++ b/lib/app_sources/sourceforge.dart @@ -13,7 +13,7 @@ class SourceForge extends AppSource { RegExp standardUrlRegEx = RegExp('^https?://$host/projects/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); if (match == null) { - throw InvalidURLError(runtimeType.toString()); + throw InvalidURLError(name); } return url.substring(0, match.end); } @@ -50,15 +50,13 @@ class SourceForge extends AppSource { apkUrlListAllReleases // This can be used skipped for fallback support later .where((element) => getVersion(element) == version) .toList(); - return APKDetails(version, apkUrlList); + return APKDetails( + version, + apkUrlList, + AppNames( + name, standardUrl.substring(standardUrl.lastIndexOf('/') + 1))); } else { throw NoReleasesError(); } } - - @override - AppNames getAppNames(String standardUrl) { - return AppNames(runtimeType.toString(), - standardUrl.substring(standardUrl.lastIndexOf('/') + 1)); - } } diff --git a/lib/components/generated_form.dart b/lib/components/generated_form.dart index a00872f..9ca009e 100644 --- a/lib/components/generated_form.dart +++ b/lib/components/generated_form.dart @@ -28,7 +28,11 @@ class GeneratedFormItem { this.belowWidgets = const [], this.hint, this.opts, - this.key = 'default'}); + this.key = 'default'}) { + if (type != FormItemType.string) { + required = false; + } + } } class GeneratedForm extends StatefulWidget { diff --git a/lib/main.dart b/lib/main.dart index 7785396..42de43d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,7 +21,7 @@ import 'package:easy_localization/src/easy_localization_controller.dart'; // ignore: implementation_imports import 'package:easy_localization/src/localization.dart'; -const String currentVersion = '0.8.12'; +const String currentVersion = '0.8.13'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES @@ -87,7 +87,7 @@ Future bgUpdateCheck(int taskId, Map? params) async { if (e is RateLimitError || e is SocketException) { var remainingMinutes = e is RateLimitError ? e.remainingMinutes : 15; logs.add(plural('bgUpdateGotErrorRetryInMinutes', remainingMinutes, - args: [e.runtimeType.toString(), remainingMinutes.toString()])); + args: [(e as AppSource).name, remainingMinutes.toString()])); AndroidAlarmManager.oneShot(Duration(minutes: remainingMinutes), Random().nextInt(pow(2, 31) as int), bgUpdateCheck, params: { 'ignoreAfterMicroseconds': nextIgnoreAfter.microsecondsSinceEpoch diff --git a/lib/pages/add_app.dart b/lib/pages/add_app.dart index f206efd..e9b9f4b 100644 --- a/lib/pages/add_app.dart +++ b/lib/pages/add_app.dart @@ -41,12 +41,12 @@ class _AddAppPageState extends State { userInput = input; fn() { var source = valid ? sourceProvider.getSource(userInput) : null; - if (pickedSource != source) { + if (pickedSource.runtimeType != source.runtimeType) { pickedSource = source; sourceSpecificAdditionalData = source != null ? source.additionalSourceAppSpecificDefaults : []; sourceSpecificDataIsValid = source != null - ? sourceProvider.ifSourceAppsRequireAdditionalData(source) + ? !sourceProvider.ifSourceAppsRequireAdditionalData(source) : true; } } @@ -308,10 +308,8 @@ class _AddAppPageState extends State { height: 64, ), Text( - tr('additionalOptsFor', args: [ - pickedSource?.runtimeType.toString() ?? - tr('source') - ]), + tr('additionalOptsFor', + args: [pickedSource?.name ?? tr('source')]), style: TextStyle( color: Theme.of(context).colorScheme.primary)), @@ -383,16 +381,20 @@ class _AddAppPageState extends State { ), ...sourceProvider.sources .map((e) => GestureDetector( - onTap: () { - launchUrlString('https://${e.host}', - mode: - LaunchMode.externalApplication); - }, + onTap: e.host != null + ? () { + launchUrlString( + 'https://${e.host}', + mode: LaunchMode + .externalApplication); + } + : null, child: Text( - '${e.runtimeType.toString()}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', - style: const TextStyle( - decoration: - TextDecoration.underline, + '${e.name}${e.enforceTrackOnly ? ' ${tr('trackOnlyInBrackets')}' : ''}${e.canSearch ? ' ${tr('searchableInBrackets')}' : ''}', + style: TextStyle( + decoration: e.host != null + ? TextDecoration.underline + : TextDecoration.none, fontStyle: FontStyle.italic), ))) .toList() diff --git a/lib/pages/import_export.dart b/lib/pages/import_export.dart index 17cea13..889969b 100644 --- a/lib/pages/import_export.dart +++ b/lib/pages/import_export.dart @@ -232,9 +232,7 @@ class _ImportExportPageState extends State { return GeneratedFormModal( title: tr('searchX', args: [ - source - .runtimeType - .toString() + source.name ]), items: [ [ @@ -319,9 +317,8 @@ class _ImportExportPageState extends State { }); }); }, - child: Text(tr('searchX', args: [ - source.runtimeType.toString() - ]))) + child: Text( + tr('searchX', args: [source.name]))) ])) .toList(), ...sourceProvider.massUrlSources diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 5ea3de2..7af0664 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -8,6 +8,7 @@ import 'package:html/dom.dart'; import 'package:http/http.dart'; import 'package:obtainium/app_sources/apkmirror.dart'; import 'package:obtainium/app_sources/fdroid.dart'; +import 'package:obtainium/app_sources/fdroidRepo.dart'; import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/gitlab.dart'; import 'package:obtainium/app_sources/izzyondroid.dart'; @@ -28,8 +29,9 @@ class AppNames { class APKDetails { late String version; late List apkUrls; + late AppNames names; - APKDetails(this.version, this.apkUrls); + APKDetails(this.version, this.apkUrls, this.names); } class App { @@ -106,11 +108,11 @@ class App { // Ensure the input is starts with HTTPS and has no WWW preStandardizeUrl(String url) { - if (url.toLowerCase().indexOf('http://') != 0 && - url.toLowerCase().indexOf('https://') != 0) { + url = url.toLowerCase(); + if (url.indexOf('http://') != 0 && url.indexOf('https://') != 0) { url = 'https://$url'; } - if (url.toLowerCase().indexOf('https://www.') == 0) { + if (url.indexOf('https://www.') == 0) { url = 'https://${url.substring(12)}'; } url = url @@ -135,8 +137,14 @@ List getLinksFromParsedHTML( .toList(); class AppSource { - late String host; + String? host; + late String name; bool enforceTrackOnly = false; + + AppSource() { + name = runtimeType.toString(); + } + String standardizeURL(String url) { throw NotImplementedError(); } @@ -147,10 +155,6 @@ class AppSource { throw NotImplementedError(); } - AppNames getAppNames(String standardUrl) { - throw NotImplementedError(); - } - // Different Sources may need different kinds of additional data for Apps List> additionalSourceAppSpecificFormItems = []; List additionalSourceAppSpecificDefaults = []; @@ -168,7 +172,7 @@ class AppSource { List additionalSourceSpecificSettingFormItems = []; String? changeLogPageFromStandardUrl(String standardUrl) { - throw NotImplementedError(); + return null; } Future apkUrlPrefetchModifier(String apkUrl) async { @@ -180,7 +184,8 @@ class AppSource { throw NotImplementedError(); } - String? tryInferringAppId(String standardUrl) { + String? tryInferringAppId(String standardUrl, + {List additionalData = const []}) { return null; } } @@ -206,7 +211,8 @@ class SourceProvider { Mullvad(), Signal(), SourceForge(), - APKMirror() + APKMirror(), + FDroidRepo() ]; // Add more mass url source classes here so they are available via the service @@ -215,12 +221,23 @@ class SourceProvider { AppSource getSource(String url) { url = preStandardizeUrl(url); AppSource? source; - for (var s in sources) { - if (url.toLowerCase().contains('://${s.host}')) { + for (var s in sources.where((element) => element.host != null)) { + if (url.contains('://${s.host}')) { source = s; break; } } + if (source == null) { + for (var s in sources.where((element) => element.host == null)) { + try { + s.standardizeURL(url); + source = s; + break; + } catch (e) { + // + } + } + } if (source == null) { throw UnsupportedURLError(); } @@ -252,7 +269,7 @@ class SourceProvider { return false; } } - return sources.map((e) => e.host).contains(parts.last); + return true; } Future getApp(AppSource source, String url, List additionalData, @@ -262,7 +279,6 @@ class SourceProvider { bool trackOnly = false, String? installedVersion}) async { String standardUrl = source.standardizeURL(preStandardizeUrl(url)); - AppNames names = source.getAppNames(standardUrl); APKDetails apk = await source .getLatestAPKDetails(standardUrl, additionalData, trackOnly: trackOnly); if (apk.apkUrls.isEmpty && !trackOnly) { @@ -271,13 +287,14 @@ class SourceProvider { String apkVersion = apk.version.replaceAll('/', '-'); return App( id ?? - source.tryInferringAppId(standardUrl) ?? - generateTempID(names, source), + source.tryInferringAppId(standardUrl, + additionalData: additionalData) ?? + generateTempID(apk.names, source), standardUrl, - names.author[0].toUpperCase() + names.author.substring(1), + apk.names.author[0].toUpperCase() + apk.names.author.substring(1), name.trim().isNotEmpty ? name - : names.name[0].toUpperCase() + names.name.substring(1), + : apk.names.name[0].toUpperCase() + apk.names.name.substring(1), installedVersion, apkVersion, apk.apkUrls, diff --git a/pubspec.yaml b/pubspec.yaml index 6eae09f..dab8583 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.8.12+76 # When changing this, update the tag in main() accordingly +version: 0.8.13+77 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0'