[REWORK] Changes saving client and channel info
This commit is contained in:
@@ -1,23 +1,19 @@
|
||||
using System.Net;
|
||||
using DotBased.Logging;
|
||||
using DotBased.Monads;
|
||||
using Manager.App.Models.Library;
|
||||
using Manager.Data.Entities.LibraryContext;
|
||||
using Manager.YouTube;
|
||||
using Manager.YouTube.Models.Innertube;
|
||||
|
||||
namespace Manager.App.Services.System;
|
||||
|
||||
public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientService> logger)
|
||||
: ExtendedBackgroundService(nameof(ClientService), "Managing YouTube clients", logger, TimeSpan.FromMinutes(10))
|
||||
{
|
||||
private readonly List<ClientChannel> _loadedClients = [];
|
||||
private CancellationToken _cancellationToken;
|
||||
private readonly YouTubeClientCollection _loadedClients = [];
|
||||
private ILibraryService? _libraryService;
|
||||
|
||||
protected override Task InitializeAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_cancellationToken = stoppingToken;
|
||||
stoppingToken.Register(CancellationRequested);
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
_libraryService = scope.ServiceProvider.GetRequiredService<ILibraryService>();
|
||||
@@ -25,17 +21,79 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override Task ExecuteServiceAsync(CancellationToken stoppingToken)
|
||||
protected override async Task ExecuteServiceAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
LogEvent($"Saving {_loadedClients.Count} loaded client(s)");
|
||||
foreach (var client in _loadedClients)
|
||||
{
|
||||
await SaveClientAsync(client, cancellationToken: stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
private void CancellationRequested()
|
||||
private async void CancellationRequested()
|
||||
{
|
||||
// Clear up
|
||||
foreach (var client in _loadedClients)
|
||||
{
|
||||
await SaveClientAsync(client);
|
||||
client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result> SaveClientAsync(YouTubeClient client, Channel? channelInfo = null, CancellationToken cancellationToken = default)
|
||||
public async Task<Result> AddClientByIdAsync(string id, CancellationToken stoppingToken = default)
|
||||
{
|
||||
if (_libraryService == null)
|
||||
{
|
||||
return ResultError.Fail("Library service is not initialized!.");
|
||||
}
|
||||
|
||||
var clientResult = await _libraryService.GetChannelByIdAsync(id, stoppingToken);
|
||||
if (!clientResult.IsSuccess)
|
||||
{
|
||||
return clientResult;
|
||||
}
|
||||
|
||||
var clientAcc = clientResult.Value.ClientAccount;
|
||||
if (clientAcc == null)
|
||||
{
|
||||
return ResultError.Fail("Client account is not initialized!.");
|
||||
}
|
||||
|
||||
var cookieCollection = new CookieCollection();
|
||||
foreach (var httpCookie in clientAcc.HttpCookies)
|
||||
{
|
||||
var cookie = new Cookie
|
||||
{
|
||||
Name = httpCookie.Name,
|
||||
Value = httpCookie.Value,
|
||||
Domain = httpCookie.Domain,
|
||||
Path = httpCookie.Path,
|
||||
Secure = httpCookie.Secure,
|
||||
HttpOnly = httpCookie.HttpOnly,
|
||||
Expires = httpCookie.ExpiresUtc ?? DateTime.MinValue
|
||||
};
|
||||
cookieCollection.Add(cookie);
|
||||
}
|
||||
var ytClientResult = await YouTubeClient.CreateAsync(cookieCollection, clientAcc.UserAgent ?? "");
|
||||
if (!ytClientResult.IsSuccess)
|
||||
{
|
||||
return ytClientResult;
|
||||
}
|
||||
|
||||
AddClient(ytClientResult.Value);
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
public void AddClient(YouTubeClient client)
|
||||
{
|
||||
if (_loadedClients.Contains(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedClients.Add(client);
|
||||
}
|
||||
|
||||
public async Task<Result> SaveClientAsync(YouTubeClient client, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_libraryService == null)
|
||||
{
|
||||
@@ -48,121 +106,7 @@ public class ClientService(IServiceScopeFactory scopeFactory, ILogger<ClientServ
|
||||
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? channelEntity;
|
||||
try
|
||||
{
|
||||
if (channelResult.IsSuccess)
|
||||
{
|
||||
channelEntity = channelResult.Value;
|
||||
UpdateChannelEntity(client, channelEntity, channelInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
channelEntity = CreateNewChannelFromClient(client, channelInfo);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogEvent("Failed to save client: " + e.Message, LogSeverity.Warning);
|
||||
return ResultError.Error(e);
|
||||
}
|
||||
|
||||
var saveResult = await _libraryService.SaveChannelAsync(channelEntity, cancellationToken);
|
||||
var saveResult = await _libraryService.SaveClientAsync(new ClientAccountEntity { Id = client.Id, UserAgent = client.UserAgent }, cancellationToken);
|
||||
return saveResult;
|
||||
}
|
||||
|
||||
private void UpdateChannelEntity(YouTubeClient client, ChannelEntity entity, Channel? channelInfo)
|
||||
{
|
||||
if (channelInfo != null)
|
||||
{
|
||||
entity.Name = channelInfo.ChannelName;
|
||||
entity.Handle = channelInfo.Handle;
|
||||
entity.Description = channelInfo.Description;
|
||||
}
|
||||
|
||||
var clientAcc = entity.ClientAccount;
|
||||
if (clientAcc != null)
|
||||
{
|
||||
clientAcc.UserAgent = clientAcc.UserAgent;
|
||||
var currentCookies = client.CookieContainer.GetAllCookies();
|
||||
foreach (var cookieEntity in clientAcc.HttpCookies.ToList())
|
||||
{
|
||||
var cookie = currentCookies[cookieEntity.Name];
|
||||
if (cookie == null)
|
||||
{
|
||||
clientAcc.HttpCookies.Remove(cookieEntity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cookie.Domain.Equals(cookieEntity.Domain, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cookieEntity.Value = cookie.Value;
|
||||
cookieEntity.Path = cookie.Path;
|
||||
cookieEntity.Secure = cookie.Secure;
|
||||
cookieEntity.HttpOnly = cookie.HttpOnly;
|
||||
cookieEntity.ExpiresUtc = cookie.Expires == DateTime.MinValue ? null : cookie.Expires;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ChannelEntity CreateNewChannelFromClient(YouTubeClient client, Channel? channelInfo)
|
||||
{
|
||||
if (channelInfo == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(channelInfo), "Channel information is required to store new client/account.");
|
||||
}
|
||||
|
||||
var cookies = new List<HttpCookieEntity>();
|
||||
foreach (var cookieObj in client.CookieContainer.GetAllCookies())
|
||||
{
|
||||
if (cookieObj is not Cookie cookie)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cookieEntity = new HttpCookieEntity
|
||||
{
|
||||
ClientId = client.Id,
|
||||
Name = cookie.Name,
|
||||
Value = cookie.Value,
|
||||
Domain = cookie.Domain,
|
||||
Path = cookie.Path,
|
||||
Secure = cookie.Secure,
|
||||
HttpOnly = cookie.HttpOnly,
|
||||
ExpiresUtc = cookie.Expires == DateTime.MinValue ? null : cookie.Expires
|
||||
};
|
||||
cookies.Add(cookieEntity);
|
||||
}
|
||||
|
||||
var clientAcc = new ClientAccountEntity
|
||||
{
|
||||
Id = client.Id,
|
||||
UserAgent = client.UserAgent,
|
||||
HttpCookies = cookies
|
||||
};
|
||||
|
||||
var channel = new ChannelEntity
|
||||
{
|
||||
Id = channelInfo.Id,
|
||||
Name = channelInfo.ChannelName,
|
||||
Handle = channelInfo.Handle,
|
||||
Description = channelInfo.Description,
|
||||
ClientAccount = clientAcc
|
||||
};
|
||||
return channel;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user