pull/1389/head
Jamie.Rees 8 years ago
parent 831c65f563
commit dd5e1c5232

@ -10,7 +10,7 @@
}
@Html.LoadWizardAssets()
<img class="landing-header" src="@formAction/Content/images/logo.png" width="300" />
<img class="landing-header" src="/images/logo.png" width="300" />
<div id="area" class="landing-block shadow">
<div class="media">

@ -1,8 +1,5 @@
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
@ -10,7 +7,7 @@ namespace Ombi.Api
{
public class Api
{
public static JsonSerializerSettings Settings = new JsonSerializerSettings
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
@ -27,5 +24,39 @@ namespace Ombi.Api
var receiveString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(receiveString, Settings);
}
public async Task<T> Request<T>(Request request)
{
using (var httpClient = new HttpClient())
{
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
{
// Add the Json Body
if (request.JsonBody != null)
{
httpRequestMessage.Content = new JsonContent(request.JsonBody);
}
// Add headers
foreach (var header in request.Headers)
{
httpRequestMessage.Headers.Add(header.Key, header.Value);
}
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
{
if (!httpResponseMessage.IsSuccessStatusCode)
{
// Logging
}
// do something with the response
var data = httpResponseMessage.Content;
var receivedString = await data.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(receivedString, Settings);
}
}
}
}
}
}

@ -71,8 +71,5 @@ namespace Ombi.Api
: $"{startingTag}{parameter}={value}";
return builder.Uri;
}
}
}

@ -0,0 +1,13 @@
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
namespace Ombi.Api
{
internal class JsonContent : StringContent
{
public JsonContent(object obj) :
base(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json")
{ }
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
</PropertyGroup>

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
namespace Ombi.Api
{
public class Request
{
public Request(string endpoint, string baseUrl, HttpMethod http)
{
Endpoint = endpoint;
BaseUrl = baseUrl;
HttpMethod = http;
}
public string Endpoint { get; }
public string BaseUrl { get; }
public HttpMethod HttpMethod { get; }
private string FullUrl
{
get
{
var sb = new StringBuilder();
sb.Append(!BaseUrl.EndsWith("/") ? string.Format("{0}/", BaseUrl) : BaseUrl);
sb.Append(Endpoint.StartsWith("/") ? Endpoint.Remove(0, 1) : Endpoint);
return sb.ToString();
}
}
private Uri _modified;
public Uri FullUri
{
get => _modified != null ? _modified : new Uri(FullUrl);
set => _modified = value;
}
public List<KeyValuePair<string, string>> Headers { get; } = new List<KeyValuePair<string, string>>();
public object JsonBody { get; set; }
public bool IsValidUrl
{
get
{
try
{
// ReSharper disable once ObjectCreationAsStatement
new Uri(FullUrl);
return true;
}
catch (Exception)
{
return false;
}
}
}
public void AddHeader(string key, string value)
{
Headers.Add(new KeyValuePair<string, string>(key, value));
}
public void AddJsonBody(object obj)
{
JsonBody = obj;
}
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
</PropertyGroup>

@ -0,0 +1,10 @@
namespace Ombi.Core.Settings.Models.External
{
public sealed class EmbySettings : ExternalSettings
{
public bool Enable { get; set; }
public string ApiKey { get; set; }
public string AdministratorId { get; set; }
public bool EnableEpisodeSearching { get; set; }
}
}

@ -0,0 +1,29 @@
using System;
using Newtonsoft.Json;
using Ombi.Helpers;
namespace Ombi.Core.Settings.Models.External
{
public abstract class ExternalSettings : Settings
{
public bool Ssl { get; set; }
public string SubDir { get; set; }
public string Ip { get; set; }
public int Port { get; set; }
[JsonIgnore]
public virtual Uri FullUri
{
get
{
if (!string.IsNullOrEmpty(SubDir))
{
var formattedSubDir = Ip.ReturnUriWithSubDir(Port, Ssl, SubDir);
return formattedSubDir;
}
var formatted = Ip.ReturnUri(Port, Ssl);
return formatted;
}
}
}
}

@ -0,0 +1,12 @@
namespace Ombi.Core.Settings.Models.External
{
public sealed class PlexSettings : ExternalSettings
{
public bool Enable { get; set; }
public bool EnableEpisodeSearching { get; set; }
public string PlexAuthToken { get; set; }
public string MachineIdentifier { get; set; }
}
}

@ -1,4 +1,6 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Ombi.Core.Settings

@ -118,12 +118,12 @@ namespace Ombi.Core.Settings
private string EncryptSettings(GlobalSettings settings)
{
return StringCipher.Encrypt(settings.Content, settings.SettingsName);
return StringCipher.EncryptString(settings.Content, $"Ombiv3SettingsEncryptionPassword");
}
private string DecryptSettings(GlobalSettings settings)
{
return StringCipher.Decrypt(settings.Content, settings.SettingsName);
return StringCipher.DecryptString(settings.Content, $"Ombiv3SettingsEncryptionPassword");
}
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
</PropertyGroup>
<ItemGroup>

@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EasyCrypto" Version="3.3.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup>

@ -1,3 +1,4 @@
using EasyCrypto;
using System;
using System.IO;
using System.Security.Cryptography;
@ -81,5 +82,18 @@ namespace Ombi.Helpers
}
}
}
public static string EncryptString(string text, string keyString)
{
var result = AesEncryption.EncryptWithPassword(text, keyString);
return result;
}
public static string DecryptString(string cipherText, string keyString)
{
var result = AesEncryption.DecryptWithPassword(cipherText, keyString);
return result;
}
}
}

