Re-added APKMirror as a Track-Only source

This commit is contained in:
Imran Remtulla
2022-11-25 18:55:17 -05:00
parent b04d2fad5c
commit 25953399ac
3 changed files with 87 additions and 35 deletions

View File

@@ -0,0 +1,55 @@
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class APKMirror extends AppSource {
APKMirror() {
host = 'apkmirror.com';
enforceTrackOnly = true;
}
@override
String standardizeURL(String url) {
RegExp standardUrlRegEx = RegExp('^https?://$host/apk/[^/]+/[^/]+');
RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase());
if (match == null) {
throw InvalidURLError(runtimeType.toString());
}
return url.substring(0, match.end);
}
@override
String? changeLogPageFromStandardUrl(String standardUrl) =>
'$standardUrl/#whatsnew';
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async {
Response res = await get(Uri.parse('$standardUrl/feed'));
if (res.statusCode == 200) {
String? titleString = parse(res.body)
.querySelector('item')
?.querySelector('title')
?.innerHtml;
String? version = titleString
?.substring(0,
RegExp(' build ( |[0-9])+').firstMatch(titleString)?.start ?? 0)
.split(' ')
.last;
if (version == null) {
throw NoVersionError();
}
return APKDetails(version, []);
} else {
throw NoReleasesError();
}
}
@override
AppNames getAppNames(String standardUrl) {
String temp = standardUrl.substring(standardUrl.indexOf('://') + 3);
List<String> names = temp.substring(temp.indexOf('/') + 1).split('/');
return AppNames(names[1], names[2]);
}
}

View File

@@ -143,7 +143,7 @@ class _AddAppPageState extends State<AddAppPage> {
(BuildContext ctx) { (BuildContext ctx) {
return GeneratedFormModal( return GeneratedFormModal(
title: title:
'App is Track-Only', '${pickedSource!.enforceTrackOnly ? 'Source' : 'App'} is Track-Only',
items: const [], items: const [],
defaultValues: const [], defaultValues: const [],
message: message:
@@ -222,7 +222,11 @@ class _AddAppPageState extends State<AddAppPage> {
(pickedSource!.additionalSourceAppSpecificDefaults (pickedSource!.additionalSourceAppSpecificDefaults
.isNotEmpty || .isNotEmpty ||
pickedSource! pickedSource!
.additionalAppSpecificSourceAgnosticDefaults .additionalAppSpecificSourceAgnosticFormItems
.where((e) => pickedSource!.enforceTrackOnly
? e.key != 'trackOnlyFormItemKey'
: true)
.map((e) => [e])
.isNotEmpty)) .isNotEmpty))
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -257,33 +261,27 @@ class _AddAppPageState extends State<AddAppPage> {
}, },
defaultValues: pickedSource! defaultValues: pickedSource!
.additionalSourceAppSpecificDefaults), .additionalSourceAppSpecificDefaults),
if (pickedSource! GeneratedForm(
.additionalSourceAppSpecificFormItems items: pickedSource!
.isNotEmpty) .additionalAppSpecificSourceAgnosticFormItems
const SizedBox( .where((e) => pickedSource!.enforceTrackOnly
height: 8, ? e.key != 'trackOnlyFormItemKey'
), : true)
if (pickedSource! .map((e) => [e])
.additionalAppSpecificSourceAgnosticFormItems .toList(),
.isNotEmpty) onValueChanges: (values, valid, isBuilding) {
GeneratedForm( if (isBuilding) {
items: pickedSource! otherAdditionalData = values;
.additionalAppSpecificSourceAgnosticFormItems otherAdditionalDataIsValid = valid;
.map((e) => [e]) } else {
.toList(), setState(() {
onValueChanges: (values, valid, isBuilding) {
if (isBuilding) {
otherAdditionalData = values; otherAdditionalData = values;
otherAdditionalDataIsValid = valid; otherAdditionalDataIsValid = valid;
} else { });
setState(() { }
otherAdditionalData = values; },
otherAdditionalDataIsValid = valid; defaultValues: pickedSource!
}); .additionalAppSpecificSourceAgnosticDefaults),
}
},
defaultValues: pickedSource!
.additionalAppSpecificSourceAgnosticDefaults),
if (pickedSource! if (pickedSource!
.additionalAppSpecificSourceAgnosticDefaults .additionalAppSpecificSourceAgnosticDefaults
.isNotEmpty) .isNotEmpty)
@@ -304,16 +302,15 @@ class _AddAppPageState extends State<AddAppPage> {
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
...sourceProvider ...sourceProvider.sources
.getSourceHosts()
.map((e) => GestureDetector( .map((e) => GestureDetector(
onTap: () { onTap: () {
launchUrlString('https://$e', launchUrlString('https://${e.host}',
mode: mode:
LaunchMode.externalApplication); LaunchMode.externalApplication);
}, },
child: Text( child: Text(
e, '${e.runtimeType.toString()}${e.enforceTrackOnly ? ' (Track-Only)' : ''}',
style: const TextStyle( style: const TextStyle(
decoration: decoration:
TextDecoration.underline, TextDecoration.underline,

View File

@@ -5,6 +5,7 @@ import 'dart:convert';
import 'package:html/dom.dart'; import 'package:html/dom.dart';
import 'package:http/http.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/fdroid.dart';
import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/github.dart';
import 'package:obtainium/app_sources/gitlab.dart'; import 'package:obtainium/app_sources/gitlab.dart';
@@ -209,7 +210,8 @@ class SourceProvider {
IzzyOnDroid(), IzzyOnDroid(),
Mullvad(), Mullvad(),
Signal(), Signal(),
SourceForge() SourceForge(),
APKMirror()
]; ];
// Add more mass url source classes here so they are available via the service // Add more mass url source classes here so they are available via the service
@@ -254,7 +256,7 @@ class SourceProvider {
return false; return false;
} }
} }
return getSourceHosts().contains(parts.last); return sources.map((e) => e.host).contains(parts.last);
} }
Future<App> getApp(AppSource source, String url, List<String> additionalData, Future<App> getApp(AppSource source, String url, List<String> additionalData,
@@ -306,6 +308,4 @@ class SourceProvider {
} }
return [apps, errors]; return [apps, errors];
} }
List<String> getSourceHosts() => sources.map((e) => e.host).toList();
} }