From fe540f5e61bbcbd06903bae69964f452fd8c841f Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 18 Mar 2023 22:54:58 -0400 Subject: [PATCH 1/4] Added Neutron Code as a Source --- README.md | 1 + lib/app_sources/neutroncode.dart | 109 +++++++++++++++++++++++++++++ lib/providers/source_provider.dart | 2 + 3 files changed, 112 insertions(+) create mode 100644 lib/app_sources/neutroncode.dart diff --git a/README.md b/README.md index 2b4b120..ddd731b 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Currently supported App sources: - Third Party F-Droid Repos - Any URLs ending with `/fdroid/`, where `` can be anything - most often `repo` - [Steam](https://store.steampowered.com/mobile) +- [Neutron Code](https://neutroncode.com) - "HTML" (Fallback) - Any other URL that returns an HTML page with links to APK files (if multiple, the last file alphabetically is picked) diff --git a/lib/app_sources/neutroncode.dart b/lib/app_sources/neutroncode.dart new file mode 100644 index 0000000..0fdbc6c --- /dev/null +++ b/lib/app_sources/neutroncode.dart @@ -0,0 +1,109 @@ +import 'dart:convert'; +import 'package:html/parser.dart'; +import 'package:http/http.dart'; +import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/source_provider.dart'; + +class NeutronCode extends AppSource { + NeutronCode() { + host = 'neutroncode.com'; + } + + @override + String standardizeURL(String url) { + RegExp standardUrlRegEx = RegExp('^https?://$host/downloads/file/[^/]+'); + RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase()); + if (match == null) { + throw InvalidURLError(name); + } + return url.substring(0, match.end); + } + + @override + String? changeLogPageFromStandardUrl(String standardUrl) => standardUrl; + + String monthNameToNumberString(String s) { + switch (s.toLowerCase()) { + case 'january': + return '01'; + case 'february': + return '02'; + case 'march': + return '03'; + case 'april': + return '04'; + case 'may': + return '05'; + case 'june': + return '06'; + case 'july': + return '07'; + case 'august': + return '08'; + case 'september': + return '09'; + case 'october': + return '10'; + case 'november': + return '11'; + case 'december': + return '12'; + default: + throw ArgumentError('Invalid month name: $s'); + } + } + + customDateParse(String dateString) { + List parts = dateString.split(' '); + if (parts.length != 3) { + return null; + } + String result = ''; + for (var s in parts.reversed) { + try { + try { + int.parse(s); + result += '$s-'; + } catch (e) { + result += '${monthNameToNumberString(s)}-'; + } + } catch (e) { + return null; + } + } + return result.substring(0, result.length - 1); + } + + @override + Future getLatestAPKDetails( + String standardUrl, + Map additionalSettings, + ) async { + Response res = await get(Uri.parse(standardUrl)); + if (res.statusCode == 200) { + var http = parse(res.body); + var name = http.querySelector('.pd-title')?.innerHtml; + var filename = http.querySelector('.pd-filename .pd-float')?.innerHtml; + if (filename == null) { + throw NoReleasesError(); + } + var version = + http.querySelector('.pd-version-txt')?.nextElementSibling?.innerHtml; + if (version == null) { + throw NoVersionError(); + } + String? apkUrl = 'https://$host/download/$filename'; + var dateStringOriginal = + http.querySelector('.pd-date-txt')?.nextElementSibling?.innerHtml; + var dateString = dateStringOriginal != null + ? (customDateParse(dateStringOriginal)) + : null; + + return APKDetails(version, [apkUrl], + AppNames(runtimeType.toString(), name ?? standardUrl.split('/').last), + releaseDate: dateString != null ? DateTime.parse(dateString) : null); + } else { + throw getObtainiumHttpError(res); + } + } +} diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 8cead1e..5b51c7f 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -15,6 +15,7 @@ import 'package:obtainium/app_sources/gitlab.dart'; import 'package:obtainium/app_sources/izzyondroid.dart'; import 'package:obtainium/app_sources/html.dart'; import 'package:obtainium/app_sources/mullvad.dart'; +import 'package:obtainium/app_sources/neutroncode.dart'; import 'package:obtainium/app_sources/signal.dart'; import 'package:obtainium/app_sources/sourceforge.dart'; import 'package:obtainium/app_sources/steammobile.dart'; @@ -338,6 +339,7 @@ class SourceProvider { APKMirror(), FDroidRepo(), SteamMobile(), + NeutronCode(), HTML() // This should ALWAYS be the last option as they are tried in order ]; From 53d33976517126cafc2f7340d7bcd92f7cd27263 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 18 Mar 2023 22:58:37 -0400 Subject: [PATCH 2/4] Remove download notification when download fails --- lib/providers/apps_provider.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index b79b89e..dc4f9c0 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -145,6 +145,9 @@ class AppsProvider with ChangeNotifier { } Future downloadApp(App app, BuildContext? context) async { + NotificationsProvider? notificationsProvider = + context?.read(); + var notifId = DownloadNotification(app.name, 0).id; if (apps[app.id] != null) { apps[app.id]!.downloadProgress = 0; notifyListeners(); @@ -155,8 +158,6 @@ class AppsProvider with ChangeNotifier { String downloadUrl = await SourceProvider() .getSource(app.url) .apkUrlPrefetchModifier(app.apkUrls[app.preferredApkIndex]); - NotificationsProvider? notificationsProvider = - context?.read(); var notif = DownloadNotification(app.name, 100); notificationsProvider?.cancel(notif.id); int? prevProg; @@ -173,7 +174,6 @@ class AppsProvider with ChangeNotifier { } prevProg = prog; }); - notificationsProvider?.cancel(notif.id); // Delete older versions of the APK if any for (var file in downloadedFile.parent.listSync()) { var fn = file.path.split('/').last; @@ -201,6 +201,7 @@ class AppsProvider with ChangeNotifier { } return DownloadedApk(app.id, downloadedFile); } finally { + notificationsProvider?.cancel(notifId); if (apps[app.id] != null) { apps[app.id]!.downloadProgress = null; notifyListeners(); From e49a6e311b825c3cf4eda19a77fff8559d8fcfa8 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 18 Mar 2023 23:09:11 -0400 Subject: [PATCH 3/4] Added Telegram App as a Source --- lib/app_sources/neutroncode.dart | 1 - lib/app_sources/telegramapp.dart | 43 ++++++++++++++++++++++++++++++ lib/providers/source_provider.dart | 2 ++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 lib/app_sources/telegramapp.dart diff --git a/lib/app_sources/neutroncode.dart b/lib/app_sources/neutroncode.dart index 0fdbc6c..6baa0a1 100644 --- a/lib/app_sources/neutroncode.dart +++ b/lib/app_sources/neutroncode.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:html/parser.dart'; import 'package:http/http.dart'; import 'package:obtainium/custom_errors.dart'; diff --git a/lib/app_sources/telegramapp.dart b/lib/app_sources/telegramapp.dart new file mode 100644 index 0000000..6b249fd --- /dev/null +++ b/lib/app_sources/telegramapp.dart @@ -0,0 +1,43 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:html/parser.dart'; +import 'package:http/http.dart'; +import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/source_provider.dart'; + +class TelegramApp extends AppSource { + TelegramApp() { + host = 'telegram.org'; + name = 'Telegram ${tr('app')}'; + } + + @override + String standardizeURL(String url) { + return 'https://$host'; + } + + @override + String? changeLogPageFromStandardUrl(String standardUrl) => null; + + @override + Future getLatestAPKDetails( + String standardUrl, + Map additionalSettings, + ) async { + Response res = await get(Uri.parse('https://t.me/s/TAndroidAPK')); + if (res.statusCode == 200) { + var http = parse(res.body); + var messages = + http.querySelectorAll('.tgme_widget_message_text.js-message_text'); + var version = messages.isNotEmpty + ? messages.last.innerHtml.split('\n').first.trim().split(' ').first + : null; + if (version == null) { + throw NoVersionError(); + } + String? apkUrl = 'https://telegram.org/dl/android/apk'; + return APKDetails(version, [apkUrl], AppNames('Telegram', 'Telegram')); + } else { + throw getObtainiumHttpError(res); + } + } +} diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index 5b51c7f..f2b7afd 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -19,6 +19,7 @@ import 'package:obtainium/app_sources/neutroncode.dart'; import 'package:obtainium/app_sources/signal.dart'; import 'package:obtainium/app_sources/sourceforge.dart'; import 'package:obtainium/app_sources/steammobile.dart'; +import 'package:obtainium/app_sources/telegramapp.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/mass_app_sources/githubstars.dart'; @@ -339,6 +340,7 @@ class SourceProvider { APKMirror(), FDroidRepo(), SteamMobile(), + TelegramApp(), NeutronCode(), HTML() // This should ALWAYS be the last option as they are tried in order ]; From 26e6eef72e33fa026dfafbef64ea8e09aad8df96 Mon Sep 17 00:00:00 2001 From: Imran Remtulla Date: Sat, 18 Mar 2023 23:10:14 -0400 Subject: [PATCH 4/4] Increment version --- lib/main.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 3843c79..5e49a1a 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.11.9'; +const String currentVersion = '0.11.10'; const String currentReleaseTag = 'v$currentVersion-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES diff --git a/pubspec.yaml b/pubspec.yaml index 6962da3..f3871a6 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.11.9+130 # When changing this, update the tag in main() accordingly +version: 0.11.10+131 # When changing this, update the tag in main() accordingly environment: sdk: '>=2.18.2 <3.0.0'