Started on the queue for requests #483 TV Requests with missing information has been completed

pull/687/head
Jamie.Rees 8 years ago
parent 5a5f7f5610
commit 50dec5f530

@ -137,6 +137,8 @@
<Compile Include="StatusChecker\AppveyorArtifactResult.cs" />
<Compile Include="StatusChecker\StatusChecker.cs" />
<Compile Include="StatusChecker\AppveyorBranchResult.cs" />
<Compile Include="TvSender.cs" />
<Compile Include="TvSenderOld.cs" />
<Compile Include="UserIdentity.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UserMapper.cs" />

@ -11,7 +11,7 @@ namespace PlexRequests.Core.Queue
Task DequeueAsync();
IEnumerable<RequestQueue> GetQueue();
Task<IEnumerable<RequestQueue>> GetQueueAsync();
void QueueItem(RequestedModel request, RequestType type, FaultType faultType);
Task QueueItemAsync(RequestedModel request, RequestType type, FaultType faultType);
void QueueItem(RequestedModel request, string id, RequestType type, FaultType faultType);
Task QueueItemAsync(RequestedModel request, string id, RequestType type, FaultType faultType);
}
}

@ -46,14 +46,14 @@ namespace PlexRequests.Core.Queue
private IRepository<RequestQueue> RequestQueue { get; }
public void QueueItem(RequestedModel request, RequestType type, FaultType faultType)
public void QueueItem(RequestedModel request, string id, RequestType type, FaultType faultType)
{
//Ensure there is not a duplicate queued item
var existingItem = RequestQueue.Custom(
connection =>
{
connection.Open();
var result = connection.Query<RequestQueue>("select * from RequestQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = request.ProviderId });
var result = connection.Query<RequestQueue>("select * from RequestQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = id });
return result;
}).FirstOrDefault();
@ -68,19 +68,19 @@ namespace PlexRequests.Core.Queue
{
Type = type,
Content = ByteConverterHelper.ReturnBytes(request),
PrimaryIdentifier = request.ProviderId,
PrimaryIdentifier = id,
FaultType = faultType
};
RequestQueue.Insert(queue);
}
public async Task QueueItemAsync(RequestedModel request, RequestType type, FaultType faultType)
public async Task QueueItemAsync(RequestedModel request, string id, RequestType type, FaultType faultType)
{
//Ensure there is not a duplicate queued item
var existingItem = await RequestQueue.CustomAsync(async connection =>
{
connection.Open();
var result = await connection.QueryAsync<RequestQueue>("select * from RequestQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = request.ProviderId });
var result = await connection.QueryAsync<RequestQueue>("select * from RequestQueue where PrimaryIdentifier = @ProviderId", new { ProviderId = id });
return result;
});
@ -95,7 +95,7 @@ namespace PlexRequests.Core.Queue
{
Type = type,
Content = ByteConverterHelper.ReturnBytes(request),
PrimaryIdentifier = request.ProviderId,
PrimaryIdentifier = id,
FaultType = faultType
};
await RequestQueue.InsertAsync(queue);

@ -42,5 +42,6 @@ namespace PlexRequests.Core.SettingModels
[Obsolete("We use the CRON job now")]
public int RecentlyAdded { get; set; }
public string RecentlyAddedCron { get; set; }
public int FaultQueueHandler { get; set; }
}
}

@ -24,18 +24,19 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NLog;
using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.SickRage;
using PlexRequests.Api.Models.Sonarr;
using PlexRequests.Core.SettingModels;
using PlexRequests.Store;
using System.Linq;
using System.Threading.Tasks;
namespace PlexRequests.UI.Helpers
namespace PlexRequests.Core
{
public class TvSender
{

@ -36,7 +36,7 @@ using PlexRequests.Api.Models.Sonarr;
using PlexRequests.Core.SettingModels;
using PlexRequests.Store;
namespace PlexRequests.UI.Helpers
namespace PlexRequests.Core
{
public class TvSenderOld
{

@ -0,0 +1,214 @@
#region Copyright
// /************************************************************************
// Copyright (c) 2016 Jamie Rees
// File: UserRequestLimitResetter.cs
// Created By: Jamie Rees
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using PlexRequests.Api;
using PlexRequests.Api.Interfaces;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers;
using PlexRequests.Services.Interfaces;
using PlexRequests.Store;
using PlexRequests.Store.Models;
using PlexRequests.Store.Repository;
using Quartz;
namespace PlexRequests.Services.Jobs
{
public class FaultQueueHandler : IJob
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public FaultQueueHandler(IJobRecord record, IRepository<RequestQueue> repo, ISonarrApi sonarrApi,
ISickRageApi srApi,
ISettingsService<SonarrSettings> sonarrSettings, ISettingsService<SickRageSettings> srSettings)
{
Record = record;
Repo = repo;
SonarrApi = sonarrApi;
SrApi = srApi;
SickrageSettings = srSettings;
SonarrSettings = sonarrSettings;
}
private IRepository<RequestQueue> Repo { get; }
private IJobRecord Record { get; }
private ISonarrApi SonarrApi { get; }
private ISickRageApi SrApi { get; }
private ISettingsService<SonarrSettings> SonarrSettings { get; set; }
private ISettingsService<SickRageSettings> SickrageSettings { get; set; }
public void Execute(IJobExecutionContext context)
{
try
{
var faultedRequests = Repo.GetAll().ToList();
var missingInfo = faultedRequests.Where(x => x.FaultType == FaultType.MissingInformation).ToList();
ProcessMissingInformation(missingInfo);
var transientErrors = faultedRequests.Where(x => x.FaultType == FaultType.RequestFault).ToList();
ProcessTransientErrors(transientErrors);
}
catch (Exception e)
{
Log.Error(e);
}
finally
{
Record.Record(JobNames.RequestLimitReset);
}
}
private void ProcessMissingInformation(List<RequestQueue> requests)
{
var sonarrSettings = SonarrSettings.GetSettings();
var sickrageSettings = SickrageSettings.GetSettings();
if (!requests.Any())
{
return;
}
var tv = requests.Where(x => x.Type == RequestType.TvShow);
// TV
var tvApi = new TvMazeApi();
foreach (var t in tv)
{
var providerId = int.Parse(t.PrimaryIdentifier);
var showInfo = tvApi.ShowLookupByTheTvDbId(providerId);
if (showInfo.externals?.thetvdb != null)
{
// We now have the info
var tvModel = ByteConverterHelper.ReturnObject<RequestedModel>(t.Content);
tvModel.ProviderId = showInfo.externals.thetvdb.Value;
var result = ProcessTvShow(tvModel, sonarrSettings, sickrageSettings);
if (!result)
{
// we now have the info but couldn't add it, so add it back into the queue but with a different fault
t.Content = ByteConverterHelper.ReturnBytes(tvModel);
t.FaultType = FaultType.RequestFault;
t.LastRetry = DateTime.UtcNow;
Repo.Update(t);
}
else
{
// Successful, remove from the fault queue
Repo.Delete(t);
}
}
}
}
private bool ProcessTvShow(RequestedModel tvModel, SonarrSettings sonarr, SickRageSettings sickrage)
{
try
{
var sender = new TvSenderOld(SonarrApi, SrApi);
if (sonarr.Enabled)
{
var task = sender.SendToSonarr(sonarr, tvModel, sonarr.QualityProfile);
var a = task.Result;
if (string.IsNullOrEmpty(a?.title))
{
// Couldn't send it
return false;
}
return true;
}
if (sickrage.Enabled)
{
var result = sender.SendToSickRage(sickrage, tvModel);
if (result?.result != "success")
{
// Couldn't send it
return false;
}
return true;
}
return false;
}
catch (Exception e)
{
Log.Error(e);
return false; // It fails so it will get added back into the queue
}
}
private void ProcessTransientErrors(List<RequestQueue> requests)
{
var sonarrSettings = SonarrSettings.GetSettings();
var sickrageSettings = SickrageSettings.GetSettings();
if (!requests.Any())
{
return;
}
var tv = requests.Where(x => x.Type == RequestType.TvShow);
var movie = requests.Where(x => x.Type == RequestType.Movie);
var album = requests.Where(x => x.Type == RequestType.Album);
foreach (var t in tv)
{
var tvModel = ByteConverterHelper.ReturnObject<RequestedModel>(t.Content);
var result = ProcessTvShow(tvModel, sonarrSettings, sickrageSettings);
if (!result)
{
// we now have the info but couldn't add it, so do nothing now.
t.LastRetry = DateTime.UtcNow;
Repo.Update(t);
}
else
{
// Successful, remove from the fault queue
Repo.Delete(t);
}
}
}
}
}

@ -93,6 +93,7 @@
<Compile Include="Jobs\SickRageCacher.cs" />
<Compile Include="Jobs\SonarrCacher.cs" />
<Compile Include="Jobs\Templates\RecentlyAddedTemplate.cs" />
<Compile Include="Jobs\FaultQueueHandler.cs" />
<Compile Include="Jobs\UserRequestLimitResetter.cs" />
<Compile Include="Models\PlexAlbum.cs" />
<Compile Include="Models\PlexEpisodeModel.cs" />

@ -25,6 +25,7 @@
// ************************************************************************/
#endregion
using System;
using Dapper.Contrib.Extensions;
namespace PlexRequests.Store.Models
@ -32,13 +33,14 @@ namespace PlexRequests.Store.Models
[Table("RequestQueue")]
public class RequestQueue : Entity
{
public int PrimaryIdentifier { get; set; }
public string PrimaryIdentifier { get; set; }
public RequestType Type { get; set; }
public byte[] Content { get; set; }
public FaultType FaultType { get; set; }
public DateTime? LastRetry { get; set; }
}
public enum FaultType

@ -136,10 +136,11 @@ CREATE INDEX IF NOT EXISTS PlexEpisodes_ProviderId ON PlexEpisodes (ProviderId);
CREATE TABLE IF NOT EXISTS RequestQueue
(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
PrimaryIdentifier INTEGER NOT NULL,
PrimaryIdentifier VARCHAR(100) NOT NULL,
Type INTEGER NOT NULL,
FaultType INTEGER NOT NULL,
Content BLOB NOT NULL
Content BLOB NOT NULL,
LastRetry VARCHAR(100)
);
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id);

@ -35,6 +35,7 @@ using NUnit.Framework;
using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.Sonarr;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels;
using PlexRequests.Store;
using PlexRequests.UI.Helpers;
@ -146,32 +147,6 @@ namespace PlexRequests.UI.Tests
true, It.IsAny<bool>()), Times.Once);
}
[Test]
public async Task RequestEpisodesWithExistingSeriesTest()
{
var episodesReturned = new List<SonarrEpisodes>
{
new SonarrEpisodes {episodeNumber = 1, seasonNumber = 2, monitored = false, id=22}
};
SonarrMock.Setup(x => x.GetEpisodes(It.IsAny<string>(), It.IsAny<string>(),
It.IsAny<Uri>())).Returns(episodesReturned);
SonarrMock.Setup(x => x.GetEpisode("22", It.IsAny<string>(), It.IsAny<Uri>())).Returns(new SonarrEpisode {id=22});
Sender = new TvSender(SonarrMock.Object, SickrageMock.Object);
var model = new RequestedModel
{
Episodes = new List<EpisodesModel> { new EpisodesModel { EpisodeNumber = 1, SeasonNumber = 2 } }
};
var series = new Series();
await Sender.RequestEpisodesWithExistingSeries(model, series, GetSonarrSettings());
SonarrMock.Verify(x => x.UpdateEpisode(It.Is<SonarrEpisode>(e => e.monitored), It.IsAny<string>(), It.IsAny<Uri>()));
SonarrMock.Verify(x => x.GetEpisode("22", It.IsAny<string>(), It.IsAny<Uri>()),Times.Once);
SonarrMock.Verify(x => x.SearchForEpisodes(It.IsAny<int[]>(), It.IsAny<string>(), It.IsAny<Uri>()), Times.Once);
}
private SonarrSettings GetSonarrSettings()
{

@ -69,11 +69,10 @@ namespace PlexRequests.UI.Jobs
JobBuilder.Create<StoreBackup>().WithIdentity("StoreBackup", "Database").Build(),
JobBuilder.Create<StoreCleanup>().WithIdentity("StoreCleanup", "Database").Build(),
JobBuilder.Create<UserRequestLimitResetter>().WithIdentity("UserRequestLimiter", "Request").Build(),
JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build()
JobBuilder.Create<RecentlyAdded>().WithIdentity("RecentlyAddedModel", "Email").Build(),
JobBuilder.Create<FaultQueueHandler>().WithIdentity("FaultQueueHandler", "Fault").Build(),
};
jobs.AddRange(jobList);
return jobs;
@ -151,7 +150,10 @@ namespace PlexRequests.UI.Jobs
{
s.UserRequestLimitResetter = 12;
}
if (s.FaultQueueHandler == 0)
{
s.FaultQueueHandler = 6;
}
var triggers = new List<ITrigger>();
@ -221,6 +223,13 @@ namespace PlexRequests.UI.Jobs
.WithSimpleSchedule(x => x.WithIntervalInHours(2).RepeatForever())
.Build();
var fault =
TriggerBuilder.Create()
.WithIdentity("FaultQueueHandler", "Fault")
.StartAt(DateBuilder.FutureDate(10, IntervalUnit.Minute))
.WithSimpleSchedule(x => x.WithIntervalInHours(s.FaultQueueHandler).RepeatForever())
.Build();
triggers.Add(rencentlyAdded);
triggers.Add(plexAvailabilityChecker);
triggers.Add(srCacher);
@ -230,6 +239,7 @@ namespace PlexRequests.UI.Jobs
triggers.Add(storeCleanup);
triggers.Add(userRequestLimiter);
triggers.Add(plexEpCacher);
triggers.Add(fault);
return triggers;
}

