mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-14 03:32:23 +01:00
9.0.8
This commit is contained in:
@@ -8,6 +8,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_common/src/extension/types.dart';
|
||||
|
||||
const String kStopBuildDownloadSignal = "kill";
|
||||
|
||||
@@ -23,61 +24,14 @@ Dio _buildDioInstance() {
|
||||
return dio;
|
||||
}
|
||||
|
||||
final String _archiveSourceUrl = "https://raw.githubusercontent.com/simplyblk/Fortnitebuilds/main/README.md";
|
||||
final String _archiveSourceUrl = "http://185.203.216.3/versions.json";
|
||||
final RegExp _rarProgressRegex = RegExp("^((100)|(\\d{1,2}(.\\d*)?))%\$");
|
||||
const String _manifestSourceUrl = "http://manifest.simplyblk.xyz";
|
||||
const String _deniedConnectionError = "The connection was denied: your firewall might be blocking the download";
|
||||
const String _unavailableError = "The build downloader is not available right now";
|
||||
const String _genericError = "The build downloader is not working correctly";
|
||||
const int _maxErrors = 100;
|
||||
|
||||
Future<List<FortniteBuild>> fetchBuilds(ignored) async {
|
||||
(_dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () =>
|
||||
HttpClient()
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
|
||||
final results = await Future.wait([_fetchManifestBuilds(), _fetchArchiveBuilds()]);
|
||||
final data = <FortniteBuild>[];
|
||||
for(final result in results) {
|
||||
data.addAll(result);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Future<List<FortniteBuild>> _fetchManifestBuilds() async {
|
||||
try {
|
||||
final response = await _dio.get<String>(
|
||||
"$_manifestSourceUrl/versions.json",
|
||||
options: Options(
|
||||
headers: {
|
||||
"Accept-Encoding": "*",
|
||||
"Cookie": "_c_t_c=1"
|
||||
}
|
||||
)
|
||||
);
|
||||
final body = response.data;
|
||||
return jsonDecode(body!).map((version) {
|
||||
final nameParts = version.split("-");
|
||||
if(nameParts.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final name = nameParts[1];
|
||||
return FortniteBuild(
|
||||
identifier: name,
|
||||
version: "Fortnite ${name}",
|
||||
link: "$_manifestSourceUrl/$name/$name.manifest",
|
||||
source: FortniteBuildSource.manifest
|
||||
);
|
||||
}).whereType<FortniteBuild>().toList();
|
||||
}catch(_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<FortniteBuild>> _fetchArchiveBuilds() async {
|
||||
final response = await _dio.get<String>(
|
||||
_archiveSourceUrl,
|
||||
options: Options(
|
||||
@@ -88,32 +42,15 @@ Future<List<FortniteBuild>> _fetchArchiveBuilds() async {
|
||||
return [];
|
||||
}
|
||||
|
||||
final data = jsonDecode(response.data ?? "{}");
|
||||
var results = <FortniteBuild>[];
|
||||
for (var line in response.data?.split("\n") ?? []) {
|
||||
if(!line.startsWith("|")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var parts = line.substring(1, line.length - 1).split("|");
|
||||
if(parts.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var link = parts.last.trim();
|
||||
if(!link.endsWith(".zip") && !link.endsWith(".rar")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var version = parts.first.trim();
|
||||
version = version.substring(0, version.indexOf("-"));
|
||||
for(final entry in data.entries) {
|
||||
results.add(FortniteBuild(
|
||||
identifier: version,
|
||||
version: "Fortnite $version",
|
||||
link: link,
|
||||
source: FortniteBuildSource.archive
|
||||
identifier: entry.key,
|
||||
version: "${entry.value["title"]} (${entry.key})",
|
||||
link: entry.value["url"]
|
||||
));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -121,107 +58,23 @@ Future<List<FortniteBuild>> _fetchArchiveBuilds() async {
|
||||
Future<void> downloadArchiveBuild(FortniteBuildDownloadOptions options) async {
|
||||
try {
|
||||
final stopped = _setupLifecycle(options);
|
||||
switch(options.build.source) {
|
||||
case FortniteBuildSource.archive:
|
||||
final outputDir = Directory("${options.destination.path}\\.build");
|
||||
await outputDir.create(recursive: true);
|
||||
final fileName = options.build.link.substring(options.build.link.lastIndexOf("/") + 1);
|
||||
final extension = path.extension(fileName);
|
||||
final tempFile = File("${outputDir.path}\\$fileName");
|
||||
if(await tempFile.exists()) {
|
||||
await tempFile.delete(recursive: true);
|
||||
}
|
||||
|
||||
final startTime = DateTime.now().millisecondsSinceEpoch;
|
||||
final response = _downloadArchive(options, tempFile, startTime);
|
||||
await Future.any([stopped.future, response]);
|
||||
if(!stopped.isCompleted) {
|
||||
await _extractArchive(stopped, extension, tempFile, options);
|
||||
}
|
||||
|
||||
delete(outputDir);
|
||||
break;
|
||||
case FortniteBuildSource.manifest:
|
||||
final response = await _dio.get<String>(
|
||||
options.build.link,
|
||||
options: Options(
|
||||
headers: {
|
||||
"Cookie": "_c_t_c=1"
|
||||
}
|
||||
)
|
||||
);
|
||||
final manifest = FortniteBuildManifestFile.fromJson(jsonDecode(response.data!));
|
||||
|
||||
final totalBytes = manifest.size;
|
||||
final outputDir = options.destination;
|
||||
await outputDir.create(recursive: true);
|
||||
|
||||
final startTime = DateTime.now().millisecondsSinceEpoch;
|
||||
final codec = GZipCodec();
|
||||
var completedBytes = 0;
|
||||
var lastPercentage = 0.0;
|
||||
|
||||
final writers = manifest.chunks.map((chunkedFile) async {
|
||||
final outputFile = File('${outputDir.path}/${chunkedFile.file}');
|
||||
if(outputFile.existsSync()) {
|
||||
if(outputFile.lengthSync() != chunkedFile.fileSize) {
|
||||
await outputFile.delete();
|
||||
} else {
|
||||
completedBytes += chunkedFile.fileSize;
|
||||
final percentage = completedBytes * 100 / totalBytes;
|
||||
if(percentage - lastPercentage > 0.1) {
|
||||
_onProgress(
|
||||
startTime,
|
||||
DateTime.now().millisecondsSinceEpoch,
|
||||
percentage,
|
||||
false,
|
||||
options
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await outputFile.parent.create(recursive: true);
|
||||
for(final chunkId in chunkedFile.chunksIds) {
|
||||
final response = await _dio.get<Uint8List>(
|
||||
"$_manifestSourceUrl/${options.build.identifier}/$chunkId.chunk",
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
headers: {
|
||||
"Accept-Encoding": "gzip",
|
||||
"Cookie": "_c_t_c=1"
|
||||
}
|
||||
),
|
||||
);
|
||||
var responseBody = response.data;
|
||||
if(responseBody == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final decodedBody = codec.decode(responseBody);
|
||||
await outputFile.writeAsBytes(
|
||||
decodedBody,
|
||||
mode: FileMode.append,
|
||||
flush: true
|
||||
);
|
||||
completedBytes += decodedBody.length;
|
||||
|
||||
final percentage = completedBytes * 100 / totalBytes;
|
||||
if(percentage - lastPercentage > 0.1) {
|
||||
_onProgress(
|
||||
startTime,
|
||||
DateTime.now().millisecondsSinceEpoch,
|
||||
percentage,
|
||||
false,
|
||||
options
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
await Future.any([stopped.future, Future.wait(writers)]);
|
||||
break;
|
||||
final outputDir = Directory("${options.destination.path}\\.build");
|
||||
await outputDir.create(recursive: true);
|
||||
final fileName = options.build.link.substring(options.build.link.lastIndexOf("/") + 1);
|
||||
final extension = path.extension(fileName);
|
||||
final tempFile = File("${outputDir.path}\\$fileName");
|
||||
if(await tempFile.exists()) {
|
||||
await tempFile.delete(recursive: true);
|
||||
}
|
||||
|
||||
final startTime = DateTime.now().millisecondsSinceEpoch;
|
||||
final response = _downloadArchive(options, tempFile, startTime);
|
||||
await Future.any([stopped.future, response]);
|
||||
if(!stopped.isCompleted) {
|
||||
await _extractArchive(stopped, extension, tempFile, options);
|
||||
}
|
||||
|
||||
delete(outputDir);
|
||||
}catch(error) {
|
||||
_onError(error, options);
|
||||
}
|
||||
@@ -358,7 +211,7 @@ Future<void> _extractArchive(Completer<dynamic> stopped, String extension, File
|
||||
throw ArgumentError("Unexpected file extension: $extension}");
|
||||
}
|
||||
|
||||
await Future.any([stopped.future, watchProcess(process.pid)]);
|
||||
await Future.any([stopped.future, process.exitCode]);
|
||||
}
|
||||
|
||||
void _onProgress(int startTime, int? now, double percentage, bool extracting, FortniteBuildDownloadOptions options) {
|
||||
@@ -385,7 +238,6 @@ void _onError(Object? error, FortniteBuildDownloadOptions options) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Completer<dynamic> _setupLifecycle(FortniteBuildDownloadOptions options) {
|
||||
var stopped = Completer();
|
||||
var lifecyclePort = ReceivePort();
|
||||
|
||||
Reference in New Issue
Block a user