Ombi/src/Ombi.Core/Engine/TvRequestEngine.cs
2017-06-14 16:30:06 +01:00

332 lines
No EOL
12 KiB
C#

using AutoMapper;
using Hangfire;
using Ombi.Api.TvMaze;
using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search;
using Ombi.Core.Rules;
using Ombi.Helpers;
using Ombi.Notifications;
using Ombi.Notifications.Models;
using Ombi.Store.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Notifications;
using Ombi.Store;
namespace Ombi.Core.Engine
{
public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine
{
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
INotificationService notificationService, IMapper map,
IRuleEvaluator rule) : base(user, requestService, rule)
{
TvApi = tvApi;
NotificationService = notificationService;
Mapper = map;
}
private INotificationService NotificationService { get; }
private ITvMazeApi TvApi { get; }
private IMapper Mapper { get; }
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
{
var showInfo = await TvApi.ShowLookupByTheTvDbId(tv.Id);
DateTime.TryParse(showInfo.premiered, out DateTime firstAir);
// For some reason the poster path is always http
var posterPath = showInfo.image?.medium.Replace("http:", "https:");
var tvRequests = new List<SeasonRequestModel>();
// Only have the TV requests we actually requested and not everything
foreach (var season in tv.SeasonRequests)
{
for (int i = season.Episodes.Count - 1; i >= 0; i--)
{
if (!season.Episodes[i].Requested)
{
season.Episodes.RemoveAt(i); // Remove the episode since it's not requested
}
}
if (season.Episodes.Any())
{
tvRequests.Add(season);
}
}
var childRequest = new ChildTvRequest
{
Id = tv.Id,
Type = RequestType.TvShow,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUser = Username,
Issues = IssueState.None,
ProviderId = tv.Id,
RequestAll = tv.RequestAll,
SeasonRequests = tvRequests
};
var model = new TvRequestModel
{
Id = tv.Id,
Type = RequestType.TvShow,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
Approved = false,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id.ToString(),
ProviderId = tv.Id
};
model.ChildRequests.Add(childRequest);
//if (childRequest.SeasonRequests.Any())
//{
// var episodes = await TvApi.EpisodeLookup(showInfo.id);
// foreach (var e in episodes)
// {
// var season = childRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
// season?.Episodes.Add(new EpisodesRequested
// {
// Url = e.url,
// Title = e.name,
// AirDate = DateTime.Parse(e.airstamp),
// EpisodeNumber = e.number
// });
// }
//}
if (tv.LatestSeason)
{
var latest = showInfo.Season.OrderBy(x => x.SeasonNumber).FirstOrDefault();
foreach (var modelSeasonRequest in childRequest.SeasonRequests)
{
if (modelSeasonRequest.SeasonNumber == latest.SeasonNumber)
{
foreach (var episodesRequested in modelSeasonRequest.Episodes)
{
episodesRequested.Requested = true;
}
}
}
}
if (tv.FirstSeason)
{
var first = showInfo.Season.OrderByDescending(x => x.SeasonNumber).FirstOrDefault();
foreach (var modelSeasonRequest in childRequest.SeasonRequests)
{
if (modelSeasonRequest.SeasonNumber == first.SeasonNumber)
{
foreach (var episodesRequested in modelSeasonRequest.Episodes)
{
episodesRequested.Requested = true;
}
}
}
}
var ruleResults = RunRequestRules(model).ToList();
if (ruleResults.Any(x => !x.Success))
{
return new RequestEngineResult
{
ErrorMessage = ruleResults.FirstOrDefault(x => !string.IsNullOrEmpty(x.Message)).Message
};
}
var existingRequest = await TvRequestService.CheckRequestAsync(model.Id);
if (existingRequest != null)
{
return await AddExistingRequest(model, existingRequest);
}
// This is a new request
return await AddRequest(model);
}
public async Task<IEnumerable<TvRequestModel>> GetRequests(int count, int position)
{
var allRequests = await TvRequestService.GetAllAsync(count, position);
return allRequests;
}
public async Task<IEnumerable<TvRequestModel>> GetRequests()
{
var allRequests = await TvRequestService.GetAllAsync();
return allRequests;
}
public async Task<IEnumerable<TvRequestModel>> SearchTvRequest(string search)
{
var allRequests = await TvRequestService.GetAllAsync();
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase));
return results;
}
public async Task<TvRequestModel> UpdateTvRequest(TvRequestModel request)
{
var allRequests = await TvRequestService.GetAllAsync();
var results = allRequests.FirstOrDefault(x => x.Id == request.Id);
results = Mapper.Map<TvRequestModel>(request);
// TODO need to check if we need to approve any child requests since they may have updated
var model = TvRequestService.UpdateRequest(results);
return model;
}
public async Task RemoveTvRequest(int requestId)
{
await TvRequestService.DeleteRequestAsync(requestId);
}
private async Task<RequestEngineResult> AddExistingRequest(TvRequestModel newRequest,
TvRequestModel existingRequest)
{
var child = newRequest.ChildRequests.FirstOrDefault(); // There will only be 1
var episodeDiff = new List<SeasonRequestModel>();
foreach (var existingChild in existingRequest.ChildRequests)
{
var difference = GetListDifferences(existingChild.SeasonRequests, child.SeasonRequests).ToList();
if (difference.Any())
episodeDiff = difference;
}
if (episodeDiff.Any())
child.SeasonRequests = episodeDiff;
existingRequest.ChildRequests.AddRange(newRequest.ChildRequests);
TvRequestService.UpdateRequest(existingRequest);
if (newRequest.Approved) // The auto approve rule
{
// TODO Auto Approval Code
}
return await AfterRequest(newRequest);
}
private IEnumerable<SeasonRequestModel> GetListDifferences(List<SeasonRequestModel> existing,
List<SeasonRequestModel> request)
{
var requestsToRemove = new List<SeasonRequestModel>();
foreach (var r in request)
{
// Do we have an existing season?
var existingSeason = existing.FirstOrDefault(x => x.SeasonNumber == r.SeasonNumber);
if (existingSeason == null)
{
continue;
}
// Compare the episodes
for (var i = r.Episodes.Count - 1; i >= 0; i--)
{
var existingEpisode = existingSeason.Episodes.FirstOrDefault(x => x.EpisodeNumber == r.Episodes[i].EpisodeNumber);
if (existingEpisode == null)
{
// we are fine, we have not yet requested this
}
else
{
// We already have this request
r.Episodes.RemoveAt(i);
}
}
if (!r.Episodes.Any())
{
requestsToRemove.Add(r);
}
}
foreach (var remove in requestsToRemove)
{
request.Remove(remove);
}
return request;
}
private async Task<RequestEngineResult> AddRequest(TvRequestModel model)
{
await TvRequestService.AddRequestAsync(model);
return await AfterRequest(model);
}
private async Task<RequestEngineResult> AfterRequest(TvRequestModel model)
{
if (ShouldSendNotification(model.Type))
{
var n = new NotificationOptions();
n.Title = model.Title;
n.RequestedUser = Username;
n.DateTime = DateTime.Now;
n.NotificationType = NotificationType.NewRequest;
n.RequestType = model.Type;
n.ImgSrc = model.PosterPath;
BackgroundJob.Enqueue(() =>
NotificationService.Publish(n).Wait()
);
}
//var limit = await RequestLimitRepo.GetAllAsync();
//var usersLimit = limit.FirstOrDefault(x => x.Username == Username && x.RequestType == model.Type);
//if (usersLimit == null)
//{
// await RequestLimitRepo.InsertAsync(new RequestLimit
// {
// Username = Username,
// RequestType = model.Type,
// FirstRequestDate = DateTime.UtcNow,
// RequestCount = 1
// });
//}
//else
//{
// usersLimit.RequestCount++;
// await RequestLimitRepo.UpdateAsync(usersLimit);
//}
return new RequestEngineResult { RequestAdded = true };
}
public async Task<IEnumerable<TvRequestModel>> GetApprovedRequests()
{
var allRequests = await TvRequestService.GetAllAsync();
return allRequests.Where(x => x.Approved && !x.Available);
}
public async Task<IEnumerable<TvRequestModel>> GetNewRequests()
{
var allRequests = await TvRequestService.GetAllAsync();
return allRequests.Where(x => !x.Approved && !x.Available);
}
public async Task<IEnumerable<TvRequestModel>> GetAvailableRequests()
{
var allRequests = await TvRequestService.GetAllAsync();
return allRequests.Where(x => x.Available);
}
}
}