支持通过 MCIM 加速模组搜索 (#4225)
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.game;
|
package org.jackhuang.hmcl.game;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
||||||
@@ -41,9 +42,9 @@ public abstract class LocalizedRemoteModRepository implements RemoteModRepositor
|
|||||||
protected abstract SortType getBackedRemoteModRepositorySortOrder();
|
protected abstract SortType getBackedRemoteModRepositorySortOrder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchResult search(String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
|
public SearchResult search(DownloadProvider downloadProvider, String gameVersion, Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
|
||||||
if (!StringUtils.containsChinese(searchFilter)) {
|
if (!StringUtils.containsChinese(searchFilter)) {
|
||||||
return getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, searchFilter, sort, sortOrder);
|
return getBackedRemoteModRepository().search(downloadProvider, gameVersion, category, pageOffset, pageSize, searchFilter, sort, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> englishSearchFiltersSet = new HashSet<>(INITIAL_CAPACITY);
|
Set<String> englishSearchFiltersSet = new HashSet<>(INITIAL_CAPACITY);
|
||||||
@@ -65,7 +66,7 @@ public abstract class LocalizedRemoteModRepository implements RemoteModRepositor
|
|||||||
RemoteMod[] searchResultArray = new RemoteMod[pageSize];
|
RemoteMod[] searchResultArray = new RemoteMod[pageSize];
|
||||||
int totalPages, chineseIndex = 0, englishIndex = pageSize - 1;
|
int totalPages, chineseIndex = 0, englishIndex = pageSize - 1;
|
||||||
{
|
{
|
||||||
SearchResult searchResult = getBackedRemoteModRepository().search(gameVersion, category, pageOffset, pageSize, String.join(" ", englishSearchFiltersSet), getBackedRemoteModRepositorySortOrder(), sortOrder);
|
SearchResult searchResult = getBackedRemoteModRepository().search(downloadProvider, gameVersion, category, pageOffset, pageSize, String.join(" ", englishSearchFiltersSet), getBackedRemoteModRepositorySortOrder(), sortOrder);
|
||||||
for (Iterator<RemoteMod> iterator = searchResult.getUnsortedResults().iterator(); iterator.hasNext(); ) {
|
for (Iterator<RemoteMod> iterator = searchResult.getUnsortedResults().iterator(); iterator.hasNext(); ) {
|
||||||
if (chineseIndex > englishIndex) {
|
if (chineseIndex > englishIndex) {
|
||||||
LOG.warning("Too many search results! Are the backed remote mod repository broken? Or are the API broken?");
|
LOG.warning("Too many search results! Are the backed remote mod repository broken? Or are the API broken?");
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ import javafx.scene.image.ImageView;
|
|||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
||||||
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
|
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
|
||||||
|
import org.jackhuang.hmcl.setting.DownloadProviders;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@@ -90,6 +92,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
private final WeakListenerHolder listenerHolder = new WeakListenerHolder();
|
private final WeakListenerHolder listenerHolder = new WeakListenerHolder();
|
||||||
private int searchID = 0;
|
private int searchID = 0;
|
||||||
protected RemoteModRepository repository;
|
protected RemoteModRepository repository;
|
||||||
|
private final DownloadProvider downloadProvider;
|
||||||
|
|
||||||
private Runnable retrySearch;
|
private Runnable retrySearch;
|
||||||
|
|
||||||
@@ -101,6 +104,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.versionSelection = versionSelection;
|
this.versionSelection = versionSelection;
|
||||||
|
this.downloadProvider = DownloadProviders.getDownloadProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableList<Node> getActions() {
|
public ObservableList<Node> getActions() {
|
||||||
@@ -171,7 +175,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
}).thenApplyAsync(
|
}).thenApplyAsync(
|
||||||
gameVersion -> repository.search(gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)
|
gameVersion -> repository.search(downloadProvider, gameVersion, category, pageOffset, 50, searchFilter, sort, RemoteModRepository.SortOrder.DESC)
|
||||||
).whenComplete(Schedulers.javafx(), (result, exception) -> {
|
).whenComplete(Schedulers.javafx(), (result, exception) -> {
|
||||||
if (searchID != currentSearchID) {
|
if (searchID != currentSearchID) {
|
||||||
return;
|
return;
|
||||||
@@ -231,6 +235,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
|
|||||||
|
|
||||||
private static class ModDownloadListPageSkin extends SkinBase<DownloadListPage> {
|
private static class ModDownloadListPageSkin extends SkinBase<DownloadListPage> {
|
||||||
private final JFXListView<RemoteMod> listView = new JFXListView<>();
|
private final JFXListView<RemoteMod> listView = new JFXListView<>();
|
||||||
|
|
||||||
protected ModDownloadListPageSkin(DownloadListPage control) {
|
protected ModDownloadListPageSkin(DownloadListPage control) {
|
||||||
super(control);
|
super(control);
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,12 @@
|
|||||||
"titleLocalized" : "about.thanks_to.mcbbs",
|
"titleLocalized" : "about.thanks_to.mcbbs",
|
||||||
"subtitleLocalized" : "about.thanks_to.mcbbs.statement"
|
"subtitleLocalized" : "about.thanks_to.mcbbs.statement"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/mcim.png",
|
||||||
|
"titleLocalized" : "about.thanks_to.mcim",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.mcim.statement",
|
||||||
|
"externalLink" : "https://github.com/mcmod-info-mirror"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"image" : "/assets/img/github.png",
|
"image" : "/assets/img/github.png",
|
||||||
"titleLocalized" : "about.thanks_to.contributors",
|
"titleLocalized" : "about.thanks_to.contributors",
|
||||||
|
|||||||
BIN
HMCL/src/main/resources/assets/img/mcim.png
Normal file
BIN
HMCL/src/main/resources/assets/img/mcim.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 503 B |
@@ -39,6 +39,8 @@ about.thanks_to.zekerzhayard.statement=Contribute a lot of technical support to
|
|||||||
about.thanks_to.zkitefly.statement=Responsible for maintaining the documentation of HMCL.
|
about.thanks_to.zkitefly.statement=Responsible for maintaining the documentation of HMCL.
|
||||||
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
|
about.thanks_to.mcbbs=MCBBS (Minecraft Chinese Forum)
|
||||||
about.thanks_to.mcbbs.statement=For providing the mcbbs.net download mirror for Chinese Mainland users. (No longer available)
|
about.thanks_to.mcbbs.statement=For providing the mcbbs.net download mirror for Chinese Mainland users. (No longer available)
|
||||||
|
about.thanks_to.mcim=mcmod-info-mirror
|
||||||
|
about.thanks_to.mcim.statement=Provides mod information cache acceleration service
|
||||||
about.thanks_to.mcmod=MCMod (mcmod.cn)
|
about.thanks_to.mcmod=MCMod (mcmod.cn)
|
||||||
about.thanks_to.mcmod.statement=For providing the Simplified Chinese translations and wiki for various mods.
|
about.thanks_to.mcmod.statement=For providing the Simplified Chinese translations and wiki for various mods.
|
||||||
about.thanks_to.red_lnn.statement=For providing the default background image.
|
about.thanks_to.red_lnn.statement=For providing the default background image.
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ about.thanks_to.zekerzhayard.statement=為 HMCL 貢獻許多技術支援
|
|||||||
about.thanks_to.zkitefly.statement=負責維護 HMCL 的文件
|
about.thanks_to.zkitefly.statement=負責維護 HMCL 的文件
|
||||||
about.thanks_to.mcbbs=MCBBS (我的世界中文論壇)
|
about.thanks_to.mcbbs=MCBBS (我的世界中文論壇)
|
||||||
about.thanks_to.mcbbs.statement=提供 MCBBS 下載源 (現已停止服務)
|
about.thanks_to.mcbbs.statement=提供 MCBBS 下載源 (現已停止服務)
|
||||||
|
about.thanks_to.mcim=mcmod-info-mirror
|
||||||
|
about.thanks_to.mcim.statement=提供 Mod 信息緩存加速服務
|
||||||
about.thanks_to.mcmod=MC 百科 (mcmod.cn)
|
about.thanks_to.mcmod=MC 百科 (mcmod.cn)
|
||||||
about.thanks_to.mcmod.statement=提供模組簡體中文名映射表與模組百科
|
about.thanks_to.mcmod.statement=提供模組簡體中文名映射表與模組百科
|
||||||
about.thanks_to.red_lnn.statement=提供預設背景圖
|
about.thanks_to.red_lnn.statement=提供預設背景圖
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ about.thanks_to.zekerzhayard.statement=为 HMCL 贡献许多技术支持
|
|||||||
about.thanks_to.zkitefly.statement=负责维护 HMCL 的文档
|
about.thanks_to.zkitefly.statement=负责维护 HMCL 的文档
|
||||||
about.thanks_to.mcbbs=MCBBS (我的世界中文论坛)
|
about.thanks_to.mcbbs=MCBBS (我的世界中文论坛)
|
||||||
about.thanks_to.mcbbs.statement=提供 MCBBS 下载源 (现已停止服务)
|
about.thanks_to.mcbbs.statement=提供 MCBBS 下载源 (现已停止服务)
|
||||||
|
about.thanks_to.mcim=mcmod-info-mirror
|
||||||
|
about.thanks_to.mcim.statement=提供 Mod 信息缓存加速服务
|
||||||
about.thanks_to.mcmod=MC 百科 (mcmod.cn)
|
about.thanks_to.mcmod=MC 百科 (mcmod.cn)
|
||||||
about.thanks_to.mcmod.statement=提供模组简体中文名映射表与模组百科
|
about.thanks_to.mcmod.statement=提供模组简体中文名映射表与模组百科
|
||||||
about.thanks_to.red_lnn.statement=提供默认背景图
|
about.thanks_to.red_lnn.statement=提供默认背景图
|
||||||
|
|||||||
@@ -78,7 +78,14 @@ public final class BMCLAPIDownloadProvider implements DownloadProvider {
|
|||||||
pair("https://maven.fabricmc.net", apiRoot + "/maven"),
|
pair("https://maven.fabricmc.net", apiRoot + "/maven"),
|
||||||
pair("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector"),
|
pair("https://authlib-injector.yushi.moe", apiRoot + "/mirrors/authlib-injector"),
|
||||||
pair("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
|
pair("https://repo1.maven.org/maven2", "https://mirrors.cloud.tencent.com/nexus/repository/maven-public"),
|
||||||
pair("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto")
|
pair("https://zkitefly.github.io/unlisted-versions-of-minecraft", "https://alist.8mi.tech/d/mirror/unlisted-versions-of-minecraft/Auto"),
|
||||||
|
|
||||||
|
// https://github.com/mcmod-info-mirror/mcim-rust-api
|
||||||
|
pair("https://api.modrinth.com", "https://mod.mcimirror.top/modrinth"),
|
||||||
|
pair("https://cdn.modrinth.com", "https://mod.mcimirror.top"),
|
||||||
|
pair("https://api.curseforge.com", "https://mod.mcimirror.top/curseforge"),
|
||||||
|
pair("https://edge.forgecdn.net", "https://mod.mcimirror.top"),
|
||||||
|
pair("https://mediafilez.forgecdn.net", "https://mod.mcimirror.top")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -83,7 +84,7 @@ public interface RemoteModRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResult search(String gameVersion, @Nullable Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder)
|
SearchResult search(DownloadProvider downloadProvider, String gameVersion, @Nullable Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
Optional<RemoteMod.Version> getRemoteVersionByLocalFile(LocalModFile localModFile, Path file) throws IOException;
|
Optional<RemoteMod.Version> getRemoteVersionByLocalFile(LocalModFile localModFile, Path file) throws IOException;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.mod.curse;
|
package org.jackhuang.hmcl.mod.curse;
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
||||||
@@ -26,6 +27,7 @@ import org.jackhuang.hmcl.util.Pair;
|
|||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.io.HttpRequest;
|
import org.jackhuang.hmcl.util.io.HttpRequest;
|
||||||
import org.jackhuang.hmcl.util.io.JarUtils;
|
import org.jackhuang.hmcl.util.io.JarUtils;
|
||||||
|
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -47,6 +49,13 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
|||||||
|
|
||||||
private static final int WORD_PERFECT_MATCH_WEIGHT = 5;
|
private static final int WORD_PERFECT_MATCH_WEIGHT = 5;
|
||||||
|
|
||||||
|
private static <R extends HttpRequest> R withApiKey(R request) {
|
||||||
|
if (request.getUrl().startsWith(PREFIX) && !apiKey.isEmpty()) {
|
||||||
|
request.header("X-API-KEY", apiKey);
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isAvailable() {
|
public static boolean isAvailable() {
|
||||||
return !apiKey.isEmpty();
|
return !apiKey.isEmpty();
|
||||||
}
|
}
|
||||||
@@ -100,29 +109,28 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
|
public SearchResult search(DownloadProvider downloadProvider, String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sortType, SortOrder sortOrder) throws IOException {
|
||||||
int categoryId = 0;
|
int categoryId = 0;
|
||||||
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
|
if (category != null && category.getSelf() instanceof CurseAddon.Category) {
|
||||||
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
|
categoryId = ((CurseAddon.Category) category.getSelf()).getId();
|
||||||
}
|
}
|
||||||
Response<List<CurseAddon>> response = HttpRequest.GET(PREFIX + "/v1/mods/search",
|
Response<List<CurseAddon>> response = withApiKey(HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v1/mods/search", mapOf(
|
||||||
pair("gameId", "432"),
|
pair("gameId", "432"),
|
||||||
pair("classId", Integer.toString(section)),
|
pair("classId", Integer.toString(section)),
|
||||||
pair("categoryId", Integer.toString(categoryId)),
|
pair("categoryId", Integer.toString(categoryId)),
|
||||||
pair("gameVersion", gameVersion),
|
pair("gameVersion", gameVersion),
|
||||||
pair("searchFilter", searchFilter),
|
pair("searchFilter", searchFilter),
|
||||||
pair("sortField", Integer.toString(toModsSearchSortField(sortType))),
|
pair("sortField", Integer.toString(toModsSearchSortField(sortType))),
|
||||||
pair("sortOrder", toSortOrder(sortOrder)),
|
pair("sortOrder", toSortOrder(sortOrder)),
|
||||||
pair("index", Integer.toString(pageOffset * pageSize)),
|
pair("index", Integer.toString(pageOffset * pageSize)),
|
||||||
pair("pageSize", Integer.toString(pageSize)))
|
pair("pageSize", Integer.toString(pageSize)))))))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
|
.getJson(Response.typeOf(listTypeOf(CurseAddon.class)));
|
||||||
if (searchFilter.isEmpty()) {
|
if (searchFilter.isEmpty()) {
|
||||||
return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize));
|
return new SearchResult(response.getData().stream().map(CurseAddon::toMod), calculateTotalPages(response, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/HMCL-dev/HMCL/issues/1549
|
// https://github.com/HMCL-dev/HMCL/issues/1549
|
||||||
String lowerCaseSearchFilter = searchFilter.toLowerCase();
|
String lowerCaseSearchFilter = searchFilter.toLowerCase(Locale.ROOT);
|
||||||
Map<String, Integer> searchFilterWords = new HashMap<>();
|
Map<String, Integer> searchFilterWords = new HashMap<>();
|
||||||
for (String s : StringUtils.tokenize(lowerCaseSearchFilter)) {
|
for (String s : StringUtils.tokenize(lowerCaseSearchFilter)) {
|
||||||
searchFilterWords.put(s, searchFilterWords.getOrDefault(s, 0) + 1);
|
searchFilterWords.put(s, searchFilterWords.getOrDefault(s, 0) + 1);
|
||||||
@@ -162,9 +170,8 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
|||||||
|
|
||||||
long hash = Integer.toUnsignedLong(MurmurHash2.hash32(baos.toByteArray(), baos.size(), 1));
|
long hash = Integer.toUnsignedLong(MurmurHash2.hash32(baos.toByteArray(), baos.size(), 1));
|
||||||
|
|
||||||
Response<FingerprintMatchesResult> response = HttpRequest.POST(PREFIX + "/v1/fingerprints/432")
|
Response<FingerprintMatchesResult> response = withApiKey(HttpRequest.POST(PREFIX + "/v1/fingerprints/432"))
|
||||||
.json(mapOf(pair("fingerprints", Collections.singletonList(hash))))
|
.json(mapOf(pair("fingerprints", Collections.singletonList(hash))))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(FingerprintMatchesResult.class));
|
.getJson(Response.typeOf(FingerprintMatchesResult.class));
|
||||||
|
|
||||||
if (response.getData().getExactMatches() == null || response.getData().getExactMatches().isEmpty()) {
|
if (response.getData().getExactMatches() == null || response.getData().getExactMatches().isEmpty()) {
|
||||||
@@ -176,32 +183,28 @@ public final class CurseForgeRemoteModRepository implements RemoteModRepository
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RemoteMod getModById(String id) throws IOException {
|
public RemoteMod getModById(String id) throws IOException {
|
||||||
Response<CurseAddon> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id)
|
Response<CurseAddon> response = withApiKey(HttpRequest.GET(PREFIX + "/v1/mods/" + id))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(CurseAddon.class));
|
.getJson(Response.typeOf(CurseAddon.class));
|
||||||
return response.data.toMod();
|
return response.data.toMod();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RemoteMod.File getModFile(String modId, String fileId) throws IOException {
|
public RemoteMod.File getModFile(String modId, String fileId) throws IOException {
|
||||||
Response<CurseAddon.LatestFile> response = HttpRequest.GET(String.format("%s/v1/mods/%s/files/%s", PREFIX, modId, fileId))
|
Response<CurseAddon.LatestFile> response = withApiKey(HttpRequest.GET(String.format("%s/v1/mods/%s/files/%s", PREFIX, modId, fileId)))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(CurseAddon.LatestFile.class));
|
.getJson(Response.typeOf(CurseAddon.LatestFile.class));
|
||||||
return response.getData().toVersion().getFile();
|
return response.getData().toVersion().getFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException {
|
public Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException {
|
||||||
Response<List<CurseAddon.LatestFile>> response = HttpRequest.GET(PREFIX + "/v1/mods/" + id + "/files",
|
Response<List<CurseAddon.LatestFile>> response = withApiKey(HttpRequest.GET(PREFIX + "/v1/mods/" + id + "/files",
|
||||||
pair("pageSize", "10000"))
|
pair("pageSize", "10000")))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(listTypeOf(CurseAddon.LatestFile.class)));
|
.getJson(Response.typeOf(listTypeOf(CurseAddon.LatestFile.class)));
|
||||||
return response.getData().stream().map(CurseAddon.LatestFile::toVersion);
|
return response.getData().stream().map(CurseAddon.LatestFile::toVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CurseAddon.Category> getCategoriesImpl() throws IOException {
|
public List<CurseAddon.Category> getCategoriesImpl() throws IOException {
|
||||||
Response<List<CurseAddon.Category>> categories = HttpRequest.GET(PREFIX + "/v1/categories", pair("gameId", "432"))
|
Response<List<CurseAddon.Category>> categories = withApiKey(HttpRequest.GET(PREFIX + "/v1/categories", pair("gameId", "432")))
|
||||||
.header("X-API-KEY", apiKey)
|
|
||||||
.getJson(Response.typeOf(listTypeOf(CurseAddon.Category.class)));
|
.getJson(Response.typeOf(listTypeOf(CurseAddon.Category.class)));
|
||||||
return reorganizeCategories(categories.getData(), section);
|
return reorganizeCategories(categories.getData(), section);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.mod.modrinth;
|
|||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
@@ -79,7 +80,7 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchResult search(String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
|
public SearchResult search(DownloadProvider downloadProvider, String gameVersion, @Nullable RemoteModRepository.Category category, int pageOffset, int pageSize, String searchFilter, SortType sort, SortOrder sortOrder) throws IOException {
|
||||||
List<List<String>> facets = new ArrayList<>();
|
List<List<String>> facets = new ArrayList<>();
|
||||||
facets.add(Collections.singletonList("project_type:" + projectType));
|
facets.add(Collections.singletonList("project_type:" + projectType));
|
||||||
if (StringUtils.isNotBlank(gameVersion)) {
|
if (StringUtils.isNotBlank(gameVersion)) {
|
||||||
@@ -95,7 +96,7 @@ public final class ModrinthRemoteModRepository implements RemoteModRepository {
|
|||||||
pair("limit", Integer.toString(pageSize)),
|
pair("limit", Integer.toString(pageSize)),
|
||||||
pair("index", convertSortType(sort))
|
pair("index", convertSortType(sort))
|
||||||
);
|
);
|
||||||
Response<ProjectSearchResult> response = HttpRequest.GET(NetworkUtils.withQuery(PREFIX + "/v2/search", query))
|
Response<ProjectSearchResult> response = HttpRequest.GET(downloadProvider.injectURL(NetworkUtils.withQuery(PREFIX + "/v2/search", query)))
|
||||||
.getJson(Response.typeOf(ProjectSearchResult.class));
|
.getJson(Response.typeOf(ProjectSearchResult.class));
|
||||||
return new SearchResult(response.getHits().stream().map(ProjectSearchResult::toMod), (int) Math.ceil((double) response.totalHits / pageSize));
|
return new SearchResult(response.getHits().stream().map(ProjectSearchResult::toMod), (int) Math.ceil((double) response.totalHits / pageSize));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,12 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
|||||||
public final class CacheFileTask extends FetchTask<Path> {
|
public final class CacheFileTask extends FetchTask<Path> {
|
||||||
|
|
||||||
public CacheFileTask(@NotNull String uri) {
|
public CacheFileTask(@NotNull String uri) {
|
||||||
super(List.of(NetworkUtils.toURI(uri)));
|
this(NetworkUtils.toURI(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CacheFileTask(@NotNull URI uri) {
|
public CacheFileTask(@NotNull URI uri) {
|
||||||
super(List.of(uri));
|
super(List.of(uri));
|
||||||
|
setName(uri.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ public abstract class HttpRequest {
|
|||||||
this.method = method;
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpRequest accept(String contentType) {
|
public HttpRequest accept(String contentType) {
|
||||||
return header("Accept", contentType);
|
return header("Accept", contentType);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user