[CHANGE] Fixed auditing, storing images from account import
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<MudTable ServerData="ServerReload">
|
||||
<MudTable @ref="@_table" ServerData="ServerReload">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Channels</MudText>
|
||||
</ToolBarContent>
|
||||
|
@@ -9,10 +9,11 @@ namespace Manager.App.Components.Pages;
|
||||
public partial class Channels : ComponentBase
|
||||
{
|
||||
private readonly DialogOptions _dialogOptions = new() { BackdropClick = false, CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.ExtraLarge };
|
||||
private MudTable<ChannelEntity>? _table;
|
||||
|
||||
private async Task<TableData<ChannelEntity>> ServerReload(TableState state, CancellationToken token)
|
||||
{
|
||||
var results = await LibraryService.GetChannelAccountsAsync(state.Page * state.PageSize, state.PageSize, token);
|
||||
var results = await LibraryService.GetChannelAccountsAsync(state.PageSize, state.Page * state.PageSize, token);
|
||||
return !results.IsSuccess ? new TableData<ChannelEntity>() : new TableData<ChannelEntity> { Items = results.Value, TotalItems = results.Total };
|
||||
}
|
||||
|
||||
@@ -44,6 +45,9 @@ public partial class Channels : ComponentBase
|
||||
Snackbar.Add($"Client {clientPrep.Channel?.Handle ?? clientPrep.YouTubeClient.Id} saved!", Severity.Success);
|
||||
}
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
if (_table != null)
|
||||
{
|
||||
await _table.ReloadServerData();
|
||||
}
|
||||
}
|
||||
}
|
18
Manager.App/Constants/LibraryConstants.cs
Normal file
18
Manager.App/Constants/LibraryConstants.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Manager.App.Constants;
|
||||
|
||||
public static class LibraryConstants
|
||||
{
|
||||
public static class Directories
|
||||
{
|
||||
public const string SubDirMedia = "Media";
|
||||
public const string SubDirChannels = "Channels";
|
||||
}
|
||||
|
||||
public static class FileTypes
|
||||
{
|
||||
public const string ChannelAvatar = "channel/avatar";
|
||||
public const string ChannelBanner = "channel/banner";
|
||||
public const string VideoThumbnail = "video/thumbnail";
|
||||
public const string VideoCaption = "video/caption";
|
||||
}
|
||||
}
|
@@ -2,11 +2,13 @@ using DotBased.Monads;
|
||||
using Manager.App.Models.Library;
|
||||
using Manager.App.Models.System;
|
||||
using Manager.Data.Entities.LibraryContext;
|
||||
using Manager.YouTube.Models.Innertube;
|
||||
|
||||
namespace Manager.App.Services;
|
||||
|
||||
public interface ILibraryService
|
||||
{
|
||||
public Task<Result> FetchChannelImagesAsync(Channel channel);
|
||||
public Task<Result<ChannelEntity>> GetChannelByIdAsync(string id, CancellationToken cancellationToken = default);
|
||||
public Task<Result> SaveChannelAsync(ChannelEntity channel, CancellationToken cancellationToken = default);
|
||||
public Task<Result<LibraryInformation>> GetLibraryInfoAsync(CancellationToken cancellationToken = default);
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using DotBased.Monads;
|
||||
using Manager.App.Constants;
|
||||
using Manager.App.Models.Library;
|
||||
using Manager.App.Models.Settings;
|
||||
using Manager.App.Models.System;
|
||||
using Manager.Data.Contexts;
|
||||
using Manager.Data.Entities.LibraryContext;
|
||||
using Manager.YouTube;
|
||||
using Manager.YouTube.Models.Innertube;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@@ -15,8 +18,7 @@ public class LibraryService : ILibraryService
|
||||
private readonly LibrarySettings _librarySettings;
|
||||
private readonly IDbContextFactory<LibraryDbContext> _dbContextFactory;
|
||||
private readonly DirectoryInfo _libraryDirectory;
|
||||
private const string SubDirMedia = "Media";
|
||||
private const string SubDirChannels = "Channels";
|
||||
|
||||
|
||||
public LibraryService(ILogger<LibraryService> logger, IOptions<LibrarySettings> librarySettings, IDbContextFactory<LibraryDbContext> contextFactory)
|
||||
{
|
||||
@@ -25,8 +27,76 @@ public class LibraryService : ILibraryService
|
||||
_dbContextFactory = contextFactory;
|
||||
_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));
|
||||
Directory.CreateDirectory(Path.Combine(_librarySettings.Path, LibraryConstants.Directories.SubDirMedia));
|
||||
Directory.CreateDirectory(Path.Combine(_librarySettings.Path, LibraryConstants.Directories.SubDirChannels));
|
||||
}
|
||||
|
||||
public async Task<Result> FetchChannelImagesAsync(Channel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
|
||||
await AddWebImagesAsync(context, channel.AvatarImages, channel.Id, "avatars", LibraryConstants.FileTypes.ChannelAvatar, LibraryConstants.Directories.SubDirChannels);
|
||||
await AddWebImagesAsync(context, channel.BannerImages, channel.Id, "banners", LibraryConstants.FileTypes.ChannelBanner, LibraryConstants.Directories.SubDirChannels);
|
||||
|
||||
if (!context.ChangeTracker.HasChanges())
|
||||
{
|
||||
_logger.LogInformation("No changes detected. Skipping.");
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ResultError.Error(e);
|
||||
}
|
||||
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
private async Task AddWebImagesAsync(LibraryDbContext context, List<WebImage> images, string foreignKey, string libSubDir, string fileType, string subDir)
|
||||
{
|
||||
foreach (var image in images)
|
||||
{
|
||||
if (context.Files.Any(f => image.Url.Equals(f.OriginalUrl, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var downloadResult = await NetworkService.DownloadBytesAsync(new HttpRequestMessage(HttpMethod.Get, image.Url));
|
||||
if (!downloadResult.IsSuccess)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var download = downloadResult.Value;
|
||||
|
||||
var fileId = Guid.NewGuid();
|
||||
var fileName = download.FileName ?? $"{fileId}.{download.ContentType?.Split('/').Last() ?? "unknown"}";
|
||||
var relativePath = Path.Combine(foreignKey, libSubDir, $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}_{fileName}");
|
||||
var savePath = Path.Combine(_libraryDirectory.FullName, subDir, relativePath);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(savePath) ?? savePath);
|
||||
await using var fileStream = File.Create(savePath);
|
||||
await fileStream.WriteAsync(download.Data.AsMemory(0, download.Data.Length));
|
||||
|
||||
var file = new FileEntity
|
||||
{
|
||||
Id = fileId,
|
||||
OriginalUrl = image.Url,
|
||||
OriginalFileName = download.FileName,
|
||||
ForeignKey = foreignKey,
|
||||
FileType = fileType,
|
||||
RelativePath = relativePath.Replace('\\', '/'),
|
||||
MimeType = download.ContentType,
|
||||
SizeBytes = download.ContentLength,
|
||||
Height = image.Height,
|
||||
Width = image.Width
|
||||
};
|
||||
|
||||
await context.Files.AddAsync(file);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<ChannelEntity>> GetChannelByIdAsync(string id, CancellationToken cancellationToken = default)
|
||||
@@ -68,7 +138,7 @@ public class LibraryService : ILibraryService
|
||||
}
|
||||
|
||||
var changed = await context.SaveChangesAsync(cancellationToken);
|
||||
return changed <= 0 ? Result.Success() : ResultError.Fail("Failed to save channel!");
|
||||
return changed <= 0 ? ResultError.Fail("Failed to save channel!") : Result.Success();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@@ -46,20 +46,29 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
LogEvent("Failed to store client no ID!", LogSeverity.Warning);
|
||||
return ResultError.Fail("Client does not have an ID, cannot save to library database!");
|
||||
}
|
||||
|
||||
if (channelInfo != null)
|
||||
{
|
||||
var imagesResult = await _libraryService.FetchChannelImagesAsync(channelInfo);
|
||||
if (!imagesResult.IsSuccess)
|
||||
{
|
||||
logger.LogWarning("Failed to fetch channel images!");
|
||||
}
|
||||
}
|
||||
|
||||
var channelResult = await _libraryService.GetChannelByIdAsync(client.Id, cancellationToken);
|
||||
|
||||
ChannelEntity? channel;
|
||||
ChannelEntity? channelEntity;
|
||||
try
|
||||
{
|
||||
if (channelResult.IsSuccess)
|
||||
{
|
||||
channel = channelResult.Value;
|
||||
UpdateChannelEntity(client, channel, channelInfo);
|
||||
channelEntity = channelResult.Value;
|
||||
UpdateChannelEntity(client, channelEntity, channelInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
channel = CreateNewChannelFromClient(client, channelInfo);
|
||||
channelEntity = CreateNewChannelFromClient(client, channelInfo);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -68,7 +77,7 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
return ResultError.Error(e);
|
||||
}
|
||||
|
||||
var saveResult = await _libraryService.SaveChannelAsync(channel, cancellationToken);
|
||||
var saveResult = await _libraryService.SaveChannelAsync(channelEntity, cancellationToken);
|
||||
return saveResult;
|
||||
}
|
||||
|
||||
@@ -113,7 +122,7 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
{
|
||||
if (channelInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(channelInfo), "Channel information required to store new client/account.");
|
||||
throw new ArgumentNullException(nameof(channelInfo), "Channel information is required to store new client/account.");
|
||||
}
|
||||
|
||||
var cookies = new List<HttpCookieEntity>();
|
||||
@@ -147,7 +156,7 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
|
||||
var channel = new ChannelEntity
|
||||
{
|
||||
Id = client.Id,
|
||||
Id = channelInfo.Id,
|
||||
Name = channelInfo.ChannelName,
|
||||
Handle = channelInfo.Handle,
|
||||
Description = channelInfo.Description,
|
||||
@@ -155,14 +164,4 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
};
|
||||
return channel;
|
||||
}
|
||||
|
||||
/*public async Task<Result<YouTubeClient>> LoadClientByIdAsync(string id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return ResultError.Fail("Client ID is empty!");
|
||||
}
|
||||
|
||||
return ResultError.Fail("Not implemented");
|
||||
}*/
|
||||
}
|
Reference in New Issue
Block a user