mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-11-02 13:03:23 +00:00
Compare commits
17 Commits
v1.0.1
...
d4ac79af00
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4ac79af00 | ||
|
|
7370d73c59 | ||
|
|
8796cc0f24 | ||
|
|
b24ae440d4 | ||
|
|
bb90ce5216 | ||
|
|
1cf9f97187 | ||
|
|
4f9129fd46 | ||
|
|
9a9d2c2ee2 | ||
|
|
736bc46745 | ||
|
|
23ae19c4c7 | ||
|
|
603470eb30 | ||
|
|
27c2406340 | ||
|
|
4578dcc11f | ||
|
|
3215fa3936 | ||
|
|
78e62f31d0 | ||
|
|
e23842fcb0 | ||
|
|
411c7f87cc |
@@ -4,24 +4,20 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="7.1.0" AllowedVersions="[5.0.0,7.*.*)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="MudBlazor" Version="8.2.0" />
|
||||
<PackageReference Include="AwesomeAssertions" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Lantean.QBTMud.Test
|
||||
Test2(a => a.Name);
|
||||
}
|
||||
|
||||
private void Test2(Expression<Func<TestClass, object>> expr)
|
||||
private void Test2(Expression<Func<TestClass, object?>> expr)
|
||||
{
|
||||
var body = expr.Body;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace Lantean.QBTMud.Test
|
||||
|
||||
var l = Expression.Lambda<Func<TestClass, object>>(convertExpression, expression);
|
||||
|
||||
Expression<Func<TestClass, object>> expr2 = a => a.Name;
|
||||
Expression<Func<TestClass, object?>> expr2 = a => a.Name;
|
||||
|
||||
var x = l.Compile();
|
||||
var res = (long)x(new TestClass { Name = "Name", Value = 12 });
|
||||
@@ -58,9 +58,9 @@ namespace Lantean.QBTMud.Test
|
||||
|
||||
public class TestClass
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
||||
public long Value { get; set; }
|
||||
}
|
||||
|
||||
@@ -92,7 +92,9 @@
|
||||
<FieldSwitch Label="When ratio reaches" Value="MaxRatioEnabled" ValueChanged="MaxRatioEnabledChanged" />
|
||||
</MudItem>
|
||||
<MudItem xs="9">
|
||||
<MudNumericField T="int" Label="" Value="MaxRatio" ValueChanged="MaxRatioChanged" Disabled="@(!MaxRatioEnabled)" Min="0" Max="9998" Variant="Variant.Outlined" Validation="MaxRatioValidation" />
|
||||
<MudNumericField T="float" Label="" Value="MaxRatio" ValueChanged="MaxRatioChanged"
|
||||
Disabled="@(!MaxRatioEnabled)" Min="0" Max="9998" Variant="Variant.Outlined"
|
||||
Validation="MaxRatioValidation" />
|
||||
</MudItem>
|
||||
<MudItem xs="3">
|
||||
<FieldSwitch Label="When total seeding time reaches" Value="MaxSeedingTimeEnabled" ValueChanged="MaxSeedingTimeEnabledChanged" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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 float MaxRatio { get; private set; }
|
||||
protected bool MaxSeedingTimeEnabled { get; private set; }
|
||||
protected int MaxSeedingTime { get; private set; }
|
||||
protected int MaxRatioAct { get; private set; }
|
||||
@@ -275,7 +275,7 @@
|
||||
await PreferencesChanged.InvokeAsync(UpdatePreferences);
|
||||
}
|
||||
|
||||
protected async Task MaxRatioChanged(int value)
|
||||
protected async Task MaxRatioChanged(float value)
|
||||
{
|
||||
MaxRatio = value;
|
||||
UpdatePreferences.MaxRatio = value;
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<MudCardContent Class="pt-0">
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
<MudSelect T="bool" Label="Default Torrent Management Mode" Value="AutoTmmEnabled" ValueChanged="AutoDeleteModeChanged" Variant="Variant.Outlined">
|
||||
<MudSelect T="bool" Label="Default Torrent Management Mode" Value="AutoTmmEnabled" ValueChanged="AutoTmmEnabledChanged" Variant="Variant.Outlined">
|
||||
<MudSelectItem Value="false">Manual</MudSelectItem>
|
||||
<MudSelectItem Value="true">Automatic</MudSelectItem>
|
||||
</MudSelect>
|
||||
|
||||
@@ -12,10 +12,7 @@ namespace Lantean.QBTMud.Components
|
||||
{
|
||||
public partial class TorrentActions : IAsyncDisposable
|
||||
{
|
||||
private const int _defaultVersion = 5;
|
||||
|
||||
private bool _disposedValue;
|
||||
private int? _version;
|
||||
|
||||
private List<UIAction>? _actions;
|
||||
|
||||
@@ -74,30 +71,7 @@ namespace Lantean.QBTMud.Components
|
||||
|
||||
protected bool OverlayVisible { get; set; }
|
||||
|
||||
protected int MajorVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_version is not null)
|
||||
{
|
||||
return _version.Value;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Version))
|
||||
{
|
||||
return _defaultVersion;
|
||||
}
|
||||
|
||||
if (!System.Version.TryParse(Version.Replace("v", ""), out var version))
|
||||
{
|
||||
return _defaultVersion;
|
||||
}
|
||||
|
||||
_version = version.Major;
|
||||
|
||||
return _version.Value;
|
||||
}
|
||||
}
|
||||
protected int MajorVersion => VersionHelper.GetMajorVersion(Version);
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
|
||||
@@ -19,28 +19,28 @@ namespace Lantean.QBTMud.Helpers
|
||||
{
|
||||
if (seconds is null)
|
||||
{
|
||||
return "";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (seconds == 8640000)
|
||||
const long InfiniteEtaSentinelSeconds = 8_640_000; // ~100 days, used by qBittorrent for "infinite" ETA.
|
||||
var value = seconds.Value;
|
||||
|
||||
if (value >= long.MaxValue || value >= TimeSpan.MaxValue.TotalSeconds || value == InfiniteEtaSentinelSeconds)
|
||||
{
|
||||
return "∞";
|
||||
}
|
||||
|
||||
if (seconds < 60)
|
||||
if (value <= 0)
|
||||
{
|
||||
return "< 1m";
|
||||
}
|
||||
|
||||
TimeSpan time;
|
||||
try
|
||||
var time = TimeSpan.FromSeconds(value);
|
||||
if (time.TotalMinutes < 1)
|
||||
{
|
||||
time = TimeSpan.FromSeconds(seconds.Value);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return "∞";
|
||||
return "< 1m";
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (prefix is not null)
|
||||
{
|
||||
@@ -83,6 +83,7 @@ namespace Lantean.QBTMud.Helpers
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Formats a file size in bytes into an appropriate unit based on the size.
|
||||
/// </summary>
|
||||
@@ -129,7 +130,7 @@ namespace Lantean.QBTMud.Helpers
|
||||
return "";
|
||||
}
|
||||
|
||||
return Size(size);
|
||||
return Size(size, prefix, suffix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -119,34 +119,34 @@ namespace Lantean.QBTMud.Helpers
|
||||
switch (category)
|
||||
{
|
||||
case CATEGORY_ALL:
|
||||
break;
|
||||
return true;
|
||||
|
||||
case CATEGORY_UNCATEGORIZED:
|
||||
if (!string.IsNullOrEmpty(torrent.Category))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
return true;
|
||||
default:
|
||||
if (string.IsNullOrEmpty(torrent.Category))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!useSubcategories)
|
||||
{
|
||||
if (torrent.Category != category)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!torrent.Category.StartsWith(category))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return string.Equals(torrent.Category, category, StringComparison.Ordinal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (string.Equals(torrent.Category, category, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var prefix = string.Concat(category, "/");
|
||||
return torrent.Category.StartsWith(prefix, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool FilterTag(Torrent torrent, string tag)
|
||||
@@ -207,7 +207,7 @@ namespace Lantean.QBTMud.Helpers
|
||||
break;
|
||||
|
||||
case Status.Paused:
|
||||
if (!state.Contains("paused") || !state.Contains("stopped"))
|
||||
if (!state.Contains("paused") && !state.Contains("stopped"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
34
Lantean.QBTMud/Helpers/VersionHelper.cs
Normal file
34
Lantean.QBTMud/Helpers/VersionHelper.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
namespace Lantean.QBTMud.Helpers
|
||||
{
|
||||
internal static class VersionHelper
|
||||
{
|
||||
private static int? _version;
|
||||
|
||||
private const int _defaultVersion = 5;
|
||||
|
||||
public static int DefaultVersion => _defaultVersion;
|
||||
|
||||
public static int GetMajorVersion(string? version)
|
||||
{
|
||||
if (_version is not null)
|
||||
{
|
||||
return _version.Value;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return _defaultVersion;
|
||||
}
|
||||
|
||||
if (!Version.TryParse(version?.Replace("v", ""), out var theVersion))
|
||||
{
|
||||
return _defaultVersion;
|
||||
}
|
||||
|
||||
_version = theVersion.Major;
|
||||
|
||||
return _version.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,19 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<CompressionEnabled>false</CompressionEnabled>
|
||||
<LangVersion>12</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<CompressionEnabled>false</CompressionEnabled>
|
||||
<LangVersion>12</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
<PackageReference Include="ByteSize" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.1" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.1" />
|
||||
<PackageReference Include="MudBlazor" Version="8.2.0" />
|
||||
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0" />
|
||||
<!-- added to fix vuln in dependency -->
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
<PackageReference Include="ByteSize" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||
<PackageReference Include="MudBlazor" Version="8.7.0" />
|
||||
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Lantean.QBTMud.Layout
|
||||
Preferences = await ApiClient.GetApplicationPreferences();
|
||||
Version = await ApiClient.GetApplicationVersion();
|
||||
var data = await ApiClient.GetMainData(_requestId);
|
||||
MainData = DataManager.CreateMainData(data);
|
||||
MainData = DataManager.CreateMainData(data, Version);
|
||||
|
||||
_requestId = data.ResponseId;
|
||||
_refreshInterval = MainData.ServerState.RefreshInterval;
|
||||
@@ -128,7 +128,7 @@ namespace Lantean.QBTMud.Layout
|
||||
|
||||
if (MainData is null || data.FullUpdate)
|
||||
{
|
||||
MainData = DataManager.CreateMainData(data);
|
||||
MainData = DataManager.CreateMainData(data, Version);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -13,9 +13,6 @@ namespace Lantean.QBTMud.Layout
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
[Inject]
|
||||
private IBrowserViewportService BrowserViewportService { get; set; } = default!;
|
||||
|
||||
@@ -78,13 +75,13 @@ namespace Lantean.QBTMud.Layout
|
||||
{
|
||||
IsDarkMode = isDarkMode.Value;
|
||||
}
|
||||
await MudThemeProvider.WatchSystemPreference(OnSystemPreferenceChanged);
|
||||
await MudThemeProvider.WatchSystemDarkModeAsync(OnSystemDarkModeChanged);
|
||||
await BrowserViewportService.SubscribeAsync(this, fireImmediately: true);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
protected Task OnSystemPreferenceChanged(bool value)
|
||||
protected Task OnSystemDarkModeChanged(bool value)
|
||||
{
|
||||
IsDarkMode = value;
|
||||
return Task.CompletedTask;
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
Dictionary<string, HashSet<string>> tagState,
|
||||
Dictionary<string, HashSet<string>> categoriesState,
|
||||
Dictionary<string, HashSet<string>> statusState,
|
||||
Dictionary<string, HashSet<string>> trackersState)
|
||||
Dictionary<string, HashSet<string>> trackersState,
|
||||
int majorVersion)
|
||||
{
|
||||
Torrents = torrents.ToDictionary();
|
||||
Tags = tags.ToHashSet();
|
||||
@@ -22,6 +23,7 @@
|
||||
CategoriesState = categoriesState;
|
||||
StatusState = statusState;
|
||||
TrackersState = trackersState;
|
||||
MajorVersion = majorVersion;
|
||||
}
|
||||
|
||||
public Dictionary<string, Torrent> Torrents { get; }
|
||||
@@ -36,5 +38,6 @@
|
||||
public Dictionary<string, HashSet<string>> TrackersState { get; }
|
||||
public string? SelectedTorrentHash { get; set; }
|
||||
public bool LostConnection { get; set; }
|
||||
public int MajorVersion { get; }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
Completed,
|
||||
Resumed,
|
||||
Paused,
|
||||
Stopped,
|
||||
Active,
|
||||
Inactive,
|
||||
Stalled,
|
||||
@@ -15,6 +16,6 @@
|
||||
StalledDownloading,
|
||||
Checking,
|
||||
Errored,
|
||||
Stopped
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
public class DataManager : IDataManager
|
||||
{
|
||||
private static readonly Status[] _statuses = Enum.GetValues<Status>();
|
||||
private static Status[]? _statusArray = null;
|
||||
|
||||
public PeerList CreatePeerList(QBitTorrentClient.Models.TorrentPeers torrentPeers)
|
||||
{
|
||||
@@ -25,8 +25,9 @@ namespace Lantean.QBTMud.Services
|
||||
return peerList;
|
||||
}
|
||||
|
||||
public MainData CreateMainData(QBitTorrentClient.Models.MainData mainData)
|
||||
public MainData CreateMainData(QBitTorrentClient.Models.MainData mainData, string version)
|
||||
{
|
||||
var majorVersion = VersionHelper.GetMajorVersion(version);
|
||||
var torrents = new Dictionary<string, Torrent>(mainData.Torrents?.Count ?? 0);
|
||||
if (mainData.Torrents is not null)
|
||||
{
|
||||
@@ -38,12 +39,19 @@ namespace Lantean.QBTMud.Services
|
||||
}
|
||||
}
|
||||
|
||||
var tags = new List<string>(mainData.Tags?.Count ?? 0);
|
||||
var tags = new List<string>();
|
||||
if (mainData.Tags is not null)
|
||||
{
|
||||
var seenTags = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var tag in mainData.Tags)
|
||||
{
|
||||
tags.Add(tag);
|
||||
var normalizedTag = NormalizeTag(tag);
|
||||
if (string.IsNullOrEmpty(normalizedTag) || !seenTags.Add(normalizedTag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tags.Add(normalizedTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +95,9 @@ namespace Lantean.QBTMud.Services
|
||||
categoriesState.Add(category, torrents.Values.Where(t => FilterHelper.FilterCategory(t, category, serverState.UseSubcategories)).ToHashesHashSet());
|
||||
}
|
||||
|
||||
var statusState = new Dictionary<string, HashSet<string>>(_statuses.Length + 2);
|
||||
foreach (var status in _statuses)
|
||||
var statuses = GetStatuses(majorVersion).ToArray();
|
||||
var statusState = new Dictionary<string, HashSet<string>>(statuses.Length + 2);
|
||||
foreach (var status in statuses)
|
||||
{
|
||||
statusState.Add(status.ToString(), torrents.Values.Where(t => FilterHelper.FilterStatus(t, status)).ToHashesHashSet());
|
||||
}
|
||||
@@ -101,7 +110,7 @@ namespace Lantean.QBTMud.Services
|
||||
trackersState.Add(tracker, torrents.Values.Where(t => FilterHelper.FilterTracker(t, tracker)).ToHashesHashSet());
|
||||
}
|
||||
|
||||
var torrentList = new MainData(torrents, tags, categories, trackers, serverState, tagState, categoriesState, statusState, trackersState);
|
||||
var torrentList = new MainData(torrents, tags, categories, trackers, serverState, tagState, categoriesState, statusState, trackersState, majorVersion);
|
||||
|
||||
return torrentList;
|
||||
}
|
||||
@@ -155,8 +164,14 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
foreach (var tag in mainData.TagsRemoved)
|
||||
{
|
||||
torrentList.Tags.Remove(tag);
|
||||
torrentList.TagState.Remove(tag);
|
||||
var normalizedTag = NormalizeTag(tag);
|
||||
if (string.IsNullOrEmpty(normalizedTag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
torrentList.Tags.Remove(normalizedTag);
|
||||
torrentList.TagState.Remove(normalizedTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +213,18 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
foreach (var tag in mainData.Tags)
|
||||
{
|
||||
torrentList.Tags.Add(tag);
|
||||
var normalizedTag = NormalizeTag(tag);
|
||||
if (string.IsNullOrEmpty(normalizedTag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
torrentList.Tags.Add(normalizedTag);
|
||||
var matchingHashes = torrentList.Torrents
|
||||
.Where(pair => FilterHelper.FilterTag(pair.Value, normalizedTag))
|
||||
.Select(pair => pair.Key)
|
||||
.ToHashSet();
|
||||
torrentList.TagState[normalizedTag] = matchingHashes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +232,7 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
foreach (var (url, hashes) in mainData.Trackers)
|
||||
{
|
||||
if (!torrentList.Trackers.TryGetValue(url, out var existingHashes))
|
||||
if (!torrentList.Trackers.TryGetValue(url, out _))
|
||||
{
|
||||
torrentList.Trackers.Add(url, hashes);
|
||||
}
|
||||
@@ -225,7 +251,7 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
var newTorrent = CreateTorrent(hash, torrent);
|
||||
torrentList.Torrents.Add(hash, newTorrent);
|
||||
AddTorrentToStates(torrentList, hash);
|
||||
AddTorrentToStates(torrentList, hash, torrentList.MajorVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -241,7 +267,7 @@ namespace Lantean.QBTMud.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddTorrentToStates(MainData torrentList, string hash)
|
||||
private static void AddTorrentToStates(MainData torrentList, string hash, int version)
|
||||
{
|
||||
var torrent = torrentList.Torrents[hash];
|
||||
|
||||
@@ -271,7 +297,7 @@ namespace Lantean.QBTMud.Services
|
||||
value.AddIfTrue(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
||||
}
|
||||
|
||||
foreach (var status in _statuses)
|
||||
foreach (var status in GetStatuses(version))
|
||||
{
|
||||
torrentList.StatusState[status.ToString()].AddIfTrue(hash, FilterHelper.FilterStatus(torrent, status));
|
||||
}
|
||||
@@ -289,6 +315,25 @@ namespace Lantean.QBTMud.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static Status[] GetStatuses(int version)
|
||||
{
|
||||
if (_statusArray is not null)
|
||||
{
|
||||
return _statusArray;
|
||||
}
|
||||
|
||||
if (version == 5)
|
||||
{
|
||||
_statusArray = Enum.GetValues<Status>().Where(s => s != Status.Paused).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
_statusArray = Enum.GetValues<Status>().Where(s => s != Status.Stopped).ToArray();
|
||||
}
|
||||
|
||||
return _statusArray;
|
||||
}
|
||||
|
||||
private static void UpdateTorrentStates(MainData torrentList, string hash)
|
||||
{
|
||||
var torrent = torrentList.Torrents[hash];
|
||||
@@ -317,7 +362,7 @@ namespace Lantean.QBTMud.Services
|
||||
value.AddIfTrueOrRemove(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
||||
}
|
||||
|
||||
foreach (var status in _statuses)
|
||||
foreach (var status in GetStatuses(torrentList.MajorVersion))
|
||||
{
|
||||
torrentList.StatusState[status.ToString()].AddIfTrueOrRemove(hash, FilterHelper.FilterStatus(torrent, status));
|
||||
}
|
||||
@@ -361,7 +406,7 @@ namespace Lantean.QBTMud.Services
|
||||
categoryState.RemoveIfTrue(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
||||
}
|
||||
|
||||
foreach (var status in _statuses)
|
||||
foreach (var status in GetStatuses(torrentList.MajorVersion))
|
||||
{
|
||||
if (!torrentList.StatusState.TryGetValue(status.ToString(), out var statusState))
|
||||
{
|
||||
@@ -487,6 +532,12 @@ namespace Lantean.QBTMud.Services
|
||||
|
||||
public Torrent CreateTorrent(string hash, QBitTorrentClient.Models.Torrent torrent)
|
||||
{
|
||||
var normalizedTags = torrent.Tags?
|
||||
.Select(NormalizeTag)
|
||||
.Where(static tag => !string.IsNullOrEmpty(tag))
|
||||
.ToList()
|
||||
?? new List<string>();
|
||||
|
||||
return new Torrent(
|
||||
hash,
|
||||
torrent.AddedOn.GetValueOrDefault(),
|
||||
@@ -527,7 +578,7 @@ namespace Lantean.QBTMud.Services
|
||||
torrent.Size.GetValueOrDefault(),
|
||||
torrent.State!,
|
||||
torrent.SuperSeeding.GetValueOrDefault(),
|
||||
torrent.Tags!,
|
||||
normalizedTags,
|
||||
torrent.TimeActive.GetValueOrDefault(),
|
||||
torrent.TotalSize.GetValueOrDefault(),
|
||||
torrent.Tracker!,
|
||||
@@ -540,6 +591,19 @@ namespace Lantean.QBTMud.Services
|
||||
torrent.MaxInactiveSeedingTime.GetValueOrDefault());
|
||||
}
|
||||
|
||||
private static string NormalizeTag(string? tag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tag))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var separatorIndex = tag.IndexOf('\t');
|
||||
var normalized = (separatorIndex >= 0) ? tag[..separatorIndex] : tag;
|
||||
|
||||
return normalized.Trim();
|
||||
}
|
||||
|
||||
private static void UpdateCategory(Category existingCategory, QBitTorrentClient.Models.Category category)
|
||||
{
|
||||
existingCategory.SavePath = category.SavePath ?? existingCategory.SavePath;
|
||||
@@ -588,7 +652,14 @@ namespace Lantean.QBTMud.Services
|
||||
if (torrent.Tags is not null)
|
||||
{
|
||||
existingTorrent.Tags.Clear();
|
||||
existingTorrent.Tags.AddRange(torrent.Tags);
|
||||
foreach (var tag in torrent.Tags)
|
||||
{
|
||||
var normalizedTag = NormalizeTag(tag);
|
||||
if (!string.IsNullOrEmpty(normalizedTag))
|
||||
{
|
||||
existingTorrent.Tags.Add(normalizedTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
existingTorrent.TimeActive = torrent.TimeActive ?? existingTorrent.TimeActive;
|
||||
existingTorrent.TotalSize = torrent.TotalSize ?? existingTorrent.TotalSize;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Lantean.QBTMud.Services
|
||||
{
|
||||
public interface IDataManager
|
||||
{
|
||||
MainData CreateMainData(QBitTorrentClient.Models.MainData mainData);
|
||||
MainData CreateMainData(QBitTorrentClient.Models.MainData mainData, string version);
|
||||
|
||||
Torrent CreateTorrent(string hash, QBitTorrentClient.Models.Torrent torrent);
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap" rel="stylesheet">
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
<link href="./_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="./css/app.css" />
|
||||
<link rel="icon" type="image/png" href="images/qbittorrent32.png" />
|
||||
<link rel="icon" href="images/qbittorrent-tray.svg">
|
||||
<link rel="mask-icon" href="images/qbittorrent-tray.svg" color="#000000">
|
||||
<link rel="apple-touch-icon" href="images/qbittorrent32.png">
|
||||
<link rel="icon" href="./images/qbittorrent-tray.svg">
|
||||
<link rel="mask-icon" href="./images/qbittorrent-tray.svg" color="#000000">
|
||||
<link rel="apple-touch-icon" href="./images/qbittorrent32.png">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -31,10 +31,10 @@
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="js/piecesbar.js"></script>
|
||||
<script src="js/interop.js"></script>
|
||||
<script src="./_framework/blazor.webassembly.js"></script>
|
||||
<script src="./_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="./js/piecesbar.js"></script>
|
||||
<script src="./js/interop.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Lantean.QBitTorrentClient.Models
|
||||
int maxConnecPerTorrent,
|
||||
int maxInactiveSeedingTime,
|
||||
bool maxInactiveSeedingTimeEnabled,
|
||||
int maxRatio,
|
||||
float maxRatio,
|
||||
int maxRatioAct,
|
||||
bool maxRatioEnabled,
|
||||
int maxSeedingTime,
|
||||
@@ -745,7 +745,7 @@ namespace Lantean.QBitTorrentClient.Models
|
||||
public bool MaxInactiveSeedingTimeEnabled { get; }
|
||||
|
||||
[JsonPropertyName("max_ratio")]
|
||||
public int MaxRatio { get; }
|
||||
public float MaxRatio { get; }
|
||||
|
||||
[JsonPropertyName("max_ratio_act")]
|
||||
public int MaxRatioAct { get; }
|
||||
|
||||
@@ -323,7 +323,7 @@ namespace Lantean.QBitTorrentClient.Models
|
||||
public bool? MaxInactiveSeedingTimeEnabled { get; set; }
|
||||
|
||||
[JsonPropertyName("max_ratio")]
|
||||
public int? MaxRatio { get; set; }
|
||||
public float? MaxRatio { get; set; }
|
||||
|
||||
[JsonPropertyName("max_ratio_act")]
|
||||
public int? MaxRatioAct { get; set; }
|
||||
|
||||
11
readme.md
11
readme.md
@@ -20,6 +20,11 @@ qbtmud replicates all core features of the qBittorrent WebUI, including:
|
||||
- **Bandwidth Scheduler** – Schedule bandwidth limits.
|
||||
- **WebUI Access** – Remotely manage torrents through the WebUI.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
For a detailed explanation of these features, refer to the [qBittorrent Options Guide](https://github.com/qbittorrent/qBittorrent/wiki/Explanation-of-Options-in-qBittorrent).
|
||||
|
||||
---
|
||||
@@ -63,11 +68,13 @@ cd qbtmud
|
||||
dotnet restore
|
||||
```
|
||||
|
||||
### 3. Build the Application
|
||||
### 3. Build and Publish the Application
|
||||
```sh
|
||||
dotnet build --configuration Release
|
||||
dotnet publish --configuration Release
|
||||
```
|
||||
|
||||
This will output the Web UI files to `Lantean.QBTMud\bin\Release\net9.0\publish\wwwroot`.
|
||||
|
||||
### 4. Configure qBittorrent to Use qbtmud
|
||||
Follow the same steps as in the **Installation** section to set qbtmud as your WebUI.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user