From 566fab8f0560e5f3a6436b705ccde2ccca9bab71 Mon Sep 17 00:00:00 2001 From: ahjephson Date: Sat, 17 Aug 2024 09:48:24 +0100 Subject: [PATCH] Update field dialogs and share ratio --- .../Dialogs/NumericFieldDialog.razor | 15 ++ .../Dialogs/NumericFieldDialog.razor.cs | 69 ++++++++++ .../Components/Dialogs/ShareRatioDialog.razor | 35 +++++ .../Dialogs/ShareRatioDialog.razor.cs | 130 ++++++++++++++++++ .../Dialogs/SliderFieldDialog.razor | 4 +- .../Dialogs/SliderFieldDialog.razor.cs | 36 ++++- ...ldDialog.razor => StringFieldDialog.razor} | 6 +- ...og.razor.cs => StringFieldDialog.razor.cs} | 13 +- .../Components/FilesTab.razor.cs | 2 +- .../Options/ConnectionOptions.razor | 2 +- .../Components/TorrentActions.razor.cs | 18 +-- .../Components/TrackersTab.razor.cs | 2 +- Lantean.QBTMudBlade/DialogHelper.cs | 54 +++++--- .../Lantean.QBTMudBlade.csproj | 6 + Lantean.QBTMudBlade/Layout/MainLayout.razor | 4 +- Lantean.QBTMudBlade/Models/ShareRatio.cs | 17 +++ Lantean.QBTMudBlade/Models/Torrent.cs | 10 +- Lantean.QBTMudBlade/Pages/Login.razor.cs | 2 +- Lantean.QBTMudBlade/Services/DataManager.cs | 6 +- Lantean.QBitTorrentClient/ApiClient.cs | 3 +- Lantean.QBitTorrentClient/IApiClient.cs | 2 +- Lantean.QBitTorrentClient/Limits.cs | 4 +- Lantean.QBitTorrentClient/Models/Torrent.cs | 12 +- 23 files changed, 394 insertions(+), 58 deletions(-) create mode 100644 Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor create mode 100644 Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor.cs create mode 100644 Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor create mode 100644 Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor.cs rename Lantean.QBTMudBlade/Components/Dialogs/{SingleFieldDialog.razor => StringFieldDialog.razor} (79%) rename Lantean.QBTMudBlade/Components/Dialogs/{SingleFieldDialog.razor.cs => StringFieldDialog.razor.cs} (66%) create mode 100644 Lantean.QBTMudBlade/Models/ShareRatio.cs diff --git a/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor b/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor new file mode 100644 index 0000000..ababcdb --- /dev/null +++ b/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor @@ -0,0 +1,15 @@ +@typeparam T + + + + + + + + + + + Cancel + Save + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor.cs b/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor.cs new file mode 100644 index 0000000..409eaa7 --- /dev/null +++ b/Lantean.QBTMudBlade/Components/Dialogs/NumericFieldDialog.razor.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using MudBlazor; +using System.Numerics; + +namespace Lantean.QBTMudBlade.Components.Dialogs +{ + public partial class NumericFieldDialog where T : struct, INumber + { + [CascadingParameter] + public MudDialogInstance MudDialog { get; set; } = default!; + + [Parameter] + public string? Label { get; set; } + + [Parameter] + public T Value { get; set; } + + [Parameter] + public T Min { get; set; } = T.Zero; + + [Parameter] + public T Max { get; set; } = T.One; + + [Parameter] + public bool Disabled { get; set; } + + [Parameter] + public Func? ValueDisplayFunc { get; set; } + + [Parameter] + public Func? ValueGetFunc { get; set; } + + private string? GetDisplayValue() + { + var value = ValueDisplayFunc?.Invoke(Value); + return value is null ? Value.ToString() : value; + } + + protected void ValueChanged(string value) + { + if (ValueGetFunc is not null) + { + Value = ValueGetFunc.Invoke(value); + + return; + } + + if (T.TryParse(value, null, out var result)) + { + Value = result; + } + else + { + Value = Min; + } + } + + protected void Cancel(MouseEventArgs args) + { + MudDialog.Cancel(); + } + + protected void Submit(MouseEventArgs args) + { + MudDialog.Close(DialogResult.Ok(Value)); + } + } +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor b/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor new file mode 100644 index 0000000..d6e497e --- /dev/null +++ b/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor @@ -0,0 +1,35 @@ + + + + + + Use global share limit + Set no share limit + Set share limit to + + + + + + + + + + + + + + + + + + + + + + + + Cancel + Save + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor.cs b/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor.cs new file mode 100644 index 0000000..5ad7042 --- /dev/null +++ b/Lantean.QBTMudBlade/Components/Dialogs/ShareRatioDialog.razor.cs @@ -0,0 +1,130 @@ +using Lantean.QBitTorrentClient; +using Lantean.QBTMudBlade.Models; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using MudBlazor; + +namespace Lantean.QBTMudBlade.Components.Dialogs +{ + public partial class ShareRatioDialog + { + [CascadingParameter] + public MudDialogInstance MudDialog { get; set; } = default!; + + [Parameter] + public string? Label { get; set; } + + [Parameter] + public ShareRatioMax? Value { get; set; } + + [Parameter] + public bool Disabled { get; set; } + + protected int ShareRatioType { get; set; } + + protected bool RatioEnabled { get; set; } + + protected float Ratio { get; set; } + + protected bool TotalMinutesEnabled { get; set; } + + protected int TotalMinutes { get; set; } + + protected bool InactiveMinutesEnabled { get; set; } + + protected int InactiveMinutes { get; set; } + + protected bool CustomEnabled => ShareRatioType == 0; + + protected void RatioEnabledChanged(bool value) + { + RatioEnabled = value; + } + + protected void RatioChanged(float value) + { + Ratio = value; + } + + protected void TotalMinutesEnabledChanged(bool value) + { + TotalMinutesEnabled = value; + } + + protected void TotalMinutesChanged(int value) + { + TotalMinutes = value; + } + + protected void InactiveMinutesEnabledChanged(bool value) + { + InactiveMinutesEnabled = value; + } + + protected void InactiveMinutesChanged(int value) + { + InactiveMinutes = value; + } + + protected override void OnParametersSet() + { + if (Value is null || (Value.RatioLimit == Limits.GlobalLimit && Value.SeedingTimeLimit == Limits.GlobalLimit && Value.InactiveSeedingTimeLimit == Limits.GlobalLimit)) + { + ShareRatioType = Limits.GlobalLimit; + } + else if (Value.MaxRatio == Limits.NoLimit && Value.MaxSeedingTime == Limits.NoLimit && Value.MaxInactiveSeedingTime == Limits.NoLimit) + { + ShareRatioType = Limits.NoLimit; + } + else + { + ShareRatioType = 0; + if (Value.RatioLimit >= 0) + { + RatioEnabled = true; + Ratio = Value.RatioLimit; + } + if (Value.SeedingTimeLimit >= 0) + { + TotalMinutesEnabled = true; + TotalMinutes = (int)Value.SeedingTimeLimit; + } + if (Value.InactiveSeedingTimeLimit >= 0) + { + InactiveMinutesEnabled = true; + InactiveMinutes = (int)Value.InactiveSeedingTimeLimit; + } + } + } + + protected void ShareRatioTypeChanged(int value) + { + ShareRatioType = value; + } + + protected void Cancel(MouseEventArgs args) + { + MudDialog.Cancel(); + } + + protected void Submit(MouseEventArgs args) + { + var result = new ShareRatio(); + if (ShareRatioType == Limits.GlobalLimit) + { + result.RatioLimit = result.SeedingTimeLimit = result.InactiveSeedingTimeLimit = Limits.GlobalLimit; + } + else if (ShareRatioType == Limits.NoLimit) + { + result.RatioLimit = result.SeedingTimeLimit = result.InactiveSeedingTimeLimit = Limits.NoLimit; + } + else + { + result.RatioLimit = RatioEnabled ? Ratio : Limits.NoLimit; + result.SeedingTimeLimit = TotalMinutesEnabled ? TotalMinutes : Limits.NoLimit; + result.InactiveSeedingTimeLimit = InactiveMinutesEnabled ? InactiveMinutes : Limits.NoLimit; + } + MudDialog.Close(DialogResult.Ok(result)); + } + } +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor b/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor index 519babf..0d7333e 100644 --- a/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor +++ b/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor @@ -4,10 +4,10 @@ - + - + diff --git a/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor.cs b/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor.cs index 83a8d07..baec82d 100644 --- a/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor.cs +++ b/Lantean.QBTMudBlade/Components/Dialogs/SliderFieldDialog.razor.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using MudBlazor; +using System.ComponentModel; using System.Numerics; namespace Lantean.QBTMudBlade.Components.Dialogs @@ -26,12 +27,39 @@ namespace Lantean.QBTMudBlade.Components.Dialogs public bool Disabled { get; set; } [Parameter] - public Func? LabelFunc { get; set; } + public Func? ValueDisplayFunc { get; set; } - private string? GetLabel() + [Parameter] + public Func? ValueGetFunc { get; set; } + + private string? GetDisplayValue() { - var label = LabelFunc?.Invoke(Value); - return label is null ? Label : label; + var value = ValueDisplayFunc?.Invoke(Value); + return value is null ? Value.ToString() : value; + } + + protected void ValueChanged(T value) + { + Value = value; + } + + protected void ValueChanged(string value) + { + if (ValueGetFunc is not null) + { + Value = ValueGetFunc.Invoke(value); + + return; + } + + if (T.TryParse(value, null, out var result)) + { + Value = result; + } + else + { + Value = Min; + } } protected void Cancel(MouseEventArgs args) diff --git a/Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor b/Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor similarity index 79% rename from Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor rename to Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor index 26b79fd..75c4111 100644 --- a/Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor +++ b/Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor @@ -1,10 +1,8 @@ -@typeparam T - - + - + diff --git a/Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor.cs b/Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor.cs similarity index 66% rename from Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor.cs rename to Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor.cs index 254db22..5d768a5 100644 --- a/Lantean.QBTMudBlade/Components/Dialogs/SingleFieldDialog.razor.cs +++ b/Lantean.QBTMudBlade/Components/Dialogs/StringFieldDialog.razor.cs @@ -4,7 +4,7 @@ using MudBlazor; namespace Lantean.QBTMudBlade.Components.Dialogs { - public partial class SingleFieldDialog + public partial class StringFieldDialog { [CascadingParameter] public MudDialogInstance MudDialog { get; set; } = default!; @@ -13,20 +13,11 @@ namespace Lantean.QBTMudBlade.Components.Dialogs public string? Label { get; set; } [Parameter] - public T? Value { get; set; } + public string? Value { get; set; } [Parameter] public bool Disabled { get; set; } - [Parameter] - public Func? LabelFunc { get; set; } - - private string? GetLabel() - { - var label = LabelFunc?.Invoke(Value); - return label is null ? Label : label; - } - protected void Cancel(MouseEventArgs args) { MudDialog.Cancel(); diff --git a/Lantean.QBTMudBlade/Components/FilesTab.razor.cs b/Lantean.QBTMudBlade/Components/FilesTab.razor.cs index 77b03a5..b5be11b 100644 --- a/Lantean.QBTMudBlade/Components/FilesTab.razor.cs +++ b/Lantean.QBTMudBlade/Components/FilesTab.razor.cs @@ -308,7 +308,7 @@ namespace Lantean.QBTMudBlade.Components { var contentItem = contentItems[0]; var name = contentItem.GetFileName(); - await DialogService.ShowSingleFieldDialog("Rename", "New name", name, async value => await ApiClient.RenameFile(Hash, contentItem.Name, contentItem.Path + value)); + await DialogService.ShowStringFieldDialog("Rename", "New name", name, async value => await ApiClient.RenameFile(Hash, contentItem.Name, contentItem.Path + value)); } else { diff --git a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor index 19fa24e..e0de66a 100644 --- a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor @@ -41,7 +41,7 @@ - + diff --git a/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs b/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs index 127e4c2..c214464 100644 --- a/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs +++ b/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs @@ -173,7 +173,7 @@ namespace Lantean.QBTMudBlade.Components savePath = torrent.SavePath; } - await DialogService.ShowSingleFieldDialog("Set Location", "Location", savePath, v => ApiClient.SetTorrentLocation(v, null, Hashes.ToArray())); + await DialogService.ShowStringFieldDialog("Set Location", "Location", savePath, v => ApiClient.SetTorrentLocation(v, null, Hashes.ToArray())); } protected async Task Rename() @@ -184,7 +184,7 @@ namespace Lantean.QBTMudBlade.Components { name = torrent.Name; } - await DialogService.ShowSingleFieldDialog("Rename", "Name", name, v => ApiClient.SetTorrentName(v, hash)); + await DialogService.ShowStringFieldDialog("Rename", "Name", name, v => ApiClient.SetTorrentName(v, hash)); } protected async Task RenameFiles() @@ -211,7 +211,7 @@ namespace Lantean.QBTMudBlade.Components string hash = Hashes.First(); if (Hashes.Any() && Torrents.TryGetValue(hash, out var torrent)) { - downloadLimit = torrent.UploadLimit; + downloadLimit = torrent.DownloadLimit; } await DialogService.InvokeDownloadRateDialog(ApiClient, downloadLimit, Hashes); @@ -231,14 +231,16 @@ namespace Lantean.QBTMudBlade.Components protected async Task LimitShareRatio() { - float ratioLimit = -1; - string hash = Hashes.First(); - if (Hashes.Any() && Torrents.TryGetValue(hash, out var torrent)) + var torrents = new List(); + foreach (var hash in Hashes) { - ratioLimit = torrent.RatioLimit; + if (Torrents.TryGetValue(hash, out var torrent)) + { + torrents.Add(torrent); + } } - await DialogService.InvokeShareRatioDialog(ApiClient, ratioLimit, Hashes); + await DialogService.InvokeShareRatioDialog(ApiClient, torrents); } protected async Task ToggleSuperSeeding() diff --git a/Lantean.QBTMudBlade/Components/TrackersTab.razor.cs b/Lantean.QBTMudBlade/Components/TrackersTab.razor.cs index ba04a90..9ea63f2 100644 --- a/Lantean.QBTMudBlade/Components/TrackersTab.razor.cs +++ b/Lantean.QBTMudBlade/Components/TrackersTab.razor.cs @@ -187,7 +187,7 @@ namespace Lantean.QBTMudBlade.Components return; } - await DialogService.ShowSingleFieldDialog("Edit Tracker", "Tracker URL", tracker.Url, async (value) => await ApiClient.EditTracker(Hash, tracker.Url, value)); + await DialogService.ShowStringFieldDialog("Edit Tracker", "Tracker URL", tracker.Url, async (value) => await ApiClient.EditTracker(Hash, tracker.Url, value)); } protected Task RemoveTrackerToolbar() diff --git a/Lantean.QBTMudBlade/DialogHelper.cs b/Lantean.QBTMudBlade/DialogHelper.cs index 07d3165..e39fcdd 100644 --- a/Lantean.QBTMudBlade/DialogHelper.cs +++ b/Lantean.QBTMudBlade/DialogHelper.cs @@ -246,14 +246,14 @@ namespace Lantean.QBTMudBlade }); } - public static async Task ShowSingleFieldDialog(this IDialogService dialogService, string title, string label, T? value, Func onSuccess) + public static async Task ShowStringFieldDialog(this IDialogService dialogService, string title, string label, string? value, Func onSuccess) { var parameters = new DialogParameters { - { nameof(SingleFieldDialog.Label), label }, - { nameof(SingleFieldDialog.Value), value } + { nameof(StringFieldDialog.Label), label }, + { nameof(StringFieldDialog.Value), value } }; - var result = await dialogService.ShowAsync>(title, parameters, FormDialogOptions); + var result = await dialogService.ShowAsync(title, parameters, FormDialogOptions); var dialogResult = await result.Result; if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null) @@ -261,19 +261,23 @@ namespace Lantean.QBTMudBlade return; } - await onSuccess((T)dialogResult.Data); + await onSuccess((string)dialogResult.Data); } public static async Task InvokeDownloadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable hashes) { - Func labelFunc = v => v == Limits.NoLimit ? "No limit" : v.ToString(); + Func valueDisplayFunc = v => v == Limits.NoLimit ? "∞" : v.ToString(); + Func valueGetFunc = v => v == "∞" ? Limits.NoLimit : long.Parse(v); var parameters = new DialogParameters { { nameof(SliderFieldDialog.Value), rate }, - { nameof(SliderFieldDialog.Min), 0L }, + { nameof(SliderFieldDialog.Min), -1L }, { nameof(SliderFieldDialog.Max), 100L }, - { nameof(SingleFieldDialog.LabelFunc), labelFunc } + { nameof(SliderFieldDialog.Value), rate }, + { nameof(SliderFieldDialog.ValueDisplayFunc), valueDisplayFunc }, + { nameof(SliderFieldDialog.ValueGetFunc), valueGetFunc }, + { nameof(SliderFieldDialog.Label), "Download rate limit" } }; var result = await dialogService.ShowAsync>("Download Rate", parameters, FormDialogOptions); @@ -288,12 +292,18 @@ namespace Lantean.QBTMudBlade public static async Task InvokeUploadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable hashes) { + Func valueDisplayFunc = v => v == Limits.NoLimit ? "∞" : v.ToString(); + Func valueGetFunc = v => v == "∞" ? Limits.NoLimit : long.Parse(v); + var parameters = new DialogParameters { { nameof(SliderFieldDialog.Value), rate }, - { nameof(SliderFieldDialog.Min), 0L }, + { nameof(SliderFieldDialog.Min), -1L }, { nameof(SliderFieldDialog.Max), 100L }, - { nameof(SliderFieldDialog.Disabled), rate == Limits.GlobalLimit }, + { nameof(SliderFieldDialog.Value), rate }, + { nameof(SliderFieldDialog.ValueDisplayFunc), valueDisplayFunc }, + { nameof(SliderFieldDialog.ValueGetFunc), valueGetFunc }, + { nameof(SliderFieldDialog.Label), "Upload rate limit" } }; var result = await dialogService.ShowAsync>("Upload Rate", parameters, FormDialogOptions); @@ -306,15 +316,25 @@ namespace Lantean.QBTMudBlade await apiClient.SetTorrentUploadLimit((long)dialogResult.Data, null, hashes.ToArray()); } - public static async Task InvokeShareRatioDialog(this IDialogService dialogService, IApiClient apiClient, float ratio, IEnumerable hashes) + public static async Task InvokeShareRatioDialog(this IDialogService dialogService, IApiClient apiClient, IEnumerable torrents) { + var torrentShareRatios = torrents.Select(t => new ShareRatioMax + { + InactiveSeedingTimeLimit = t.InactiveSeedingTimeLimit, + MaxInactiveSeedingTime = t.InactiveSeedingTimeLimit, + MaxRatio = t.MaxRatio, + MaxSeedingTime = t.MaxSeedingTime, + RatioLimit = t.RatioLimit, + SeedingTimeLimit = t.SeedingTimeLimit, + }); + + var torrentsHaveSameShareRatio = torrentShareRatios.Distinct().Count() == 1; + var parameters = new DialogParameters { - { nameof(SliderFieldDialog.Value), ratio }, - { nameof(SliderFieldDialog.Min), 0F }, - { nameof(SliderFieldDialog.Max), 100F }, + { nameof(ShareRatioDialog.Value), torrentsHaveSameShareRatio ? torrentShareRatios.FirstOrDefault() : null }, }; - var result = await dialogService.ShowAsync>("Share ratio", parameters, FormDialogOptions); + var result = await dialogService.ShowAsync("Share ratio", parameters, FormDialogOptions); var dialogResult = await result.Result; if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null) @@ -322,7 +342,9 @@ namespace Lantean.QBTMudBlade return; } - await apiClient.SetTorrentShareLimit((float)dialogResult.Data, 0, null, hashes.ToArray()); + var shareRatio = (ShareRatio)dialogResult.Data; + + await apiClient.SetTorrentShareLimit(shareRatio.RatioLimit, shareRatio.SeedingTimeLimit, shareRatio.InactiveSeedingTimeLimit, null, torrents.Select(t => t.Hash).ToArray()); } public static async Task>?> ShowFilterOptionsDialog(this IDialogService dialogService, List>? propertyFilterDefinitions) diff --git a/Lantean.QBTMudBlade/Lantean.QBTMudBlade.csproj b/Lantean.QBTMudBlade/Lantean.QBTMudBlade.csproj index cb4f283..97853f8 100644 --- a/Lantean.QBTMudBlade/Lantean.QBTMudBlade.csproj +++ b/Lantean.QBTMudBlade/Lantean.QBTMudBlade.csproj @@ -26,6 +26,12 @@ true + + true + + + true + true diff --git a/Lantean.QBTMudBlade/Layout/MainLayout.razor b/Lantean.QBTMudBlade/Layout/MainLayout.razor index 2782cac..f87d20b 100644 --- a/Lantean.QBTMudBlade/Layout/MainLayout.razor +++ b/Lantean.QBTMudBlade/Layout/MainLayout.razor @@ -3,7 +3,7 @@ - + @@ -16,7 +16,7 @@ @if (ErrorBoundary?.Errors.Count > 0) { - + } diff --git a/Lantean.QBTMudBlade/Models/ShareRatio.cs b/Lantean.QBTMudBlade/Models/ShareRatio.cs new file mode 100644 index 0000000..eb14ba4 --- /dev/null +++ b/Lantean.QBTMudBlade/Models/ShareRatio.cs @@ -0,0 +1,17 @@ +namespace Lantean.QBTMudBlade.Models +{ + public record ShareRatio + { + public float RatioLimit { get; set; } + public float SeedingTimeLimit { get; set; } + public float InactiveSeedingTimeLimit { get; set; } + + } + + public record ShareRatioMax : ShareRatio + { + public float MaxRatio { get; set; } + public float MaxSeedingTime { get; set; } + public float MaxInactiveSeedingTime { get; set; } + } +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Models/Torrent.cs b/Lantean.QBTMudBlade/Models/Torrent.cs index ab31fcd..1e66ceb 100644 --- a/Lantean.QBTMudBlade/Models/Torrent.cs +++ b/Lantean.QBTMudBlade/Models/Torrent.cs @@ -50,7 +50,9 @@ long uploaded, long uploadedSession, long uploadSpeed, - long reannounce) + long reannounce, + float inactiveSeedingTimeLimit, + float maxInactiveSeedingTime) { Hash = hash; AddedOn = addedOn; @@ -100,6 +102,8 @@ UploadedSession = uploadedSession; UploadSpeed = uploadSpeed; Reannounce = reannounce; + InactiveSeedingTimeLimit = inactiveSeedingTimeLimit; + MaxInactiveSeedingTime = maxInactiveSeedingTime; } protected Torrent() @@ -213,6 +217,10 @@ public long Reannounce { get; set; } + public float InactiveSeedingTimeLimit { get; set; } + + public float MaxInactiveSeedingTime { get; set; } + public override bool Equals(object? obj) { if (obj is null) return false; diff --git a/Lantean.QBTMudBlade/Pages/Login.razor.cs b/Lantean.QBTMudBlade/Pages/Login.razor.cs index dedf86d..efeeeb5 100644 --- a/Lantean.QBTMudBlade/Pages/Login.razor.cs +++ b/Lantean.QBTMudBlade/Pages/Login.razor.cs @@ -48,7 +48,7 @@ namespace Lantean.QBTMudBlade.Pages #if DEBUG protected override Task OnInitializedAsync() { - return DoLogin("admin", "ALKEVRPZP"); + return DoLogin("admin", "YZQC4Jhcw"); } #endif } diff --git a/Lantean.QBTMudBlade/Services/DataManager.cs b/Lantean.QBTMudBlade/Services/DataManager.cs index 95f21bc..df01673 100644 --- a/Lantean.QBTMudBlade/Services/DataManager.cs +++ b/Lantean.QBTMudBlade/Services/DataManager.cs @@ -532,7 +532,9 @@ namespace Lantean.QBTMudBlade.Services torrent.Uploaded.GetValueOrDefault(), torrent.UploadedSession.GetValueOrDefault(), torrent.UploadSpeed.GetValueOrDefault(), - torrent.Reannounce ?? 0); + torrent.Reannounce ?? 0, + torrent.InactiveSeedingTimeLimit.GetValueOrDefault(), + torrent.MaxInactiveSeedingTime.GetValueOrDefault()); } private static void UpdateCategory(Category existingCategory, QBitTorrentClient.Models.Category category) @@ -593,6 +595,8 @@ namespace Lantean.QBTMudBlade.Services existingTorrent.UploadedSession = torrent.UploadedSession ?? existingTorrent.UploadedSession; existingTorrent.UploadSpeed = torrent.UploadSpeed ?? existingTorrent.UploadSpeed; existingTorrent.Reannounce = torrent.Reannounce ?? existingTorrent.Reannounce; + existingTorrent.InactiveSeedingTimeLimit = torrent.InactiveSeedingTimeLimit ?? existingTorrent.InactiveSeedingTimeLimit; + existingTorrent.MaxInactiveSeedingTime = torrent.MaxInactiveSeedingTime ?? existingTorrent.MaxInactiveSeedingTime; } public Dictionary CreateContentsList(IReadOnlyList files) diff --git a/Lantean.QBitTorrentClient/ApiClient.cs b/Lantean.QBitTorrentClient/ApiClient.cs index abaf799..56dea8c 100644 --- a/Lantean.QBitTorrentClient/ApiClient.cs +++ b/Lantean.QBitTorrentClient/ApiClient.cs @@ -675,12 +675,13 @@ namespace Lantean.QBitTorrentClient response.EnsureSuccessStatusCode(); } - public async Task SetTorrentShareLimit(float ratioLimit, float seedingTimeLimit, bool? all = null, params string[] hashes) + public async Task SetTorrentShareLimit(float ratioLimit, float seedingTimeLimit, float inactiveSeedingTimeLimit, bool? all = null, params string[] hashes) { var content = new FormUrlEncodedBuilder() .AddAllOrPipeSeparated("hashes", all, hashes) .Add("ratioLimit", ratioLimit) .Add("seedingTimeLimit", seedingTimeLimit) + .Add("inactiveSeedingTimeLimit", inactiveSeedingTimeLimit) .ToFormUrlEncodedContent(); var response = await _httpClient.PostAsync("torrents/setShareLimits", content); diff --git a/Lantean.QBitTorrentClient/IApiClient.cs b/Lantean.QBitTorrentClient/IApiClient.cs index e8c0bdd..978d339 100644 --- a/Lantean.QBitTorrentClient/IApiClient.cs +++ b/Lantean.QBitTorrentClient/IApiClient.cs @@ -122,7 +122,7 @@ namespace Lantean.QBitTorrentClient Task SetTorrentDownloadLimit(long limit, bool? all = null, params string[] hashes); - Task SetTorrentShareLimit(float ratioLimit, float seedingTimeLimit, bool? all = null, params string[] hashes); + Task SetTorrentShareLimit(float ratioLimit, float seedingTimeLimit, float inactiveSeedingTimeLimit, bool? all = null, params string[] hashes); Task> GetTorrentUploadLimit(bool? all = null, params string[] hashes); diff --git a/Lantean.QBitTorrentClient/Limits.cs b/Lantean.QBitTorrentClient/Limits.cs index 391c94a..f57d3b8 100644 --- a/Lantean.QBitTorrentClient/Limits.cs +++ b/Lantean.QBitTorrentClient/Limits.cs @@ -2,8 +2,8 @@ { public static class Limits { - public const long GlobalLimit = -2; + public const int GlobalLimit = -2; - public const long NoLimit = -1; + public const int NoLimit = -1; } } \ No newline at end of file diff --git a/Lantean.QBitTorrentClient/Models/Torrent.cs b/Lantean.QBitTorrentClient/Models/Torrent.cs index 725ed43..9329c6c 100644 --- a/Lantean.QBitTorrentClient/Models/Torrent.cs +++ b/Lantean.QBitTorrentClient/Models/Torrent.cs @@ -54,7 +54,9 @@ namespace Lantean.QBitTorrentClient.Models long? uploaded, long? uploadedSession, long? uploadSpeed, - long? reannounce) + long? reannounce, + float? inactiveSeedingTimeLimit, + float? maxInactiveSeedingTime) { AddedOn = addedOn; AmountLeft = amountLeft; @@ -104,6 +106,8 @@ namespace Lantean.QBitTorrentClient.Models UploadedSession = uploadedSession; UploadSpeed = uploadSpeed; Reannounce = reannounce; + InactiveSeedingTimeLimit = inactiveSeedingTimeLimit; + MaxInactiveSeedingTime = maxInactiveSeedingTime; } [JsonPropertyName("added_on")] @@ -250,5 +254,11 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("reannounce")] public long? Reannounce { get; } + + [JsonPropertyName("inactive_seeding_time_limit")] + public float? InactiveSeedingTimeLimit { get; } + + [JsonPropertyName("max_inactive_seeding_time")] + public float? MaxInactiveSeedingTime { get; } } } \ No newline at end of file