mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-21 05:43:19 -07:00
Started adding Emby, Lots of backend work done. Need a few more services done and login and user management. #435
This commit is contained in:
parent
2ab7aaa4b9
commit
868301f552
43 changed files with 1495 additions and 18 deletions
|
@ -97,6 +97,8 @@ namespace Ombi.UI.Modules.Admin
|
|||
private IDiscordApi DiscordApi { get; }
|
||||
private ISettingsService<RadarrSettings> RadarrSettings { get; }
|
||||
private IRadarrApi RadarrApi { get; }
|
||||
private ISettingsService<EmbySettings> EmbySettings { get; }
|
||||
private IEmbyApi EmbyApi { get; }
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
public AdminModule(ISettingsService<PlexRequestSettings> prService,
|
||||
|
@ -124,7 +126,8 @@ namespace Ombi.UI.Modules.Admin
|
|||
ISettingsService<NotificationSettingsV2> notifyService, IRecentlyAdded recentlyAdded,
|
||||
ISettingsService<WatcherSettings> watcherSettings ,
|
||||
ISettingsService<DiscordNotificationSettings> discord,
|
||||
IDiscordApi discordapi, ISettingsService<RadarrSettings> settings, IRadarrApi radarrApi
|
||||
IDiscordApi discordapi, ISettingsService<RadarrSettings> settings, IRadarrApi radarrApi,
|
||||
ISettingsService<EmbySettings> embySettings, IEmbyApi emby
|
||||
, ISecurityExtensions security) : base("admin", prService, security)
|
||||
{
|
||||
PrService = prService;
|
||||
|
@ -160,7 +163,9 @@ namespace Ombi.UI.Modules.Admin
|
|||
DiscordApi = discordapi;
|
||||
RadarrSettings = settings;
|
||||
RadarrApi = radarrApi;
|
||||
|
||||
EmbyApi = emby;
|
||||
EmbySettings = embySettings;
|
||||
|
||||
Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx);
|
||||
|
||||
Get["/"] = _ => Admin();
|
||||
|
@ -180,6 +185,10 @@ namespace Ombi.UI.Modules.Admin
|
|||
Get["/plex"] = _ => Plex();
|
||||
Post["/plex", true] = async (x, ct) => await SavePlex();
|
||||
|
||||
Get["/emby", true] = async (x, ct) => await Emby();
|
||||
Post["/emby", true] = async (x, ct) => await SaveEmby();
|
||||
|
||||
|
||||
Get["/sonarr"] = _ => Sonarr();
|
||||
Post["/sonarr"] = _ => SaveSonarr();
|
||||
Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles();
|
||||
|
@ -438,6 +447,13 @@ namespace Ombi.UI.Modules.Admin
|
|||
return Response.AsJson(valid.SendJsonError());
|
||||
}
|
||||
|
||||
var embySettings = await EmbySettings.GetSettingsAsync();
|
||||
|
||||
if (embySettings.Enable)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Emby is enabled, we cannot enable Plex and Emby" });
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(plexSettings.MachineIdentifier))
|
||||
{
|
||||
//Lookup identifier
|
||||
|
@ -453,6 +469,41 @@ namespace Ombi.UI.Modules.Admin
|
|||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||
}
|
||||
|
||||
private async Task<Negotiator> Emby()
|
||||
{
|
||||
var settings = await EmbySettings.GetSettingsAsync();
|
||||
|
||||
return View["Emby", settings];
|
||||
}
|
||||
|
||||
private async Task<Response> SaveEmby()
|
||||
{
|
||||
var emby = this.Bind<EmbySettings>();
|
||||
var valid = this.Validate(emby);
|
||||
if (!valid.IsValid)
|
||||
{
|
||||
return Response.AsJson(valid.SendJsonError());
|
||||
}
|
||||
|
||||
var plexSettings = await PlexService.GetSettingsAsync();
|
||||
if (plexSettings.Enable)
|
||||
{
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Plex is enabled, we cannot enable Plex and Emby" });
|
||||
}
|
||||
|
||||
// Get the users
|
||||
var users = EmbyApi.GetUsers(emby.FullUri, emby.ApiKey);
|
||||
// Find admin
|
||||
var admin = users.FirstOrDefault(x => x.Policy.IsAdministrator);
|
||||
emby.AdministratorId = admin?.Id;
|
||||
|
||||
var result = await EmbySettings.SaveSettingsAsync(emby);
|
||||
|
||||
return Response.AsJson(result
|
||||
? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Emby!" }
|
||||
: new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." });
|
||||
}
|
||||
|
||||
private Negotiator Sonarr()
|
||||
{
|
||||
var settings = SonarrService.GetSettings();
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Ombi.UI.Modules
|
|||
|
||||
public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi,
|
||||
ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService<PlexRequestSettings> pr, ISecurityExtensions security,
|
||||
IWatcherApi watcherApi, IRadarrApi radarrApi) : base("test", pr, security)
|
||||
IWatcherApi watcherApi, IRadarrApi radarrApi, IEmbyApi emby) : base("test", pr, security)
|
||||
{
|
||||
this.RequiresAuthentication();
|
||||
|
||||
|
@ -57,6 +57,7 @@ namespace Ombi.UI.Modules
|
|||
HeadphonesApi = hpApi;
|
||||
WatcherApi = watcherApi;
|
||||
RadarrApi = radarrApi;
|
||||
Emby = emby;
|
||||
|
||||
Post["/cp"] = _ => CouchPotatoTest();
|
||||
Post["/sonarr"] = _ => SonarrTest();
|
||||
|
@ -66,6 +67,7 @@ namespace Ombi.UI.Modules
|
|||
Post["/headphones"] = _ => HeadphonesTest();
|
||||
Post["/plexdb"] = _ => TestPlexDb();
|
||||
Post["/watcher"] = _ => WatcherTest();
|
||||
Post["/emby"] = _ => EmbyTest();
|
||||
}
|
||||
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
@ -76,6 +78,7 @@ namespace Ombi.UI.Modules
|
|||
private IHeadphonesApi HeadphonesApi { get; }
|
||||
private IWatcherApi WatcherApi { get; }
|
||||
private IRadarrApi RadarrApi { get; }
|
||||
private IEmbyApi Emby { get; set; }
|
||||
|
||||
private Response CouchPotatoTest()
|
||||
{
|
||||
|
@ -213,7 +216,7 @@ namespace Ombi.UI.Modules
|
|||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Plex, please check your settings." });
|
||||
|
||||
}
|
||||
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||
{
|
||||
Log.Warn("Exception thrown when attempting to get Plex's status: ");
|
||||
Log.Warn(e);
|
||||
|
@ -225,6 +228,35 @@ namespace Ombi.UI.Modules
|
|||
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
|
||||
}
|
||||
}
|
||||
private Response EmbyTest()
|
||||
{
|
||||
var emby = this.Bind<EmbySettings>();
|
||||
var valid = this.Validate(emby);
|
||||
if (!valid.IsValid)
|
||||
{
|
||||
return Response.AsJson(valid.SendJsonError());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var status = Emby.GetUsers(emby?.FullUri, emby?.ApiKey);
|
||||
return status != null
|
||||
? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to Emby successfully!" })
|
||||
: Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Emby, please check your settings." });
|
||||
|
||||
}
|
||||
catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them.
|
||||
{
|
||||
Log.Warn("Exception thrown when attempting to get Emby's users: ");
|
||||
Log.Warn(e);
|
||||
var message = $"Could not connect to Emby, please check your settings. <strong>Exception Message:</strong> {e.Message}";
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
message = $"Could not connect to Emby, please check your settings. <strong>Exception Message:</strong> {e.InnerException.Message}";
|
||||
}
|
||||
return Response.AsJson(new JsonResponseModel { Result = false, Message = message });
|
||||
}
|
||||
}
|
||||
|
||||
private Response SickRageTest()
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ using Nancy;
|
|||
using Nancy.Extensions;
|
||||
using Nancy.Linker;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Api.Models.Plex;
|
||||
using Ombi.Core;
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace Ombi.UI.NinjectModules
|
|||
Bind<IDiscordApi>().To<DiscordApi>();
|
||||
Bind<IRadarrApi>().To<RadarrApi>();
|
||||
Bind<ITraktApi>().To<TraktApi>();
|
||||
Bind<IEmbyApi>().To<EmbyApi>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,9 @@ namespace Ombi.UI.NinjectModules
|
|||
Bind<IPlexEpisodeCacher>().To<PlexEpisodeCacher>();
|
||||
Bind<IFaultQueueHandler>().To<FaultQueueHandler>();
|
||||
Bind<IPlexUserChecker>().To<PlexUserChecker>();
|
||||
|
||||
Bind<IEmbyAvailabilityChecker>().To<EmbyAvailabilityChecker>();
|
||||
|
||||
|
||||
Bind<IAnalytics>().To<Analytics>();
|
||||
Bind<ISchedulerFactory>().To<StdSchedulerFactory>();
|
||||
|
|
|
@ -295,6 +295,7 @@
|
|||
</Compile>
|
||||
<Compile Include="Start\StartupOptions.cs" />
|
||||
<Compile Include="Start\UpdateValue.cs" />
|
||||
<Compile Include="Validators\EmbyValidator.cs" />
|
||||
<Compile Include="Validators\RadarrValidator.cs" />
|
||||
<Compile Include="Validators\WatcherValidator.cs" />
|
||||
<Compile Include="Validators\SlackSettingsValidator.cs" />
|
||||
|
@ -803,6 +804,9 @@
|
|||
<Content Include="Views\Integration\Radarr.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Views\Admin\Emby.cshtml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Web.Debug.config">
|
||||
<DependentUpon>web.config</DependentUpon>
|
||||
</None>
|
||||
|
|
|
@ -31,6 +31,7 @@ using Ninject;
|
|||
using Ninject.Planning.Bindings.Resolvers;
|
||||
using Ninject.Syntax;
|
||||
using NLog;
|
||||
using Ombi.Api;
|
||||
using Ombi.Api.Interfaces;
|
||||
using Ombi.Core;
|
||||
using Ombi.Core.Migration;
|
||||
|
@ -83,6 +84,7 @@ namespace Ombi.UI
|
|||
var scheduler = new Scheduler();
|
||||
|
||||
|
||||
|
||||
// Reset any jobs running
|
||||
var jobSettings = kernel.Get<IRepository<ScheduledJobs>>();
|
||||
var all = jobSettings.GetAll();
|
||||
|
|
42
Ombi.UI/Validators/EmbyValidator.cs
Normal file
42
Ombi.UI/Validators/EmbyValidator.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#region Copyright
|
||||
// /************************************************************************
|
||||
// Copyright (c) 2016 Jamie Rees
|
||||
// File: SonarrValidator.cs
|
||||
// Created By: Jamie Rees
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
// ************************************************************************/
|
||||
#endregion
|
||||
|
||||
using FluentValidation;
|
||||
using Ombi.Core.SettingModels;
|
||||
|
||||
namespace Ombi.UI.Validators
|
||||
{
|
||||
public class EmbyValidator : AbstractValidator<EmbySettings>
|
||||
{
|
||||
public EmbyValidator()
|
||||
{
|
||||
RuleFor(request => request.Ip).NotNull().WithMessage("You must specify a IP/Host name.");
|
||||
RuleFor(request => request.Port).NotNull().WithMessage("You must specify a Port.");
|
||||
RuleFor(request => request.ApiKey).NotNull().WithMessage("You must specify a Api Key.");
|
||||
}
|
||||
}
|
||||
}
|
146
Ombi.UI/Views/Admin/Emby.cshtml
Normal file
146
Ombi.UI/Views/Admin/Emby.cshtml
Normal file
|
@ -0,0 +1,146 @@
|
|||
@using Ombi.UI.Helpers
|
||||
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<Ombi.Core.SettingModels.EmbySettings>
|
||||
@Html.Partial("Shared/Partial/_Sidebar")
|
||||
@{
|
||||
int port;
|
||||
if (Model.Port == 0)
|
||||
{
|
||||
port = 8096;
|
||||
}
|
||||
else
|
||||
{
|
||||
port = Model.Port;
|
||||
}
|
||||
}
|
||||
<div class="col-sm-8 col-sm-push-1">
|
||||
<form class="form-horizontal" method="POST" id="mainForm">
|
||||
<fieldset>
|
||||
<legend>Emby Settings</legend>
|
||||
|
||||
@Html.Checkbox(Model.Enable, "Enable", "Enabled")
|
||||
<div class="form-group">
|
||||
<label for="Ip" class="control-label">Emby Hostname or IP</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" value="@Model.Ip">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="portNumber" class="control-label">Port</label>
|
||||
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="@port">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
|
||||
@if (Model.Ssl)
|
||||
{
|
||||
<input type="checkbox" id="Ssl" name="Ssl" checked="checked"><label for="Ssl">SSL</label>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input type="checkbox" id="Ssl" name="Ssl"><label for="Ssl">SSL</label>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="SubDir" class="control-label">Emby Base Url</label>
|
||||
<div>
|
||||
<input type="text" class="form-control form-control-custom " id="SubDir" name="SubDir" value="@Model.SubDir">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ApiKey" class="control-label">Emby Api Key</label>
|
||||
<div class="">
|
||||
<input type="text" class="form-control-custom form-control" id="ApiKey" name="ApiKey" placeholder="Api Key" value="@Model.ApiKey">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button id="testEmby" type="submit" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<button id="save" type="submit" class="btn btn-primary-outline">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var base = '@Html.GetBaseUrl()';
|
||||
|
||||
$('#testEmby').click(function (e) {
|
||||
e.preventDefault();
|
||||
var url = createBaseUrl(base, '/test/emby');
|
||||
var $form = $("#mainForm");
|
||||
|
||||
$('#spinner').attr("class", "fa fa-spinner fa-spin");
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
url: url,
|
||||
data: $form.serialize(),
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
$('#spinner').attr("class", "");
|
||||
console.log(response);
|
||||
if (response.result === true) {
|
||||
generateNotify(response.message, "success");
|
||||
|
||||
$('#spinner').attr("class", "fa fa-check");
|
||||
} else {
|
||||
generateNotify(response.message, "warning");
|
||||
$('#spinner').attr("class", "fa fa-times");
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
|
||||
$('#spinner').attr("class", "fa fa-times");
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#save').click(function (e) {
|
||||
e.preventDefault();
|
||||
var port = $('#portNumber').val();
|
||||
if (isNaN(port)) {
|
||||
generateNotify("You must specify a Port.", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
var $form = $("#mainForm");
|
||||
$.ajax({
|
||||
type: $form.prop("method"),
|
||||
data: $form.serialize(),
|
||||
url: $form.prop("action"),
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response.result === true) {
|
||||
generateNotify(response.message, "success");
|
||||
} else {
|
||||
generateNotify(response.message, "warning");
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e);
|
||||
generateNotify("Something went wrong!", "danger");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
|
@ -17,6 +17,8 @@
|
|||
<fieldset>
|
||||
<legend>Plex Settings</legend>
|
||||
@*<input id="advancedToggle" type="checkbox"/>*@ @*TODO*@
|
||||
|
||||
@Html.Checkbox(Model.Enable, "Enable", "Enable")
|
||||
<div class="form-group">
|
||||
<label for="Ip" class="control-label">Plex Hostname or IP</label>
|
||||
<div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue