153 lines
6.6 KiB
Objective-C
153 lines
6.6 KiB
Objective-C
#import "MinecraftResourceDownloadTask.h"
|
|
#import "ModrinthAPI.h"
|
|
#import "PLProfiles.h"
|
|
|
|
@implementation ModrinthAPI
|
|
|
|
- (instancetype)init {
|
|
return [super initWithURL:@"https://api.modrinth.com/v2"];
|
|
}
|
|
|
|
- (NSMutableArray *)searchModWithFilters:(NSDictionary<NSString *, NSString *> *)searchFilters previousPageResult:(NSMutableArray *)modrinthSearchResult {
|
|
int limit = 50;
|
|
|
|
NSMutableString *facetString = [NSMutableString new];
|
|
[facetString appendString:@"["];
|
|
[facetString appendFormat:@"[\"project_type:%@\"]", searchFilters[@"isModpack"].boolValue ? @"modpack" : @"mod"];
|
|
if (searchFilters[@"mcVersion"].length > 0) {
|
|
[facetString appendFormat:@",[\"versions:%@\"]", searchFilters[@"mcVersion"]];
|
|
}
|
|
[facetString appendString:@"]"];
|
|
|
|
NSDictionary *params = @{
|
|
@"facets": facetString,
|
|
@"query": [searchFilters[@"name"] stringByReplacingOccurrencesOfString:@" " withString:@"+"],
|
|
@"limit": @(limit),
|
|
@"index": @"relevance",
|
|
@"offset": @(modrinthSearchResult.count)
|
|
};
|
|
NSDictionary *response = [self getEndpoint:@"search" params:params];
|
|
if (!response) {
|
|
return nil;
|
|
}
|
|
|
|
NSMutableArray *result = modrinthSearchResult ?: [NSMutableArray new];
|
|
for (NSDictionary *hit in response[@"hits"]) {
|
|
BOOL isModpack = [hit[@"project_type"] isEqualToString:@"modpack"];
|
|
[result addObject:@{
|
|
@"apiSource": @(1), // Constant MODRINTH
|
|
@"isModpack": @(isModpack),
|
|
@"id": hit[@"project_id"],
|
|
@"title": hit[@"title"],
|
|
@"description": hit[@"description"],
|
|
@"imageUrl": hit[@"icon_url"]
|
|
}.mutableCopy];
|
|
}
|
|
self.reachedLastPage = result.count >= [response[@"total_hits"] unsignedLongValue];
|
|
return result;
|
|
}
|
|
|
|
- (void)loadDetailsOfMod:(NSMutableDictionary *)item {
|
|
NSArray *response = [self getEndpoint:[NSString stringWithFormat:@"project/%@/version", item[@"id"]] params:nil];
|
|
if (!response) {
|
|
return;
|
|
}
|
|
NSArray<NSString *> *names = [response valueForKey:@"name"];
|
|
NSMutableArray<NSString *> *mcNames = [NSMutableArray new];
|
|
NSMutableArray<NSString *> *urls = [NSMutableArray new];
|
|
NSMutableArray<NSString *> *hashes = [NSMutableArray new];
|
|
NSMutableArray<NSString *> *sizes = [NSMutableArray new];
|
|
[response enumerateObjectsUsingBlock:
|
|
^(NSDictionary *version, NSUInteger i, BOOL *stop) {
|
|
NSDictionary *file = [version[@"files"] firstObject];
|
|
mcNames[i] = [version[@"game_versions"] firstObject];
|
|
sizes[i] = file[@"size"];
|
|
urls[i] = file[@"url"];
|
|
NSDictionary *hashesMap = file[@"hashes"];
|
|
hashes[i] = hashesMap[@"sha1"] ?: [NSNull null];
|
|
}];
|
|
item[@"versionNames"] = names;
|
|
item[@"mcVersionNames"] = mcNames;
|
|
item[@"versionSizes"] = sizes;
|
|
item[@"versionUrls"] = urls;
|
|
item[@"versionHashes"] = hashes;
|
|
item[@"versionDetailsLoaded"] = @(YES);
|
|
}
|
|
|
|
- (void)downloader:(MinecraftResourceDownloadTask *)downloader submitDownloadTasksFromPackage:(NSString *)packagePath toPath:(NSString *)destPath {
|
|
NSError *error;
|
|
UZKArchive *archive = [[UZKArchive alloc] initWithPath:packagePath error:&error];
|
|
if (error) {
|
|
[downloader finishDownloadWithErrorString:[NSString stringWithFormat:@"Failed to open modpack package: %@", error.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
NSData *indexData = [archive extractDataFromFile:@"modrinth.index.json" error:&error];
|
|
NSDictionary* indexDict = [NSJSONSerialization JSONObjectWithData:indexData options:kNilOptions error:&error];
|
|
if (error) {
|
|
[downloader finishDownloadWithErrorString:[NSString stringWithFormat:@"Failed to parse modrinth.index.json: %@", error.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
downloader.progress.totalUnitCount = [indexDict[@"files"] count];
|
|
for (NSDictionary *indexFile in indexDict[@"files"]) {
|
|
/*
|
|
if ([indexFile[@"downloads"] count] > 1) {
|
|
[downloader finishDownloadWithErrorString:[NSString stringWithFormat:@"Unhandled multiple files download %@", indexFile[@"downloads"]]];
|
|
return;
|
|
}
|
|
*/
|
|
NSString *url = [indexFile[@"downloads"] firstObject];
|
|
NSString *sha = indexFile[@"hashes"][@"sha1"];
|
|
NSString *path = [destPath stringByAppendingPathComponent:indexFile[@"path"]];
|
|
NSUInteger size = [indexFile[@"fileSize"] unsignedLongLongValue];
|
|
NSURLSessionDownloadTask *task = [downloader createDownloadTask:url size:size sha:sha altName:nil toPath:path];
|
|
if (task) {
|
|
[downloader.fileList addObject:indexFile[@"path"]];
|
|
[task resume];
|
|
} else if (!downloader.progress.cancelled) {
|
|
downloader.progress.completedUnitCount++;
|
|
} else {
|
|
return; // cancelled
|
|
}
|
|
}
|
|
|
|
[ModpackUtils archive:archive extractDirectory:@"overrides" toPath:destPath error:&error];
|
|
if (error) {
|
|
[downloader finishDownloadWithErrorString:[NSString stringWithFormat:@"Failed to extract overrides from modpack package: %@", error.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
[ModpackUtils archive:archive extractDirectory:@"client-overrides" toPath:destPath error:&error];
|
|
if (error) {
|
|
[downloader finishDownloadWithErrorString:[NSString stringWithFormat:@"Failed to extract client-overrides from modpack package: %@", error.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
// Delete package cache
|
|
[NSFileManager.defaultManager removeItemAtPath:packagePath error:nil];
|
|
|
|
// Download dependency client json (if available)
|
|
NSDictionary<NSString *, NSString *> *depInfo = [ModpackUtils infoForDependencies:indexDict[@"dependencies"]];
|
|
if (depInfo[@"json"]) {
|
|
NSString *jsonPath = [NSString stringWithFormat:@"%1$s/versions/%2$@/%[email protected]", getenv("POJAV_GAME_DIR"), depInfo[@"id"]];
|
|
NSURLSessionDownloadTask *task = [downloader createDownloadTask:depInfo[@"json"] size:0 sha:nil altName:nil toPath:jsonPath];
|
|
[task resume];
|
|
}
|
|
// TODO: automation for Forge
|
|
|
|
// Create profile
|
|
NSString *tmpIconPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"icon.png"];
|
|
PLProfiles.current.profiles[indexDict[@"name"]] = @{
|
|
@"gameDir": [NSString stringWithFormat:@"./custom_gamedir/%@", destPath.lastPathComponent],
|
|
@"name": indexDict[@"name"],
|
|
@"lastVersionId": depInfo[@"id"],
|
|
@"icon": [NSString stringWithFormat:@"data:image/png;base64,%@",
|
|
[[NSData dataWithContentsOfFile:tmpIconPath]
|
|
base64EncodedStringWithOptions:0]]
|
|
}.mutableCopy;
|
|
PLProfiles.current.selectedProfileName = indexDict[@"name"];
|
|
}
|
|
|
|
@end
|