From 3d0dbde9f4cbe0fc4c48db3df2956b0bb4181329 Mon Sep 17 00:00:00 2001 From: ahjephson <16685186+ahjephson@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:40:14 +0100 Subject: [PATCH] Add v5 only preferences --- Lantean.QBTMud/Components/FiltersNav.razor.cs | 2 +- .../Components/Options/AdvancedOptions.razor | 17 ++++++++++- .../Options/AdvancedOptions.razor.cs | 12 +++++++- .../Components/Options/BehaviourOptions.razor | 20 ++++++++++++- .../Options/BehaviourOptions.razor.cs | 22 +++++++++++++- .../Components/TorrentActions.razor.cs | 5 ++-- Lantean.QBTMud/Helpers/DialogHelper.cs | 30 ++++++++++++++++++- Lantean.QBTMud/Layout/LoggedInLayout.razor | 10 ++++++- Lantean.QBTMud/Layout/LoggedInLayout.razor.cs | 26 ++++++++++++++++ Lantean.QBTMud/Models/ServerState.cs | 20 +++++++++++-- Lantean.QBTMud/Services/DataManager.cs | 16 +++++++++- .../Models/Preferences.cs | 17 ++++++++++- .../Models/ServerState.cs | 14 +++++++-- .../Models/UpdatePreferences.cs | 9 ++++++ 14 files changed, 204 insertions(+), 16 deletions(-) diff --git a/Lantean.QBTMud/Components/FiltersNav.razor.cs b/Lantean.QBTMud/Components/FiltersNav.razor.cs index bcd796f..719a24a 100644 --- a/Lantean.QBTMud/Components/FiltersNav.razor.cs +++ b/Lantean.QBTMud/Components/FiltersNav.razor.cs @@ -371,7 +371,7 @@ namespace Lantean.QBTMud.Components { var torrents = GetAffectedTorrentHashes(type); - await DialogService.InvokeDeleteTorrentDialog(ApiClient, [.. torrents]); + await DialogService.InvokeDeleteTorrentDialog(ApiClient, Preferences?.ConfirmTorrentDeletion == true, [.. torrents]); } private Dictionary GetTags() diff --git a/Lantean.QBTMud/Components/Options/AdvancedOptions.razor b/Lantean.QBTMud/Components/Options/AdvancedOptions.razor index 1c63590..4c8cbc1 100644 --- a/Lantean.QBTMud/Components/Options/AdvancedOptions.razor +++ b/Lantean.QBTMud/Components/Options/AdvancedOptions.razor @@ -68,6 +68,21 @@ + + + + Confirmation + + + + + + + + + + + @@ -240,4 +255,4 @@ - \ No newline at end of file + diff --git a/Lantean.QBTMud/Components/Options/AdvancedOptions.razor.cs b/Lantean.QBTMud/Components/Options/AdvancedOptions.razor.cs index 754e9d2..5895ba7 100644 --- a/Lantean.QBTMud/Components/Options/AdvancedOptions.razor.cs +++ b/Lantean.QBTMud/Components/Options/AdvancedOptions.razor.cs @@ -16,6 +16,8 @@ namespace Lantean.QBTMud.Components.Options protected int SaveResumeDataInterval { get; private set; } protected int TorrentFileSizeLimit { get; private set; } protected bool RecheckCompletedTorrents { get; private set; } + + protected bool ConfirmTorrentRecheck { get; private set; } protected string? AppInstanceName { get; private set; } protected int RefreshInterval { get; private set; } protected bool ResolvePeerCountries { get; private set; } @@ -97,6 +99,7 @@ namespace Lantean.QBTMud.Components.Options SaveResumeDataInterval = Preferences.SaveResumeDataInterval; TorrentFileSizeLimit = Preferences.TorrentFileSizeLimit / 1024 / 1024; RecheckCompletedTorrents = Preferences.RecheckCompletedTorrents; + ConfirmTorrentRecheck = Preferences.ConfirmTorrentRecheck; AppInstanceName = Preferences.AppInstanceName; RefreshInterval = Preferences.RefreshInterval; ResolvePeerCountries = Preferences.ResolvePeerCountries; @@ -209,6 +212,13 @@ namespace Lantean.QBTMud.Components.Options await PreferencesChanged.InvokeAsync(UpdatePreferences); } + protected async Task ConfirmTorrentRecheckChanged(bool value) + { + ConfirmTorrentRecheck = value; + UpdatePreferences.ConfirmTorrentRecheck = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + protected async Task AppInstanceNameChanged(string value) { AppInstanceName = value; @@ -608,4 +618,4 @@ namespace Lantean.QBTMud.Components.Options await PreferencesChanged.InvokeAsync(UpdatePreferences); } } -} \ No newline at end of file +} diff --git a/Lantean.QBTMud/Components/Options/BehaviourOptions.razor b/Lantean.QBTMud/Components/Options/BehaviourOptions.razor index 3a5280d..6ccd4b8 100644 --- a/Lantean.QBTMud/Components/Options/BehaviourOptions.razor +++ b/Lantean.QBTMud/Components/Options/BehaviourOptions.razor @@ -17,6 +17,24 @@ + + + + Transfer List + + + + + + + + + + + + + + @@ -71,4 +89,4 @@ - \ No newline at end of file + diff --git a/Lantean.QBTMud/Components/Options/BehaviourOptions.razor.cs b/Lantean.QBTMud/Components/Options/BehaviourOptions.razor.cs index c566ecf..67b77b3 100644 --- a/Lantean.QBTMud/Components/Options/BehaviourOptions.razor.cs +++ b/Lantean.QBTMud/Components/Options/BehaviourOptions.razor.cs @@ -4,6 +4,10 @@ namespace Lantean.QBTMud.Components.Options { public partial class BehaviourOptions : Options { + protected bool ConfirmTorrentDeletion { get; set; } + + protected bool StatusBarExternalIp { get; set; } + protected bool FileLogEnabled { get; set; } protected string? FileLogPath { get; set; } @@ -27,6 +31,8 @@ namespace Lantean.QBTMud.Components.Options return false; } + ConfirmTorrentDeletion = Preferences.ConfirmTorrentDeletion; + StatusBarExternalIp = Preferences.StatusBarExternalIp; FileLogEnabled = Preferences.FileLogEnabled; FileLogPath = Preferences.FileLogPath; FileLogBackupEnabled = Preferences.FileLogBackupEnabled; @@ -39,6 +45,20 @@ namespace Lantean.QBTMud.Components.Options return true; } + protected async Task ConfirmTorrentDeletionChanged(bool value) + { + ConfirmTorrentDeletion = value; + UpdatePreferences.ConfirmTorrentDeletion = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task StatusBarExternalIpChanged(bool value) + { + StatusBarExternalIp = value; + UpdatePreferences.StatusBarExternalIp = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + protected async Task FileLogEnabledChanged(bool value) { FileLogEnabled = value; @@ -96,4 +116,4 @@ namespace Lantean.QBTMud.Components.Options await PreferencesChanged.InvokeAsync(UpdatePreferences); } } -} \ No newline at end of file +} diff --git a/Lantean.QBTMud/Components/TorrentActions.razor.cs b/Lantean.QBTMud/Components/TorrentActions.razor.cs index 99f6621..ace3a67 100644 --- a/Lantean.QBTMud/Components/TorrentActions.razor.cs +++ b/Lantean.QBTMud/Components/TorrentActions.razor.cs @@ -7,7 +7,6 @@ using Lantean.QBTMud.Services; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using MudBlazor; -using System.Linq; namespace Lantean.QBTMud.Components { @@ -162,7 +161,7 @@ namespace Lantean.QBTMud.Components protected async Task Remove() { - var deleted = await DialogService.InvokeDeleteTorrentDialog(ApiClient, Hashes.ToArray()); + var deleted = await DialogService.InvokeDeleteTorrentDialog(ApiClient, Preferences?.ConfirmTorrentDeletion == true, Hashes.ToArray()); if (deleted) { @@ -258,7 +257,7 @@ namespace Lantean.QBTMud.Components protected async Task ForceRecheck() { - await ApiClient.RecheckTorrents(null, Hashes.ToArray()); + await DialogService.ForceRecheckAsync(ApiClient, Hashes, Preferences?.ConfirmTorrentRecheck == true); } protected async Task ForceReannounce() diff --git a/Lantean.QBTMud/Helpers/DialogHelper.cs b/Lantean.QBTMud/Helpers/DialogHelper.cs index e3b7282..16ac0b6 100644 --- a/Lantean.QBTMud/Helpers/DialogHelper.cs +++ b/Lantean.QBTMud/Helpers/DialogHelper.cs @@ -122,7 +122,7 @@ namespace Lantean.QBTMud.Helpers _ = await apiClient.AddTorrent(addTorrentParams); } - public static async Task InvokeDeleteTorrentDialog(this IDialogService dialogService, IApiClient apiClient, params string[] hashes) + public static async Task InvokeDeleteTorrentDialog(this IDialogService dialogService, IApiClient apiClient, bool confirmTorrentDeletion, params string[] hashes) { if (hashes.Length == 0) { @@ -134,6 +134,12 @@ namespace Lantean.QBTMud.Helpers { nameof(DeleteDialog.Count), hashes.Length } }; + if (!confirmTorrentDeletion) + { + await apiClient.DeleteTorrents(hashes: hashes, deleteFiles: false); + return true; + } + var reference = await dialogService.ShowAsync($"Remove torrent{(hashes.Length == 1 ? "" : "s")}?", parameters, ConfirmDialogOptions); var dialogResult = await reference.Result; if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null) @@ -146,6 +152,28 @@ namespace Lantean.QBTMud.Helpers return true; } + public static async Task ForceRecheckAsync(this IDialogService dialogService, IApiClient apiClient, IEnumerable hashes, bool confirmTorrentRecheck) + { + var hashArray = hashes?.ToArray() ?? []; + if (hashArray.Length == 0) + { + return; + } + + if (confirmTorrentRecheck) + { + var content = $"Are you sure you want to recheck the selected torrent{(hashArray.Length == 1 ? "" : "s")}?"; + + var confirmed = await dialogService.ShowConfirmDialog("Force recheck", content); + if (!confirmed) + { + return; + } + } + + await apiClient.RecheckTorrents(null, hashArray); + } + public static async Task InvokeDownloadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable hashes) { Func valueDisplayFunc = v => v == Limits.NoLimit ? "∞" : v.ToString(); diff --git a/Lantean.QBTMud/Layout/LoggedInLayout.razor b/Lantean.QBTMud/Layout/LoggedInLayout.razor index 9b554af..38c1113 100644 --- a/Lantean.QBTMud/Layout/LoggedInLayout.razor +++ b/Lantean.QBTMud/Layout/LoggedInLayout.razor @@ -33,6 +33,14 @@ } @DisplayHelpers.Size(MainData?.ServerState.FreeSpaceOnDisk, "Free space: ") + @{ + var externalIpLabel = Preferences?.StatusBarExternalIp == true ? BuildExternalIpLabel(MainData?.ServerState) : null; + } + @if (!string.IsNullOrEmpty(externalIpLabel)) + { + + @externalIpLabel + } DHT @(MainData?.ServerState.DHTNodes ?? 0) nodes @@ -70,4 +78,4 @@ - \ No newline at end of file + diff --git a/Lantean.QBTMud/Layout/LoggedInLayout.razor.cs b/Lantean.QBTMud/Layout/LoggedInLayout.razor.cs index 5d491fd..f892066 100644 --- a/Lantean.QBTMud/Layout/LoggedInLayout.razor.cs +++ b/Lantean.QBTMud/Layout/LoggedInLayout.razor.cs @@ -201,6 +201,32 @@ namespace Lantean.QBTMud.Layout }; } + private static string? BuildExternalIpLabel(ServerState? serverState) + { + if (serverState is null) + { + return null; + } + + var v4 = serverState.LastExternalAddressV4; + var v6 = serverState.LastExternalAddressV6; + var hasV4 = !string.IsNullOrWhiteSpace(v4); + var hasV6 = !string.IsNullOrWhiteSpace(v6); + + if (!hasV4 && !hasV6) + { + return "External IP: N/A"; + } + + if (hasV4 && hasV6) + { + return $"External IPs: {v4}, {v6}"; + } + + var address = hasV4 ? v4 : v6; + return $"External IP: {address}"; + } + private void OnCategoryChanged(string category) { if (Category == category) diff --git a/Lantean.QBTMud/Models/ServerState.cs b/Lantean.QBTMud/Models/ServerState.cs index ca6e827..a1740e7 100644 --- a/Lantean.QBTMud/Models/ServerState.cs +++ b/Lantean.QBTMud/Models/ServerState.cs @@ -27,7 +27,17 @@ long uploadRateLimit, bool useAltSpeedLimits, bool useSubcategories, - float writeCacheOverload) : base(connectionStatus, dHTNodes, downloadInfoData, downloadInfoSpeed, downloadRateLimit, uploadInfoData, uploadInfoSpeed, uploadRateLimit) + float writeCacheOverload, + string lastExternalAddressV4, + string lastExternalAddressV6) : base( + connectionStatus, + dHTNodes, + downloadInfoData, + downloadInfoSpeed, + downloadRateLimit, + uploadInfoData, + uploadInfoSpeed, + uploadRateLimit) { AllTimeDownloaded = allTimeDownloaded; AllTimeUploaded = allTimeUploaded; @@ -46,6 +56,8 @@ UseAltSpeedLimits = useAltSpeedLimits; UseSubcategories = useSubcategories; WriteCacheOverload = writeCacheOverload; + LastExternalAddressV4 = lastExternalAddressV4; + LastExternalAddressV6 = lastExternalAddressV6; } public ServerState() @@ -85,5 +97,9 @@ public bool UseSubcategories { get; set; } public float WriteCacheOverload { get; set; } + + public string LastExternalAddressV4 { get; set; } = string.Empty; + + public string LastExternalAddressV6 { get; set; } = string.Empty; } -} \ No newline at end of file +} diff --git a/Lantean.QBTMud/Services/DataManager.cs b/Lantean.QBTMud/Services/DataManager.cs index 9b311c8..ee2e974 100644 --- a/Lantean.QBTMud/Services/DataManager.cs +++ b/Lantean.QBTMud/Services/DataManager.cs @@ -145,7 +145,9 @@ namespace Lantean.QBTMud.Services serverState.UploadRateLimit.GetValueOrDefault(), serverState.UseAltSpeedLimits.GetValueOrDefault(), serverState.UseSubcategories.GetValueOrDefault(), - serverState.WriteCacheOverload.GetValueOrDefault()); + serverState.WriteCacheOverload.GetValueOrDefault(), + serverState.LastExternalAddressV4 ?? string.Empty, + serverState.LastExternalAddressV6 ?? string.Empty); } public bool MergeMainData(QBitTorrentClient.Models.MainData mainData, MainData torrentList, out bool filterChanged) @@ -551,6 +553,18 @@ namespace Lantean.QBTMud.Services changed = true; } + if (serverState.LastExternalAddressV4 is not null && existingServerState.LastExternalAddressV4 != serverState.LastExternalAddressV4) + { + existingServerState.LastExternalAddressV4 = serverState.LastExternalAddressV4; + changed = true; + } + + if (serverState.LastExternalAddressV6 is not null && existingServerState.LastExternalAddressV6 != serverState.LastExternalAddressV6) + { + existingServerState.LastExternalAddressV6 = serverState.LastExternalAddressV6; + changed = true; + } + return changed; } diff --git a/Lantean.QBitTorrentClient/Models/Preferences.cs b/Lantean.QBitTorrentClient/Models/Preferences.cs index 6d7cdda..774a5ec 100644 --- a/Lantean.QBitTorrentClient/Models/Preferences.cs +++ b/Lantean.QBitTorrentClient/Models/Preferences.cs @@ -221,7 +221,10 @@ namespace Lantean.QBitTorrentClient.Models bool webUiUpnp, bool webUiUseCustomHttpHeadersEnabled, string webUiUsername, - string webUiPassword + string webUiPassword, + bool confirmTorrentDeletion, + bool confirmTorrentRecheck, + bool statusBarExternalIp ) { AddToTopOfQueue = addToTopOfQueue; @@ -440,6 +443,9 @@ namespace Lantean.QBitTorrentClient.Models WebUiUseCustomHttpHeadersEnabled = webUiUseCustomHttpHeadersEnabled; WebUiUsername = webUiUsername; WebUiPassword = webUiPassword; + ConfirmTorrentDeletion = confirmTorrentDeletion; + ConfirmTorrentRecheck = confirmTorrentRecheck; + StatusBarExternalIp = statusBarExternalIp; } [JsonPropertyName("add_to_top_of_queue")] @@ -1089,5 +1095,14 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("web_ui_password")] public string WebUiPassword { get; } + + [JsonPropertyName("confirm_torrent_deletion")] + public bool ConfirmTorrentDeletion { get; } + + [JsonPropertyName("confirm_torrent_recheck")] + public bool ConfirmTorrentRecheck { get; } + + [JsonPropertyName("status_bar_external_ip")] + public bool StatusBarExternalIp { get; } } } diff --git a/Lantean.QBitTorrentClient/Models/ServerState.cs b/Lantean.QBitTorrentClient/Models/ServerState.cs index 920c40c..36e8271 100644 --- a/Lantean.QBitTorrentClient/Models/ServerState.cs +++ b/Lantean.QBitTorrentClient/Models/ServerState.cs @@ -30,7 +30,9 @@ namespace Lantean.QBitTorrentClient.Models long? uploadRateLimit, bool? useAltSpeedLimits, bool? useSubcategories, - float? writeCacheOverload) : base(connectionStatus, dHTNodes, downloadInfoData, downloadInfoSpeed, downloadRateLimit, uploadInfoData, uploadInfoSpeed, uploadRateLimit) + float? writeCacheOverload, + string? lastExternalAddressV4 = null, + string? lastExternalAddressV6 = null) : base(connectionStatus, dHTNodes, downloadInfoData, downloadInfoSpeed, downloadRateLimit, uploadInfoData, uploadInfoSpeed, uploadRateLimit) { AllTimeDownloaded = allTimeDownloaded; AllTimeUploaded = allTimeUploaded; @@ -49,6 +51,8 @@ namespace Lantean.QBitTorrentClient.Models UseAltSpeedLimits = useAltSpeedLimits; UseSubcategories = useSubcategories; WriteCacheOverload = writeCacheOverload; + LastExternalAddressV4 = lastExternalAddressV4; + LastExternalAddressV6 = lastExternalAddressV6; } [JsonPropertyName("alltime_dl")] @@ -101,5 +105,11 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("write_cache_overload")] public float? WriteCacheOverload { get; } + + [JsonPropertyName("last_external_address_v4")] + public string? LastExternalAddressV4 { get; } + + [JsonPropertyName("last_external_address_v6")] + public string? LastExternalAddressV6 { get; } } -} \ No newline at end of file +} diff --git a/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs b/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs index 21e2033..19818b6 100644 --- a/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs +++ b/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs @@ -653,6 +653,15 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("web_ui_password")] public string? WebUiPassword { get; set; } + [JsonPropertyName("confirm_torrent_deletion")] + public bool? ConfirmTorrentDeletion { get; set; } + + [JsonPropertyName("confirm_torrent_recheck")] + public bool? ConfirmTorrentRecheck { get; set; } + + [JsonPropertyName("status_bar_external_ip")] + public bool? StatusBarExternalIp { get; set; } + public void Validate() { if (MaxRatio.HasValue && MaxRatioEnabled.HasValue)