Added "skip latest" option to APKPure (also fallback toggle)

This commit is contained in:
Imran Remtulla
2024-10-01 15:49:00 -04:00
parent 783e8029b6
commit cbcc8c4eaf
24 changed files with 137 additions and 83 deletions

View File

@@ -315,6 +315,7 @@
"wiki": "Pomoć/Wiki", "wiki": "Pomoć/Wiki",
"crowdsourcedConfigsLabel": "Konfiguracije aplikacije obezbeđene pomoću velikog broja ljudi (crowdsourcing) (koristite na svoju odgovornost)", "crowdsourcedConfigsLabel": "Konfiguracije aplikacije obezbeđene pomoću velikog broja ljudi (crowdsourcing) (koristite na svoju odgovornost)",
"allowInsecure": "Allow insecure HTTP requests", "allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?", "one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?" "other": "Želite li ukloniti aplikacije?"

View File

@@ -315,6 +315,7 @@
"wiki": "Nápověda/Wiki", "wiki": "Nápověda/Wiki",
"crowdsourcedConfigsLabel": "Konfigurace aplikací s využitím crowdsourcingu (použití na vlastní nebezpečí)", "crowdsourcedConfigsLabel": "Konfigurace aplikací s využitím crowdsourcingu (použití na vlastní nebezpečí)",
"allowInsecure": "Povolení nezabezpečených požadavků HTTP", "allowInsecure": "Povolení nezabezpečených požadavků HTTP",
"stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Odstranit Apku?", "one": "Odstranit Apku?",
"other": "Odstranit Apky?" "other": "Odstranit Apky?"

View File

@@ -315,6 +315,7 @@
"wiki": "Hjælp/Wiki", "wiki": "Hjælp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourcede app-konfigurationer (brug på egen risiko)", "crowdsourcedConfigsLabel": "Crowdsourcede app-konfigurationer (brug på egen risiko)",
"allowInsecure": "Tillad usikre HTTP-anmodninger", "allowInsecure": "Tillad usikre HTTP-anmodninger",
"stayOneVersionBehind": "Vær en version bagud i forhold til den nyeste",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Fjern app?", "one": "Fjern app?",
"other": "Fjern apps?" "other": "Fjern apps?"

View File

@@ -315,6 +315,7 @@
"wiki": "Hilfe/Wiki", "wiki": "Hilfe/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App-Konfigurationen (Verwendung auf eigene Gefahr)", "crowdsourcedConfigsLabel": "Crowdsourced App-Konfigurationen (Verwendung auf eigene Gefahr)",
"allowInsecure": "Unsichere HTTP-Anfragen zulassen", "allowInsecure": "Unsichere HTTP-Anfragen zulassen",
"stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App entfernen?", "one": "App entfernen?",
"other": "Apps entfernen?" "other": "Apps entfernen?"

View File

@@ -315,6 +315,7 @@
"wiki": "Helpo/Vikio", "wiki": "Helpo/Vikio",
"crowdsourcedConfigsLabel": "Komunumaj apo-agordoj (uzu kun singardo)", "crowdsourcedConfigsLabel": "Komunumaj apo-agordoj (uzu kun singardo)",
"allowInsecure": "Allow insecure HTTP requests", "allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Forigi la aplikaĵon?", "one": "Forigi la aplikaĵon?",
"other": "Forigi la aplikaĵojn?" "other": "Forigi la aplikaĵojn?"

View File

@@ -315,6 +315,7 @@
"wiki": "Help/Wiki", "wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"allowInsecure": "Allow insecure HTTP requests", "allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"

View File

@@ -315,6 +315,7 @@
"wiki": "Ayuda/Wiki", "wiki": "Ayuda/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
"allowInsecure": "Permitir peticiones HTTP inseguras", "allowInsecure": "Permitir peticiones HTTP inseguras",
"stayOneVersionBehind": "Mantenerse una versión por detrás de la última",
"removeAppQuestion": { "removeAppQuestion": {
"one": "¿Eliminar aplicación?", "one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?" "other": "¿Eliminar aplicaciones?"

View File

@@ -315,6 +315,7 @@
"wiki": "راهنما/ویکی", "wiki": "راهنما/ویکی",
"crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)", "crowdsourcedConfigsLabel": "تنظیمات برنامه Crowdsourced (با مسئولیت خود استفاده کنید)",
"allowInsecure": "درخواست های HTTP ناامن را مجاز کنید", "allowInsecure": "درخواست های HTTP ناامن را مجاز کنید",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "برنامه حذف شود؟", "one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟" "other": "برنامه ها حذف شوند؟"

View File

@@ -315,6 +315,7 @@
"wiki": "Aide/Wiki", "wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configurations d'applications par la communauté (à utiliser à vos risques et périls)", "crowdsourcedConfigsLabel": "Configurations d'applications par la communauté (à utiliser à vos risques et périls)",
"allowInsecure": "Autoriser les requêtes HTTP non sécurisées", "allowInsecure": "Autoriser les requêtes HTTP non sécurisées",
"stayOneVersionBehind": "Rester à une version de la dernière",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Supprimer l'application?", "one": "Supprimer l'application?",
"other": "Supprimer les applications?" "other": "Supprimer les applications?"

View File

@@ -315,6 +315,7 @@
"wiki": "Súgó/Wiki", "wiki": "Súgó/Wiki",
"crowdsourcedConfigsLabel": "Crowdsource-ből származó alkalmazások beállítása (saját felelősségére használja)", "crowdsourcedConfigsLabel": "Crowdsource-ből származó alkalmazások beállítása (saját felelősségére használja)",
"allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése", "allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése",
"stayOneVersionBehind": "Maradjon egy verzióval a legfrissebb mögött",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?", "one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?" "other": "Eltávolítja az alkalmazásokat?"

View File

@@ -204,7 +204,7 @@
"categoryDeleteWarning": "Semua aplikasi dalam kategori yang dihapus akan diatur sebagai tidak terkategori.", "categoryDeleteWarning": "Semua aplikasi dalam kategori yang dihapus akan diatur sebagai tidak terkategori.",
"addCategory": "Tambah kategori", "addCategory": "Tambah kategori",
"label": "Label", "label": "Label",
"language": "Language", "language": "Bahasa",
"copiedToClipboard": "Disalin ke papan klip", "copiedToClipboard": "Disalin ke papan klip",
"storagePermissionDenied": "Izin penyimpanan ditolak", "storagePermissionDenied": "Izin penyimpanan ditolak",
"selectedCategorizeWarning": "Ini akan mengganti pengaturan kategori yang ada untuk aplikasi terpilih.", "selectedCategorizeWarning": "Ini akan mengganti pengaturan kategori yang ada untuk aplikasi terpilih.",
@@ -315,6 +315,7 @@
"wiki": "Bantuan/Wiki", "wiki": "Bantuan/Wiki",
"crowdsourcedConfigsLabel": "Konfigurasi aplikasi Crowdsourced (risiko penggunaan ditanggung sendiri)", "crowdsourcedConfigsLabel": "Konfigurasi aplikasi Crowdsourced (risiko penggunaan ditanggung sendiri)",
"allowInsecure": "Izinkan permintaan HTTP yang tidak aman", "allowInsecure": "Izinkan permintaan HTTP yang tidak aman",
"stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Hapus aplikasi?", "one": "Hapus aplikasi?",
"other": "Hapus aplikasi?" "other": "Hapus aplikasi?"
@@ -375,4 +376,4 @@
"one": "{} APK", "one": "{} APK",
"other": "{} APK" "other": "{} APK"
} }
} }

View File

@@ -315,6 +315,7 @@
"wiki": "Aiuto/Wiki", "wiki": "Aiuto/Wiki",
"crowdsourcedConfigsLabel": "Configurazioni di app in crowdsourcing (uso a proprio rischio)", "crowdsourcedConfigsLabel": "Configurazioni di app in crowdsourcing (uso a proprio rischio)",
"allowInsecure": "Consentire le richieste HTTP non sicure", "allowInsecure": "Consentire le richieste HTTP non sicure",
"stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Rimuovere l'app?", "one": "Rimuovere l'app?",
"other": "Rimuovere le app?" "other": "Rimuovere le app?"

View File

