import 'dart:convert'; import 'package:http/http.dart'; import 'package:obtainium/custom_errors.dart'; import 'package:obtainium/providers/source_provider.dart'; class Jenkins extends AppSource { @override String trimJobUrl(String url) { RegExp standardUrlRegEx = RegExp('.*/job/[^/]+'); RegExpMatch? match = standardUrlRegEx.firstMatch(url); if (match == null) { throw InvalidURLError(name); } return url.substring(0, match.end); } @override String? changeLogPageFromStandardUrl(String standardUrl) => '$standardUrl/-/releases'; @override Future getLatestAPKDetails( String standardUrl, Map additionalSettings, ) async { standardUrl = trimJobUrl(standardUrl); Response res = await get(Uri.parse('$standardUrl/lastSuccessfulBuild/api/json')); if (res.statusCode == 200) { var json = jsonDecode(res.body); var releaseDate = json['timestamp'] == null ? null : DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int); var version = json['number'] == null ? null : (json['number'] as int).toString(); if (version == null) { throw NoVersionError(); } var apkUrls = (json['artifacts'] as List) .map((e) { var path = (e['relativePath'] as String?); if (path != null && path.isNotEmpty) { path = '$standardUrl/lastSuccessfulBuild/artifact/$path'; } return path == null ? const MapEntry('', '') : MapEntry( (e['fileName'] ?? e['relativePath']) as String, path); }) .where((url) => url.value.isNotEmpty && url.key.toLowerCase().endsWith('.apk')) .toList(); if (apkUrls.isEmpty) { throw NoAPKError(); } return APKDetails( version, apkUrls, releaseDate: releaseDate, AppNames(Uri.parse(standardUrl).host, standardUrl.split('/').last)); } else { throw getObtainiumHttpError(res); } } }