mirror of
				https://github.com/lantean-code/qbtmud.git
				synced 2025-11-03 13:33:19 +00:00 
			
		
		
		
	Add new v5 properties to AddTorrent
This commit is contained in:
		@@ -1,33 +1,50 @@
 | 
			
		||||
<MudGrid>
 | 
			
		||||
@using Lantean.QBitTorrentClient.Models
 | 
			
		||||
 | 
			
		||||
<MudGrid>
 | 
			
		||||
    <MudItem xs="12">
 | 
			
		||||
        <MudSwitch Label="Additional Options" @bind-Value="Expanded" LabelPlacement="Placement.End" />
 | 
			
		||||
    </MudItem>
 | 
			
		||||
</MudGrid>
 | 
			
		||||
<MudCollapse Expanded="Expanded">
 | 
			
		||||
    <MudGrid>
 | 
			
		||||
    <MudGrid Class="mt-2">
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect Label="Torrent Management Mode" @bind-Value="TorrentManagementMode" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="false">Manual</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="true">Automatic</MudSelectItem>
 | 
			
		||||
            <MudSelect T="bool" Label="Torrent management mode" Value="@TorrentManagementMode" ValueChanged="@SetTorrentManagementMode" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="@false">Manual</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@true">Automatic</MudSelectItem>
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="6">
 | 
			
		||||
            <MudTextField T="string" Label="Save files to location" Value="@SavePath" ValueChanged="@SavePathChanged" Variant="Variant.Outlined" Disabled="@TorrentManagementMode" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="6">
 | 
			
		||||
            <FieldSwitch Label="Use incomplete save path" Value="@UseDownloadPath" ValueChanged="@SetUseDownloadPath" Disabled="@TorrentManagementMode" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudTextField Label="Save files to location" @bind-Value="SavePath" Variant="Variant.Outlined"></MudTextField>
 | 
			
		||||
            <MudTextField T="string" Label="Incomplete save path" Value="@DownloadPath" ValueChanged="@DownloadPathChanged" Variant="Variant.Outlined" Disabled="@DownloadPathDisabled" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        @if (ShowCookieOption)
 | 
			
		||||
        {
 | 
			
		||||
            <MudItem xs="12">
 | 
			
		||||
                <MudTextField Label="Cookie" @bind-Value="Cookie" Variant="Variant.Outlined"></MudTextField>
 | 
			
		||||
                <MudTextField Label="Cookie" @bind-Value="Cookie" Variant="Variant.Outlined" />
 | 
			
		||||
            </MudItem>
 | 
			
		||||
        }
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudTextField Label="Rename" @bind-Value="RenameTorrent" Variant="Variant.Outlined"></MudTextField>
 | 
			
		||||
            <MudTextField Label="Rename" @bind-Value="RenameTorrent" Variant="Variant.Outlined" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect Label="Category" @bind-Value="Category" Variant="Variant.Outlined">
 | 
			
		||||
                @foreach (var category in Categories)
 | 
			
		||||
            <MudSelect T="string" Label="Category" Value="@Category" ValueChanged="@CategoryChanged" Variant="Variant.Outlined" Clearable="true">
 | 
			
		||||
                <MudSelectItem Value="@string.Empty">None</MudSelectItem>
 | 
			
		||||
                @foreach (var category in CategoryOptions)
 | 
			
		||||
                {
 | 
			
		||||
                    <MudSelectItem Value="category">@category</MudSelectItem>
 | 
			
		||||
                    <MudSelectItem Value="@category.Name">@category.Name</MudSelectItem>
 | 
			
		||||
                }
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect T="string" Label="Tags" Variant="Variant.Outlined" MultiSelection="true" SelectedValues="@SelectedTags" SelectedValuesChanged="@SelectedTagsChanged" Disabled="@(AvailableTags.Count == 0)">
 | 
			
		||||
                @foreach (var tag in AvailableTags)
 | 
			
		||||
                {
 | 
			
		||||
                    <MudSelectItem Value="@tag">@tag</MudSelectItem>
 | 
			
		||||
                }
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
@@ -38,7 +55,7 @@
 | 
			
		||||
            <FieldSwitch Label="Add to top of queue" @bind-Value="AddToTopOfQueue" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect Label="Stop condition" @bind-Value="StopCondition" Variant="Variant.Outlined">
 | 
			
		||||
            <MudSelect T="string" Label="Stop condition" Value="@StopCondition" ValueChanged="@StopConditionChanged" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="@("None")">None</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@("MetadataReceived")">Metadata received</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@("FilesChecked")">Files checked</MudSelectItem>
 | 
			
		||||
