mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-10-28 18:43:34 +00:00
Compare commits
18 Commits
1.0.0
...
feature/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc51505e3f | ||
|
|
1cf9f97187 | ||
|
|
4f9129fd46 | ||
|
|
9a9d2c2ee2 | ||
|
|
736bc46745 | ||
|
|
23ae19c4c7 | ||
|
|
603470eb30 | ||
|
|
27c2406340 | ||
|
|
4578dcc11f | ||
|
|
3215fa3936 | ||
|
|
78e62f31d0 | ||
|
|
e23842fcb0 | ||
|
|
411c7f87cc | ||
|
|
4098f8f5a9 | ||
|
|
12f81c5978 | ||
|
|
717738d720 | ||
|
|
885c34c8cf | ||
|
|
ef3c68a6aa |
@@ -4,24 +4,20 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentAssertions" Version="7.1.0" AllowedVersions="[5.0.0,7.*.*)" />
|
<PackageReference Include="AwesomeAssertions" Version="9.2.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||||
<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="System.Text.RegularExpressions" Version="4.3.1" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Lantean.QBTMud.Test
|
|||||||
Test2(a => a.Name);
|
Test2(a => a.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Test2(Expression<Func<TestClass, object>> expr)
|
private void Test2(Expression<Func<TestClass, object?>> expr)
|
||||||
{
|
{
|
||||||
var body = expr.Body;
|
var body = expr.Body;
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ namespace Lantean.QBTMud.Test
|
|||||||
|
|
||||||
var l = Expression.Lambda<Func<TestClass, object>>(convertExpression, expression);
|
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 x = l.Compile();
|
||||||
var res = (long)x(new TestClass { Name = "Name", Value = 12 });
|
var res = (long)x(new TestClass { Name = "Name", Value = 12 });
|
||||||
@@ -58,9 +58,9 @@ namespace Lantean.QBTMud.Test
|
|||||||
|
|
||||||
public class TestClass
|
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; }
|
public long Value { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
20
Lantean.QBTMud/Components/Dialogs/SearchPluginsDialog.razor
Normal file
20
Lantean.QBTMud/Components/Dialogs/SearchPluginsDialog.razor
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<MudDialog>
|
||||||
|
<DialogContent>
|
||||||
|
<MudGrid>
|
||||||
|
<MudItem xs="12">
|
||||||
|
<MudList T="string">
|
||||||
|
<MudListItem Icon="@Icons.Material.Filled.Add" IconColor="Color.Info" OnClick="AddCategory">Add</MudListItem>
|
||||||
|
<MudListItem Icon="@Icons.Material.Filled.Remove" IconColor="Color.Error" OnClick="RemoveCategory">Remove</MudListItem>
|
||||||
|
<MudDivider />
|
||||||
|
@foreach (var plugin in Plugins)
|
||||||
|
{
|
||||||
|
var pluginRef = plugin;
|
||||||
|
<MudListItem Icon="@GetIcon(pluginRef.FullName)" IconColor="Color.Default" OnClick="@(e => SetPlugin(pluginRef))">@pluginRef.Name</MudListItem>
|
||||||
|
}
|
||||||
|
</MudList>
|
||||||
|
</MudItem>
|
||||||
|
</MudGrid>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using Lantean.QBitTorrentClient;
|
||||||
|
using Lantean.QBitTorrentClient.Models;
|
||||||
|
using Lantean.QBTMud.Helpers;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MudBlazor;
|
||||||
|
|
||||||
|
namespace Lantean.QBTMud.Components.Dialogs
|
||||||
|
{
|
||||||
|
public partial class SearchPluginsDialog
|
||||||
|
{
|
||||||
|
[Inject]
|
||||||
|
protected IApiClient ApiClient { get; set; } = default!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
protected IDialogService DialogService { get; set; } = default!;
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
IMudDialogInstance MudDialog { get; set; } = default!;
|
||||||
|
|
||||||
|
protected HashSet<SearchPlugin> Plugins { get; set; } = [];
|
||||||
|
|
||||||
|
protected IList<string> TorrentCategories { get; private set; } = [];
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
Plugins = [.. (await ApiClient.GetSearchPlugins())];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string GetIcon(string tag)
|
||||||
|
{
|
||||||
|
return Icons.Material.Filled.PlusOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task SetPlugin(QBitTorrentClient.Models.SearchPlugin plugin)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task AddCategory()
|
||||||
|
{
|
||||||
|
var addedCategoy = await DialogService.InvokeAddCategoryDialog(ApiClient);
|
||||||
|
if (addedCategoy is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ApiClient.SetTorrentCategory(addedCategoy, Hashes);
|
||||||
|
Plugins.Add(addedCategoy);
|
||||||
|
await GetTorrentCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task RemoveCategory()
|
||||||
|
{
|
||||||
|
await ApiClient.RemoveTorrentCategory(Hashes);
|
||||||
|
await GetTorrentCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Task CloseDialog()
|
||||||
|
{
|
||||||
|
MudDialog.Close();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Cancel()
|
||||||
|
{
|
||||||
|
MudDialog.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,10 +12,7 @@ namespace Lantean.QBTMud.Components
|
|||||||
{
|
{
|
||||||
public partial class TorrentActions : IAsyncDisposable
|
public partial class TorrentActions : IAsyncDisposable
|
||||||
{
|
{
|
||||||
private const int _defaultVersion = 5;
|
|
||||||
|
|
||||||
private bool _disposedValue;
|
private bool _disposedValue;
|
||||||
private int? _version;
|
|
||||||
|
|
||||||
private List<UIAction>? _actions;
|
private List<UIAction>? _actions;
|
||||||
|
|
||||||
@@ -74,30 +71,7 @@ namespace Lantean.QBTMud.Components
|
|||||||
|
|
||||||
protected bool OverlayVisible { get; set; }
|
protected bool OverlayVisible { get; set; }
|
||||||
|
|
||||||
protected int MajorVersion
|
protected int MajorVersion => VersionHelper.GetMajorVersion(Version);
|
||||||
{
|
|
||||||
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 override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
@@ -441,7 +415,7 @@ namespace Lantean.QBTMud.Components
|
|||||||
thereAreFirstLastPiecePrio = true;
|
thereAreFirstLastPiecePrio = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (torrent.Progress > 0.999999) // not downloaded
|
if (torrent.Progress < 0.999999) // not downloaded
|
||||||
{
|
{
|
||||||
allAreDownloaded = false;
|
allAreDownloaded = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -435,5 +435,22 @@ namespace Lantean.QBTMud.Helpers
|
|||||||
|
|
||||||
await dialogService.ShowAsync<SubMenuDialog>(parent.Text, parameters, FormDialogOptions);
|
await dialogService.ShowAsync<SubMenuDialog>(parent.Text, parameters, FormDialogOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<QBitTorrentClient.Models.SearchPlugin?> ShowSearchPluginsDialog(this IDialogService dialogService)
|
||||||
|
{
|
||||||
|
var parameters = new DialogParameters
|
||||||
|
{
|
||||||
|
{ nameof(SearchPluginsDialog.Hashes), "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await dialogService.ShowAsync<SearchPluginsDialog>("Search Plugins", parameters, FormDialogOptions);
|
||||||
|
var dialogResult = await result.Result;
|
||||||
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (QBitTorrentClient.Models.SearchPlugin)dialogResult.Data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ namespace Lantean.QBTMud.Helpers
|
|||||||
{
|
{
|
||||||
time = TimeSpan.FromSeconds(seconds.Value);
|
time = TimeSpan.FromSeconds(seconds.Value);
|
||||||
}
|
}
|
||||||
catch (OverflowException)
|
catch
|
||||||
{
|
{
|
||||||
return "∞";
|
return "∞";
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ namespace Lantean.QBTMud.Helpers
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return Size(size);
|
return Size(size, prefix, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,13 +12,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||||
<PackageReference Include="ByteSize" Version="2.1.2" />
|
<PackageReference Include="ByteSize" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.10" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.1" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.10" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.10" />
|
||||||
<PackageReference Include="MudBlazor" Version="8.2.0" />
|
<PackageReference Include="MudBlazor" Version="8.13.0" />
|
||||||
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0" />
|
<PackageReference Include="MudBlazor.ThemeManager" Version="3.0.0" />
|
||||||
<!-- added to fix vuln in dependency -->
|
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace Lantean.QBTMud.Layout
|
|||||||
Preferences = await ApiClient.GetApplicationPreferences();
|
Preferences = await ApiClient.GetApplicationPreferences();
|
||||||
Version = await ApiClient.GetApplicationVersion();
|
Version = await ApiClient.GetApplicationVersion();
|
||||||
var data = await ApiClient.GetMainData(_requestId);
|
var data = await ApiClient.GetMainData(_requestId);
|
||||||
MainData = DataManager.CreateMainData(data);
|
MainData = DataManager.CreateMainData(data, Version);
|
||||||
|
|
||||||
_requestId = data.ResponseId;
|
_requestId = data.ResponseId;
|
||||||
_refreshInterval = MainData.ServerState.RefreshInterval;
|
_refreshInterval = MainData.ServerState.RefreshInterval;
|
||||||
@@ -128,7 +128,7 @@ namespace Lantean.QBTMud.Layout
|
|||||||
|
|
||||||
if (MainData is null || data.FullUpdate)
|
if (MainData is null || data.FullUpdate)
|
||||||
{
|
{
|
||||||
MainData = DataManager.CreateMainData(data);
|
MainData = DataManager.CreateMainData(data, Version);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ namespace Lantean.QBTMud.Layout
|
|||||||
|
|
||||||
private bool _disposedValue;
|
private bool _disposedValue;
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected NavigationManager NavigationManager { get; set; } = default!;
|
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private IBrowserViewportService BrowserViewportService { get; set; } = default!;
|
private IBrowserViewportService BrowserViewportService { get; set; } = default!;
|
||||||
|
|
||||||
@@ -78,13 +75,13 @@ namespace Lantean.QBTMud.Layout
|
|||||||
{
|
{
|
||||||
IsDarkMode = isDarkMode.Value;
|
IsDarkMode = isDarkMode.Value;
|
||||||
}
|
}
|
||||||
await MudThemeProvider.WatchSystemPreference(OnSystemPreferenceChanged);
|
await MudThemeProvider.WatchSystemDarkModeAsync(OnSystemDarkModeChanged);
|
||||||
await BrowserViewportService.SubscribeAsync(this, fireImmediately: true);
|
await BrowserViewportService.SubscribeAsync(this, fireImmediately: true);
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task OnSystemPreferenceChanged(bool value)
|
protected Task OnSystemDarkModeChanged(bool value)
|
||||||
{
|
{
|
||||||
IsDarkMode = value;
|
IsDarkMode = value;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
Dictionary<string, HashSet<string>> tagState,
|
Dictionary<string, HashSet<string>> tagState,
|
||||||
Dictionary<string, HashSet<string>> categoriesState,
|
Dictionary<string, HashSet<string>> categoriesState,
|
||||||
Dictionary<string, HashSet<string>> statusState,
|
Dictionary<string, HashSet<string>> statusState,
|
||||||
Dictionary<string, HashSet<string>> trackersState)
|
Dictionary<string, HashSet<string>> trackersState,
|
||||||
|
int majorVersion)
|
||||||
{
|
{
|
||||||
Torrents = torrents.ToDictionary();
|
Torrents = torrents.ToDictionary();
|
||||||
Tags = tags.ToHashSet();
|
Tags = tags.ToHashSet();
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
CategoriesState = categoriesState;
|
CategoriesState = categoriesState;
|
||||||
StatusState = statusState;
|
StatusState = statusState;
|
||||||
TrackersState = trackersState;
|
TrackersState = trackersState;
|
||||||
|
MajorVersion = majorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, Torrent> Torrents { get; }
|
public Dictionary<string, Torrent> Torrents { get; }
|
||||||
@@ -36,5 +38,6 @@
|
|||||||
public Dictionary<string, HashSet<string>> TrackersState { get; }
|
public Dictionary<string, HashSet<string>> TrackersState { get; }
|
||||||
public string? SelectedTorrentHash { get; set; }
|
public string? SelectedTorrentHash { get; set; }
|
||||||
public bool LostConnection { get; set; }
|
public bool LostConnection { get; set; }
|
||||||
|
public int MajorVersion { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
Completed,
|
Completed,
|
||||||
Resumed,
|
Resumed,
|
||||||
Paused,
|
Paused,
|
||||||
|
Stopped,
|
||||||
Active,
|
Active,
|
||||||
Inactive,
|
Inactive,
|
||||||
Stalled,
|
Stalled,
|
||||||
@@ -15,6 +16,6 @@
|
|||||||
StalledDownloading,
|
StalledDownloading,
|
||||||
Checking,
|
Checking,
|
||||||
Errored,
|
Errored,
|
||||||
Stopped
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudText Class="pl-5 no-wrap">Search</MudText>
|
<MudText Class="pl-5 no-wrap">Search</MudText>
|
||||||
|
<MudDivider Vertical="true" />
|
||||||
|
<MudIconButton Icon="@Icons.Material.Outlined.Settings" OnClick="ShowSearchPlugins" title="Search plugins" />
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|
||||||
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4">
|
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4">
|
||||||
|
|||||||
@@ -150,6 +150,11 @@ namespace Lantean.QBTMud.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task ShowSearchPlugins()
|
||||||
|
{
|
||||||
|
await DialogService.ShowSearchPluginsDialog();
|
||||||
|
}
|
||||||
|
|
||||||
protected IEnumerable<ColumnDefinition<QBitTorrentClient.Models.SearchResult>> Columns => ColumnsDefinitions;
|
protected IEnumerable<ColumnDefinition<QBitTorrentClient.Models.SearchResult>> Columns => ColumnsDefinitions;
|
||||||
|
|
||||||
public static List<ColumnDefinition<QBitTorrentClient.Models.SearchResult>> ColumnsDefinitions { get; } =
|
public static List<ColumnDefinition<QBitTorrentClient.Models.SearchResult>> ColumnsDefinitions { get; } =
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
{
|
{
|
||||||
public class DataManager : IDataManager
|
public class DataManager : IDataManager
|
||||||
{
|
{
|
||||||
private static readonly Status[] _statuses = Enum.GetValues<Status>();
|
private static Status[]? _statusArray = null;
|
||||||
|
|
||||||
public PeerList CreatePeerList(QBitTorrentClient.Models.TorrentPeers torrentPeers)
|
public PeerList CreatePeerList(QBitTorrentClient.Models.TorrentPeers torrentPeers)
|
||||||
{
|
{
|
||||||
@@ -25,8 +25,9 @@ namespace Lantean.QBTMud.Services
|
|||||||
return peerList;
|
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);
|
var torrents = new Dictionary<string, Torrent>(mainData.Torrents?.Count ?? 0);
|
||||||
if (mainData.Torrents is not null)
|
if (mainData.Torrents is not null)
|
||||||
{
|
{
|
||||||
@@ -87,8 +88,9 @@ namespace Lantean.QBTMud.Services
|
|||||||
categoriesState.Add(category, torrents.Values.Where(t => FilterHelper.FilterCategory(t, category, serverState.UseSubcategories)).ToHashesHashSet());
|
categoriesState.Add(category, torrents.Values.Where(t => FilterHelper.FilterCategory(t, category, serverState.UseSubcategories)).ToHashesHashSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
var statusState = new Dictionary<string, HashSet<string>>(_statuses.Length + 2);
|
var statuses = GetStatuses(majorVersion).ToArray();
|
||||||
foreach (var status in _statuses)
|
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());
|
statusState.Add(status.ToString(), torrents.Values.Where(t => FilterHelper.FilterStatus(t, status)).ToHashesHashSet());
|
||||||
}
|
}
|
||||||
@@ -101,7 +103,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
trackersState.Add(tracker, torrents.Values.Where(t => FilterHelper.FilterTracker(t, tracker)).ToHashesHashSet());
|
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;
|
return torrentList;
|
||||||
}
|
}
|
||||||
@@ -206,7 +208,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
{
|
{
|
||||||
foreach (var (url, hashes) in mainData.Trackers)
|
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);
|
torrentList.Trackers.Add(url, hashes);
|
||||||
}
|
}
|
||||||
@@ -225,7 +227,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
{
|
{
|
||||||
var newTorrent = CreateTorrent(hash, torrent);
|
var newTorrent = CreateTorrent(hash, torrent);
|
||||||
torrentList.Torrents.Add(hash, newTorrent);
|
torrentList.Torrents.Add(hash, newTorrent);
|
||||||
AddTorrentToStates(torrentList, hash);
|
AddTorrentToStates(torrentList, hash, torrentList.MajorVersion);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -241,7 +243,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];
|
var torrent = torrentList.Torrents[hash];
|
||||||
|
|
||||||
@@ -271,7 +273,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
value.AddIfTrue(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
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));
|
torrentList.StatusState[status.ToString()].AddIfTrue(hash, FilterHelper.FilterStatus(torrent, status));
|
||||||
}
|
}
|
||||||
@@ -289,6 +291,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)
|
private static void UpdateTorrentStates(MainData torrentList, string hash)
|
||||||
{
|
{
|
||||||
var torrent = torrentList.Torrents[hash];
|
var torrent = torrentList.Torrents[hash];
|
||||||
@@ -317,7 +338,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
value.AddIfTrueOrRemove(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
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));
|
torrentList.StatusState[status.ToString()].AddIfTrueOrRemove(hash, FilterHelper.FilterStatus(torrent, status));
|
||||||
}
|
}
|
||||||
@@ -361,7 +382,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
categoryState.RemoveIfTrue(hash, FilterHelper.FilterCategory(torrent, category, torrentList.ServerState.UseSubcategories));
|
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))
|
if (!torrentList.StatusState.TryGetValue(status.ToString(), out var statusState))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace Lantean.QBTMud.Services
|
|||||||
{
|
{
|
||||||
public interface IDataManager
|
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);
|
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.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<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="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 href="./_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||||
<link rel="stylesheet" href="css/app.css" />
|
<link rel="stylesheet" href="./css/app.css" />
|
||||||
<link rel="icon" type="image/png" href="images/qbittorrent32.png" />
|
<link rel="icon" type="image/png" href="images/qbittorrent32.png" />
|
||||||
<link rel="icon" href="images/qbittorrent-tray.svg">
|
<link rel="icon" href="./images/qbittorrent-tray.svg">
|
||||||
<link rel="mask-icon" href="images/qbittorrent-tray.svg" color="#000000">
|
<link rel="mask-icon" href="./images/qbittorrent-tray.svg" color="#000000">
|
||||||
<link rel="apple-touch-icon" href="images/qbittorrent32.png">
|
<link rel="apple-touch-icon" href="./images/qbittorrent32.png">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
<a href="" class="reload">Reload</a>
|
<a href="" class="reload">Reload</a>
|
||||||
<a class="dismiss">🗙</a>
|
<a class="dismiss">🗙</a>
|
||||||
</div>
|
</div>
|
||||||
<script src="_framework/blazor.webassembly.js"></script>
|
<script src="./_framework/blazor.webassembly.js"></script>
|
||||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
<script src="./_content/MudBlazor/MudBlazor.min.js"></script>
|
||||||
<script src="js/piecesbar.js"></script>
|
<script src="./js/piecesbar.js"></script>
|
||||||
<script src="js/interop.js"></script>
|
<script src="./js/interop.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
92
readme.md
92
readme.md
@@ -1,14 +1,82 @@
|
|||||||
# qbt-mud
|
# qbtmud
|
||||||
|
|
||||||
## To-Do
|
qbtmud is a drop-in replacement for qBittorrent's default WebUI, implementing all of its functionality with a modern and user-friendly interface.
|
||||||
|
|
||||||
- Rename multiple files dialog
|
## Features
|
||||||
- ~~RSS feeds and dialogs~~
|
|
||||||
- ~~About~~
|
qbtmud replicates all core features of the qBittorrent WebUI, including:
|
||||||
- ~~Context menu for files list/trackers list/peers list~~
|
|
||||||
- ~~Tag management page~~
|
- **Torrent Management** – Add, remove, and control torrents.
|
||||||
- ~~Category management page~~
|
- **Tracker Control** – View and manage trackers.
|
||||||
- ~~Update all tables to use DynamicTable~~
|
- **Peer Management** – Monitor and manage peers connected to torrents.
|
||||||
- ~~Log~~
|
- **File Prioritization** – Select and prioritize specific files within a torrent.
|
||||||
- ~~Blocks~~
|
- **Speed Limits** – Set global and per-torrent speed limits.
|
||||||
- ~~Search~~
|
- **RSS Integration** – Subscribe to RSS feeds for automated torrent downloads.
|
||||||
|
- **Search Functionality** – Integrated torrent search.
|
||||||
|
- **Sequential Downloading** – Download files in order for media streaming.
|
||||||
|
- **Super Seeding Mode** – Efficiently distribute torrents as an initial seeder.
|
||||||
|
- **IP Filtering** – Improve security by filtering specific IP addresses.
|
||||||
|
- **IPv6 Support** – Full support for IPv6 networks.
|
||||||
|
- **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).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install qbtmud without building from source:
|
||||||
|
|
||||||
|
### 1. Download the Latest Release
|
||||||
|
- Go to the [qbtmud Releases](https://github.com/lantean-code/qbtmud/releases) page.
|
||||||
|
- Download the latest release archive for your operating system.
|
||||||
|
|
||||||
|
### 2. Extract the Archive
|
||||||
|
- Extract the contents of the downloaded archive to a directory of your choice.
|
||||||
|
|
||||||
|
### 3. Configure qBittorrent to Use qbtmud
|
||||||
|
- Open qBittorrent and navigate to `Tools` > `Options` > `Web UI`.
|
||||||
|
- Enable the option **"Use alternative WebUI"**.
|
||||||
|
- Set the **"Root Folder"** to the directory where you extracted qbtmud.
|
||||||
|
- Click **OK** to save the settings.
|
||||||
|
|
||||||
|
### 4. Access qbtmud
|
||||||
|
- Open your web browser and go to `http://localhost:8080` (or the port configured in qBittorrent).
|
||||||
|
|
||||||
|
For more detailed instructions, refer to the [Alternate WebUI Usage Guide](https://github.com/qbittorrent/qBittorrent/wiki/Alternate-WebUI-usage).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building from Source
|
||||||
|
|
||||||
|
To build qbtmud from source, you need to have the **.NET 9.0 SDK** installed on your system.
|
||||||
|
|
||||||
|
### 1. Clone the Repository
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/lantean-code/qbtmud.git
|
||||||
|
cd qbtmud
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Restore Dependencies
|
||||||
|
```sh
|
||||||
|
dotnet restore
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Build the Application
|
||||||
|
```sh
|
||||||
|
dotnet build --configuration Release
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Configure qBittorrent to Use qbtmud
|
||||||
|
Follow the same steps as in the **Installation** section to set qbtmud as your WebUI.
|
||||||
|
|
||||||
|
### 5. Run qbtmud
|
||||||
|
Navigate to the directory containing the built files and run the application using the appropriate command for your OS.
|
||||||
|
|
||||||
|
By following these steps, you can set up qbtmud to manage your qBittorrent server with an improved web interface, offering better functionality and usability.
|
||||||
|
|||||||
Reference in New Issue
Block a user