167 lines
5.6 KiB
C#
167 lines
5.6 KiB
C#
using System.Net;
|
|
using DotBased.Logging;
|
|
using DotBased.Monads;
|
|
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<YouTubeClient> _clients = [];
|
|
private CancellationToken _cancellationToken;
|
|
private ILibraryService? _libraryService;
|
|
|
|
protected override Task InitializeAsync(CancellationToken stoppingToken)
|
|
{
|
|
_cancellationToken = stoppingToken;
|
|
stoppingToken.Register(CancellationRequested);
|
|
using var scope = scopeFactory.CreateScope();
|
|
_libraryService = scope.ServiceProvider.GetRequiredService<ILibraryService>();
|
|
LogEvent("Initializing service...");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected override Task ExecuteServiceAsync(CancellationToken stoppingToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void CancellationRequested()
|
|
{
|
|
// Clear up
|
|
}
|
|
|
|
public async Task<Result> SaveClientAsync(YouTubeClient client, Channel? channelInfo = null, CancellationToken cancellationToken = default)
|
|
{
|
|
if (_libraryService == null)
|
|
{
|
|
return ResultError.Fail("Library service is not initialized!.");
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(client.Id))
|
|
{
|
|
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? 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);
|
|
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;
|
|
}
|
|
} |