mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-11 15:56:05 -07:00
#254 Removed the cache, we are now storing the plex information into the database.
There is a big structure change around this, also increased the default check time to be in hours.
This commit is contained in:
parent
af1c93620f
commit
2608e53399
29 changed files with 479 additions and 170 deletions
|
@ -34,7 +34,6 @@ using NLog;
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
using PlexRequests.Api.Models.Plex;
|
using PlexRequests.Api.Models.Plex;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
using PlexRequests.Helpers.Exceptions;
|
|
||||||
|
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ namespace PlexRequests.Api
|
||||||
request.AddJsonBody(userModel);
|
request.AddJsonBody(userModel);
|
||||||
|
|
||||||
var obj = RetryHandler.Execute<PlexAuthentication>(() => Api.Execute<PlexAuthentication> (request, new Uri(SignInUri)),
|
var obj = RetryHandler.Execute<PlexAuthentication>(() => Api.Execute<PlexAuthentication> (request, new Uri(SignInUri)),
|
||||||
(exception, timespan) => Log.Error (exception, "Exception when calling SignIn for Plex, Retrying {0}", timespan), null);
|
(exception, timespan) => Log.Error (exception, "Exception when calling SignIn for Plex, Retrying {0}", timespan));
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace PlexRequests.Core.SettingModels
|
||||||
StoreBackup = 24;
|
StoreBackup = 24;
|
||||||
StoreCleanup = 24;
|
StoreCleanup = 24;
|
||||||
UserRequestLimitResetter = 12;
|
UserRequestLimitResetter = 12;
|
||||||
PlexEpisodeCacher = 20;
|
PlexEpisodeCacher = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int PlexAvailabilityChecker { get; set; }
|
public int PlexAvailabilityChecker { get; set; }
|
||||||
|
|
|
@ -79,6 +79,8 @@
|
||||||
<Compile Include="AssemblyHelperTests.cs" />
|
<Compile Include="AssemblyHelperTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="PlexHelperTests.cs" />
|
<Compile Include="PlexHelperTests.cs" />
|
||||||
|
<Compile Include="TypeHelperTests.cs" />
|
||||||
|
<Compile Include="StringHelperTests.cs" />
|
||||||
<Compile Include="UriHelperTests.cs" />
|
<Compile Include="UriHelperTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -86,10 +88,18 @@
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PlexRequests.Core\PlexRequests.Core.csproj">
|
||||||
|
<Project>{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}</Project>
|
||||||
|
<Name>PlexRequests.Core</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\PlexRequests.Helpers\PlexRequests.Helpers.csproj">
|
<ProjectReference Include="..\PlexRequests.Helpers\PlexRequests.Helpers.csproj">
|
||||||
<Project>{1252336d-42a3-482a-804c-836e60173dfa}</Project>
|
<Project>{1252336d-42a3-482a-804c-836e60173dfa}</Project>
|
||||||
<Name>PlexRequests.Helpers</Name>
|
<Name>PlexRequests.Helpers</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\PlexRequests.Store\PlexRequests.Store.csproj">
|
||||||
|
<Project>{92433867-2B7B-477B-A566-96C382427525}</Project>
|
||||||
|
<Name>PlexRequests.Store</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Choose>
|
<Choose>
|
||||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||||
|
|
|
@ -29,9 +29,8 @@ using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
using PlexRequests.Core.Models;
|
using PlexRequests.Core.Models;
|
||||||
using PlexRequests.UI.Helpers;
|
|
||||||
|
|
||||||
namespace PlexRequests.UI.Tests
|
namespace PlexRequests.Helpers.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class StringHelperTests
|
public class StringHelperTests
|
||||||
|
@ -48,6 +47,12 @@ namespace PlexRequests.UI.Tests
|
||||||
return input.ToCamelCaseWords();
|
return input.ToCamelCaseWords();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(PrefixData))]
|
||||||
|
public string AddPrefix(string[] input, string prefix, string separator)
|
||||||
|
{
|
||||||
|
return input.AddPrefix(prefix, separator);
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<TestCaseData> StringData
|
private static IEnumerable<TestCaseData> StringData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -71,5 +76,19 @@ namespace PlexRequests.UI.Tests
|
||||||
yield return new TestCaseData(IssueStatus.ResolvedIssue.ToString()).Returns("Resolved Issue").SetName("enum resolved");
|
yield return new TestCaseData(IssueStatus.ResolvedIssue.ToString()).Returns("Resolved Issue").SetName("enum resolved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> PrefixData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(new[] {"abc","def","ghi"}, "@", ",").Returns("@abc,@def,@ghi").SetName("Happy Path");
|
||||||
|
yield return new TestCaseData(new[] {"abc","def","ghi"}, "!!", "").Returns("!!abc!!def!!ghi").SetName("Different Separator Path");
|
||||||
|
yield return new TestCaseData(new[] {"abc"}, "", "").Returns("abc").SetName("Single Item");
|
||||||
|
yield return new TestCaseData(new string[0], "", "").Returns(string.Empty).SetName("Empty Array");
|
||||||
|
yield return new TestCaseData(new [] {"abc","aaaa"}, null, ",").Returns("abc,aaaa").SetName("Null prefix");
|
||||||
|
yield return new TestCaseData(new [] {"abc","aaaa"}, "@", null).Returns("@abc@aaaa").SetName("Null separator test");
|
||||||
|
yield return new TestCaseData(new [] {"abc","aaaa"}, null, null).Returns("abcaaaa").SetName("Null separator and prefix");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
73
PlexRequests.Helpers.Tests/TypeHelperTests.cs
Normal file
73
PlexRequests.Helpers.Tests/TypeHelperTests.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: StringHelperTests.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 NUnit.Framework;
|
||||||
|
|
||||||
|
using PlexRequests.Store;
|
||||||
|
|
||||||
|
namespace PlexRequests.Helpers.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TypeHelperTests
|
||||||
|
{
|
||||||
|
[TestCaseSource(nameof(TypeData))]
|
||||||
|
public string[] FirstCharToUpperTest(Type input)
|
||||||
|
{
|
||||||
|
return input.GetPropertyNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<TestCaseData> TypeData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
yield return new TestCaseData(typeof(TestClass1)).Returns(new[] { "Test1", "Test2", "Test3" }).SetName("Simple Class");
|
||||||
|
yield return new TestCaseData(typeof(int)).Returns(new string[0]).SetName("NoPropeties Class");
|
||||||
|
yield return new TestCaseData(typeof(IEnumerable<>)).Returns(new string[0]).SetName("Interface");
|
||||||
|
yield return new TestCaseData(typeof(string)).Returns(new[] { "Chars", "Length" }).SetName("String");
|
||||||
|
yield return new TestCaseData(typeof(RequestedModel)).Returns(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
"ProviderId", "ImdbId", "TvDbId", "Overview", "Title", "PosterPath", "ReleaseDate", "Type",
|
||||||
|
"Status", "Approved", "RequestedBy", "RequestedDate", "Available", "Issues", "OtherMessage", "AdminNote",
|
||||||
|
"SeasonList", "SeasonCount", "SeasonsRequested", "MusicBrainzId", "RequestedUsers","ArtistName",
|
||||||
|
"ArtistId","IssueId","Episodes","AllUsers","CanApprove","Id"
|
||||||
|
}).SetName("Requested Model");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private sealed class TestClass1
|
||||||
|
{
|
||||||
|
public string Test1 { get; set; }
|
||||||
|
public int Test2 { get; set; }
|
||||||
|
public long[] Test3 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,8 @@
|
||||||
<Compile Include="SerializerSettings.cs" />
|
<Compile Include="SerializerSettings.cs" />
|
||||||
<Compile Include="StringCipher.cs" />
|
<Compile Include="StringCipher.cs" />
|
||||||
<Compile Include="StringHasher.cs" />
|
<Compile Include="StringHasher.cs" />
|
||||||
|
<Compile Include="StringHelper.cs" />
|
||||||
|
<Compile Include="TypeHelper.cs" />
|
||||||
<Compile Include="UriHelper.cs" />
|
<Compile Include="UriHelper.cs" />
|
||||||
<Compile Include="UserClaims.cs" />
|
<Compile Include="UserClaims.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -25,9 +25,10 @@
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace PlexRequests.UI.Helpers
|
namespace PlexRequests.Helpers
|
||||||
{
|
{
|
||||||
public static class StringHelper
|
public static class StringHelper
|
||||||
{
|
{
|
||||||
|
@ -46,5 +47,22 @@ namespace PlexRequests.UI.Helpers
|
||||||
return input;
|
return input;
|
||||||
return Regex.Replace(input.FirstCharToUpper(), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
return Regex.Replace(input.FirstCharToUpper(), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string AddPrefix(this string[] values, string prefix, string separator)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var len = values.Length;
|
||||||
|
for (var i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
sb.Append(prefix).Append(values[i]);
|
||||||
|
|
||||||
|
// If it's not the last item in the collection, then add a separator
|
||||||
|
if (i < len - 1)
|
||||||
|
{
|
||||||
|
sb.Append(separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
39
PlexRequests.Helpers/TypeHelper.cs
Normal file
39
PlexRequests.Helpers/TypeHelper.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: TypeHelper.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.Linq;
|
||||||
|
|
||||||
|
namespace PlexRequests.Helpers
|
||||||
|
{
|
||||||
|
public static class TypeHelper
|
||||||
|
{
|
||||||
|
public static string[] GetPropertyNames(this Type t)
|
||||||
|
{
|
||||||
|
return t.GetProperties().Select(x => x.Name).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ namespace PlexRequests.Services.Tests
|
||||||
private Mock<INotificationService> NotificationMock { get; set; }
|
private Mock<INotificationService> NotificationMock { get; set; }
|
||||||
private Mock<IJobRecord> JobRec { get; set; }
|
private Mock<IJobRecord> JobRec { get; set; }
|
||||||
private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
private Mock<IRepository<UsersToNotify>> NotifyUsers { get; set; }
|
||||||
|
private Mock<IRepository<PlexEpisodes>> PlexEpisodes { get; set; }
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
|
@ -64,8 +65,9 @@ namespace PlexRequests.Services.Tests
|
||||||
NotificationMock = new Mock<INotificationService>();
|
NotificationMock = new Mock<INotificationService>();
|
||||||
CacheMock = new Mock<ICacheProvider>();
|
CacheMock = new Mock<ICacheProvider>();
|
||||||
NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
NotifyUsers = new Mock<IRepository<UsersToNotify>>();
|
||||||
|
PlexEpisodes = new Mock<IRepository<PlexEpisodes>>();
|
||||||
JobRec = new Mock<IJobRecord>();
|
JobRec = new Mock<IJobRecord>();
|
||||||
Checker = new PlexAvailabilityChecker(SettingsMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object);
|
Checker = new PlexAvailabilityChecker(SettingsMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object, PlexEpisodes.Object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
#endregion
|
#endregion
|
||||||
using PlexRequests.Services.Models;
|
using PlexRequests.Services.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using PlexRequests.Store.Models;
|
||||||
|
|
||||||
namespace PlexRequests.Services.Interfaces
|
namespace PlexRequests.Services.Interfaces
|
||||||
{
|
{
|
||||||
|
@ -43,12 +46,12 @@ namespace PlexRequests.Services.Interfaces
|
||||||
/// Gets the episode's stored in the cache.
|
/// Gets the episode's stored in the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
HashSet<PlexEpisodeModel> GetEpisodeCache();
|
Task<IEnumerable<PlexEpisodes>> GetEpisodes();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the episode's stored in the cache and then filters on the TheTvDBId.
|
/// Gets the episode's stored in the cache and then filters on the TheTvDBId.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="theTvDbId">The tv database identifier.</param>
|
/// <param name="theTvDbId">The tv database identifier.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IEnumerable<PlexEpisodeModel> GetEpisodeCache(int theTvDbId);
|
Task<IEnumerable<PlexEpisodes>> GetEpisodes(int theTvDbId);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,8 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Dapper;
|
||||||
|
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
using PlexRequests.Api.Interfaces;
|
using PlexRequests.Api.Interfaces;
|
||||||
|
@ -53,7 +55,7 @@ namespace PlexRequests.Services.Jobs
|
||||||
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
public class PlexAvailabilityChecker : IJob, IAvailabilityChecker
|
||||||
{
|
{
|
||||||
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
public PlexAvailabilityChecker(ISettingsService<PlexSettings> plexSettings, IRequestService request, IPlexApi plex, ICacheProvider cache,
|
||||||
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users)
|
INotificationService notify, IJobRecord rec, IRepository<UsersToNotify> users, IRepository<PlexEpisodes> repo)
|
||||||
{
|
{
|
||||||
Plex = plexSettings;
|
Plex = plexSettings;
|
||||||
RequestService = request;
|
RequestService = request;
|
||||||
|
@ -62,9 +64,11 @@ namespace PlexRequests.Services.Jobs
|
||||||
Notification = notify;
|
Notification = notify;
|
||||||
Job = rec;
|
Job = rec;
|
||||||
UserNotifyRepo = users;
|
UserNotifyRepo = users;
|
||||||
|
EpisodeRepo = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<PlexSettings> Plex { get; }
|
private ISettingsService<PlexSettings> Plex { get; }
|
||||||
|
private IRepository<PlexEpisodes> EpisodeRepo { get; }
|
||||||
private IRequestService RequestService { get; }
|
private IRequestService RequestService { get; }
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
|
@ -241,15 +245,23 @@ namespace PlexRequests.Services.Jobs
|
||||||
|
|
||||||
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
public bool IsEpisodeAvailable(string theTvDbId, int season, int episode)
|
||||||
{
|
{
|
||||||
var episodes = Cache.Get<HashSet<PlexEpisodeModel>>(CacheKeys.PlexEpisodes);
|
var ep = EpisodeRepo.Custom(
|
||||||
if (episodes == null)
|
connection =>
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
var result = connection.Query<PlexEpisodes>("select * from PlexEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
if (!ep.Any())
|
||||||
{
|
{
|
||||||
Log.Info("Episode cache info is not available. tvdbid: {0}, season: {1}, episode: {2}",theTvDbId, season, episode);
|
Log.Info("Episode cache info is not available. tvdbid: {0}, season: {1}, episode: {2}",theTvDbId, season, episode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
foreach (var result in episodes)
|
foreach (var result in ep)
|
||||||
{
|
{
|
||||||
if (result.Episodes.ProviderId.Equals(theTvDbId) && result.Episodes.EpisodeNumber == episode && result.Episodes.SeasonNumber == season)
|
if (result.ProviderId.Equals(theTvDbId) && result.EpisodeNumber == episode && result.SeasonNumber == season)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -258,35 +270,43 @@ namespace PlexRequests.Services.Jobs
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the episode's stored in the cache.
|
/// Gets the episode's db in the cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public HashSet<PlexEpisodeModel> GetEpisodeCache()
|
public async Task<IEnumerable<PlexEpisodes>> GetEpisodes()
|
||||||
{
|
{
|
||||||
var episodes = Cache.Get<HashSet<PlexEpisodeModel>>(CacheKeys.PlexEpisodes);
|
var episodes = await EpisodeRepo.GetAllAsync();
|
||||||
if (episodes == null)
|
if (episodes == null)
|
||||||
{
|
{
|
||||||
Log.Info("Episode cache info is not available.");
|
Log.Info("Episode cache info is not available.");
|
||||||
return new HashSet<PlexEpisodeModel>();
|
return new HashSet<PlexEpisodes>();
|
||||||
}
|
}
|
||||||
return episodes;
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the episode's stored in the cache and then filters on the TheTvDBId.
|
/// Gets the episode's stored in the db and then filters on the TheTvDBId.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="theTvDbId">The tv database identifier.</param>
|
/// <param name="theTvDbId">The tv database identifier.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IEnumerable<PlexEpisodeModel> GetEpisodeCache(int theTvDbId)
|
public async Task<IEnumerable<PlexEpisodes>> GetEpisodes(int theTvDbId)
|
||||||
{
|
{
|
||||||
var episodes = Cache.Get<List<PlexEpisodeModel>>(CacheKeys.PlexEpisodes);
|
var ep = await EpisodeRepo.CustomAsync(async connection =>
|
||||||
if (episodes == null)
|
{
|
||||||
|
connection.Open();
|
||||||
|
var result = await connection.QueryAsync<PlexEpisodes>("select * from PlexEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
var plexEpisodeses = ep as PlexEpisodes[] ?? ep.ToArray();
|
||||||
|
if (!plexEpisodeses.Any())
|
||||||
{
|
{
|
||||||
Log.Info("Episode cache info is not available.");
|
Log.Info("Episode db info is not available.");
|
||||||
return new List<PlexEpisodeModel>();
|
return new List<PlexEpisodes>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return episodes.Where(x => x.Episodes.ProviderId == theTvDbId.ToString());
|
return plexEpisodeses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PlexAlbum> GetPlexAlbums()
|
public List<PlexAlbum> GetPlexAlbums()
|
||||||
|
|
|
@ -37,6 +37,8 @@ using PlexRequests.Core.SettingModels;
|
||||||
using PlexRequests.Helpers;
|
using PlexRequests.Helpers;
|
||||||
using PlexRequests.Services.Interfaces;
|
using PlexRequests.Services.Interfaces;
|
||||||
using PlexRequests.Services.Models;
|
using PlexRequests.Services.Models;
|
||||||
|
using PlexRequests.Store.Models;
|
||||||
|
using PlexRequests.Store.Repository;
|
||||||
|
|
||||||
using Quartz;
|
using Quartz;
|
||||||
|
|
||||||
|
@ -45,12 +47,13 @@ namespace PlexRequests.Services.Jobs
|
||||||
public class PlexEpisodeCacher : IJob
|
public class PlexEpisodeCacher : IJob
|
||||||
{
|
{
|
||||||
public PlexEpisodeCacher(ISettingsService<PlexSettings> plexSettings, IPlexApi plex, ICacheProvider cache,
|
public PlexEpisodeCacher(ISettingsService<PlexSettings> plexSettings, IPlexApi plex, ICacheProvider cache,
|
||||||
IJobRecord rec)
|
IJobRecord rec, IRepository<PlexEpisodes> repo)
|
||||||
{
|
{
|
||||||
Plex = plexSettings;
|
Plex = plexSettings;
|
||||||
PlexApi = plex;
|
PlexApi = plex;
|
||||||
Cache = cache;
|
Cache = cache;
|
||||||
Job = rec;
|
Job = rec;
|
||||||
|
Repo = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISettingsService<PlexSettings> Plex { get; }
|
private ISettingsService<PlexSettings> Plex { get; }
|
||||||
|
@ -58,19 +61,23 @@ namespace PlexRequests.Services.Jobs
|
||||||
private IPlexApi PlexApi { get; }
|
private IPlexApi PlexApi { get; }
|
||||||
private ICacheProvider Cache { get; }
|
private ICacheProvider Cache { get; }
|
||||||
private IJobRecord Job { get; }
|
private IJobRecord Job { get; }
|
||||||
|
private IRepository<PlexEpisodes> Repo { get; }
|
||||||
private const int ResultCount = 25;
|
private const int ResultCount = 25;
|
||||||
private const string PlexType = "episode";
|
private const string PlexType = "episode";
|
||||||
|
private const string TableName = "PlexEpisodes";
|
||||||
|
|
||||||
|
|
||||||
public void CacheEpisodes()
|
public void CacheEpisodes()
|
||||||
{
|
{
|
||||||
var videoHashset = new HashSet<Video>();
|
var videoHashset = new HashSet<Video>();
|
||||||
var settings = Plex.GetSettings();
|
var settings = Plex.GetSettings();
|
||||||
|
// Ensure Plex is setup correctly
|
||||||
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the librarys and then get the tv section
|
||||||
var sections = PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
|
var sections = PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
|
||||||
var tvSection = sections.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
var tvSection = sections.Directories.FirstOrDefault(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
|
||||||
var tvSectionId = tvSection?.Key;
|
var tvSectionId = tvSection?.Key;
|
||||||
|
@ -78,10 +85,15 @@ namespace PlexRequests.Services.Jobs
|
||||||
var currentPosition = 0;
|
var currentPosition = 0;
|
||||||
int totalSize;
|
int totalSize;
|
||||||
|
|
||||||
|
// Get the first 25 episodes (Paged)
|
||||||
var episodes = PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount);
|
var episodes = PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount);
|
||||||
|
|
||||||
|
// Parse the total amount of episodes
|
||||||
int.TryParse(episodes.TotalSize, out totalSize);
|
int.TryParse(episodes.TotalSize, out totalSize);
|
||||||
|
|
||||||
currentPosition += ResultCount;
|
currentPosition += ResultCount;
|
||||||
|
|
||||||
|
// Get all of the episodes in batches until we them all (Got'a catch 'em all!)
|
||||||
while (currentPosition < totalSize)
|
while (currentPosition < totalSize)
|
||||||
{
|
{
|
||||||
videoHashset.UnionWith(PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount).Video
|
videoHashset.UnionWith(PlexApi.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, tvSectionId, currentPosition, ResultCount).Video
|
||||||
|
@ -89,29 +101,40 @@ namespace PlexRequests.Services.Jobs
|
||||||
currentPosition += ResultCount;
|
currentPosition += ResultCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
var episodesModel = new HashSet<PlexEpisodeModel>();
|
var entities = new HashSet<PlexEpisodes>();
|
||||||
|
|
||||||
foreach (var video in videoHashset)
|
foreach (var video in videoHashset)
|
||||||
{
|
{
|
||||||
var ratingKey = video.RatingKey;
|
|
||||||
var metadata = PlexApi.GetEpisodeMetaData(settings.PlexAuthToken, settings.FullUri, ratingKey);
|
|
||||||
|
|
||||||
|
// Get the individual episode Metadata (This is for us to get the TheTVDBId which also includes the episode number and season number)
|
||||||
|
var metadata = PlexApi.GetEpisodeMetaData(settings.PlexAuthToken, settings.FullUri, video.RatingKey);
|
||||||
|
|
||||||
|
// Loop through the metadata and create the model to insert into the DB
|
||||||
foreach (var metadataVideo in metadata.Video)
|
foreach (var metadataVideo in metadata.Video)
|
||||||
{
|
{
|
||||||
episodesModel.Add(new PlexEpisodeModel
|
var epInfo = PlexHelper.GetSeasonsAndEpisodesFromPlexGuid(metadataVideo.Guid);
|
||||||
{
|
entities.Add(
|
||||||
RatingKey = metadataVideo.RatingKey,
|
new PlexEpisodes
|
||||||
EpisodeTitle = metadataVideo.Title,
|
{
|
||||||
Guid = metadataVideo.Guid,
|
EpisodeNumber = epInfo.EpisodeNumber,
|
||||||
ShowTitle = metadataVideo.GrandparentTitle
|
EpisodeTitle = metadataVideo.Title,
|
||||||
});
|
ProviderId = epInfo.ProviderId,
|
||||||
|
RatingKey = metadataVideo.RatingKey,
|
||||||
|
SeasonNumber = epInfo.SeasonNumber,
|
||||||
|
ShowTitle = metadataVideo.Title
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete all of the current items
|
||||||
|
Repo.DeleteAll(TableName);
|
||||||
|
|
||||||
if (episodesModel.Any())
|
// Insert the new items
|
||||||
|
var result = Repo.BatchInsert(entities, TableName, typeof(PlexEpisodes).GetPropertyNames());
|
||||||
|
|
||||||
|
if (!result)
|
||||||
{
|
{
|
||||||
Cache.Set(CacheKeys.PlexEpisodes, episodesModel, CacheKeys.TimeFrameMinutes.SchedulerCaching);
|
Log.Error("Saving the plex episodes to the DB Failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Dapper, Version=1.50.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Dapper.1.50.0-beta8\lib\net45\Dapper.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Microsoft.Build.Framework" />
|
<Reference Include="Microsoft.Build.Framework" />
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.3.6\lib\net45\NLog.dll</HintPath>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
<package id="Common.Logging" version="3.0.0" targetFramework="net45" />
|
||||||
<package id="Common.Logging.Core" version="3.0.0" targetFramework="net45" />
|
<package id="Common.Logging.Core" version="3.0.0" targetFramework="net45" />
|
||||||
|
<package id="Dapper" version="1.50.0-beta8" targetFramework="net45" />
|
||||||
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
<package id="MailKit" version="1.2.21" targetFramework="net45" requireReinstallation="True" />
|
||||||
<package id="MimeKit" version="1.2.22" targetFramework="net45" />
|
<package id="MimeKit" version="1.2.22" targetFramework="net45" />
|
||||||
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
<package id="NLog" version="4.3.6" targetFramework="net45" />
|
||||||
|
|
41
PlexRequests.Store/Models/PlexEpisodes.cs
Normal file
41
PlexRequests.Store/Models/PlexEpisodes.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2016 Jamie Rees
|
||||||
|
// File: LogEntity.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 Dapper.Contrib.Extensions;
|
||||||
|
|
||||||
|
namespace PlexRequests.Store.Models
|
||||||
|
{
|
||||||
|
[Table("PlexEpisodes")]
|
||||||
|
public class PlexEpisodes : Entity
|
||||||
|
{
|
||||||
|
public string EpisodeTitle { get; set; }
|
||||||
|
public string ShowTitle { get; set; }
|
||||||
|
public string RatingKey { get; set; }
|
||||||
|
public string ProviderId { get; set; }
|
||||||
|
public int SeasonNumber { get; set; }
|
||||||
|
public int EpisodeNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,6 +65,7 @@
|
||||||
<Compile Include="DbConfiguration.cs" />
|
<Compile Include="DbConfiguration.cs" />
|
||||||
<Compile Include="Entity.cs" />
|
<Compile Include="Entity.cs" />
|
||||||
<Compile Include="Models\IssueBlobs.cs" />
|
<Compile Include="Models\IssueBlobs.cs" />
|
||||||
|
<Compile Include="Models\PlexEpisodes.cs" />
|
||||||
<Compile Include="Models\PlexUsers.cs" />
|
<Compile Include="Models\PlexUsers.cs" />
|
||||||
<Compile Include="Models\ScheduledJobs.cs" />
|
<Compile Include="Models\ScheduledJobs.cs" />
|
||||||
<Compile Include="Models\RequestLimit.cs" />
|
<Compile Include="Models\RequestLimit.cs" />
|
||||||
|
|
|
@ -24,10 +24,14 @@
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Dapper;
|
||||||
using Dapper.Contrib.Extensions;
|
using Dapper.Contrib.Extensions;
|
||||||
|
|
||||||
using Mono.Data.Sqlite;
|
using Mono.Data.Sqlite;
|
||||||
|
@ -53,6 +57,24 @@ namespace PlexRequests.Store.Repository
|
||||||
public abstract Task<T> GetAsync(int id);
|
public abstract Task<T> GetAsync(int id);
|
||||||
public abstract T Get(int id);
|
public abstract T Get(int id);
|
||||||
public abstract Task<T> GetAsync(string id);
|
public abstract Task<T> GetAsync(string id);
|
||||||
|
private IDbConnection Connection => Config.DbConnection();
|
||||||
|
|
||||||
|
|
||||||
|
public IEnumerable<T> Custom(Func<IDbConnection , IEnumerable<T>> func)
|
||||||
|
{
|
||||||
|
using (var cnn = Connection)
|
||||||
|
{
|
||||||
|
return func(cnn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<T>> CustomAsync(Func<IDbConnection, Task<IEnumerable<T>>> func)
|
||||||
|
{
|
||||||
|
using (var cnn = Connection)
|
||||||
|
{
|
||||||
|
return await func(cnn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public long Insert(T entity)
|
public long Insert(T entity)
|
||||||
{
|
{
|
||||||
|
@ -251,5 +273,50 @@ namespace PlexRequests.Store.Repository
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool BatchInsert(IEnumerable<T> entities, string tableName, params string[] values)
|
||||||
|
{
|
||||||
|
// If we have nothing to update, then it didn't fail...
|
||||||
|
if (!entities.Any())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ResetCache();
|
||||||
|
using (var db = Config.DbConnection())
|
||||||
|
{
|
||||||
|
|
||||||
|
var format = values.AddPrefix("@", ",");
|
||||||
|
var processQuery = $"INSERT INTO {tableName} VALUES ({format})";
|
||||||
|
var result = db.Execute(processQuery, entities);
|
||||||
|
return result == values.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SqliteException e) when (e.ErrorCode == SQLiteErrorCode.Corrupt)
|
||||||
|
{
|
||||||
|
Log.Fatal(CorruptMessage);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAll(string tableName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ResetCache();
|
||||||
|
using (var db = Config.DbConnection())
|
||||||
|
{
|
||||||
|
db.Open();
|
||||||
|
db.Execute($"delete from {tableName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SqliteException e) when (e.ErrorCode == SQLiteErrorCode.Corrupt)
|
||||||
|
{
|
||||||
|
Log.Fatal(CorruptMessage);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,81 +1,89 @@
|
||||||
#region Copyright
|
#region Copyright
|
||||||
// /************************************************************************
|
// /************************************************************************
|
||||||
// Copyright (c) 2016 Jamie Rees
|
// Copyright (c) 2016 Jamie Rees
|
||||||
// File: IRepository.cs
|
// File: IRepository.cs
|
||||||
// Created By: Jamie Rees
|
// Created By: Jamie Rees
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
// a copy of this software and associated documentation files (the
|
// a copy of this software and associated documentation files (the
|
||||||
// "Software"), to deal in the Software without restriction, including
|
// "Software"), to deal in the Software without restriction, including
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
// the following conditions:
|
// the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be
|
// The above copyright notice and this permission notice shall be
|
||||||
// included in all copies or substantial portions of the Software.
|
// included in all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// ************************************************************************/
|
// ************************************************************************/
|
||||||
#endregion
|
#endregion
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
namespace PlexRequests.Store.Repository
|
using System.Threading.Tasks;
|
||||||
{
|
|
||||||
public interface IRepository<T>
|
namespace PlexRequests.Store.Repository
|
||||||
{
|
{
|
||||||
/// <summary>
|
public interface IRepository<T>
|
||||||
/// Inserts the specified entity.
|
{
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="entity">The entity.</param>
|
/// Inserts the specified entity.
|
||||||
long Insert(T entity);
|
/// </summary>
|
||||||
Task<int> InsertAsync(T entity);
|
/// <param name="entity">The entity.</param>
|
||||||
|
long Insert(T entity);
|
||||||
/// <summary>
|
Task<int> InsertAsync(T entity);
|
||||||
/// Gets all.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <returns></returns>
|
/// Gets all.
|
||||||
IEnumerable<T> GetAll();
|
/// </summary>
|
||||||
Task<IEnumerable<T>> GetAllAsync();
|
/// <returns></returns>
|
||||||
|
IEnumerable<T> GetAll();
|
||||||
|
Task<IEnumerable<T>> GetAllAsync();
|
||||||
/// <summary>
|
|
||||||
/// Gets the specified identifier.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="id">The identifier.</param>
|
/// Gets the specified identifier.
|
||||||
/// <returns></returns>
|
/// </summary>
|
||||||
T Get(string id);
|
/// <param name="id">The identifier.</param>
|
||||||
Task<T> GetAsync(string id);
|
/// <returns></returns>
|
||||||
T Get(int id);
|
T Get(string id);
|
||||||
Task<T> GetAsync(int id);
|
Task<T> GetAsync(string id);
|
||||||
/// <summary>
|
T Get(int id);
|
||||||
/// Deletes the specified entity.
|
Task<T> GetAsync(int id);
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="entity">The entity.</param>
|
/// Deletes the specified entity.
|
||||||
void Delete(T entity);
|
/// </summary>
|
||||||
Task DeleteAsync(T entity);
|
/// <param name="entity">The entity.</param>
|
||||||
|
void Delete(T entity);
|
||||||
/// <summary>
|
Task DeleteAsync(T entity);
|
||||||
/// Updates the specified entity.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="entity">The entity.</param>
|
/// Updates the specified entity.
|
||||||
/// <returns></returns>
|
/// </summary>
|
||||||
bool Update(T entity);
|
/// <param name="entity">The entity.</param>
|
||||||
Task<bool> UpdateAsync(T entity);
|
/// <returns></returns>
|
||||||
|
bool Update(T entity);
|
||||||
/// <summary>
|
Task<bool> UpdateAsync(T entity);
|
||||||
/// Updates all.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="entity">The entity.</param>
|
/// Updates all.
|
||||||
/// <returns></returns>
|
/// </summary>
|
||||||
bool UpdateAll(IEnumerable<T> entity);
|
/// <param name="entity">The entity.</param>
|
||||||
Task<bool> UpdateAllAsync(IEnumerable<T> entity);
|
/// <returns></returns>
|
||||||
}
|
bool UpdateAll(IEnumerable<T> entity);
|
||||||
}
|
Task<bool> UpdateAllAsync(IEnumerable<T> entity);
|
||||||
|
|
||||||
|
bool BatchInsert(IEnumerable<T> entities, string tableName, params string[] values);
|
||||||
|
|
||||||
|
IEnumerable<T> Custom(Func<IDbConnection, IEnumerable<T>> func);
|
||||||
|
Task<IEnumerable<T>> CustomAsync(Func<IDbConnection, Task<IEnumerable<T>>> func);
|
||||||
|
void DeleteAll(string tableName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -99,4 +99,17 @@ CREATE TABLE IF NOT EXISTS PlexUsers
|
||||||
PlexUserId INTEGER NOT NULL,
|
PlexUserId INTEGER NOT NULL,
|
||||||
UserAlias varchar(100) NOT NULL
|
UserAlias varchar(100) NOT NULL
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON RequestLimit (Id);
|
CREATE UNIQUE INDEX IF NOT EXISTS PlexUsers_Id ON PlexUsers (Id);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS PlexEpisodes
|
||||||
|
(
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
EpisodeTitle VARCHAR(100) NOT NULL,
|
||||||
|
ShowTitle VARCHAR(100) NOT NULL,
|
||||||
|
RatingKey VARCHAR(100) NOT NULL,
|
||||||
|
ProviderId VARCHAR(100) NOT NULL,
|
||||||
|
SeasonNumber INTEGER NOT NULL,
|
||||||
|
EpisodeNumber INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS PlexEpisodes_Id ON PlexEpisodes (Id);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS PlexEpisodes_ProviderId ON PlexEpisodes (ProviderId);
|
|
@ -72,8 +72,6 @@ namespace PlexRequests.Store
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,6 @@
|
||||||
<Compile Include="LandingPageTests.cs" />
|
<Compile Include="LandingPageTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SearchModuleTests.cs" />
|
<Compile Include="SearchModuleTests.cs" />
|
||||||
<Compile Include="StringHelperTests.cs" />
|
|
||||||
<Compile Include="TestRootPathProvider.cs" />
|
<Compile Include="TestRootPathProvider.cs" />
|
||||||
<Compile Include="TvSenderTests.cs" />
|
<Compile Include="TvSenderTests.cs" />
|
||||||
<Compile Include="UserLoginModuleTests.cs" />
|
<Compile Include="UserLoginModuleTests.cs" />
|
||||||
|
|
|
@ -53,8 +53,6 @@ using Nancy.Json;
|
||||||
|
|
||||||
using Ninject;
|
using Ninject;
|
||||||
|
|
||||||
using StackExchange.Profiling;
|
|
||||||
|
|
||||||
namespace PlexRequests.UI
|
namespace PlexRequests.UI
|
||||||
{
|
{
|
||||||
public class Bootstrapper : NinjectNancyBootstrapper
|
public class Bootstrapper : NinjectNancyBootstrapper
|
||||||
|
@ -88,10 +86,7 @@ namespace PlexRequests.UI
|
||||||
|
|
||||||
base.ApplicationStartup(container, pipelines);
|
base.ApplicationStartup(container, pipelines);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
pipelines.BeforeRequest += StartProfiler;
|
|
||||||
pipelines.AfterRequest += EndProfiler;
|
|
||||||
#endif
|
|
||||||
var settings = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
var settings = new SettingsServiceV2<PlexRequestSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
|
||||||
var baseUrl = settings.GetSettings().BaseUrl;
|
var baseUrl = settings.GetSettings().BaseUrl;
|
||||||
var redirect = string.IsNullOrEmpty(baseUrl) ? "~/login" : $"~/{baseUrl}/login";
|
var redirect = string.IsNullOrEmpty(baseUrl) ? "~/login" : $"~/{baseUrl}/login";
|
||||||
|
@ -198,15 +193,5 @@ namespace PlexRequests.UI
|
||||||
loc.SetContainer(container);
|
loc.SetContainer(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Response StartProfiler(NancyContext ctx)
|
|
||||||
{
|
|
||||||
MiniProfiler.Start();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EndProfiler(NancyContext ctx)
|
|
||||||
{
|
|
||||||
MiniProfiler.Stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -608,10 +608,11 @@ namespace PlexRequests.UI.Modules
|
||||||
}
|
}
|
||||||
if (episodeRequest)
|
if (episodeRequest)
|
||||||
{
|
{
|
||||||
var cachedEpisodes = Checker.GetEpisodeCache().ToList();
|
var cachedEpisodesTask = await Checker.GetEpisodes();
|
||||||
|
var cachedEpisodes = cachedEpisodesTask.ToList();
|
||||||
foreach (var d in difference)
|
foreach (var d in difference)
|
||||||
{
|
{
|
||||||
if (cachedEpisodes.Any(x => x.Episodes.SeasonNumber == d.SeasonNumber && x.Episodes.EpisodeNumber == d.EpisodeNumber && x.Episodes.ProviderId == providerId))
|
if (cachedEpisodes.Any(x => x.SeasonNumber == d.SeasonNumber && x.EpisodeNumber == d.EpisodeNumber && x.ProviderId == providerId))
|
||||||
{
|
{
|
||||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}" });
|
return Response.AsJson(new JsonResponseModel { Result = false, Message = $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}" });
|
||||||
}
|
}
|
||||||
|
@ -983,15 +984,15 @@ namespace PlexRequests.UI.Modules
|
||||||
sonarrEpisodes = sonarrEp?.ToList() ?? new List<SonarrEpisodes>();
|
sonarrEpisodes = sonarrEp?.ToList() ?? new List<SonarrEpisodes>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var plexCache = Checker.GetEpisodeCache(seriesId).ToList();
|
var plexCacheTask = await Checker.GetEpisodes(seriesId);
|
||||||
|
var plexCache = plexCacheTask.ToList();
|
||||||
foreach (var ep in seasons)
|
foreach (var ep in seasons)
|
||||||
{
|
{
|
||||||
var requested = dbDbShow?.Episodes
|
var requested = dbDbShow?.Episodes
|
||||||
.Any(episodesModel =>
|
.Any(episodesModel =>
|
||||||
ep.number == episodesModel.EpisodeNumber && ep.season == episodesModel.SeasonNumber) ?? false;
|
ep.number == episodesModel.EpisodeNumber && ep.season == episodesModel.SeasonNumber) ?? false;
|
||||||
|
|
||||||
var alreadyInPlex = plexCache.Any(x => x.Episodes.EpisodeNumber == ep.number && x.Episodes.SeasonNumber == ep.season);
|
var alreadyInPlex = plexCache.Any(x => x.EpisodeNumber == ep.number && x.SeasonNumber == ep.season);
|
||||||
var inSonarr = sonarrEpisodes.Any(x => x.seasonNumber == ep.season && x.episodeNumber == ep.number && x.monitored);
|
var inSonarr = sonarrEpisodes.Any(x => x.seasonNumber == ep.season && x.episodeNumber == ep.number && x.monitored);
|
||||||
|
|
||||||
model.Add(new EpisodeListViewModel
|
model.Add(new EpisodeListViewModel
|
||||||
|
|
|
@ -44,7 +44,6 @@ using PlexRequests.Helpers;
|
||||||
using PlexRequests.Helpers.Analytics;
|
using PlexRequests.Helpers.Analytics;
|
||||||
using PlexRequests.UI.Models;
|
using PlexRequests.UI.Models;
|
||||||
|
|
||||||
using StackExchange.Profiling;
|
|
||||||
|
|
||||||
using Action = PlexRequests.Helpers.Analytics.Action;
|
using Action = PlexRequests.Helpers.Analytics.Action;
|
||||||
|
|
||||||
|
@ -78,17 +77,8 @@ namespace PlexRequests.UI.Modules
|
||||||
|
|
||||||
public async Task<Negotiator> Index()
|
public async Task<Negotiator> Index()
|
||||||
{
|
{
|
||||||
var profiler = MiniProfiler.Current;
|
var settings = await AuthService.GetSettingsAsync();
|
||||||
using (profiler.Step("Loading Index"))
|
return View["Index", settings];
|
||||||
{
|
|
||||||
using (profiler.Step("Loading AuthSettingsAsync and returning View"))
|
|
||||||
{
|
|
||||||
var settings = await AuthService.GetSettingsAsync();
|
|
||||||
return View["Index", settings];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Response> LoginUser()
|
private async Task<Response> LoginUser()
|
||||||
|
|
|
@ -65,14 +65,6 @@
|
||||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="MiniProfiler, Version=3.0.10.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\MiniProfiler.3.0.10\lib\net40\MiniProfiler.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="MiniProfiler.Mvc, Version=3.0.11.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\MiniProfiler.MVC4.3.0.11\lib\net40\MiniProfiler.Mvc.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
|
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
|
@ -219,7 +211,6 @@
|
||||||
<Compile Include="Helpers\HeadphonesSender.cs" />
|
<Compile Include="Helpers\HeadphonesSender.cs" />
|
||||||
<Compile Include="Helpers\AngularViewBase.cs" />
|
<Compile Include="Helpers\AngularViewBase.cs" />
|
||||||
<Compile Include="Helpers\ServiceLocator.cs" />
|
<Compile Include="Helpers\ServiceLocator.cs" />
|
||||||
<Compile Include="Helpers\StringHelper.cs" />
|
|
||||||
<Compile Include="Helpers\Themes.cs" />
|
<Compile Include="Helpers\Themes.cs" />
|
||||||
<Compile Include="Helpers\TvSender.cs" />
|
<Compile Include="Helpers\TvSender.cs" />
|
||||||
<Compile Include="Helpers\ValidationHelper.cs" />
|
<Compile Include="Helpers\ValidationHelper.cs" />
|
||||||
|
|
|
@ -34,4 +34,7 @@ using System.Runtime.InteropServices;
|
||||||
[assembly: AssemblyVersion("1.0.*")]
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
[assembly: AssemblyInformationalVersionAttribute("1.0.0.0")]
|
[assembly: AssemblyInformationalVersionAttribute("1.0.0.0")]
|
||||||
[assembly: InternalsVisibleTo("PlexRequests.UI.Tests")]
|
[assembly: InternalsVisibleTo("PlexRequests.UI.Tests")]
|
||||||
|
[assembly: InternalsVisibleTo("PlexRequests.UI.Tests1")]
|
||||||
|
[assembly: InternalsVisibleTo("PlexRequests.Explorables")]
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="PlexEpisodeCacher" class="control-label">Plex Episode Cacher (min)</label>
|
<label for="PlexEpisodeCacher" class="control-label">Plex Episode Cacher (hour)</label>
|
||||||
<input type="text" class="form-control form-control-custom " id="PlexEpisodeCacher" name="PlexEpisodeCacher" value="@Model.PlexEpisodeCacher">
|
<input type="text" class="form-control form-control-custom " id="PlexEpisodeCacher" name="PlexEpisodeCacher" value="@Model.PlexEpisodeCacher">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@using System.Linq
|
@using System.Linq
|
||||||
@using PlexRequests.Core.Models
|
@using PlexRequests.Core.Models
|
||||||
|
@using PlexRequests.Helpers
|
||||||
@using PlexRequests.UI.Helpers
|
@using PlexRequests.UI.Helpers
|
||||||
@{
|
@{
|
||||||
var baseUrl = Html.GetBaseUrl();
|
var baseUrl = Html.GetBaseUrl();
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net45" />
|
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net45" />
|
||||||
<package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net45" />
|
<package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net45" />
|
||||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
|
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
|
||||||
<package id="MiniProfiler" version="3.0.10" targetFramework="net45" />
|
|
||||||
<package id="MiniProfiler.MVC4" version="3.0.11" targetFramework="net45" />
|
|
||||||
<package id="Moment.js" version="2.9.0" targetFramework="net45" />
|
<package id="Moment.js" version="2.9.0" targetFramework="net45" />
|
||||||
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
|
<package id="Mono.Posix" version="4.0.0.0" targetFramework="net45" />
|
||||||
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
<package id="Nancy" version="1.4.3" targetFramework="net45" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue