Skip to content

Commit 62e3603

Browse files
committed
modrinth: prioritize target loader when resolving project versions
1 parent b24de72 commit 62e3603

File tree

5 files changed

+537
-38
lines changed

5 files changed

+537
-38
lines changed

src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.nio.file.Files;
88
import java.nio.file.Path;
99
import java.util.ArrayList;
10+
import java.util.Collection;
1011
import java.util.Collections;
1112
import java.util.HashSet;
1213
import java.util.List;
@@ -181,31 +182,52 @@ public Mono<Path> downloadMrPack(VersionFile versionFile) {
181182
public Mono<List<Version>> getVersionsForProject(String projectIdOrSlug,
182183
@Nullable Loader loader, String gameVersion
183184
) {
184-
return sharedFetch.fetch(
185-
uriBuilder.resolve("/v2/project/{id|slug}/version",
186-
queryParameters()
187-
.addStringArray("loaders", expandCompatibleLoaders(loader))
188-
.addStringArray("game_versions", gameVersion),
189-
projectIdOrSlug
185+
return getJustVersionsForProject(projectIdOrSlug, gameVersion,
186+
loader != null ? Collections.singletonList(loader.toString()) : null
187+
)
188+
.switchIfEmpty(
189+
getJustVersionsForProject(projectIdOrSlug, gameVersion,
190+
expandCompatibleLoaders(loader)
190191
)
191192
)
192-
.toObjectList(Version.class)
193-
.assemble()
194-
.flatMap(versions ->
195-
versions.isEmpty() ?
196-
getProject(projectIdOrSlug)
197-
.flatMap(project -> Mono.error(new NoFilesAvailableException(project, loader, gameVersion)))
198-
: Mono.just(versions)
199-
);
193+
.switchIfEmpty(
194+
getProject(projectIdOrSlug)
195+
.flatMap(project -> Mono.error(new NoFilesAvailableException(project, loader, gameVersion)))
196+
);
197+
}
198+
199+
/**
200+
* @return the non-empty list of versions or an empty mono
201+
*/
202+
private Mono<List<Version>> getJustVersionsForProject(String projectIdOrSlug, String gameVersion,
203+
Collection<String> loaderNames
204+
) {
205+
return
206+
loaderNames == null || loaderNames.isEmpty() ?
207+
Mono.empty() :
208+
sharedFetch.fetch(
209+
uriBuilder.resolve("/v2/project/{id|slug}/version",
210+
queryParameters()
211+
.addStringArray("loaders", loaderNames)
212+
.addStringArray("game_versions", gameVersion),
213+
projectIdOrSlug
214+
)
215+
)
216+
.toObjectList(Version.class)
217+
.assemble()
218+
.filter(versions -> !versions.isEmpty());
200219
}
201220

221+
/**
222+
* @param loader the target loader
223+
* @return a list of the compatible loaders
224+
*/
202225
private List<String> expandCompatibleLoaders(@Nullable Loader loader) {
203226
if (loader == null) {
204227
return null;
205228
}
206229

207230
final ArrayList<String> expanded = new ArrayList<>();
208-
expanded.add(loader.toString());
209231
Loader compatibleWith = loader;
210232
while ((compatibleWith = compatibleWith.getCompatibleWith()) != null) {
211233
expanded.add(compatibleWith.toString());

src/test/java/me/itzg/helpers/modrinth/ModrinthApiClientTest.java

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,33 +45,75 @@ void getBulkProjectsWithUnknownServerSide(WireMockRuntimeInfo wmInfo) {
4545
}
4646
}
4747

48-
@Test
49-
void getVersionsForProject(WireMockRuntimeInfo wmInfo) {
50-
51-
stubFor(get(urlPathMatching("/v2/project/(BITzwT7B|clickvillagers)/version"))
52-
.withQueryParam("loaders", equalTo("[\"purpur\",\"paper\",\"spigot\"]"))
53-
.withQueryParam("game_versions", equalTo("[\"1.20.1\"]"))
54-
.willReturn(aResponse()
55-
.withHeader("Content-Type", "application/json")
56-
.withBodyFile("modrinth/project-BITzwT7B-version-resp.json")
57-
)
58-
);
48+
@Nested
49+
class getVersionsForProject {
50+
@Test
51+
void exactLoader(WireMockRuntimeInfo wmInfo) {
5952

60-
try (ModrinthApiClient client = new ModrinthApiClient(wmInfo.getHttpBaseUrl(), "modrinth", Options.builder().build())) {
61-
final List<Version> result = client.getVersionsForProject("BITzwT7B", Loader.purpur, "1.20.1")
62-
.block();
53+
stubFor(get(urlPathMatching("/v2/project/(BITzwT7B|clickvillagers)/version"))
54+
.withQueryParam("loaders", equalTo("[\"purpur\"]"))
55+
.withQueryParam("game_versions", equalTo("[\"1.20.1\"]"))
56+
.willReturn(aResponse()
57+
.withHeader("Content-Type", "application/json")
58+
.withBodyFile("modrinth/project-BITzwT7B-version-resp.json")
59+
)
60+
);
61+
62+
try (ModrinthApiClient client = new ModrinthApiClient(wmInfo.getHttpBaseUrl(), "modrinth", Options.builder().build())) {
63+
final List<Version> result = client.getVersionsForProject("BITzwT7B", Loader.purpur, "1.20.1")
64+
.block();
65+
66+
assertThat(result)
67+
.hasSize(3)
68+
.extracting(Version::getId)
69+
.containsExactly(
70+
"O9nndrTu",
71+
"DfUyEmsH",
72+
"oUJMLDhz"
73+
);
74+
}
75+
}
76+
77+
@Test
78+
void fallbackToCompatibleLoader(WireMockRuntimeInfo wmInfo) {
79+
stubFor(get(urlPathMatching("/v2/project/entityculling/version"))
80+
.withQueryParam("loaders", equalTo("[\"neoforge\"]"))
81+
.withQueryParam("game_versions", equalTo("[\"1.12.2\"]"))
82+
.willReturn(aResponse()
83+
.withHeader("Content-Type", "application/json")
84+
.withBodyFile("modrinth/versions-entityculling-neoforge-not-forge.json")
85+
)
86+
);
87+
stubFor(get(urlPathMatching("/v2/project/entityculling/version"))
88+
.withQueryParam("loaders", equalTo("[\"forge\"]"))
89+
.withQueryParam("game_versions", equalTo("[\"1.12.2\"]"))
90+
.willReturn(aResponse()
91+
.withHeader("Content-Type", "application/json")
92+
.withBodyFile("modrinth/versions-entityculling-forge.json")
93+
)
94+
);
6395

64-
assertThat(result)
65-
.hasSize(3)
66-
.extracting(Version::getId)
67-
.containsExactly(
68-
"O9nndrTu",
69-
"DfUyEmsH",
70-
"oUJMLDhz"
71-
);
96+
try (ModrinthApiClient client = new ModrinthApiClient(wmInfo.getHttpBaseUrl(), "modrinth",
97+
Options.builder().build()
98+
)) {
99+
final List<Version> result = client.getVersionsForProject(
100+
"entityculling",
101+
Loader.neoforge,
102+
"1.12.2"
103+
)
104+
.block();
105+
106+
assertThat(result)
107+
.extracting(Version::getId)
108+
.containsExactly(
109+
"knltv3Vh"
110+
);
111+
}
72112
}
73113
}
74114

115+
116+
75117
@Nested
76118
class resolveProjectVersion {
77119

@@ -142,7 +184,7 @@ void noFiles(WireMockRuntimeInfo wmInfo) {
142184
@Test
143185
void noApplicableVersionsOfType(WireMockRuntimeInfo wmInfo) {
144186
stubFor(get(urlPathMatching("/v2/project/(3wmN97b8|multiverse-core)/version"))
145-
.withQueryParam("loaders", equalTo("[\"purpur\",\"paper\",\"spigot\"]"))
187+
.withQueryParam("loaders", equalTo("[\"purpur\"]"))
146188
.withQueryParam("game_versions", equalTo("[\"1.21.1\"]"))
147189
.willReturn(aResponse()
148190
.withHeader("Content-Type", "application/json")

0 commit comments

Comments
 (0)