@@ -151,6 +151,67 @@ - (BOOL)isSafeModFileName:(NSString *)fileName {
151151 return [lower hasSuffix: @" .jar" ];
152152}
153153
154+ - (NSString *)normalizedProviderSource : (id )value {
155+ if (![value isKindOfClass: NSString .class]) {
156+ return nil ;
157+ }
158+ NSString *source = [[value stringByTrimmingCharactersInSet: NSCharacterSet .whitespaceAndNewlineCharacterSet] lowercaseString ];
159+ if ([source isEqualToString: @" modrinth" ] ||
160+ [source isEqualToString: @" curseforge" ] ||
161+ [source isEqualToString: @" manual" ]) {
162+ return source;
163+ }
164+ return nil ;
165+ }
166+
167+ - (NSString *)providerSourceForURLString : (id )value {
168+ if (![value isKindOfClass: NSString .class] || [value length ] == 0 ) {
169+ return nil ;
170+ }
171+ NSURL *url = [NSURL URLWithString: value];
172+ NSString *host = url.host .lowercaseString ?: @" " ;
173+ NSString *urlString = [value lowercaseString ];
174+ if ([host containsString: @" modrinth.com" ] || [urlString containsString: @" modrinth.com/" ]) {
175+ return @" modrinth" ;
176+ }
177+ if ([host containsString: @" curseforge.com" ] ||
178+ [host containsString: @" forgecdn.net" ] ||
179+ [host containsString: @" cursecdn.com" ] ||
180+ [urlString containsString: @" curseforge.com/" ] ||
181+ [urlString containsString: @" forgecdn.net/" ] ||
182+ [urlString containsString: @" cursecdn.com/" ]) {
183+ return @" curseforge" ;
184+ }
185+ return nil ;
186+ }
187+
188+ - (NSString *)inferredProviderSourceForRecord : (NSDictionary *)record {
189+ NSString *source = [self normalizedProviderSource: record[@" source" ]];
190+ NSString *downloadSource = [self providerSourceForURLString: record[@" downloadUrl" ]];
191+ NSString *manualSource = [self providerSourceForURLString: record[@" manualUrl" ]];
192+ NSString *urlSource = downloadSource ?: manualSource;
193+ if (urlSource && (!source || [source isEqualToString: @" manual" ] || ![urlSource isEqualToString: source])) {
194+ return urlSource;
195+ }
196+ if (source) {
197+ return source;
198+ }
199+
200+ NSString *iconSource = [self providerSourceForURLString: record[@" iconUrl" ]];
201+ if (iconSource) {
202+ return iconSource;
203+ }
204+
205+ if (record[@" fileId" ] || [record[@" projectId" ] isKindOfClass: NSNumber .class]) {
206+ return @" curseforge" ;
207+ }
208+ if ([record[@" versionId" ] isKindOfClass: NSString .class] ||
209+ [record[@" projectId" ] isKindOfClass: NSString .class]) {
210+ return @" modrinth" ;
211+ }
212+ return @" manual" ;
213+ }
214+
154215- (NSArray <NSString *> *)modFileNames {
155216 NSArray *contents = [NSFileManager .defaultManager contentsOfDirectoryAtPath: self .modsDir error: nil ] ?: @[];
156217 NSMutableArray *files = [NSMutableArray new ];
@@ -177,9 +238,7 @@ - (BOOL)isSafeModFileName:(NSString *)fileName {
177238 if (mod[@" title" ] == nil ) {
178239 mod[@" title" ] = fileName.stringByDeletingPathExtension ;
179240 }
180- if (mod[@" source" ] == nil ) {
181- mod[@" source" ] = @" manual" ;
182- }
241+ mod[@" source" ] = [self inferredProviderSourceForRecord: mod];
183242 mod[@" fileName" ] = fileName;
184243 mod[@" actualFileName" ] = actualFileName;
185244 mod[@" path" ] = [self .modsDir stringByAppendingPathComponent: actualFileName];
@@ -438,7 +497,7 @@ - (NSDictionary *)installPlanForFiles:(NSArray<NSDictionary *> *)files error:(NS
438497 }
439498
440499 NSString *destination = [self .modsDir stringByAppendingPathComponent: fileName];
441- NSString *source = file[ @" source " ] ?: @" manual " ;
500+ NSString *source = [ self inferredProviderSourceForRecord: file] ;
442501 id projectId = file[@" projectId" ];
443502 NSString *existingFileName = [self existingFileNameForSource: source projectId: projectId];
444503 if (existingFileName.length > 0 && ![existingFileName isEqualToString: fileName]) {
@@ -463,6 +522,7 @@ - (NSDictionary *)installPlanForFiles:(NSArray<NSDictionary *> *)files error:(NS
463522 record[key] = value;
464523 }
465524 }
525+ record[@" source" ] = source;
466526 record[@" installedAt" ] = installedAt;
467527 record[@" enabled" ] = @YES ;
468528 [records addObject: record];
0 commit comments