Feature: Download Terracotta binary from Gitee, CNB, alist (sponsored by 8mi) first in China mainland. (#4700)

Co-authored-by: Glavo <zjx001202@gmail.com>
This commit is contained in:
Burning_TNT
2025-10-19 21:03:32 +08:00
committed by GitHub
parent 94ca81035b
commit d66c080dea
4 changed files with 51 additions and 38 deletions

View File

@@ -23,7 +23,9 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
import org.jackhuang.hmcl.terracotta.provider.GeneralProvider; import org.jackhuang.hmcl.terracotta.provider.GeneralProvider;
import org.jackhuang.hmcl.terracotta.provider.ITerracottaProvider; import org.jackhuang.hmcl.terracotta.provider.ITerracottaProvider;
import org.jackhuang.hmcl.terracotta.provider.MacOSProvider; import org.jackhuang.hmcl.terracotta.provider.MacOSProvider;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.i18n.LocaleUtils;
import org.jackhuang.hmcl.util.i18n.LocalizedText; import org.jackhuang.hmcl.util.i18n.LocalizedText;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
@@ -61,11 +63,14 @@ public final class TerracottaMetadata {
@SerializedName("classifiers") Map<String, String> classifiers, @SerializedName("classifiers") Map<String, String> classifiers,
@SerializedName("downloads") List<String> downloads, @SerializedName("downloads") List<String> downloads,
@SerializedName("downloads_CN") List<String> downloadsCN,
@SerializedName("links") List<Link> links @SerializedName("links") List<Link> links
) { ) {
private TerracottaNative of(String classifier) { private TerracottaNative of(String classifier) {
List<URI> links = new ArrayList<>(this.downloads.size()); List<URI> links = new ArrayList<>(this.downloads.size() + this.downloadsCN.size());
for (String download : this.downloads) { for (String download : LocaleUtils.IS_CHINA_MAINLAND
? Lang.merge(this.downloadsCN, this.downloads)
: Lang.merge(this.downloads, this.downloadsCN)) {
links.add(URI.create(download.replace("${version}", this.latest).replace("${classifier}", classifier))); links.add(URI.create(download.replace("${version}", this.latest).replace("${classifier}", classifier)));
} }

View File

@@ -19,7 +19,13 @@ package org.jackhuang.hmcl.ui.account;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@@ -45,51 +51,23 @@ import org.jackhuang.hmcl.util.i18n.LocaleUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.BindingMapping;
import org.jackhuang.hmcl.util.javafx.MappedObservableList; import org.jackhuang.hmcl.util.javafx.MappedObservableList;
import org.jackhuang.hmcl.util.platform.NativeUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.windows.Kernel32;
import org.jackhuang.hmcl.util.platform.windows.WinConstants;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Locale; import java.util.Locale;
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig; import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public final class AccountListPage extends DecoratorAnimatedPage implements DecoratorPage { public final class AccountListPage extends DecoratorAnimatedPage implements DecoratorPage {
static final BooleanProperty RESTRICTED = new SimpleBooleanProperty(true); static final BooleanProperty RESTRICTED = new SimpleBooleanProperty(true);
private static boolean isExemptedRegion() {
if ("Asia/Shanghai".equals(ZoneId.systemDefault().getId()))
return true;
// Check if the time zone is UTC+8
if (ZonedDateTime.now().getOffset().getTotalSeconds() == Duration.ofHours(8).toSeconds()) {
if ("CN".equals(LocaleUtils.SYSTEM_DEFAULT.getCountry()))
return true;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && NativeUtils.USE_JNA) {
Kernel32 kernel32 = Kernel32.INSTANCE;
// https://learn.microsoft.com/windows/win32/intl/table-of-geographical-locations
if (kernel32 != null && kernel32.GetUserGeoID(WinConstants.GEOCLASS_NATION) == 45) // China
return true;
}
}
return false;
}
static { static {
String property = System.getProperty("hmcl.offline.auth.restricted", "auto"); String property = System.getProperty("hmcl.offline.auth.restricted", "auto");
if ("false".equals(property) if ("false".equals(property)
|| "auto".equals(property) && isExemptedRegion() || "auto".equals(property) && LocaleUtils.IS_CHINA_MAINLAND
|| globalConfig().isEnableOfflineAccount()) || globalConfig().isEnableOfflineAccount())
RESTRICTED.set(false); RESTRICTED.set(false);
else else

View File

@@ -15,12 +15,12 @@
"windows-x86_64.exe": "sha256:de518b2b4e60336fd272092326799966efc4e72acd65576d83e61d4d242fd61d" "windows-x86_64.exe": "sha256:de518b2b4e60336fd272092326799966efc4e72acd65576d83e61d4d242fd61d"
}, },
"downloads": [ "downloads": [
"https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}", "https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}"
],
"downloads_CN": [
"https://gitee.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}", "https://gitee.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}",
"https://alist.8mi.tech/d/mirror/HMCL-Terracotta/Auto/v${version}/terracotta-${version}-${classifier}", "https://cnb.cool/HMCL-Terracotta/Terracotta/-/releases/download/v${version}/terracotta-${version}-${classifier}",
"https://ghfast.top/https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}", "https://alist.8mi.tech/d/mirror/HMCL-Terracotta/Auto/v${version}/terracotta-${version}-${classifier}"
"https://cdn.crashmc.com/https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}",
"https://cp.zkitefly.eu.org/https://github.com/burningtnt/Terracotta/releases/download/v${version}/terracotta-${version}-${classifier}"
], ],
"links": [ "links": [
{ {

View File

@@ -20,6 +20,10 @@ package org.jackhuang.hmcl.util.i18n;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.IOUtils;
import org.jackhuang.hmcl.util.platform.NativeUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.windows.Kernel32;
import org.jackhuang.hmcl.util.platform.windows.WinConstants;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
@@ -27,6 +31,9 @@ import org.jetbrains.annotations.Unmodifiable;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@@ -385,6 +392,29 @@ public final class LocaleUtils {
return "zh".equals(getRootLanguage(locale)); return "zh".equals(getRootLanguage(locale));
} }
public static final boolean IS_CHINA_MAINLAND = isChinaMainland();
private static boolean isChinaMainland() {
if ("Asia/Shanghai".equals(ZoneId.systemDefault().getId()))
return true;
// Check if the time zone is UTC+8
if (ZonedDateTime.now().getOffset().getTotalSeconds() == Duration.ofHours(8).toSeconds()) {
if ("CN".equals(LocaleUtils.SYSTEM_DEFAULT.getCountry()))
return true;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS && NativeUtils.USE_JNA) {
Kernel32 kernel32 = Kernel32.INSTANCE;
// https://learn.microsoft.com/windows/win32/intl/table-of-geographical-locations
if (kernel32 != null && kernel32.GetUserGeoID(WinConstants.GEOCLASS_NATION) == 45) // China
return true;
}
}
return false;
}
private LocaleUtils() { private LocaleUtils() {
} }
} }