@@ -47,22 +64,58 @@
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <FieldSwitch Label="Skip hash check" @bind-Value="SkipHashCheck" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudSelect Label="Content layout" @bind-Value="ContentLayout" Variant="Variant.Outlined">
 | 
			
		||||
            <MudSelectItem Value="@("Original")">Original</MudSelectItem>
 | 
			
		||||
            <MudSelectItem Value="@("Subfolder")">Create subfolder</MudSelectItem>
 | 
			
		||||
            <MudSelectItem Value="@("NoSubfolder")">Don't create subfolder'</MudSelectItem>
 | 
			
		||||
        </MudSelect>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <FieldSwitch Label="Download in sequentual order" @bind-Value="DownloadInSequentialOrder" />
 | 
			
		||||
            <MudSelect T="string" Label="Content layout" Value="@ContentLayout" ValueChanged="@ContentLayoutChanged" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="@("Original")">Original</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@("Subfolder")">Create subfolder</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@("NoSubfolder")">Don't create subfolder</MudSelectItem>
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <FieldSwitch Label="Download in sequential order" @bind-Value="DownloadInSequentialOrder" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <FieldSwitch Label="Download first and last pieces first" @bind-Value="DownloadFirstAndLastPiecesFirst" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
        <MudItem xs="12" sm="6">
 | 
			
		||||
            <MudNumericField Label="Limit download rate" @bind-Value="DownloadLimit" Variant="Variant.Outlined" Min="0" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
        <MudItem xs="12" sm="6">
 | 
			
		||||
            <MudNumericField Label="Limit upload rate" @bind-Value="UploadLimit" Variant="Variant.Outlined" Min="0" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect T="ShareLimitMode" Label="Share limit preset" Value="@SelectedShareLimitMode" ValueChanged="@ShareLimitModeChanged" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitMode.Global">Use global share limit</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitMode.NoLimit">Set no share limit</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitMode.Custom">Set custom share limit</MudSelectItem>
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="4">
 | 
			
		||||
            <FieldSwitch Label="Ratio" Value="@RatioLimitEnabled" ValueChanged="@RatioLimitEnabledChanged" Disabled="@(!IsCustomShareLimit)" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="8">
 | 
			
		||||
            <MudNumericField T="float" Label="Ratio limit" Value="@RatioLimit" ValueChanged="@RatioLimitChanged" Disabled="@(!RatioLimitEnabled || !IsCustomShareLimit)" Min="0" Step="0.1f" Format="F2" Variant="Variant.Outlined" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="4">
 | 
			
		||||
            <FieldSwitch Label="Total minutes" Value="@SeedingTimeLimitEnabled" ValueChanged="@SeedingTimeLimitEnabledChanged" Disabled="@(!IsCustomShareLimit)" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="8">
 | 
			
		||||
            <MudNumericField T="int" Label="Total minutes" Value="@SeedingTimeLimit" ValueChanged="@SeedingTimeLimitChanged" Disabled="@(!SeedingTimeLimitEnabled || !IsCustomShareLimit)" Min="1" Variant="Variant.Outlined" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="4">
 | 
			
		||||
            <FieldSwitch Label="Inactive minutes" Value="@InactiveSeedingTimeLimitEnabled" ValueChanged="@InactiveSeedingTimeLimitEnabledChanged" Disabled="@(!IsCustomShareLimit)" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12" sm="8">
 | 
			
		||||
            <MudNumericField T="int" Label="Inactive minutes" Value="@InactiveSeedingTimeLimit" ValueChanged="@InactiveSeedingTimeLimitChanged" Disabled="@(!InactiveSeedingTimeLimitEnabled || !IsCustomShareLimit)" Min="1" Variant="Variant.Outlined" />
 | 
			
		||||
        </MudItem>
 | 
			
		||||
        <MudItem xs="12">
 | 
			
		||||
            <MudSelect T="ShareLimitAction" Label="Action when limit is reached" Value="@SelectedShareLimitAction" ValueChanged="@ShareLimitActionChanged" Disabled="@(!IsCustomShareLimit)" Variant="Variant.Outlined">
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitAction.Default">Default</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitAction.Stop">Stop torrent</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitAction.Remove">Remove torrent</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitAction.RemoveWithContent">Remove torrent and data</MudSelectItem>
 | 
			
		||||
                <MudSelectItem Value="@ShareLimitAction.EnableSuperSeeding">Enable super seeding</MudSelectItem>
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
        </MudItem>
 | 
			
		||||
    </MudGrid>
 | 
			
		||||
