mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-02-23 17:19:44 +08:00
parent
edd95ad626
commit
d4579852bb
@ -17,18 +17,30 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.main;
|
package org.jackhuang.hmcl.ui.main;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
import org.jackhuang.hmcl.ui.construct.ComponentList;
|
||||||
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem;
|
||||||
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
public class AboutPage extends StackPane {
|
public final class AboutPage extends StackPane {
|
||||||
|
|
||||||
public AboutPage() {
|
public AboutPage() {
|
||||||
ComponentList about = new ComponentList();
|
ComponentList about = new ComponentList();
|
||||||
@ -48,131 +60,9 @@ public class AboutPage extends StackPane {
|
|||||||
about.getContent().setAll(launcher, author);
|
about.getContent().setAll(launcher, author);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentList thanks = new ComponentList();
|
ComponentList thanks = loadIconedTwoLineList("/assets/about/thanks.json");
|
||||||
{
|
|
||||||
IconedTwoLineListItem yushijinhun = new IconedTwoLineListItem();
|
|
||||||
yushijinhun.setImage(FXUtils.newBuiltinImage("/assets/img/yushijinhun.png"));
|
|
||||||
yushijinhun.setTitle("yushijinhun");
|
|
||||||
yushijinhun.setSubtitle(i18n("about.thanks_to.yushijinhun.statement"));
|
|
||||||
yushijinhun.setExternalLink("https://yushi.moe/");
|
|
||||||
|
|
||||||
IconedTwoLineListItem bangbang93 = new IconedTwoLineListItem();
|
ComponentList deps = loadIconedTwoLineList("/assets/about/deps.json");
|
||||||
bangbang93.setImage(FXUtils.newBuiltinImage("/assets/img/bangbang93.png"));
|
|
||||||
bangbang93.setTitle("bangbang93");
|
|
||||||
bangbang93.setSubtitle(i18n("about.thanks_to.bangbang93.statement"));
|
|
||||||
bangbang93.setExternalLink("https://bmclapi2.bangbang93.com/");
|
|
||||||
|
|
||||||
IconedTwoLineListItem glavo = new IconedTwoLineListItem();
|
|
||||||
glavo.setImage(FXUtils.newBuiltinImage("/assets/img/glavo.png"));
|
|
||||||
glavo.setTitle("Glavo");
|
|
||||||
glavo.setSubtitle(i18n("about.thanks_to.glavo.statement"));
|
|
||||||
glavo.setExternalLink("https://github.com/Glavo");
|
|
||||||
|
|
||||||
IconedTwoLineListItem zekerzhayard = new IconedTwoLineListItem();
|
|
||||||
zekerzhayard.setImage(FXUtils.newBuiltinImage("/assets/img/zekerzhayard.png"));
|
|
||||||
zekerzhayard.setTitle("ZekerZhayard");
|
|
||||||
zekerzhayard.setSubtitle(i18n("about.thanks_to.zekerzhayard.statement"));
|
|
||||||
zekerzhayard.setExternalLink("https://github.com/ZekerZhayard");
|
|
||||||
|
|
||||||
IconedTwoLineListItem zkitefly = new IconedTwoLineListItem();
|
|
||||||
zkitefly.setImage(FXUtils.newBuiltinImage("/assets/img/zkitefly.png"));
|
|
||||||
zkitefly.setTitle("Zkitefly");
|
|
||||||
zkitefly.setSubtitle(i18n("about.thanks_to.zkitefly.statement"));
|
|
||||||
zkitefly.setExternalLink("https://github.com/zkitefly");
|
|
||||||
|
|
||||||
IconedTwoLineListItem burningtnt = new IconedTwoLineListItem();
|
|
||||||
burningtnt.setImage(FXUtils.newBuiltinImage("/assets/img/burningtnt.png"));
|
|
||||||
burningtnt.setTitle("Burning_TNT");
|
|
||||||
burningtnt.setSubtitle(i18n("about.thanks_to.burningtnt.statement"));
|
|
||||||
burningtnt.setExternalLink("https://github.com/burningtnt");
|
|
||||||
|
|
||||||
IconedTwoLineListItem shulkerSakura = new IconedTwoLineListItem();
|
|
||||||
shulkerSakura.setTitle("ShulkerSakura");
|
|
||||||
shulkerSakura.setImage(FXUtils.newBuiltinImage("/assets/img/ShulkerSakura.png"));
|
|
||||||
shulkerSakura.setSubtitle(i18n("about.thanks_to.shulkersakura.statement"));
|
|
||||||
shulkerSakura.setExternalLink("https://github.com/ShulkerSakura");
|
|
||||||
|
|
||||||
IconedTwoLineListItem gamerteam = new IconedTwoLineListItem();
|
|
||||||
gamerteam.setTitle("gamerteam");
|
|
||||||
gamerteam.setImage(FXUtils.newBuiltinImage("/assets/img/gamerteam.png"));
|
|
||||||
gamerteam.setSubtitle(i18n("about.thanks_to.gamerteam.statement"));
|
|
||||||
gamerteam.setExternalLink("http://www.zhaisoul.com/");
|
|
||||||
|
|
||||||
IconedTwoLineListItem redLnn = new IconedTwoLineListItem();
|
|
||||||
redLnn.setTitle("Red_lnn");
|
|
||||||
redLnn.setImage(FXUtils.newBuiltinImage("/assets/img/red_lnn.png"));
|
|
||||||
redLnn.setSubtitle(i18n("about.thanks_to.red_lnn.statement"));
|
|
||||||
|
|
||||||
IconedTwoLineListItem mcmod = new IconedTwoLineListItem();
|
|
||||||
mcmod.setImage(FXUtils.newBuiltinImage("/assets/img/mcmod.png"));
|
|
||||||
mcmod.setTitle(i18n("about.thanks_to.mcmod"));
|
|
||||||
mcmod.setSubtitle(i18n("about.thanks_to.mcmod.statement"));
|
|
||||||
mcmod.setExternalLink("https://www.mcmod.cn/");
|
|
||||||
|
|
||||||
IconedTwoLineListItem mcbbs = new IconedTwoLineListItem();
|
|
||||||
mcbbs.setImage(FXUtils.newBuiltinImage("/assets/img/chest.png"));
|
|
||||||
mcbbs.setTitle(i18n("about.thanks_to.mcbbs"));
|
|
||||||
mcbbs.setSubtitle(i18n("about.thanks_to.mcbbs.statement"));
|
|
||||||
|
|
||||||
IconedTwoLineListItem contributors = new IconedTwoLineListItem();
|
|
||||||
contributors.setImage(FXUtils.newBuiltinImage("/assets/img/github.png"));
|
|
||||||
contributors.setTitle(i18n("about.thanks_to.contributors"));
|
|
||||||
contributors.setSubtitle(i18n("about.thanks_to.contributors.statement"));
|
|
||||||
contributors.setExternalLink("https://github.com/HMCL-dev/HMCL/graphs/contributors");
|
|
||||||
|
|
||||||
IconedTwoLineListItem users = new IconedTwoLineListItem();
|
|
||||||
users.setImage(FXUtils.newBuiltinImage("/assets/img/icon.png"));
|
|
||||||
users.setTitle(i18n("about.thanks_to.users"));
|
|
||||||
users.setSubtitle(i18n("about.thanks_to.users.statement"));
|
|
||||||
users.setExternalLink("https://docs.hmcl.net/groups.html");
|
|
||||||
|
|
||||||
thanks.getContent().setAll(yushijinhun, bangbang93, glavo, zekerzhayard, zkitefly, burningtnt, mcmod, mcbbs, shulkerSakura, gamerteam, redLnn, contributors, users);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentList dep = new ComponentList();
|
|
||||||
{
|
|
||||||
IconedTwoLineListItem javafx = new IconedTwoLineListItem();
|
|
||||||
javafx.setTitle("JavaFX");
|
|
||||||
javafx.setSubtitle("Copyright © 2013, 2024, Oracle and/or its affiliates.\nLicensed under the GPL 2 with Classpath Exception.");
|
|
||||||
javafx.setExternalLink("https://openjfx.io/");
|
|
||||||
|
|
||||||
IconedTwoLineListItem jfoenix = new IconedTwoLineListItem();
|
|
||||||
jfoenix.setTitle("JFoenix");
|
|
||||||
jfoenix.setSubtitle("Copyright © 2016 JFoenix.\nLicensed under the MIT License.");
|
|
||||||
jfoenix.setExternalLink("https://github.com/sshahine/JFoenix");
|
|
||||||
|
|
||||||
IconedTwoLineListItem gson = new IconedTwoLineListItem();
|
|
||||||
gson.setTitle("Gson");
|
|
||||||
gson.setSubtitle("Copyright © 2008 Google Inc.\nLicensed under the Apache 2.0 License.");
|
|
||||||
gson.setExternalLink("https://github.com/google/gson");
|
|
||||||
|
|
||||||
IconedTwoLineListItem xz = new IconedTwoLineListItem();
|
|
||||||
xz.setTitle("XZ for Java");
|
|
||||||
xz.setSubtitle("Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain.");
|
|
||||||
xz.setExternalLink("https://tukaani.org/xz/java.html");
|
|
||||||
|
|
||||||
IconedTwoLineListItem fxgson = new IconedTwoLineListItem();
|
|
||||||
fxgson.setTitle("fx-gson");
|
|
||||||
fxgson.setSubtitle("Copyright © 2016 Joffrey Bion.\nLicensed under the MIT License.");
|
|
||||||
fxgson.setExternalLink("https://github.com/joffrey-bion/fx-gson");
|
|
||||||
|
|
||||||
IconedTwoLineListItem constantPoolScanner = new IconedTwoLineListItem();
|
|
||||||
constantPoolScanner.setTitle("Constant Pool Scanner");
|
|
||||||
constantPoolScanner.setSubtitle("Copyright © 1997-2010 Oracle and/or its affiliates.\nLicensed under the GPL 2 or the CDDL.");
|
|
||||||
constantPoolScanner.setExternalLink("https://github.com/jenkinsci/constant-pool-scanner");
|
|
||||||
|
|
||||||
IconedTwoLineListItem openNBT = new IconedTwoLineListItem();
|
|
||||||
openNBT.setTitle("OpenNBT");
|
|
||||||
openNBT.setSubtitle("Copyright © 2013-2021 Steveice10.\nLicensed under the MIT License.");
|
|
||||||
openNBT.setExternalLink("https://github.com/GeyserMC/OpenNBT");
|
|
||||||
|
|
||||||
IconedTwoLineListItem minecraftJFXSkin = new IconedTwoLineListItem();
|
|
||||||
minecraftJFXSkin.setTitle("minecraft-jfx-skin");
|
|
||||||
minecraftJFXSkin.setSubtitle("Copyright © 2016 InfinityStudio.\nLicensed under the GPL 3.");
|
|
||||||
minecraftJFXSkin.setExternalLink("https://github.com/InfinityStudio/minecraft-jfx-skin");
|
|
||||||
|
|
||||||
dep.getContent().setAll(javafx, jfoenix, gson, xz, fxgson, constantPoolScanner, openNBT, minecraftJFXSkin);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentList legal = new ComponentList();
|
ComponentList legal = new ComponentList();
|
||||||
{
|
{
|
||||||
@ -204,7 +94,7 @@ public class AboutPage extends StackPane {
|
|||||||
thanks,
|
thanks,
|
||||||
|
|
||||||
ComponentList.createComponentListTitle(i18n("about.dependency")),
|
ComponentList.createComponentListTitle(i18n("about.dependency")),
|
||||||
dep,
|
deps,
|
||||||
|
|
||||||
ComponentList.createComponentListTitle(i18n("about.legal")),
|
ComponentList.createComponentListTitle(i18n("about.legal")),
|
||||||
legal
|
legal
|
||||||
@ -216,4 +106,49 @@ public class AboutPage extends StackPane {
|
|||||||
FXUtils.smoothScrolling(scrollPane);
|
FXUtils.smoothScrolling(scrollPane);
|
||||||
getChildren().setAll(scrollPane);
|
getChildren().setAll(scrollPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ComponentList loadIconedTwoLineList(String path) {
|
||||||
|
ComponentList componentList = new ComponentList();
|
||||||
|
|
||||||
|
InputStream input = FXUtils.class.getResourceAsStream(path);
|
||||||
|
if (input == null) {
|
||||||
|
LOG.warning("Resources not found: " + path);
|
||||||
|
return componentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Reader reader = new InputStreamReader(input)) {
|
||||||
|
JsonArray array = JsonUtils.GSON.fromJson(reader, JsonArray.class);
|
||||||
|
|
||||||
|
for (JsonElement element : array) {
|
||||||
|
JsonObject obj = element.getAsJsonObject();
|
||||||
|
IconedTwoLineListItem item = new IconedTwoLineListItem();
|
||||||
|
|
||||||
|
if (obj.has("image")) {
|
||||||
|
String image = obj.get("image").getAsString();
|
||||||
|
item.setImage(image.startsWith("/")
|
||||||
|
? FXUtils.newBuiltinImage(image)
|
||||||
|
: new Image(image));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.has("title"))
|
||||||
|
item.setTitle(obj.get("title").getAsString());
|
||||||
|
else if (obj.has("titleLocalized"))
|
||||||
|
item.setTitle(i18n(obj.get("titleLocalized").getAsString()));
|
||||||
|
|
||||||
|
if (obj.has("subtitle"))
|
||||||
|
item.setSubtitle(obj.get("subtitle").getAsString());
|
||||||
|
else if (obj.has("subtitleLocalized"))
|
||||||
|
item.setSubtitle(i18n(obj.get("subtitleLocalized").getAsString()));
|
||||||
|
|
||||||
|
if (obj.has("externalLink"))
|
||||||
|
item.setExternalLink(obj.get("externalLink").getAsString());
|
||||||
|
|
||||||
|
componentList.getContent().add(item);
|
||||||
|
}
|
||||||
|
} catch (IOException | JsonParseException e) {
|
||||||
|
LOG.warning("Failed to load list: " + path, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
62
HMCL/src/main/resources/assets/about/deps.json
Normal file
62
HMCL/src/main/resources/assets/about/deps.json
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"title" : "OpenJFX",
|
||||||
|
"subtitle" : "Copyright © 2013, 2024, Oracle and/or its affiliates.\nLicensed under the GPL 2 with Classpath Exception.",
|
||||||
|
"externalLink" : "https://openjfx.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "JFoenix",
|
||||||
|
"subtitle" : "Copyright © 2016 JFoenix.\nLicensed under the MIT License.",
|
||||||
|
"externalLink" : "https://github.com/sshahine/JFoenix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "Gson",
|
||||||
|
"subtitle" : "Copyright © 2008 Google Inc.\nLicensed under the Apache 2.0 License.",
|
||||||
|
"externalLink" : "https://github.com/google/gson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "Apache Commons Compress",
|
||||||
|
"subtitle" : "Licensed under the Apache 2.0 License.",
|
||||||
|
"externalLink" : "https://commons.apache.org/proper/commons-compress/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "XZ for Java",
|
||||||
|
"subtitle" : "Lasse Collin, Igor Pavlov, and/or Brett Okken.\nPublic Domain.",
|
||||||
|
"externalLink" : "https://tukaani.org/xz/java.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "FX Gson",
|
||||||
|
"subtitle" : "Copyright © 2016 Joffrey Bion.\nLicensed under the MIT License.",
|
||||||
|
"externalLink" : "https://github.com/joffrey-bion/fx-gson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "jsoup",
|
||||||
|
"subtitle" : "Copyright © 2009 - 2024 Jonathan Hedley (https://jsoup.org/)\nLicensed under the MIT License.",
|
||||||
|
"externalLink" : "https://jsoup.org/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "NanoHTTPD",
|
||||||
|
"subtitle" : "Copyright © 2012 - 2015 nanohttpd.\nLicensed under the BSD 3-clause License.",
|
||||||
|
"externalLink" : "https://github.com/NanoHttpd/nanohttpd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "Constant Pool Scanner",
|
||||||
|
"subtitle" : "Copyright © 1997-2010 Oracle and/or its affiliates.\nLicensed under the GPL 2 or the CDDL.",
|
||||||
|
"externalLink" : "https://github.com/jenkinsci/constant-pool-scanner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "OpenNBT",
|
||||||
|
"subtitle" : "Copyright © 2013-2021 Steveice10.\nLicensed under the MIT License.",
|
||||||
|
"externalLink" : "https://github.com/GeyserMC/OpenNBT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "minecraft-jfx-skin",
|
||||||
|
"subtitle" : "Copyright © 2016 InfinityStudio.\nLicensed under the GPL 3.",
|
||||||
|
"externalLink" : "https://github.com/InfinityStudio/minecraft-jfx-skin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title" : "SimplePNG",
|
||||||
|
"subtitle" : "Copyright © 2023 Glavo.\nLicensed under the Apache 2.0 License.",
|
||||||
|
"externalLink" : "https://github.com/Glavo/SimplePNG"
|
||||||
|
}
|
||||||
|
]
|
78
HMCL/src/main/resources/assets/about/thanks.json
Normal file
78
HMCL/src/main/resources/assets/about/thanks.json
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/yushijinhun.png",
|
||||||
|
"title" : "yushijinhun",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.yushijinhun.statement",
|
||||||
|
"externalLink" : "https://github.com/yushijinhun"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/bangbang93.png",
|
||||||
|
"title" : "bangbang93",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.bangbang93.statement",
|
||||||
|
"externalLink" : "https://www.bangbang93.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/glavo.png",
|
||||||
|
"title" : "Glavo",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.glavo.statement",
|
||||||
|
"externalLink" : "https://github.com/Glavo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/zekerzhayard.png",
|
||||||
|
"title" : "ZekerZhayard",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.zekerzhayard.statement",
|
||||||
|
"externalLink" : "https://github.com/ZekerZhayard"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/zkitefly.png",
|
||||||
|
"title" : "Zkitefly",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.zkitefly.statement",
|
||||||
|
"externalLink" : "https://github.com/zkitefly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/burningtnt.png",
|
||||||
|
"title" : "Burning_TNT",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.burningtnt.statement",
|
||||||
|
"externalLink" : "https://github.com/burningtnt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/ShulkerSakura.png",
|
||||||
|
"title" : "ShulkerSakura",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.shulkersakura.statement",
|
||||||
|
"externalLink" : "https://github.com/ShulkerSakura"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/gamerteam.png",
|
||||||
|
"title" : "gamerteam",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.gamerteam.statement",
|
||||||
|
"externalLink" : "https://github.com/ZhaiSoul"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/red_lnn.png",
|
||||||
|
"title" : "Red_lnn",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.red_lnn.statement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/mcmod.png",
|
||||||
|
"titleLocalized" : "about.thanks_to.mcmod",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.mcmod.statement",
|
||||||
|
"externalLink" : "https://www.mcmod.cn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/chest.png",
|
||||||
|
"titleLocalized" : "about.thanks_to.mcbbs",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.mcbbs.statement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/github.png",
|
||||||
|
"titleLocalized" : "about.thanks_to.contributors",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.contributors.statement",
|
||||||
|
"externalLink" : "https://github.com/HMCL-dev/HMCL/graphs/contributors"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image" : "/assets/img/icon.png",
|
||||||
|
"titleLocalized" : "about.thanks_to.users",
|
||||||
|
"subtitleLocalized" : "about.thanks_to.users.statement",
|
||||||
|
"externalLink" : "https://docs.hmcl.net/groups.html"
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user