#1464 added the Plex episode cacher

#865
pull/1510/head
Jamie.Rees 8 years ago
parent bf043fc76e
commit 0e6462bbd5

@ -10,10 +10,11 @@ namespace Ombi.Api.Plex
Task<PlexStatus> GetStatus(string authToken, string uri); Task<PlexStatus> GetStatus(string authToken, string uri);
Task<PlexAuthentication> SignIn(UserRequest user); Task<PlexAuthentication> SignIn(UserRequest user);
Task<PlexServer> GetServer(string authToken); Task<PlexServer> GetServer(string authToken);
Task<PlexLibraries> GetLibrarySections(string authToken, string plexFullHost); Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost);
Task<PlexLibraries> GetLibrary(string authToken, string plexFullHost, string libraryId); Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId);
Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, string ratingKey); Task<PlexMetadata> GetEpisodeMetaData(string authToken, string host, string ratingKey);
Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId); Task<PlexMetadata> GetMetadata(string authToken, string plexFullHost, string itemId);
Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey); Task<PlexMetadata> GetSeasons(string authToken, string plexFullHost, string ratingKey);
Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount);
} }
} }

@ -26,7 +26,7 @@
#endregion #endregion
namespace Ombi.Api.Plex.Models namespace Ombi.Api.Plex.Models
{ {
public class PlexLibraries public class PlexContainer
{ {
public Mediacontainer MediaContainer { get; set; } public Mediacontainer MediaContainer { get; set; }
} }

@ -60,18 +60,18 @@ namespace Ombi.Api.Plex
return await Api.Request<PlexServer>(request); return await Api.Request<PlexServer>(request);
} }
public async Task<PlexLibraries> GetLibrarySections(string authToken, string plexFullHost) public async Task<PlexContainer> GetLibrarySections(string authToken, string plexFullHost)
{ {
var request = new Request("library/sections", plexFullHost, HttpMethod.Get); var request = new Request("library/sections", plexFullHost, HttpMethod.Get);
AddHeaders(request, authToken); AddHeaders(request, authToken);
return await Api.Request<PlexLibraries>(request); return await Api.Request<PlexContainer>(request);
} }
public async Task<PlexLibraries> GetLibrary(string authToken, string plexFullHost, string libraryId) public async Task<PlexContainer> GetLibrary(string authToken, string plexFullHost, string libraryId)
{ {
var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get); var request = new Request($"library/sections/{libraryId}/all", plexFullHost, HttpMethod.Get);
AddHeaders(request, authToken); AddHeaders(request, authToken);
return await Api.Request<PlexLibraries>(request); return await Api.Request<PlexContainer>(request);
} }
/// <summary> /// <summary>
@ -106,6 +106,26 @@ namespace Ombi.Api.Plex
return await Api.Request<PlexMetadata>(request); return await Api.Request<PlexMetadata>(request);
} }
/// <summary>
/// Gets all episodes.
/// </summary>
/// <param name="authToken">The authentication token.</param>
/// <param name="host">The host.</param>
/// <param name="section">The section.</param>
/// <param name="start">The start count.</param>
/// <param name="retCount">The return count, how many items you want returned.</param>
/// <returns></returns>
public async Task<PlexContainer> GetAllEpisodes(string authToken, string host, string section, int start, int retCount)
{
var request = new Request($"/library/sections/{section}/all", host, HttpMethod.Get);
request.AddQueryString("type", "4");
AddLimitHeaders(request, start, retCount);
AddHeaders(request, authToken);
return await Api.Request<PlexContainer>(request);
}
/// <summary> /// <summary>
/// Adds the required headers and also the authorization header /// Adds the required headers and also the authorization header
/// </summary> /// </summary>
@ -129,5 +149,11 @@ namespace Ombi.Api.Plex
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml"); request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
request.AddHeader("Accept", "application/json"); request.AddHeader("Accept", "application/json");
} }
private void AddLimitHeaders(Request request, int from, int to)
{
request.AddHeader("X-Plex-Container-Start", from.ToString());
request.AddHeader("X-Plex-Container-Size", to.ToString());
}
} }
} }

@ -98,7 +98,7 @@ namespace Ombi.Api.Radarr
} }
catch (JsonSerializationException jse) catch (JsonSerializationException jse)
{ {
Logger.LogError(LoggingEvents.RadarrApiException, jse, "Error When adding movie to Radarr"); Logger.LogError(LoggingEvents.RadarrApi, jse, "Error When adding movie to Radarr");
} }
return null; return null;
} }

