mirror of
				https://github.com/ImranR98/Obtainium.git
				synced 2025-10-31 05:23:28 +01:00 
			
		
		
		
	Compare commits
	
		
			10 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c0968e8991 | ||
|  | 243b1eb2ac | ||
|  | c6c61d1c83 | ||
|  | f207967411 | ||
|  | 29bb5cc8cd | ||
|  | dbbc2ff19c | ||
|  | c012b016f9 | ||
|  | 22815b8209 | ||
|  | 619d4f1a51 | ||
|  | 50e8929763 | 
| @@ -31,11 +31,7 @@ Currently supported App sources: | ||||
|   - [Tencent App Store](https://sj.qq.com/) | ||||
|   - Jenkins Jobs | ||||
|   - [APKMirror](https://apkmirror.com/) (Track-Only) | ||||
| - Open Source - App-Specific: | ||||
|   - [VLC](https://videolan.org/) | ||||
| - Other - App-Specific: | ||||
|   - [WhatsApp](https://whatsapp.com) | ||||
|   - [Telegram App](https://telegram.org) | ||||
|   - [Neutron Code](https://neutroncode.com) | ||||
| - Direct APK Link | ||||
| - "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Allow insecure HTTP requests", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Želite li ukloniti aplikaciju?", | ||||
|         "other": "Želite li ukloniti aplikacije?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Konfigurace aplikací s využitím crowdsourcingu", | ||||
|     "allowInsecure": "Povolení nezabezpečených požadavků HTTP", | ||||
|     "stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější", | ||||
|     "refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Odstranit Apku?", | ||||
|         "other": "Odstranit Apky?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourcede app-konfigurationer", | ||||
|     "allowInsecure": "Tillad usikre HTTP-anmodninger", | ||||
|     "stayOneVersionBehind": "Forbliv én version bagud den seneste", | ||||
|     "refreshBeforeDownload": "Opdater app-detaljer før download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Fjern app?", | ||||
|         "other": "Fjern apps?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App-Konfigurationen", | ||||
|     "allowInsecure": "Unsichere HTTP-Anfragen zulassen", | ||||
|     "stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben", | ||||
|     "refreshBeforeDownload": "App-Details vor dem Download aktualisieren", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "App entfernen?", | ||||
|         "other": "Apps entfernen?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Allow insecure HTTP requests", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Forigi la aplikaĵon?", | ||||
|         "other": "Forigi la aplikaĵojn?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Allow insecure HTTP requests", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Remove App?", | ||||
|         "other": "Remove Apps?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Configuración de aplicaciones por crowdsourcing", | ||||
|     "allowInsecure": "Permitir peticiones HTTP inseguras", | ||||
|     "stayOneVersionBehind": "Mantenerse una versión por detrás de la última", | ||||
|     "refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "¿Eliminar aplicación?", | ||||
|         "other": "¿Eliminar aplicaciones?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "درخواست های HTTP ناامن را مجاز کنید", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "برنامه حذف شود؟", | ||||
|         "other": "برنامه ها حذف شوند؟" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Applis communautaires", | ||||
|     "allowInsecure": "Autoriser les requêtes HTTP non sécurisées", | ||||
|     "stayOneVersionBehind": "Rester à une version de la dernière", | ||||
|     "refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Supprimer l'application ?", | ||||
|         "other": "Supprimer les applications ?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése", | ||||
|     "stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött", | ||||
|     "refreshBeforeDownload": "Az alkalmazás adatainak frissítése letöltés előtt", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Eltávolítja az alkalmazást?", | ||||
|         "other": "Eltávolítja az alkalmazásokat?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Konfigurasi Aplikasi Crowdsourced", | ||||
|     "allowInsecure": "Izinkan permintaan HTTP yang tidak aman", | ||||
|     "stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru", | ||||
|     "refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Hapus aplikasi?", | ||||
|         "other": "Hapus aplikasi?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Configurazioni di app in crowdsourcing", | ||||
|     "allowInsecure": "Consentire le richieste HTTP non sicure", | ||||
|     "stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente", | ||||
|     "refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Rimuovere l'app?", | ||||
|         "other": "Rimuovere le app?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "クラウドソーシングによるアプリの設定", | ||||
|     "allowInsecure": "安全でないHTTPリクエストを許可する", | ||||
|     "stayOneVersionBehind": "最新のバージョンから1つ前のものを使用する", | ||||
|     "refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "アプリを削除しますか?", | ||||
|         "other": "アプリを削除しますか?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "App-configuraties door menigte", | ||||
|     "allowInsecure": "Onveilige HTTP-verzoeken toestaan", | ||||
|     "stayOneVersionBehind": "Blijf een versie achter op de nieuwste", | ||||
|     "refreshBeforeDownload": "Vernieuw app details voor download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "App verwijderen?", | ||||
|         "other": "Apps verwijderen?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Baza konfiguracji", | ||||
|     "allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP", | ||||
|     "stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą", | ||||
|     "refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Usunąć aplikację?", | ||||
|         "few": "Usunąć aplikacje?", | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Configurações de aplicações com base em crowdsourcing", | ||||
|     "allowInsecure": "Permitir pedidos HTTP inseguros", | ||||
|     "stayOneVersionBehind": "Manter-se uma versão atrás da mais recente", | ||||
|     "refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Remover aplicativo?", | ||||
|         "other": "Remover aplicativos?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Конфиги приложений с помощью краудсорсинга", | ||||
|     "allowInsecure": "Разрешить небезопасные HTTP-запросы", | ||||
|     "stayOneVersionBehind": "Не отставайте от последней версии", | ||||
|     "refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Удалить приложение?", | ||||
|         "other": "Удалить приложения?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Appkonfigurationer med hjälp av crowdsourcing", | ||||
|     "allowInsecure": "Tillåt osäkra HTTP-förfrågningar", | ||||
|     "stayOneVersionBehind": "Håll dig en version bakom den senaste", | ||||
|     "refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Ta Bort App?", | ||||
|         "other": "Ta Bort Appar?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Kitle Kaynaklı Uygulama Yapılandırmaları", | ||||
|     "allowInsecure": "Güvensiz HTTP isteklerine izin ver", | ||||
|     "stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın", | ||||
|     "refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Uygulamayı Kaldır?", | ||||
|         "other": "Uygulamaları Kaldır?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Налаштування краудсорсингових додатків", | ||||
|     "allowInsecure": "Дозволити незахищені HTTP-запити", | ||||
|     "stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою", | ||||
|     "refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Видалити застосунок?", | ||||
|         "other": "Видалити застосунки?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Allow insecure HTTP requests", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "Gỡ ứng dụng?", | ||||
|         "other": "Gỡ ứng dụng?" | ||||
|   | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "Crowdsourced App Configs", | ||||
|     "allowInsecure": "Allow insecure HTTP requests", | ||||
|     "stayOneVersionBehind": "Stay one version behind latest", | ||||
|     "refreshBeforeDownload": "Refresh app details before download", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "移除應用程式?", | ||||
|         "other": "移除應用程式?" | ||||
|   | ||||
| @@ -186,10 +186,10 @@ | ||||
|     "additionalOptions": "附加选项", | ||||
|     "disableVersionDetection": "禁用版本检测", | ||||
|     "noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。", | ||||
|     "downloadingX": "正在下载“{}”", | ||||
|     "downloadingX": "正在下载 {}", | ||||
|     "downloadX": "下载 {}", | ||||
|     "downloadedX": "下载 {}", | ||||
|     "releaseAsset": "发行版附件", | ||||
|     "downloadedX": "已下载 {}", | ||||
|     "releaseAsset": "发行文件", | ||||
|     "downloadNotifDescription": "提示应用的下载进度", | ||||
|     "noAPKFound": "未找到 APK 文件", | ||||
|     "noVersionDetection": "禁用版本检测", | ||||
| @@ -317,6 +317,7 @@ | ||||
|     "crowdsourcedConfigsShort": "众包应用程序配置", | ||||
|     "allowInsecure": "允许不安全的 HTTP 请求", | ||||
|     "stayOneVersionBehind": "比最新版本晚一个版本", | ||||
|     "refreshBeforeDownload": "下载前刷新应用程序详细信息", | ||||
|     "removeAppQuestion": { | ||||
|         "one": "是否删除应用?", | ||||
|         "other": "是否删除应用?" | ||||
|   | ||||
| @@ -7,6 +7,9 @@ import 'package:obtainium/providers/apps_provider.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) { | ||||
|   if (ambiguousUrl.startsWith('//')) { | ||||
|     ambiguousUrl = '${referenceAbsoluteUrl.scheme}:$ambiguousUrl'; | ||||
|   } | ||||
|   try { | ||||
|     Uri.parse(ambiguousUrl).origin; | ||||
|     return ambiguousUrl; | ||||
| @@ -353,7 +356,12 @@ class HTML extends AppSource { | ||||
|                     forAPKDownload: true), | ||||
|                 allowInsecure: additionalSettings['allowInsecure'] == true)) | ||||
|             .toString(); | ||||
|     return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(), | ||||
|     return APKDetails( | ||||
|         version, | ||||
|         [rel] | ||||
|             .map((e) => | ||||
|                 MapEntry('${e.hashCode}-${Uri.parse(e).pathSegments.last}', e)) | ||||
|             .toList(), | ||||
|         AppNames(uri.host, tr('app'))); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,110 +0,0 @@ | ||||
| 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 VLC extends AppSource { | ||||
|   VLC() { | ||||
|     hosts = ['videolan.org']; | ||||
|   } | ||||
|   get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/'; | ||||
|  | ||||
|   @override | ||||
|   Future<Map<String, String>?> getRequestHeaders( | ||||
|       Map<String, dynamic> additionalSettings, | ||||
|       {bool forAPKDownload = false}) async { | ||||
|     return { | ||||
|       "User-Agent": | ||||
|           "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36" | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) { | ||||
|     return 'https://${hosts[0]}'; | ||||
|   } | ||||
|  | ||||
|   Future<String?> getLatestVersion( | ||||
|       String standardUrl, Map<String, dynamic> additionalSettings) async { | ||||
|     Response res = await sourceRequest(dwUrlBase, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwLinks = parse(res.body) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => element.attributes['href'] != 'last/') | ||||
|           .map((e) => e.attributes['href']?.split('/')[0]) | ||||
|           .toList(); | ||||
|       String? version = dwLinks.isNotEmpty ? dwLinks.last : null; | ||||
|       if (version == null) { | ||||
|         throw NoVersionError(); | ||||
|       } | ||||
|       return version; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<APKDetails> getLatestAPKDetails( | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     Response res = await get( | ||||
|         Uri.parse('https://www.videolan.org/vlc/download-android.html')); | ||||
|     if (res.statusCode == 200) { | ||||
|       var dwUrlBase = 'get.videolan.org/vlc-android'; | ||||
|       var dwLinks = parse(res.body) | ||||
|           .querySelectorAll('a') | ||||
|           .where((element) => | ||||
|               element.attributes['href']?.contains(dwUrlBase) ?? false) | ||||
|           .toList(); | ||||
|       String? version = dwLinks.isNotEmpty | ||||
|           ? dwLinks.first.attributes['href'] | ||||
|               ?.split('/') | ||||
|               .where((s) => s.isNotEmpty) | ||||
|               .last | ||||
|           : null; | ||||
|       if (version == null) { | ||||
|         throw NoVersionError(); | ||||
|       } | ||||
|       String? targetUrl = 'https://$dwUrlBase/$version/'; | ||||
|       var apkUrls = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'] | ||||
|           .map((e) => '${targetUrl}VLC-Android-$version-$e.apk') | ||||
|           .toList(); | ||||
|       return APKDetails( | ||||
|           version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC')); | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl, | ||||
|       Map<String, dynamic> additionalSettings) async { | ||||
|     Response res = await sourceRequest(apkUrl, additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       String? apkUrl = | ||||
|           parse(res.body).querySelector('#alt_link')?.attributes['href']; | ||||
|       if (apkUrl == null) { | ||||
|         throw NoAPKError(); | ||||
|       } | ||||
|       return apkUrl; | ||||
|     } else if (res.statusCode == 500 && | ||||
|         res.body.toLowerCase().indexOf('mirror') > 0) { | ||||
|       var html = parse(res.body); | ||||
|       var err = ''; | ||||
|       html.body?.nodes.forEach((element) { | ||||
|         if (element.text != null) { | ||||
|           err += '${element.text}\n'; | ||||
|         } | ||||
|       }); | ||||
|       err = err.trim(); | ||||
|       if (err.isEmpty) { | ||||
|         err = tr('err'); | ||||
|       } | ||||
|       throw ObtainiumError(err); | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -1,55 +0,0 @@ | ||||
| import 'package:html/parser.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| class WhatsApp extends AppSource { | ||||
|   WhatsApp() { | ||||
|     hosts = ['whatsapp.com']; | ||||
|     versionDetectionDisallowed = true; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) { | ||||
|     return 'https://${hosts[0]}'; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl, | ||||
|       Map<String, dynamic> additionalSettings) async { | ||||
|     Response res = | ||||
|         await sourceRequest('$standardUrl/android', additionalSettings); | ||||
|     if (res.statusCode == 200) { | ||||
|       var targetLinks = parse(res.body) | ||||
|           .querySelectorAll('a') | ||||
|           .map((e) => e.attributes['href'] ?? '') | ||||
|           .where((e) => e.isNotEmpty) | ||||
|           .where((e) => e.contains('WhatsApp.apk')) | ||||
|           .toList(); | ||||
|       if (targetLinks.isEmpty) { | ||||
|         throw NoAPKError(); | ||||
|       } | ||||
|       return targetLinks[0]; | ||||
|     } else { | ||||
|       throw getObtainiumHttpError(res); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<APKDetails> getLatestAPKDetails( | ||||
|     String standardUrl, | ||||
|     Map<String, dynamic> additionalSettings, | ||||
|   ) async { | ||||
|     // This is a CDN link that is consistent per version | ||||
|     // But it has query params that change constantly | ||||
|     Uri apkUri = Uri.parse(await apkUrlPrefetchModifier( | ||||
|         standardUrl, standardUrl, additionalSettings)); | ||||
|     var unusableApkUrl = '${apkUri.origin}/${apkUri.path}'; | ||||
|     // So we use the param-less URL is a pseudo-version to add the app and check for updates | ||||
|     // See #357 for why we can't scrape the version number directly | ||||
|     // But we re-fetch the URL again with its latest query params at the actual download time | ||||
|     String version = unusableApkUrl.hashCode.toString(); | ||||
|     return APKDetails(version, getApkUrlsFromUrls([unusableApkUrl]), | ||||
|         AppNames('Meta', 'WhatsApp')); | ||||
|   } | ||||
| } | ||||
| @@ -888,6 +888,11 @@ class AppsProvider with ChangeNotifier { | ||||
|       } | ||||
|       MapEntry<String, String>? apkUrl; | ||||
|       var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true; | ||||
|       var refreshBeforeDownload = | ||||
|           apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true; | ||||
|       if (refreshBeforeDownload) { | ||||
|         await checkUpdate(apps[id]!.app.id); | ||||
|       } | ||||
|       if (!trackOnly) { | ||||
|         // ignore: use_build_context_synchronously | ||||
|         apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false); | ||||
| @@ -1074,6 +1079,11 @@ class AppsProvider with ChangeNotifier { | ||||
|         throw ObtainiumError(tr('appNotFound')); | ||||
|       } | ||||
|       MapEntry<String, String>? fileUrl; | ||||
|       var refreshBeforeDownload = | ||||
|           apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true; | ||||
|       if (refreshBeforeDownload) { | ||||
|         await checkUpdate(apps[id]!.app.id); | ||||
|       } | ||||
|       if (apps[id]!.app.apkUrls.isNotEmpty || | ||||
|           apps[id]!.app.otherAssetUrls.isNotEmpty) { | ||||
|         // ignore: use_build_context_synchronously | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter_local_notifications/flutter_local_notifications.dart'; | ||||
| import 'package:obtainium/providers/settings_provider.dart'; | ||||
| import 'package:obtainium/providers/source_provider.dart'; | ||||
|  | ||||
| class ObtainiumNotification { | ||||
| @@ -44,23 +45,19 @@ class SilentUpdateNotification extends ObtainiumNotification { | ||||
|   SilentUpdateNotification(List<App> updates, bool succeeded, {int? id}) | ||||
|       : super( | ||||
|             id ?? 3, | ||||
|             succeeded | ||||
|                 ? tr('appsUpdated') | ||||
|                 : tr('appsNotUpdated'), | ||||
|             succeeded ? tr('appsUpdated') : tr('appsNotUpdated'), | ||||
|             '', | ||||
|             'APPS_UPDATED', | ||||
|             tr('appsUpdatedNotifChannel'), | ||||
|             tr('appsUpdatedNotifDescription'), | ||||
|             Importance.defaultImportance) { | ||||
|     message = updates.length == 1 | ||||
|         ? tr(succeeded | ||||
|             ? 'xWasUpdatedToY' | ||||
|             : 'xWasNotUpdatedToY', | ||||
|         ? tr(succeeded ? 'xWasUpdatedToY' : 'xWasNotUpdatedToY', | ||||
|             args: [updates[0].finalName, updates[0].latestVersion]) | ||||
|         : plural(succeeded | ||||
|             ? 'xAndNMoreUpdatesInstalled' | ||||
|             : "xAndNMoreUpdatesFailed", | ||||
|                 updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]); | ||||
|         : plural( | ||||
|             succeeded ? 'xAndNMoreUpdatesInstalled' : "xAndNMoreUpdatesFailed", | ||||
|             updates.length - 1, | ||||
|             args: [updates[0].finalName, (updates.length - 1).toString()]); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -214,7 +211,7 @@ class NotificationsProvider { | ||||
|                 channelDescription: channelDescription, | ||||
|                 importance: importance, | ||||
|                 priority: importanceToPriority[importance]!, | ||||
|                 groupKey: 'dev.imranr.obtainium.$channelCode', | ||||
|                 groupKey: '$obtainiumId.$channelCode', | ||||
|                 progress: progPercent ?? 0, | ||||
|                 maxProgress: 100, | ||||
|                 showProgress: progPercent != null, | ||||
|   | ||||
| @@ -25,11 +25,8 @@ import 'package:obtainium/app_sources/jenkins.dart'; | ||||
| import 'package:obtainium/app_sources/neutroncode.dart'; | ||||
| import 'package:obtainium/app_sources/sourceforge.dart'; | ||||
| import 'package:obtainium/app_sources/sourcehut.dart'; | ||||
| import 'package:obtainium/app_sources/telegramapp.dart'; | ||||
| import 'package:obtainium/app_sources/tencent.dart'; | ||||
| import 'package:obtainium/app_sources/uptodown.dart'; | ||||
| import 'package:obtainium/app_sources/vlc.dart'; | ||||
| import 'package:obtainium/app_sources/whatsapp.dart'; | ||||
| import 'package:obtainium/components/generated_form.dart'; | ||||
| import 'package:obtainium/custom_errors.dart'; | ||||
| import 'package:obtainium/mass_app_sources/githubstars.dart'; | ||||
| @@ -214,6 +211,72 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) { | ||||
|           '\\d+.\\d+.\\d+'; | ||||
|       additionalSettings = replacementAdditionalSettings; | ||||
|     } | ||||
|     // WhatsApp from before it was removed should be converted to HTML (#1943) | ||||
|     if (json['url'] == 'https://whatsapp.com' && | ||||
|         json['id'] == 'com.whatsapp' && | ||||
|         json['author'] == 'Meta' && | ||||
|         json['name'] == 'WhatsApp' && | ||||
|         json['overrideSource'] == null && | ||||
|         additionalSettings['trackOnly'] == false && | ||||
|         additionalSettings['versionExtractionRegEx'] == '' && | ||||
|         json['lastUpdateCheck'] != null) { | ||||
|       json['url'] = 'https://whatsapp.com/android'; | ||||
|       var replacementAdditionalSettings = getDefaultValuesFromFormItems( | ||||
|           HTML().combinedAppSpecificSettingFormItems); | ||||
|       replacementAdditionalSettings['refreshBeforeDownload'] = true; | ||||
|       additionalSettings = replacementAdditionalSettings; | ||||
|     } | ||||
|     // VLC from before it was removed should be converted to HTML (#1943) | ||||
|     if (json['url'] == 'https://videolan.org' && | ||||
|         json['id'] == 'org.videolan.vlc' && | ||||
|         json['author'] == 'VideoLAN' && | ||||
|         json['name'] == 'VLC' && | ||||
|         json['overrideSource'] == null && | ||||
|         additionalSettings['trackOnly'] == false && | ||||
|         additionalSettings['versionExtractionRegEx'] == '' && | ||||
|         json['lastUpdateCheck'] != null) { | ||||
|       json['url'] = 'https://www.videolan.org/vlc/download-android.html'; | ||||
|       var replacementAdditionalSettings = getDefaultValuesFromFormItems( | ||||
|           HTML().combinedAppSpecificSettingFormItems); | ||||
|       replacementAdditionalSettings['refreshBeforeDownload'] = true; | ||||
|       replacementAdditionalSettings['intermediateLink'] = | ||||
|           <Map<String, dynamic>>[ | ||||
|         { | ||||
|           'customLinkFilterRegex': 'APK', | ||||
|           'filterByLinkText': true, | ||||
|           'skipSort': false, | ||||
|           'reverseSort': false, | ||||
|           'sortByLastLinkSegment': false | ||||
|         }, | ||||
|         { | ||||
|           'customLinkFilterRegex': 'arm64-v8a\\.apk\$', | ||||
|           'filterByLinkText': false, | ||||
|           'skipSort': false, | ||||
|           'reverseSort': false, | ||||
|           'sortByLastLinkSegment': false | ||||
|         } | ||||
|       ]; | ||||
|       replacementAdditionalSettings['versionExtractionRegEx'] = | ||||
|           '/vlc-android/([^/]+)/'; | ||||
|       replacementAdditionalSettings['matchGroupToUse'] = "1"; | ||||
|       additionalSettings = replacementAdditionalSettings; | ||||
|     } | ||||
|     // Telegram App from before it was removed should be converted to Direct APK Link (#1943) | ||||
|     if (json['url'] == 'https://telegram.org' && | ||||
|         json['id'] == 'org.telegram.messenger.web' && | ||||
|         json['author'] == 'Telegram' && | ||||
|         json['name'] == 'Telegram' && | ||||
|         json['overrideSource'] == null && | ||||
|         additionalSettings['trackOnly'] == false && | ||||
|         additionalSettings['versionExtractionRegEx'] == '' && | ||||
|         json['lastUpdateCheck'] != null) { | ||||
|       json['url'] = 'https://telegram.org/dl/android/apk'; | ||||
|       var newSource = DirectAPKLink(); | ||||
|       json['overrideSource'] = newSource.runtimeType.toString(); | ||||
|       var replacementAdditionalSettings = getDefaultValuesFromFormItems( | ||||
|           newSource.combinedAppSpecificSettingFormItems); | ||||
|       additionalSettings = replacementAdditionalSettings; | ||||
|     } | ||||
|   } | ||||
|   json['additionalSettings'] = jsonEncode(additionalSettings); | ||||
|   // F-Droid no longer needs cloudflare exception since override can be used - migrate apps appropriately | ||||
| @@ -240,7 +303,7 @@ class App { | ||||
|   late String name; | ||||
|   String? installedVersion; | ||||
|   late String latestVersion; | ||||
|   List<MapEntry<String, String>> apkUrls = []; | ||||
|   List<MapEntry<String, String>> apkUrls = []; // Key is name, value is URL | ||||
|   List<MapEntry<String, String>> otherAssetUrls = []; | ||||
|   late int preferredApkIndex; | ||||
|   late Map<String, dynamic> additionalSettings; | ||||
| @@ -586,6 +649,10 @@ abstract class AppSource { | ||||
|           label: tr('skipUpdateNotifications')) | ||||
|     ], | ||||
|     [GeneratedFormTextField('about', label: tr('about'), required: false)], | ||||
|     [ | ||||
|       GeneratedFormSwitch('refreshBeforeDownload', | ||||
|           label: tr('refreshBeforeDownload')) | ||||
|     ] | ||||
|   ]; | ||||
|  | ||||
|   // Previous 2 variables combined into one at runtime for convenient usage | ||||
| @@ -808,9 +875,6 @@ class SourceProvider { | ||||
|         Tencent(), | ||||
|         Jenkins(), | ||||
|         APKMirror(), | ||||
|         VLC(), | ||||
|         WhatsApp(), | ||||
|         TelegramApp(), | ||||
|         NeutronCode(), | ||||
|         DirectAPKLink(), | ||||
|         HTML() // This should ALWAYS be the last option as they are tried in order | ||||
|   | ||||
							
								
								
									
										32
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -404,10 +404,10 @@ packages: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
|       name: flutter_launcher_icons | ||||
|       sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" | ||||
|       sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.14.1" | ||||
|     version: "0.14.2" | ||||
|   flutter_lints: | ||||
|     dependency: "direct dev" | ||||
|     description: | ||||
| @@ -449,10 +449,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: flutter_markdown | ||||
|       sha256: "999a4e3cb3e1532a971c86d6c73a480264f6a687959d4887cb4e2990821827e4" | ||||
|       sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.7.4+2" | ||||
|     version: "0.7.4+3" | ||||
|   flutter_plugin_android_lifecycle: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -667,18 +667,18 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_android | ||||
|       sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a | ||||
|       sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.2.12" | ||||
|     version: "2.2.14" | ||||
|   path_provider_foundation: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: path_provider_foundation | ||||
|       sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 | ||||
|       sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.4.0" | ||||
|     version: "2.4.1" | ||||
|   path_provider_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -843,10 +843,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: shared_preferences_android | ||||
|       sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" | ||||
|       sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.3.3" | ||||
|     version: "2.3.4" | ||||
|   shared_preferences_foundation: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1057,10 +1057,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_ios | ||||
|       sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e | ||||
|       sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "6.3.1" | ||||
|     version: "6.3.2" | ||||
|   url_launcher_linux: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1073,10 +1073,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: url_launcher_macos | ||||
|       sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" | ||||
|       sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.2.1" | ||||
|     version: "3.2.2" | ||||
|   url_launcher_platform_interface: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -1169,10 +1169,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: win32 | ||||
|       sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" | ||||
|       sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "5.8.0" | ||||
|     version: "5.9.0" | ||||
|   win32_registry: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
| @@ -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: 1.1.32+2289 | ||||
| version: 1.1.33+2290 | ||||
|  | ||||
| environment: | ||||
|   sdk: '>=3.0.0 <4.0.0' | ||||
|   | ||||
		Reference in New Issue
	
	Block a user