mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-14 17:22:54 -07:00
parent
bf043fc76e
commit
0e6462bbd5
31 changed files with 410 additions and 33 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
9
src/Ombi.Schedule/Jobs/Plex/IPlexEpisodeCacher.cs
Normal file
9
src/Ombi.Schedule/Jobs/Plex/IPlexEpisodeCacher.cs
Normal file
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
146
src/Ombi.Schedule/Jobs/Plex/PlexEpisodeCacher.cs
Normal file
146
src/Ombi.Schedule/Jobs/Plex/PlexEpisodeCacher.cs
Normal file
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs
Normal file
22
src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs
Normal file
|
@ -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; }
|
||||||
|
|
27
src/Ombi.Store/Entities/PlexEpisode.cs
Normal file
27
src/Ombi.Store/Entities/PlexEpisode.cs
Normal file
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,4 +86,16 @@ export interface ILandingPageSettings extends ISettings {
|
||||||
export interface ICustomizationSettings extends ISettings {
|
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…
Add table
Add a link
Reference in a new issue