@ -9,10 +9,4 @@
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" /> <ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
<HintPath>..\..\..\..\..\.nuget\packages\microsoft.extensions.logging.abstractions\1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>

@ -61,7 +61,7 @@ namespace Ombi.Api.TvMaze
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogError(LoggingEvents.ApiException, e, "Exception when calling ShowLookupByTheTvDbId with id:{0}",theTvDbId); Logger.LogError(LoggingEvents.Api, e, "Exception when calling ShowLookupByTheTvDbId with id:{0}",theTvDbId);
return null; return null;
} }
} }

@ -45,7 +45,7 @@ namespace Ombi.Api
{ {
if (!httpResponseMessage.IsSuccessStatusCode) if (!httpResponseMessage.IsSuccessStatusCode)
{ {
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
} }
// do something with the response // do something with the response
var data = httpResponseMessage.Content; var data = httpResponseMessage.Content;
@ -89,7 +89,7 @@ namespace Ombi.Api
{ {
if (!httpResponseMessage.IsSuccessStatusCode) if (!httpResponseMessage.IsSuccessStatusCode)
{ {
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
} }
// do something with the response // do something with the response
var data = httpResponseMessage.Content; var data = httpResponseMessage.Content;
@ -123,7 +123,7 @@ namespace Ombi.Api
{ {
if (!httpResponseMessage.IsSuccessStatusCode) if (!httpResponseMessage.IsSuccessStatusCode)
{ {
Logger.LogError(LoggingEvents.ApiException, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}"); Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
} }
} }
} }

@ -68,7 +68,7 @@ namespace Ombi.Core
if (!string.IsNullOrEmpty(result.Error?.message)) if (!string.IsNullOrEmpty(result.Error?.message))
{ {
Log.LogError(LoggingEvents.RadarrCacherException,result.Error.message); Log.LogError(LoggingEvents.RadarrCacher,result.Error.message);
return new MovieSenderResult { Success = false, Message = result.Error.message, MovieSent = false }; return new MovieSenderResult { Success = false, Message = result.Error.message, MovieSent = false };
} }
if (!string.IsNullOrEmpty(result.title)) if (!string.IsNullOrEmpty(result.title))

@ -35,6 +35,7 @@ using Ombi.Api.Service;
using Ombi.Api.Slack; using Ombi.Api.Slack;
using Ombi.Core.Rule.Interfaces; using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Senders; using Ombi.Core.Senders;
using Ombi.Schedule.Jobs.Plex;
using Ombi.Schedule.Ombi; using Ombi.Schedule.Ombi;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher; using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher;
@ -121,6 +122,7 @@ namespace Ombi.DependencyInjection
public static void RegisterJobs(this IServiceCollection services) public static void RegisterJobs(this IServiceCollection services)
{ {
services.AddTransient<IPlexContentCacher, PlexContentCacher>(); services.AddTransient<IPlexContentCacher, PlexContentCacher>();
services.AddTransient<IPlexEpisodeCacher, PlexEpisodeCacher>();
services.AddTransient<IJobSetup, JobSetup>(); services.AddTransient<IJobSetup, JobSetup>();
services.AddTransient<IRadarrCacher, RadarrCacher>(); services.AddTransient<IRadarrCacher, RadarrCacher>();
services.AddTransient<IOmbiAutomaticUpdater, OmbiAutomaticUpdater>(); services.AddTransient<IOmbiAutomaticUpdater, OmbiAutomaticUpdater>();

@ -6,11 +6,12 @@ namespace Ombi.Helpers
{ {
public static EventId Authentication => new EventId(500); public static EventId Authentication => new EventId(500);
public static EventId ApiException => new EventId(1000); public static EventId Api => new EventId(1000);
public static EventId RadarrApiException => new EventId(1001); public static EventId RadarrApi => new EventId(1001);
public static EventId CacherException => new EventId(2000); public static EventId Cacher => new EventId(2000);
public static EventId RadarrCacherException => new EventId(2001); public static EventId RadarrCacher => new EventId(2001);
public static EventId PlexEpisodeCacher => new EventId(2001);
public static EventId MovieSender => new EventId(3000); public static EventId MovieSender => new EventId(3000);

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Ombi.Schedule.Jobs.Plex
{
public interface IPlexEpisodeCacher
{
Task Start();
}
}

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Api.Plex; using Ombi.Api.Plex;
using Ombi.Api.Plex.Models; using Ombi.Api.Plex.Models;
@ -42,18 +43,21 @@ namespace Ombi.Schedule.Jobs.Plex
{ {
public class PlexContentCacher : IPlexContentCacher public class PlexContentCacher : IPlexContentCacher
{ {
public PlexContentCacher(ISettingsService<PlexSettings> plex, IPlexApi plexApi, ILogger<PlexContentCacher> logger, IPlexContentRepository repo) public PlexContentCacher(ISettingsService<PlexSettings> plex, IPlexApi plexApi, ILogger<PlexContentCacher> logger, IPlexContentRepository repo,
IPlexEpisodeCacher epsiodeCacher)
{ {
Plex = plex; Plex = plex;
PlexApi = plexApi; PlexApi = plexApi;
Logger = logger; Logger = logger;
Repo = repo; Repo = repo;
EpisodeCacher = epsiodeCacher;
} }
private ISettingsService<PlexSettings> Plex { get; } private ISettingsService<PlexSettings> Plex { get; }
private IPlexApi PlexApi { get; } private IPlexApi PlexApi { get; }
private ILogger<PlexContentCacher> Logger { get; } private ILogger<PlexContentCacher> Logger { get; }
private IPlexContentRepository Repo { get; } private IPlexContentRepository Repo { get; }
private IPlexEpisodeCacher EpisodeCacher { get; }
public async Task CacheContent() public async Task CacheContent()
{ {
@ -71,10 +75,12 @@ namespace Ombi.Schedule.Jobs.Plex
try try
{ {
await StartTheCache(plexSettings); await StartTheCache(plexSettings);
BackgroundJob.Enqueue(() => EpisodeCacher.Start());
} }
catch (Exception e) catch (Exception e)
{ {
Logger.LogWarning(LoggingEvents.CacherException, e, "Exception thrown when attempting to cache the Plex Content"); Logger.LogWarning(LoggingEvents.Cacher, e, "Exception thrown when attempting to cache the Plex Content");
} }
} }

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Hangfire.Common;
using Microsoft.Extensions.Logging;
using Ombi.Api.Plex;
using Ombi.Api.Plex.Models;
using Ombi.Api.Plex.Models.Server;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models.External;
using Ombi.Helpers;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Serilog;
namespace Ombi.Schedule.Jobs.Plex
{
public class PlexEpisodeCacher : IPlexEpisodeCacher
{
public PlexEpisodeCacher(ISettingsService<PlexSettings> s, ILogger<PlexEpisodeCacher> log, IPlexApi plexApi,
IPlexContentRepository repo)
{
_settings = s;
_log = log;
_api = plexApi;
_repo = repo;
}
private readonly ISettingsService<PlexSettings> _settings;
private readonly ILogger<PlexEpisodeCacher> _log;
private readonly IPlexApi _api;
private readonly IPlexContentRepository _repo;
public async Task Start()
{
try
{
var s = await _settings.GetSettingsAsync();
if (!s.Enable)
{
return;
}
foreach (var server in s.Servers)
{
await Cache(server);
}
}
catch (Exception e)
{
_log.LogError(LoggingEvents.Cacher, e, "Caching Episodes Failed");
}
}
private async Task Cache(PlexServers settings)
{
if (!Validate(settings))
{
return;
}
// Get the librarys and then get the tv section
var sections = await _api.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);
// Filter the libSections
var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(Jobs.PlexContentCacher.PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase));
foreach (var section in tvSections)
{
if (settings.PlexSelectedLibraries.Any())
{
// Make sure we have enabled this
var keys = settings.PlexSelectedLibraries.Where(x => x.Enabled).Select(x => x.Key.ToString()).ToList();
if (!keys.Contains(section.key))
{
// We are not monitoring this lib
continue;
}
// Get the episodes
await GetEpisodes(settings, section);
}
}
}
private async Task GetEpisodes(PlexServers settings, Directory section)
{
// Get the first 50
var currentPosition = 0;
var ResultCount = 50;
var episodes = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, ResultCount);
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.size}");
await ProcessEpsiodes(episodes);
currentPosition += ResultCount;
while (currentPosition < episodes.MediaContainer.size)
{
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
ResultCount);
await ProcessEpsiodes(ep);
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {ResultCount} more episodes. Total Remaining {currentPosition - episodes.MediaContainer.size}");
currentPosition += ResultCount;
}
}
private async Task ProcessEpsiodes(PlexContainer episodes)
{
var ep = new HashSet<PlexEpisode>();
foreach (var episode in episodes.MediaContainer.Metadata)
{
// I don't think we need to get the metadata, we only need to get the metadata if we need the provider id (TheTvDbid). Why do we need it for episodes?
// We have the parent and grandparent rating keys to link up to the season and series
//var metadata = _api.GetEpisodeMetaData(server.PlexAuthToken, server.FullUri, episode.ratingKey);
ep.Add(new PlexEpisode
{
EpisodeNumber = episode.index,
SeasonNumber = episode.parentIndex,
GrandparentKey = episode.grandparentKey,
ParentKey = episode.parentKey,
Key = episode.key,
Title = episode.title
});
}
await _repo.AddRange(ep);
}
private bool Validate(PlexServers settings)
{
if (string.IsNullOrEmpty(settings.PlexAuthToken))
{
return false ;
}
return true;
}
}
}

@ -59,7 +59,7 @@ namespace Ombi.Schedule.Jobs.Radarr
} }
catch (System.Exception ex) catch (System.Exception ex)
{ {
Logger.LogError(LoggingEvents.CacherException, ex, "Failed caching queued items from Radarr"); Logger.LogError(LoggingEvents.Cacher, ex, "Failed caching queued items from Radarr");
} }
} }
} }

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace Ombi.Settings.Settings.Models
{
public class AuthenticationSettings
{
/// <summary>
/// This determins if Plex and/or Emby users can log into Ombi
/// </summary>
/// <value>
/// <c>true</c> if [allow external users to authenticate]; otherwise, <c>false</c>.
/// </value>
public bool AllowExternalUsersToAuthenticate { get; set; }
// Password Options
public bool RequireDigit { get; set; }
public int RequiredLength { get; set; }
public bool RequireLowercase { get; set; }
public bool RequireNonAlphanumeric { get; set; }
public bool RequireUppercase { get; set; }
}
}

@ -17,7 +17,7 @@ namespace Ombi.Core.Settings.Models.External
public string PlexAuthToken { get; set; } public string PlexAuthToken { get; set; }
public string MachineIdentifier { get; set; } public string MachineIdentifier { get; set; }
public List<PlexSelectedLibraries> PlexSelectedLibraries { get; set; } public List<PlexSelectedLibraries> PlexSelectedLibraries { get; set; } = new List<PlexSelectedLibraries>();
} }
public class PlexSelectedLibraries public class PlexSelectedLibraries
{ {

@ -7,6 +7,5 @@
public bool Wizard { get; set; } public bool Wizard { get; set; }
public string ApiKey { get; set; } public string ApiKey { get; set; }
public bool AllowExternalUsersToAuthenticate { get; set; }
} }
} }

@ -15,6 +15,7 @@ namespace Ombi.Store.Context
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
DbSet<GlobalSettings> Settings { get; set; } DbSet<GlobalSettings> Settings { get; set; }
DbSet<PlexContent> PlexContent { get; set; } DbSet<PlexContent> PlexContent { get; set; }
DbSet<PlexEpisode> PlexEpisode { get; set; }
DbSet<RadarrCache> RadarrCache { get; set; } DbSet<RadarrCache> RadarrCache { get; set; }
DatabaseFacade Database { get; } DatabaseFacade Database { get; }
EntityEntry<T> Entry<T>(T entry) where T : class; EntityEntry<T> Entry<T>(T entry) where T : class;

