diff --git a/README.md b/README.md index 6518041..b0b3bd9 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Currently supported App sources: - [Huawei AppGallery](https://appgallery.huawei.com/) - [Tencent App Store](https://sj.qq.com/) - [CoolApk](https://coolapk.com/) + - [vivo App Store (CN)](https://h5.appstore.vivo.com.cn/) - [RuStore](https://rustore.ru/) - Jenkins Jobs - [APKMirror](https://apkmirror.com/) (Track-Only) diff --git a/assets/translations/en.json b/assets/translations/en.json index acc31b7..9ea7e44 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -321,6 +321,7 @@ "refreshBeforeDownload": "Refresh app details before download", "tencentAppStore": "Tencent App Store", "coolApk": "CoolApk", + "vivoAppStore": "vivo App Store (CN)", "name": "Name", "smartname": "Name (smart)", "sortMethod": "Sort method", diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 4e617a0..33e3782 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -321,6 +321,7 @@ "refreshBeforeDownload": "下载前刷新应用程序详细信息", "tencentAppStore": "腾讯应用宝", "coolApk": "酷安", + "vivoAppStore": "vivo 应用商店(中国)", "name": "名称", "smartname": "姓名(智能)", "sortMethod": "排序方法", diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt index d620444..ecdd345 100644 --- a/fastlane/metadata/android/en-US/full_description.txt +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -26,6 +26,7 @@
  • Huawei AppGallery
  • Tencent App Store
  • CoolApk
  • +
  • vivo App Store (CN)
  • Jenkins Jobs
  • RuStore
  • diff --git a/fastlane/metadata/android/ru/full_description.txt b/fastlane/metadata/android/ru/full_description.txt index 7249abd..61e9331 100644 --- a/fastlane/metadata/android/ru/full_description.txt +++ b/fastlane/metadata/android/ru/full_description.txt @@ -26,6 +26,7 @@
  • Huawei AppGallery
  • Tencent App Store
  • CoolApk
  • +
  • vivo App Store (CN)
  • Jenkins Jobs
  • RuStore
  • diff --git a/lib/app_sources/vivoappstore.dart b/lib/app_sources/vivoappstore.dart new file mode 100644 index 0000000..9b55ce2 --- /dev/null +++ b/lib/app_sources/vivoappstore.dart @@ -0,0 +1,97 @@ +import 'dart:convert'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:obtainium/custom_errors.dart'; +import 'package:obtainium/providers/source_provider.dart'; + +class VivoAppStore extends AppSource { + static const appDetailUrl = + 'https://h5coml.vivo.com.cn/h5coml/appdetail_h5/browser_v2/index.html?appId='; + + VivoAppStore() { + name = tr('vivoAppStore'); + hosts = ['h5.appstore.vivo.com.cn', 'h5coml.vivo.com.cn']; + naiveStandardVersionDetection = true; + canSearch = true; + } + + @override + String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) { + var vivoAppId = parseVivoAppId(url); + return '$appDetailUrl$vivoAppId'; + } + + @override + Future tryInferringAppId(String standardUrl, + {Map additionalSettings = const {}}) async { + var json = await getDetailJson(standardUrl, additionalSettings); + return json['package_name']; + } + + @override + Future getLatestAPKDetails( + String standardUrl, Map additionalSettings) async { + var json = await getDetailJson(standardUrl, additionalSettings); + var appName = json['title_zh'].toString(); + var packageName = json['package_name'].toString(); + var versionName = json['version_name'].toString(); + var versionCode = json['version_code'].toString(); + var developer = json['developer'].toString(); + var uploadTime = json['upload_time'].toString(); + var apkUrl = json['download_url'].toString(); + var apkName = '${packageName}_$versionCode.apk'; + return APKDetails( + versionName, [MapEntry(apkName, apkUrl)], AppNames(developer, appName), + releaseDate: DateTime.parse(uploadTime)); + } + + @override + Future>> search(String query, + {Map querySettings = const {}}) async { + var apiBaseUrl = + 'https://h5-api.appstore.vivo.com.cn/h5appstore/search/result-list?app_version=2100&page_index=1&apps_per_page=20&target=local&cfrom=2&key='; + var searchUrl = '$apiBaseUrl${Uri.encodeQueryComponent(query)}'; + var response = await sourceRequest(searchUrl, {}); + if (response.statusCode != 200) { + throw getObtainiumHttpError(response); + } + var json = jsonDecode(response.body); + if (json['code'] != 0 || !json['data']['appSearchResponse']['result']) { + throw NoReleasesError(); + } + Map> results = {}; + var resultsJson = json['data']['appSearchResponse']['value']; + for (var item in (resultsJson as List)) { + results['$appDetailUrl${item['id']}'] = [ + item['title_zh'].toString(), + item['developer'].toString() + ]; + } + return results; + } + + Future> getDetailJson( + String standardUrl, Map additionalSettings) async { + var vivoAppId = parseVivoAppId(standardUrl); + var apiBaseUrl = 'https://h5-api.appstore.vivo.com.cn/detail/'; + var params = '?frompage=messageh5&app_version=2100'; + var detailUrl = '$apiBaseUrl$vivoAppId$params'; + var response = await sourceRequest(detailUrl, additionalSettings); + if (response.statusCode != 200) { + throw getObtainiumHttpError(response); + } + var json = jsonDecode(response.body); + if (json['id'] == null) { + throw NoReleasesError(); + } + return json; + } + + String parseVivoAppId(String url) { + var appId = Uri.parse(url.replaceAll('/#', '')).queryParameters['appId']; + if (appId == null || appId.isEmpty) { + throw InvalidURLError(name); + } + return appId; + } +} diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index a9852d6..0f08d78 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -31,6 +31,7 @@ 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/vivoappstore.dart'; import 'package:obtainium/components/generated_form.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/mass_app_sources/githubstars.dart'; @@ -955,6 +956,7 @@ class SourceProvider { HuaweiAppGallery(), Tencent(), CoolApk(), + VivoAppStore(), Jenkins(), APKMirror(), RuStore(),