diff --git a/Manager.App/Components/Pages/Accounts.razor b/Manager.App/Components/Pages/Accounts.razor index f693a25..0fa1d66 100644 --- a/Manager.App/Components/Pages/Accounts.razor +++ b/Manager.App/Components/Pages/Accounts.razor @@ -1,4 +1,5 @@ @page "/Accounts" +@using Manager.App.Controllers @using Manager.App.Models.Settings @using Manager.App.Services.System @using Microsoft.Extensions.Options @@ -26,14 +27,18 @@ AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"> + Name Handle ID + Cookies - @context.Channel?.Name - @context.Channel?.Handle + + @context.Name + @context.Handle @context.Id + @context.HasCookies No channels found diff --git a/Manager.App/Components/Pages/Accounts.razor.cs b/Manager.App/Components/Pages/Accounts.razor.cs index f46ab89..7c25e66 100644 --- a/Manager.App/Components/Pages/Accounts.razor.cs +++ b/Manager.App/Components/Pages/Accounts.razor.cs @@ -1,6 +1,5 @@ using Manager.App.Components.Dialogs; using Manager.App.Models.Library; -using Manager.Data.Entities.LibraryContext; using Microsoft.AspNetCore.Components; using MudBlazor; @@ -8,14 +7,14 @@ namespace Manager.App.Components.Pages; public partial class Accounts : ComponentBase { - private MudTable? _table; + private MudTable? _table; private readonly DialogOptions _dialogOptions = new() { BackdropClick = false, CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.ExtraLarge }; private string _search = ""; - private async Task> ServerReload(TableState state, CancellationToken token) + private async Task> ServerReload(TableState state, CancellationToken token) { var results = await LibraryService.GetAccountsAsync(_search, state.Page * state.PageSize, state.PageSize, token); - return !results.IsSuccess ? new TableData() : new TableData() { Items = results.Value, TotalItems = results.Total }; + return !results.IsSuccess ? new TableData() : new TableData { Items = results.Value, TotalItems = results.Total }; } private void OnSearch(string text) diff --git a/Manager.App/Components/Pages/Channels.razor b/Manager.App/Components/Pages/Channels.razor index 38d7ab9..e60b2bf 100644 --- a/Manager.App/Components/Pages/Channels.razor +++ b/Manager.App/Components/Pages/Channels.razor @@ -1,4 +1,5 @@ @page "/Channels" +@using Manager.App.Controllers @inject ILibraryService LibraryService @@ -13,11 +14,13 @@ AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"> + Name Handle Channel id + @context.Name @context.Handle @context.Id diff --git a/Manager.App/Components/Pages/Channels.razor.cs b/Manager.App/Components/Pages/Channels.razor.cs index bc47493..3705465 100644 --- a/Manager.App/Components/Pages/Channels.razor.cs +++ b/Manager.App/Components/Pages/Channels.razor.cs @@ -1,4 +1,4 @@ -using Manager.Data.Entities.LibraryContext; +using Manager.App.Models.Library; using Microsoft.AspNetCore.Components; using MudBlazor; @@ -6,13 +6,13 @@ namespace Manager.App.Components.Pages; public partial class Channels : ComponentBase { - private MudTable? _table; + private MudTable? _table; private string _search = ""; - private async Task> ServerReload(TableState state, CancellationToken token) + private async Task> ServerReload(TableState state, CancellationToken token) { var results = await LibraryService.GetChannelsAsync(_search, state.Page * state.PageSize, state.PageSize, token); - return !results.IsSuccess ? new TableData() : new TableData { Items = results.Value, TotalItems = results.Total }; + return !results.IsSuccess ? new TableData() : new TableData { Items = results.Value, TotalItems = results.Total }; } private void OnSearch(string text) diff --git a/Manager.App/Controllers/FileController.cs b/Manager.App/Controllers/FileController.cs index 3a81545..a2b154f 100644 --- a/Manager.App/Controllers/FileController.cs +++ b/Manager.App/Controllers/FileController.cs @@ -7,6 +7,8 @@ namespace Manager.App.Controllers; [Route("api/v1/[controller]")] public class FileController(ILibraryService libraryService) : ControllerBase { + public static string CreateProvideUrl(Guid? id) => id == null ? "" : $"/api/v1/file/provide?id={id}"; + [HttpGet("provide")] public async Task ProvideFile([FromQuery(Name = "id")] Guid id, CancellationToken cancellationToken) { diff --git a/Manager.App/Services/ILibraryService.cs b/Manager.App/Services/ILibraryService.cs index f1ad57e..b4f5038 100644 --- a/Manager.App/Services/ILibraryService.cs +++ b/Manager.App/Services/ILibraryService.cs @@ -14,6 +14,6 @@ public interface ILibraryService public Task> GetChannelByIdAsync(string id, CancellationToken cancellationToken = default); public Task SaveChannelAsync(InnertubeChannel innertubeChannel, CancellationToken cancellationToken = default); public Task> GetLibraryInfoAsync(CancellationToken cancellationToken = default); - public Task> GetAccountsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default); - public Task> GetChannelsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default); + public Task> GetAccountsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default); + public Task> GetChannelsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/Manager.App/Services/LibraryService.cs b/Manager.App/Services/LibraryService.cs index a42b006..50df9ba 100644 --- a/Manager.App/Services/LibraryService.cs +++ b/Manager.App/Services/LibraryService.cs @@ -150,7 +150,7 @@ public class LibraryService : ILibraryService return ResultError.Fail($"File with id {id} not found."); } - var fs = new FileStream(Path.Combine(_libraryDirectory.FullName, file.RelativePath), FileMode.Open, FileAccess.Read, FileShare.Read); + var fs = new FileStream(Path.Combine(_libraryDirectory.FullName, LibraryConstants.Directories.SubDirChannels, file.RelativePath), FileMode.Open, FileAccess.Read, FileShare.Read); return new LibraryFile { DataStream = fs, SizeBytes = file.SizeBytes, FileName = file.OriginalFileName ?? file.Id.ToString(), MimeType = file.MimeType ?? MediaTypeNames.Application.Octet }; } catch (Exception e) @@ -268,7 +268,7 @@ public class LibraryService : ILibraryService } } - public async Task> GetAccountsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default) + public async Task> GetAccountsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default) { if (total == 0) { @@ -278,16 +278,16 @@ public class LibraryService : ILibraryService try { await using var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken); - var accounts = context.ClientAccounts + var accountsQuery = context.ClientAccounts .Include(ca => ca.Channel) .Include(ca => ca.HttpCookies) - .OrderByDescending(ca => ca.Id); - var totalAccounts = accounts.Count(); + .OrderByDescending(ca => ca.Id).AsQueryable(); + var totalAccounts = accountsQuery.Count(); if (!string.IsNullOrWhiteSpace(search) && totalAccounts != 0) { var normalizedSearch = $"%{search.ToLower()}%"; - var searched = accounts + accountsQuery = accountsQuery .Where(ca => EF.Functions.Like( ( @@ -298,11 +298,20 @@ public class LibraryService : ILibraryService normalizedSearch ) ); - totalAccounts = searched.Count(); - accounts = searched.OrderByDescending(ca => ca.Id); + totalAccounts = accountsQuery.Count(); } - return new ListResultReturn(totalAccounts == 0 ? [] : accounts.Skip(offset).Take(total).ToList(), totalAccounts); + var accountViews = accountsQuery.Skip(offset).Take(total).Select(account => new AccountListView + { + Id = account.Id, + Name = account.Channel != null ? account.Channel.Name : "", + Handle = account.Channel != null ? account.Channel.Handle : "", + HasCookies = account.HttpCookies.Count != 0, + AvatarFileId = account.Files == null ? null + : account.Files.Where(f => f.FileType == LibraryConstants.FileTypes.ChannelAvatar).OrderBy(x => x.Id).Select(f => f.Id).FirstOrDefault() + }); + + return new ListResultReturn(totalAccounts == 0 ? [] : accountViews.ToList(), totalAccounts); } catch (Exception e) { @@ -310,21 +319,26 @@ public class LibraryService : ILibraryService } } - public async Task> GetChannelsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default) + public async Task> GetChannelsAsync(string? search, int offset = 0, int total = 20, CancellationToken cancellationToken = default) { + if (total == 0) + { + total = 20; + } + try { await using var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken); - var orderedAccounts = context.Channels.OrderBy(x => x.Id); - var totalChannels = orderedAccounts.Count(); - if (!string.IsNullOrWhiteSpace(search) && orderedAccounts.Any()) + var channelQuery = context.Channels.OrderByDescending(c => c.Id).AsQueryable(); + + var totalChannels = channelQuery.Count(); + if (!string.IsNullOrWhiteSpace(search) && totalChannels != 0) { var normalizedSearch = $"%{search.ToLower()}%"; - var searched = orderedAccounts + channelQuery = channelQuery .Where(ca => - EF.Functions.Like( - ( + EF.Functions.Like(( ca.Id.ToString() + " " + ca.Name + " " + ca.Handle @@ -332,11 +346,19 @@ public class LibraryService : ILibraryService normalizedSearch ) ); - totalChannels = searched.Count(); - orderedAccounts = searched.OrderByDescending(ca => ca.Id); + totalChannels = channelQuery.Count(); } + + var channelViews = channelQuery.Skip(offset).Take(total).Select(channel => new ChannelListView + { + Id = channel.Id, + Name = channel.Name, + Handle = channel.Handle, + AvatarFileId = channel.Files == null ? null + : channel.Files.Where(f => f.FileType == LibraryConstants.FileTypes.ChannelAvatar).OrderBy(x => x.Id).Select(f => f.Id).FirstOrDefault() + }); - return new ListResultReturn(totalChannels == 0 ? [] : orderedAccounts.Skip(offset).Take(total).ToList(), totalChannels); + return new ListResultReturn(totalChannels == 0 ? [] : channelViews.ToList(), totalChannels); } catch (Exception e) { @@ -366,6 +388,6 @@ public class LibraryService : ILibraryService } _logger.LogError(exception, "Service error"); - return ResultError.Fail("Failed to get library information"); + return ResultError.Error(exception); } } \ No newline at end of file