diff --git a/.github/ISSUE_TEMPLATE/any_other.yml b/.github/ISSUE_TEMPLATE/any_other.yml
index 31c15e1ed7..658d2d2079 100644
--- a/.github/ISSUE_TEMPLATE/any_other.yml
+++ b/.github/ISSUE_TEMPLATE/any_other.yml
@@ -34,5 +34,7 @@ body:
required: false
- label: "我已检查过 [PBH 文档](https://docs.pbh-btn.com/)(特别是常见问题),且即使使用了搜索也没有找到与此有关的内容 (This not a question/or the question that not listed in README's FAQ or [PBH WIKI](https://docs.pbh-btn.com/))"
required: false
+ - label: "我没有检查这个检查清单,只是闭眼选中了所有的复选框,请关闭这个 Issue (I have not read these checkboxes and therefore I just ticked them all, Please close this issue)"
+ required: false
- label: "我同意遵守 PBH-BTN 包容性条约,不发布 “嘲讽、骂战、引战、开盒(有时也称为人肉搜索)、人身攻击、仇恨、暴力、侮辱性言辞、违法违规、黑灰产、危害国家安全、实施或帮助他人实施电信犯罪” 等内容。并已知晓如果仍旧发布了这些内容,我的账号将立刻从包括但不限于 PBH-BTN 组织、社交软件中封禁。所有主题、内容都将被立刻删除或折叠,撤销、删除和收回您所做出的一切贡献,并封禁 BTN 网络的中账号权限、排除您所提交的所有数据。在您违反相关规则时,PBH-BTN 将会将您的注册、登录、和最近访问的 IP 地址、电子邮件地址、以及其它可能追踪您或将您去匿名化的信息从定期删除转为永不删除,并在任何国家或地区的政府、公安机关或有关部门需要时无通知的提供这些数据。 (I agree to abide by the PBH-BTN Inclusivity Pact by not posting content such as “taunting, name-calling, war-mongering, open-boxing (sometimes referred to as mansplaining), personal attacks, hatred, violence, insulting language, illegal activities, black and grey business, endangering national security, and committing or assisting others in committing telecommunication crimes”. I am aware that if I continue to post such content, my account will be immediately banned from organizations including but not limited to PBH-BTN, social software. All topics and content will be immediately deleted or collapsed, all contributions will be revoked, deleted and retracted, and you will be banned from the BTN network and all data you have submitted will be excluded. In the event of a violation of these rules, PBH-BTN will delete your registration, login, and most recent IP address, email address, and any other information that may be used to track you or de-anonymize you from regular to permanent deletion, and will make this data available to the government, public security, or other relevant authorities without notice if they request it, no matter what country or region.)"
required: false
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 40a098c798..962b33107c 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -56,6 +56,8 @@ body:
required: false
- label: "RedHat/Fedora 软件包 (RedHat/Fedora .rpm package)"
required: false
+ - label: "FreeBSD 软件包(FreeBSD .pkg package)"
+ required: false
- type: checkboxes
id: downloaders
attributes:
diff --git a/.github/ISSUE_TEMPLATE/web_ui.yml b/.github/ISSUE_TEMPLATE/web_ui.yml
index a40a179af1..ff88a2db94 100644
--- a/.github/ISSUE_TEMPLATE/web_ui.yml
+++ b/.github/ISSUE_TEMPLATE/web_ui.yml
@@ -69,9 +69,9 @@ body:
required: false
- label: "我已检查过 [PBH 文档](https://docs.pbh-btn.com/)(特别是常见问题),且即使使用了搜索也没有找到与此有关的内容 (This not a question/or the question that not listed in README's FAQ or [PBH WIKI](https://docs.pbh-btn.com/))"
required: false
- - label: "我没有检查这个检查清单,只是闭眼选中了所有的复选框,请关闭这个 Issue (I have not read these checkboxes and therefore I just ticked them all, Please close this issue)"
- required: false
- label: "所添加的下载器已满足 README 中的前置要求(如版本号和插件)(The downloaders that I've added already satisfied the requirements (E.g install plugins/adapters))"
required: false
+ - label: "我没有检查这个检查清单,只是闭眼选中了所有的复选框,请关闭这个 Issue (I have not read these checkboxes and therefore I just ticked them all, Please close this issue)"
+ required: false
- label: "我同意遵守 PBH-BTN 包容性条约,不发布 “嘲讽、骂战、引战、开盒(有时也称为人肉搜索)、人身攻击、仇恨、暴力、侮辱性言辞、违法违规、黑灰产、危害国家安全、实施或帮助他人实施电信犯罪” 等内容。并已知晓如果仍旧发布了这些内容,我的账号将立刻从包括但不限于 PBH-BTN 组织、社交软件中封禁。所有主题、内容都将被立刻删除或折叠,撤销、删除和收回您所做出的一切贡献,并封禁 BTN 网络的中账号权限、排除您所提交的所有数据。在您违反相关规则时,PBH-BTN 将会将您的注册、登录、和最近访问的 IP 地址、电子邮件地址、以及其它可能追踪您或将您去匿名化的信息从定期删除转为永不删除,并在任何国家或地区的政府、公安机关或有关部门需要时无通知的提供这些数据。 (I agree to abide by the PBH-BTN Inclusivity Pact by not posting content such as “taunting, name-calling, war-mongering, open-boxing (sometimes referred to as mansplaining), personal attacks, hatred, violence, insulting language, illegal activities, black and grey business, endangering national security, and committing or assisting others in committing telecommunication crimes”. I am aware that if I continue to post such content, my account will be immediately banned from organizations including but not limited to PBH-BTN, social software. All topics and content will be immediately deleted or collapsed, all contributions will be revoked, deleted and retracted, and you will be banned from the BTN network and all data you have submitted will be excluded. In the event of a violation of these rules, PBH-BTN will delete your registration, login, and most recent IP address, email address, and any other information that may be used to track you or de-anonymize you from regular to permanent deletion, and will make this data available to the government, public security, or other relevant authorities without notice if they request it, no matter what country or region.)"
required: false
diff --git a/install4j/project.install4j~ b/install4j/project.install4j~
deleted file mode 100644
index d327b09c7a..0000000000
--- a/install4j/project.install4j~
+++ /dev/null
@@ -1,1612 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:components.peerbanhelper.description}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- sys.installationDir
-
-
- context.getBooleanVariable("sys.confirmedUpdateInstallation")
-
-
-
-
-
- ${form:welcomeMessage}
-
- !context.isConsole()
-
-
-
-
-
-
-
-
-
-
- updateCheck
-
-
-
-
- ${i18n:ClickNext}
-
-
-
-
-
- !context.getBooleanVariable("sys.confirmedUpdateInstallation")
-
-
-
-
- sys.installationDir
-
-
- context.getVariable("sys.responseFile") == null
-
-
-
-
-
- ${i18n:SelectDirLabel(${compiler:sys.fullName})}
-
-
-
-
-
-
-
- suggestAppDir
- validateApplicationId
- existingDirWarning
- checkWritable
- manualEntryAllowed
- checkFreeSpace
- showRequiredDiskSpace
- showFreeDiskSpace
- allowSpacesOnUnix
- validationScript
- standardValidation
-
-
-
-
-
-
-
-
- ${i18n:SelectComponentsLabel2}
-
- !context.isConsole()
-
-
-
-
-
-
- selectionChangedScript
-
-
-
-
-
-
-
-
- ${form:confirmationMessage}
-
- !context.isConsole()
-
-
-
- ${i18n:CreateDesktopIcon}
- createDesktopLinkAction
-
-
-
-
- ${i18n:checkbox.followsystemstartup}
- startupWhenLoggedIn
-
-
-
-
- ${i18n:checkbox.registersystemservice}
- registerSystemService
-
-
-
-
-
- context.getBooleanVariable("registerSystemService")
-
-
-
- ${i18n:InfoBeforeClickLabel}
-
- !context.isConsole()
-
-
-
- ${i18n:systemservice.note}
-
-
-
-
- textSource
- displayedText
- displayedTextFile
- variableName
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}
-
- !context.getBooleanVariable("sys.programGroupDisabled")
-
-
-
-
-
-
-
- ${compiler:sys.fullName}
-
-
-
-
-
-
-
-
-
-
- context.getBooleanVariable("createDesktopLinkAction")
-
-
-
-
-
-
- PeerBanHelper
-
- context.getBooleanVariable("startupWhenLoggedIn")
-
-
-
- ${compiler:sys.fullName} ${compiler:sys.version}
-
-
-
-
-
- 70
- com.ghostchu.peerbanhelper.PBHService
-
-
-
-
- context.getBooleanVariable("registerSystemService")
-
-
-
-
- 70
-
- context.getBooleanVariable("registerSystemService")
-
-
-
-
-
- ${i18n:WizardPreparing}
-
-
-
-
-
-
-
-
- 26
-
- context.getBooleanVariable("executeLauncherAction") && (!context.isUnattended())
-
-
-
-
-
- ${form:finishedMessage}
-
-
-
-
- ${i18n:RunEntryExec("${compiler:sys.fullName}")}
-
- executeLauncherAction
-
-
-
-
-
-
-
-
- ${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${form:welcomeMessage}
-
- !context.isConsole()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 70
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:UninstallerPreparing}
-
-
-
-
-
-
-
-
-
- ${form:successMessage}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bgupdater
-
- -Dapple.awt.UIElement=true
- ${compiler:sys.fullName}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${installer:updatesUrl?:${compiler:sys.updatesUrl}}
- updateDescriptor
-
-
-
-
-
-
-
-
- updateDescriptorEntry
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- updaterNewVersion
-
-
-
-
-
-
-
- updaterDownloadUrl
-
-
-
-
-
-
-
- updaterDownloadFile
-
-
-
-
-
-
-
- ${installer:updaterDownloadUrl}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 755
-
-
-
-
-
-
-
- ${installer:updaterNewVersion}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- updaterStagingDir
-
-
-
-
-
-
-
-
-
-
-
-
- new File((String)context.getVariable("updaterStagingDir")).exists()
-
-
-
-
-
-
-
-
-
-
-
-
-
- ((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")
-
-
-
-
-
-
-
-
-
-
-
-
-
- !((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")
-
-
-
-
-
-
- ${installer:updaterNewVersion}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- updater
-
- ${i18n:updater.WindowTitle("${compiler:sys.fullName}")}
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.WelcomeTitle("${compiler:sys.fullName}")}
-
-
-
-
-
- ${i18n:updater.WelcomeInfoText("${compiler:sys.fullName}")}
-
- !context.isConsole()
-
- labelText
-
-
-
-
-
-
- ${i18n:updater.CheckForUpdateSubtitle}
- ${i18n:updater.CheckForUpdateTitle}
-
- context.getWizardContext().setControlButtonVisible(ControlButtonType.NEXT, false);
-context.getWizardContext().setControlButtonVisible(ControlButtonType.PREVIOUS, false);
-context.goForward(1, true, true);
-
-
-
-
-
-
-
-
-
- ${installer:updatesUrl?:${compiler:sys.updatesUrl}}
- updateDescriptor
-
-
-
-
-
-
-
-
- updateDescriptorEntry
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- updaterNewVersion
-
-
-
-
-
-
-
- updaterDownloadSize
-
-
-
-
-
-
-
- updaterComment
-
-
-
-
-
-
-
- updaterDownloadUrl
-
-
-
-
-
-
-
- isArchive
-
-
-
-
-
-
-
- isDmg
-
-
-
-
-
-
-
-
- ${i18n:updater.CheckForUpdateLabel}
-
-
- statusVisible
- initialStatusMessage
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.UpToDateTitle}
-
-
-
-
-
- ${i18n:updater.UpToDateInfoText("${compiler:sys.fullName}")}
-
- !context.isConsole()
-
- labelText
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.NewVersionAvailableSubtitle("${compiler:sys.fullName}")}
- ${i18n:updater.NewVersionAvailableTitle}
-
- !context.getBooleanVariable("skipNewVersionAvailable")
-
-
-
- ${i18n:updater.CurrentVersionLabel}
-
-
-
-
-
- ${installer:sys.version}
-
-
-
-
-
-
- ${i18n:updater.NewVersionLabel}
-
-
-
-
-
- ${installer:updaterNewVersion}
-
-
-
-
-
-
-
- ${i18n:updater.ShowComments}
-
- ((String)context.getVariable("updaterComment")).length() > 0
-
-
-
-
-
-
- ${i18n:updater.DownloadLocationLabel}
-
-
-
-
- ${installer:sys.downloadsDir}
- ${i18n:updater.DownloadToLabel}
-
- updaterDownloadLocation
-
-
-
-
- ${i18n:updater.DownloadSizeLabel}
- ${installer:updaterDownloadSize}
-
-
-
-
-
-
-
- ${i18n:updater.CommentsSubTitle}
- ${i18n:updater.CommentsTitle}
-
- false // This screen is only shown if the user clicks the "Show comments" hyperlink label in the previous screen.
-
- if (context.isConsole()) {
- context.goBackInHistory(1);
-}
-return true;
- WizardContext wizardContext = context.getWizardContext();
-wizardContext.setControlButtonVisible(ControlButtonType.NEXT, false);
-wizardContext.setControlButtonVisible(ControlButtonType.CANCEL, false);
-
-
-
-
- ${i18n:updater.CommentsLabel}
-
- !context.isConsole()
-
- labelText
-
-
-
-
- ${installer:updaterComment}
-
-
-
-
- textSource
- displayedText
- displayedTextFile
- variableName
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.DownloadSubTitle}
- ${i18n:updater.DownloadTitle}
-
- context.getWizardContext().setControlButtonVisible(ControlButtonType.NEXT, false);
-context.getWizardContext().setControlButtonVisible(ControlButtonType.PREVIOUS, false);
-context.goForward(1, true, true);
-
-
-
-
-
-
-
- updaterDownloadFile
-
-
-
-
-
-
-
- ${installer:updaterDownloadUrl}
-
-
-
-
-
-
-
-
-
- 755
-
-
-
-
-
-
- statusVisible
- initialStatusMessage
-
-
-
-
-
-
-
-
- ${i18n:updater.FinishTitle}
-
- !(context.getBooleanVariable("isArchive") && context.getBooleanVariable("isDmg"))
-
-
-
-
-
-
-
-
-
-
-
-
-
- installerArguments
-
-
-
-
-
-
- ${installer:installerArguments}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- !context.isConsole()
-
- labelText
-
-
-
-
-
- ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")}
-
- !context.isConsole()
-
- labelText
-
-
-
-
- ${i18n:updater.LaunchUpdaterQuestion}
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.LaunchUpdaterLabel}
- ${i18n:updater.DoNotLaunchUpdaterLabel}
-
- updaterLaunchSelection
-
- !context.getBooleanVariable("isArchive")
-
-
-
-
-
-
- ${i18n:updater.OpenContainingFolderLabel}
-
- !context.isConsole()
-
-
-
-
-
-
-
-
-
-
-
- ${i18n:updater.FinishTitle}
-
- context.getBooleanVariable("isArchive") && context.getBooleanVariable("isDmg")
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- !context.isConsole()
-
- labelText
-
-
-
-
-
- ${i18n:updater.FinishInfoText("${compiler:sys.fullName}")}
-
- !context.isConsole()
-
- labelText
-
-
-
-
- ${i18n:updater.LaunchUpdaterQuestion}
-
-
-
-
-
-
-
-
-
- ${i18n:updater.OpenContainingFolderLabel}
-
- updaterOpenDmg
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pom.xml b/pom.xml
index 8159cb7fc5..4a5e4ba0eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.ghostchu.peerbanhelper
peerbanhelper
- 7.3.0
+ 7.3.1
jar
PeerBanHelper
@@ -305,11 +305,6 @@
sqlite-jdbc-loongarch64
3.47.0.0
-
- com.zaxxer
- HikariCP
- 6.2.1
-
com.github.mizosoft.methanol
methanol
diff --git a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
index 31188f6805..592acb6080 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/PeerBanHelperServer.java
@@ -82,7 +82,7 @@
public class PeerBanHelperServer implements Reloadable {
private static final long BANLIST_SAVE_INTERVAL = 60 * 60 * 1000;
private final CheckResult NO_MATCHES_CHECK_RESULT = new CheckResult(getClass(), PeerAction.NO_ACTION, 0, new TranslationComponent("No Matches"), new TranslationComponent("No Matches"));
- private final Map BAN_LIST = new ConcurrentHashMap<>();
+ private final Map BAN_LIST = new ConcurrentSkipListMap<>();
@Getter
private final AtomicBoolean needReApplyBanList = new AtomicBoolean();
private final Deque scheduledBanListOperations = new ConcurrentLinkedDeque<>();
@@ -484,7 +484,7 @@ public void banWave() {
try (TimeoutProtect protect = new TimeoutProtect(ExceptedTime.CHECK_BANS.getTimeout(), (t) -> {
log.error(tlUI(Lang.TIMING_CHECK_BANS));
})) {
- getDownloaders().forEach(downloader -> protect.getService().submit(() -> {
+ peers.keySet().forEach(downloader -> protect.getService().submit(() -> {
try {
downloaderBanDetailMap.put(downloader, checkBans(peers.get(downloader), downloader));
} catch (Exception e) {
@@ -524,6 +524,7 @@ public void banWave() {
log.error(tlUI(Lang.TIMING_ADD_BANS));
})) {
var banlistClone = List.copyOf(BAN_LIST.keySet());
+
downloaderBanDetailMap.forEach((downloader, details) -> {
try {
List relaunch = Collections.synchronizedList(new ArrayList<>());
@@ -603,7 +604,6 @@ public void banWave() {
banWaveWatchDog.feed();
metrics.recordCheck();
banWaveLock.unlock();
- System.gc();
}
}
@@ -617,7 +617,6 @@ private List checkBans(Map> provided, @NotNull Do
try {
CheckResult checkResult = checkBan(torrent, peer, downloader);
details.add(new BanDetail(torrent, peer, checkResult, checkResult.duration()));
-
} catch (Exception e) {
log.error("Unexpected error occurred while checking bans", e);
throw e;
@@ -743,7 +742,9 @@ public Map>> collectPeers() {
getDownloaders().forEach(downloader -> service.submit(() -> {
try {
Map> p = collectPeers(downloader);
- peers.put(downloader, p);
+ if (p != null) {
+ peers.put(downloader, p);
+ }
} catch (Exception e) {
log.error(tlUI(Lang.DOWNLOADER_UNHANDLED_EXCEPTION), e);
}
@@ -752,6 +753,7 @@ public Map>> collectPeers() {
return peers;
}
+ @Nullable
public Map> collectPeers(Downloader downloader) {
Map> peers = new ConcurrentHashMap<>();
var loginResult = downloader.login();
@@ -763,7 +765,7 @@ public Map> collectPeers(Downloader downloader) {
downloader.setLastStatus(DownloaderLastStatus.NEED_TAKE_ACTION, loginResult.getMessage());
}
}
- return Collections.emptyMap();
+ return null;
}
List torrents = downloader.getTorrents();
Semaphore parallelReqRestrict = new Semaphore(downloader.getMaxConcurrentPeerRequestSlots());
diff --git a/src/main/java/com/ghostchu/peerbanhelper/database/Database.java b/src/main/java/com/ghostchu/peerbanhelper/database/Database.java
index 5b51c8ce89..a8111ab931 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/database/Database.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/database/Database.java
@@ -9,8 +9,6 @@
import com.j256.ormlite.field.DataPersisterManager;
import com.j256.ormlite.jdbc.JdbcSingleConnectionSource;
import com.j256.ormlite.jdbc.db.SqliteDatabaseType;
-import com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -21,6 +19,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.sql.Connection;
+import java.sql.DriverManager;
import java.sql.SQLException;
import java.time.Duration;
@@ -34,7 +33,6 @@ public class Database {
private final File dbMaintenanceFile;
private final Laboratory laboratory;
private JdbcSingleConnectionSource dataSource;
- private HikariDataSource hikari;
private DatabaseHelper helper;
public Database(Laboratory laboratory) throws SQLException, ClassNotFoundException {
@@ -47,7 +45,6 @@ public Database(Laboratory laboratory) throws SQLException, ClassNotFoundExcepti
this.dbMaintenanceFile = new File(databaseDirectory, "peerbanhelper.db.maintenance");
registerPersisters();
setupDatabase(sqliteDb);
-
}
private void registerPersisters() {
@@ -73,19 +70,13 @@ private void setLastMaintenanceTime(long time) {
}
public void setupDatabase(File file) throws SQLException {
- HikariConfig config = new HikariConfig();
- config.setPoolName("PeerBanHelper SQLite Connection Pool");
- config.setDriverClassName("org.sqlite.JDBC");
- config.setJdbcUrl("jdbc:sqlite:" + file);
- config.setConnectionTestQuery("SELECT 1");
- config.setMaximumPoolSize(1); // 50 Connections (including idle connections)
- this.hikari = new HikariDataSource(config);
- Connection rawConnection = this.hikari.getConnection();
+ Connection rawConnection = DriverManager.getConnection("jdbc:sqlite:" + file);
if (System.getProperty("disableSQLitePragmaSettings") == null) {
try (var stmt = rawConnection.createStatement()) {
stmt.executeUpdate("PRAGMA synchronous = NORMAL");
stmt.executeUpdate("PRAGMA journal_mode = WAL");
- stmt.executeUpdate("PRAGMA auto_vacuum = INCREMENTAL");
+ stmt.executeUpdate("PRAGMA mmap_size = 50331648");
+ stmt.executeUpdate("PRAGMA OPTIMIZE");
try {
if (System.currentTimeMillis() - getLastMaintenanceTime() >= Duration.ofDays(Main.getMainConfig().getInt("persist.vacuum-interval-days")).toMillis()) {
if (System.getProperty("pbh.disableSQLiteVacuum") == null) {
diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java
index 5e66bb2cda..9e62b65a0f 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java
@@ -1,5 +1,6 @@
package com.ghostchu.peerbanhelper.downloader.impl.qbittorrent;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.ghostchu.peerbanhelper.Main;
import com.ghostchu.peerbanhelper.alert.AlertManager;
import com.ghostchu.peerbanhelper.downloader.AbstractDownloader;
@@ -24,6 +25,9 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
@@ -143,13 +147,24 @@ public String getEndpoint() {
public boolean isLoggedIn() {
- HttpResponse resp;
+ HttpResponse resp;
try {
- resp = httpClient.send(MutableRequest.GET(apiEndpoint + "/app/version"), HttpResponse.BodyHandlers.discarding());
+ resp = httpClient.send(MutableRequest.GET(apiEndpoint + "/app/buildInfo"), HttpResponse.BodyHandlers.ofString());
+ if (resp.statusCode() != 200) {
+ return false;
+ }
+ QBittorrentBuildInfo info = JsonUtil.getGson().fromJson(resp.body(), QBittorrentBuildInfo.class);
+ if (info == null) {
+ return false;
+ }
+ if (info.getQt() == null) {
+ return false;
+ }
+ return !info.getQt().isBlank();
} catch (Exception e) {
+ log.error("Failed to check login status", e);
return false;
}
- return resp.statusCode() == 200;
}
@Override
@@ -354,4 +369,24 @@ public void close() throws Exception {
}
public record TorrentProperties(boolean isPrivate, long completed, long pieceSize, long piecesHave) {}
+
+ @AllArgsConstructor
+ @NoArgsConstructor
+ @Data
+ public static class QBittorrentBuildInfo {
+ @JsonProperty("bitness")
+ private Integer bitness;
+ @JsonProperty("boost")
+ private String boost;
+ @JsonProperty("libtorrent")
+ private String libtorrent;
+ @JsonProperty("openssl")
+ private String openssl;
+ @JsonProperty("platform")
+ private String platform;
+ @JsonProperty("qt")
+ private String qt;
+ @JsonProperty("zlib")
+ private String zlib;
+ }
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/ipdb/IPDB.java b/src/main/java/com/ghostchu/peerbanhelper/ipdb/IPDB.java
index ac7a24df54..3e118ee769 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/ipdb/IPDB.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/ipdb/IPDB.java
@@ -8,9 +8,7 @@
import com.github.mizosoft.methanol.MutableRequest;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
-import com.maxmind.db.MaxMindDbConstructor;
-import com.maxmind.db.MaxMindDbParameter;
-import com.maxmind.db.Reader;
+import com.maxmind.db.*;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.AsnResponse;
import com.maxmind.geoip2.model.CityResponse;
@@ -19,6 +17,7 @@
import com.maxmind.geoip2.record.Country;
import com.maxmind.geoip2.record.Location;
import lombok.Getter;
+import lombok.SneakyThrows;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
@@ -42,7 +41,6 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -51,10 +49,6 @@
@Slf4j
public class IPDB implements AutoCloseable {
- private final Cache MINI_CACHE = CacheBuilder.newBuilder()
- .maximumSize(1000)
- .expireAfterAccess(5, TimeUnit.SECONDS)
- .build();
private final File dataFolder;
private final long updateInterval = 3888000000L; // 45天
private final String accountId;
@@ -98,25 +92,19 @@ public IPDB(File dataFolder, String accountId, String licenseKey, String databas
}
public IPGeoData query(InetAddress address) {
- try {
- return MINI_CACHE.get(address, () -> {
- IPGeoData geoData = new IPGeoData();
- geoData.setAs(queryAS(address));
- geoData.setCountry(queryCountry(address));
- geoData.setCity(queryCity(address));
- geoData.setNetwork(queryNetwork(address));
- if (geoData.getCountry() != null && geoData.getCountry().getIso() != null) {
- String iso = geoData.getCountry().getIso();
- if (iso.equalsIgnoreCase("CN") || iso.equalsIgnoreCase("TW")
- || iso.equalsIgnoreCase("HK") || iso.equalsIgnoreCase("MO")) {
- queryGeoCN(address, geoData);
- }
- }
- return geoData;
- });
- } catch (ExecutionException e) {
- return new IPGeoData();
+ IPGeoData geoData = new IPGeoData();
+ geoData.setAs(queryAS(address));
+ geoData.setCountry(queryCountry(address));
+ geoData.setCity(queryCity(address));
+ geoData.setNetwork(queryNetwork(address));
+ if (geoData.getCountry() != null && geoData.getCountry().getIso() != null) {
+ String iso = geoData.getCountry().getIso();
+ if (iso.equalsIgnoreCase("CN") || iso.equalsIgnoreCase("TW")
+ || iso.equalsIgnoreCase("HK") || iso.equalsIgnoreCase("MO")) {
+ queryGeoCN(address, geoData);
+ }
}
+ return geoData;
}
@@ -262,10 +250,16 @@ private void updateGeoCN(File mmdbGeoCNFile) throws IOException {
private void loadMMDB() throws IOException {
this.languageTag = List.of(Main.DEF_LOCALE, "en");
this.mmdbCity = new DatabaseReader.Builder(mmdbCityFile)
- .locales(List.of(Main.DEF_LOCALE, "en")).build();
+ .locales(List.of(Main.DEF_LOCALE, "en"))
+ .fileMode(Reader.FileMode.MEMORY_MAPPED)
+ .withCache(new MaxMindNodeCache())
+ .build();
this.mmdbASN = new DatabaseReader.Builder(mmdbASNFile)
- .locales(List.of(Main.DEF_LOCALE, "en")).build();
- this.geoCN = new Reader(mmdbGeoCNFile);
+ .locales(List.of(Main.DEF_LOCALE, "en"))
+ .fileMode(Reader.FileMode.MEMORY_MAPPED)
+ .withCache(new MaxMindNodeCache())
+ .build();
+ this.geoCN = new Reader(mmdbGeoCNFile, Reader.FileMode.MEMORY_MAPPED, new MaxMindNodeCache());
}
private void updateMMDB(String databaseName, File target) throws IOException {
@@ -432,4 +426,17 @@ public CNLookupResult(
}
}
+ public static final class MaxMindNodeCache implements NodeCache {
+ private final static Cache cache = CacheBuilder.newBuilder()
+ .maximumSize(2000)
+ .expireAfterAccess(1, TimeUnit.HOURS)
+ .build();
+
+ @SneakyThrows
+ @Override
+ public DecodedValue get(CacheKey cacheKey, Loader loader) throws IOException {
+ return cache.get(cacheKey, () -> loader.load(cacheKey));
+ }
+ }
+
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/AutoRangeBan.java b/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/AutoRangeBan.java
index 5b2b9f557a..30d88ec8b0 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/AutoRangeBan.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/module/impl/rule/AutoRangeBan.java
@@ -96,14 +96,14 @@ private void reloadConfig() {
if (isHandShaking(peer)) {
return pass();
}
- if (getServer().getBannedPeers().containsKey(peer.getPeerAddress())) {
+ if (getServer().getBannedPeersDirect().containsKey(peer.getPeerAddress())) {
return pass();
}
IPAddress peerAddress = peer.getPeerAddress().getAddress().withoutPrefixLength();
if (peerAddress.isIPv4Convertible()) {
peerAddress = peerAddress.toIPv4();
}
- for (Map.Entry bannedPeerEntry : getServer().getBannedPeers().entrySet()) {
+ for (Map.Entry bannedPeerEntry : getServer().getBannedPeersDirect().entrySet()) {
if (bannedPeerEntry.getValue().isBanForDisconnect()) {
continue;
}
diff --git a/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/PBHDownloaderController.java b/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/PBHDownloaderController.java
index eaafb592b5..ad4b8b770a 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/PBHDownloaderController.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/module/impl/webapi/PBHDownloaderController.java
@@ -82,7 +82,6 @@ private void handleDownloaderPut(Context ctx) {
if (name.contains(".")) {
throw new IllegalArgumentException("Illegal character (.) in name: " + name);
}
- boolean paused = draftDownloader.has("paused") && draftDownloader.get("paused").getAsBoolean();
JsonObject config = draftDownloader.get("config").getAsJsonObject();
Downloader downloader = getServer().createDownloader(name, config);
if (downloader == null) {
@@ -90,7 +89,6 @@ private void handleDownloaderPut(Context ctx) {
ctx.json(new StdResp(false, tl(locale(ctx), Lang.DOWNLOADER_API_ADD_FAILURE), null));
return;
}
- downloader.setPaused(paused);
if (getServer().registerDownloader(downloader)) {
ctx.status(HttpStatus.CREATED);
ctx.json(new StdResp(true, tl(locale(ctx), Lang.DOWNLOADER_API_CREATED), null));
@@ -113,7 +111,6 @@ private void handleDownloaderPatch(Context ctx, String downloaderName) {
if (name.contains(".")) {
throw new IllegalArgumentException("Illegal character (.) in name: " + name);
}
- boolean paused = draftDownloader.has("paused") && draftDownloader.get("paused").getAsBoolean();
JsonObject config = draftDownloader.get("config").getAsJsonObject();
Downloader downloader = getServer().createDownloader(name, config);
if (downloader == null) {
@@ -121,7 +118,6 @@ private void handleDownloaderPatch(Context ctx, String downloaderName) {
ctx.json(new StdResp(false, tl(locale(ctx), Lang.DOWNLOADER_API_UPDATE_FAILURE), null));
return;
}
- downloader.setPaused(paused);
// 可能重命名了?
getServer().getDownloaders().stream()
.filter(d -> d.getName().equals(downloaderName))
@@ -147,7 +143,6 @@ private void handleDownloaderTest(Context ctx) {
if (name.contains(".")) {
throw new IllegalArgumentException("Illegal character (.) in name: " + name);
}
- boolean paused = draftDownloader.has("paused") && draftDownloader.get("paused").getAsBoolean();
JsonObject config = draftDownloader.get("config").getAsJsonObject();
// if (getServer().getDownloaders().stream().anyMatch(d -> d.getName().equals(name))) {
// ctx.status(HttpStatus.CONFLICT);
@@ -160,9 +155,8 @@ private void handleDownloaderTest(Context ctx) {
ctx.json(new StdResp(false, tl(locale(ctx), Lang.DOWNLOADER_API_ADD_FAILURE), null));
return;
}
- downloader.setPaused(paused);
try {
- if (!paused) {
+ if (!downloader.isPaused()) {
var testResult = downloader.login();
if (testResult.success()) {
ctx.json(new StdResp(testResult.success(), tl(locale(ctx), Lang.DOWNLOADER_API_TEST_OK), null));
diff --git a/src/main/java/com/ghostchu/peerbanhelper/util/IPAddressUtil.java b/src/main/java/com/ghostchu/peerbanhelper/util/IPAddressUtil.java
index aeb9d145e7..44983c8bea 100644
--- a/src/main/java/com/ghostchu/peerbanhelper/util/IPAddressUtil.java
+++ b/src/main/java/com/ghostchu/peerbanhelper/util/IPAddressUtil.java
@@ -66,9 +66,7 @@ public static IPAddress getIPAddress(String ip) {
@Nullable
public static IPAddress getIPAddressNoAutoConversation(String ip) {
try {
- return IP_ADDRESS_CACHE.get(ip, () -> {
- return new IPAddressString(ip).toAddress();
- });
+ return IP_ADDRESS_CACHE.get(ip, () -> new IPAddressString(ip).toAddress());
} catch (ExecutionException e) {
log.error("Unable to get ipaddress from ip {}", ip, e);
return null;
diff --git a/webui/src/api/model/downloader.ts b/webui/src/api/model/downloader.ts
index dcf635ab76..f46702caf1 100644
--- a/webui/src/api/model/downloader.ts
+++ b/webui/src/api/model/downloader.ts
@@ -29,7 +29,6 @@ export interface Downloader {
name: string
endpoint: string
type: ClientStatusEnum
- paused: boolean
}
export interface Torrent {
diff --git a/webui/src/locale/en-US.ts b/webui/src/locale/en-US.ts
index 1d0c4ff977..18ccd89cd5 100644
--- a/webui/src/locale/en-US.ts
+++ b/webui/src/locale/en-US.ts
@@ -31,7 +31,7 @@ export default {
'changeLogModel.updateNow': 'Update Now',
'globalPauseModel.title': 'Are you sure to enable global pause mode?',
'globalPauseModel.description':
- 'This will pause all ban and check operations of all downloaders until the next restart or cancel pause.',
+ 'This will pause all ban and check operations of all downloaders until the next restart or cancel pause. IPs in banlist will be unbanned immediately.',
'global.pause.pauseAll': 'Pause',
'global.pause.pauseAll.tips':
"This will stop PeerBanhelper's all functions and unban all Peers, suitable for modifying downloader configuration",
diff --git a/webui/src/locale/zh-CN.ts b/webui/src/locale/zh-CN.ts
index 4f597f2e63..7d3795a12b 100644
--- a/webui/src/locale/zh-CN.ts
+++ b/webui/src/locale/zh-CN.ts
@@ -32,7 +32,8 @@ export default {
'changeLogModel.notNow': '不是现在',
'changeLogModel.updateNow': '立即更新',
'globalPauseModel.title': '确定启用全局暂停模式吗?',
- 'globalPauseModel.description': '这将暂停所有下载器的封禁和检查操作,直至下次重启或者取消暂停。',
+ 'globalPauseModel.description':
+ '这将暂停所有下载器的封禁和检查操作,直至下次重启或者取消暂停。已封禁的 IP 地址将全部立刻解除封禁。',
'global.pause.pauseAll': '暂停',
'global.pause.pauseAll.tips':
'这将停止 PeerBanhelper 的全部功能并解封全部 Peer,适用于修改下载器配置等场景',
diff --git a/webui/src/views/charts/components/banTrends.vue b/webui/src/views/charts/components/banTrends.vue
index 14996ea618..8b2d8b0308 100644
--- a/webui/src/views/charts/components/banTrends.vue
+++ b/webui/src/views/charts/components/banTrends.vue
@@ -99,7 +99,18 @@ const option = reactive({
range: [dayjs().startOf('day').add(-7, 'day').toDate(), new Date()]
})
-const usedOption = computed(() => chartOptions.value)
+const usedOption = computed(() => ({
+ tooltip: {
+ trigger: 'axis',
+ backgroundColor: darkStore.isDark ? '#333335' : '#ffffff',
+ borderColor: darkStore.isDark ? '#333335' : '#ffffff',
+ textStyle: {
+ color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : undefined
+ }
+ },
+ backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+ ...chartOptions.value
+}))
const chartOptions = ref({
xAxis: {
@@ -109,14 +120,6 @@ const chartOptions = ref({
yAxis: {
type: 'value'
},
- tooltip: {
- trigger: 'axis',
- backgroundColor: darkStore.isDark ? '#333335' : '',
- borderColor: darkStore.isDark ? '#333335' : '',
- textStyle: {
- color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
- }
- },
grid: {
left: '15%'
},
@@ -126,8 +129,7 @@ const chartOptions = ref({
type: 'line',
name: t('page.charts.line.options.field')
}
- ],
- backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined
+ ]
})
watch(option, (v) => {
diff --git a/webui/src/views/charts/components/fieldPie.vue b/webui/src/views/charts/components/fieldPie.vue
index 9dfd10df50..8f506c2540 100644
--- a/webui/src/views/charts/components/fieldPie.vue
+++ b/webui/src/views/charts/components/fieldPie.vue
@@ -97,19 +97,22 @@ const loadingOptions = computed(() => ({
}))
const err = ref()
-const usedOption = computed(() => chartOption.value)
-
-const chartOption = ref({
+const usedOption = computed(() => ({
tooltip: {
trigger: 'item',
appendToBody: true,
formatter: '{b}
{c} ({d}%)',
- backgroundColor: darkStore.isDark ? '#333335' : '',
- borderColor: darkStore.isDark ? '#333335' : '',
+ backgroundColor: darkStore.isDark ? '#333335' : '#ffffff',
+ borderColor: darkStore.isDark ? '#333335' : '#ffffff',
textStyle: {
- color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
+ color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : undefined
}
},
+ backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+ ...chartOption.value
+}))
+
+const chartOption = ref({
legend: {
orient: 'vertical',
left: 'right',
@@ -126,7 +129,6 @@ const chartOption = ref({
show: true
}
},
- backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
series: [
{
name: t('page.charts.options.field.' + option.field),
diff --git a/webui/src/views/charts/components/ispPie.vue b/webui/src/views/charts/components/ispPie.vue
index ae50f05839..51f5fc7a33 100644
--- a/webui/src/views/charts/components/ispPie.vue
+++ b/webui/src/views/charts/components/ispPie.vue
@@ -130,19 +130,22 @@ const loadingOptions = computed(() => ({
maskColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.4)'
}))
-const usedOption = computed(() => chartOption.value)
-
-const chartOption = ref({
+const usedOption = computed(() => ({
tooltip: {
trigger: 'item',
appendToBody: true,
formatter: '{b}
{c} ({d}%)',
- backgroundColor: darkStore.isDark ? '#333335' : '',
- borderColor: darkStore.isDark ? '#333335' : '',
+ backgroundColor: darkStore.isDark ? '#333335' : '#ffffff',
+ borderColor: darkStore.isDark ? '#333335' : '#ffffff',
textStyle: {
- color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
+ color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : undefined
}
},
+ backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+ ...chartOption.value
+}))
+
+const chartOption = ref({
legend: {
orient: 'vertical',
left: 'right',
@@ -159,7 +162,6 @@ const chartOption = ref({
show: true
}
},
- backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
series: [
{
name: '',
diff --git a/webui/src/views/charts/components/traffic.vue b/webui/src/views/charts/components/traffic.vue
index 5e10b41352..b7d898eccd 100644
--- a/webui/src/views/charts/components/traffic.vue
+++ b/webui/src/views/charts/components/traffic.vue
@@ -111,18 +111,16 @@ const loadingOptions = computed(() => ({
const { t, d } = useI18n()
const err = ref()
-const usedOption = computed(() => chartOptions.value)
-
-const chartOptions = ref({
+const usedOption = computed(() => ({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
- backgroundColor: darkStore.isDark ? '#333335' : '',
- borderColor: darkStore.isDark ? '#333335' : '',
+ backgroundColor: darkStore.isDark ? '#333335' : '#ffffff',
+ borderColor: darkStore.isDark ? '#333335' : '#ffffff',
textStyle: {
- color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
+ color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : undefined
},
formatter: function (value: CallbackDataParams[]) {
return (
@@ -137,6 +135,10 @@ const chartOptions = ref({
}
},
backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+ ...chartOptions.value
+}))
+
+const chartOptions = ref({
legend: {
data: [t('page.charts.traffic.options.download'), t('page.charts.traffic.options.upload')]
},
diff --git a/webui/src/views/charts/components/trends.vue b/webui/src/views/charts/components/trends.vue
index 83e567b66f..e10b80730a 100644
--- a/webui/src/views/charts/components/trends.vue
+++ b/webui/src/views/charts/components/trends.vue
@@ -88,7 +88,18 @@ const loadingOptions = computed(() => ({
textColor: darkStore.isDark ? 'rgba(255, 255, 255, 0.9)' : 'rgb(29, 33, 41)',
maskColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.4)'
}))
-const usedOption = computed(() => chartOptions.value)
+const usedOption = computed(() => ({
+ tooltip: {
+ trigger: 'axis',
+ backgroundColor: darkStore.isDark ? '#333335' : '#ffffff',
+ borderColor: darkStore.isDark ? '#333335' : '#ffffff',
+ textStyle: {
+ color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
+ }
+ },
+ backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+ ...chartOptions.value
+}))
const chartOptions = ref({
xAxis: {
@@ -98,15 +109,7 @@ const chartOptions = ref({
yAxis: {
type: 'value'
},
- tooltip: {
- trigger: 'axis',
- backgroundColor: darkStore.isDark ? '#333335' : '',
- borderColor: darkStore.isDark ? '#333335' : '',
- textStyle: {
- color: darkStore.isDark ? 'rgba(255, 255, 255, 0.7)' : ''
- }
- },
- backgroundColor: darkStore.isDark ? 'rgba(0, 0, 0, 0.0)' : undefined,
+
series: [
{
data: [] as [Date, number][],
diff --git a/webui/src/views/dashboard/components/editDownloaderModal.vue b/webui/src/views/dashboard/components/editDownloaderModal.vue
index a5dd6cb2fa..ab16f056ff 100644
--- a/webui/src/views/dashboard/components/editDownloaderModal.vue
+++ b/webui/src/views/dashboard/components/editDownloaderModal.vue
@@ -13,7 +13,7 @@
qBittorrent
@@ -43,7 +43,11 @@
>
-
+
@@ -79,7 +83,6 @@ const formMap: Record = {
const form = reactive({
name: '',
- paused: false,
config: {
basicAuth: {},
verifySsl: true,
diff --git a/webui/src/views/rule-management/components/subscribe/logModal.vue b/webui/src/views/rule-management/components/subscribe/logModal.vue
index 2073349844..c673af7e16 100644
--- a/webui/src/views/rule-management/components/subscribe/logModal.vue
+++ b/webui/src/views/rule-management/components/subscribe/logModal.vue
@@ -3,8 +3,7 @@
v-model:visible="showModal"
:title="t('page.rule_management.ruleSubscribe.updateLog')"
unmount-on-close
- width="auto"
- :modal-style="{ width: '35vw' }"
+ :modal-style="{ width: '30vw' }"
>