mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-14 02:26:55 -07:00
Merge pull request #7 from tidusjar/develop
Bringing develop up to date
This commit is contained in:
commit
ccb496f252
86 changed files with 4083 additions and 351 deletions
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.Friends;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
using Ombi.Api.Plex.Models.Server;
|
||||
using Ombi.Api.Plex.Models.Status;
|
||||
|
||||
|
@ -20,5 +22,8 @@ namespace Ombi.Api.Plex
|
|||
Task<PlexFriends> GetUsers(string authToken);
|
||||
Task<PlexAccount> GetAccount(string authToken);
|
||||
Task<PlexMetadata> GetRecentlyAdded(string authToken, string uri, string sectionId);
|
||||
Task<OAuthPin> CreatePin();
|
||||
Task<OAuthPin> GetPin(int pinId);
|
||||
Uri GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard);
|
||||
}
|
||||
}
|
27
src/Ombi.Api.Plex/Models/OAuth/OAuthPin.cs
Normal file
27
src/Ombi.Api.Plex/Models/OAuth/OAuthPin.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
namespace Ombi.Api.Plex.Models.OAuth
|
||||
{
|
||||
public class OAuthPin
|
||||
{
|
||||
public int id { get; set; }
|
||||
public string code { get; set; }
|
||||
public bool trusted { get; set; }
|
||||
public string clientIdentifier { get; set; }
|
||||
public Location location { get; set; }
|
||||
public int expiresIn { get; set; }
|
||||
public DateTime createdAt { get; set; }
|
||||
public DateTime expiresAt { get; set; }
|
||||
public string authToken { get; set; }
|
||||
}
|
||||
|
||||
public class Location
|
||||
{
|
||||
public string code { get; set; }
|
||||
public string country { get; set; }
|
||||
public string city { get; set; }
|
||||
public string subdivisions { get; set; }
|
||||
public string coordinates { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,53 @@
|
|||
using System.Net.Http;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.Friends;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
using Ombi.Api.Plex.Models.Server;
|
||||
using Ombi.Api.Plex.Models.Status;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
|
||||
namespace Ombi.Api.Plex
|
||||
{
|
||||
public class PlexApi : IPlexApi
|
||||
{
|
||||
public PlexApi(IApi api)
|
||||
public PlexApi(IApi api, ISettingsService<CustomizationSettings> settings)
|
||||
{
|
||||
Api = api;
|
||||
_custom = settings;
|
||||
}
|
||||
|
||||
private IApi Api { get; }
|
||||
private readonly ISettingsService<CustomizationSettings> _custom;
|
||||
|
||||
private string _app;
|
||||
private string ApplicationName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_app))
|
||||
{
|
||||
var settings = _custom.GetSettings();
|
||||
if (settings.ApplicationName.IsNullOrEmpty())
|
||||
{
|
||||
_app = "Ombi";
|
||||
}
|
||||
else
|
||||
{
|
||||
_app = settings.ApplicationName;
|
||||
}
|
||||
|
||||
return _app;
|
||||
}
|
||||
|
||||
return _app;
|
||||
}
|
||||
}
|
||||
|
||||
private const string SignInUri = "https://plex.tv/users/sign_in.json";
|
||||
private const string FriendsUri = "https://plex.tv/pms/friends/all";
|
||||
|
@ -156,6 +189,50 @@ namespace Ombi.Api.Plex
|
|||
return await Api.Request<PlexMetadata>(request);
|
||||
}
|
||||
|
||||
public async Task<OAuthPin> CreatePin()
|
||||
{
|
||||
var request = new Request($"api/v2/pins", "https://plex.tv/", HttpMethod.Post);
|
||||
request.AddQueryString("strong", "true");
|
||||
AddHeaders(request);
|
||||
|
||||
return await Api.Request<OAuthPin>(request);
|
||||
}
|
||||
|
||||
public async Task<OAuthPin> GetPin(int pinId)
|
||||
{
|
||||
var request = new Request($"api/v2/pins/{pinId}", "https://plex.tv/", HttpMethod.Get);
|
||||
AddHeaders(request);
|
||||
|
||||
return await Api.Request<OAuthPin>(request);
|
||||
}
|
||||
|
||||
public Uri GetOAuthUrl(int pinId, string code, string applicationUrl, bool wizard)
|
||||
{
|
||||
var request = new Request("auth#", "https://app.plex.tv", HttpMethod.Get);
|
||||
AddHeaders(request);
|
||||
var forwardUrl = wizard
|
||||
? new Request($"Wizard/OAuth/{pinId}", applicationUrl, HttpMethod.Get)
|
||||
: new Request($"Login/OAuth/{pinId}", applicationUrl, HttpMethod.Get);
|
||||
|
||||
request.AddQueryString("forwardUrl", forwardUrl.FullUri.ToString());
|
||||
request.AddQueryString("pinID", pinId.ToString());
|
||||
request.AddQueryString("code", code);
|
||||
request.AddQueryString("context[device][product]", "Ombi");
|
||||
request.AddQueryString("context[device][environment]", "bundled");
|
||||
request.AddQueryString("clientID", $"OmbiV3");
|
||||
|
||||
if (request.FullUri.Fragment.Equals("#"))
|
||||
{
|
||||
var uri = request.FullUri.ToString();
|
||||
var withoutEnd = uri.Remove(uri.Length - 1, 1);
|
||||
var startOfQueryLocation = withoutEnd.IndexOf('?');
|
||||
var better = withoutEnd.Insert(startOfQueryLocation, "#");
|
||||
request.FullUri = new Uri(better);
|
||||
}
|
||||
|
||||
return request.FullUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the required headers and also the authorization header
|
||||
/// </summary>
|
||||
|
@ -174,7 +251,7 @@ namespace Ombi.Api.Plex
|
|||
private void AddHeaders(Request request)
|
||||
{
|
||||
request.AddHeader("X-Plex-Client-Identifier", $"OmbiV3");
|
||||
request.AddHeader("X-Plex-Product", "Ombi");
|
||||
request.AddHeader("X-Plex-Product", ApplicationName);
|
||||
request.AddHeader("X-Plex-Version", "3");
|
||||
request.AddContentHeader("Content-Type", request.ContentType == ContentType.Json ? "application/json" : "application/xml");
|
||||
request.AddHeader("Accept", "application/json");
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Pushover.Models;
|
||||
|
@ -17,7 +18,7 @@ namespace Ombi.Api.Pushover
|
|||
|
||||
public async Task<PushoverResponse> PushAsync(string accessToken, string message, string userToken)
|
||||
{
|
||||
var request = new Request($"messages.json?token={accessToken}&user={userToken}&message={message}", PushoverEndpoint, HttpMethod.Post);
|
||||
var request = new Request($"messages.json?token={accessToken}&user={userToken}&message={WebUtility.HtmlEncode(message)}", PushoverEndpoint, HttpMethod.Post);
|
||||
|
||||
var result = await _api.Request<PushoverResponse>(request);
|
||||
return result;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Polly" Version="5.8.0" />
|
||||
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ombi.Api
|
|||
{
|
||||
public Request()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Request(string endpoint, string baseUrl, HttpMethod http, ContentType contentType = ContentType.Json)
|
||||
|
@ -105,10 +105,10 @@ namespace Ombi.Api
|
|||
hasQuery = true;
|
||||
startingTag = builder.Query.Contains("?") ? "&" : "?";
|
||||
}
|
||||
|
||||
builder.Query = hasQuery
|
||||
? $"{builder.Query}{startingTag}{key}={value}"
|
||||
: $"{startingTag}{key}={value}";
|
||||
|
||||
_modified = builder.Uri;
|
||||
}
|
||||
|
||||
|
|
76
src/Ombi.Core/Authentication/PlexOAuthManager.cs
Normal file
76
src/Ombi.Core/Authentication/PlexOAuthManager.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Settings.Settings.Models;
|
||||
|
||||
namespace Ombi.Core.Authentication
|
||||
{
|
||||
public class PlexOAuthManager : IPlexOAuthManager
|
||||
{
|
||||
public PlexOAuthManager(IPlexApi api, ISettingsService<CustomizationSettings> settings)
|
||||
{
|
||||
_api = api;
|
||||
_customizationSettingsService = settings;
|
||||
}
|
||||
|
||||
private readonly IPlexApi _api;
|
||||
private readonly ISettingsService<CustomizationSettings> _customizationSettingsService;
|
||||
|
||||
public async Task<OAuthPin> RequestPin()
|
||||
{
|
||||
var pin = await _api.CreatePin();
|
||||
return pin;
|
||||
}
|
||||
|
||||
public async Task<string> GetAccessTokenFromPin(int pinId)
|
||||
{
|
||||
var pin = await _api.GetPin(pinId);
|
||||
if (pin.expiresAt < DateTime.UtcNow)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (pin.authToken.IsNullOrEmpty())
|
||||
{
|
||||
// Looks like we do not have a pin yet, we should retry a few times.
|
||||
var retryCount = 0;
|
||||
var retryMax = 5;
|
||||
var retryWaitMs = 1000;
|
||||
while (pin.authToken.IsNullOrEmpty() && retryCount < retryMax)
|
||||
{
|
||||
retryCount++;
|
||||
await Task.Delay(retryWaitMs);
|
||||
pin = await _api.GetPin(pinId);
|
||||
}
|
||||
}
|
||||
return pin.authToken;
|
||||
}
|
||||
|
||||
public async Task<PlexAccount> GetAccount(string accessToken)
|
||||
{
|
||||
return await _api.GetAccount(accessToken);
|
||||
}
|
||||
|
||||
public async Task<Uri> GetOAuthUrl(int pinId, string code)
|
||||
{
|
||||
var settings = await _customizationSettingsService.GetSettingsAsync();
|
||||
if (settings.ApplicationUrl.IsNullOrEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = _api.GetOAuthUrl(pinId, code, settings.ApplicationUrl, false);
|
||||
return url;
|
||||
}
|
||||
|
||||
public Uri GetWizardOAuthUrl(int pinId, string code, string websiteAddress)
|
||||
{
|
||||
var url = _api.GetOAuthUrl(pinId, code, websiteAddress, true);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,14 +32,7 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
private OmbiUser _user;
|
||||
protected async Task<OmbiUser> GetUser()
|
||||
{
|
||||
if (IsApiUser)
|
||||
{
|
||||
return new OmbiUser
|
||||
{
|
||||
UserName = Username,
|
||||
};
|
||||
}
|
||||
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.UserName == Username));
|
||||
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.UserName.Equals(Username, StringComparison.CurrentCultureIgnoreCase)));
|
||||
}
|
||||
|
||||
protected async Task<string> UserAlias()
|
||||
|
@ -49,10 +42,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
|
||||
protected async Task<bool> IsInRole(string roleName)
|
||||
{
|
||||
if (IsApiUser && roleName != OmbiRoles.Disabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return await UserManager.IsInRoleAsync(await GetUser(), roleName);
|
||||
}
|
||||
|
||||
|
@ -72,7 +61,5 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
var ruleResults = await Rules.StartSpecificRules(model, rule);
|
||||
return ruleResults;
|
||||
}
|
||||
|
||||
private bool IsApiUser => Username.Equals("Api", StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
}
|
|
@ -63,13 +63,17 @@ namespace Ombi.Core.Engine
|
|||
var recentlyAddedLog = new HashSet<RecentlyAddedLog>();
|
||||
foreach (var p in plexContent)
|
||||
{
|
||||
if (!p.HasTheMovieDb)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (p.Type == PlexMediaTypeEntity.Movie)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentId = p.Id,
|
||||
ContentId = int.Parse(p.TheMovieDbId),
|
||||
ContentType = ContentType.Parent
|
||||
});
|
||||
}
|
||||
|
@ -78,12 +82,18 @@ namespace Ombi.Core.Engine
|
|||
// Add the episodes
|
||||
foreach (var ep in p.Episodes)
|
||||
{
|
||||
if (!ep.Series.HasTvDb)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentId = ep.Id,
|
||||
ContentType = ContentType.Episode
|
||||
ContentId = int.Parse(ep.Series.TvDbId),
|
||||
ContentType = ContentType.Episode,
|
||||
EpisodeNumber = ep.EpisodeNumber,
|
||||
SeasonNumber = ep.SeasonNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -91,13 +101,17 @@ namespace Ombi.Core.Engine
|
|||
|
||||
foreach (var e in embyContent)
|
||||
{
|
||||
if (e.TheMovieDbId.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (e.Type == EmbyMediaType.Movie)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Emby,
|
||||
ContentId = e.Id,
|
||||
ContentId = int.Parse(e.TheMovieDbId),
|
||||
ContentType = ContentType.Parent
|
||||
});
|
||||
}
|
||||
|
@ -106,12 +120,18 @@ namespace Ombi.Core.Engine
|
|||
// Add the episodes
|
||||
foreach (var ep in e.Episodes)
|
||||
{
|
||||
if (ep.Series.TvDbId.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Emby,
|
||||
ContentId = ep.Id,
|
||||
ContentType = ContentType.Episode
|
||||
ContentId = int.Parse(ep.Series.TvDbId),
|
||||
ContentType = ContentType.Episode,
|
||||
EpisodeNumber = ep.EpisodeNumber,
|
||||
SeasonNumber = ep.SeasonNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ namespace Ombi.Core.Engine
|
|||
results.ImdbId = request.ImdbId;
|
||||
results.Overview = request.Overview;
|
||||
results.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath);
|
||||
results.Background = PosterPathHelper.FixBackgroundPath(request.Background);
|
||||
results.QualityOverride = request.QualityOverride;
|
||||
results.RootFolder = request.RootFolder;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Ombi.Core.Helpers
|
|||
public ChildRequests ChildRequest { get; set; }
|
||||
public List<SeasonsViewModel> TvRequests { get; protected set; }
|
||||
public string PosterPath { get; protected set; }
|
||||
public string BackdropPath { get; protected set; }
|
||||
public DateTime FirstAir { get; protected set; }
|
||||
public TvRequests NewRequest { get; protected set; }
|
||||
protected TvMazeShow ShowInfo { get; set; }
|
||||
|
@ -44,6 +45,7 @@ namespace Ombi.Core.Helpers
|
|||
{
|
||||
var showIds = await MovieDbApi.GetTvExternals(result.Id);
|
||||
ShowInfo.externals.imdb = showIds.imdb_id;
|
||||
BackdropPath = result.BackdropPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +242,8 @@ namespace Ombi.Core.Helpers
|
|||
ImdbId = ShowInfo.externals?.imdb ?? string.Empty,
|
||||
TvDbId = tv.TvDbId,
|
||||
ChildRequests = new List<ChildRequests>(),
|
||||
TotalSeasons = tv.Seasons.Count()
|
||||
TotalSeasons = tv.Seasons.Count(),
|
||||
Background = BackdropPath
|
||||
};
|
||||
NewRequest.ChildRequests.Add(ChildRequest);
|
||||
|
||||
|
|
16
src/Ombi.Core/IPlexOAuthManager.cs
Normal file
16
src/Ombi.Core/IPlexOAuthManager.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Api.Plex.Models.OAuth;
|
||||
|
||||
namespace Ombi.Core.Authentication
|
||||
{
|
||||
public interface IPlexOAuthManager
|
||||
{
|
||||
Task<string> GetAccessTokenFromPin(int pinId);
|
||||
Task<OAuthPin> RequestPin();
|
||||
Task<Uri> GetOAuthUrl(int pinId, string code);
|
||||
Uri GetWizardOAuthUrl(int pinId, string code, string websiteAddress);
|
||||
Task<PlexAccount> GetAccount(string accessToken);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Ombi.Core.Models.Search
|
|||
public bool Requested { get; set; }
|
||||
public bool Available { get; set; }
|
||||
public string PlexUrl { get; set; }
|
||||
public string EmbyUrl { get; set; }
|
||||
public string Quality { get; set; }
|
||||
public abstract RequestType Type { get; }
|
||||
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="3.0.1" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.19" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.5" />
|
||||
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.0.0-alpha6-79" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Ombi.Core.Rule.Rules.Search
|
|||
if (item != null)
|
||||
{
|
||||
obj.Available = true;
|
||||
obj.EmbyUrl = item.Url;
|
||||
|
||||
if (obj.Type == RequestType.TvShow)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ using Ombi.Store.Repository.Requests;
|
|||
using Ombi.Updater;
|
||||
using PlexContentCacher = Ombi.Schedule.Jobs.Plex;
|
||||
using Ombi.Api.Telegram;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Processor;
|
||||
using Ombi.Schedule.Jobs.Plex.Interfaces;
|
||||
using Ombi.Schedule.Jobs.SickRage;
|
||||
|
@ -82,6 +83,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IRecentlyAddedEngine, RecentlyAddedEngine>();
|
||||
services.AddTransient<ITvSender, TvSender>();
|
||||
services.AddTransient<IMassEmailSender, MassEmailSender>();
|
||||
services.AddTransient<IPlexOAuthManager, PlexOAuthManager>();
|
||||
}
|
||||
public static void RegisterHttp(this IServiceCollection services)
|
||||
{
|
||||
|
|
17
src/Ombi.Helpers/EmbyHelper.cs
Normal file
17
src/Ombi.Helpers/EmbyHelper.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Helpers
|
||||
{
|
||||
public class EmbyHelper
|
||||
{
|
||||
public static string GetEmbyMediaUrl(string mediaId)
|
||||
{
|
||||
var url =
|
||||
$"http://app.emby.media/itemdetails.html?id={mediaId}";
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,5 +14,12 @@ namespace Ombi.Helpers
|
|||
yield return source1;
|
||||
}
|
||||
}
|
||||
|
||||
public static HashSet<T> ToHashSet<T>(
|
||||
this IEnumerable<T> source,
|
||||
IEqualityComparer<T> comparer = null)
|
||||
{
|
||||
return new HashSet<T>(source, comparer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
<PackageReference Include="EasyCrypto" Version="3.3.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.0.0-pre-05" />
|
||||
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -18,5 +18,19 @@ namespace Ombi.Helpers
|
|||
|
||||
return poster;
|
||||
}
|
||||
|
||||
public static string FixBackgroundPath(string background)
|
||||
{
|
||||
// https://image.tmdb.org/t/p/w1280/fJAvGOitU8y53ByeHnM4avtKFaG.jpg
|
||||
|
||||
if (background.Contains("image.tmdb.org", CompareOptions.IgnoreCase))
|
||||
{
|
||||
// Somehow we have a full path here for the poster, we only want the last segment
|
||||
var backgroundSegments = background.Split('/');
|
||||
return backgroundSegments.Last();
|
||||
}
|
||||
|
||||
return background;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ensure.That" Version="7.0.0-pre32" />
|
||||
<PackageReference Include="MailKit" Version="1.20.0" />
|
||||
<PackageReference Include="MailKit" Version="2.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -66,6 +66,8 @@ namespace Ombi.Schedule
|
|||
RecurringJob.AddOrUpdate(() => _embyUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _plexUserImporter.Start(), JobSettingsHelper.UserImporter(s));
|
||||
RecurringJob.AddOrUpdate(() => _newsletter.Start(), JobSettingsHelper.Newsletter(s));
|
||||
|
||||
BackgroundJob.Enqueue(() => _refreshMetadata.Start());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
Title = tvInfo.Name,
|
||||
Type = EmbyMediaType.Series,
|
||||
EmbyId = tvShow.Id,
|
||||
Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id),
|
||||
AddedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
@ -135,6 +136,7 @@ namespace Ombi.Schedule.Jobs.Emby
|
|||
Title = movieInfo.Name,
|
||||
Type = EmbyMediaType.Movie,
|
||||
EmbyId = movieInfo.Id,
|
||||
Url = EmbyHelper.GetEmbyMediaUrl(movieInfo.Id),
|
||||
AddedAt = DateTime.UtcNow,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MailKit;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Api.TvMaze;
|
||||
|
@ -26,7 +29,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, IRepository<RecentlyAddedLog> addedLog,
|
||||
IMovieDbApi movieApi, ITvMazeApi tvApi, IEmailProvider email, ISettingsService<CustomizationSettings> custom,
|
||||
ISettingsService<EmailNotificationSettings> emailSettings, INotificationTemplatesRepository templateRepo,
|
||||
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter)
|
||||
UserManager<OmbiUser> um, ISettingsService<NewsletterSettings> newsletter, ILogger<NewsletterJob> log)
|
||||
{
|
||||
_plex = plex;
|
||||
_emby = emby;
|
||||
|
@ -42,6 +45,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
_emailSettings.ClearCache();
|
||||
_customizationSettings.ClearCache();
|
||||
_newsletterSettings.ClearCache();
|
||||
_log = log;
|
||||
}
|
||||
|
||||
private readonly IPlexContentRepository _plex;
|
||||
|
@ -55,6 +59,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
private readonly ISettingsService<EmailNotificationSettings> _emailSettings;
|
||||
private readonly ISettingsService<NewsletterSettings> _newsletterSettings;
|
||||
private readonly UserManager<OmbiUser> _userManager;
|
||||
private readonly ILogger _log;
|
||||
|
||||
public async Task Start(NewsletterSettings settings, bool test)
|
||||
{
|
||||
|
@ -74,152 +79,172 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return;
|
||||
}
|
||||
|
||||
var customization = await _customizationSettings.GetSettingsAsync();
|
||||
|
||||
// Get the Content
|
||||
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||
var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||
|
||||
var addedLog = _recentlyAddedLog.GetAll();
|
||||
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||
|
||||
var addedPlexEpisodesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode).Select(x => x.ContentId);
|
||||
var addedEmbyEpisodesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode).Select(x => x.ContentId);
|
||||
|
||||
// Filter out the ones that we haven't sent yet
|
||||
var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && !addedPlexMovieLogIds.Contains(x.Id));
|
||||
var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !addedEmbyMoviesLogIds.Contains(x.Id));
|
||||
|
||||
var plexEpisodesToSend = _plex.GetAllEpisodes().Include(x => x.Series).Where(x => !addedPlexEpisodesLogIds.Contains(x.Id)).AsNoTracking();
|
||||
var embyEpisodesToSend = _emby.GetAllEpisodes().Include(x => x.Series).Where(x => !addedEmbyEpisodesLogIds.Contains(x.Id)).AsNoTracking();
|
||||
|
||||
var body = string.Empty;
|
||||
if (test)
|
||||
try
|
||||
{
|
||||
var plexm = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10);
|
||||
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
body = await BuildHtml(plexm, embym, plext, embyt, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
|
||||
if (body.IsNullOrEmpty())
|
||||
|
||||
|
||||
var customization = await _customizationSettings.GetSettingsAsync();
|
||||
// Get the Content
|
||||
var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||
var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
|
||||
|
||||
var addedLog = _recentlyAddedLog.GetAll();
|
||||
var addedPlexMovieLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||
var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
|
||||
|
||||
var addedPlexEpisodesLogIds =
|
||||
addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
|
||||
var addedEmbyEpisodesLogIds =
|
||||
addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);
|
||||
|
||||
// Filter out the ones that we haven't sent yet
|
||||
var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && !addedPlexMovieLogIds.Contains(int.Parse(x.TheMovieDbId)));
|
||||
var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !addedEmbyMoviesLogIds.Contains(int.Parse(x.TheMovieDbId)));
|
||||
_log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
|
||||
_log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
|
||||
|
||||
var plexEpisodesToSend =
|
||||
FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds);
|
||||
var embyEpisodesToSend = FilterEmbyEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).AsNoTracking(),
|
||||
addedEmbyEpisodesLogIds);
|
||||
|
||||
_log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count());
|
||||
_log.LogInformation("Emby Episodes to send: {0}", embyEpisodesToSend.Count());
|
||||
var body = string.Empty;
|
||||
if (test)
|
||||
{
|
||||
return;
|
||||
var plexm = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10);
|
||||
var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
|
||||
var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
|
||||
body = await BuildHtml(plexm, embym, plext, embyt, settings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!test)
|
||||
{
|
||||
// Get the users to send it to
|
||||
var users = await _userManager.GetUsersInRoleAsync(OmbiRoles.RecievesNewsletter);
|
||||
if (!users.Any())
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var emails in settings.ExternalEmails)
|
||||
{
|
||||
users.Add(new OmbiUser
|
||||
body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, settings);
|
||||
if (body.IsNullOrEmpty())
|
||||
{
|
||||
UserName = emails,
|
||||
Email = emails
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
var emailTasks = new List<Task>();
|
||||
foreach (var user in users)
|
||||
|
||||
if (!test)
|
||||
{
|
||||
if (user.Email.IsNullOrEmpty())
|
||||
// Get the users to send it to
|
||||
var users = await _userManager.GetUsersInRoleAsync(OmbiRoles.RecievesNewsletter);
|
||||
if (!users.Any())
|
||||
{
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
var messageContent = ParseTemplate(template, customization, user);
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
|
||||
emailTasks.Add(_email.Send(
|
||||
new NotificationMessage { Message = html, Subject = messageContent.Subject, To = user.Email },
|
||||
emailSettings));
|
||||
}
|
||||
|
||||
// Now add all of this to the Recently Added log
|
||||
var recentlyAddedLog = new HashSet<RecentlyAddedLog>();
|
||||
foreach (var p in plexContentMoviesToSend)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
foreach (var emails in settings.ExternalEmails)
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentType = ContentType.Parent,
|
||||
ContentId = p.Id
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
foreach (var p in plexEpisodesToSend)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
users.Add(new OmbiUser
|
||||
{
|
||||
UserName = emails,
|
||||
Email = emails
|
||||
});
|
||||
}
|
||||
var emailTasks = new List<Task>();
|
||||
foreach (var user in users)
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentType = ContentType.Episode,
|
||||
ContentId = p.Id
|
||||
});
|
||||
}
|
||||
// Get the users to send it to
|
||||
if (user.Email.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var e in embyContentMoviesToSend)
|
||||
{
|
||||
if (e.Type == EmbyMediaType.Movie)
|
||||
var messageContent = ParseTemplate(template, customization, user);
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
|
||||
emailTasks.Add(_email.Send(
|
||||
new NotificationMessage { Message = html, Subject = messageContent.Subject, To = user.Email },
|
||||
emailSettings));
|
||||
}
|
||||
|
||||
// Now add all of this to the Recently Added log
|
||||
var recentlyAddedLog = new HashSet<RecentlyAddedLog>();
|
||||
foreach (var p in plexContentMoviesToSend)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentType = ContentType.Parent,
|
||||
ContentId = int.Parse(p.TheMovieDbId),
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
foreach (var p in plexEpisodesToSend)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Plex,
|
||||
ContentType = ContentType.Episode,
|
||||
ContentId = int.Parse(p.Series.TvDbId),
|
||||
EpisodeNumber = p.EpisodeNumber,
|
||||
SeasonNumber = p.SeasonNumber
|
||||
});
|
||||
}
|
||||
foreach (var e in embyContentMoviesToSend)
|
||||
{
|
||||
if (e.Type == EmbyMediaType.Movie)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Emby,
|
||||
ContentType = ContentType.Parent,
|
||||
ContentId = int.Parse(e.TheMovieDbId),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var p in embyEpisodesToSend)
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Emby,
|
||||
ContentType = ContentType.Parent,
|
||||
ContentId = e.Id
|
||||
ContentType = ContentType.Episode,
|
||||
ContentId = int.Parse(p.Series.TvDbId),
|
||||
EpisodeNumber = p.EpisodeNumber,
|
||||
SeasonNumber = p.SeasonNumber
|
||||
});
|
||||
}
|
||||
await _recentlyAddedLog.AddRange(recentlyAddedLog);
|
||||
await Task.WhenAll(emailTasks.ToArray());
|
||||
}
|
||||
|
||||
foreach (var p in embyEpisodesToSend)
|
||||
else
|
||||
{
|
||||
recentlyAddedLog.Add(new RecentlyAddedLog
|
||||
var admins = await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin);
|
||||
foreach (var a in admins)
|
||||
{
|
||||
AddedAt = DateTime.Now,
|
||||
Type = RecentlyAddedType.Emby,
|
||||
ContentType = ContentType.Episode,
|
||||
ContentId = p.Id
|
||||
});
|
||||
}
|
||||
await _recentlyAddedLog.AddRange(recentlyAddedLog);
|
||||
if (a.Email.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var messageContent = ParseTemplate(template, customization, a);
|
||||
|
||||
await Task.WhenAll(emailTasks.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
var admins = await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin);
|
||||
foreach (var a in admins)
|
||||
{
|
||||
if (a.Email.IsNullOrEmpty())
|
||||
{
|
||||
continue;
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
|
||||
await _email.Send(
|
||||
new NotificationMessage { Message = html, Subject = messageContent.Subject, To = a.Email },
|
||||
emailSettings);
|
||||
}
|
||||
var messageContent = ParseTemplate(template, customization, a);
|
||||
|
||||
var email = new NewsletterTemplate();
|
||||
|
||||
var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);
|
||||
|
||||
await _email.Send(
|
||||
new NotificationMessage { Message = html, Subject = messageContent.Subject, To = a.Email },
|
||||
emailSettings);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.LogError(e, "Error when attempting to create newsletter");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,6 +254,40 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await Start(newsletterSettings, false);
|
||||
}
|
||||
|
||||
private HashSet<PlexEpisode> FilterPlexEpisodes(IEnumerable<PlexEpisode> source, IQueryable<RecentlyAddedLog> recentlyAdded)
|
||||
{
|
||||
var itemsToReturn = new HashSet<PlexEpisode>();
|
||||
foreach (var ep in source)
|
||||
{
|
||||
var tvDbId = int.Parse(ep.Series.TvDbId);
|
||||
if (recentlyAdded.Any(x => x.ContentId == tvDbId && x.EpisodeNumber == ep.EpisodeNumber && x.SeasonNumber == ep.SeasonNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemsToReturn.Add(ep);
|
||||
}
|
||||
|
||||
return itemsToReturn;
|
||||
}
|
||||
|
||||
private HashSet<EmbyEpisode> FilterEmbyEpisodes(IEnumerable<EmbyEpisode> source, IQueryable<RecentlyAddedLog> recentlyAdded)
|
||||
{
|
||||
var itemsToReturn = new HashSet<EmbyEpisode>();
|
||||
foreach (var ep in source)
|
||||
{
|
||||
var tvDbId = int.Parse(ep.Series.TvDbId);
|
||||
if (recentlyAdded.Any(x => x.ContentId == tvDbId && x.EpisodeNumber == ep.EpisodeNumber && x.SeasonNumber == ep.SeasonNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemsToReturn.Add(ep);
|
||||
}
|
||||
|
||||
return itemsToReturn;
|
||||
}
|
||||
|
||||
private NotificationMessageContent ParseTemplate(NotificationTemplates template, CustomizationSettings settings, OmbiUser username)
|
||||
{
|
||||
var resolver = new NotificationMessageResolver();
|
||||
|
@ -239,7 +298,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
return resolver.ParseMessage(template, curlys);
|
||||
}
|
||||
|
||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, IQueryable<PlexEpisode> plexEpisodes, IQueryable<EmbyEpisode> embyEp, NewsletterSettings settings)
|
||||
private async Task<string> BuildHtml(IQueryable<PlexServerContent> plexContentToSend, IQueryable<EmbyContent> embyContentToSend, HashSet<PlexEpisode> plexEpisodes, HashSet<EmbyEpisode> embyEp, NewsletterSettings settings)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
|
@ -285,8 +344,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
_log.LogError(e, "Error when Processing Plex Movies {0}", info.Title);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -315,7 +373,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
theMovieDbId = result.id.ToString();
|
||||
}
|
||||
|
||||
|
||||
var info = await _movieApi.GetMovieInformationWithExtraInfo(int.Parse(theMovieDbId));
|
||||
if (info == null)
|
||||
{
|
||||
|
@ -327,8 +385,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
_log.LogError(e, "Error when processing Emby Movies {0}", info.Title);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -366,7 +423,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
AddParagraph(sb, info.Overview);
|
||||
}
|
||||
|
||||
private async Task ProcessPlexTv(IQueryable<PlexEpisode> plexContent, StringBuilder sb)
|
||||
private async Task ProcessPlexTv(HashSet<PlexEpisode> plexContent, StringBuilder sb)
|
||||
{
|
||||
var series = new List<PlexServerContent>();
|
||||
foreach (var plexEpisode in plexContent)
|
||||
|
@ -437,7 +494,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
sb.Append("<tr>");
|
||||
sb.Append(
|
||||
"<td align=\"center\" style=\"font-family: sans-serif; font-size: 14px; vertical-align: top;\" valign=\"top\">");
|
||||
|
||||
|
||||
var title = $"{t.Title} ({t.ReleaseYear})";
|
||||
|
||||
Href(sb, $"https://www.imdb.com/title/{info.externals.imdb}/");
|
||||
|
@ -483,7 +540,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log.Error(e);
|
||||
_log.LogError(e, "Error when processing Plex TV {0}", t.Title);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -494,7 +551,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
|
||||
}
|
||||
|
||||
private async Task ProcessEmbyTv(IQueryable<EmbyEpisode> embyContent, StringBuilder sb)
|
||||
private async Task ProcessEmbyTv(HashSet<EmbyEpisode> embyContent, StringBuilder sb)
|
||||
{
|
||||
var series = new List<EmbyContent>();
|
||||
foreach (var episode in embyContent)
|
||||
|
@ -584,7 +641,7 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Log.Error(e);
|
||||
_log.LogError(e, "Error when processing Emby TV {0}", t.Title);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="1.50.2" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.3.7" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.19" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.19" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.3.10" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
|
||||
<PackageReference Include="Hangfire.RecurringJobExtensions" Version="1.1.6" />
|
||||
<PackageReference Include="Hangfire.SQLite" Version="1.4.2" />
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace Ombi.Core.Settings.Models.External
|
|||
{
|
||||
public bool Enable { get; set; }
|
||||
public List<PlexServers> Servers { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class PlexServers : ExternalSettings
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace Ombi.Settings.Settings.Models.Notifications
|
|||
public bool DisableTv { get; set; }
|
||||
public bool DisableMovies { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public List<string> ExternalEmails { get; set; }
|
||||
public List<string> ExternalEmails { get; set; } = new List<string>();
|
||||
}
|
||||
}
|
|
@ -123,7 +123,23 @@ namespace Ombi.Store.Context
|
|||
{
|
||||
NormalizedName = OmbiRoles.RecievesNewsletter.ToUpper()
|
||||
});
|
||||
SaveChanges();
|
||||
}
|
||||
|
||||
// Make sure we have the API User
|
||||
var apiUserExists = Users.Any(x => x.UserName.Equals("Api", StringComparison.CurrentCultureIgnoreCase));
|
||||
if (!apiUserExists)
|
||||
{
|
||||
Users.Add(new OmbiUser
|
||||
{
|
||||
UserName = "Api",
|
||||
UserType = UserType.SystemUser,
|
||||
NormalizedUserName = "API",
|
||||
|
||||
});
|
||||
SaveChanges();
|
||||
}
|
||||
|
||||
//Check if templates exist
|
||||
var templates = NotificationTemplates.ToList();
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace Ombi.Store.Entities
|
|||
public string TheMovieDbId { get; set; }
|
||||
public string TvDbId { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
public ICollection<EmbyEpisode> Episodes { get; set; }
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ namespace Ombi.Store.Entities
|
|||
{
|
||||
public RecentlyAddedType Type { get; set; }
|
||||
public ContentType ContentType { get; set; }
|
||||
public int ContentId { get; set; } // This is dependant on the type
|
||||
public int ContentId { get; set; } // This is dependant on the type, it's either TMDBID or TVDBID
|
||||
public int? EpisodeNumber { get; set; }
|
||||
public int? SeasonNumber { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Ombi.Store.Entities.Requests
|
|||
public string Overview { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string PosterPath { get; set; }
|
||||
public string Background { get; set; }
|
||||
public DateTime ReleaseDate { get; set; }
|
||||
public string Status { get; set; }
|
||||
/// <summary>
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace Ombi.Store.Entities
|
|||
{
|
||||
public enum UserType
|
||||
{
|
||||
SystemUser = 0,
|
||||
LocalUser = 1,
|
||||
PlexUser = 2,
|
||||
EmbyUser = 3,
|
||||
|
|
950
src/Ombi.Store/Migrations/20180413021646_tvrequestsbackground.Designer.cs
generated
Normal file
950
src/Ombi.Store/Migrations/20180413021646_tvrequestsbackground.Designer.cs
generated
Normal file
|
@ -0,0 +1,950 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180413021646_tvrequestsbackground")]
|
||||
partial class tvrequestsbackground
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class tvrequestsbackground : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Background",
|
||||
table: "TvRequests",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Background",
|
||||
table: "TvRequests");
|
||||
}
|
||||
}
|
||||
}
|
950
src/Ombi.Store/Migrations/20180419054711_EmbyButton.Designer.cs
generated
Normal file
950
src/Ombi.Store/Migrations/20180419054711_EmbyButton.Designer.cs
generated
Normal file
|
@ -0,0 +1,950 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180419054711_EmbyButton")]
|
||||
partial class EmbyButton
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
24
src/Ombi.Store/Migrations/20180419054711_EmbyButton.cs
Normal file
24
src/Ombi.Store/Migrations/20180419054711_EmbyButton.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class EmbyButton : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Url",
|
||||
table: "EmbyContent",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Url",
|
||||
table: "EmbyContent");
|
||||
}
|
||||
}
|
||||
}
|
956
src/Ombi.Store/Migrations/20180420225638_NewsletterChanges.Designer.cs
generated
Normal file
956
src/Ombi.Store/Migrations/20180420225638_NewsletterChanges.Designer.cs
generated
Normal file
|
@ -0,0 +1,956 @@
|
|||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Store.Context;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Entities.Requests;
|
||||
using System;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
[DbContext(typeof(OmbiContext))]
|
||||
[Migration("20180420225638_NewsletterChanges")]
|
||||
partial class NewsletterChanges
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApplicationConfiguration");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Audit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AuditArea");
|
||||
|
||||
b.Property<int>("AuditType");
|
||||
|
||||
b.Property<DateTime>("DateTime");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("User");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Audit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.CouchPotatoCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CouchPotatoCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("EmbyId");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("ParentId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("EmbyEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<string>("SettingsName");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("GlobalSettings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("Agent");
|
||||
|
||||
b.Property<bool>("Enabled");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<int>("NotificationType");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("NotificationTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("PlayerId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("NotificationUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("Alias");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<string>("EmbyConnectUserId");
|
||||
|
||||
b.Property<int?>("EpisodeRequestLimit");
|
||||
|
||||
b.Property<DateTime?>("LastLoggedIn");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<int?>("MovieRequestLimit");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("ProviderUserId");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserAccessToken");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<int>("UserType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("GrandparentKey");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GrandparentKey");
|
||||
|
||||
b.ToTable("PlexEpisode");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ParentKey");
|
||||
|
||||
b.Property<int>("PlexContentId");
|
||||
|
||||
b.Property<int?>("PlexServerContentId");
|
||||
|
||||
b.Property<int>("SeasonKey");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlexServerContentId");
|
||||
|
||||
b.ToTable("PlexSeasonsContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexServerContent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int>("Key");
|
||||
|
||||
b.Property<string>("Quality");
|
||||
|
||||
b.Property<string>("ReleaseYear");
|
||||
|
||||
b.Property<string>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TvDbId");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("PlexServerContent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RadarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.RecentlyAddedLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AddedAt");
|
||||
|
||||
b.Property<int>("ContentId");
|
||||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int?>("EpisodeNumber");
|
||||
|
||||
b.Property<int?>("SeasonNumber");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("RecentlyAddedLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<int>("ParentRequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("SeriesType");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentRequestId");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("ChildRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("IssueCategory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Comment");
|
||||
|
||||
b.Property<DateTime>("Date");
|
||||
|
||||
b.Property<int?>("IssuesId");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssuesId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("IssueComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("IssueCategoryId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("ProviderId");
|
||||
|
||||
b.Property<int?>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime?>("ResovledDate");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("UserReportedId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IssueCategoryId");
|
||||
|
||||
b.HasIndex("IssueId");
|
||||
|
||||
b.HasIndex("UserReportedId");
|
||||
|
||||
b.ToTable("Issues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<bool?>("Denied");
|
||||
|
||||
b.Property<string>("DeniedReason");
|
||||
|
||||
b.Property<DateTime?>("DigitalReleaseDate");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<int?>("IssueId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<DateTime>("RequestedDate");
|
||||
|
||||
b.Property<string>("RequestedUserId");
|
||||
|
||||
b.Property<int>("RootPathOverride");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<int>("TheMovieDbId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeCount");
|
||||
|
||||
b.Property<DateTime>("RequestDate");
|
||||
|
||||
b.Property<int>("RequestId");
|
||||
|
||||
b.Property<int>("RequestType");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RequestLog");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
||||
b.Property<string>("PosterPath");
|
||||
|
||||
b.Property<int?>("QualityOverride");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate");
|
||||
|
||||
b.Property<int?>("RootFolder");
|
||||
|
||||
b.Property<string>("Status");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("TvRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SickRageEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SickRageEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.SonarrEpisodeCache", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("HasFile");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.Property<int>("TvDbId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SonarrEpisodeCache");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Token");
|
||||
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("AirDate");
|
||||
|
||||
b.Property<bool>("Approved");
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<int>("EpisodeNumber");
|
||||
|
||||
b.Property<bool>("Requested");
|
||||
|
||||
b.Property<int>("SeasonId");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SeasonId");
|
||||
|
||||
b.ToTable("EpisodeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("ChildRequestId");
|
||||
|
||||
b.Property<int>("SeasonNumber");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ChildRequestId");
|
||||
|
||||
b.ToTable("SeasonRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.EmbyContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("ParentId")
|
||||
.HasPrincipalKey("EmbyId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.NotificationUserId", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany("NotificationUserIds")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent", "Series")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("GrandparentKey")
|
||||
.HasPrincipalKey("Key")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.PlexServerContent")
|
||||
.WithMany("Seasons")
|
||||
.HasForeignKey("PlexServerContentId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
.WithMany("ChildRequests")
|
||||
.HasForeignKey("ParentRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.IssueComments", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.Issues", "Issues")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("IssuesId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.Issues", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.IssueCategory", "IssueCategory")
|
||||
.WithMany()
|
||||
.HasForeignKey("IssueCategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.Requests.MovieRequests")
|
||||
.WithMany("Issues")
|
||||
.HasForeignKey("IssueId");
|
||||
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "UserReported")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserReportedId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Tokens", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season")
|
||||
.WithMany("Episodes")
|
||||
.HasForeignKey("SeasonId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest")
|
||||
.WithMany("SeasonRequests")
|
||||
.HasForeignKey("ChildRequestId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Store.Migrations
|
||||
{
|
||||
public partial class NewsletterChanges : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "EpisodeNumber",
|
||||
table: "RecentlyAddedLog",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SeasonNumber",
|
||||
table: "RecentlyAddedLog",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.Sql("DELETE FROM RecentlyAddedLog");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EpisodeNumber",
|
||||
table: "RecentlyAddedLog");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SeasonNumber",
|
||||
table: "RecentlyAddedLog");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -197,6 +197,8 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EmbyContent");
|
||||
|
@ -453,6 +455,10 @@ namespace Ombi.Store.Migrations
|
|||
|
||||
b.Property<int>("ContentType");
|
||||
|
||||
b.Property<int?>("EpisodeNumber");
|
||||
|
||||
b.Property<int?>("SeasonNumber");
|
||||
|
||||
b.Property<int>("Type");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
@ -645,6 +651,8 @@ namespace Ombi.Store.Migrations
|
|||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Background");
|
||||
|
||||
b.Property<string>("ImdbId");
|
||||
|
||||
b.Property<string>("Overview");
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.9" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -81,6 +81,7 @@ namespace Ombi.Store.Repository
|
|||
|
||||
public void Update(GlobalSettings entity)
|
||||
{
|
||||
Db.Update(entity);
|
||||
//_cache.Remove(GetName(entity.SettingsName));
|
||||
Db.SaveChanges();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import { CookieComponent } from "./auth/cookie.component";
|
|||
import { PageNotFoundComponent } from "./errors/not-found.component";
|
||||
import { LandingPageComponent } from "./landingpage/landingpage.component";
|
||||
import { LoginComponent } from "./login/login.component";
|
||||
import { LoginOAuthComponent } from "./login/loginoauth.component";
|
||||
import { ResetPasswordComponent } from "./login/resetpassword.component";
|
||||
import { TokenResetPasswordComponent } from "./login/tokenresetpassword.component";
|
||||
|
||||
|
@ -41,6 +42,7 @@ const routes: Routes = [
|
|||
{ path: "*", component: PageNotFoundComponent },
|
||||
{ path: "", redirectTo: "/search", pathMatch: "full" },
|
||||
{ path: "login", component: LoginComponent },
|
||||
{ path: "Login/OAuth/:pin", component: LoginOAuthComponent },
|
||||
{ path: "login/:landing", component: LoginComponent },
|
||||
{ path: "reset", component: ResetPasswordComponent },
|
||||
{ path: "token", component: TokenResetPasswordComponent },
|
||||
|
@ -116,6 +118,7 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
|
|||
ResetPasswordComponent,
|
||||
TokenResetPasswordComponent,
|
||||
CookieComponent,
|
||||
LoginOAuthComponent,
|
||||
],
|
||||
providers: [
|
||||
NotificationService,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
username: string;
|
||||
password: string;
|
||||
rememberMe: boolean;
|
||||
usePlexOAuth: boolean;
|
||||
}
|
||||
|
||||
export interface ILocalUser {
|
||||
|
|
|
@ -18,6 +18,10 @@ export class AuthService extends ServiceHelpers {
|
|||
return this.http.post(`${this.url}/`, JSON.stringify(login), {headers: this.headers});
|
||||
}
|
||||
|
||||
public oAuth(pin: number): Observable<any> {
|
||||
return this.http.get<any>(`${this.url}/${pin}`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public requiresPassword(login: IUserLogin): Observable<boolean> {
|
||||
return this.http.post<boolean>(`${this.url}/requirePassword`, JSON.stringify(login), {headers: this.headers});
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
user: IPlexUser;
|
||||
}
|
||||
|
||||
export interface IPlexOAuthAccessToken {
|
||||
accessToken: string;
|
||||
}
|
||||
|
||||
export interface IPlexUser {
|
||||
email: string;
|
||||
uuid: string;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
requested: boolean;
|
||||
available: boolean;
|
||||
plexUrl: string;
|
||||
embyUrl: string;
|
||||
quality: string;
|
||||
digitalReleaseDate: Date;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ export interface ISearchTvResult {
|
|||
requested: boolean;
|
||||
available: boolean;
|
||||
plexUrl: string;
|
||||
embyUrl: string;
|
||||
firstSeason: boolean;
|
||||
latestSeason: boolean;
|
||||
}
|
||||
|
|
|
@ -7,29 +7,52 @@ include the remember me checkbox
|
|||
<div *ngIf="background" @fadeInOut class="bg" [style.background-image]="background"></div>
|
||||
<div class="container" id="login">
|
||||
<div class="card card-container">
|
||||
|
||||
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
|
||||
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="{{baseUrl}}/images/logo.png"/></div>
|
||||
<div *ngIf="customizationSettings.logo"><img id="profile-img" class="center" [src]="customizationSettings.logo" /></div>
|
||||
<div *ngIf="!customizationSettings.logo">
|
||||
<img id="profile-img" class="profile-img-card" src="{{baseUrl}}/images/logo.png" />
|
||||
</div>
|
||||
<div *ngIf="customizationSettings.logo">
|
||||
<img id="profile-img" class="center" [src]="customizationSettings.logo" />
|
||||
</div>
|
||||
<p id="profile-name" class="profile-name-card"></p>
|
||||
|
||||
<form *ngIf="authenticationSettings" class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
|
||||
|
||||
<input type="email" id="inputEmail" class="form-control" formControlName="username" [attr.placeholder]="'Login.UsernamePlaceholder' | translate" autofocus>
|
||||
<input *ngIf="!authenticationSettings.allowNoPassword" type="password" id="inputPassword" class="form-control" formControlName="password" [attr.placeholder]="'Login.PasswordPlaceholder' | translate">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="RememberMe" formControlName="rememberMe" >
|
||||
|
||||
<label for="RememberMe" [translate]="'Login.RememberMe'"></label>
|
||||
|
||||
<div *ngIf="!plexEnabled || !customizationSettings.applicationUrl || loginWithOmbi">
|
||||
<form *ngIf="authenticationSettings" class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">
|
||||
|
||||
|
||||
<input type="email" id="inputEmail" class="form-control" formControlName="username" [attr.placeholder]="'Login.UsernamePlaceholder' | translate"
|
||||
autofocus>
|
||||
<input *ngIf="!authenticationSettings.allowNoPassword" type="password" id="inputPassword" class="form-control" formControlName="password"
|
||||
[attr.placeholder]="'Login.PasswordPlaceholder' | translate">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="RememberMe" formControlName="rememberMe">
|
||||
|
||||
<label for="RememberMe" [translate]="'Login.RememberMe'"></label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-success" type="submit" [translate]="'Login.SignInButton'"></button>
|
||||
</form><!-- /form -->
|
||||
<a [routerLink]="['/reset']" class="forgot-password col-md-12">
|
||||
<b [translate]="'Login.ForgottenPassword'"></b>
|
||||
</a>
|
||||
</div><!-- /card-container -->
|
||||
</div><!-- /container -->
|
||||
<button class="btn btn-success" type="submit" [translate]="'Login.SignInButton'"></button>
|
||||
<a [routerLink]="['/reset']" class="forgot-password col-md-12">
|
||||
<b [translate]="'Login.ForgottenPassword'"></b>
|
||||
</a>
|
||||
</form>
|
||||
<!-- /form -->
|
||||
</div>
|
||||
<!-- Main OAuth Flow -->
|
||||
<div class="form-signin" *ngIf="plexEnabled && customizationSettings.applicationUrl && !loginWithOmbi">
|
||||
<button class="btn btn-success" type="button" (click)="loginWithOmbi = true">
|
||||
Sign In With {{appName}}</button>
|
||||
</div>
|
||||
<div class="form-signin" *ngIf="plexEnabled && customizationSettings.applicationUrl && !loginWithOmbi">
|
||||
<button class="btn btn-primary" type="button" (click)="oauth()">
|
||||
Sign In With Plex</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /card-container -->
|
||||
</div>
|
||||
<!-- /container -->
|
||||
</div>
|
||||
|
|
|
@ -25,9 +25,20 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
public form: FormGroup;
|
||||
public customizationSettings: ICustomizationSettings;
|
||||
public authenticationSettings: IAuthenticationSettings;
|
||||
public plexEnabled: boolean;
|
||||
public background: any;
|
||||
public landingFlag: boolean;
|
||||
public baseUrl: string;
|
||||
public loginWithOmbi: boolean;
|
||||
|
||||
public get appName(): string {
|
||||
if(this.customizationSettings.applicationName) {
|
||||
return this.customizationSettings.applicationName;
|
||||
} else {
|
||||
return "Ombi";
|
||||
}
|
||||
}
|
||||
|
||||
private timer: any;
|
||||
|
||||
private errorBody: string;
|
||||
|
@ -68,6 +79,7 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
public ngOnInit() {
|
||||
this.settingsService.getAuthentication().subscribe(x => this.authenticationSettings = x);
|
||||
this.settingsService.getCustomization().subscribe(x => this.customizationSettings = x);
|
||||
this.settingsService.getStatusPlex().subscribe(x => this.plexEnabled = x);
|
||||
this.images.getRandomBackground().subscribe(x => {
|
||||
this.background = this.sanitizer.bypassSecurityTrustStyle("linear-gradient(-10deg, transparent 20%, rgba(0,0,0,0.7) 20.0%, rgba(0,0,0,0.7) 80.0%, transparent 80%),url(" + x.url + ")");
|
||||
});
|
||||
|
@ -90,7 +102,7 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
return;
|
||||
}
|
||||
const value = form.value;
|
||||
const user = { password: value.password, username: value.username, rememberMe:value.rememberMe };
|
||||
const user = { password: value.password, username: value.username, rememberMe: value.rememberMe, usePlexOAuth: false };
|
||||
this.authService.requiresPassword(user).subscribe(x => {
|
||||
if(x && this.authenticationSettings.allowNoPassword) {
|
||||
// Looks like this user requires a password
|
||||
|
@ -111,6 +123,12 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
public oauth() {
|
||||
this.authService.login({usePlexOAuth: true, password:"",rememberMe:true,username:""}).subscribe(x => {
|
||||
window.location.href = x.url;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
@ -124,5 +142,4 @@ export class LoginComponent implements OnDestroy, OnInit {
|
|||
.bypassSecurityTrustStyle("linear-gradient(-10deg, transparent 20%, rgba(0,0,0,0.7) 20.0%, rgba(0,0,0,0.7) 80.0%, transparent 80%), url(" + x.url + ")");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
16
src/Ombi/ClientApp/app/login/loginoauth.component.html
Normal file
16
src/Ombi/ClientApp/app/login/loginoauth.component.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
<div >
|
||||
|
||||
<div class="container" id="login">
|
||||
<div class="card card-container">
|
||||
<label>Please Wait...</label>
|
||||
|
||||
<div *ngIf="error">
|
||||
<label>{{error}}</label>
|
||||
|
||||
<a [routerLink]="['/login']">
|
||||
Back </a>
|
||||
</div>
|
||||
</div><!-- /card-container -->
|
||||
</div><!-- /container -->
|
||||
</div>
|
42
src/Ombi/ClientApp/app/login/loginoauth.component.ts
Normal file
42
src/Ombi/ClientApp/app/login/loginoauth.component.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./loginoauth.component.html",
|
||||
})
|
||||
export class LoginOAuthComponent implements OnInit {
|
||||
public pin: number;
|
||||
public error: string;
|
||||
|
||||
constructor(private authService: AuthService, private router: Router,
|
||||
private route: ActivatedRoute) {
|
||||
this.route.params
|
||||
.subscribe((params: any) => {
|
||||
this.pin = params.pin;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.auth();
|
||||
}
|
||||
|
||||
public auth() {
|
||||
this.authService.oAuth(this.pin).subscribe(x => {
|
||||
if(x.access_token) {
|
||||
localStorage.setItem("id_token", x.access_token);
|
||||
|
||||
if (this.authService.loggedIn()) {
|
||||
this.router.navigate(["search"]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(x.errorMessage) {
|
||||
this.error = x.errorMessage;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
|
@ -228,9 +228,14 @@ export class TvRequestsComponent implements OnInit {
|
|||
}
|
||||
|
||||
private loadBackdrop(val: TreeNode): void {
|
||||
this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
|
||||
if (val.data.background != null) {
|
||||
val.data.background = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + x + ")");
|
||||
("url(https://image.tmdb.org/t/p/w1280" + val.data.background + ")");
|
||||
} else {
|
||||
this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
|
||||
val.data.background = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + x + ")");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
<br/>
|
||||
<div *ngIf="result.available">
|
||||
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
|
||||
<a *ngIf="result.embyUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.embyUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Emby</a>
|
||||
</div>
|
||||
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
|
||||
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
|
|
|
@ -118,17 +118,25 @@
|
|||
|
||||
<div *ngIf="node.data.fullyAvailable">
|
||||
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
|
||||
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}</button>
|
||||
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<br />
|
||||
<div *ngIf="node.data.plexUrl && node.data.available">
|
||||
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.plexUrl}}"
|
||||
target="_blank">
|
||||
<i class="fa fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}</a>
|
||||
</div>
|
||||
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.plexUrl}}"
|
||||
target="_blank">
|
||||
<i class="fa fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="node.data.embyUrl && node.data.available">
|
||||
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.embyUrl}}"
|
||||
target="_blank">
|
||||
<i class="fa fa-eye"></i> {{ 'Search.ViewOnEmby' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown" *ngIf="issueCategories && issuesEnabled">
|
||||
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="true">
|
||||
aria-expanded="true">
|
||||
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
@ -139,8 +147,8 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div *ngIf="!node.data.available">
|
||||
<br/>
|
||||
<br/>
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -4,3 +4,4 @@ export * from "./plex.service";
|
|||
export * from "./radarr.service";
|
||||
export * from "./sonarr.service";
|
||||
export * from "./tester.service";
|
||||
export * from "./plexoauth.service";
|
||||
|
|
|
@ -29,4 +29,8 @@ export class PlexService extends ServiceHelpers {
|
|||
public getFriends(): Observable<IUsersModel[]> {
|
||||
return this.http.get<IUsersModel[]>(`${this.url}Friends`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public oAuth(wizard: boolean): Observable<any> {
|
||||
return this.http.get<any>(`${this.url}oauth/${wizard}`, {headers: this.headers});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { PlatformLocation } from "@angular/common";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import { Observable } from "rxjs/Rx";
|
||||
|
||||
import { ServiceHelpers } from "../service.helpers";
|
||||
|
||||
import { IPlexOAuthAccessToken } from "../../interfaces";
|
||||
|
||||
@Injectable()
|
||||
export class PlexOAuthService extends ServiceHelpers {
|
||||
constructor(http: HttpClient, public platformLocation: PlatformLocation) {
|
||||
super(http, "/api/v1/PlexOAuth/", platformLocation);
|
||||
}
|
||||
|
||||
public oAuth(pin: number): Observable<IPlexOAuthAccessToken> {
|
||||
return this.http.get<IPlexOAuthAccessToken>(`${this.url}${pin}`, {headers: this.headers});
|
||||
}
|
||||
}
|
|
@ -71,6 +71,10 @@ export class SettingsService extends ServiceHelpers {
|
|||
return this.http.get<IPlexSettings>(`${this.url}/Plex/`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public getStatusPlex(): Observable<boolean> {
|
||||
return this.http.get<boolean>(`${this.url}/Plexstatus/`, {headers: this.headers});
|
||||
}
|
||||
|
||||
public savePlex(settings: IPlexSettings): Observable<boolean> {
|
||||
return this.http.post<boolean>(`${this.url}/Plex/`, JSON.stringify(settings), {headers: this.headers});
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export class CreateAdminComponent {
|
|||
this.identityService.createWizardUser({username: this.username, password: this.password, usePlexAdminAccount: false}).subscribe(x => {
|
||||
if (x) {
|
||||
// Log me in.
|
||||
this.auth.login({ username: this.username, password: this.password, rememberMe:false }).subscribe(c => {
|
||||
this.auth.login({ username: this.username, password: this.password, rememberMe: false, usePlexOAuth:false }).subscribe(c => {
|
||||
|
||||
localStorage.setItem("id_token", c.access_token);
|
||||
|
||||
|
|
|
@ -17,9 +17,16 @@
|
|||
<small>Please note we do not store this information, we only store your Plex Authorization Token that will allow Ombi to view your media and friends</small>
|
||||
<div class="form-group">
|
||||
<div style="text-align: center; margin-top: 20px">
|
||||
<button (click)="requestAuthToken()" class="btn btn-primary-outline">Request Token <i class="fa fa-key"></i></button>
|
||||
<button (click)="requestAuthToken()" class="btn btn-success-outline">Request Token <i class="fa fa-key"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center">OR</p>
|
||||
<div class="form-group">
|
||||
<div style="text-align: center; margin-top: 20px">
|
||||
<button (click)="oauth()" class="btn btn-primary" type="button">Continue With Plex</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { Component } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { ConfirmationService } from "primeng/primeng";
|
||||
|
||||
import { PlexService } from "../../services";
|
||||
import { IdentityService, NotificationService, SettingsService } from "../../services";
|
||||
import { AuthService } from "./../../auth/auth.service";
|
||||
|
@ -17,7 +15,6 @@ export class PlexComponent {
|
|||
|
||||
constructor(private plexService: PlexService, private router: Router,
|
||||
private notificationService: NotificationService,
|
||||
private confirmationService: ConfirmationService,
|
||||
private identityService: IdentityService,
|
||||
private settings: SettingsService,
|
||||
private auth: AuthService) { }
|
||||
|
@ -28,25 +25,21 @@ export class PlexComponent {
|
|||
this.notificationService.error("Username or password was incorrect. Could not authenticate with Plex.");
|
||||
return;
|
||||
}
|
||||
this.confirmationService.confirm({
|
||||
message: "Do you want your Plex user to be the main admin account on Ombi?",
|
||||
header: "Use Plex Account",
|
||||
icon: "fa fa-check",
|
||||
accept: () => {
|
||||
this.identityService.createWizardUser({
|
||||
|
||||
this.identityService.createWizardUser({
|
||||
username: "",
|
||||
password: "",
|
||||
usePlexAdminAccount: true,
|
||||
}).subscribe(x => {
|
||||
if (x) {
|
||||
this.auth.login({ username: this.login, password: this.password, rememberMe:false }).subscribe(c => {
|
||||
}).subscribe(y => {
|
||||
if (y) {
|
||||
this.auth.login({ username: this.login, password: this.password, rememberMe: false, usePlexOAuth: false }).subscribe(c => {
|
||||
localStorage.setItem("id_token", c.access_token);
|
||||
|
||||
// Mark that we have done the settings now
|
||||
this.settings.getOmbi().subscribe(ombi => {
|
||||
ombi.wizard = true;
|
||||
|
||||
this.settings.saveOmbi(ombi).subscribe(x => {
|
||||
this.settings.saveOmbi(ombi).subscribe(s => {
|
||||
this.settings.getUserManagementSettings().subscribe(usr => {
|
||||
|
||||
usr.importPlexAdmin = true;
|
||||
|
@ -64,10 +57,14 @@ export class PlexComponent {
|
|||
}
|
||||
});
|
||||
},
|
||||
reject: () => {
|
||||
this.router.navigate(["Wizard/CreateAdmin"]);
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
public oauth() {
|
||||
this.plexService.oAuth(true).subscribe(x => {
|
||||
if(x.url) {
|
||||
window.location.href = x.url;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
14
src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.html
Normal file
14
src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
<img class="landing-header" src="/images/logo.png" width="300" />
|
||||
<div class="landing-block shadow">
|
||||
<div class="media">
|
||||
<div id="contentBody" class="media-body">
|
||||
<h4 class="media-heading landing-title">Plex Authentication</h4>
|
||||
<div class="form-group">
|
||||
<label for="username" class="control-label">Please Wait</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p-confirmDialog></p-confirmDialog>
|
67
src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts
Normal file
67
src/Ombi/ClientApp/app/wizard/plex/plexoauth.component.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { IdentityService, PlexOAuthService, SettingsService } from "../../services";
|
||||
import { AuthService } from "./../../auth/auth.service";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./plexoauth.component.html",
|
||||
})
|
||||
export class PlexOAuthComponent implements OnInit {
|
||||
public pinId: number;
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private plexOauth: PlexOAuthService,
|
||||
private identityService: IdentityService,
|
||||
private settings: SettingsService,
|
||||
private router: Router,
|
||||
private auth: AuthService) {
|
||||
|
||||
this.route.params
|
||||
.subscribe((params: any) => {
|
||||
this.pinId = params.pin;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.plexOauth.oAuth(this.pinId).subscribe(x => {
|
||||
if(!x.accessToken) {
|
||||
return;
|
||||
// RETURN
|
||||
}
|
||||
|
||||
this.identityService.createWizardUser({
|
||||
username: "",
|
||||
password: "",
|
||||
usePlexAdminAccount: true,
|
||||
}).subscribe(u => {
|
||||
if (u) {
|
||||
this.auth.oAuth(this.pinId).subscribe(c => {
|
||||
localStorage.setItem("id_token", c.access_token);
|
||||
|
||||
// Mark that we have done the settings now
|
||||
this.settings.getOmbi().subscribe(ombi => {
|
||||
ombi.wizard = true;
|
||||
|
||||
this.settings.saveOmbi(ombi).subscribe(s => {
|
||||
this.settings.getUserManagementSettings().subscribe(usr => {
|
||||
|
||||
usr.importPlexAdmin = true;
|
||||
this.settings.saveUserManagementSettings(usr).subscribe(saved => {
|
||||
this.router.navigate(["login"]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
//this.notificationService.error("Could not get the Plex Admin Information");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,8 @@ import { WelcomeComponent } from "./welcome/welcome.component";
|
|||
import { EmbyService } from "../services";
|
||||
import { PlexService } from "../services";
|
||||
import { IdentityService } from "../services";
|
||||
import { PlexOAuthService } from "../services";
|
||||
import { PlexOAuthComponent } from "./plex/plexoauth.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", component: WelcomeComponent},
|
||||
|
@ -21,6 +23,7 @@ const routes: Routes = [
|
|||
{ path: "Plex", component: PlexComponent},
|
||||
{ path: "Emby", component: EmbyComponent},
|
||||
{ path: "CreateAdmin", component: CreateAdminComponent},
|
||||
{ path: "OAuth/:pin", component: PlexOAuthComponent},
|
||||
];
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -33,6 +36,7 @@ const routes: Routes = [
|
|||
WelcomeComponent,
|
||||
MediaServerComponent,
|
||||
PlexComponent,
|
||||
PlexOAuthComponent,
|
||||
CreateAdminComponent,
|
||||
EmbyComponent,
|
||||
],
|
||||
|
@ -44,6 +48,7 @@ const routes: Routes = [
|
|||
IdentityService,
|
||||
EmbyService,
|
||||
ConfirmationService,
|
||||
PlexOAuthService,
|
||||
],
|
||||
|
||||
})
|
||||
|
|
37
src/Ombi/Controllers/External/PlexController.cs
vendored
37
src/Ombi/Controllers/External/PlexController.cs
vendored
|
@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
|
|||
using Ombi.Api.Plex;
|
||||
using Ombi.Api.Plex.Models;
|
||||
using Ombi.Attributes;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
|
@ -21,16 +22,18 @@ namespace Ombi.Controllers.External
|
|||
public class PlexController : Controller
|
||||
{
|
||||
public PlexController(IPlexApi plexApi, ISettingsService<PlexSettings> plexSettings,
|
||||
ILogger<PlexController> logger)
|
||||
ILogger<PlexController> logger, IPlexOAuthManager manager)
|
||||
{
|
||||
PlexApi = plexApi;
|
||||
PlexSettings = plexSettings;
|
||||
_log = logger;
|
||||
_plexOAuthManager = manager;
|
||||
}
|
||||
|
||||
private IPlexApi PlexApi { get; }
|
||||
private ISettingsService<PlexSettings> PlexSettings { get; }
|
||||
private readonly ILogger<PlexController> _log;
|
||||
private readonly IPlexOAuthManager _plexOAuthManager;
|
||||
|
||||
/// <summary>
|
||||
/// Signs into the Plex API.
|
||||
|
@ -173,5 +176,37 @@ namespace Ombi.Controllers.External
|
|||
// Filter out any dupes
|
||||
return vm.DistinctBy(x => x.Id);
|
||||
}
|
||||
|
||||
[HttpGet("oauth/{wizard:bool}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> OAuth(bool wizard)
|
||||
{
|
||||
//https://app.plex.tv/auth#?forwardUrl=http://google.com/&clientID=Ombi-Test&context%5Bdevice%5D%5Bproduct%5D=Ombi%20SSO&pinID=798798&code=4lgfd
|
||||
// Plex OAuth
|
||||
// Redirect them to Plex
|
||||
// We need a PIN first
|
||||
var pin = await _plexOAuthManager.RequestPin();
|
||||
|
||||
Uri url;
|
||||
if (!wizard)
|
||||
{
|
||||
url = await _plexOAuthManager.GetOAuthUrl(pin.id, pin.code);
|
||||
}
|
||||
else
|
||||
{
|
||||
var websiteAddress =$"{this.Request.Scheme}://{this.Request.Host}{this.Request.PathBase}";
|
||||
url = _plexOAuthManager.GetWizardOAuthUrl(pin.id, pin.code, websiteAddress);
|
||||
}
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
return new JsonResult(new
|
||||
{
|
||||
error = "Application URL has not been set"
|
||||
});
|
||||
}
|
||||
|
||||
return new JsonResult(new {url = url.ToString()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ namespace Ombi.Controllers
|
|||
[PowerUser]
|
||||
public async Task<IEnumerable<UserViewModel>> GetAllUsers()
|
||||
{
|
||||
var users = await UserManager.Users
|
||||
var users = await UserManager.Users.Where(x => x.UserType != UserType.SystemUser)
|
||||
.ToListAsync();
|
||||
|
||||
var model = new List<UserViewModel>();
|
||||
|
|
78
src/Ombi/Controllers/PlexOAuthController.cs
Normal file
78
src/Ombi/Controllers/PlexOAuthController.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Ombi.Api.Plex;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Settings;
|
||||
using Ombi.Core.Settings.Models.External;
|
||||
using Ombi.Helpers;
|
||||
|
||||
namespace Ombi.Controllers
|
||||
{
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[ApiV1]
|
||||
[AllowAnonymous]
|
||||
public class PlexOAuthController : Controller
|
||||
{
|
||||
public PlexOAuthController(IPlexOAuthManager manager, IPlexApi plexApi, ISettingsService<PlexSettings> plexSettings,
|
||||
ILogger<PlexOAuthController> log)
|
||||
{
|
||||
_manager = manager;
|
||||
_plexApi = plexApi;
|
||||
_plexSettings = plexSettings;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
private readonly IPlexOAuthManager _manager;
|
||||
private readonly IPlexApi _plexApi;
|
||||
private readonly ISettingsService<PlexSettings> _plexSettings;
|
||||
private readonly ILogger _log;
|
||||
|
||||
[HttpGet("{pinId:int}")]
|
||||
public async Task<IActionResult> OAuthWizardCallBack([FromRoute] int pinId)
|
||||
{
|
||||
var accessToken = await _manager.GetAccessTokenFromPin(pinId);
|
||||
if (accessToken.IsNullOrEmpty())
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
error = "Authentication did not work. Please try again"
|
||||
});
|
||||
}
|
||||
var settings = await _plexSettings.GetSettingsAsync();
|
||||
var server = await _plexApi.GetServer(accessToken);
|
||||
var servers = server.Server.FirstOrDefault();
|
||||
if (servers == null)
|
||||
{
|
||||
_log.LogWarning("Looks like we can't find any Plex Servers");
|
||||
}
|
||||
_log.LogDebug("Adding first server");
|
||||
|
||||
settings.Enable = true;
|
||||
settings.Servers = new List<PlexServers> {
|
||||
new PlexServers
|
||||
{
|
||||
PlexAuthToken = accessToken,
|
||||
Id = new Random().Next(),
|
||||
Ip = servers?.LocalAddresses?.Split(new []{','}, StringSplitOptions.RemoveEmptyEntries)?.FirstOrDefault() ?? string.Empty,
|
||||
MachineIdentifier = servers?.MachineIdentifier ?? string.Empty,
|
||||
Port = int.Parse(servers?.Port ?? "0"),
|
||||
Ssl = (servers?.Scheme ?? "http") != "http",
|
||||
Name = "Server 1",
|
||||
}
|
||||
};
|
||||
|
||||
await _plexSettings.SaveSettingsAsync(settings);
|
||||
return Json(new { accessToken });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -142,7 +142,19 @@ namespace Ombi.Controllers
|
|||
[HttpGet("plex")]
|
||||
public async Task<PlexSettings> PlexSettings()
|
||||
{
|
||||
return await Get<PlexSettings>();
|
||||
var s = await Get<PlexSettings>();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
[HttpGet("plexstatus")]
|
||||
[AllowAnonymous]
|
||||
public async Task<bool> PlexStatusSettings()
|
||||
{
|
||||
var s = await Get<PlexSettings>();
|
||||
|
||||
|
||||
return s.Enable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -274,12 +286,6 @@ namespace Ombi.Controllers
|
|||
public async Task<IActionResult> GetThemeContent([FromQuery]string url)
|
||||
{
|
||||
var css = await _githubApi.GetThemesRawContent(url);
|
||||
var ombiSettings = await OmbiSettings();
|
||||
if (ombiSettings.BaseUrl != null)
|
||||
{
|
||||
int index = css.IndexOf("/api/");
|
||||
css = css.Insert(index, ombiSettings.BaseUrl);
|
||||
}
|
||||
return Content(css, "text/css");
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Identity;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Ombi.Api;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Helpers;
|
||||
using Ombi.Models;
|
||||
|
@ -23,18 +25,21 @@ namespace Ombi.Controllers
|
|||
[Produces("application/json")]
|
||||
public class TokenController
|
||||
{
|
||||
public TokenController(OmbiUserManager um, IOptions<TokenAuthentication> ta, IAuditRepository audit, ITokenRepository token)
|
||||
public TokenController(OmbiUserManager um, IOptions<TokenAuthentication> ta, IAuditRepository audit, ITokenRepository token,
|
||||
IPlexOAuthManager oAuthManager)
|
||||
{
|
||||
_userManager = um;
|
||||
_tokenAuthenticationOptions = ta.Value;
|
||||
_audit = audit;
|
||||
_token = token;
|
||||
_plexOAuthManager = oAuthManager;
|
||||
}
|
||||
|
||||
private readonly TokenAuthentication _tokenAuthenticationOptions;
|
||||
private readonly IAuditRepository _audit;
|
||||
private readonly ITokenRepository _token;
|
||||
private readonly OmbiUserManager _userManager;
|
||||
private readonly IPlexOAuthManager _plexOAuthManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the token.
|
||||
|
@ -44,71 +49,132 @@ namespace Ombi.Controllers
|
|||
[HttpPost]
|
||||
public async Task<IActionResult> GetToken([FromBody] UserAuthModel model)
|
||||
{
|
||||
await _audit.Record(AuditType.None, AuditArea.Authentication,
|
||||
if (!model.UsePlexOAuth)
|
||||
{
|
||||
await _audit.Record(AuditType.None, AuditArea.Authentication,
|
||||
$"UserName {model.Username} attempting to authenticate");
|
||||
|
||||
var user = await _userManager.FindByNameAsync(model.Username);
|
||||
var user = await _userManager.FindByNameAsync(model.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
// Could this be an email login?
|
||||
user = await _userManager.FindByEmailAsync(model.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
user.EmailLogin = true;
|
||||
}
|
||||
|
||||
|
||||
// Verify Password
|
||||
if (await _userManager.CheckPasswordAsync(user, model.Password))
|
||||
{
|
||||
return await CreateToken(model.RememberMe, user);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Plex OAuth
|
||||
// Redirect them to Plex
|
||||
// We need a PIN first
|
||||
var pin = await _plexOAuthManager.RequestPin();
|
||||
|
||||
//https://app.plex.tv/auth#?forwardUrl=http://google.com/&clientID=Ombi-Test&context%5Bdevice%5D%5Bproduct%5D=Ombi%20SSO&pinID=798798&code=4lgfd
|
||||
var url = await _plexOAuthManager.GetOAuthUrl(pin.id, pin.code);
|
||||
if (url == null)
|
||||
{
|
||||
return new JsonResult(new
|
||||
{
|
||||
error = "Application URL has not been set"
|
||||
});
|
||||
}
|
||||
return new JsonResult(new { url = url.ToString() });
|
||||
}
|
||||
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
private async Task<IActionResult> CreateToken(bool rememberMe, OmbiUser user)
|
||||
{
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
|
||||
if (roles.Contains(OmbiRoles.Disabled))
|
||||
{
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
user.LastLoggedIn = DateTime.UtcNow;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
||||
new Claim(ClaimTypes.Name, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
||||
};
|
||||
claims.AddRange(roles.Select(role => new Claim("role", role)));
|
||||
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenAuthenticationOptions.SecretKey));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
claims: claims,
|
||||
expires: rememberMe ? DateTime.UtcNow.AddDays(7) : DateTime.UtcNow.AddHours(5),
|
||||
signingCredentials: creds,
|
||||
audience: "Ombi", issuer: "Ombi"
|
||||
);
|
||||
var accessToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
if (rememberMe)
|
||||
{
|
||||
// Save the token so we can refresh it later
|
||||
//await _token.CreateToken(new Tokens() {Token = accessToken, User = user});
|
||||
}
|
||||
|
||||
return new JsonResult(new
|
||||
{
|
||||
access_token = accessToken,
|
||||
expiration = token.ValidTo
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet("{pinId:int}")]
|
||||
public async Task<IActionResult> OAuth(int pinId)
|
||||
{
|
||||
var accessToken = await _plexOAuthManager.GetAccessTokenFromPin(pinId);
|
||||
|
||||
if (accessToken.IsNullOrEmpty())
|
||||
{
|
||||
// Looks like we are not authenticated.
|
||||
return new JsonResult(new
|
||||
{
|
||||
errorMessage = "Could not authenticate with Plex"
|
||||
});
|
||||
}
|
||||
|
||||
// Let's look for the users account
|
||||
var account = await _plexOAuthManager.GetAccount(accessToken);
|
||||
|
||||
// Get the ombi user
|
||||
var user = await _userManager.FindByNameAsync(account.user.username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
// Could this be an email login?
|
||||
user = await _userManager.FindByEmailAsync(model.Username);
|
||||
user = await _userManager.FindByEmailAsync(account.user.email);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
user.EmailLogin = true;
|
||||
}
|
||||
|
||||
// Verify Password
|
||||
if (await _userManager.CheckPasswordAsync(user, model.Password))
|
||||
{
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
|
||||
if (roles.Contains(OmbiRoles.Disabled))
|
||||
{
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
user.LastLoggedIn = DateTime.UtcNow;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id),
|
||||
new Claim(ClaimTypes.Name, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
||||
};
|
||||
claims.AddRange(roles.Select(role => new Claim("role", role)));
|
||||
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenAuthenticationOptions.SecretKey));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
claims: claims,
|
||||
expires: model.RememberMe ? DateTime.UtcNow.AddDays(7) : DateTime.UtcNow.AddHours(5),
|
||||
signingCredentials: creds,
|
||||
audience: "Ombi", issuer:"Ombi"
|
||||
);
|
||||
var accessToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
if (model.RememberMe)
|
||||
{
|
||||
// Save the token so we can refresh it later
|
||||
//await _token.CreateToken(new Tokens() {Token = accessToken, User = user});
|
||||
}
|
||||
|
||||
return new JsonResult(new
|
||||
{
|
||||
access_token = accessToken,
|
||||
expiration = token.ValidTo
|
||||
});
|
||||
}
|
||||
|
||||
return new UnauthorizedResult();
|
||||
return await CreateToken(true, user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -127,7 +193,7 @@ namespace Ombi.Controllers
|
|||
{
|
||||
return new UnauthorizedResult();
|
||||
}
|
||||
|
||||
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
public string Password { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
public bool UsePlexAdminAccount { get; set; }
|
||||
public bool UsePlexOAuth { get; set; }
|
||||
}
|
||||
}
|
|
@ -61,13 +61,13 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="6.1.1" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.3.7" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.19" />
|
||||
<PackageReference Include="Hangfire.Console" Version="1.3.10" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
|
||||
<PackageReference Include="Hangfire.RecurringJobExtensions" Version="1.1.6" />
|
||||
<PackageReference Include="Hangfire.SQLite" Version="1.4.2" />
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.0.2" />
|
||||
|
@ -78,7 +78,7 @@
|
|||
<PackageReference Include="Serilog.Sinks.File" Version="3.2.0" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.1-dev-00771" />
|
||||
<PackageReference Include="Serilog.Sinks.SQLite" Version="3.8.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.Csp" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace Ombi
|
|||
ctx.SaveChanges();
|
||||
}
|
||||
}
|
||||
else if(!baseUrl.Equals(dbBaseUrl.Value))
|
||||
else if(baseUrl.HasValue() && !baseUrl.Equals(dbBaseUrl.Value))
|
||||
{
|
||||
dbBaseUrl.Value = baseUrl;
|
||||
ctx.SaveChanges();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"commandLineArgs": "-baseurl /testing",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
|
|
|
@ -173,26 +173,22 @@ namespace Ombi
|
|||
settings.ApiKey = Guid.NewGuid().ToString("N");
|
||||
ombiService.SaveSettings(settings);
|
||||
}
|
||||
|
||||
// Check if it's in the startup args
|
||||
var appConfig = serviceProvider.GetService<IApplicationConfigRepository>();
|
||||
var baseUrl = appConfig.Get(ConfigurationTypes.BaseUrl).Result;
|
||||
if (baseUrl != null)
|
||||
{
|
||||
if (baseUrl.Value.HasValue())
|
||||
{
|
||||
settings.BaseUrl = baseUrl.Value;
|
||||
ombiService.SaveSettings(settings);
|
||||
}
|
||||
}
|
||||
if (settings.BaseUrl.HasValue())
|
||||
{
|
||||
app.UsePathBase(settings.BaseUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if it's in the startup args
|
||||
var appConfig = serviceProvider.GetService<IApplicationConfigRepository>();
|
||||
var baseUrl = appConfig.Get(ConfigurationTypes.BaseUrl).Result;
|
||||
if (baseUrl != null)
|
||||
{
|
||||
if (baseUrl.Value.HasValue())
|
||||
{
|
||||
settings.BaseUrl = baseUrl.Value;
|
||||
ombiService.SaveSettings(settings);
|
||||
|
||||
app.UsePathBase(settings.BaseUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.UseHangfireServer(new BackgroundJobServerOptions { WorkerCount = 1, ServerTimeout = TimeSpan.FromDays(1), ShutdownTimeout = TimeSpan.FromDays(1)});
|
||||
app.UseHangfireDashboard(settings.BaseUrl.HasValue() ? $"{settings.BaseUrl}/hangfire" : "/hangfire",
|
||||
|
@ -223,7 +219,6 @@ namespace Ombi
|
|||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
|
||||
c.ShowJsonEditor();
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
|
|
|
@ -17,56 +17,56 @@
|
|||
}
|
||||
|
||||
var appName = customization.ApplicationName;
|
||||
if(string.IsNullOrEmpty(appName))
|
||||
if (string.IsNullOrEmpty(appName))
|
||||
{
|
||||
appName = "Ombi";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
<!--
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bbbbbbbb
|
||||
OOOOOOOOO b::::::b iiii
|
||||
OO:::::::::OO b::::::b i::::i
|
||||
OO:::::::::::::OO b::::::b iiii
|
||||
O:::::::OOO:::::::O b:::::b
|
||||
O::::::O O::::::O mmmmmmm mmmmmmm b:::::bbbbbbbbb iiiiiii
|
||||
O:::::O O:::::O mm:::::::m m:::::::mm b::::::::::::::bb i:::::i
|
||||
O:::::O O:::::Om::::::::::mm::::::::::mb::::::::::::::::b i::::i
|
||||
O:::::O O:::::Om::::::::::::::::::::::mb:::::bbbbb:::::::b i::::i
|
||||
O:::::O O:::::Om:::::mmm::::::mmm:::::mb:::::b b::::::b i::::i
|
||||
O:::::O O:::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O:::::O O:::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O::::::O O::::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i
|
||||
OO:::::::::::::OO m::::m m::::m m::::mb::::::::::::::::b i::::::i
|
||||
OO:::::::::OO m::::m m::::m m::::mb:::::::::::::::b i::::::i
|
||||
OOOOOOOOO mmmmmm mmmmmm mmmmmmbbbbbbbbbbbbbbbb iiiiiiii
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-->
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
bbbbbbbb
|
||||
OOOOOOOOO b::::::b iiii
|
||||
OO:::::::::OO b::::::b i::::i
|
||||
OO:::::::::::::OO b::::::b iiii
|
||||
O:::::::OOO:::::::O b:::::b
|
||||
O::::::O O::::::O mmmmmmm mmmmmmm b:::::bbbbbbbbb iiiiiii
|
||||
O:::::O O:::::O mm:::::::m m:::::::mm b::::::::::::::bb i:::::i
|
||||
O:::::O O:::::Om::::::::::mm::::::::::mb::::::::::::::::b i::::i
|
||||
O:::::O O:::::Om::::::::::::::::::::::mb:::::bbbbb:::::::b i::::i
|
||||
O:::::O O:::::Om:::::mmm::::::mmm:::::mb:::::b b::::::b i::::i
|
||||
O:::::O O:::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O:::::O O:::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O::::::O O::::::Om::::m m::::m m::::mb:::::b b:::::b i::::i
|
||||
O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i
|
||||
OO:::::::::::::OO m::::m m::::m m::::mb::::::::::::::::b i::::::i
|
||||
OO:::::::::OO m::::m m::::m m::::mb:::::::::::::::b i::::::i
|
||||
OOOOOOOOO mmmmmm mmmmmm mmmmmmbbbbbbbbbbbbbbbb iiiiiiii
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-->
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<meta name="description" content="Ombi, media request tool">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@appName</title>
|
||||
<meta property="og:title" content=“@appName”/>
|
||||
<meta property="og:image" content="~/images/logo.png"/>
|
||||
<meta property="og:site_name" content=“@appName”/>
|
||||
<base href="/@baseUrl"/>
|
||||
<meta property="og:title" content=“@appName” />
|
||||
<meta property="og:image" content="~/images/logo.png" />
|
||||
<meta property="og:site_name" content=“@appName” />
|
||||
<base href="/@baseUrl" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="~/images/favicon/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="~/images/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="~/images/favicon/favicon-16x16.png">
|
||||
|
@ -80,23 +80,35 @@ O:::::::OOO:::::::Om::::m m::::m m::::mb:::::bbbbbb::::::bi::::::i
|
|||
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="~/loading.css" asp-append-version="true"/>
|
||||
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true"/>
|
||||
<link rel="stylesheet" href="~/loading.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />
|
||||
<script src="~/dist/vendor.js" asp-append-version="true" defer></script>
|
||||
<script src="~/dist/main.js" asp-append-version="true" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
@{
|
||||
@{
|
||||
if (customization.HasPresetTheme)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(baseUrl))
|
||||
{
|
||||
if (!customization.PresetThemeContent.Contains("/" + baseUrl))
|
||||
{
|
||||
var index = customization.PresetThemeContent.IndexOf("/api/");
|
||||
if (index > 0)
|
||||
{
|
||||
customization.PresetThemeContent = customization.PresetThemeContent.Insert(index, "/" + baseUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<style>
|
||||
@Html.Raw(customization.PresetThemeContent)
|
||||
</style>
|
||||
</style>
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(customization.CustomCssLink))
|
||||
{
|
||||
<link rel="stylesheet" href="@customization.CustomCssLink" asp-append-version="true"/>
|
||||
<link rel="stylesheet" href="@customization.CustomCssLink" asp-append-version="true" />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Se på Plex",
|
||||
"ViewOnEmby": "Se på Emby",
|
||||
"RequestAdded": "{{title}} er anmodet med succes",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "In Plex anschauen",
|
||||
"ViewOnEmby": "In Emby anschauen",
|
||||
"RequestAdded": "Anfrage für {{title}} wurde erfolgreich hinzugefügt",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease":"Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "View On Plex",
|
||||
"ViewOnEmby": "View On Emby",
|
||||
"RequestAdded": "Request for {{title}} has been added successfully",
|
||||
"Similar":"Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Ver en Plex",
|
||||
"ViewOnEmby": "Ver en Emby",
|
||||
"RequestAdded": "La solicitud de {{title}} se ha agregado con éxito",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Regarder sur Plex",
|
||||
"ViewOnEmby": "Regarder sur Emby",
|
||||
"RequestAdded": "La demande pour {{title}} a été ajoutée avec succès",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Guarda su Plex",
|
||||
"ViewOnEmby": "Guarda su Emby",
|
||||
"RequestAdded": "La richiesta per {{title}} è stata aggiunta correttamente",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Bekijk op Plex",
|
||||
"ViewOnEmby": "Bekijk op Emby",
|
||||
"RequestAdded": "Aanvraag voor {{title}} is succesvol toegevoegd",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital utgivelse: {{date}}",
|
||||
"TheatricalRelease": "Kinopremiere: {{date}}",
|
||||
"ViewOnPlex": "Spill av på Plex",
|
||||
"ViewOnEmby": "Spill av på Emby",
|
||||
"RequestAdded": "Forespørsel om {{title}} er lagt til",
|
||||
"Similar": "Lignende",
|
||||
"Movies": {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
"DigitalDate": "Digital Release: {{date}}",
|
||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||
"ViewOnPlex": "Visa på Plex",
|
||||
"ViewOnEmby": "Visa på Emby",
|
||||
"RequestAdded": "Efterfrågan om {{title}} har lagts till",
|
||||
"Similar": "Similar",
|
||||
"Movies": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue