mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-16 06:36:44 +02:00
Custom version extraction for HTML (#861)
This commit is contained in:
@ -251,6 +251,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Isento de atualizações em segundo plano (se ativadas)",
|
"exemptFromBackgroundUpdates": "Isento de atualizações em segundo plano (se ativadas)",
|
||||||
"bgUpdatesOnWiFiOnly": "Desative atualizações em segundo plano quando não estiver em WiFi",
|
"bgUpdatesOnWiFiOnly": "Desative atualizações em segundo plano quando não estiver em WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remover App?",
|
"one": "Remover App?",
|
||||||
"other": "Remover Apps?"
|
"other": "Remover Apps?"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Želite li ukloniti aplikaciju?",
|
"one": "Želite li ukloniti aplikaciju?",
|
||||||
"other": "Želite li ukloniti aplikacije?"
|
"other": "Želite li ukloniti aplikacije?"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Ausschluss von Hintergrundaktualisierungen (falls aktiviert)",
|
"exemptFromBackgroundUpdates": "Ausschluss von Hintergrundaktualisierungen (falls aktiviert)",
|
||||||
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
|
"bgUpdatesOnWiFiOnly": "Hintergrundaktualisierungen deaktivieren, wenn kein WLAN vorhanden ist",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "App entfernen?",
|
"one": "App entfernen?",
|
||||||
"other": "Apps entfernen?"
|
"other": "Apps entfernen?"
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Remove App?",
|
"one": "Remove App?",
|
||||||
"other": "Remove Apps?"
|
"other": "Remove Apps?"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "¿Eliminar Aplicación?",
|
"one": "¿Eliminar Aplicación?",
|
||||||
"other": "¿Eliminar Aplicaciones?"
|
"other": "¿Eliminar Aplicaciones?"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "برنامه حذف شود؟",
|
"one": "برنامه حذف شود؟",
|
||||||
"other": "برنامه ها حذف شوند؟"
|
"other": "برنامه ها حذف شوند؟"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Supprimer l'application ?",
|
"one": "Supprimer l'application ?",
|
||||||
"other": "Supprimer les applications ?"
|
"other": "Supprimer les applications ?"
|
||||||
|
@ -247,6 +247,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Mentes a háttérben történő frissítések alól (ha engedélyezett)",
|
"exemptFromBackgroundUpdates": "Mentes a háttérben történő frissítések alól (ha engedélyezett)",
|
||||||
"bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n",
|
"bgUpdatesOnWiFiOnly": "Tiltsa le a háttérben frissítéseket, ha nincs Wi-Fi-n",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Eltávolítja az alkalmazást?",
|
"one": "Eltávolítja az alkalmazást?",
|
||||||
"other": "Eltávolítja az alkalmazást?"
|
"other": "Eltávolítja az alkalmazást?"
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Rimuovere l'app?",
|
"one": "Rimuovere l'app?",
|
||||||
"other": "Rimuovere le app?"
|
"other": "Rimuovere le app?"
|
||||||
|
@ -249,6 +249,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "バックグラウンドアップデートを行わない (有効な場合)",
|
"exemptFromBackgroundUpdates": "バックグラウンドアップデートを行わない (有効な場合)",
|
||||||
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合,バックグラウンドアップデートを無効にする",
|
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合,バックグラウンドアップデートを無効にする",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "アプリを削除しますか?",
|
"one": "アプリを削除しますか?",
|
||||||
"other": "アプリを削除しますか?"
|
"other": "アプリを削除しますか?"
|
||||||
|
@ -254,6 +254,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Wyklucz z uaktualnień w tle (jeśli są włączone)",
|
"exemptFromBackgroundUpdates": "Wyklucz z uaktualnień w tle (jeśli są włączone)",
|
||||||
"bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi",
|
"bgUpdatesOnWiFiOnly": "Wyłącz aktualizacje w tle, gdy nie ma połączenia z Wi-Fi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Usunąć aplikację?",
|
"one": "Usunąć aplikację?",
|
||||||
"few": "Usunąć aplikacje?",
|
"few": "Usunąć aplikacje?",
|
||||||
|
@ -248,6 +248,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "Удалить приложение?",
|
"one": "Удалить приложение?",
|
||||||
"other": "Удалить приложения?"
|
"other": "Удалить приложения?"
|
||||||
|
@ -249,6 +249,8 @@
|
|||||||
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
"exemptFromBackgroundUpdates": "Exempt from background updates (if enabled)",
|
||||||
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
"bgUpdatesOnWiFiOnly": "Disable background updates when not on WiFi",
|
||||||
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
"autoSelectHighestVersionCode": "Auto-select highest versionCode APK",
|
||||||
|
"versionExtractionRegEx": "Version Extraction RegEx",
|
||||||
|
"matchGroupToUse": "Match Group to Use",
|
||||||
"removeAppQuestion": {
|
"removeAppQuestion": {
|
||||||
"one": "是否删除应用?",
|
"one": "是否删除应用?",
|
||||||
"other": "是否删除应用?"
|
"other": "是否删除应用?"
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:obtainium/components/generated_form.dart';
|
import 'package:obtainium/components/generated_form.dart';
|
||||||
@ -109,6 +110,26 @@ class HTML extends AppSource {
|
|||||||
hint: '([0-9]+\.)*[0-9]+/\$',
|
hint: '([0-9]+\.)*[0-9]+/\$',
|
||||||
required: false,
|
required: false,
|
||||||
additionalValidators: [(value) => regExValidator(value)])
|
additionalValidators: [(value) => regExValidator(value)])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
GeneratedFormTextField('versionExtractionRegEx',
|
||||||
|
label: tr('versionExtractionRegEx'),
|
||||||
|
required: false,
|
||||||
|
additionalValidators: [(value) => regExValidator(value)]),
|
||||||
|
GeneratedFormTextField('matchGroupToUse',
|
||||||
|
label: tr('matchGroupToUse'),
|
||||||
|
required: false,
|
||||||
|
hint: '1',
|
||||||
|
textInputType: const TextInputType.numberWithOptions(),
|
||||||
|
additionalValidators: [
|
||||||
|
(value) {
|
||||||
|
value ??= '1';
|
||||||
|
if (int.tryParse(value) == null) {
|
||||||
|
return tr('invalidInput');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
])
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
overrideVersionDetectionFormDefault('noVersionDetection',
|
overrideVersionDetectionFormDefault('noVersionDetection',
|
||||||
@ -183,10 +204,23 @@ class HTML extends AppSource {
|
|||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
var rel = links.last;
|
var rel = links.last;
|
||||||
var version = rel.hashCode.toString();
|
String? version = rel.hashCode.toString();
|
||||||
|
var versionExtractionRegEx =
|
||||||
|
additionalSettings['versionExtractionRegEx'] as String?;
|
||||||
|
if (versionExtractionRegEx?.isNotEmpty == true) {
|
||||||
|
var match = RegExp(versionExtractionRegEx!).allMatches(rel);
|
||||||
|
if (match.isEmpty) {
|
||||||
|
throw NoVersionError();
|
||||||
|
}
|
||||||
|
version = match.last
|
||||||
|
.group(int.parse(additionalSettings['matchGroupToUse'] as String));
|
||||||
|
if (version?.isEmpty == true) {
|
||||||
|
throw NoVersionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
List<String> apkUrls =
|
List<String> apkUrls =
|
||||||
[rel].map((e) => ensureAbsoluteUrl(e, uri)).toList();
|
[rel].map((e) => ensureAbsoluteUrl(e, uri)).toList();
|
||||||
return APKDetails(version, apkUrls.map((e) => MapEntry(e, e)).toList(),
|
return APKDetails(version!, apkUrls.map((e) => MapEntry(e, e)).toList(),
|
||||||
AppNames(uri.host, tr('app')));
|
AppNames(uri.host, tr('app')));
|
||||||
} else {
|
} else {
|
||||||
throw getObtainiumHttpError(res);
|
throw getObtainiumHttpError(res);
|
||||||
|
@ -25,6 +25,7 @@ class GeneratedFormTextField extends GeneratedFormItem {
|
|||||||
late int max;
|
late int max;
|
||||||
late String? hint;
|
late String? hint;
|
||||||
late bool password;
|
late bool password;
|
||||||
|
late TextInputType? textInputType;
|
||||||
|
|
||||||
GeneratedFormTextField(String key,
|
GeneratedFormTextField(String key,
|
||||||
{String label = 'Input',
|
{String label = 'Input',
|
||||||
@ -34,7 +35,8 @@ class GeneratedFormTextField extends GeneratedFormItem {
|
|||||||
this.required = true,
|
this.required = true,
|
||||||
this.max = 1,
|
this.max = 1,
|
||||||
this.hint,
|
this.hint,
|
||||||
this.password = false})
|
this.password = false,
|
||||||
|
this.textInputType})
|
||||||
: super(key,
|
: super(key,
|
||||||
label: label,
|
label: label,
|
||||||
belowWidgets: belowWidgets,
|
belowWidgets: belowWidgets,
|
||||||
@ -144,7 +146,8 @@ Color generateRandomLightColor() {
|
|||||||
// Map from HPLuv color space to RGB, use constant saturation=100, lightness=70
|
// Map from HPLuv color space to RGB, use constant saturation=100, lightness=70
|
||||||
final List<double> rgbValuesDbl = Hsluv.hpluvToRgb([hue, 100, 70]);
|
final List<double> rgbValuesDbl = Hsluv.hpluvToRgb([hue, 100, 70]);
|
||||||
// Map RBG values from 0-1 to 0-255:
|
// Map RBG values from 0-1 to 0-255:
|
||||||
final List<int> rgbValues = rgbValuesDbl.map((rgb) => (rgb * 255).toInt()).toList();
|
final List<int> rgbValues =
|
||||||
|
rgbValuesDbl.map((rgb) => (rgb * 255).toInt()).toList();
|
||||||
return Color.fromARGB(255, rgbValues[0], rgbValues[1], rgbValues[2]);
|
return Color.fromARGB(255, rgbValues[0], rgbValues[1], rgbValues[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +193,7 @@ class _GeneratedFormState extends State<GeneratedForm> {
|
|||||||
if (formItem is GeneratedFormTextField) {
|
if (formItem is GeneratedFormTextField) {
|
||||||
final formFieldKey = GlobalKey<FormFieldState>();
|
final formFieldKey = GlobalKey<FormFieldState>();
|
||||||
return TextFormField(
|
return TextFormField(
|
||||||
|
keyboardType: formItem.textInputType,
|
||||||
obscureText: formItem.password,
|
obscureText: formItem.password,
|
||||||
autocorrect: !formItem.password,
|
autocorrect: !formItem.password,
|
||||||
enableSuggestions: !formItem.password,
|
enableSuggestions: !formItem.password,
|
||||||
@ -370,34 +374,37 @@ class _GeneratedFormState extends State<GeneratedForm> {
|
|||||||
}) ??
|
}) ??
|
||||||
[const SizedBox.shrink()],
|
[const SizedBox.shrink()],
|
||||||
(values[widget.items[r][e].key]
|
(values[widget.items[r][e].key]
|
||||||
as Map<String, MapEntry<int, bool>>?)
|
as Map<String, MapEntry<int, bool>>?)
|
||||||
?.values
|
?.values
|
||||||
.where((e) => e.value)
|
.where((e) => e.value)
|
||||||
.length == 1
|
.length ==
|
||||||
|
1
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
var temp = values[widget.items[r][e].key]
|
var temp = values[widget.items[r][e].key]
|
||||||
as Map<String, MapEntry<int, bool>>;
|
as Map<String, MapEntry<int, bool>>;
|
||||||
// get selected category str where bool is true
|
// get selected category str where bool is true
|
||||||
final oldEntry = temp.entries.firstWhere((entry) => entry.value.value);
|
final oldEntry = temp.entries
|
||||||
// generate new color, ensure it is not the same
|
.firstWhere((entry) => entry.value.value);
|
||||||
int newColor = oldEntry.value.key;
|
// generate new color, ensure it is not the same
|
||||||
while(oldEntry.value.key == newColor) {
|
int newColor = oldEntry.value.key;
|
||||||
newColor = generateRandomLightColor().value;
|
while (oldEntry.value.key == newColor) {
|
||||||
}
|
newColor = generateRandomLightColor().value;
|
||||||
// Update entry with new color, remain selected
|
}
|
||||||
temp.update(oldEntry.key, (old) => MapEntry(newColor, old.value));
|
// Update entry with new color, remain selected
|
||||||
values[widget.items[r][e].key] = temp;
|
temp.update(oldEntry.key,
|
||||||
someValueChanged();
|
(old) => MapEntry(newColor, old.value));
|
||||||
});
|
values[widget.items[r][e].key] = temp;
|
||||||
},
|
someValueChanged();
|
||||||
icon: const Icon(Icons.format_color_fill_rounded),
|
});
|
||||||
visualDensity: VisualDensity.compact,
|
},
|
||||||
tooltip: tr('colour'),
|
icon: const Icon(Icons.format_color_fill_rounded),
|
||||||
))
|
visualDensity: VisualDensity.compact,
|
||||||
|
tooltip: tr('colour'),
|
||||||
|
))
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
(values[widget.items[r][e].key]
|
(values[widget.items[r][e].key]
|
||||||
as Map<String, MapEntry<int, bool>>?)
|
as Map<String, MapEntry<int, bool>>?)
|
||||||
|
Reference in New Issue
Block a user