[CHANGE] Library service, db migrations, ui blazor

This commit is contained in:
max
2025-08-31 20:11:03 +02:00
parent aeb9adf930
commit 98fe4b9391
19 changed files with 1206 additions and 18 deletions

View File

@@ -0,0 +1,23 @@
<MudOverlay Absolute="Absolute" DarkBackground LockScroll @bind-Visible="Visible" ZIndex="ZIndex">
<MudStack AlignItems="AlignItems.Center">
<MudProgressCircular Indeterminate/>
<MudText>@Message</MudText>
@if (CancellationTokenSource != null)
{
<MudButton OnClick="() => CancellationTokenSource.Cancel()" Disabled="CancellationTokenSource.IsCancellationRequested">Cancel operation</MudButton>
}
</MudStack>
</MudOverlay>
@code {
[Parameter]
public bool Visible { get; set; }
[Parameter]
public string Message { get; set; } = "Loading...";
[Parameter]
public bool Absolute { get; set; }
[Parameter]
public int ZIndex { get; set; } = 9999;
[Parameter]
public CancellationTokenSource? CancellationTokenSource { get; set; }
}

View File

@@ -16,5 +16,7 @@
</MudTooltip>
}
</MudAppBar>
@Body
<div style="margin: 20px">
@Body
</div>
</CascadingValue>

View File

@@ -1,9 +1,9 @@
@inherits LayoutComponentBase
<MudThemeProvider @ref="@_themeProvider" IsDarkModeChanged="@OnDarkThemeChanged" Theme="@_mudTheme" IsDarkMode="@DarkTheme"/>
<MudPopoverProvider />
<MudDialogProvider/>
<MudSnackbarProvider/>
<MudPopoverProvider @rendermode="InteractiveServer"/>
<MudDialogProvider @rendermode="InteractiveServer"/>
<MudSnackbarProvider @rendermode="InteractiveServer"/>
<CascadingValue Value="this">
<MudLayout>

View File

@@ -0,0 +1,6 @@
@page "/Accounts"
@code {
}

View File

@@ -0,0 +1,7 @@
using Microsoft.AspNetCore.Components;
namespace Manager.App.Components.Pages;
public partial class Accounts : ComponentBase
{
}

View File

@@ -0,0 +1,40 @@
@page "/Library"
@inject ISnackbar Snackbar
@inject ILibraryService LibraryService
<PageTitle>Library information</PageTitle>
<ForcedLoadingOverlay Visible="_loading" CancellationTokenSource="@_cancellationTokenSource"/>
@if (_libraryInformation != null)
{
<MudSimpleTable Bordered Dense Elevation="0" Outlined Square Hover>
<tbody>
<tr>
<td>Library path:</td>
<td>@_libraryInformation.LibraryPath</td>
</tr>
<tr>
<td>Created at (UTC):</td>
<td>@_libraryInformation.CreatedAtUtc</td>
</tr>
<tr>
<td>Last modified (UTC):</td>
<td>@_libraryInformation.LastModifiedUtc</td>
</tr>
<tr>
<td>Library size:</td>
<td>@Suffix.BytesToSizeSuffix(_libraryInformation.TotalSizeBytes)</td>
</tr>
<tr>
<td>Total media:</td>
<td>@_libraryInformation.TotalMedia</td>
</tr>
<tr>
<td>Total channels:</td>
<td>@_libraryInformation.TotalChannels</td>
</tr>
</tbody>
</MudSimpleTable>
}

View File

@@ -0,0 +1,36 @@
using Manager.App.Models.Library;
using MudBlazor;
namespace Manager.App.Components.Pages;
public partial class Library
{
private LibraryInformation? _libraryInformation;
private bool _loading;
private CancellationTokenSource _cancellationTokenSource = new();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
}
_loading = true;
await InvokeAsync(StateHasChanged);
var result = await LibraryService.GetLibraryInfoAsync(_cancellationTokenSource.Token);
if (result is { IsSuccess: true, Value: not null })
{
_libraryInformation = result.Value;
}
else
{
Snackbar.Add($"Failed to get library info. Error: {result.Error?.Description}", Severity.Error);
}
_loading = false;
await InvokeAsync(StateHasChanged);
}
}
}

View File

@@ -6,8 +6,11 @@
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using DotBased.Utilities
@using Manager.App
@using Manager.App.Components
@using Manager.App.Components.Application
@using Manager.App.Services
@* MudBlazor *@
@using MudBlazor

View File

@@ -10,7 +10,11 @@
<PackageReference Include="DotBased" Version="1.0.0" />
<PackageReference Include="DotBased.Logging.MEL" Version="1.0.0" />
<PackageReference Include="DotBased.Logging.Serilog" Version="1.0.0" />
<PackageReference Include="MudBlazor" Version="8.10.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.19">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MudBlazor" Version="8.11.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
</ItemGroup>
@@ -26,4 +30,8 @@
<ProjectReference Include="..\Manager.YouTube\Manager.YouTube.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Logs\Debug\" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,9 @@
using DotBased.Monads;
using Manager.App.Models.Library;
namespace Manager.App.Services;
public interface ILibraryService
{
public Task<Result<LibraryInformation>> GetLibraryInfoAsync(CancellationToken cancellationToken = default);
}

View File

@@ -21,14 +21,51 @@ public class LibraryService : ILibraryService
_logger = logger;
_librarySettings = librarySettings.Value;
_dbContextFactory = contextFactory;
_libraryDirectory = Directory.CreateDirectory(Path.Combine(_librarySettings.Path, SubDirMedia));
_libraryDirectory = Directory.CreateDirectory(Path.Combine(_librarySettings.Path, SubDirChannels));
_libraryDirectory = Directory.CreateDirectory(_librarySettings.Path);
logger.LogDebug("Working dir for library: {LibraryWorkingDir}", _libraryDirectory.FullName);
Directory.CreateDirectory(Path.Combine(_librarySettings.Path, SubDirMedia));
Directory.CreateDirectory(Path.Combine(_librarySettings.Path, SubDirChannels));
}
public async Task<Result<LibraryInformation>> GetLibraryInfoAsync()
public async Task<Result<LibraryInformation>> GetLibraryInfoAsync(CancellationToken cancellationToken = default)
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
//TODO: Get library info
return ResultError.Fail("Not implemented!");
try
{
await using var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
var libInfo = new LibraryInformation
{
LibraryPath = _libraryDirectory.FullName,
CreatedAtUtc = _libraryDirectory.CreationTimeUtc,
LastModifiedUtc = _libraryDirectory.LastWriteTimeUtc,
TotalChannels = await context.Channels.CountAsync(cancellationToken: cancellationToken),
TotalMedia = await context.Media.CountAsync(cancellationToken: cancellationToken),
TotalSizeBytes = GetDirectorySize(_libraryDirectory)
};
return libInfo;
}
catch (Exception e)
{
if (e is OperationCanceledException)
{
return ResultError.Fail("Library service operation cancelled");
}
_logger.LogError(e, "Failed to get library information");
return ResultError.Fail("Failed to get library information");
}
}
private long GetDirectorySize(DirectoryInfo dir)
{
try
{
var size = dir.EnumerateFiles("", SearchOption.AllDirectories).Select(f => f.Length).Sum();
return size;
}
catch (Exception e)
{
_logger.LogError(e, "Error while getting directory size.");
throw;
}
}
}