diff --git a/README.md b/README.md
index 8fe68eaeaf..af878b78f8 100644
--- a/README.md
+++ b/README.md
@@ -352,6 +352,11 @@ server:
不是的,进度检查器会累加此 IP 地址在特定种子上的下载进度。如果对方出现进度回退、断开更换端口重连、更换 PeerID、更换 Client name 重新下载时,下载器会认为这是一个新客户端,并从头开始计算下载数据(吸血者也使用此手段绕过吸血检查)。但对于 PBH 来说,只要对方 IP 地址未改变(或者处于特定区间内),并且下载的种子未更换的情况下,下载进度会持续增量累积,避免对方欺骗反吸血检查。例如一个文件大小是 1000MB,对方下载 102% 代表对方在这个 1000MB 大小的种子上,实际下载了 1020MB 的数据。
+### PBH 提示我的下载器 “连续多次登录失败” ,并暂停了该怎么办?
+
+您可以点击下载器的编辑按钮,然后直接点击确定保存。PBH 将会解除暂停状态并重新尝试登陆,此时会显示登陆失败的原因。请根据原因进行故障排查(例如:网络连接问题、WebUI
+是否启用、用户名密码是否正确等)
+
## Install4j
PeerBanHelper 使用 [Install4j multi-platform installer builder](https://www.ej-technologies.com/products/install4j/overview.html) 打包多平台安装程序。感谢 ej-technolgies 的开放源代码许可证。点击链接或者下面的图片下载 install4j。
diff --git a/pom.xml b/pom.xml
index dd689a3cc5..ccfa368ff3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.ghostchu.peerbanhelper
peerbanhelper
- 5.0.3
+ 5.0.4
takari-jar
PeerBanHelper
diff --git a/src/main/java/com/ghostchu/peerbanhelper/Main.java b/src/main/java/com/ghostchu/peerbanhelper/Main.java
index 8e60b484e9..1b21ff119c 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/Main.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/Main.java
@@ -26,6 +26,7 @@
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
@@ -36,7 +37,6 @@
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
-import java.util.logging.Level;
@Slf4j
public class Main {
@@ -131,6 +131,7 @@ private static void setupProxySettings() {
if (proxySection == null) return;
String host = proxySection.getString("host");
String port = String.valueOf(proxySection.getInt("port"));
+ String nonProxyHost = proxySection.getString("non-proxy-hosts", "");
switch (proxySection.getInt("setting")) {
case 1 -> System.setProperty("java.net.useSystemProxies", "true");
case 2 -> {
@@ -138,10 +139,13 @@ private static void setupProxySettings() {
System.setProperty("http.proxyPort", port);
System.setProperty("https.proxyHost", host);
System.setProperty("https.proxyPort", port);
+ System.setProperty("http.nonProxyHosts", nonProxyHost);
+ System.setProperty("https.nonProxyHosts", nonProxyHost);
}
case 3 -> {
System.setProperty("socksProxyHost", host);
System.setProperty("socksProxyPort", port);
+ System.setProperty("socksNonProxyHosts", nonProxyHost);
}
default -> System.setProperty("java.net.useSystemProxies", "false");
}
@@ -180,7 +184,7 @@ private static YamlConfiguration loadConfiguration(File file) {
configuration.load(file);
} catch (IOException | InvalidConfigurationException e) {
log.error("Unable to load configuration: invalid YAML configuration // 无法加载配置文件:无效的 YAML 配置,请检查是否有语法错误", e);
- guiManager.createDialog(Level.SEVERE, "Invalid YAML configuration | 无效 YAML 配置文件", String.format("Failed to read configuration: %s", file));
+ JOptionPane.showMessageDialog(null, "Invalid/Corrupted YAML configuration | 无效或损坏的 YAML 配置文件", String.format("Failed to read configuration: %s", file), JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
return configuration;
diff --git a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
index ec4ecec58f..e2e5dd2fac 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
@@ -6,6 +6,7 @@
import com.ghostchu.peerbanhelper.database.dao.impl.BanListDao;
import com.ghostchu.peerbanhelper.downloader.Downloader;
import com.ghostchu.peerbanhelper.downloader.DownloaderLastStatus;
+import com.ghostchu.peerbanhelper.downloader.DownloaderLoginResult;
import com.ghostchu.peerbanhelper.downloader.impl.biglybt.BiglyBT;
import com.ghostchu.peerbanhelper.downloader.impl.deluge.Deluge;
import com.ghostchu.peerbanhelper.downloader.impl.qbittorrent.QBittorrent;
@@ -344,7 +345,7 @@ private void registerBanWaveTimer() {
return thread;
});
log.info(tlUI(Lang.PBH_BAN_WAVE_STARTED));
- BAN_WAVE_SERVICE.scheduleAtFixedRate(this::banWave, 1, profileConfig.getLong("check-interval", 5000), TimeUnit.MILLISECONDS);
+ BAN_WAVE_SERVICE.scheduleWithFixedDelay(this::banWave, 1, profileConfig.getLong("check-interval", 5000), TimeUnit.MILLISECONDS);
}
@@ -598,6 +599,9 @@ public Map> collectPeers(Downloader downloader) {
if (!loginResult.success()) {
log.error(tlUI(Lang.ERR_CLIENT_LOGIN_FAILURE_SKIP, downloader.getName(), downloader.getEndpoint(), tlUI(loginResult.getMessage())));
downloader.setLastStatus(DownloaderLastStatus.ERROR, loginResult.getMessage());
+ if (loginResult.getStatus() == DownloaderLoginResult.Status.MISSING_COMPONENTS || loginResult.getStatus() == DownloaderLoginResult.Status.REQUIRE_TAKE_ACTIONS) {
+ downloader.setLastStatus(DownloaderLastStatus.NEED_TAKE_ACTION, loginResult.getMessage());
+ }
return Collections.emptyMap();
}
List torrents = downloader.getTorrents();
diff --git a/src/main/java/com/ghostchu/peerbanhelper/config/MainConfigUpdateScript.java b/src/main/java/com/ghostchu/peerbanhelper/config/MainConfigUpdateScript.java
index f2ea5172d2..088b254bf6 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/config/MainConfigUpdateScript.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/config/MainConfigUpdateScript.java
@@ -28,6 +28,10 @@ private void validate() {
}
}
+ @UpdateScript(version = 14)
+ public void proxyServerConfigSectionEnhanced() {
+ conf.set("proxy.non-proxy-host", "127.0.0.1|localhost");
+ }
@UpdateScript(version = 13)
public void proxyServerConfigSection() {
conf.set("proxy.setting", 0);
diff --git a/src/main/java/com/ghostchu/peerbanhelper/database/dao/impl/TorrentDao.java b/src/main/java/com/ghostchu/peerbanhelper/database/dao/impl/TorrentDao.java
index f8c95aa2e5..4519b9a11e 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/database/dao/impl/TorrentDao.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/database/dao/impl/TorrentDao.java
@@ -17,9 +17,11 @@ public TorrentDao(@Autowired Database database) throws SQLException {
@Override
public synchronized TorrentEntity createIfNotExists(TorrentEntity data) throws SQLException {
- List list = queryForMatchingArgs(data);
+ List list = queryForEq("infoHash", data.getInfoHash());
if (list.isEmpty()) {
- return super.createIfNotExists(data);
+ long id = create(data);
+ data.setId(id);
+ return data;
}
return list.getFirst();
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/database/table/TorrentEntity.java b/src/main/java/com/ghostchu/peerbanhelper/database/table/TorrentEntity.java
index 3616b06474..f35b02c9ab 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/database/table/TorrentEntity.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/database/table/TorrentEntity.java
@@ -13,9 +13,9 @@
public final class TorrentEntity {
@DatabaseField(generatedId = true)
private Long id;
- @DatabaseField(canBeNull = false, uniqueIndex = true, uniqueCombo = true)
+ @DatabaseField(canBeNull = false, uniqueIndex = true)
private String infoHash;
- @DatabaseField(canBeNull = false, uniqueCombo = true)
+ @DatabaseField(canBeNull = false)
private String name;
@DatabaseField(canBeNull = false)
private Long size;
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/AbstractDownloader.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/AbstractDownloader.java
new file mode 100644
index 0000000000..e84b8f7540
--- /dev/null
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/AbstractDownloader.java
@@ -0,0 +1,69 @@
+package com.ghostchu.peerbanhelper.downloader;
+
+import com.ghostchu.peerbanhelper.text.Lang;
+import com.ghostchu.peerbanhelper.text.TranslationComponent;
+import com.ghostchu.peerbanhelper.util.MsgUtil;
+
+import java.util.Date;
+
+public abstract class AbstractDownloader implements Downloader {
+ protected String name;
+ private DownloaderLastStatus lastStatus = DownloaderLastStatus.UNKNOWN;
+ private TranslationComponent statusMessage;
+ private int failedLoginAttempts = 0;
+ private long nextLoginTry = 0L;
+
+ public AbstractDownloader(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public DownloaderLoginResult login() {
+ if (nextLoginTry >= System.currentTimeMillis()) {
+ return new DownloaderLoginResult(DownloaderLoginResult.Status.REQUIRE_TAKE_ACTIONS
+ , new TranslationComponent(Lang.TOO_MANY_FAILED_ATTEMPT, MsgUtil.getDateFormatter().format(new Date(nextLoginTry)))
+ );
+ }
+ DownloaderLoginResult result;
+ try {
+ result = login0();
+ if (result.success()) {
+ failedLoginAttempts = 0;
+ return result;
+ }
+ failedLoginAttempts++;
+ return result;
+ } catch (Throwable e) {
+ failedLoginAttempts++;
+ throw e;
+ } finally {
+ if (failedLoginAttempts >= 15) {
+ nextLoginTry = System.currentTimeMillis() + (1000 * 60 * 30);
+ failedLoginAttempts = 0;
+ }
+ }
+ }
+
+ public abstract DownloaderLoginResult login0();
+
+ @Override
+ public DownloaderLastStatus getLastStatus() {
+ return lastStatus;
+ }
+
+ @Override
+ public void setLastStatus(DownloaderLastStatus lastStatus, TranslationComponent statusMessage) {
+ this.lastStatus = lastStatus;
+ this.statusMessage = statusMessage;
+ }
+
+ @Override
+ public TranslationComponent getLastStatusMessage() {
+ return statusMessage;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/DownloaderLoginResult.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/DownloaderLoginResult.java
index 8bd7e95b6b..b96133704f 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/DownloaderLoginResult.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/DownloaderLoginResult.java
@@ -22,6 +22,7 @@ public enum Status {
INCORRECT_CREDENTIAL,
MISSING_COMPONENTS,
NETWORK_ERROR,
- EXCEPTION
+ EXCEPTION,
+ REQUIRE_TAKE_ACTIONS
}
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java
index 071a03da5a..20274943b0 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java
@@ -1,7 +1,6 @@
package com.ghostchu.peerbanhelper.downloader.impl.biglybt;
-import com.ghostchu.peerbanhelper.downloader.Downloader;
-import com.ghostchu.peerbanhelper.downloader.DownloaderLastStatus;
+import com.ghostchu.peerbanhelper.downloader.AbstractDownloader;
import com.ghostchu.peerbanhelper.downloader.DownloaderLoginResult;
import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound.BanBean;
import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound.BanListReplacementBean;
@@ -47,17 +46,14 @@
import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;
-public class BiglyBT implements Downloader {
+public class BiglyBT extends AbstractDownloader {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(BiglyBT.class);
private final String apiEndpoint;
private final HttpClient httpClient;
private final Config config;
- private DownloaderLastStatus lastStatus = DownloaderLastStatus.UNKNOWN;
- private String name;
- private TranslationComponent statusMessage;
public BiglyBT(String name, Config config) {
- this.name = name;
+ super(name);
this.config = config;
this.apiEndpoint = config.getEndpoint();
CookieManager cm = new CookieManager();
@@ -100,7 +96,8 @@ public YamlConfiguration saveDownloader() {
return config.saveToYaml();
}
- public DownloaderLoginResult login() {
+ @Override
+ public DownloaderLoginResult login0() {
HttpResponse resp;
try {
resp = httpClient.send(MutableRequest.GET(apiEndpoint + "/metadata"), HttpResponse.BodyHandlers.discarding());
@@ -114,7 +111,6 @@ public DownloaderLoginResult login() {
} catch (Exception e) {
return new DownloaderLoginResult(DownloaderLoginResult.Status.NETWORK_ERROR, new TranslationComponent(Lang.DOWNLOADER_LOGIN_IO_EXCEPTION, e.getClass().getName() + ": " + e.getMessage()));
}
-
}
@Override
@@ -122,31 +118,6 @@ public String getEndpoint() {
return apiEndpoint;
}
-// @Override
-// public String getWebUIEndpoint() {
-// return config.getEndpoint();
-// }
-
-// @Override
-// public @Nullable DownloaderBasicAuth getDownloaderBasicAuth() {
-// return null;
-// }
-//
-// @Override
-// public @Nullable WebViewScriptCallback getWebViewJavaScript() {
-// return null;
-// }
-//
-// @Override
-// public boolean isSupportWebview() {
-// return false;
-// }
-
- @Override
- public String getName() {
- return name;
- }
-
@Override
public String getType() {
return "BiglyBT";
@@ -267,22 +238,6 @@ private void setBanListFull(Collection peerAddresses) {
}
}
- @Override
- public DownloaderLastStatus getLastStatus() {
- return lastStatus;
- }
-
- @Override
- public void setLastStatus(DownloaderLastStatus lastStatus, TranslationComponent statusMessage) {
- this.lastStatus = lastStatus;
- this.statusMessage = statusMessage;
- }
-
- @Override
- public TranslationComponent getLastStatusMessage() {
- return statusMessage;
- }
-
@Override
public void close() {
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java
index 8e83f87e46..a2a733245b 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java
@@ -1,7 +1,6 @@
package com.ghostchu.peerbanhelper.downloader.impl.deluge;
-import com.ghostchu.peerbanhelper.downloader.Downloader;
-import com.ghostchu.peerbanhelper.downloader.DownloaderLastStatus;
+import com.ghostchu.peerbanhelper.downloader.AbstractDownloader;
import com.ghostchu.peerbanhelper.downloader.DownloaderLoginResult;
import com.ghostchu.peerbanhelper.peer.Peer;
import com.ghostchu.peerbanhelper.peer.PeerFlag;
@@ -35,7 +34,7 @@
import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;
-public class Deluge implements Downloader {
+public class Deluge extends AbstractDownloader {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(Deluge.class);
private static final List MUST_HAVE_METHODS = ImmutableList.of(
"peerbanhelperadapter.replace_blocklist",
@@ -43,13 +42,11 @@ public class Deluge implements Downloader {
"peerbanhelperadapter.get_active_torrents_info",
"peerbanhelperadapter.ban_ips"
);
- private final String name;
private final DelugeServer client;
private final Config config;
- private DownloaderLastStatus lastStatus = DownloaderLastStatus.UNKNOWN;
- private TranslationComponent statusMessage;
public Deluge(String name, Config config) {
+ super(name);
this.name = name;
this.config = config;
this.client = new DelugeServer(config.getEndpoint() + config.getRpcUrl(), config.getPassword(), config.isVerifySsl(), HttpClient.Version.valueOf(config.getHttpVersion()), null, null);
@@ -65,8 +62,6 @@ public static Deluge loadFromConfig(String name, JsonObject section) {
return new Deluge(name, config);
}
-
-
@Override
public JsonObject saveDownloaderJson() {
return JsonUtil.getGson().toJsonTree(config).getAsJsonObject();
@@ -82,38 +77,13 @@ public String getEndpoint() {
return config.getEndpoint();
}
-// @Override
-// public String getWebUIEndpoint() {
-// return config.getEndpoint();
-// }
-
-// @Override
-// public @Nullable DownloaderBasicAuth getDownloaderBasicAuth() {
-// return null;
-// }
-//
-// @Override
-// public @Nullable WebViewScriptCallback getWebViewJavaScript() {
-// return null;
-// }
-//
-// @Override
-// public boolean isSupportWebview() {
-// return true;
-// }
-
- @Override
- public String getName() {
- return name;
- }
-
@Override
public String getType() {
return "Deluge";
}
@Override
- public DownloaderLoginResult login() {
+ public DownloaderLoginResult login0() {
try {
if (!this.client.login().isLoggedIn()) {
return new DownloaderLoginResult(DownloaderLoginResult.Status.INCORRECT_CREDENTIAL, new TranslationComponent(Lang.DOWNLOADER_LOGIN_INCORRECT_CRED));
@@ -210,22 +180,6 @@ public void relaunchTorrentIfNeededByTorrentWrapper(Collection t
}
- @Override
- public DownloaderLastStatus getLastStatus() {
- return lastStatus;
- }
-
- @Override
- public void setLastStatus(DownloaderLastStatus lastStatus, TranslationComponent statusMessage) {
- this.lastStatus = lastStatus;
- this.statusMessage = statusMessage;
- }
-
- @Override
- public TranslationComponent getLastStatusMessage() {
- return statusMessage;
- }
-
@Override
public void close() {
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/QBittorrent.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/QBittorrent.java
index d52dafcb51..1172dbc854 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/QBittorrent.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/QBittorrent.java
@@ -1,7 +1,6 @@
package com.ghostchu.peerbanhelper.downloader.impl.qbittorrent;
-import com.ghostchu.peerbanhelper.downloader.Downloader;
-import com.ghostchu.peerbanhelper.downloader.DownloaderLastStatus;
+import com.ghostchu.peerbanhelper.downloader.AbstractDownloader;
import com.ghostchu.peerbanhelper.downloader.DownloaderLoginResult;
import com.ghostchu.peerbanhelper.peer.Peer;
import com.ghostchu.peerbanhelper.text.Lang;
@@ -39,16 +38,12 @@
import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;
@Slf4j
-public class QBittorrent implements Downloader {
+public class QBittorrent extends AbstractDownloader {
private final String apiEndpoint;
private final HttpClient httpClient;
private final Config config;
- private DownloaderLastStatus lastStatus = DownloaderLastStatus.UNKNOWN;
- private String name;
- private TranslationComponent statusMessage;
-
public QBittorrent(String name, Config config) {
- this.name = name;
+ super(name);
this.config = config;
this.apiEndpoint = config.getEndpoint() + "/api/v2";
CookieManager cm = new CookieManager();
@@ -95,7 +90,7 @@ public YamlConfiguration saveDownloader() {
return config.saveToYaml();
}
- public DownloaderLoginResult login() {
+ public DownloaderLoginResult login0() {
if (isLoggedIn())
return new DownloaderLoginResult(DownloaderLoginResult.Status.SUCCESS, new TranslationComponent(Lang.STATUS_TEXT_OK)); // 重用 Session 会话
try {
@@ -124,52 +119,6 @@ public String getEndpoint() {
return apiEndpoint;
}
-// @Override
-// public String getWebUIEndpoint() {
-// return config.getEndpoint();
-// }
-//
-// @Override
-// public @Nullable DownloaderBasicAuth getDownloaderBasicAuth() {
-// if (config.getBasicAuth() != null) {
-// return new DownloaderBasicAuth(config.getEndpoint(), config.getBasicAuth().getUser(), config.getBasicAuth().getPass());
-// }
-// return null;
-// }
-//
-// @Override
-// public @Nullable WebViewScriptCallback getWebViewJavaScript() {
-// return (url, content) -> {
-// if (content.contains("loginform")) {
-// return String.format("""
-// const xhr = new XMLHttpRequest();
-// xhr.open('POST', 'api/v2/auth/login', true);
-// xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=UTF-8');
-// xhr.addEventListener('readystatechange', function() {
-// if (xhr.readyState === 4) { // DONE state
-// if ((xhr.status === 200) && (xhr.responseText === "Ok."))
-// location.reload(true);
-// }
-// }
-// );
-// const queryString = "username=%s&password=%s";
-// xhr.send(queryString);
-// """, UrlEncoderDecoder.encodePath(config.getUsername()), UrlEncoderDecoder.encodePath(config.getPassword()));
-// } else {
-// return null;
-// }
-// };
-// }
-//
-// @Override
-// public boolean isSupportWebview() {
-// return true;
-// }
-
- @Override
- public String getName() {
- return name;
- }
@Override
public String getType() {
@@ -331,25 +280,10 @@ private void setBanListFull(Collection peerAddresses) {
}
@Override
- public DownloaderLastStatus getLastStatus() {
- return lastStatus;
- }
-
- @Override
- public void setLastStatus(DownloaderLastStatus lastStatus, TranslationComponent statusMessage) {
- this.lastStatus = lastStatus;
- this.statusMessage = statusMessage;
- }
+ public void close() throws Exception {
- @Override
- public TranslationComponent getLastStatusMessage() {
- return statusMessage;
}
- @Override
- public void close() {
-
- }
@NoArgsConstructor
@Data
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java
index 6223a68b9a..d73b558af9 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java
@@ -1,7 +1,6 @@
package com.ghostchu.peerbanhelper.downloader.impl.transmission;
-import com.ghostchu.peerbanhelper.downloader.Downloader;
-import com.ghostchu.peerbanhelper.downloader.DownloaderLastStatus;
+import com.ghostchu.peerbanhelper.downloader.AbstractDownloader;
import com.ghostchu.peerbanhelper.downloader.DownloaderLoginResult;
import com.ghostchu.peerbanhelper.peer.Peer;
import com.ghostchu.peerbanhelper.text.Lang;
@@ -34,21 +33,18 @@
import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;
-public class Transmission implements Downloader {
+public class Transmission extends AbstractDownloader {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(Transmission.class);
- private final String name;
private final TrClient client;
private final String blocklistUrl;
private final Config config;
- private DownloaderLastStatus lastStatus = DownloaderLastStatus.UNKNOWN;
- private TranslationComponent statusMessage;
/*
API 受限,实际实现起来意义不大
*/
public Transmission(String name, String blocklistUrl, Config config) {
- this.name = name;
+ super(name);
this.config = config;
this.client = new TrClient(config.getEndpoint() + config.getRpcUrl(), config.getUsername(), config.getPassword(), config.isVerifySsl(), HttpClient.Version.valueOf(config.getHttpVersion()));
this.blocklistUrl = blocklistUrl;
@@ -84,32 +80,6 @@ public String getEndpoint() {
return config.getEndpoint();
}
-// @Override
-// public String getWebUIEndpoint() {
-// return config.getEndpoint();
-// }
-
-// @Override
-// public @Nullable DownloaderBasicAuth getDownloaderBasicAuth() {
-// return new DownloaderBasicAuth(config.getEndpoint(), config.getUsername(), config.getPassword());
-// }
-//
-// @Override
-// public @Nullable WebViewScriptCallback getWebViewJavaScript() {
-// return null;
-// }
-//
-// @Override
-// public boolean isSupportWebview() {
-// return true;
-// }
-
-
- @Override
- public String getName() {
- return name;
- }
-
@Override
public String getType() {
return "Transmission";
@@ -117,7 +87,7 @@ public String getType() {
@SneakyThrows(InterruptedException.class)
@Override
- public DownloaderLoginResult login() {
+ public DownloaderLoginResult login0() {
RqSessionGet get = new RqSessionGet();
TypedResponse resp = client.execute(get); // 执行任意 RPC 操作以刷新 session
String version = resp.getArgs().getVersion();
@@ -211,23 +181,6 @@ public void relaunchTorrentIfNeededByTorrentWrapper(Collection t
}).map(t -> Long.parseLong(t.getId())).toList());
}
- @Override
- public DownloaderLastStatus getLastStatus() {
- return lastStatus;
- }
-
- @Override
- public void setLastStatus(DownloaderLastStatus lastStatus, TranslationComponent statusMessage) {
- this.lastStatus = lastStatus;
- this.statusMessage = statusMessage;
- }
-
- @Override
- public TranslationComponent getLastStatusMessage() {
- return statusMessage;
- }
-
-
@Override
public void close() {
client.shutdown();
diff --git a/src/main/java/com/ghostchu/peerbanhelper/gui/impl/javafx/JavaFxImpl.java b/src/main/java/com/ghostchu/peerbanhelper/gui/impl/javafx/JavaFxImpl.java
index 23d78c6f0d..2ebae739e5 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/gui/impl/javafx/JavaFxImpl.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/gui/impl/javafx/JavaFxImpl.java
@@ -358,23 +358,17 @@ public void createDialog(Level level, String title, String description) {
@Override
public void createNotification(Level level, String title, String description) {
- Alert.AlertType alertType = Alert.AlertType.NONE;
- if (level.equals(Level.WARNING)) {
- alertType = Alert.AlertType.WARNING;
- }
- if (level.equals(Level.SEVERE)) {
- alertType = Alert.AlertType.ERROR;
- }
- if (level.equals(Level.INFO)) {
- alertType = Alert.AlertType.INFORMATION;
+ if (trayIcon != null) {
+ TrayIcon.MessageType messageType = TrayIcon.MessageType.INFO;
+ if (level.equals(Level.WARNING)) {
+ messageType = TrayIcon.MessageType.WARNING;
+ }
+ if (level.equals(Level.SEVERE)) {
+ messageType = TrayIcon.MessageType.ERROR;
+ }
+ trayIcon.displayMessage(title, description, messageType);
+ return;
}
- Alert.AlertType finalAlertType = alertType;
- Platform.runLater(() -> {
- Alert alert = new Alert(finalAlertType);
- alert.setTitle(title);
- alert.setHeaderText(title);
- alert.setContentText(description);
- alert.show();
- });
+ createDialog(level, title, description);
}
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java b/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
index 0058d89a8f..255c471adb 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
@@ -295,7 +295,8 @@ public enum Lang {
USER_MANUALLY_BAN_RULE,
USER_MANUALLY_BAN_REASON,
SCHEDULED_OPERATIONS,
- ARB_BANNED_REASON
+ ARB_BANNED_REASON,
+ TOO_MANY_FAILED_ATTEMPT
;
diff --git a/src/main/java/com/ghostchu/peerbanhelper/util/MsgUtil.java b/src/main/java/com/ghostchu/peerbanhelper/util/MsgUtil.java
index d7b2dc0b97..4d5c664114 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/util/MsgUtil.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/util/MsgUtil.java
@@ -8,10 +8,12 @@
import java.lang.management.ThreadInfo;
import java.text.CharacterIterator;
import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
import java.text.StringCharacterIterator;
public class MsgUtil {
private static final DecimalFormat df = new DecimalFormat("0.00%");
+ private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String humanReadableByteCountBin(long bytes) {
long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
if (absB < 1024) {
@@ -107,6 +109,9 @@ public static DecimalFormat getPercentageFormatter() {
return df;
}
+ public static SimpleDateFormat getDateFormatter() {
+ return sdf;
+ }
/**
* Replace args in raw to args
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 1a5d5c07e4..d46c2176cc 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,4 +1,4 @@
-config-version: 12
+config-version: 13
# 设置程序语言
# default 跟随操作系统 (Follow the operating system)
# en_us English (US)
@@ -118,3 +118,5 @@ proxy:
host: "127.0.0.1"
# 代理服务器端口号
port: 7890
+ # 代理例外地址,使用 | 分隔不同条目
+ non-proxy-host: "127.0.0.1|localhost"
diff --git a/src/main/resources/lang/en_us/messages.yml b/src/main/resources/lang/en_us/messages.yml
index ec23578bc5..9290bb678b 100644
--- a/src/main/resources/lang/en_us/messages.yml
+++ b/src/main/resources/lang/en_us/messages.yml
@@ -118,9 +118,9 @@ GUI_TRAY_MESSAGE_DESCRIPTION: "Click the tray icon to reopen the window; right-c
GUI_TABBED_LOGS: "Run Logs"
GUI_TABBED_PEERS: "Connected Peers"
ABOUT_VIEW_GITHUB: "View GitHub page..."
-IPDB_UPDATING: "{} database is outdated and needs updating, please wait while PBH connects to Maxmind servers to update data..."
-IPDB_UPDATE_FAILED: "Error downloading database {} from Maxmind: {}"
-IPDB_UPDATE_SUCCESS: "Successfully updated database {} from Maxmind!"
+IPDB_UPDATING: "{} database is outdated and needs updating, please wait while PBH connects to the server to update data..."
+IPDB_UPDATE_FAILED: "Error downloading database {} from server: {}"
+IPDB_UPDATE_SUCCESS: "Successfully updated database {} from server!"
IPDB_INVALID: "IPDB feature automatically disabled due to an error during initialization. Please check the log file to fix the issue"
IPDB_NEED_CONFIG: "IPDB feature requires configuration, please fill in the relevant information in ip-database in config.yml"
DOWNLOAD_PROGRESS_DETERMINED: "Download progress: downloaded {}/{} bytes, progress: {}%"
@@ -309,4 +309,6 @@ USER_SCRIPT_RULE: "User Aviator Script Custom Rule"
USER_SCRIPT_RUN_RESULT: "UserScript {}: {}"
SCHEDULED_OPERATIONS: "[Scheduled Tasks] Processed {} ban list external changes"
-ARB_BANNED_REASON: "IP address {} is in the same ban range as another banned IP address {}, performing chain ban operation: {}@{}"
\ No newline at end of file
+ARB_BANNED_REASON: "IP address {} is in the same ban range as another banned IP address {}, performing chain ban operation: {}@{}"
+
+TOO_MANY_FAILED_ATTEMPT: "Too many failed login attempts. We paused attempt until {}."
\ No newline at end of file
diff --git a/src/main/resources/lang/messages_fallback.yml b/src/main/resources/lang/messages_fallback.yml
index 28d3923e96..ad9719eed5 100644
--- a/src/main/resources/lang/messages_fallback.yml
+++ b/src/main/resources/lang/messages_fallback.yml
@@ -309,4 +309,6 @@ USER_SCRIPT_RULE: "用户 Aviator Script 自定脚本规则"
USER_SCRIPT_RUN_RESULT: "用户脚本 {}: {}"
SCHEDULED_OPERATIONS: "[计划任务] 已处理 {} 个封禁列表的外部计划更改"
-ARB_BANNED_REASON: "IP 地址 {} 与另一个已封禁的 IP 地址 {} 处于同一封禁区间内,执行连锁封禁操作:{}@{}"
\ No newline at end of file
+ARB_BANNED_REASON: "IP 地址 {} 与另一个已封禁的 IP 地址 {} 处于同一封禁区间内,执行连锁封禁操作:{}@{}"
+
+TOO_MANY_FAILED_ATTEMPT: "连接此下载器时连续多次错误,已暂停登录尝试。暂停状态将于 {} 恢复"
\ No newline at end of file
diff --git a/src/main/resources/lang/zh_cn/messages.yml b/src/main/resources/lang/zh_cn/messages.yml
index 28d3923e96..8780255a0d 100644
--- a/src/main/resources/lang/zh_cn/messages.yml
+++ b/src/main/resources/lang/zh_cn/messages.yml
@@ -118,9 +118,9 @@ GUI_TRAY_MESSAGE_DESCRIPTION: "点击托盘图标重新打开窗口;右键托
GUI_TABBED_LOGS: "运行日志"
GUI_TABBED_PEERS: "已连接的Peers"
ABOUT_VIEW_GITHUB: "查看 Github 页面..."
-IPDB_UPDATING: "{} 数据库已过期且需要更新,请等待 PBH 连接到 Maxmind 服务器更新数据……"
-IPDB_UPDATE_FAILED: "从 Maxmind 下载数据库 {} 时出现错误:{}"
-IPDB_UPDATE_SUCCESS: "从 Maxmind 更新数据库 {} 成功!"
+IPDB_UPDATING: "{} 数据库已过期且需要更新,请等待 PBH 连接到服务器更新数据……"
+IPDB_UPDATE_FAILED: "下载数据库 {} 时出现错误:{}"
+IPDB_UPDATE_SUCCESS: "更新数据库 {} 成功!"
IPDB_INVALID: "由于在初始化过程中出现错误,IPDB 功能已被自动禁用。请检查日志文件以修复问题"
IPDB_NEED_CONFIG: "IPDB 功能需要配置才能使用,请在 config.yml 的 ip-database 中填写相关配置信息"
DOWNLOAD_PROGRESS_DETERMINED: "下载进度:已下载 {}/{} 字节,进度:{}%"
@@ -309,4 +309,6 @@ USER_SCRIPT_RULE: "用户 Aviator Script 自定脚本规则"
USER_SCRIPT_RUN_RESULT: "用户脚本 {}: {}"
SCHEDULED_OPERATIONS: "[计划任务] 已处理 {} 个封禁列表的外部计划更改"
-ARB_BANNED_REASON: "IP 地址 {} 与另一个已封禁的 IP 地址 {} 处于同一封禁区间内,执行连锁封禁操作:{}@{}"
\ No newline at end of file
+ARB_BANNED_REASON: "IP 地址 {} 与另一个已封禁的 IP 地址 {} 处于同一封禁区间内,执行连锁封禁操作:{}@{}"
+
+TOO_MANY_FAILED_ATTEMPT: "连接此下载器时连续多次错误,已暂停登录尝试,请检查用户名密码和网络连接。暂停状态将于 {} 恢复"
\ No newline at end of file
diff --git a/src/main/resources/profile.yml b/src/main/resources/profile.yml
index 66beeffa82..c2fdf8abbd 100644
--- a/src/main/resources/profile.yml
+++ b/src/main/resources/profile.yml
@@ -158,7 +158,7 @@ module:
# IPV4 前缀长度
ipv4: 30 # /32 = 单个 IP,/24 = 整个 ?.?.?.x 段
# IPV6 前缀长度
- ipv6: 64 # /64 = ISP 通常分配给家宽用户的前缀长度
+ ipv6: 60 # /60 = ISP 通常分配给家宽用户的前缀长度
# 启用来自 BTN 网络的规则
btn:
enabled: true