@@ -315,6 +315,7 @@
"wiki": "ヘルプ/ウィキ", "wiki": "ヘルプ/ウィキ",
"crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)", "crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)",
"allowInsecure": "安全でないHTTPリクエストを許可する", "allowInsecure": "安全でないHTTPリクエストを許可する",
"stayOneVersionBehind": "最新バージョンから1つ遅れ",
"removeAppQuestion": { "removeAppQuestion": {
"one": "アプリを削除しますか?", "one": "アプリを削除しますか?",
"other": "アプリを削除しますか?" "other": "アプリを削除しますか?"

View File

@@ -315,6 +315,7 @@
"wiki": "Help/Wiki", "wiki": "Help/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App-configuraties (gebruik op eigen risico)", "crowdsourcedConfigsLabel": "Crowdsourced App-configuraties (gebruik op eigen risico)",
"allowInsecure": "Onveilige HTTP-verzoeken toestaan", "allowInsecure": "Onveilige HTTP-verzoeken toestaan",
"stayOneVersionBehind": "Blijf een versie achter op de nieuwste",
"removeAppQuestion": { "removeAppQuestion": {
"one": "App verwijderen?", "one": "App verwijderen?",
"other": "Apps verwijderen?" "other": "Apps verwijderen?"

View File

@@ -315,6 +315,7 @@
"wiki": "Pomoc/Wiki", "wiki": "Pomoc/Wiki",
"crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)", "crowdsourcedConfigsLabel": "Konfiguracje aplikacji pochodzące z crowdsourcingu (korzystanie na własne ryzyko)",
"allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP", "allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP",
"stayOneVersionBehind": "Pozostań jedną wersję za najnowszą",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Usunąć aplikację?", "one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?", "few": "Usunąć aplikacje?",

View File

@@ -315,6 +315,7 @@
"wiki": "Ajuda/Wiki", "wiki": "Ajuda/Wiki",
"crowdsourcedConfigsLabel": "Configurações de aplicações de crowdsourcing (utilização por sua conta e risco)", "crowdsourcedConfigsLabel": "Configurações de aplicações de crowdsourcing (utilização por sua conta e risco)",
"allowInsecure": "Permitir pedidos HTTP inseguros", "allowInsecure": "Permitir pedidos HTTP inseguros",
"stayOneVersionBehind": "Manter-se uma versão atrás da mais recente",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remover aplicativo?", "one": "Remover aplicativo?",
"other": "Remover aplicativos?" "other": "Remover aplicativos?"

View File

@@ -315,6 +315,7 @@
"wiki": "Помощь/Вики", "wiki": "Помощь/Вики",
"crowdsourcedConfigsLabel": "Конфигурации приложений на основе краудсорсинга (используйте на свой страх и риск)", "crowdsourcedConfigsLabel": "Конфигурации приложений на основе краудсорсинга (используйте на свой страх и риск)",
"allowInsecure": "Разрешить небезопасные HTTP-запросы", "allowInsecure": "Разрешить небезопасные HTTP-запросы",
"stayOneVersionBehind": "Не отставайте от последней версии",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@@ -315,6 +315,7 @@
"wiki": "Hjälp/Wiki", "wiki": "Hjälp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourcade appkonfigurationer (använd på egen risk)", "crowdsourcedConfigsLabel": "Crowdsourcade appkonfigurationer (använd på egen risk)",
"allowInsecure": "Tillåt osäkra HTTP-förfrågningar", "allowInsecure": "Tillåt osäkra HTTP-förfrågningar",
"stayOneVersionBehind": "Håll dig en version bakom den senaste",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Ta Bort App?", "one": "Ta Bort App?",
"other": "Ta Bort Appar?" "other": "Ta Bort Appar?"

View File

@@ -315,6 +315,7 @@
"wiki": "Yardım/Wiki", "wiki": "Yardım/Wiki",
"crowdsourcedConfigsLabel": "Kitle Kaynaklı Uygulama Yapılandırmaları (riski size ait olmak üzere kullanın)", "crowdsourcedConfigsLabel": "Kitle Kaynaklı Uygulama Yapılandırmaları (riski size ait olmak üzere kullanın)",
"allowInsecure": "Güvensiz HTTP isteklerine izin ver", "allowInsecure": "Güvensiz HTTP isteklerine izin ver",
"stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Uygulamayı Kaldır?", "one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?" "other": "Uygulamaları Kaldır?"

View File

@@ -315,6 +315,7 @@
"wiki": "Довідка/Вікі", "wiki": "Довідка/Вікі",
"crowdsourcedConfigsLabel": "Краудсорсингові конфігурації додатків (використовуйте на свій страх і ризик)", "crowdsourcedConfigsLabel": "Краудсорсингові конфігурації додатків (використовуйте на свій страх і ризик)",
"allowInsecure": "Дозволити незахищені HTTP-запити", "allowInsecure": "Дозволити незахищені HTTP-запити",
"stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Видалити застосунок?", "one": "Видалити застосунок?",
"other": "Видалити застосунки?" "other": "Видалити застосунки?"

View File

@@ -315,6 +315,7 @@
"wiki": "Trợ giúp/Wiki", "wiki": "Trợ giúp/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)", "crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use at your own risk)",
"allowInsecure": "Allow insecure HTTP requests", "allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Gỡ ứng dụng?", "one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?" "other": "Gỡ ứng dụng?"

View File

@@ -315,6 +315,7 @@
"wiki": "幫助/維基", "wiki": "幫助/維基",
"crowdsourcedConfigsLabel": "群眾外包的應用程式設定(使用風險自負)", "crowdsourcedConfigsLabel": "群眾外包的應用程式設定(使用風險自負)",
"allowInsecure": "Allow insecure HTTP requests", "allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"removeAppQuestion": { "removeAppQuestion": {
"one": "移除應用程式?", "one": "移除應用程式?",
"other": "移除應用程式?" "other": "移除應用程式?"

View File

@@ -315,6 +315,7 @@
"wiki": "帮助/Wiki", "wiki": "帮助/Wiki",
"crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)", "crowdsourcedConfigsLabel": "众包应用程序配置(使用风险自负)",
"allowInsecure": "允许不安全的 HTTP 请求", "allowInsecure": "允许不安全的 HTTP 请求",
"stayOneVersionBehind": "比最新版本晚一个版本",
"removeAppQuestion": { "removeAppQuestion": {
"one": "是否删除应用?", "one": "是否删除应用?",
"other": "是否删除应用?" "other": "是否删除应用?"

View File

@@ -2,6 +2,7 @@ import 'package:device_info_plus/device_info_plus.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
import 'package:obtainium/app_sources/html.dart'; import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
@@ -26,6 +27,16 @@ class APKPure extends AppSource {
allowSubDomains = true; allowSubDomains = true;
naiveStandardVersionDetection = true; naiveStandardVersionDetection = true;
showReleaseDateAsVersionToggle = true; showReleaseDateAsVersionToggle = true;
additionalSourceAppSpecificSettingFormItems = [
[
GeneratedFormSwitch('fallbackToOlderReleases',
label: tr('fallbackToOlderReleases'), defaultValue: true)
],
[
GeneratedFormSwitch('stayOneVersionBehind',
label: tr('stayOneVersionBehind'), defaultValue: false)
]
];
} }
@override @override
@@ -54,6 +65,97 @@ class APKPure extends AppSource {
return Uri.parse(standardUrl).pathSegments.last; return Uri.parse(standardUrl).pathSegments.last;
} }
getDetailsForVersionLink(
String standardUrl,
String appId,
String host,
List<String> supportedArchs,
String link,
Map<String, dynamic> additionalSettings) async {
var res = await sourceRequest(link, additionalSettings);
if (res.statusCode == 200) {
var html = parse(res.body);
var apksDiv =
html.querySelector('#version-list div div.show-more-content');
DateTime? topReleaseDate;
var apkUrls = apksDiv
?.querySelectorAll('div.group-title')
.map((e) {
String architectureString = e.text.trim();
if (architectureString.toLowerCase() == 'unlimited' ||
architectureString.toLowerCase() == 'universal') {
architectureString = '';
}
List<String> architectures = architectureString
.split(',')
.map((e) => e.trim())
.where((e) => e.isNotEmpty)
.toList();
// Only take the first APK for each architecture, ignore others for now, for simplicity
// Unclear why there can even be multiple APKs for the same version and arch
var apkInfo = e.nextElementSibling?.querySelector('div.info');
String? versionCode = RegExp('[0-9]+')
.firstMatch(apkInfo
?.querySelector('div.info-top span.code')
?.text ??
'')
?.group(0)
?.trim();
var types = apkInfo
?.querySelectorAll('div.info-top span.tag')
.map((e) => e.text.trim())
.map((t) => t == 'APKs' ? 'APK' : t) ??
[];
String type = types.isEmpty
? 'APK'
: types.length == 1
? types.first
: types.last;
String? dateString = apkInfo
?.querySelector('div.info-bottom span.time')
?.text
.trim();
DateTime? releaseDate = parseDateTimeMMMddCommayyyy(dateString);
if (additionalSettings['autoApkFilterByArch'] == true &&
architectures.isNotEmpty &&
architectures
.where((a) => supportedArchs.contains(a))
.isEmpty) {
return const MapEntry('', '');
}
topReleaseDate ??=
releaseDate; // Just use the release date of the first APK in the list as the release date for this version
return MapEntry(
'$appId-$versionCode-$architectureString.${type.toLowerCase()}',
'https://d.${hosts.contains(host) ? 'cdnpure.com' : host}/b/$type/$appId?versionCode=$versionCode');
})
.where((e) => e.key.isNotEmpty)
.toList() ??
[];
if (apkUrls.isEmpty) {
throw NoAPKError();
}
String version = Uri.parse(link).pathSegments.last;
String author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
String appName =
html.querySelector('h1.info-title')?.text.trim() ?? appId;
String? changeLog = html
.querySelector('div.module.change-log')
?.innerHtml
.trim()
.replaceAll("<br>", " \n");
return APKDetails(version, apkUrls, AppNames(author, appName),
releaseDate: topReleaseDate, changeLog: changeLog);
} else {
throw getObtainiumHttpError(res);
}
}
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, String standardUrl,
@@ -80,88 +182,17 @@ class APKPure extends AppSource {
for (var i = 0; i < versionLinks.length; i++) { for (var i = 0; i < versionLinks.length; i++) {
var link = versionLinks[i]; var link = versionLinks[i];
var res = await sourceRequest(link.key, additionalSettings); try {
if (res.statusCode == 200) { if (i == 0 && additionalSettings['stayOneVersionBehind'] == true) {
var html = parse(res.body); throw NoReleasesError();
var apksDiv = }
html.querySelector('#version-list div div.show-more-content'); return await getDetailsForVersionLink(standardUrl, appId, host,
DateTime? topReleaseDate; supportedArchs, link.key, additionalSettings);
var apkUrls = apksDiv } catch (e) {
?.querySelectorAll('div.group-title') if (additionalSettings['fallbackToOlderReleases'] != true ||
.map((e) { i == versionLinks.length - 1) {
String architectureString = e.text.trim(); rethrow;
if (architectureString.toLowerCase() == 'unlimited' ||
architectureString.toLowerCase() == 'universal') {
architectureString = '';
}
List<String> architectures = architectureString
.split(',')
.map((e) => e.trim())
.where((e) => e.isNotEmpty)
.toList();
// Only take the first APK for each architecture, ignore others for now, for simplicity
// Unclear why there can even be multiple APKs for the same version and arch
var apkInfo = e.nextElementSibling?.querySelector('div.info');
String? versionCode = RegExp('[0-9]+')
.firstMatch(apkInfo
?.querySelector('div.info-top span.code')
?.text ??
'')
?.group(0)
?.trim();
var types = apkInfo
?.querySelectorAll('div.info-top span.tag')
.map((e) => e.text.trim())
.map((t) => t == 'APKs' ? 'APK' : t) ??
[];
String type = types.isEmpty
? 'APK'
: types.length == 1
? types.first
: types.last;
String? dateString = apkInfo
?.querySelector('div.info-bottom span.time')
?.text
.trim();
DateTime? releaseDate =
parseDateTimeMMMddCommayyyy(dateString);
if (additionalSettings['autoApkFilterByArch'] == true &&
architectures.isNotEmpty &&
architectures
.where((a) => supportedArchs.contains(a))
.isEmpty) {
return const MapEntry('', '');
}
topReleaseDate ??=
releaseDate; // Just use the release date of the first APK in the list as the release date for this version
return MapEntry(
'$appId-$versionCode-$architectureString.${type.toLowerCase()}',
'https://d.${hosts.contains(host) ? 'cdnpure.com' : host}/b/$type/$appId?versionCode=$versionCode');
})
.where((e) => e.key.isNotEmpty)
.toList() ??
[];
if (apkUrls.isEmpty) {
continue;
} }
String version = Uri.parse(link.key).pathSegments.last;
String author = html
.querySelector('span.info-sdk')
?.text
.trim()
.substring(version.length + 4) ??
Uri.parse(standardUrl).pathSegments.reversed.last;
String appName =
html.querySelector('h1.info-title')?.text.trim() ?? appId;
String? changeLog = html
.querySelector('div.module.change-log')
?.innerHtml
.trim()
.replaceAll("<br>", " \n");
return APKDetails(version, apkUrls, AppNames(author, appName),
releaseDate: topReleaseDate, changeLog: changeLog);
} else {
throw getObtainiumHttpError(res);
} }
} }
throw NoAPKError(); throw NoAPKError();