mirror of
https://github.com/ImranR98/Obtainium.git
synced 2025-08-19 05:00:21 +02:00
Added farsroid.com as a source (#2435)
This commit is contained in:
76
lib/app_sources/farsroid.dart
Normal file
76
lib/app_sources/farsroid.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:html/parser.dart';
|
||||
import 'package:obtainium/app_sources/html.dart';
|
||||
import 'package:obtainium/custom_errors.dart';
|
||||
import 'package:obtainium/providers/source_provider.dart';
|
||||
|
||||
class Farsroid extends AppSource {
|
||||
Farsroid() {
|
||||
hosts = ['farsroid.com'];
|
||||
name = 'Farsroid';
|
||||
}
|
||||
|
||||
@override
|
||||
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
|
||||
RegExp standardUrlRegEx = RegExp(
|
||||
'^https?://([^\\.]+\\.)${getSourceRegex(hosts)}/[^/]+',
|
||||
caseSensitive: false,
|
||||
);
|
||||
RegExpMatch? match = standardUrlRegEx.firstMatch(url);
|
||||
if (match == null) {
|
||||
throw InvalidURLError(name);
|
||||
}
|
||||
return match.group(0)!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<APKDetails> getLatestAPKDetails(
|
||||
String standardUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
String appName = Uri.parse(standardUrl).pathSegments.last;
|
||||
|
||||
var res = await sourceRequest(standardUrl, additionalSettings);
|
||||
if (res.statusCode != 200) {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
var html = parse(res.body);
|
||||
var dlinks = html.querySelectorAll('.download-links');
|
||||
if (dlinks.isEmpty) {
|
||||
throw NoReleasesError();
|
||||
}
|
||||
var postId = dlinks.first.attributes['data-post-id'] ?? '';
|
||||
var version = dlinks.first.attributes['data-post-version'] ?? '';
|
||||
|
||||
if (postId.isEmpty || version.isEmpty) {
|
||||
throw NoVersionError();
|
||||
}
|
||||
|
||||
var res2 = await sourceRequest(
|
||||
Uri.encodeFull(
|
||||
'https://${hosts[0]}/api/download-box/?post_id=$postId&post_version=$version',
|
||||
),
|
||||
additionalSettings,
|
||||
);
|
||||
var html2 = jsonDecode(res2.body)?['data']?['content'] as String? ?? '';
|
||||
if (html2.isEmpty) {
|
||||
throw NoAPKError();
|
||||
}
|
||||
var apkLinks =
|
||||
(await grabLinksCommon(html2, res2.request!.url, additionalSettings))
|
||||
.map((l) => MapEntry(Uri.parse(l.key).pathSegments.last, l.key))
|
||||
.where(
|
||||
(l) => l.key.toLowerCase().startsWith(
|
||||
'$appName-$version'.toLowerCase(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
if (apkLinks.isEmpty) {
|
||||
throw NoAPKError();
|
||||
}
|
||||
|
||||
return APKDetails(version, apkLinks, AppNames(name, appName));
|
||||
}
|
||||
}
|
@@ -113,14 +113,23 @@ List<MapEntry<String, String>> getLinksInLines(String lines) =>
|
||||
|
||||
// Given an HTTP response, grab some links according to the common additional settings
|
||||
// (those that apply to intermediate and final steps)
|
||||
Future<List<MapEntry<String, String>>> grabLinksCommon(
|
||||
Future<List<MapEntry<String, String>>> grabLinksCommonFromRes(
|
||||
Response res,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
if (res.statusCode != 200) {
|
||||
throw getObtainiumHttpError(res);
|
||||
}
|
||||
var html = parse(res.body);
|
||||
return grabLinksCommon(res.body, res.request!.url, additionalSettings);
|
||||
}
|
||||
|
||||
// Note keys are URLs, values are filenames (opposite to the AppSource apkUrls)
|
||||
Future<List<MapEntry<String, String>>> grabLinksCommon(
|
||||
String rawBody,
|
||||
Uri reqUrl,
|
||||
Map<String, dynamic> additionalSettings,
|
||||
) async {
|
||||
var html = parse(rawBody);
|
||||
List<MapEntry<String, String>> allLinks = html
|
||||
.querySelectorAll('a')
|
||||
.map(
|
||||
@@ -132,21 +141,21 @@ Future<List<MapEntry<String, String>>> grabLinksCommon(
|
||||
),
|
||||
)
|
||||
.where((element) => element.key.isNotEmpty)
|
||||
.map((e) => MapEntry(ensureAbsoluteUrl(e.key, res.request!.url), e.value))
|
||||
.map((e) => MapEntry(ensureAbsoluteUrl(e.key, reqUrl), e.value))
|
||||
.toList();
|
||||
if (allLinks.isEmpty) {
|
||||
allLinks = getLinksInLines(res.body);
|
||||
allLinks = getLinksInLines(rawBody);
|
||||
}
|
||||
if (allLinks.isEmpty) {
|
||||
// Getting desperate
|
||||
try {
|
||||
var jsonStrings = collectAllStringsFromJSONObject(jsonDecode(res.body));
|
||||
var jsonStrings = collectAllStringsFromJSONObject(jsonDecode(rawBody));
|
||||
allLinks = getLinksInLines(jsonStrings.join('\n'));
|
||||
if (allLinks.isEmpty) {
|
||||
allLinks = getLinksInLines(
|
||||
jsonStrings
|
||||
.map((l) {
|
||||
return ensureAbsoluteUrl(l, res.request!.url);
|
||||
return ensureAbsoluteUrl(l, reqUrl);
|
||||
})
|
||||
.join('\n'),
|
||||
);
|
||||
@@ -368,7 +377,7 @@ class HTML extends AppSource {
|
||||
.where((l) => l['customLinkFilterRegex'].isNotEmpty == true)
|
||||
.toList();
|
||||
for (int i = 0; i < (additionalSettings['intermediateLink'].length); i++) {
|
||||
var intLinks = await grabLinksCommon(
|
||||
var intLinks = await grabLinksCommonFromRes(
|
||||
await sourceRequest(currentUrl, additionalSettings),
|
||||
additionalSettings['intermediateLink'][i],
|
||||
);
|
||||
@@ -392,7 +401,7 @@ class HTML extends AppSource {
|
||||
.join('\n')
|
||||
.split('\n')
|
||||
.join('\\n');
|
||||
links = await grabLinksCommon(res, additionalSettings);
|
||||
links = await grabLinksCommonFromRes(res, additionalSettings);
|
||||
links = filterApks(
|
||||
links,
|
||||
additionalSettings['apkFilterRegEx'],
|
||||
|
@@ -16,6 +16,7 @@ import 'package:obtainium/app_sources/aptoide.dart';
|
||||
import 'package:obtainium/app_sources/codeberg.dart';
|
||||
import 'package:obtainium/app_sources/coolapk.dart';
|
||||
import 'package:obtainium/app_sources/directAPKLink.dart';
|
||||
import 'package:obtainium/app_sources/farsroid.dart';
|
||||
import 'package:obtainium/app_sources/fdroid.dart';
|
||||
import 'package:obtainium/app_sources/fdroidrepo.dart';
|
||||
import 'package:obtainium/app_sources/github.dart';
|
||||
@@ -63,11 +64,13 @@ class APKDetails {
|
||||
});
|
||||
}
|
||||
|
||||
List<List<String>> stringMapListTo2DList(List<MapEntry<String, String>> mapList) =>
|
||||
mapList.map((e) => [e.key, e.value]).toList();
|
||||
List<List<String>> stringMapListTo2DList(
|
||||
List<MapEntry<String, String>> mapList,
|
||||
) => mapList.map((e) => [e.key, e.value]).toList();
|
||||
|
||||
List<MapEntry<String, String>> assumed2DlistToStringMapList(List<dynamic> arr) =>
|
||||
arr.map((e) => MapEntry(e[0] as String, e[1] as String)).toList();
|
||||
List<MapEntry<String, String>> assumed2DlistToStringMapList(
|
||||
List<dynamic> arr,
|
||||
) => arr.map((e) => MapEntry(e[0] as String, e[1] as String)).toList();
|
||||
|
||||
// App JSON schema has changed multiple times over the many versions of Obtainium
|
||||
// This function takes an App JSON and modifies it if needed to conform to the latest (current) version
|
||||
@@ -1074,6 +1077,7 @@ class SourceProvider {
|
||||
Jenkins(),
|
||||
APKMirror(),
|
||||
RuStore(),
|
||||
Farsroid(),
|
||||
TelegramApp(),
|
||||
NeutronCode(),
|
||||
DirectAPKLink(),
|
||||
|
Reference in New Issue
Block a user