@ -0,0 +1,123 @@
using System;
namespace Ombi.Helpers
{
public static class UriHelper
{
private const string Https = "Https";
private const string Http = "Http";
public static Uri ReturnUri(this string val)
{
if (val == null)
{
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
}
try
{
var uri = new UriBuilder();
if (val.StartsWith("http://", StringComparison.Ordinal))
{
uri = new UriBuilder(val);
}
else if (val.StartsWith("https://", StringComparison.Ordinal))
{
uri = new UriBuilder(val);
}
else if (val.Contains(":"))
{
var split = val.Split(':', '/');
int port;
int.TryParse(split[1], out port);
uri = split.Length == 3
? new UriBuilder(Http, split[0], port, "/" + split[2])
: new UriBuilder(Http, split[0], port);
}
else
{
uri = new UriBuilder(Http, val);
}
return uri.Uri;
}
catch (Exception exception)
{
throw new Exception(exception.Message, exception);
}
}
/// <summary>
/// Returns the URI.
/// </summary>
/// <param name="val">The value.</param>
/// <param name="port">The port.</param>
/// <param name="ssl">if set to <c>true</c> [SSL].</param>
/// <param name="subdir">The subdir.</param>
/// <returns></returns>
/// <exception cref="ApplicationSettingsException">The URI is null, please check your settings to make sure you have configured the applications correctly.</exception>
/// <exception cref="System.Exception"></exception>
public static Uri ReturnUri(this string val, int port, bool ssl = default(bool))
{
if (val == null)
{
throw new ApplicationSettingsException("The URI is null, please check your settings to make sure you have configured the applications correctly.");
}
try
{
var uri = new UriBuilder();
if (val.StartsWith("http://", StringComparison.Ordinal))
{
var split = val.Split('/');
uri = split.Length >= 4 ? new UriBuilder(Http, split[2], port, "/" + split[3]) : new UriBuilder(new Uri($"{val}:{port}"));
}
else if (val.StartsWith("https://", StringComparison.Ordinal))
{
var split = val.Split('/');
uri = split.Length >= 4
? new UriBuilder(Https, split[2], port, "/" + split[3])
: new UriBuilder(Https, split[2], port);
}
else if (ssl)
{
uri = new UriBuilder(Https, val, port);
}
else
{
uri = new UriBuilder(Http, val, port);
}
return uri.Uri;
}
catch (Exception exception)
{
throw new Exception(exception.Message, exception);
}
}
public static Uri ReturnUriWithSubDir(this string val, int port, bool ssl, string subDir)
{
var uriBuilder = new UriBuilder(val);
if (ssl)
{
uriBuilder.Scheme = Https;
}
if (!string.IsNullOrEmpty(subDir))
{
uriBuilder.Path = subDir;
}
uriBuilder.Port = port;
return uriBuilder.Uri;
}
}
public class ApplicationSettingsException : Exception
{
public ApplicationSettingsException(string s) : base(s)
{
}
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
</PropertyGroup>

@ -65,7 +65,6 @@ namespace Ombi.Store.Repository
public async Task UpdateAsync(GlobalSettings entity)
{
Db.Settings.Update(entity);
await Db.SaveChangesAsync();
}
@ -77,7 +76,6 @@ namespace Ombi.Store.Repository
public void Update(GlobalSettings entity)
{
Db.Settings.Update(entity);
Db.SaveChanges();
}
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<TargetFramework>netstandard1.6</TargetFramework>
<!--<NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>-->
</PropertyGroup>

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Ombi.Api;
using Ombi.TheMovieDbApi.Models;
@ -13,63 +12,62 @@ namespace Ombi.TheMovieDbApi
Api = new Api.Api();
}
private const string ApiToken = "b8eabaf5608b88d0298aa189dd90bf00";
private static readonly Uri BaseUri = new Uri("http://api.themoviedb.org/3/");
public Api.Api Api { get; }
private static readonly string BaseUri ="http://api.themoviedb.org/3/";
private Api.Api Api { get; }
public async Task<MovieResponse> GetMovieInformation(int movieId)
{
var url = BaseUri.ChangePath("movie/{0}", movieId.ToString());
url = AddHeaders(url);
return await Api.Get<MovieResponse>(url);
var request = new Request($"movie/{movieId}", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
return await Api.Request<MovieResponse>(request);
}
public async Task<MovieResponse> GetMovieInformationWithVideo(int movieId)
{
var url = BaseUri.ChangePath("movie/{0}", movieId.ToString());
url = AddHeaders(url);
url = url.AddQueryParameter("append_to_response", "videos");
return await Api.Get<MovieResponse>(url);
var request = new Request($"movie/{movieId}", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
request.FullUri = request.FullUri.AddQueryParameter("append_to_response", "videos");
return await Api.Request<MovieResponse>(request);
}
public async Task<TheMovieDbContainer<SearchResult>> SearchMovie(string searchTerm)
{
var url = BaseUri.ChangePath("search/movie/");
url = AddHeaders(url);
url = url.AddQueryParameter("query", searchTerm);
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
var request = new Request($"search/movie", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
request.FullUri = request.FullUri.AddQueryParameter("query", searchTerm);
return await Api.Request<TheMovieDbContainer<SearchResult>>(request);
}
public async Task<TheMovieDbContainer<SearchResult>> PopularMovies()
{
var url = BaseUri.ChangePath("movie/popular");
url = AddHeaders(url);
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
var request = new Request($"movie/popular", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
return await Api.Request<TheMovieDbContainer<SearchResult>>(request);
}
public async Task<TheMovieDbContainer<SearchResult>> TopRated()
{
var url = BaseUri.ChangePath("movie/top_rated");
url = AddHeaders(url);
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
var request = new Request($"movie/top_rated", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
return await Api.Request<TheMovieDbContainer<SearchResult>>(request);
}
public async Task<TheMovieDbContainer<SearchResult>> Upcoming()
{
var url = BaseUri.ChangePath("movie/upcoming");
url = AddHeaders(url);
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
var request = new Request($"movie/upcoming", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
return await Api.Request<TheMovieDbContainer<SearchResult>>(request);
}
public async Task<TheMovieDbContainer<SearchResult>> NowPlaying()
{
var url = BaseUri.ChangePath("movie/now_playing");
url = AddHeaders(url);
return await Api.Get<TheMovieDbContainer<SearchResult>>(url);
var request = new Request($"movie/now_playing", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
return await Api.Request<TheMovieDbContainer<SearchResult>>(request);
}
private Uri AddHeaders(Uri url)
{
return url.AddQueryParameter("api_key", ApiToken);
}
}
}

@ -1,6 +1,5 @@
/wwwroot/css/**
/wwwroot/fonts/**
/wwwroot/images/**
/wwwroot/lib/**
/wwwroot/maps/**
/wwwroot/app/**/*.js

@ -1,8 +1,10 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ombi.Core.Settings;
using Ombi.Core.Settings.Models;
using Ombi.Core.Settings.Models.External;
namespace Ombi.Controllers
{
@ -19,19 +21,51 @@ namespace Ombi.Controllers
[HttpGet("ombi")]
public async Task<OmbiSettings> OmbiSettings()
{
var settings = SettingsResolver.Resolve<OmbiSettings>();
return await settings.GetSettingsAsync();
return await Get<OmbiSettings>();
}
[HttpPost("ombi")]
public async Task<bool> OmbiSettings([FromBody]OmbiSettings ombi)
{
var settings = SettingsResolver.Resolve<OmbiSettings>();
return await Save(ombi);
}
[HttpGet("plex")]
public async Task<PlexSettings> PlexSettings()
{
return await Get<PlexSettings>();
}
return await settings.SaveSettingsAsync(ombi);
[HttpPost("plex")]
public async Task<bool> PlexSettings([FromBody]PlexSettings plex)
{
return await Save(plex);
}
[HttpGet("emby")]
public async Task<EmbySettings> EmbySettings()
{
return await Get<EmbySettings>();
}
[HttpPost("emby")]
public async Task<bool> EmbySettings([FromBody]EmbySettings emby)
{
return await Save(emby);
}
private async Task<T> Get<T>()
{
var settings = SettingsResolver.Resolve<T>();
return await settings.GetSettingsAsync();
}
private async Task<bool> Save<T>(T settingsModel)
{
var settings = SettingsResolver.Resolve<T>();
return await settings.SaveSettingsAsync(settingsModel);
}
}
}

@ -16,19 +16,82 @@
<Content Include="wwwroot\app\auth\IUserLogin.ts" />
<Content Include="wwwroot\app\login\login.component.html" />
<Content Include="wwwroot\app\login\login.component.ts" />
<Content Include="wwwroot\app\services\setting.service.js" />
<Content Include="wwwroot\app\services\setting.service.js.map" />
<Content Include="wwwroot\app\services\setting.service.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\services\settings.service.js" />
<Content Include="wwwroot\app\services\settings.service.js.map" />
<Content Include="wwwroot\app\services\settings.service.ts" />
<Content Include="wwwroot\app\settings\emby\emby.component.html" />
<Content Include="wwwroot\app\settings\emby\emby.component.js" />
<Content Include="wwwroot\app\settings\emby\emby.component.js.map" />
<Content Include="wwwroot\app\settings\emby\emby.component.ts" />
<Content Include="wwwroot\app\settings\emby\plex.component.html">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\settings\emby\plex.component.js">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\settings\emby\plex.component.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\settings\interfaces\ISettings.ts" />
<Content Include="wwwroot\app\settings\plex\plex.component.html">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\settings\plex\ombi.component.js.map">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\settings\plex\plex.component.js" />
<Content Include="wwwroot\app\settings\plex\plex.component.js.map" />
<Content Include="wwwroot\app\settings\plex\plex.component.ts" />
<Content Include="wwwroot\app\settings\settingsmenu.component.html" />
<Content Include="wwwroot\app\settings\settingsmenu.component.js" />
<Content Include="wwwroot\app\settings\settingsmenu.component.js.map" />
<Content Include="wwwroot\app\settings\settingsmenu.component.ts" />
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.html">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.js" />
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.js.map" />
<Content Include="wwwroot\app\wizard\mediaserver\mediaserver.component.ts" />
<Content Include="wwwroot\app\wizard\mediaserver\welcome.component.js">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\mediaserver\welcome.component.js.map">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\mediaserver\welcome.component.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\settings.module.js">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\settings.module.js.map">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\settings.module.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\welcome\weclome.component.html">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\welcome\emby.component.js">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\welcome\emby.component.js.map">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\welcome\emby.component.ts">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="wwwroot\app\wizard\welcome\weclome.component.js" />
<Content Include="wwwroot\app\wizard\welcome\weclome.component.js.map" />
<Content Include="wwwroot\app\wizard\welcome\weclome.component.ts" />
<Content Include="wwwroot\app\wizard\welcome\welcome.component.html" />
<Content Include="wwwroot\app\wizard\welcome\welcome.component.js" />
<Content Include="wwwroot\app\wizard\welcome\welcome.component.js.map" />
<Content Include="wwwroot\app\wizard\welcome\welcome.component.ts" />
<Content Include="wwwroot\app\wizard\wizard.module.js" />
<Content Include="wwwroot\app\wizard\wizard.module.js.map" />
<Content Include="wwwroot\app\wizard\wizard.module.ts" />
</ItemGroup>
<ItemGroup>

@ -1,4 +1,4 @@
<p-growl [value]="notificationService.messages" ></p-growl>
<p-growl [value]="notificationService.messages" [life]="500000" ></p-growl>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">

@ -26,6 +26,7 @@ import { AuthModule } from './auth/auth.module';
// Modules
import { SettingsModule } from './settings/settings.module';
import { WizardModule } from './wizard/wizard.module';
import { ButtonModule } from 'primeng/primeng';
import { GrowlModule } from 'primeng/components/growl/growl';
@ -52,7 +53,8 @@ const routes: Routes = [
DataTableModule,
SharedModule,
InfiniteScrollModule,
AuthModule
AuthModule,
WizardModule
],
declarations: [
AppComponent,

@ -3,7 +3,7 @@ import { AuthHttp } from 'angular2-jwt';
import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from './service.helpers';
import { IOmbiSettings } from '../settings/interfaces/ISettings';
import { IOmbiSettings, IEmbySettings, IPlexSettings } from '../settings/interfaces/ISettings';
@Injectable()
@ -13,11 +13,27 @@ export class SettingsService extends ServiceAuthHelpers {
}
getOmbi(): Observable<IOmbiSettings> {
return this.http.get(this.url).map(this.extractData);
return this.http.get(`${this.url}/Ombi/`).map(this.extractData);
}
saveOmbi(settings: IOmbiSettings): Observable<boolean> {
return this.http.post(`${this.url}/Ombi/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
}
getEmby(): Observable<IEmbySettings> {
return this.http.get(`${this.url}/Emby/`).map(this.extractData);
}
saveEmby(settings: IEmbySettings): Observable<boolean> {
return this.http.post(`${this.url}/Emby/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
}
getPlex(): Observable<IPlexSettings> {
return this.http.get(`${this.url}/Plex/`).map(this.extractData);
}
savePlex(settings: IPlexSettings): Observable<boolean> {
return this.http.post(`${this.url}/Plex/`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData);
}
}

@ -0,0 +1,58 @@
<div class="col-sm-8 col-sm-push-1">
<fieldset>
<legend>Emby Configuration</legend>
<div class="form-group">
<label for="Ip" class="control-label">Hostname or IP</label>
<div>
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" [(ngModel)]="settings.ip" value="{{settings.ip}}">
</div>
</div>
<div class="form-group">
<label for="portNumber" class="control-label">Port</label>
<div>
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{settings.port}}">
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="ssl" [(ngModel)]="settings.ssl" ng-checked="settings.ssl">
<label for="ssl">SSL</label>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="EnableTvEpisodeSearching" [(ngModel)]="settings.enableEpisodeSearching" ng-checked="settings.enableEpisodeSearching">
<label for="EnableTvEpisodeSearching">Enable Episode Searching</label>
</div>
</div>
<div class="form-group">
<label for="authToken" class="control-label">Emby Api Key</label>
<div class="">
<input type="text" class="form-control-custom form-control" id="authToken" [(ngModel)]="settings.apiKey" placeholder="Emby Api Key" value="{{settings.apiKey}}">
</div>
</div>
<div class="form-group">
<div>
<button id="testPlex" type="submit" (click)="test()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
</div>
</div>
<div class="form-group">
<div>
<button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</fieldset>
</div>

@ -0,0 +1,35 @@
import { Component, OnInit } from '@angular/core';
import { IEmbySettings } from '../interfaces/ISettings'
import { SettingsService } from '../../services/settings.service';
import { NotificationService } from "../../services/notification.service";
@Component({
selector: 'ombi',
moduleId: module.id,
templateUrl: './emby.component.html',
})
export class EmbyComponent implements OnInit {
constructor(private settingsService: SettingsService, private notificationService: NotificationService) { }
settings: IEmbySettings;
ngOnInit(): void {
this.settingsService.getEmby().subscribe(x => this.settings = x);
}
test() {
// TODO Emby Service
}
save() {
this.settingsService.saveEmby(this.settings).subscribe(x => {
if (x) {
this.notificationService.success("Settings Saved", "Successfully saved Emby settings");
} else {
this.notificationService.success("Settings Saved", "There was an error when saving the Emby settings");
}
});
}
}

@ -2,10 +2,31 @@
id:number
}
export interface IExternalSettings extends ISettings {
ssl: boolean,
subDir: boolean,
ip: string,
port:number
}
export interface IOmbiSettings extends ISettings {
port: number,
//baseUrl:string,
collectAnalyticData: boolean,
wizard: boolean,
apiKey:string
}
export interface IEmbySettings extends IExternalSettings {
enable: boolean,
apiKey: string,
administratorId: string,
enableEpisodeSearching:boolean
}
export interface IPlexSettings extends IExternalSettings {
enable: boolean,
enableEpisodeSearching: boolean,
plexAuthToken: string,
machineIdentifier: string
}

@ -1,10 +1,11 @@
<div class="col-sm-8 col-sm-push-1">
<fieldset>
<legend>Ombi Configuration</legend>
<div class="form-group">
<label for="portNumber" class="control-label">Port</label>
<div>
<input type="text" [(ngModel="settings.port" )] class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{settings.port}}">
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{settings.port}}">
</div>
</div>
<small class="control-label">You will have to restart after changing the port.</small>
@ -22,28 +23,28 @@
<div class="form-group">
<label for="ApiKey" class="control-label">Api Key</label>
<div class="input-group">
<input [(ngModel="settings.apiKey" )]] type="text" [readonly]="true" class="form-control form-control-custom" id="ApiKey" name="ApiKey" value="{{settings.apiKey}}">
<input [(ngModel)]="settings.apiKey" type="text" [readonly]="true" class="form-control form-control-custom" id="ApiKey" name="ApiKey" value="{{settings.apiKey}}">
<div class="input-group-addon">
<div (click)="refreshApiKey()" id="refreshKey" class="fa fa-refresh" title="Reset API Key"></div>
</div>
<div class="input-group-addon">
<div class="fa fa-clipboard" data-clipboard-action="copy"></div>
<div class="fa fa-clipboard" ></div>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="CollectAnalyticData" name="CollectAnalyticData" [(ngModel="settings.collectAnalyticData" )]] ng-checked="settings.collectAnalyticData">
<input type="checkbox" id="CollectAnalyticData" name="CollectAnalyticData" [(ngModel)]="settings.collectAnalyticData" ng-checked="settings.collectAnalyticData">
<label for="CollectAnalyticData">Allow us to collect anonymous analytical data e.g. browser used</label>
</div>
</div>
<div class="form-group">
<div>
<button type="submit" id="save" class="btn btn-primary-outline">Submit</button>
<button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</fieldset>

