using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Interfaces.Locking; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Interfaces.Trakt; using ErsatzTV.Infrastructure.Data; using LanguageExt; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Unit = LanguageExt.Unit; namespace ErsatzTV.Application.MediaCollections.Commands { public class AddTraktListHandler : TraktCommandBase, IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; private readonly IEntityLocker _entityLocker; public AddTraktListHandler( ITraktApiClient traktApiClient, ISearchRepository searchRepository, ISearchIndex searchIndex, IDbContextFactory dbContextFactory, ILogger logger, IEntityLocker entityLocker) : base(traktApiClient, searchRepository, searchIndex, logger) { _dbContextFactory = dbContextFactory; _entityLocker = entityLocker; } public async Task> Handle(AddTraktList request, CancellationToken cancellationToken) { try { Validation validation = ValidateUrl(request); return await validation.Match( DoAdd, error => Task.FromResult>(error.Join())); } finally { _entityLocker.UnlockTrakt(); } } private static Validation ValidateUrl(AddTraktList request) { const string PATTERN = @"(?:https:\/\/trakt\.tv\/users\/)?([\w\-_]+)\/(?:lists\/)?([\w\-_]+)"; Match match = Regex.Match(request.TraktListUrl, PATTERN); if (match.Success) { string user = match.Groups[1].Value; string list = match.Groups[2].Value; return new Parameters(user, list); } return BaseError.New("Invalid Trakt list url"); } private async Task> DoAdd(Parameters parameters) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); return await TraktApiClient.GetUserList(parameters.User, parameters.List) .BindT(list => SaveList(dbContext, list)) .BindT(list => SaveListItems(dbContext, list)) .BindT(list => MatchListItems(dbContext, list)) .MapT(_ => Unit.Default); // match list items (and update in search index) } private record Parameters(string User, string List); } }