diff --git a/Lantean.QBTBlazor.Test/Lantean.QBTBlazor.Test.csproj b/Lantean.QBTBlazor.Test/Lantean.QBTBlazor.Test.csproj index 3531ced..17c5002 100644 --- a/Lantean.QBTBlazor.Test/Lantean.QBTBlazor.Test.csproj +++ b/Lantean.QBTBlazor.Test/Lantean.QBTBlazor.Test.csproj @@ -20,6 +20,10 @@ + + + + diff --git a/Lantean.QBTMudBlade/Components/GeneralTab.razor b/Lantean.QBTMudBlade/Components/GeneralTab.razor index dde794e..af41d54 100644 --- a/Lantean.QBTMudBlade/Components/GeneralTab.razor +++ b/Lantean.QBTMudBlade/Components/GeneralTab.razor @@ -1,97 +1,99 @@ -
Transfer
- - - @DisplayHelpers.Duration(Properties?.TimeElapsed) - - - @DisplayHelpers.Duration(Properties?.EstimatedTimeOfArrival) - - - @DisplayHelpers.Duration(Properties?.Connections) @DisplayHelpers.EmptyIfNull(Properties?.ConnectionsLimit, "(", " max)") - + + Transfer + + + @DisplayHelpers.Duration(Properties?.TimeElapsed) + + + @DisplayHelpers.Duration(Properties?.EstimatedTimeOfArrival) + + + @DisplayHelpers.Duration(Properties?.Connections) @DisplayHelpers.EmptyIfNull(Properties?.ConnectionsLimit, "(", " max)") + - - @DisplayHelpers.Size(Properties?.TotalDownloaded) @DisplayHelpers.Size(Properties?.TotalDownloadedSession, "(", " this session)") - - - @DisplayHelpers.Size(Properties?.TotalUploaded) @DisplayHelpers.Size(Properties?.TotalUploaded, "(", " this session)") - - - @DisplayHelpers.Size(Properties?.Seeds) @DisplayHelpers.EmptyIfNull(Properties?.Seeds, "(", " total)") - + + @DisplayHelpers.Size(Properties?.TotalDownloaded) @DisplayHelpers.Size(Properties?.TotalDownloadedSession, "(", " this session)") + + + @DisplayHelpers.Size(Properties?.TotalUploaded) @DisplayHelpers.Size(Properties?.TotalUploaded, "(", " this session)") + + + @DisplayHelpers.Size(Properties?.Seeds) @DisplayHelpers.EmptyIfNull(Properties?.Seeds, "(", " total)") + - - @DisplayHelpers.Speed(Properties?.DownloadSpeed) @DisplayHelpers.Speed(Properties?.DownloadSpeedAverage, "(", " avg.)") - - - @DisplayHelpers.Speed(Properties?.UploadSpeed) @DisplayHelpers.Speed(Properties?.UploadSpeedAverage, "(", " avg.)") - - - @DisplayHelpers.Size(Properties?.Peers) @DisplayHelpers.EmptyIfNull(Properties?.Peers, "(", " total)") - + + @DisplayHelpers.Speed(Properties?.DownloadSpeed) @DisplayHelpers.Speed(Properties?.DownloadSpeedAverage, "(", " avg.)") + + + @DisplayHelpers.Speed(Properties?.UploadSpeed) @DisplayHelpers.Speed(Properties?.UploadSpeedAverage, "(", " avg.)") + + + @DisplayHelpers.Size(Properties?.Peers) @DisplayHelpers.EmptyIfNull(Properties?.Peers, "(", " total)") + - - @DisplayHelpers.Speed(Properties?.DownloadLimit) - - - @DisplayHelpers.Speed(Properties?.UploadLimit) - - - @DisplayHelpers.Size(Properties?.TotalWasted) - + + @DisplayHelpers.Speed(Properties?.DownloadLimit) + + + @DisplayHelpers.Speed(Properties?.UploadLimit) + + + @DisplayHelpers.Size(Properties?.TotalWasted) + - - @Properties?.ShareRatio.ToString("0.00") - - - @DisplayHelpers.Duration(Properties?.Reannounce) - - - @DisplayHelpers.DateTime(Properties?.LastSeen, "Never") - + + @Properties?.ShareRatio.ToString("0.00") + + + @DisplayHelpers.Duration(Properties?.Reannounce) + + + @DisplayHelpers.DateTime(Properties?.LastSeen, "Never") + - + -
Information
- - - @DisplayHelpers.Size(Properties?.TotalSize) - - - - @if (Properties is not null) - { - @Properties.PiecesNum x @DisplayHelpers.Size(Properties.PieceSize) (have @Properties.PiecesHave) - } - - - - @Properties?.CreatedBy - + Information + + + @DisplayHelpers.Size(Properties?.TotalSize) + + + + @if (Properties is not null) + { + @Properties.PiecesNum x @DisplayHelpers.Size(Properties.PieceSize) (have @Properties.PiecesHave) + } + + + + @Properties?.CreatedBy + - - @DisplayHelpers.DateTime(Properties?.AdditionDate) - - - @DisplayHelpers.DateTime(Properties?.CompletionDate) - - - @DisplayHelpers.DateTime(Properties?.CreationDate) - + + @DisplayHelpers.DateTime(Properties?.AdditionDate) + + + @DisplayHelpers.DateTime(Properties?.CompletionDate) + + + @DisplayHelpers.DateTime(Properties?.CreationDate) + - - @Properties?.InfoHashV1 - + + @Properties?.InfoHashV1 + - - @Properties?.InfoHashV2 - + + @Properties?.InfoHashV2 + - - @Properties?.SavePath - + + @Properties?.SavePath + - - @Properties?.Comment - - \ No newline at end of file + + @Properties?.Comment + + + diff --git a/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor b/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor new file mode 100644 index 0000000..620351c --- /dev/null +++ b/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor.cs b/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor.cs new file mode 100644 index 0000000..ccc8267 --- /dev/null +++ b/Lantean.QBTMudBlade/Components/MudFieldSwitch.razor.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Components; + +namespace Lantean.QBTMudBlade.Components +{ + public partial class MudFieldSwitch + { + [Parameter] + public bool Value { get; set; } + + [Parameter] + public EventCallback ValueChanged { get; set; } + + [Parameter] + public string? Label { get; set; } + + protected async Task ValueChangedCallback(bool value) + { + Value = value; + await ValueChanged.InvokeAsync(value); + } + } +} diff --git a/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor b/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor index 67b5042..433075e 100644 --- a/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor @@ -3,12 +3,241 @@ - + qBittorrent Section - + + + Fastresume files + SQLite database (experimental) + + + + MiB + + + + Any interface + @foreach (var networkInterface in NetworkInterfaces) + { + @networkInterface.Name + } + + + + + All addresses + All IPv4 addresses + All IPv6 addresses + @foreach (var address in NetworkInterfaceAddresses) + { + @address + } + + + + min + + + MiB + + + + + + ms + + + + + + + + + + + + + + + + - \ No newline at end of file + + + + + + qBittorrent Section + + + + + + + + + + + + + + + + + + + + + MiB + + + MiB + + + s + + + KiB + + + + Default + Memory mapped files + POSIX-compliant + + + + + Disable OS cache + Enable OS cache + + + + + Disable OS cache + Enable OS cache + Write-through (requires libtorrent >= 2.0.6) + + + + + + + + + + + + + KiB + + + KiB + + + % + + + + + + KiB + + + KiB + + + + + + + + + + + + + + + + + + + Prefer TCP + Peer proportional (throttles TCP) + + + + + + + + + + + + + + + + + + + + Fixed slots + Upload rate based + + + + + Round-robin + Fastest upload + Anti-leech + + + + + + + + + + + + + + + + + + + % + + + % + + + s + + + + + + + + + + + + + + + + + + + diff --git a/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor.cs index 7a33834..4fa44f5 100644 --- a/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/AdvancedOptions.razor.cs @@ -1,10 +1,613 @@ -namespace Lantean.QBTMudBlade.Components.Options +using Lantean.QBitTorrentClient; +using Lantean.QBitTorrentClient.Models; +using Microsoft.AspNetCore.Components; + +namespace Lantean.QBTMudBlade.Components.Options { public partial class AdvancedOptions : Options { + [Inject] + public IApiClient ApiClient { get; set; } = default!; + + protected string? ResumeDataStorageType { get; private set; } + protected int MemoryWorkingSetLimit { get; private set; } + protected string? CurrentNetworkInterface { get; private set; } + protected string? CurrentInterfaceAddress { get; private set; } + protected int SaveResumeDataInterval { get; private set; } + protected int TorrentFileSizeLimit { get; private set; } + protected bool RecheckCompletedTorrents { get; private set; } + protected string? AppInstanceName { get; private set; } + protected int RefreshInterval { get; private set; } + protected bool ResolvePeerCountries { get; private set; } + protected bool ReannounceWhenAddressChanged { get; private set; } + protected int BdecodeDepthLimit { get; private set; } + protected int BdecodeTokenLimit { get; private set; } + protected int AsyncIoThreads { get; private set; } + protected int HashingThreads { get; private set; } + protected int FilePoolSize { get; private set; } + protected int CheckingMemoryUse { get; private set; } + protected int DiskCache { get; private set; } + protected int DiskCacheTtl { get; private set; } + protected int DiskQueueSize { get; private set; } + protected int DiskIoType { get; private set; } + protected int DiskIoReadMode { get; private set; } + protected int DiskIoWriteMode { get; private set; } + protected bool EnableCoalesceReadWrite { get; private set; } + protected bool EnablePieceExtentAffinity { get; private set; } + protected bool EnableUploadSuggestions { get; private set; } + protected int SendBufferWatermark { get; private set; } + protected int SendBufferLowWatermark { get; private set; } + protected int SendBufferWatermarkFactor { get; private set; } + protected int ConnectionSpeed { get; private set; } + protected int SocketSendBufferSize { get; private set; } + protected int SocketReceiveBufferSize { get; private set; } + protected int SocketBacklogSize { get; private set; } + protected int OutgoingPortsMin { get; private set; } + protected int OutgoingPortsMax { get; private set; } + protected int UpnpLeaseDuration { get; private set; } + protected int PeerTos { get; private set; } + protected int UtpTcpMixedMode { get; private set; } + protected bool IdnSupportEnabled { get; private set; } + protected bool EnableMultiConnectionsFromSameIp { get; private set; } + protected bool ValidateHttpsTrackerCertificate { get; private set; } + protected bool SsrfMitigation { get; private set; } + protected bool BlockPeersOnPrivilegedPorts { get; private set; } + protected bool EnableEmbeddedTracker { get; private set; } + protected int EmbeddedTrackerPort { get; private set; } + protected bool EmbeddedTrackerPortForwarding { get; private set; } + protected bool MarkOfTheWeb { get; private set; } + protected string? PythonExecutablePath { get; private set; } + protected int UploadSlotsBehavior { get; private set; } + protected int UploadChokingAlgorithm { get; private set; } + protected bool AnnounceToAllTrackers { get; private set; } + protected bool AnnounceToAllTiers { get; private set; } + protected string? AnnounceIp { get; private set; } + protected int MaxConcurrentHttpAnnounces { get; private set; } + protected int StopTrackerTimeout { get; private set; } + protected int PeerTurnover { get; private set; } + protected int PeerTurnoverCutoff { get; private set; } + protected int PeerTurnoverInterval { get; private set; } + protected int RequestQueueSize { get; private set; } + protected string? DhtBootstrapNodes { get; private set; } + protected int I2pInboundQuantity { get; private set; } + protected int I2pOutboundQuantity { get; private set; } + protected int I2pInboundLength { get; private set; } + protected int I2pOutboundLength { get; private set; } + + protected IReadOnlyList NetworkInterfaces { get; private set; } = []; + + protected IReadOnlyList NetworkInterfaceAddresses { get; private set; } = []; + + protected override async Task OnInitializedAsync() + { + NetworkInterfaces = await ApiClient.GetNetworkInterfaces(); + } + protected override bool SetOptions() { + if (Preferences is null) + { + return false; + } + + ResumeDataStorageType = Preferences.ResumeDataStorageType; + MemoryWorkingSetLimit = Preferences.MemoryWorkingSetLimit; + CurrentNetworkInterface = Preferences.CurrentNetworkInterface; + CurrentInterfaceAddress = Preferences.CurrentInterfaceAddress; + SaveResumeDataInterval = Preferences.SaveResumeDataInterval; + TorrentFileSizeLimit = Preferences.TorrentFileSizeLimit; + RecheckCompletedTorrents = Preferences.RecheckCompletedTorrents; + AppInstanceName = Preferences.AppInstanceName; + RefreshInterval = Preferences.RefreshInterval; + ResolvePeerCountries = Preferences.ResolvePeerCountries; + ReannounceWhenAddressChanged = Preferences.ReannounceWhenAddressChanged; + BdecodeDepthLimit = Preferences.BdecodeDepthLimit; + BdecodeTokenLimit = Preferences.BdecodeTokenLimit; + AsyncIoThreads = Preferences.AsyncIoThreads; + HashingThreads = Preferences.HashingThreads; + FilePoolSize = Preferences.FilePoolSize; + CheckingMemoryUse = Preferences.CheckingMemoryUse; + DiskCache = Preferences.DiskCache; + DiskCacheTtl = Preferences.DiskCacheTtl; + DiskQueueSize = Preferences.DiskQueueSize; + DiskIoType = Preferences.DiskIoType; + DiskIoReadMode = Preferences.DiskIoReadMode; + DiskIoWriteMode = Preferences.DiskIoWriteMode; + EnableCoalesceReadWrite = Preferences.EnableCoalesceReadWrite; + EnablePieceExtentAffinity = Preferences.EnablePieceExtentAffinity; + EnableUploadSuggestions = Preferences.EnableUploadSuggestions; + SendBufferWatermark = Preferences.SendBufferWatermark; + SendBufferLowWatermark = Preferences.SendBufferLowWatermark; + SendBufferWatermarkFactor = Preferences.SendBufferWatermarkFactor; + ConnectionSpeed = Preferences.ConnectionSpeed; + SocketSendBufferSize = Preferences.SocketSendBufferSize; + SocketReceiveBufferSize = Preferences.SocketReceiveBufferSize; + SocketBacklogSize = Preferences.SocketBacklogSize; + OutgoingPortsMin = Preferences.OutgoingPortsMin; + OutgoingPortsMax = Preferences.OutgoingPortsMax; + UpnpLeaseDuration = Preferences.UpnpLeaseDuration; + PeerTos = Preferences.PeerTos; + UtpTcpMixedMode = Preferences.UtpTcpMixedMode; + IdnSupportEnabled = Preferences.IdnSupportEnabled; + EnableMultiConnectionsFromSameIp = Preferences.EnableMultiConnectionsFromSameIp; + ValidateHttpsTrackerCertificate = Preferences.ValidateHttpsTrackerCertificate; + SsrfMitigation = Preferences.SsrfMitigation; + BlockPeersOnPrivilegedPorts = Preferences.BlockPeersOnPrivilegedPorts; + EnableEmbeddedTracker = Preferences.EnableEmbeddedTracker; + EmbeddedTrackerPort = Preferences.EmbeddedTrackerPort; + EmbeddedTrackerPortForwarding = Preferences.EmbeddedTrackerPortForwarding; + MarkOfTheWeb = Preferences.MarkOfTheWeb; + PythonExecutablePath = Preferences.PythonExecutablePath; + UploadSlotsBehavior = Preferences.UploadSlotsBehavior; + UploadChokingAlgorithm = Preferences.UploadChokingAlgorithm; + AnnounceToAllTrackers = Preferences.AnnounceToAllTrackers; + AnnounceToAllTiers = Preferences.AnnounceToAllTiers; + AnnounceIp = Preferences.AnnounceIp; + MaxConcurrentHttpAnnounces = Preferences.MaxConcurrentHttpAnnounces; + StopTrackerTimeout = Preferences.StopTrackerTimeout; + PeerTurnover = Preferences.PeerTurnover; + PeerTurnoverCutoff = Preferences.PeerTurnoverCutoff; + PeerTurnoverInterval = Preferences.PeerTurnoverInterval; + RequestQueueSize = Preferences.RequestQueueSize; + DhtBootstrapNodes = Preferences.DhtBootstrapNodes; + I2pInboundQuantity = Preferences.I2pInboundQuantity; + I2pOutboundQuantity = Preferences.I2pOutboundQuantity; + I2pInboundLength = Preferences.I2pInboundLength; + I2pOutboundLength = Preferences.I2pOutboundLength; + return true; } + + protected async Task ResumeDataStorageTypeChanged(string value) + { + ResumeDataStorageType = value; + UpdatePreferences.ResumeDataStorageType = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MemoryWorkingSetLimitChanged(int value) + { + MemoryWorkingSetLimit = value; + UpdatePreferences.MemoryWorkingSetLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task CurrentNetworkInterfaceChanged(string value) + { + CurrentNetworkInterface = value; + UpdatePreferences.CurrentNetworkInterface = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + + NetworkInterfaceAddresses = await ApiClient.GetNetworkInterfaceAddressList(value); + } + + protected async Task CurrentInterfaceAddressChanged(string value) + { + CurrentInterfaceAddress = value; + UpdatePreferences.CurrentInterfaceAddress = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SaveResumeDataIntervalChanged(int value) + { + SaveResumeDataInterval = value; + UpdatePreferences.SaveResumeDataInterval = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task TorrentFileSizeLimitChanged(int value) + { + TorrentFileSizeLimit = value; + UpdatePreferences.TorrentFileSizeLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RecheckCompletedTorrentsChanged(bool value) + { + RecheckCompletedTorrents = value; + UpdatePreferences.RecheckCompletedTorrents = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AppInstanceNameChanged(string value) + { + AppInstanceName = value; + UpdatePreferences.AppInstanceName = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RefreshIntervalChanged(int value) + { + RefreshInterval = value; + UpdatePreferences.RefreshInterval = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task ResolvePeerCountriesChanged(bool value) + { + ResolvePeerCountries = value; + UpdatePreferences.ResolvePeerCountries = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task ReannounceWhenAddressChangedChanged(bool value) + { + ReannounceWhenAddressChanged = value; + UpdatePreferences.ReannounceWhenAddressChanged = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BdecodeDepthLimitChanged(int value) + { + BdecodeDepthLimit = value; + UpdatePreferences.BdecodeDepthLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BdecodeTokenLimitChanged(int value) + { + BdecodeTokenLimit = value; + UpdatePreferences.BdecodeTokenLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AsyncIoThreadsChanged(int value) + { + AsyncIoThreads = value; + UpdatePreferences.AsyncIoThreads = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task HashingThreadsChanged(int value) + { + HashingThreads = value; + UpdatePreferences.HashingThreads = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task FilePoolSizeChanged(int value) + { + FilePoolSize = value; + UpdatePreferences.FilePoolSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task CheckingMemoryUseChanged(int value) + { + CheckingMemoryUse = value; + UpdatePreferences.CheckingMemoryUse = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskCacheChanged(int value) + { + DiskCache = value; + UpdatePreferences.DiskCache = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskCacheTtlChanged(int value) + { + DiskCacheTtl = value; + UpdatePreferences.DiskCacheTtl = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskQueueSizeChanged(int value) + { + DiskQueueSize = value; + UpdatePreferences.DiskQueueSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskIoTypeChanged(int value) + { + DiskIoType = value; + UpdatePreferences.DiskIoType = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskIoReadModeChanged(int value) + { + DiskIoReadMode = value; + UpdatePreferences.DiskIoReadMode = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DiskIoWriteModeChanged(int value) + { + DiskIoWriteMode = value; + UpdatePreferences.DiskIoWriteMode = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EnableCoalesceReadWriteChanged(bool value) + { + EnableCoalesceReadWrite = value; + UpdatePreferences.EnableCoalesceReadWrite = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EnablePieceExtentAffinityChanged(bool value) + { + EnablePieceExtentAffinity = value; + UpdatePreferences.EnablePieceExtentAffinity = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EnableUploadSuggestionsChanged(bool value) + { + EnableUploadSuggestions = value; + UpdatePreferences.EnableUploadSuggestions = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SendBufferWatermarkChanged(int value) + { + SendBufferWatermark = value; + UpdatePreferences.SendBufferWatermark = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SendBufferLowWatermarkChanged(int value) + { + SendBufferLowWatermark = value; + UpdatePreferences.SendBufferLowWatermark = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SendBufferWatermarkFactorChanged(int value) + { + SendBufferWatermarkFactor = value; + UpdatePreferences.SendBufferWatermarkFactor = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task ConnectionSpeedChanged(int value) + { + ConnectionSpeed = value; + UpdatePreferences.ConnectionSpeed = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SocketSendBufferSizeChanged(int value) + { + SocketSendBufferSize = value; + UpdatePreferences.SocketSendBufferSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SocketReceiveBufferSizeChanged(int value) + { + SocketReceiveBufferSize = value; + UpdatePreferences.SocketReceiveBufferSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SocketBacklogSizeChanged(int value) + { + SocketBacklogSize = value; + UpdatePreferences.SocketBacklogSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task OutgoingPortsMinChanged(int value) + { + OutgoingPortsMin = value; + UpdatePreferences.OutgoingPortsMin = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task OutgoingPortsMaxChanged(int value) + { + OutgoingPortsMax = value; + UpdatePreferences.OutgoingPortsMax = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task UpnpLeaseDurationChanged(int value) + { + UpnpLeaseDuration = value; + UpdatePreferences.UpnpLeaseDuration = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PeerTosChanged(int value) + { + PeerTos = value; + UpdatePreferences.PeerTos = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task UtpTcpMixedModeChanged(int value) + { + UtpTcpMixedMode = value; + UpdatePreferences.UtpTcpMixedMode = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task IdnSupportEnabledChanged(bool value) + { + IdnSupportEnabled = value; + UpdatePreferences.IdnSupportEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EnableMultiConnectionsFromSameIpChanged(bool value) + { + EnableMultiConnectionsFromSameIp = value; + UpdatePreferences.EnableMultiConnectionsFromSameIp = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task ValidateHttpsTrackerCertificateChanged(bool value) + { + ValidateHttpsTrackerCertificate = value; + UpdatePreferences.ValidateHttpsTrackerCertificate = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SsrfMitigationChanged(bool value) + { + SsrfMitigation = value; + UpdatePreferences.SsrfMitigation = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BlockPeersOnPrivilegedPortsChanged(bool value) + { + BlockPeersOnPrivilegedPorts = value; + UpdatePreferences.BlockPeersOnPrivilegedPorts = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EnableEmbeddedTrackerChanged(bool value) + { + EnableEmbeddedTracker = value; + UpdatePreferences.EnableEmbeddedTracker = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EmbeddedTrackerPortChanged(int value) + { + EmbeddedTrackerPort = value; + UpdatePreferences.EmbeddedTrackerPort = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EmbeddedTrackerPortForwardingChanged(bool value) + { + EmbeddedTrackerPortForwarding = value; + UpdatePreferences.EmbeddedTrackerPortForwarding = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MarkOfTheWebChanged(bool value) + { + MarkOfTheWeb = value; + UpdatePreferences.MarkOfTheWeb = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PythonExecutablePathChanged(string value) + { + PythonExecutablePath = value; + UpdatePreferences.PythonExecutablePath = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task UploadSlotsBehaviorChanged(int value) + { + UploadSlotsBehavior = value; + UpdatePreferences.UploadSlotsBehavior = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task UploadChokingAlgorithmChanged(int value) + { + UploadChokingAlgorithm = value; + UpdatePreferences.UploadChokingAlgorithm = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AnnounceToAllTrackersChanged(bool value) + { + AnnounceToAllTrackers = value; + UpdatePreferences.AnnounceToAllTrackers = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AnnounceToAllTiersChanged(bool value) + { + AnnounceToAllTiers = value; + UpdatePreferences.AnnounceToAllTiers = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AnnounceIpChanged(string value) + { + AnnounceIp = value; + UpdatePreferences.AnnounceIp = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxConcurrentHttpAnnouncesChanged(int value) + { + MaxConcurrentHttpAnnounces = value; + UpdatePreferences.MaxConcurrentHttpAnnounces = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task StopTrackerTimeoutChanged(int value) + { + StopTrackerTimeout = value; + UpdatePreferences.StopTrackerTimeout = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PeerTurnoverChanged(int value) + { + PeerTurnover = value; + UpdatePreferences.PeerTurnover = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PeerTurnoverCutoffChanged(int value) + { + PeerTurnoverCutoff = value; + UpdatePreferences.PeerTurnoverCutoff = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PeerTurnoverIntervalChanged(int value) + { + PeerTurnoverInterval = value; + UpdatePreferences.PeerTurnoverInterval = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RequestQueueSizeChanged(int value) + { + RequestQueueSize = value; + UpdatePreferences.RequestQueueSize = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DhtBootstrapNodesChanged(string value) + { + DhtBootstrapNodes = value; + UpdatePreferences.DhtBootstrapNodes = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task I2pInboundQuantityChanged(int value) + { + I2pInboundQuantity = value; + UpdatePreferences.I2pInboundQuantity = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task I2pOutboundQuantityChanged(int value) + { + I2pOutboundQuantity = value; + UpdatePreferences.I2pOutboundQuantity = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task I2pInboundLengthChanged(int value) + { + I2pInboundLength = value; + UpdatePreferences.I2pInboundLength = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task I2pOutboundLengthChanged(int value) + { + I2pOutboundLength = value; + UpdatePreferences.I2pOutboundLength = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + } } diff --git a/Lantean.QBTMudBlade/Components/Options/BehaviourOptions.razor b/Lantean.QBTMudBlade/Components/Options/BehaviourOptions.razor index f0df2d7..d84d6c6 100644 --- a/Lantean.QBTMudBlade/Components/Options/BehaviourOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/BehaviourOptions.razor @@ -3,13 +3,13 @@ - Language + Language - + English @@ -20,33 +20,33 @@ - Log File + Log File - + - + - + - + - + - + - + days months years @@ -59,10 +59,15 @@ + + + Performance + + - + diff --git a/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor b/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor index 67b5042..c8a2c0c 100644 --- a/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor @@ -3,12 +3,133 @@ - + Privacy - + + + + + + + + + + + + Allow encryption + Require encryption + Disable encryption + + + + + More information + + + + + + + + + + + + + + + + + + + Torrent Queueing + + + + + + + + + + + + + + + + + + + + + KiB/s + + + KiB/s + + + seconds + + + + + + + + + Seeding Limits + + + + + + + + + + + + + + + + + + + + + + + + + Stop torrent + Remove torrent + Remove torrent and its files + Enable super seeding for torrent + + + + + + + + + + Seeding Limits + + + + + + + + + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor.cs index aef6f6f..0c8fc2f 100644 --- a/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/BitTorrentOptions.razor.cs @@ -2,9 +2,223 @@ { public partial class BitTorrentOptions : Options { + protected bool Dht { get; private set; } + protected bool Pex { get; private set; } + protected bool Lsd { get; private set; } + protected int Encryption { get; private set; } + protected bool AnonymousMode { get; private set; } + protected int MaxActiveCheckingTorrents { get; private set; } + protected bool QueueingEnabled { get; private set; } + protected int MaxActiveDownloads { get; private set; } + protected int MaxActiveUploads { get; private set; } + protected int MaxActiveTorrents { get; private set; } + protected bool DontCountSlowTorrents { get; private set; } + protected int SlowTorrentDlRateThreshold { get; private set; } + protected int SlowTorrentUlRateThreshold { get; private set; } + protected int SlowTorrentInactiveTimer { get; private set; } + protected bool MaxRatioEnabled { get; private set; } + protected int MaxRatio { get; private set; } + protected bool MaxSeedingTimeEnabled { get; private set; } + protected int MaxSeedingTime { get; private set; } + protected int MaxRatioAct { get; private set; } + protected bool MaxInactiveSeedingTimeEnabled { get; private set; } + protected int MaxInactiveSeedingTime { get; private set; } + protected bool AddTrackersEnabled { get; private set; } + protected string? AddTrackers { get; private set; } + protected override bool SetOptions() { + if (Preferences is null) + { + return false; + } + + Dht = Preferences.Dht; + Pex = Preferences.Pex; + Lsd = Preferences.Lsd; + Encryption = Preferences.Encryption; + AnonymousMode = Preferences.AnonymousMode; + MaxActiveCheckingTorrents = Preferences.MaxActiveCheckingTorrents; + QueueingEnabled = Preferences.QueueingEnabled; + MaxActiveDownloads = Preferences.MaxActiveDownloads; + MaxActiveUploads = Preferences.MaxActiveUploads; + MaxActiveTorrents = Preferences.MaxActiveTorrents; + DontCountSlowTorrents = Preferences.DontCountSlowTorrents; + SlowTorrentDlRateThreshold = Preferences.SlowTorrentDlRateThreshold; + SlowTorrentUlRateThreshold = Preferences.SlowTorrentUlRateThreshold; + SlowTorrentInactiveTimer = Preferences.SlowTorrentInactiveTimer; + MaxRatioEnabled = Preferences.MaxRatioEnabled; + MaxRatio = Preferences.MaxRatio; + MaxSeedingTimeEnabled = Preferences.MaxSeedingTimeEnabled; + MaxSeedingTime = Preferences.MaxSeedingTime; + MaxRatioAct = Preferences.MaxRatioAct; + MaxInactiveSeedingTimeEnabled = Preferences.MaxInactiveSeedingTimeEnabled; + MaxInactiveSeedingTime = Preferences.MaxInactiveSeedingTime; + AddTrackersEnabled = Preferences.AddTrackersEnabled; + AddTrackers = Preferences.AddTrackers; + return true; } + + protected async Task DhtChanged(bool value) + { + Dht = value; + UpdatePreferences.Dht = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PexChanged(bool value) + { + Pex = value; + UpdatePreferences.Pex = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task LsdChanged(bool value) + { + Lsd = value; + UpdatePreferences.Lsd = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task EncryptionChanged(int value) + { + Encryption = value; + UpdatePreferences.Encryption = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AnonymousModeChanged(bool value) + { + AnonymousMode = value; + UpdatePreferences.AnonymousMode = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxActiveCheckingTorrentsChanged(int value) + { + MaxActiveCheckingTorrents = value; + UpdatePreferences.MaxActiveCheckingTorrents = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task QueueingEnabledChanged(bool value) + { + QueueingEnabled = value; + UpdatePreferences.QueueingEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxActiveDownloadsChanged(int value) + { + MaxActiveDownloads = value; + UpdatePreferences.MaxActiveDownloads = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxActiveUploadsChanged(int value) + { + MaxActiveUploads = value; + UpdatePreferences.MaxActiveUploads = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxActiveTorrentsChanged(int value) + { + MaxActiveTorrents = value; + UpdatePreferences.MaxActiveTorrents = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DontCountSlowTorrentsChanged(bool value) + { + DontCountSlowTorrents = value; + UpdatePreferences.DontCountSlowTorrents = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SlowTorrentDlRateThresholdChanged(int value) + { + SlowTorrentDlRateThreshold = value; + UpdatePreferences.SlowTorrentDlRateThreshold = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SlowTorrentUlRateThresholdChanged(int value) + { + SlowTorrentUlRateThreshold = value; + UpdatePreferences.SlowTorrentUlRateThreshold = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SlowTorrentInactiveTimerChanged(int value) + { + SlowTorrentInactiveTimer = value; + UpdatePreferences.SlowTorrentInactiveTimer = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxRatioEnabledChanged(bool value) + { + MaxRatioEnabled = value; + UpdatePreferences.MaxRatioEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxRatioChanged(int value) + { + MaxRatio = value; + UpdatePreferences.MaxRatio = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxSeedingTimeEnabledChanged(bool value) + { + MaxSeedingTimeEnabled = value; + UpdatePreferences.MaxSeedingTimeEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxSeedingTimeChanged(int value) + { + MaxSeedingTime = value; + UpdatePreferences.MaxSeedingTime = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxRatioActChanged(int value) + { + MaxRatioAct = value; + UpdatePreferences.MaxRatioAct = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxInactiveSeedingTimeEnabledChanged(bool value) + { + MaxInactiveSeedingTimeEnabled = value; + UpdatePreferences.MaxInactiveSeedingTimeEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task MaxInactiveSeedingTimeChanged(int value) + { + MaxInactiveSeedingTime = value; + UpdatePreferences.MaxInactiveSeedingTime = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AddTrackersEnabledChanged(bool value) + { + AddTrackersEnabled = value; + UpdatePreferences.AddTrackersEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AddTrackersChanged(string value) + { + AddTrackers = value; + UpdatePreferences.AddTrackers = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } } -} +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor index fddb7a0..7cb04ce 100644 --- a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor @@ -4,7 +4,7 @@ - + TCP and μTP TCP μTP @@ -17,16 +17,19 @@ - Listening Port + Listening Port - - + + - Random + Random + + + Let System Decide @@ -38,7 +41,7 @@ - Connections Limits + Connections Limits @@ -47,25 +50,122 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Proxy Server + + + + + + + None + SOCKS4 + SOCKS5 + HTTP + + + + + + + + + + + + + + + + + + + + + + Info: The password is saved unencrypted + + + + + + + + + + + + + + + + + + + + + + IP Filtering + + + + + + + + + + + + + + + diff --git a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor.cs index e1a142c..b747237 100644 --- a/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/ConnectionOptions.razor.cs @@ -19,6 +19,8 @@ namespace Lantean.QBTMudBlade.Components.Options protected string? I2pAddress { get; private set; } protected int I2pPort { get; private set; } protected bool I2pMixedMode { get; private set; } + protected bool ProxyDisabled { get; private set; } + protected bool ProxySocks4 { get; private set; } protected string? ProxyType { get; private set; } protected string? ProxyIp { get; private set; } protected int ProxyPort { get; private set; } @@ -215,6 +217,8 @@ namespace Lantean.QBTMudBlade.Components.Options { ProxyType = value; UpdatePreferences.ProxyType = value; + ProxyDisabled = value == "None"; + ProxySocks4 = value == "SOCKS4"; await PreferencesChanged.InvokeAsync(UpdatePreferences); } @@ -316,9 +320,6 @@ namespace Lantean.QBTMudBlade.Components.Options await PreferencesChanged.InvokeAsync(UpdatePreferences); } - protected const int MinPortValue = 1024; - protected const int MaxPortValue = 65535; - protected async Task GenerateRandomPort() { var random = new Random(); @@ -326,5 +327,10 @@ namespace Lantean.QBTMudBlade.Components.Options await ListenPortChanged(port); } + + protected async Task UseSystemPort() + { + await ListenPortChanged(0); + } } } \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor b/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor index d9306fd..54a9554 100644 --- a/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor @@ -3,26 +3,26 @@ - When adding a torrent + When adding a torrent - + Original Create subfolder Don't create subfolder - + - + None Metadata received Files Checked @@ -36,6 +36,11 @@ + + + Files + + @@ -51,31 +56,31 @@ - Saving Management + Saving Management - + Manual Automatic - + Relocate torrent Switch torrent to Manual Mode - + Relocate affected torrents Switch affected torrents to Manual Mode - + Relocate affected torrents Switch affected torrents to Manual Mode @@ -84,7 +89,7 @@ - + @@ -92,7 +97,7 @@ - + @@ -102,7 +107,7 @@ - + @@ -112,7 +117,7 @@ - + @@ -123,7 +128,7 @@ - Automatically add torrents from + Automatically add torrents from @@ -202,44 +207,18 @@ + + + Excluded Files + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -248,7 +227,43 @@ - Run exernal program + Email Notifications + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Run exernal program @@ -257,13 +272,13 @@ - + - + Supported parameters (case sensitive): diff --git a/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor.cs index 6e6ef8d..b2f6b01 100644 --- a/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/DownloadsOptions.razor.cs @@ -260,10 +260,12 @@ namespace Lantean.QBTMudBlade.Components.Options UpdatePreferences.ScanDirs = ScanDirs; await PreferencesChanged.InvokeAsync(UpdatePreferences); +#pragma warning disable S2583 // Conditionally executed code should be reachable if (AddedScanDirs.Count == 0) { AddDefaultScanDir(); } +#pragma warning restore S2583 // Conditionally executed code should be reachable } protected void AddedScanDirsValueChanged(int index, string value) diff --git a/Lantean.QBTMudBlade/Components/Options/Options.cs b/Lantean.QBTMudBlade/Components/Options/Options.cs index 690e495..e74ad26 100644 --- a/Lantean.QBTMudBlade/Components/Options/Options.cs +++ b/Lantean.QBTMudBlade/Components/Options/Options.cs @@ -6,12 +6,18 @@ namespace Lantean.QBTMudBlade.Components.Options public abstract class Options : ComponentBase { private bool _preferencesRead; - protected UpdatePreferences UpdatePreferences { get; set; } = new UpdatePreferences(); + + protected const int MinPortValue = 1024; + protected const int MaxPortValue = 65535; [Parameter] [EditorRequired] public Preferences? Preferences { get; set; } + [Parameter] + [EditorRequired] + public UpdatePreferences UpdatePreferences { get; set; } = default!; + [Parameter] [EditorRequired] public EventCallback PreferencesChanged { get; set; } @@ -25,6 +31,8 @@ namespace Lantean.QBTMudBlade.Components.Options protected override void OnParametersSet() { + UpdatePreferences ??= new UpdatePreferences(); + if (_preferencesRead) { return; diff --git a/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor b/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor index 67b5042..6b894fc 100644 --- a/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor @@ -3,12 +3,56 @@ - + RSS Reader - + + + + + min + + + + + + + + + + + + RSS Torrent Auto Downloader + + + + + + + + + Edit auto downloading rules + + + + + + + + + RSS Smart Episode Filter + + + + + + + + + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor.cs index 54a1bff..f4076f8 100644 --- a/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/RSSOptions.razor.cs @@ -2,9 +2,84 @@ { public partial class RSSOptions : Options { + protected bool RssProcessingEnabled { get; private set; } + protected int RssRefreshInterval { get; private set; } + protected long RssFetchDelay { get; private set; } + protected int RssMaxArticlesPerFeed { get; private set; } + protected bool RssAutoDownloadingEnabled { get; private set; } + protected bool RssDownloadRepackProperEpisodes { get; private set; } + protected string? RssSmartEpisodeFilters { get; private set; } + protected override bool SetOptions() { + if (Preferences is null) + { + return false; + } + + RssProcessingEnabled = Preferences.RssProcessingEnabled; + RssRefreshInterval = Preferences.RssRefreshInterval; + RssFetchDelay = Preferences.RssFetchDelay; + RssMaxArticlesPerFeed = Preferences.RssMaxArticlesPerFeed; + RssAutoDownloadingEnabled = Preferences.RssAutoDownloadingEnabled; + RssDownloadRepackProperEpisodes = Preferences.RssDownloadRepackProperEpisodes; + RssSmartEpisodeFilters = Preferences.RssSmartEpisodeFilters; + return true; } + + protected async Task RssProcessingEnabledChanged(bool value) + { + RssProcessingEnabled = value; + UpdatePreferences.RssProcessingEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssRefreshIntervalChanged(int value) + { + RssRefreshInterval = value; + UpdatePreferences.RssRefreshInterval = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssFetchDelayChanged(int value) + { + RssFetchDelay = value; + UpdatePreferences.RssFetchDelay = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssMaxArticlesPerFeedChanged(int value) + { + RssMaxArticlesPerFeed = value; + UpdatePreferences.RssMaxArticlesPerFeed = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssAutoDownloadingEnabledChanged(bool value) + { + RssAutoDownloadingEnabled = value; + UpdatePreferences.RssAutoDownloadingEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssDownloadRepackProperEpisodesChanged(bool value) + { + RssDownloadRepackProperEpisodes = value; + UpdatePreferences.RssDownloadRepackProperEpisodes = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RssSmartEpisodeFiltersChanged(string value) + { + RssSmartEpisodeFilters = value; + UpdatePreferences.RssSmartEpisodeFilters = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task OpenRssRulesDialog() + { + await Task.Delay(0); + } } -} +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor b/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor index 67b5042..927efa7 100644 --- a/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor @@ -3,12 +3,85 @@ - + Global Rate Limits - + + KiB/s + + + KiB/s + + + 0 means unlimited + + + + + + + + + Alternative Rate Limits + + + + + + KiB/s + + + KiB/s + + + 0 means unlimited + + + + + + + + + + + + + Every day + Weekdays + Weekends + Monday + Tuesday + Wednesday + Thursday + Friday + Saturday + Sunday + + + + + + + + + + Rate Limits Settings + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor.cs index df5ec5a..8a28868 100644 --- a/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/SpeedOptions.razor.cs @@ -2,9 +2,160 @@ { public partial class SpeedOptions : Options { + protected int UpLimit { get; private set; } + protected int DlLimit { get; private set; } + protected int AltUpLimit { get; private set; } + protected int AltDlLimit { get; private set; } + protected int BittorrentProtocol { get; private set; } + protected bool LimitUtpRate { get; private set; } + protected bool LimitTcpOverhead { get; private set; } + protected bool LimitLanPeers { get; private set; } + protected bool SchedulerEnabled { get; private set; } + protected TimeSpan ScheduleFrom { get; private set; } + protected TimeSpan ScheduleTo { get; private set; } + protected int SchedulerDays { get; private set; } + protected override bool SetOptions() { + if (Preferences is null) + { + return false; + } + + UpLimit = Preferences.UpLimit; + DlLimit = Preferences.DlLimit; + AltUpLimit = Preferences.AltUpLimit; + AltDlLimit = Preferences.AltDlLimit; + BittorrentProtocol = Preferences.BittorrentProtocol; + LimitUtpRate = Preferences.LimitUtpRate; + LimitTcpOverhead = Preferences.LimitTcpOverhead; + LimitLanPeers = Preferences.LimitLanPeers; + SchedulerEnabled = Preferences.SchedulerEnabled; + ScheduleFrom = TimeSpan.FromMinutes((Preferences.ScheduleFromHour * 60) + Preferences.ScheduleFromMin); + ScheduleTo = TimeSpan.FromMinutes((Preferences.ScheduleToHour * 60) + Preferences.ScheduleToMin); + SchedulerDays = Preferences.SchedulerDays; + return true; } + + protected async Task UpLimitChanged(int value) + { + UpLimit = value; + UpdatePreferences.UpLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DlLimitChanged(int value) + { + DlLimit = value; + UpdatePreferences.DlLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AltUpLimitChanged(int value) + { + AltUpLimit = value; + UpdatePreferences.AltUpLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AltDlLimitChanged(int value) + { + AltDlLimit = value; + UpdatePreferences.AltDlLimit = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BittorrentProtocolChanged(int value) + { + BittorrentProtocol = value; + UpdatePreferences.BittorrentProtocol = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task LimitUtpRateChanged(bool value) + { + LimitUtpRate = value; + UpdatePreferences.LimitUtpRate = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task LimitTcpOverheadChanged(bool value) + { + LimitTcpOverhead = value; + UpdatePreferences.LimitTcpOverhead = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task LimitLanPeersChanged(bool value) + { + LimitLanPeers = value; + UpdatePreferences.LimitLanPeers = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task SchedulerEnabledChanged(bool value) + { + SchedulerEnabled = value; + UpdatePreferences.SchedulerEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task ScheduleFromChanged(TimeSpan? value) + { + if (value is null) + { + return; + } + + ScheduleFrom = value.Value; + bool hasChanged = false; + if (value.Value.Hours != Preferences?.ScheduleFromHour) + { + UpdatePreferences.ScheduleFromHour = value.Value.Hours; + hasChanged = true; + } + if (value.Value.Minutes != Preferences?.ScheduleFromMin) + { + UpdatePreferences.ScheduleFromMin = value.Value.Minutes; + hasChanged = true; + } + if (hasChanged) + { + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + } + + protected async Task ScheduleToChanged(TimeSpan? value) + { + if (value is null) + { + return; + } + + ScheduleTo = value.Value; + bool hasChanged = false; + if (value.Value.Hours != Preferences?.ScheduleToHour) + { + UpdatePreferences.ScheduleToHour = value.Value.Hours; + hasChanged = true; + } + if (value.Value.Minutes != Preferences?.ScheduleToMin) + { + UpdatePreferences.ScheduleToMin = value.Value.Minutes; + hasChanged = true; + } + if (hasChanged) + { + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + } + + protected async Task SchedulerDaysChanged(int value) + { + SchedulerDays = value; + UpdatePreferences.SchedulerDays = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } } -} +} \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor b/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor index 67b5042..45871eb 100644 --- a/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor +++ b/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor @@ -3,12 +3,218 @@ - + Web User Interface (Remote control) - + + + + + + + + + + + + + + + + + Certificate + + + + + + + + + + + + + + + + + + + + + Authentication + + + + + + + + + + + + + + + + + + + + + + + + seconds + + + seconds + + + + + + + + + Alternative Web UI + + + + + + + + + + + + + + + + + + Security + + + + + + + + + + + + + + + + + + + + + + + + + + + Security + + + + + + + + + + + + + + + + + + + + + + + + + + + Http Headers + + + + + + + + + + + + + + + + + + Reverse Proxy + + + + + + + + + + + + + + + + + + Dynamic Domain Name + + + + + + + + + + DynDNS + NO-IP + + + + Register + + + + + + + + + + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor.cs b/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor.cs index 789b07d..6fcd243 100644 --- a/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor.cs +++ b/Lantean.QBTMudBlade/Components/Options/WebUIOptions.razor.cs @@ -2,9 +2,309 @@ { public partial class WebUIOptions : Options { + protected string? Locale { get; private set; } + protected bool PerformanceWarning { get; private set; } + protected string? WebUiDomainList { get; private set; } + protected string? WebUiAddress { get; private set; } + protected int WebUiPort { get; private set; } + protected bool WebUiUpnp { get; private set; } + protected bool UseHttps { get; private set; } + protected string? WebUiHttpsCertPath { get; private set; } + protected string? WebUiHttpsKeyPath { get; private set; } + protected string? WebUiUsername { get; private set; } + protected string? WebUiPassword { get; private set; } + protected bool BypassLocalAuth { get; private set; } + protected bool BypassAuthSubnetWhitelistEnabled { get; private set; } + protected string? BypassAuthSubnetWhitelist { get; private set; } + protected int WebUiMaxAuthFailCount { get; private set; } + protected int WebUiBanDuration { get; private set; } + protected int WebUiSessionTimeout { get; private set; } + protected bool AlternativeWebuiEnabled { get; private set; } + protected string? AlternativeWebuiPath { get; private set; } + protected bool WebUiClickjackingProtectionEnabled { get; private set; } + protected bool WebUiCsrfProtectionEnabled { get; private set; } + protected bool WebUiSecureCookieEnabled { get; private set; } + protected bool WebUiHostHeaderValidationEnabled { get; private set; } + protected bool WebUiUseCustomHttpHeadersEnabled { get; private set; } + protected string? WebUiCustomHttpHeaders { get; private set; } + protected bool WebUiReverseProxyEnabled { get; private set; } + protected string? WebUiReverseProxiesList { get; private set; } + protected bool DyndnsEnabled { get; private set; } + protected int DyndnsService { get; private set; } + protected string? DyndnsDomain { get; private set; } + protected string? DyndnsUsername { get; private set; } + protected string? DyndnsPassword { get; private set; } + protected override bool SetOptions() { + if (Preferences is null) + { + return false; + } + + Locale = Preferences.Locale; + PerformanceWarning = Preferences.PerformanceWarning; + WebUiDomainList = Preferences.WebUiDomainList; + WebUiAddress = Preferences.WebUiAddress; + WebUiPort = Preferences.WebUiPort; + WebUiUpnp = Preferences.WebUiUpnp; + UseHttps = Preferences.UseHttps; + WebUiHttpsCertPath = Preferences.WebUiHttpsCertPath; + WebUiHttpsKeyPath = Preferences.WebUiHttpsKeyPath; + WebUiUsername = Preferences.WebUiUsername; + WebUiPassword = Preferences.WebUiPassword; + BypassLocalAuth = Preferences.BypassLocalAuth; + BypassAuthSubnetWhitelistEnabled = Preferences.BypassAuthSubnetWhitelistEnabled; + BypassAuthSubnetWhitelist = Preferences.BypassAuthSubnetWhitelist; + WebUiMaxAuthFailCount = Preferences.WebUiMaxAuthFailCount; + WebUiBanDuration = Preferences.WebUiBanDuration; + WebUiSessionTimeout = Preferences.WebUiSessionTimeout; + AlternativeWebuiEnabled = Preferences.AlternativeWebuiEnabled; + AlternativeWebuiPath = Preferences.AlternativeWebuiPath; + WebUiClickjackingProtectionEnabled = Preferences.WebUiClickjackingProtectionEnabled; + WebUiCsrfProtectionEnabled = Preferences.WebUiCsrfProtectionEnabled; + WebUiSecureCookieEnabled = Preferences.WebUiSecureCookieEnabled; + WebUiHostHeaderValidationEnabled = Preferences.WebUiHostHeaderValidationEnabled; + WebUiUseCustomHttpHeadersEnabled = Preferences.WebUiUseCustomHttpHeadersEnabled; + WebUiCustomHttpHeaders = Preferences.WebUiCustomHttpHeaders; + WebUiReverseProxyEnabled = Preferences.WebUiReverseProxyEnabled; + WebUiReverseProxiesList = Preferences.WebUiReverseProxiesList; + DyndnsEnabled = Preferences.DyndnsEnabled; + DyndnsService = Preferences.DyndnsService; + DyndnsDomain = Preferences.DyndnsDomain; + DyndnsUsername = Preferences.DyndnsUsername; + DyndnsPassword = Preferences.DyndnsPassword; + return true; } + + protected async Task LocaleChanged(string value) + { + Locale = value; + UpdatePreferences.Locale = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task PerformanceWarningChanged(bool value) + { + PerformanceWarning = value; + UpdatePreferences.PerformanceWarning = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiDomainListChanged(string value) + { + WebUiDomainList = value; + UpdatePreferences.WebUiDomainList = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiAddressChanged(string value) + { + WebUiAddress = value; + UpdatePreferences.WebUiAddress = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiPortChanged(int value) + { + WebUiPort = value; + UpdatePreferences.WebUiPort = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiUpnpChanged(bool value) + { + WebUiUpnp = value; + UpdatePreferences.WebUiUpnp = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task UseHttpsChanged(bool value) + { + UseHttps = value; + UpdatePreferences.UseHttps = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiHttpsCertPathChanged(string value) + { + WebUiHttpsCertPath = value; + UpdatePreferences.WebUiHttpsCertPath = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiHttpsKeyPathChanged(string value) + { + WebUiHttpsKeyPath = value; + UpdatePreferences.WebUiHttpsKeyPath = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiUsernameChanged(string value) + { + WebUiUsername = value; + UpdatePreferences.WebUiUsername = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiPasswordChanged(string value) + { + WebUiPassword = value; + UpdatePreferences.WebUiPassword = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BypassLocalAuthChanged(bool value) + { + BypassLocalAuth = value; + UpdatePreferences.BypassLocalAuth = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BypassAuthSubnetWhitelistEnabledChanged(bool value) + { + BypassAuthSubnetWhitelistEnabled = value; + UpdatePreferences.BypassAuthSubnetWhitelistEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task BypassAuthSubnetWhitelistChanged(string value) + { + BypassAuthSubnetWhitelist = value; + UpdatePreferences.BypassAuthSubnetWhitelist = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiMaxAuthFailCountChanged(int value) + { + WebUiMaxAuthFailCount = value; + UpdatePreferences.WebUiMaxAuthFailCount = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiBanDurationChanged(int value) + { + WebUiBanDuration = value; + UpdatePreferences.WebUiBanDuration = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiSessionTimeoutChanged(int value) + { + WebUiSessionTimeout = value; + UpdatePreferences.WebUiSessionTimeout = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AlternativeWebuiEnabledChanged(bool value) + { + AlternativeWebuiEnabled = value; + UpdatePreferences.AlternativeWebuiEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task AlternativeWebuiPathChanged(string value) + { + AlternativeWebuiPath = value; + UpdatePreferences.AlternativeWebuiPath = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiClickjackingProtectionEnabledChanged(bool value) + { + WebUiClickjackingProtectionEnabled = value; + UpdatePreferences.WebUiClickjackingProtectionEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiCsrfProtectionEnabledChanged(bool value) + { + WebUiCsrfProtectionEnabled = value; + UpdatePreferences.WebUiCsrfProtectionEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiSecureCookieEnabledChanged(bool value) + { + WebUiSecureCookieEnabled = value; + UpdatePreferences.WebUiSecureCookieEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiHostHeaderValidationEnabledChanged(bool value) + { + WebUiHostHeaderValidationEnabled = value; + UpdatePreferences.WebUiHostHeaderValidationEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiUseCustomHttpHeadersEnabledChanged(bool value) + { + WebUiUseCustomHttpHeadersEnabled = value; + UpdatePreferences.WebUiUseCustomHttpHeadersEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiCustomHttpHeadersChanged(string value) + { + WebUiCustomHttpHeaders = value; + UpdatePreferences.WebUiCustomHttpHeaders = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiReverseProxyEnabledChanged(bool value) + { + WebUiReverseProxyEnabled = value; + UpdatePreferences.WebUiReverseProxyEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task WebUiReverseProxiesListChanged(string value) + { + WebUiReverseProxiesList = value; + UpdatePreferences.WebUiReverseProxiesList = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DyndnsEnabledChanged(bool value) + { + DyndnsEnabled = value; + UpdatePreferences.DyndnsEnabled = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DyndnsServiceChanged(int value) + { + DyndnsService = value; + UpdatePreferences.DyndnsService = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DyndnsDomainChanged(string value) + { + DyndnsDomain = value; + UpdatePreferences.DyndnsDomain = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DyndnsUsernameChanged(string value) + { + DyndnsUsername = value; + UpdatePreferences.DyndnsUsername = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task DyndnsPasswordChanged(string value) + { + DyndnsPassword = value; + UpdatePreferences.DyndnsPassword = value; + await PreferencesChanged.InvokeAsync(UpdatePreferences); + } + + protected async Task RegisterDyndnsService() + { + await Task.Delay(0); + } } } diff --git a/Lantean.QBTMudBlade/Components/TorrentActions.razor b/Lantean.QBTMudBlade/Components/TorrentActions.razor index 3dfdb28..5a13dec 100644 --- a/Lantean.QBTMudBlade/Components/TorrentActions.razor +++ b/Lantean.QBTMudBlade/Components/TorrentActions.razor @@ -64,7 +64,7 @@ else } else { - + @foreach (var childItem in option.Children) { @ChildItem(childItem) diff --git a/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs b/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs index e6b4d30..cf1dea0 100644 --- a/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs +++ b/Lantean.QBTMudBlade/Components/TorrentActions.razor.cs @@ -1,7 +1,9 @@ using Lantean.QBitTorrentClient; +using Lantean.QBTMudBlade.Interop; using Lantean.QBTMudBlade.Models; using Lantean.QBTMudBlade.Services; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; using MudBlazor; namespace Lantean.QBTMudBlade.Components @@ -26,6 +28,9 @@ namespace Lantean.QBTMudBlade.Components [Inject] public IClipboardService ClipboardService { get; set; } = default!; + [Inject] + public IJSRuntime JSRuntime { get; set; } = default!; + [Parameter] [EditorRequired] public IEnumerable Hashes { get; set; } = default!; @@ -155,7 +160,7 @@ namespace Lantean.QBTMudBlade.Components protected async Task ToggleSuperSeeding() { var torrents = GetTorrents(); - + await ApiClient.SetSuperSeeding(false, null, torrents.Where(t => t.SuperSeeding).Select(t => t.Hash).ToArray()); await ApiClient.SetSuperSeeding(true, null, torrents.Where(t => !t.SuperSeeding).Select(t => t.Hash).ToArray()); } @@ -195,9 +200,19 @@ namespace Lantean.QBTMudBlade.Components await ClipboardService.WriteToClipboard(value); } + protected async Task Copy(Func selector) + { + await Copy(string.Join(Environment.NewLine, GetTorrents().Select(selector))); + } + protected async Task Export() { - await Task.Delay(5); + foreach (var torrent in GetTorrents()) + { + var url = await ApiClient.GetExportUrl(torrent.Hash); + await JSRuntime.FileDownload(url, $"{torrent.Name}.torrent"); + await Task.Delay(200); + } } private IEnumerable GetTorrents() @@ -265,11 +280,11 @@ namespace Lantean.QBTMudBlade.Components }), new Action("Copy", Icons.Material.Filled.FolderCopy, Color.Info, new List { - new Action("Name", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(firstTorrent.Name))), - new Action("Info hash v1", Icons.Material.Filled.Tag, Color.Info, EventCallback.Factory.Create(this, () => Copy(firstTorrent.InfoHashV1))), - new Action("Info hash v2", Icons.Material.Filled.Tag, Color.Info, EventCallback.Factory.Create(this, () => Copy(firstTorrent.InfoHashV2))), - new Action("Magnet link", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(firstTorrent.MagnetUri))), - new Action("Torrent ID", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(firstTorrent.Hash))), + new Action("Name", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(t => t.Name))), + new Action("Info hash v1", Icons.Material.Filled.Tag, Color.Info, EventCallback.Factory.Create(this, () => Copy(t => t.InfoHashV1))), + new Action("Info hash v2", Icons.Material.Filled.Tag, Color.Info, EventCallback.Factory.Create(this, () => Copy(t => t.InfoHashV2))), + new Action("Magnet link", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(t => t.MagnetUri))), + new Action("Torrent ID", Icons.Material.Filled.TextFields, Color.Info, EventCallback.Factory.Create(this, () => Copy(t => t.Hash))), }), new Action("Export", Icons.Material.Filled.SaveAlt, Color.Info, EventCallback.Factory.Create(this, Export)), }; diff --git a/Lantean.QBTMudBlade/DisplayHelpers.cs b/Lantean.QBTMudBlade/DisplayHelpers.cs index 7f0ccdc..54be109 100644 --- a/Lantean.QBTMudBlade/DisplayHelpers.cs +++ b/Lantean.QBTMudBlade/DisplayHelpers.cs @@ -260,7 +260,7 @@ namespace Lantean.QBTMudBlade var dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(value.Value); - return dateTimeOffset.ToLocalTime().ToString(); + return dateTimeOffset.ToLocalTime().DateTime.ToString(); } /// diff --git a/Lantean.QBTMudBlade/Interop/InteropHelper.cs b/Lantean.QBTMudBlade/Interop/InteropHelper.cs index 53f4566..307c748 100644 --- a/Lantean.QBTMudBlade/Interop/InteropHelper.cs +++ b/Lantean.QBTMudBlade/Interop/InteropHelper.cs @@ -8,5 +8,10 @@ namespace Lantean.QBTMudBlade.Interop { return await runtime.InvokeAsync("qbt.getBoundingClientRect", id); } + + public static async Task FileDownload(this IJSRuntime runtime, string url, string? filename = null) + { + await runtime.InvokeVoidAsync("qbt.triggerFileDownload", url, filename); + } } } \ No newline at end of file diff --git a/Lantean.QBTMudBlade/Pages/Login.razor.cs b/Lantean.QBTMudBlade/Pages/Login.razor.cs index 066a40d..ddca916 100644 --- a/Lantean.QBTMudBlade/Pages/Login.razor.cs +++ b/Lantean.QBTMudBlade/Pages/Login.razor.cs @@ -49,7 +49,7 @@ namespace Lantean.QBTMudBlade.Pages #if DEBUG protected override async Task OnInitializedAsync() { - await DoLogin("admin", "kL76z3W36"); + await DoLogin("admin", "Pmw29AWNK"); } #endif } diff --git a/Lantean.QBTMudBlade/Pages/Options.razor b/Lantean.QBTMudBlade/Pages/Options.razor index 07be6c2..80ab5c3 100644 --- a/Lantean.QBTMudBlade/Pages/Options.razor +++ b/Lantean.QBTMudBlade/Pages/Options.razor @@ -26,30 +26,30 @@ - + - + - + - + - + - + - + - + - + \ No newline at end of file diff --git a/Lantean.QBTMudBlade/wwwroot/css/app.css b/Lantean.QBTMudBlade/wwwroot/css/app.css index 762bdfe..c4ad4ff 100644 --- a/Lantean.QBTMudBlade/wwwroot/css/app.css +++ b/Lantean.QBTMudBlade/wwwroot/css/app.css @@ -109,4 +109,17 @@ td.no-wrap { .background-blur { backdrop-filter: blur(10px); +} + +.icon-menu::after { + content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath d='M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z'/%3E%3C/svg%3E"); + width: 25px; + height: 25px; + position: absolute; + top: 10px; + right: -5px; +} + +.field-switch { + } \ No newline at end of file diff --git a/Lantean.QBTMudBlade/wwwroot/js/interop.js b/Lantean.QBTMudBlade/wwwroot/js/interop.js new file mode 100644 index 0000000..6b390b1 --- /dev/null +++ b/Lantean.QBTMudBlade/wwwroot/js/interop.js @@ -0,0 +1,17 @@ +const qbt = {}; + +qbt.triggerFileDownload = (url, fileName) => { + const anchorElement = document.createElement('a'); + anchorElement.href = url; + anchorElement.download = fileName ?? ''; + anchorElement.click(); + anchorElement.remove(); +} + +qbt.getBoundingClientRect = (id) => { + const element = document.getElementById(id); + + return element.getBoundingClientRect(); +} + +window.qbt = qbt; \ No newline at end of file diff --git a/Lantean.QBitTorrentClient/ApiClient.cs b/Lantean.QBitTorrentClient/ApiClient.cs index 3ec5b34..3461ad6 100644 --- a/Lantean.QBitTorrentClient/ApiClient.cs +++ b/Lantean.QBitTorrentClient/ApiClient.cs @@ -126,6 +126,24 @@ namespace Lantean.QBitTorrentClient return await response.Content.ReadAsStringAsync(); } + public async Task> GetNetworkInterfaces() + { + var response = await _httpClient.GetAsync("app/networkInterfaceList"); + + response.EnsureSuccessStatusCode(); + + return await GetJsonList(response.Content); + } + + public async Task> GetNetworkInterfaceAddressList(string @interface) + { + var response = await _httpClient.GetAsync($"app/networkInterfaceAddressList?iface={@interface}"); + + response.EnsureSuccessStatusCode(); + + return await GetJsonList(response.Content); + } + #endregion Application #region Log @@ -915,6 +933,11 @@ namespace Lantean.QBitTorrentClient response.EnsureSuccessStatusCode(); } + public Task GetExportUrl(string hash) + { + return Task.FromResult($"{_httpClient.BaseAddress}torrents/export?hash={hash}"); + } + #endregion Torrent management #region RSS diff --git a/Lantean.QBitTorrentClient/IApiClient.cs b/Lantean.QBitTorrentClient/IApiClient.cs index 2ea6d35..7499e69 100644 --- a/Lantean.QBitTorrentClient/IApiClient.cs +++ b/Lantean.QBitTorrentClient/IApiClient.cs @@ -30,6 +30,10 @@ namespace Lantean.QBitTorrentClient Task GetDefaultSavePath(); + Task> GetNetworkInterfaces(); + + Task> GetNetworkInterfaceAddressList(string @interface); + #endregion Application #region Log @@ -162,6 +166,8 @@ namespace Lantean.QBitTorrentClient Task RenameFolder(string hash, string oldPath, string newPath); + Task GetExportUrl(string hash); + #endregion Torrent management #region RSS diff --git a/Lantean.QBitTorrentClient/MockApiClient.cs b/Lantean.QBitTorrentClient/MockApiClient.cs index 5b7cc66..c786489 100644 --- a/Lantean.QBitTorrentClient/MockApiClient.cs +++ b/Lantean.QBitTorrentClient/MockApiClient.cs @@ -76,6 +76,11 @@ namespace Lantean.QBitTorrentClient return _apiClient.EditTracker(hash, originalUrl, newUrl); } + public Task GetExportUrl(string hash) + { + return _apiClient.GetExportUrl(hash); + } + public Task> GetAllCategories() { return _apiClient.GetAllCategories(); @@ -116,6 +121,16 @@ namespace Lantean.QBitTorrentClient return _apiClient.GetDefaultSavePath(); } + public Task> GetNetworkInterfaces() + { + return _apiClient.GetNetworkInterfaces(); + } + + public Task> GetNetworkInterfaceAddressList(string @interface) + { + return _apiClient.GetNetworkInterfaceAddressList(@interface); + } + public Task GetGlobalDownloadLimit() { return _apiClient.GetGlobalDownloadLimit(); diff --git a/Lantean.QBitTorrentClient/Models/NetworkInterface.cs b/Lantean.QBitTorrentClient/Models/NetworkInterface.cs new file mode 100644 index 0000000..f03b136 --- /dev/null +++ b/Lantean.QBitTorrentClient/Models/NetworkInterface.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; + +namespace Lantean.QBitTorrentClient.Models +{ + public record NetworkInterface + { + [JsonConstructor] + public NetworkInterface( + string name, + string value) + { + Name = name; + Value = value; + } + + [JsonPropertyName("name")] + public string Name { get; } + + [JsonPropertyName("value")] + public string Value { get; } + } +} \ No newline at end of file diff --git a/Lantean.QBitTorrentClient/Models/Preferences.cs b/Lantean.QBitTorrentClient/Models/Preferences.cs index f4baecf..860ff36 100644 --- a/Lantean.QBitTorrentClient/Models/Preferences.cs +++ b/Lantean.QBitTorrentClient/Models/Preferences.cs @@ -17,6 +17,7 @@ namespace Lantean.QBitTorrentClient.Models bool announceToAllTiers, bool announceToAllTrackers, bool anonymousMode, + string appInstanceName, int asyncIoThreads, int autoDeleteMode, bool autoTmmEnabled, @@ -39,6 +40,7 @@ namespace Lantean.QBitTorrentClient.Models string currentInterfaceName, string currentNetworkInterface, bool dht, + string dhtBootstrapNodes, int diskCache, int diskCacheTtl, int diskIoReadMode, @@ -100,6 +102,7 @@ namespace Lantean.QBitTorrentClient.Models string mailNotificationSmtp, bool mailNotificationSslEnabled, string mailNotificationUsername, + bool markOfTheWeb, int maxActiveCheckingTorrents, int maxActiveDownloads, int maxActiveTorrents, @@ -138,6 +141,7 @@ namespace Lantean.QBitTorrentClient.Models bool proxyRss, string proxyType, string proxyUsername, + string pythonExecutablePath, bool queueingEnabled, bool randomPort, bool reannounceWhenAddressChanged, @@ -147,6 +151,7 @@ namespace Lantean.QBitTorrentClient.Models bool resolvePeerCountries, string resumeDataStorageType, bool rssAutoDownloadingEnabled, + long rssFetchDelay, bool rssDownloadRepackProperEpisodes, int rssMaxArticlesPerFeed, bool rssProcessingEnabled, @@ -207,7 +212,8 @@ namespace Lantean.QBitTorrentClient.Models int webUiSessionTimeout, bool webUiUpnp, bool webUiUseCustomHttpHeadersEnabled, - string webUiUsername + string webUiUsername, + string webUiPassword ) { AddToTopOfQueue = addToTopOfQueue; @@ -221,6 +227,7 @@ namespace Lantean.QBitTorrentClient.Models AnnounceToAllTiers = announceToAllTiers; AnnounceToAllTrackers = announceToAllTrackers; AnonymousMode = anonymousMode; + AppInstanceName = appInstanceName; AsyncIoThreads = asyncIoThreads; AutoDeleteMode = autoDeleteMode; AutoTmmEnabled = autoTmmEnabled; @@ -243,6 +250,7 @@ namespace Lantean.QBitTorrentClient.Models CurrentInterfaceName = currentInterfaceName; CurrentNetworkInterface = currentNetworkInterface; Dht = dht; + DhtBootstrapNodes = dhtBootstrapNodes; DiskCache = diskCache; DiskCacheTtl = diskCacheTtl; DiskIoReadMode = diskIoReadMode; @@ -304,6 +312,7 @@ namespace Lantean.QBitTorrentClient.Models MailNotificationSmtp = mailNotificationSmtp; MailNotificationSslEnabled = mailNotificationSslEnabled; MailNotificationUsername = mailNotificationUsername; + MarkOfTheWeb = markOfTheWeb; MaxActiveCheckingTorrents = maxActiveCheckingTorrents; MaxActiveDownloads = maxActiveDownloads; MaxActiveTorrents = maxActiveTorrents; @@ -342,6 +351,7 @@ namespace Lantean.QBitTorrentClient.Models ProxyRss = proxyRss; ProxyType = proxyType; ProxyUsername = proxyUsername; + PythonExecutablePath = pythonExecutablePath; QueueingEnabled = queueingEnabled; RandomPort = randomPort; ReannounceWhenAddressChanged = reannounceWhenAddressChanged; @@ -352,6 +362,7 @@ namespace Lantean.QBitTorrentClient.Models ResumeDataStorageType = resumeDataStorageType; RssAutoDownloadingEnabled = rssAutoDownloadingEnabled; RssDownloadRepackProperEpisodes = rssDownloadRepackProperEpisodes; + RssFetchDelay = rssFetchDelay; RssMaxArticlesPerFeed = rssMaxArticlesPerFeed; RssProcessingEnabled = rssProcessingEnabled; RssRefreshInterval = rssRefreshInterval; @@ -412,6 +423,7 @@ namespace Lantean.QBitTorrentClient.Models WebUiUpnp = webUiUpnp; WebUiUseCustomHttpHeadersEnabled = webUiUseCustomHttpHeadersEnabled; WebUiUsername = webUiUsername; + WebUiPassword = webUiPassword; } [JsonPropertyName("add_to_top_of_queue")] @@ -447,6 +459,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("anonymous_mode")] public bool AnonymousMode { get; } + [JsonPropertyName("app_instance_name")] + public string AppInstanceName { get; } + [JsonPropertyName("async_io_threads")] public int AsyncIoThreads { get; } @@ -513,6 +528,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("dht")] public bool Dht { get; } + [JsonPropertyName("dht_bootstrap_nodes")] + public string DhtBootstrapNodes { get; } + [JsonPropertyName("disk_cache")] public int DiskCache { get; } @@ -696,6 +714,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("mail_notification_username")] public string MailNotificationUsername { get; } + [JsonPropertyName("mark_of_the_web")] + public bool MarkOfTheWeb { get; } + [JsonPropertyName("max_active_checking_torrents")] public int MaxActiveCheckingTorrents { get; } @@ -810,6 +831,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("proxy_username")] public string ProxyUsername { get; } + [JsonPropertyName("python_executable_path")] + public string PythonExecutablePath { get; } + [JsonPropertyName("queueing_enabled")] public bool QueueingEnabled { get; } @@ -840,6 +864,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("rss_download_repack_proper_episodes")] public bool RssDownloadRepackProperEpisodes { get; } + [JsonPropertyName("rss_fetch_delay")] + public long RssFetchDelay { get; } + [JsonPropertyName("rss_max_articles_per_feed")] public int RssMaxArticlesPerFeed { get; } @@ -1019,5 +1046,8 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("web_ui_username")] public string WebUiUsername { get; } + + [JsonPropertyName("web_ui_password")] + public string WebUiPassword { get; } } } \ No newline at end of file diff --git a/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs b/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs index b0c1972..a6ffef0 100644 --- a/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs +++ b/Lantean.QBitTorrentClient/Models/UpdatePreferences.cs @@ -37,6 +37,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("anonymous_mode")] public bool? AnonymousMode { get; set; } + [JsonPropertyName("app_instance_name")] + public string? AppInstanceName { get; set; } + [JsonPropertyName("async_io_threads")] public int? AsyncIoThreads { get; set; } @@ -103,6 +106,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("dht")] public bool? Dht { get; set; } + [JsonPropertyName("dht_bootstrap_nodes")] + public string? DhtBootstrapNodes { get; set; } + [JsonPropertyName("disk_cache")] public int? DiskCache { get; set; } @@ -286,6 +292,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("mail_notification_username")] public string? MailNotificationUsername { get; set; } + [JsonPropertyName("mark_of_the_web")] + public bool? MarkOfTheWeb { get; set; } + [JsonPropertyName("max_active_checking_torrents")] public int? MaxActiveCheckingTorrents { get; set; } @@ -400,6 +409,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("proxy_username")] public string? ProxyUsername { get; set; } + [JsonPropertyName("python_executable_path")] + public string? PythonExecutablePath { get; set; } + [JsonPropertyName("queueing_enabled")] public bool? QueueingEnabled { get; set; } @@ -430,6 +442,9 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("rss_download_repack_proper_episodes")] public bool? RssDownloadRepackProperEpisodes { get; set; } + [JsonPropertyName("rss_fetch_delay")] + public long? RssFetchDelay { get; set; } + [JsonPropertyName("rss_max_articles_per_feed")] public int? RssMaxArticlesPerFeed { get; set; } @@ -609,5 +624,8 @@ namespace Lantean.QBitTorrentClient.Models [JsonPropertyName("web_ui_username")] public string? WebUiUsername { get; set; } + + [JsonPropertyName("web_ui_password")] + public string? WebUiPassword { get; set; } } } \ No newline at end of file