@ -2,6 +2,7 @@
import { IOmbiSettings } from '../interfaces/ISettings'
import { SettingsService } from '../../services/settings.service';
import { NotificationService } from "../../services/notification.service";
@Component({
selector: 'ombi',
@ -10,11 +11,18 @@ import { SettingsService } from '../../services/settings.service';
})
export class OmbiComponent implements OnInit {
constructor(private settingsService: SettingsService) { }
constructor(private settingsService: SettingsService, private notificationService: NotificationService) { }
settings: IOmbiSettings;
ngOnInit(): void {
this.settings = {
apiKey: "",
port: 3579,
wizard: true,
collectAnalyticData: true,
id:0
}
this.settingsService.getOmbi().subscribe(x => this.settings = x);
}
@ -22,4 +30,14 @@ export class OmbiComponent implements OnInit {
refreshApiKey() {
}
save() {
this.settingsService.saveOmbi(this.settings).subscribe(x => {
if (x) {
this.notificationService.success("Settings Saved", "Successfully saved Ombi settings");
} else {
this.notificationService.success("Settings Saved", "There was an error when saving the Ombi settings");
}
});
}
}

@ -0,0 +1,85 @@
<div class="col-sm-8 col-sm-push-1">
<fieldset>
<legend>Plex Configuration</legend>
<div class="form-group">
<label for="Ip" class="control-label">Hostname or IP</label>
<div>
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" placeholder="localhost" [(ngModel)]="settings.ip" value="{{settings.ip}}">
</div>
</div>
<div class="form-group">
<label for="portNumber" class="control-label">Port</label>
<div>
<input type="text" [(ngModel)]="settings.port" class="form-control form-control-custom " id="portNumber" name="Port" placeholder="Port Number" value="{{settings.port}}">
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="ssl" [(ngModel)]="settings.ssl" ng-checked="settings.ssl">
<label for="ssl">SSL</label>
</div>
</div>
<div class="form-group">
<div class="checkbox">
<input type="checkbox" id="EnableTvEpisodeSearching" [(ngModel)]="settings.enableEpisodeSearching" ng-checked="settings.enableEpisodeSearching">
<label for="EnableTvEpisodeSearching">Enable Episode Searching</label>
</div>
<small>
If enabled then we will lookup all episodes on your Plex server and store them in the local database. This will stop episode requests that already exist on Plex (that might not be in Sonarr).
Please be aware that this is a very resource intensive process and while the Plex Episode Cacher job is running the application may appear slow (Depending on the size of your Plex library).
</small>
</div>
<div class="form-group">
<label for="authToken" class="control-label">Plex Authorization Token</label>
<div class="">
<input type="text" class="form-control-custom form-control" id="authToken" [(ngModel)]="settings.plexAuthToken" placeholder="Plex Auth Token" value="{{settings.plexAuthToken}}">
</div>
</div>
<div class="form-group">
<label for="MachineIdentifier" class="control-label">Machine Identifier</label>
<div class="">
<input type="text" class="form-control-custom form-control" id="MachineIdentifier" name="MachineIdentifier" [(ngModel)]="settings.machineIdentifier" value="{{settings.machineIdentifier}}">
</div>
</div>
<div class="form-group">
<label for="username" class="control-label">Username and Password</label>
<div>
<input type="text" class="form-control form-control-custom" id="username" [(ngModel)]="username" placeholder="username">
</div>
<br />
<div>
<input type="password" class="form-control form-control-custom" id="password" [(ngModel)]="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="">
<button id="requestToken" (click)="requestToken()" class="btn btn-primary-outline">Request Token <i class="fa fa-key"></i></button>
</div>
</div>
<div class="form-group">
<div>
<button id="testPlex" type="submit" (click)="testPlex()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
</div>
</div>
<div class="form-group">
<div>
<button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</fieldset>
</div>

@ -0,0 +1,41 @@
import { Component, OnInit } from '@angular/core';
import { IPlexSettings } from '../interfaces/ISettings'
import { SettingsService } from '../../services/settings.service';
import { NotificationService } from "../../services/notification.service";
@Component({
selector: 'ombi',
moduleId: module.id,
templateUrl: './plex.component.html',
})
export class PlexComponent implements OnInit {
constructor(private settingsService: SettingsService, private notificationService: NotificationService) { }
settings: IPlexSettings;
username: string;
password:string;
ngOnInit(): void {
this.settingsService.getPlex().subscribe(x => this.settings = x);
}
requestToken() {
// TODO Plex Service
}
testPlex() {
// TODO Plex Service
}
save() {
this.settingsService.savePlex(this.settings).subscribe(x => {
if (x) {
this.notificationService.success("Settings Saved", "Successfully saved Plex settings");
} else {
this.notificationService.success("Settings Saved", "There was an error when saving the Plex settings");
}
});
}
}

@ -8,13 +8,17 @@ import { AuthGuard } from '../auth/auth.guard';
import { AuthModule } from '../auth/auth.module';
import { OmbiComponent } from './ombi/ombi.component'
import { PlexComponent } from './plex/plex.component'
import { EmbyComponent } from './emby/emby.component'
import { SettingsMenuComponent } from './settingsmenu.component';
import { MenuModule, InputSwitchModule, InputTextModule } from 'primeng/primeng';
const routes: Routes = [
{ path: 'Settings/Ombi', component: OmbiComponent, canActivate: [AuthGuard] }
{ path: 'Settings/Ombi', component: OmbiComponent, canActivate: [AuthGuard] },
{ path: 'Settings/Plex', component: PlexComponent, canActivate: [AuthGuard] },
{ path: 'Settings/Emby', component: EmbyComponent, canActivate: [AuthGuard] },
];
@NgModule({
@ -29,7 +33,9 @@ const routes: Routes = [
],
declarations: [
SettingsMenuComponent,
OmbiComponent
OmbiComponent,
PlexComponent,
EmbyComponent,
],
exports: [
RouterModule

@ -0,0 +1,17 @@
 <div>
<h4 class="media-heading landing-title wizard-heading" id="statusTitle">Please choose your media server</h4>
<div class="form-group">
<div class="row">
<a (click)="emby()" id="embyImg">
<img class="wizard-img" src="/images/emby-logo-dark.jpg" />
</a>
</div>
<div class="row">
<a (click)="plex()" id="plexImg">
<img class="wizard-img" src="/images/plex-logo-reversed.png" />
</a>
</div>
</div>
</div>

@ -0,0 +1,22 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'ombi',
moduleId: module.id,
templateUrl: './mediaserver.component.html',
})
export class MediaServerComponent {
constructor(private router: Router) {
}
plex() {
this.router.navigate(['Wizard/Plex']);
}
emby() {
this.router.navigate(['Wizard/Emby']);
}
}

@ -0,0 +1,17 @@

<img class="landing-header" src="/images/logo.png" width="300" />
<div id="area" class="landing-block shadow">
<div class="media">
<div id="contentBody" class="media-body">
<h4 class="media-heading landing-title" id="statusTitle">Welcome to Ombi</h4>
<div class="form-group">
<small>we are just going to run though the initial Ombi setup!</small>
<div style="text-align: center; margin-top: 20px">
<a (click)="next()" class="btn btn-primary-outline">Next</a>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,18 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'ombi',
moduleId: module.id,
templateUrl: './welcome.component.html',
})
export class WelcomeComponent {
constructor(private router: Router) {
}
next() {
this.router.navigate(['Wizard/MediaServer']);
}
}

@ -0,0 +1,31 @@
import { NgModule, } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { WelcomeComponent } from './welcome/welcome.component';
import { MediaServerComponent } from './mediaserver/mediaserver.component';
const routes: Routes = [
{ path: 'Wizard', component: WelcomeComponent},
{ path: 'Wizard/MediaServer', component: MediaServerComponent},
];
@NgModule({
imports: [
CommonModule,
FormsModule,
RouterModule.forChild(routes)
],
declarations: [
WelcomeComponent,
MediaServerComponent
],
exports: [
RouterModule
],
providers: [
],
})
export class WizardModule { }

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Loading…
Cancel
Save