mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-07-28 11:52:44 +02:00
Compare commits
4 Commits
v0.7.3-bet
...
v0.7.4-bet
Author | SHA1 | Date | |
---|---|---|---|
|
a4bc278e4c | ||
|
b04986622b | ||
|
2059e4fd44 | ||
|
618a1523cf |
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:obtainium/custom_errors.dart';
|
import 'package:obtainium/custom_errors.dart';
|
||||||
@@ -28,41 +30,24 @@ class FDroid extends AppSource {
|
|||||||
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
String? tryInferringAppId(String standardUrl) {
|
||||||
|
return Uri.parse(standardUrl).pathSegments.last;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
APKDetails getAPKUrlsFromFDroidPackagesAPIResponse(
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Response res, String apkUrlPrefix) {
|
||||||
String standardUrl, List<String> additionalData) async {
|
|
||||||
Response res = await get(Uri.parse(standardUrl));
|
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
var releases = parse(res.body).querySelectorAll('.package-version');
|
List<dynamic> releases = jsonDecode(res.body)['packages'] ?? [];
|
||||||
if (releases.isEmpty) {
|
if (releases.isEmpty) {
|
||||||
throw NoReleasesError();
|
throw NoReleasesError();
|
||||||
}
|
}
|
||||||
String? latestVersion = releases[0]
|
String? latestVersion = releases[0]['versionName'];
|
||||||
.querySelector('.package-version-header b')
|
|
||||||
?.innerHtml
|
|
||||||
.split(' ')
|
|
||||||
.sublist(1)
|
|
||||||
.join(' ');
|
|
||||||
if (latestVersion == null) {
|
if (latestVersion == null) {
|
||||||
throw NoVersionError();
|
throw NoVersionError();
|
||||||
}
|
}
|
||||||
List<String> apkUrls = releases
|
List<String> apkUrls = releases
|
||||||
.where((element) =>
|
.where((element) => element['versionName'] == latestVersion)
|
||||||
element
|
.map((e) => '${apkUrlPrefix}_${e['versionCode']}.apk')
|
||||||
.querySelector('.package-version-header b')
|
|
||||||
?.innerHtml
|
|
||||||
.split(' ')
|
|
||||||
.sublist(1)
|
|
||||||
.join(' ') ==
|
|
||||||
latestVersion)
|
|
||||||
.map((e) =>
|
|
||||||
e
|
|
||||||
.querySelector('.package-version-download a')
|
|
||||||
?.attributes['href'] ??
|
|
||||||
'')
|
|
||||||
.where((element) => element.isNotEmpty)
|
|
||||||
.toList();
|
.toList();
|
||||||
if (apkUrls.isEmpty) {
|
if (apkUrls.isEmpty) {
|
||||||
throw NoAPKError();
|
throw NoAPKError();
|
||||||
@@ -73,6 +58,15 @@ class FDroid extends AppSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
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
|
@override
|
||||||
AppNames getAppNames(String standardUrl) {
|
AppNames getAppNames(String standardUrl) {
|
||||||
return AppNames('F-Droid', Uri.parse(standardUrl).pathSegments.last);
|
return AppNames('F-Droid', Uri.parse(standardUrl).pathSegments.last);
|
||||||
|
@@ -105,9 +105,6 @@ class GitHub extends AppSource {
|
|||||||
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
||||||
'$standardUrl/releases';
|
'$standardUrl/releases';
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
@@ -23,9 +23,6 @@ class GitLab extends AppSource {
|
|||||||
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
||||||
'$standardUrl/-/releases';
|
'$standardUrl/-/releases';
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import 'package:html/parser.dart';
|
import 'package:html/parser.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:obtainium/app_sources/fdroid.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';
|
||||||
|
|
||||||
@@ -22,41 +23,18 @@ class IzzyOnDroid extends AppSource {
|
|||||||
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
String? tryInferringAppId(String standardUrl) {
|
||||||
|
return FDroid().tryInferringAppId(standardUrl);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
Response res = await get(Uri.parse(standardUrl));
|
String? appId = tryInferringAppId(standardUrl);
|
||||||
if (res.statusCode == 200) {
|
return FDroid().getAPKUrlsFromFDroidPackagesAPIResponse(
|
||||||
var parsedHtml = parse(res.body);
|
await get(
|
||||||
var multipleVersionApkUrls = parsedHtml
|
Uri.parse('https://apt.izzysoft.de/fdroid/api/v1/packages/$appId')),
|
||||||
.querySelectorAll('a')
|
'https://android.izzysoft.de/frepo/$appId');
|
||||||
.where((element) =>
|
|
||||||
element.attributes['href']?.toLowerCase().endsWith('.apk') ??
|
|
||||||
false)
|
|
||||||
.map((e) => 'https://$host${e.attributes['href'] ?? ''}')
|
|
||||||
.toList();
|
|
||||||
if (multipleVersionApkUrls.isEmpty) {
|
|
||||||
throw NoAPKError();
|
|
||||||
}
|
|
||||||
var version = parsedHtml
|
|
||||||
.querySelector('#keydata')
|
|
||||||
?.querySelectorAll('b')
|
|
||||||
.where(
|
|
||||||
(element) => element.innerHtml.toLowerCase().contains('version'))
|
|
||||||
.toList()[0]
|
|
||||||
.parentNode
|
|
||||||
?.parentNode
|
|
||||||
?.children[1]
|
|
||||||
.innerHtml;
|
|
||||||
if (version == null) {
|
|
||||||
throw NoVersionError();
|
|
||||||
}
|
|
||||||
return APKDetails(version, [multipleVersionApkUrls[0]]);
|
|
||||||
} else {
|
|
||||||
throw NoReleasesError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@@ -22,9 +22,6 @@ class Mullvad extends AppSource {
|
|||||||
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
String? changeLogPageFromStandardUrl(String standardUrl) =>
|
||||||
'https://github.com/mullvad/mullvadvpn-app/blob/master/CHANGELOG.md';
|
'https://github.com/mullvad/mullvadvpn-app/blob/master/CHANGELOG.md';
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
@@ -16,9 +16,6 @@ class Signal extends AppSource {
|
|||||||
@override
|
@override
|
||||||
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
@@ -21,9 +21,6 @@ class SourceForge extends AppSource {
|
|||||||
@override
|
@override
|
||||||
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
String? changeLogPageFromStandardUrl(String standardUrl) => null;
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<APKDetails> getLatestAPKDetails(
|
Future<APKDetails> getLatestAPKDetails(
|
||||||
String standardUrl, List<String> additionalData) async {
|
String standardUrl, List<String> additionalData) async {
|
||||||
|
@@ -16,7 +16,7 @@ import 'package:dynamic_color/dynamic_color.dart';
|
|||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
|
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
|
||||||
|
|
||||||
const String currentVersion = '0.7.3';
|
const String currentVersion = '0.7.4';
|
||||||
const String currentReleaseTag =
|
const String currentReleaseTag =
|
||||||
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
|
||||||
|
|
||||||
|
@@ -115,18 +115,23 @@ class _AddAppPageState extends State<AddAppPage> {
|
|||||||
additionalData);
|
additionalData);
|
||||||
await settingsProvider
|
await settingsProvider
|
||||||
.getInstallPermission();
|
.getInstallPermission();
|
||||||
// ignore: use_build_context_synchronously
|
// Only download the APK here if you need to for the package ID
|
||||||
var apkUrl = await appsProvider
|
if (sourceProvider
|
||||||
.confirmApkUrl(app, context);
|
.isTempId(app.id)) {
|
||||||
if (apkUrl == null) {
|
// ignore: use_build_context_synchronously
|
||||||
throw ObtainiumError('Cancelled');
|
var apkUrl = await appsProvider
|
||||||
|
.confirmApkUrl(app, context);
|
||||||
|
if (apkUrl == null) {
|
||||||
|
throw ObtainiumError(
|
||||||
|
'Cancelled');
|
||||||
|
}
|
||||||
|
app.preferredApkIndex =
|
||||||
|
app.apkUrls.indexOf(apkUrl);
|
||||||
|
var downloadedApk =
|
||||||
|
await appsProvider
|
||||||
|
.downloadApp(app);
|
||||||
|
app.id = downloadedApk.appId;
|
||||||
}
|
}
|
||||||
app.preferredApkIndex =
|
|
||||||
app.apkUrls.indexOf(apkUrl);
|
|
||||||
var downloadedApk =
|
|
||||||
await appsProvider
|
|
||||||
.downloadApp(app);
|
|
||||||
app.id = downloadedApk.appId;
|
|
||||||
if (appsProvider.apps
|
if (appsProvider.apps
|
||||||
.containsKey(app.id)) {
|
.containsKey(app.id)) {
|
||||||
throw ObtainiumError(
|
throw ObtainiumError(
|
||||||
|
@@ -155,14 +155,18 @@ class AppSource {
|
|||||||
throw NotImplementedError();
|
throw NotImplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> apkUrlPrefetchModifier(String apkUrl) {
|
Future<String> apkUrlPrefetchModifier(String apkUrl) async {
|
||||||
throw NotImplementedError();
|
return apkUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canSearch = false;
|
bool canSearch = false;
|
||||||
Future<Map<String, String>> search(String query) {
|
Future<Map<String, String>> search(String query) {
|
||||||
throw NotImplementedError();
|
throw NotImplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? tryInferringAppId(String standardUrl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ObtainiumError getObtainiumHttpError(Response res) {
|
ObtainiumError getObtainiumHttpError(Response res) {
|
||||||
@@ -240,7 +244,9 @@ class SourceProvider {
|
|||||||
APKDetails apk =
|
APKDetails apk =
|
||||||
await source.getLatestAPKDetails(standardUrl, additionalData);
|
await source.getLatestAPKDetails(standardUrl, additionalData);
|
||||||
return App(
|
return App(
|
||||||
id ?? generateTempID(names, source),
|
id ??
|
||||||
|
source.tryInferringAppId(standardUrl) ??
|
||||||
|
generateTempID(names, source),
|
||||||
standardUrl,
|
standardUrl,
|
||||||
names.author[0].toUpperCase() + names.author.substring(1),
|
names.author[0].toUpperCase() + names.author.substring(1),
|
||||||
name.trim().isNotEmpty
|
name.trim().isNotEmpty
|
||||||
|
@@ -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
|
# 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
|
# 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.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.7.3+59 # When changing this, update the tag in main() accordingly
|
version: 0.7.4+60 # When changing this, update the tag in main() accordingly
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.2 <3.0.0'
|
sdk: '>=2.18.2 <3.0.0'
|
||||||
|
Reference in New Issue
Block a user