@ -26,6 +26,7 @@ namespace Ombi.Store.Context
public DbSet<NotificationTemplates> NotificationTemplates { get; set; } public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
public DbSet<GlobalSettings> Settings { get; set; } public DbSet<GlobalSettings> Settings { get; set; }
public DbSet<PlexContent> PlexContent { get; set; } public DbSet<PlexContent> PlexContent { get; set; }
public DbSet<PlexEpisode> PlexEpisode { get; set; }
public DbSet<RadarrCache> RadarrCache { get; set; } public DbSet<RadarrCache> RadarrCache { get; set; }
public DbSet<MovieRequests> MovieRequests { get; set; } public DbSet<MovieRequests> MovieRequests { get; set; }

@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Ombi.Store.Entities
{
[Table("PlexEpisode")]
public class PlexEpisode : Entity
{
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string Key { get; set; } // RatingKey
public string Title { get; set; }
/// <summary>
/// The Show key
/// </summary>
/// <value>
/// The parent key.
/// </value>
public string ParentKey { get; set; }
/// <summary>
/// The Series key
/// </summary>
/// <value>
/// The grandparent key.
/// </value>
public string GrandparentKey { get; set; }
}
}

@ -10,7 +10,7 @@ using Ombi.Helpers;
namespace Ombi.Store.Migrations namespace Ombi.Store.Migrations
{ {
[DbContext(typeof(OmbiContext))] [DbContext(typeof(OmbiContext))]
[Migration("20170811145836_Inital")] [Migration("20170823144220_Inital")]
partial class Inital partial class Inital
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -271,6 +271,28 @@ namespace Ombi.Store.Migrations
b.ToTable("PlexContent"); b.ToTable("PlexContent");
}); });
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<string>("GrandparentKey");
b.Property<string>("Key");
b.Property<string>("ParentKey");
b.Property<int>("SeasonNumber");
b.Property<string>("Title");
b.HasKey("Id");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")