@ -589,7 +589,7 @@ namespace PlexRequests.UI.Modules
catch (Exception e)
{
Log.Fatal(e);
await FaultQueue.QueueItemAsync(model, RequestType.Movie, FaultType.RequestFault);
await FaultQueue.QueueItemAsync(model, movieInfo.Id.ToString(), RequestType.Movie, FaultType.RequestFault);
await NotificationService.Publish(new NotificationModel
{
@ -690,26 +690,6 @@ namespace PlexRequests.UI.Modules
TvDbId = showId.ToString()
};
if (showInfo.externals?.thetvdb == null)
{
await FaultQueue.QueueItemAsync(model, RequestType.TvShow, FaultType.MissingInformation);
await NotificationService.Publish(new NotificationModel
{
DateTime = DateTime.Now,
User = Username,
RequestType = RequestType.TvShow,
Title = model.Title,
NotificationType = NotificationType.ItemAddedToFaultQueue
});
return Response.AsJson(new JsonResponseModel
{
Result = true,
Message = $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}"
});
}
model.ProviderId = showInfo.externals?.thetvdb ?? 0;
var seasonsList = new List<int>();
switch (seasons)
{
@ -876,6 +856,26 @@ namespace PlexRequests.UI.Modules
});
}
if (showInfo.externals?.thetvdb == null)
{
await FaultQueue.QueueItemAsync(model, showInfo.id.ToString(), RequestType.TvShow, FaultType.MissingInformation);
await NotificationService.Publish(new NotificationModel
{
DateTime = DateTime.Now,
User = Username,
RequestType = RequestType.TvShow,
Title = model.Title,
NotificationType = NotificationType.ItemAddedToFaultQueue
});
return Response.AsJson(new JsonResponseModel
{
Result = true,
Message = $"{fullShowName} {Resources.UI.Search_SuccessfullyAdded}"
});
}
model.ProviderId = showInfo.externals?.thetvdb ?? 0;
try
{
if (ShouldAutoApprove(RequestType.TvShow, settings))
@ -936,7 +936,7 @@ namespace PlexRequests.UI.Modules
}
catch (Exception e)
{
await FaultQueue.QueueItemAsync(model, RequestType.TvShow, FaultType.RequestFault);
await FaultQueue.QueueItemAsync(model, showInfo.id.ToString(), RequestType.TvShow, FaultType.RequestFault);
await NotificationService.Publish(new NotificationModel
{
DateTime = DateTime.Now,
@ -1102,7 +1102,7 @@ namespace PlexRequests.UI.Modules
catch (Exception e)
{
Log.Error(e);
await FaultQueue.QueueItemAsync(model, RequestType.Movie, FaultType.RequestFault);
await FaultQueue.QueueItemAsync(model, albumInfo.id, RequestType.Movie, FaultType.RequestFault);
await NotificationService.Publish(new NotificationModel
{

@ -216,8 +216,6 @@
<Compile Include="Helpers\SecurityExtensions.cs" />
<Compile Include="Helpers\ServiceLocator.cs" />
<Compile Include="Helpers\Themes.cs" />
<Compile Include="Helpers\TvSender.cs" />
<Compile Include="Helpers\TvSenderOld.cs" />
<Compile Include="Helpers\ValidationHelper.cs" />
<Compile Include="Jobs\CustomJobFactory.cs" />
<Compile Include="Jobs\Scheduler.cs" />

Loading…
Cancel
Save