</MudCollapse>
 | 
			
		||||
@@ -1,4 +1,10 @@
 | 
			
		||||
using Lantean.QBitTorrentClient;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Lantean.QBitTorrentClient;
 | 
			
		||||
using Lantean.QBitTorrentClient.Models;
 | 
			
		||||
using Lantean.QBTMud.Models;
 | 
			
		||||
using Microsoft.AspNetCore.Components;
 | 
			
		||||
 | 
			
		||||
@@ -6,6 +12,15 @@ namespace Lantean.QBTMud.Components.Dialogs
 | 
			
		||||
{
 | 
			
		||||
    public partial class AddTorrentOptions
 | 
			
		||||
    {
 | 
			
		||||
        private readonly List<CategoryOption> _categoryOptions = new();
 | 
			
		||||
        private readonly Dictionary<string, CategoryOption> _categoryLookup = new(StringComparer.Ordinal);
 | 
			
		||||
        private string _manualSavePath = string.Empty;
 | 
			
		||||
        private bool _manualUseDownloadPath;
 | 
			
		||||
        private string _manualDownloadPath = string.Empty;
 | 
			
		||||
        private string _defaultSavePath = string.Empty;
 | 
			
		||||
        private string _defaultDownloadPath = string.Empty;
 | 
			
		||||
        private bool _defaultDownloadPathEnabled;
 | 
			
		||||
 | 
			
		||||
        [Inject]
 | 
			
		||||
        protected IApiClient ApiClient { get; set; } = default!;
 | 
			
		||||
 | 
			
		||||
@@ -16,15 +31,25 @@ namespace Lantean.QBTMud.Components.Dialogs
 | 
			
		||||
 | 
			
		||||
        protected bool TorrentManagementMode { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected string SavePath { get; set; } = default!;
 | 
			
		||||
        protected string SavePath { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
        protected string DownloadPath { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
        protected bool UseDownloadPath { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected bool DownloadPathDisabled => TorrentManagementMode || !UseDownloadPath;
 | 
			
		||||
 | 
			
		||||
        protected string? Cookie { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected string? RenameTorrent { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected IEnumerable<string> Categories { get; set; } = [];
 | 
			
		||||
        protected IReadOnlyList<CategoryOption> CategoryOptions => _categoryOptions;
 | 
			
		||||
 | 
			
		||||
        protected string? Category { get; set; }
 | 
			
		||||
        protected string? Category { get; set; } = string.Empty;
 | 
			
		||||
 | 
			
		||||
        protected List<string> AvailableTags { get; private set; } = [];
 | 
			
		||||
 | 
			
		||||
        protected HashSet<string> SelectedTags { get; private set; } = new(StringComparer.Ordinal);
 | 
			
		||||
 | 
			
		||||
        protected bool StartTorrent { get; set; } = true;
 | 
			
		||||
 | 
			
		||||
@@ -32,41 +57,264 @@ namespace Lantean.QBTMud.Components.Dialogs
 | 
			
		||||
 | 
			
		||||
        protected string StopCondition { get; set; } = "None";
 | 
			
		||||
 | 
			
		||||
        protected bool SkipHashCheck { get; set; } = false;
 | 
			
		||||
        protected bool SkipHashCheck { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected string ContentLayout { get; set; } = "Original";
 | 
			
		||||
 | 
			
		||||
        protected bool DownloadInSequentialOrder { get; set; } = false;
 | 
			
		||||
        protected bool DownloadInSequentialOrder { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected bool DownloadFirstAndLastPiecesFirst { get; set; } = false;
 | 
			
		||||
        protected bool DownloadFirstAndLastPiecesFirst { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected long DownloadLimit { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected long UploadLimit { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected ShareLimitMode SelectedShareLimitMode { get; set; } = ShareLimitMode.Global;
 | 
			
		||||
 | 
			
		||||
        protected bool RatioLimitEnabled { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected float RatioLimit { get; set; } = 1.0f;
 | 
			
		||||
 | 
			
		||||
        protected bool SeedingTimeLimitEnabled { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected int SeedingTimeLimit { get; set; } = 1440;
 | 
			
		||||
 | 
			
		||||
        protected bool InactiveSeedingTimeLimitEnabled { get; set; }
 | 
			
		||||
 | 
			
		||||
        protected int InactiveSeedingTimeLimit { get; set; } = 1440;
 | 
			
		||||
 | 
			
		||||
        protected ShareLimitAction SelectedShareLimitAction { get; set; } = ShareLimitAction.Default;
 | 
			
		||||
 | 
			
		||||
        protected bool IsCustomShareLimit => SelectedShareLimitMode == ShareLimitMode.Custom;
 | 
			
		||||
 | 
			
		||||
        protected override async Task OnInitializedAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var categories = await ApiClient.GetAllCategories();
 | 
			
		||||
            Categories = categories.Select(c => c.Key).ToList();
 | 
			
		||||
            foreach (var (name, value) in categories.OrderBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
            {
 | 
			
		||||
                var option = new CategoryOption(name, value.SavePath, value.DownloadPath);
 | 
			
		||||
                _categoryOptions.Add(option);
 | 
			
		||||
                _categoryLookup[name] = option;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var tags = await ApiClient.GetAllTags();
 | 
			
		||||
            AvailableTags = tags.OrderBy(t => t, StringComparer.OrdinalIgnoreCase).ToList();
 | 
			
		||||
 | 
			
		||||
            var preferences = await ApiClient.GetApplicationPreferences();
 | 
			
		||||
 | 
			
		||||
            TorrentManagementMode = preferences.AutoTmmEnabled;
 | 
			
		||||
            SavePath = preferences.SavePath;
 | 
			
		||||
 | 
			
		||||
            _defaultSavePath = preferences.SavePath ?? string.Empty;
 | 
			
		||||
            _manualSavePath = _defaultSavePath;
 | 
			
		||||
            SavePath = _defaultSavePath;
 | 
			
		||||
 | 
			
		||||
            _defaultDownloadPath = preferences.TempPath ?? string.Empty;
 | 
			
		||||
            _defaultDownloadPathEnabled = preferences.TempPathEnabled;
 | 
			
		||||
            _manualDownloadPath = _defaultDownloadPath;
 | 
			
		||||
            _manualUseDownloadPath = preferences.TempPathEnabled;
 | 
			
		||||
            UseDownloadPath = _manualUseDownloadPath;
 | 
			
		||||
            DownloadPath = UseDownloadPath ? _manualDownloadPath : string.Empty;
 | 
			
		||||
 | 
			
		||||
            StartTorrent = !preferences.AddStoppedEnabled;
 | 
			
		||||
            AddToTopOfQueue = preferences.AddToTopOfQueue;
 | 
			
		||||
            StopCondition = preferences.TorrentStopCondition;
 | 
			
		||||
            ContentLayout = preferences.TorrentContentLayout;
 | 
			
		||||
 | 
			
		||||
            RatioLimitEnabled = preferences.MaxRatioEnabled;
 | 
			
		||||
            RatioLimit = preferences.MaxRatio;
 | 
			
		||||
            SeedingTimeLimitEnabled = preferences.MaxSeedingTimeEnabled;
 | 
			
		||||
            if (preferences.MaxSeedingTimeEnabled)
 | 
			
		||||
            {
 | 
			
		||||
                SeedingTimeLimit = preferences.MaxSeedingTime;
 | 
			
		||||
            }
 | 
			
		||||
            InactiveSeedingTimeLimitEnabled = preferences.MaxInactiveSeedingTimeEnabled;
 | 
			
		||||
            if (preferences.MaxInactiveSeedingTimeEnabled)
 | 
			
		||||
            {
 | 
			
		||||
                InactiveSeedingTimeLimit = preferences.MaxInactiveSeedingTime;
 | 
			
		||||
            }
 | 
			
		||||
            SelectedShareLimitAction = MapShareLimitAction(preferences.MaxRatioAct);
 | 
			
		||||
 | 
			
		||||
            if (TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                ApplyAutomaticPaths();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SetTorrentManagementMode(bool value)
 | 
			
		||||
        {
 | 
			
		||||
            if (TorrentManagementMode == value)
 | 
			
		||||
            {
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TorrentManagementMode = value;
 | 
			
		||||
            if (TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                ApplyAutomaticPaths();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                RestoreManualPaths();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SavePathChanged(string value)
 | 
			
		||||
        {
 | 
			
		||||
            SavePath = value;
 | 
			
		||||
            if (!TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                _manualSavePath = value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SetUseDownloadPath(bool value)
 | 
			
		||||
        {
 | 
			
		||||
            if (TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _manualUseDownloadPath = value;
 | 
			
		||||
            UseDownloadPath = value;
 | 
			
		||||
 | 
			
		||||
            if (value)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(_manualDownloadPath))
 | 
			
		||||
                {
 | 
			
		||||
                    _manualDownloadPath = string.IsNullOrWhiteSpace(_defaultDownloadPath) ? string.Empty : _defaultDownloadPath;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                DownloadPath = _manualDownloadPath;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _manualDownloadPath = DownloadPath;
 | 
			
		||||
                DownloadPath = string.Empty;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task DownloadPathChanged(string value)
 | 
			
		||||
        {
 | 
			
		||||
            DownloadPath = value;
 | 
			
		||||
            if (!TorrentManagementMode && UseDownloadPath)
 | 
			
		||||
            {
 | 
			
		||||
                _manualDownloadPath = value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task CategoryChanged(string? value)
 | 
			
		||||
        {
 | 
			
		||||
            Category = string.IsNullOrWhiteSpace(value) ? null : value;
 | 
			
		||||
            if (TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                ApplyAutomaticPaths();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SelectedTagsChanged(IEnumerable<string> tags)
 | 
			
		||||
        {
 | 
			
		||||
            SelectedTags = tags is null
 | 
			
		||||
                ? new HashSet<string>(StringComparer.Ordinal)
 | 
			
		||||
                : new HashSet<string>(tags, StringComparer.Ordinal);
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task StopConditionChanged(string value)
 | 
			
		||||
        {
 | 
			
		||||
            StopCondition = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task ContentLayoutChanged(string value)
 | 
			
		||||
        {
 | 
			
		||||
            ContentLayout = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task ShareLimitModeChanged(ShareLimitMode mode)
 | 
			
		||||
        {
 | 
			
		||||
            SelectedShareLimitMode = mode;
 | 
			
		||||
            if (mode != ShareLimitMode.Custom)
 | 
			
		||||
            {
 | 
			
		||||
                RatioLimitEnabled = false;
 | 
			
		||||
                SeedingTimeLimitEnabled = false;
 | 
			
		||||
                InactiveSeedingTimeLimitEnabled = false;
 | 
			
		||||
                SelectedShareLimitAction = ShareLimitAction.Default;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task RatioLimitEnabledChanged(bool value)
 | 
			
		||||
        {
 | 
			
		||||
            RatioLimitEnabled = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task RatioLimitChanged(float value)
 | 
			
		||||
        {
 | 
			
		||||
            RatioLimit = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SeedingTimeLimitEnabledChanged(bool value)
 | 
			
		||||
        {
 | 
			
		||||
            SeedingTimeLimitEnabled = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task SeedingTimeLimitChanged(int value)
 | 
			
		||||
        {
 | 
			
		||||
            SeedingTimeLimit = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task InactiveSeedingTimeLimitEnabledChanged(bool value)
 | 
			
		||||
        {
 | 
			
		||||
            InactiveSeedingTimeLimitEnabled = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task InactiveSeedingTimeLimitChanged(int value)
 | 
			
		||||
        {
 | 
			
		||||
            InactiveSeedingTimeLimit = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected Task ShareLimitActionChanged(ShareLimitAction value)
 | 
			
		||||
        {
 | 
			
		||||
            SelectedShareLimitAction = value;
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public TorrentOptions GetTorrentOptions()
 | 
			
		||||
        {
 | 
			
		||||
            return new TorrentOptions(
 | 
			
		||||
            var options = new TorrentOptions(
 | 
			
		||||
                TorrentManagementMode,
 | 
			
		||||
                SavePath,
 | 
			
		||||
                _manualSavePath,
 | 
			
		||||
                Cookie,
 | 
			
		||||
                RenameTorrent,
 | 
			
		||||
                Category,
 | 
			
		||||
                string.IsNullOrWhiteSpace(Category) ? null : Category,
 | 
			
		||||
                StartTorrent,
 | 
			
		||||
                AddToTopOfQueue,
 | 
			
		||||
                StopCondition,
 | 
			
		||||
@@ -76,6 +324,152 @@ namespace Lantean.QBTMud.Components.Dialogs
 | 
			
		||||
                DownloadFirstAndLastPiecesFirst,
 | 
			
		||||
                DownloadLimit,
 | 
			
		||||
                UploadLimit);
 | 
			
		||||
 | 
			
		||||
            options.UseDownloadPath = TorrentManagementMode ? null : UseDownloadPath;
 | 
			
		||||
            options.DownloadPath = (!TorrentManagementMode && UseDownloadPath) ? DownloadPath : null;
 | 
			
		||||
            options.Tags = SelectedTags.Count > 0 ? SelectedTags.ToArray() : null;
 | 
			
		||||
 | 
			
		||||
            switch (SelectedShareLimitMode)
 | 
			
		||||
            {
 | 
			
		||||
                case ShareLimitMode.Global:
 | 
			
		||||
                    options.RatioLimit = Limits.GlobalLimit;
 | 
			
		||||
                    options.SeedingTimeLimit = Limits.GlobalLimit;
 | 
			
		||||
                    options.InactiveSeedingTimeLimit = Limits.GlobalLimit;
 | 
			
		||||
                    options.ShareLimitAction = ShareLimitAction.Default.ToString();
 | 
			
		||||
                    break;
 | 
			
		||||
                case ShareLimitMode.NoLimit:
 | 
			
		||||
                    options.RatioLimit = Limits.NoLimit;
 | 
			
		||||
                    options.SeedingTimeLimit = Limits.NoLimit;
 | 
			
		||||
                    options.InactiveSeedingTimeLimit = Limits.NoLimit;
 | 
			
		||||
                    options.ShareLimitAction = ShareLimitAction.Default.ToString();
 | 
			
		||||
                    break;
 | 
			
		||||
                case ShareLimitMode.Custom:
 | 
			
		||||
                    options.RatioLimit = RatioLimitEnabled ? RatioLimit : Limits.NoLimit;
 | 
			
		||||
                    options.SeedingTimeLimit = SeedingTimeLimitEnabled ? SeedingTimeLimit : Limits.NoLimit;
 | 
			
		||||
                    options.InactiveSeedingTimeLimit = InactiveSeedingTimeLimitEnabled ? InactiveSeedingTimeLimit : Limits.NoLimit;
 | 
			
		||||
                    options.ShareLimitAction = SelectedShareLimitAction.ToString();
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return options;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ApplyAutomaticPaths()
 | 
			
		||||
        {
 | 
			
		||||
            SavePath = ResolveAutomaticSavePath();
 | 
			
		||||
            var (enabled, path) = ResolveAutomaticDownloadPath();
 | 
			
		||||
            UseDownloadPath = enabled;
 | 
			
		||||
            DownloadPath = enabled ? path ?? string.Empty : string.Empty;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void RestoreManualPaths()
 | 
			
		||||
        {
 | 
			
		||||
            SavePath = _manualSavePath;
 | 
			
		||||
            UseDownloadPath = _manualUseDownloadPath;
 | 
			
		||||
            DownloadPath = _manualUseDownloadPath ? _manualDownloadPath : string.Empty;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string ResolveAutomaticSavePath()
 | 
			
		||||
        {
 | 
			
		||||
            var category = GetSelectedCategory();
 | 
			
		||||
            if (category is null)
 | 
			
		||||
            {
 | 
			
		||||
                return _defaultSavePath;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(category.SavePath))
 | 
			
		||||
            {
 | 
			
		||||
                return category.SavePath!;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(_defaultSavePath) && !string.IsNullOrWhiteSpace(category.Name))
 | 
			
		||||
            {
 | 
			
		||||
                return Path.Combine(_defaultSavePath, category.Name);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return _defaultSavePath;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private (bool Enabled, string? Path) ResolveAutomaticDownloadPath()
 | 
			
		||||
        {
 | 
			
		||||
            var category = GetSelectedCategory();
 | 
			
		||||
            if (category is null)
 | 
			
		||||
            {
 | 
			
		||||
                if (!_defaultDownloadPathEnabled)
 | 
			
		||||
                {
 | 
			
		||||
                    return (false, string.Empty);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return (true, _defaultDownloadPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (category.DownloadPath is null)
 | 
			
		||||
            {
 | 
			
		||||
                if (!_defaultDownloadPathEnabled)
 | 
			
		||||
                {
 | 
			
		||||
                    return (false, string.Empty);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return (true, ComposeDefaultDownloadPath(category.Name));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!category.DownloadPath.Enabled)
 | 
			
		||||
            {
 | 
			
		||||
                return (false, string.Empty);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(category.DownloadPath.Path))
 | 
			
		||||
            {
 | 
			
		||||
                return (true, category.DownloadPath.Path);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (true, ComposeDefaultDownloadPath(category.Name));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string ComposeDefaultDownloadPath(string categoryName)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(_defaultDownloadPath))
 | 
			
		||||
            {
 | 
			
		||||
                return string.Empty;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(categoryName))
 | 
			
		||||
            {
 | 
			
		||||
                return _defaultDownloadPath;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Path.Combine(_defaultDownloadPath, categoryName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private CategoryOption? GetSelectedCategory()
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(Category))
 | 
			
		||||
            {
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return _categoryLookup.TryGetValue(Category, out var option) ? option : null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static ShareLimitAction MapShareLimitAction(int preferenceValue)
 | 
			
		||||
        {
 | 
			
		||||
            return preferenceValue switch
 | 
			
		||||
            {
 | 
			
		||||
                0 => ShareLimitAction.Stop,
 | 
			
		||||
                1 => ShareLimitAction.Remove,
 | 
			
		||||
                2 => ShareLimitAction.RemoveWithContent,
 | 
			
		||||
                3 => ShareLimitAction.EnableSuperSeeding,
 | 
			
		||||
                _ => ShareLimitAction.Default
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected enum ShareLimitMode
 | 
			
		||||
        {
 | 
			
		||||
            Global,
 | 
			
		||||
            NoLimit,
 | 
			
		||||
            Custom
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected sealed record CategoryOption(string Name, string? SavePath, DownloadPathOption? DownloadPath);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using Lantean.QBitTorrentClient;
 | 
			
		||||
using ShareLimitAction = Lantean.QBitTorrentClient.Models.ShareLimitAction;
 | 
			
		||||
using Lantean.QBTMud.Components.Dialogs;
 | 
			
		||||
@@ -77,12 +76,18 @@ namespace Lantean.QBTMud.Helpers
 | 
			
		||||
                addTorrentParams.ContentLayout = Enum.Parse<QBitTorrentClient.Models.TorrentContentLayout>(options.ContentLayout);
 | 
			
		||||
            }
 | 
			
		||||
            addTorrentParams.DownloadLimit = options.DownloadLimit;
 | 
			
		||||
            addTorrentParams.DownloadPath = options.DownloadPath;
 | 
			
		||||
            if (!string.IsNullOrWhiteSpace(options.DownloadPath))
 | 
			
		||||
            {
 | 
			
		||||
                addTorrentParams.DownloadPath = options.DownloadPath;
 | 
			
		||||
            }
 | 
			
		||||
            addTorrentParams.FirstLastPiecePriority = options.DownloadFirstAndLastPiecesFirst;
 | 
			
		||||
            addTorrentParams.InactiveSeedingTimeLimit = options.InactiveSeedingTimeLimit;
 | 
			
		||||
            addTorrentParams.RatioLimit = options.RatioLimit;
 | 
			
		||||
            addTorrentParams.RenameTorrent = options.RenameTorrent;
 | 
			
		||||
            addTorrentParams.SavePath = options.SavePath;
 | 
			
		||||
            if (!options.TorrentManagementMode)
 | 
			
		||||
            {
 | 
			
		||||
                addTorrentParams.SavePath = options.SavePath;
 | 
			
		||||
            }
 | 
			
		||||
            addTorrentParams.SeedingTimeLimit = options.SeedingTimeLimit;
 | 
			
		||||
            addTorrentParams.SequentialDownload = options.DownloadInSequentialOrder;
 | 
			
		||||
            if (!string.IsNullOrEmpty(options.ShareLimitAction))
 | 
			
		||||
@@ -97,7 +102,10 @@ namespace Lantean.QBTMud.Helpers
 | 
			
		||||
            addTorrentParams.Stopped = !options.StartTorrent;
 | 
			
		||||
            addTorrentParams.Tags = options.Tags;
 | 
			
		||||
            addTorrentParams.UploadLimit = options.UploadLimit;
 | 
			
		||||
            addTorrentParams.UseDownloadPath = options.UseDownloadPath;
 | 
			
		||||
            if (options.UseDownloadPath.HasValue)
 | 
			
		||||
            {
 | 
			
		||||
                addTorrentParams.UseDownloadPath = options.UseDownloadPath;
 | 
			
		||||
            }
 | 
			
		||||
            return addTorrentParams;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -259,7 +267,7 @@ namespace Lantean.QBTMud.Helpers
 | 
			
		||||
                ShareLimitAction = t.ShareLimitAction,
 | 
			
		||||
            }).ToList();
 | 
			
		||||
 | 
			
		||||
            var referenceValue = shareRatioValues.First();
 | 
			
		||||
            var referenceValue = shareRatioValues[0];
 | 
			
		||||
            var torrentsHaveSameShareRatio = shareRatioValues.Distinct().Count() == 1;
 | 
			
		||||
 | 
			
		||||
            var parameters = new DialogParameters
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
using Lantean.QBitTorrentClient.Models;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Lantean.QBitTorrentClient.Converters
 | 
			
		||||
{
 | 
			
		||||
    public sealed class DownloadPathOptionJsonConverter : JsonConverter<DownloadPathOption>
 | 
			
		||||
    {
 | 
			
		||||
        public override DownloadPathOption? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
 | 
			
		||||
        {
 | 
			
		||||
            return reader.TokenType switch
 | 
			
		||||
            {
 | 
			
		||||
                JsonTokenType.Null => null,
 | 
			
		||||
                JsonTokenType.False => new DownloadPathOption(false, null),
 | 
			
		||||
                JsonTokenType.True => new DownloadPathOption(true, null),
 | 
			
		||||
                JsonTokenType.String => new DownloadPathOption(true, reader.GetString()),
 | 
			
		||||
                _ => throw new JsonException($"Unexpected token {reader.TokenType} when parsing download_path.")
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override void Write(Utf8JsonWriter writer, DownloadPathOption? value, JsonSerializerOptions options)
 | 
			
		||||
        {
 | 
			
		||||
            if (value is null)
 | 
			
		||||
            {
 | 
			
		||||
                writer.WriteNullValue();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!value.Enabled)
 | 
			
		||||
            {
 | 
			
		||||
                writer.WriteBooleanValue(false);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(value.Path))
 | 
			
		||||
            {
 | 
			
		||||
                writer.WriteBooleanValue(true);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            writer.WriteStringValue(value.Path);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
using Lantean.QBitTorrentClient.Converters;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace Lantean.QBitTorrentClient.Models
 | 
			
		||||
{
 | 
			
		||||
@@ -7,10 +8,12 @@ namespace Lantean.QBitTorrentClient.Models
 | 
			
		||||
        [JsonConstructor]
 | 
			
		||||
        public Category(
 | 
			
		||||
            string name,
 | 
			
		||||
            string? savePath)
 | 
			
		||||
            string? savePath,
 | 
			
		||||
            DownloadPathOption? downloadPath)
 | 
			
		||||
        {
 | 
			
		||||
            Name = name;
 | 
			
		||||
            SavePath = savePath;
 | 
			
		||||
            DownloadPath = downloadPath;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [JsonPropertyName("name")]
 | 
			
		||||
@@ -18,5 +21,9 @@ namespace Lantean.QBitTorrentClient.Models
 | 
			
		||||
 | 
			
		||||
        [JsonPropertyName("savePath")]
 | 
			
		||||
        public string? SavePath { get; }
 | 
			
		||||
 | 
			
		||||
        [JsonPropertyName("download_path")]
 | 
			
		||||
        [JsonConverter(typeof(DownloadPathOptionJsonConverter))]
 | 
			
		||||
        public DownloadPathOption? DownloadPath { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Lantean.QBitTorrentClient/Models/DownloadPathOption.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Lantean.QBitTorrentClient/Models/DownloadPathOption.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
namespace Lantean.QBitTorrentClient.Models
 | 
			
		||||
{
 | 
			
		||||
    public record DownloadPathOption
 | 
			
		||||
    {
 | 
			
		||||
        public DownloadPathOption(bool enabled, string? path)
 | 
			
		||||
        {
 | 
			
		||||
            Enabled = enabled;
 | 
			
		||||
            Path = path;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Enabled { get; }
 | 
			
		||||
 | 
			
		||||
        public string? Path { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user