@ -144,6 +144,24 @@ namespace Ombi.Store.Migrations
table.PrimaryKey("PK_PlexContent", x => x.Id); table.PrimaryKey("PK_PlexContent", x => x.Id);
}); });
migrationBuilder.CreateTable(
name: "PlexEpisode",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
EpisodeNumber = table.Column<int>(nullable: false),
GrandparentKey = table.Column<string>(nullable: true),
Key = table.Column<string>(nullable: true),
ParentKey = table.Column<string>(nullable: true),
SeasonNumber = table.Column<int>(nullable: false),
Title = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PlexEpisode", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "RadarrCache", name: "RadarrCache",
columns: table => new columns: table => new
@ -596,6 +614,9 @@ namespace Ombi.Store.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "NotificationTemplates"); name: "NotificationTemplates");
migrationBuilder.DropTable(
name: "PlexEpisode");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "PlexSeasonsContent"); name: "PlexSeasonsContent");

@ -270,6 +270,28 @@ namespace Ombi.Store.Migrations
b.ToTable("PlexContent"); b.ToTable("PlexContent");
}); });
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("EpisodeNumber");
b.Property<string>("GrandparentKey");
b.Property<string>("Key");
b.Property<string>("ParentKey");
b.Property<int>("SeasonNumber");
b.Property<string>("Title");
b.HasKey("Id");
b.ToTable("PlexEpisode");
});
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Store.Entities; using Ombi.Store.Entities;
@ -13,5 +14,9 @@ namespace Ombi.Store.Repository
Task<PlexContent> Get(string providerId); Task<PlexContent> Get(string providerId);
Task<PlexContent> GetByKey(string key); Task<PlexContent> GetByKey(string key);
Task Update(PlexContent existingContent); Task Update(PlexContent existingContent);
IQueryable<PlexEpisode> GetAllEpisodes();
Task<PlexEpisode> Add(PlexEpisode content);
Task<PlexEpisode> GetEpisodeByKey(string key);
Task AddRange(IEnumerable<PlexEpisode> content);
} }
} }

@ -26,6 +26,7 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Ombi.Store.Context; using Ombi.Store.Context;
@ -81,5 +82,26 @@ namespace Ombi.Store.Repository
Db.PlexContent.Update(existingContent); Db.PlexContent.Update(existingContent);
await Db.SaveChangesAsync(); await Db.SaveChangesAsync();
} }
public IQueryable<PlexEpisode> GetAllEpisodes()
{
return Db.PlexEpisode.AsQueryable();
}
public async Task<PlexEpisode> Add(PlexEpisode content)
{
await Db.PlexEpisode.AddAsync(content);
await Db.SaveChangesAsync();
return content;
}
public async Task<PlexEpisode> GetEpisodeByKey(string key)
{
return await Db.PlexEpisode.FirstOrDefaultAsync(x => x.Key == key);
}
public async Task AddRange(IEnumerable<PlexEpisode> content)
{
Db.PlexEpisode.AddRange(content);
await Db.SaveChangesAsync();
}
} }
} }

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -50,6 +51,10 @@ namespace Ombi.Store.Repository
public GlobalSettings Get(string pageName) public GlobalSettings Get(string pageName)
{ {
var entity = Db.Settings.FirstOrDefault(x => x.SettingsName == pageName); var entity = Db.Settings.FirstOrDefault(x => x.SettingsName == pageName);
if (entity == null)
{
throw new ArgumentNullException($"The setting {pageName} does not exist");
}
Db.Entry(entity).Reload(); Db.Entry(entity).Reload();
return entity; return entity;
} }

@ -87,3 +87,15 @@ export interface ICustomizationSettings extends ISettings {
applicationName: string, applicationName: string,
logo: string, logo: string,
} }
export interface IAuthenticationSettings extends ISettings {
allowExternalUsersToAuthenticate: boolean,
// Password
requiredDigit: boolean,
requiredLength: number,
requiredLowercase: boolean,
requireNonAlphanumeric: boolean,
requireUppercase:boolean,
}

@ -11,7 +11,8 @@ import {
ISonarrSettings, ISonarrSettings,
ILandingPageSettings, ILandingPageSettings,
ICustomizationSettings, ICustomizationSettings,
IRadarrSettings IRadarrSettings,
IAuthenticationSettings
} from '../interfaces/ISettings'; } from '../interfaces/ISettings';
import { import {
IEmailNotificationSettings, IEmailNotificationSettings,
@ -80,6 +81,17 @@ export class SettingsService extends ServiceAuthHelpers {
.map(this.extractData).catch(this.handleError); .map(this.extractData).catch(this.handleError);
} }
getAuthentication(): Observable<IAuthenticationSettings> {
return this.httpAuth.get(`${this.url}/Authentication`).map(this.extractData)
.catch(this.handleError);
}
saveAuthentication(settings: IAuthenticationSettings): Observable<boolean> {
return this.httpAuth.post(`${this.url}/Authentication`, JSON.stringify(settings), { headers: this.headers })
.map(this.extractData).catch(this.handleError);
}
// Using http since we need it not to be authenticated to get the landing page settings // Using http since we need it not to be authenticated to get the landing page settings
getLandingPage(): Observable<ILandingPageSettings> { getLandingPage(): Observable<ILandingPageSettings> {
return this.nonAuthHttp.get(`${this.url}/LandingPage`).map(this.extractData).catch(this.handleError); return this.nonAuthHttp.get(`${this.url}/LandingPage`).map(this.extractData).catch(this.handleError);

@ -47,7 +47,7 @@ namespace Ombi.Controllers.External
settings.Enable = true; settings.Enable = true;
settings.Servers = new List<PlexServers> { new PlexServers{ settings.Servers = new List<PlexServers> { new PlexServers{
PlexAuthToken = result.user.authentication_token, PlexAuthToken = result.user.authentication_token,
Id = new Random().Next(), Id = new Random().Next(),
Ip = servers.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(), Ip = servers.LocalAddresses.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(),
MachineIdentifier = servers.MachineIdentifier, MachineIdentifier = servers.MachineIdentifier,
@ -87,7 +87,7 @@ PlexAuthToken = result.user.authentication_token,
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("Libraries")] [HttpPost("Libraries")]
public async Task<PlexLibraries> GetPlexLibraries([FromBody] PlexServers settings) public async Task<PlexContainer> GetPlexLibraries([FromBody] PlexServers settings)
{ {
var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri); var libs = await PlexApi.GetLibrarySections(settings.PlexAuthToken, settings.FullUri);

@ -192,6 +192,27 @@ namespace Ombi.Controllers
return await Get<RadarrSettings>(); return await Get<RadarrSettings>();
} }
/// <summary>
/// Save the Authentication settings.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
[HttpPost("authentication")]
public async Task<bool> AuthenticationsSettings([FromBody]AuthenticationSettings settings)
{
return await Save(settings);
}
/// <summary>
/// Gets the Authentication Settings.
/// </summary>
/// <returns></returns>
[HttpGet("authentication")]
public async Task<AuthenticationSettings> AuthenticationsSettings()
{
return await Get<AuthenticationSettings>();
}
/// <summary> /// <summary>
/// Save the Radarr settings. /// Save the Radarr settings.
/// </summary> /// </summary>

Loading…
Cancel
Save