diff --git a/src/Ombi.Api.CouchPotato/CouchPotatoApi.cs b/src/Ombi.Api.CouchPotato/CouchPotatoApi.cs new file mode 100644 index 000000000..8980c4b11 --- /dev/null +++ b/src/Ombi.Api.CouchPotato/CouchPotatoApi.cs @@ -0,0 +1,84 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Ombi.Api.CouchPotato.Models; +using Ombi.Helpers; + +namespace Ombi.Api.CouchPotato +{ + public class CouchPotatoApi : ICouchPotatoApi + { + public CouchPotatoApi(IApi api, ILogger log) + { + _api = api; + _log = log; + } + + private readonly IApi _api; + private readonly ILogger _log; + + public async Task AddMovie(string imdbid, string apiKey, string title, string baseUrl, string profileId = default(string)) + { + var request = new Request($"/api/{apiKey}/movie.add", baseUrl, HttpMethod.Get); + + request.AddQueryString("title", title); + request.AddQueryString("identifier", imdbid); + if (!string.IsNullOrEmpty(profileId)) + { + request.AddQueryString("profile_id", profileId); + } + + var obj = await _api.Request(request); + + if (obj.Count > 0) + { + try + { + var result = (bool)obj["success"]; + return result; + } + catch (Exception e) + { + _log.LogError(LoggingEvents.CouchPotatoApi, e, "Error calling AddMovie"); + return false; + } + } + return false; + } + + public async Task Status(string url, string apiKey) + { + var request = new Request($"api/{apiKey}/app.available/", url, HttpMethod.Get); + return await _api.Request(request); + } + + public async Task GetProfiles(string url, string apiKey) + { + var request = new Request($"api/{apiKey}/profile.list/", url, HttpMethod.Get); + return await _api.Request(request); + } + + public async Task GetMovies(string baseUrl, string apiKey, string[] status) + { + var request = new Request($"/api/{apiKey}/movie.list", baseUrl, HttpMethod.Get); + + request.AddQueryString("status",string.Join(",", status)); + request.OnBeforeDeserialization = json => + { + json.Replace("[]", "{}"); + }; + return await _api.Request(request); + } + + public async Task GetApiKey(string baseUrl, string username, string password) + { + var request = new Request("getkey/",baseUrl, HttpMethod.Get); + request.AddQueryString("u",username.CalcuateMd5Hash()); + request.AddQueryString("p",password.CalcuateMd5Hash()); + + return await _api.Request(request); + } + } +} diff --git a/src/Ombi.Api.CouchPotato/ICouchPotatoApi.cs b/src/Ombi.Api.CouchPotato/ICouchPotatoApi.cs new file mode 100644 index 000000000..fdf567497 --- /dev/null +++ b/src/Ombi.Api.CouchPotato/ICouchPotatoApi.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Ombi.Api.CouchPotato.Models; + +namespace Ombi.Api.CouchPotato +{ + public interface ICouchPotatoApi + { + Task AddMovie(string imdbid, string apiKey, string title, string baseUrl, string profileId = null); + Task GetApiKey(string baseUrl, string username, string password); + Task GetMovies(string baseUrl, string apiKey, string[] status); + Task GetProfiles(string url, string apiKey); + Task Status(string url, string apiKey); + } +} \ No newline at end of file diff --git a/src/Ombi.Api.CouchPotato/Models/CouchPotatoApiKey.cs b/src/Ombi.Api.CouchPotato/Models/CouchPotatoApiKey.cs new file mode 100644 index 000000000..9fdfe6473 --- /dev/null +++ b/src/Ombi.Api.CouchPotato/Models/CouchPotatoApiKey.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Ombi.Api.CouchPotato.Models +{ + public class CouchPotatoApiKey + { + [JsonProperty("success")] + public bool success { get; set; } + [JsonProperty("api_key")] + public string ApiKey { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.CouchPotato/Models/CouchPotatoMovies.cs b/src/Ombi.Api.CouchPotato/Models/CouchPotatoMovies.cs new file mode 100644 index 000000000..a1b2619cf --- /dev/null +++ b/src/Ombi.Api.CouchPotato/Models/CouchPotatoMovies.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; + +namespace Ombi.Api.CouchPotato.Models +{ + public class CouchPotatoMovies + { + public List movies { get; set; } + public int total { get; set; } + public bool success { get; set; } + public bool empty { get; set; } + } + + public class Movie + { + public string _id { get; set; } + public string _rev { get; set; } + public string _t { get; set; } + public object category_id { get; set; } + public Files files { get; set; } + public Identifiers identifiers { get; set; } + public Info info { get; set; } + public int last_edit { get; set; } + public string profile_id { get; set; } + public List releases { get; set; } + public string status { get; set; } + public List tags { get; set; } + public string title { get; set; } + public string type { get; set; } + } + public class CouchPotatoAdd + { + public Movie movie { get; set; } + public bool success { get; set; } + } + + public class Rating + { + public List imdb { get; set; } + } + + public class Images + { + public List actors { get; set; } + public List backdrop { get; set; } + public List backdrop_original { get; set; } + public List banner { get; set; } + public List clear_art { get; set; } + public List disc_art { get; set; } + public List extra_fanart { get; set; } + public List extra_thumbs { get; set; } + public List landscape { get; set; } + public List logo { get; set; } + public List poster { get; set; } + public List poster_original { get; set; } + } + + public class Info + { + public List actor_roles { get; set; } + public List actors { get; set; } + public List directors { get; set; } + public List genres { get; set; } + public Images images { get; set; } + public string imdb { get; set; } + public string mpaa { get; set; } + public string original_title { get; set; } + public string plot { get; set; } + public Rating rating { get; set; } + public Release_Date release_date { get; set; } + public string released { get; set; } + public int runtime { get; set; } + public string tagline { get; set; } + public List titles { get; set; } + public int tmdb_id { get; set; } + public string type { get; set; } + public bool via_imdb { get; set; } + public bool via_tmdb { get; set; } + public List writers { get; set; } + public int year { get; set; } + } + + public class Release_Date + { + public bool bluray { get; set; } + public int dvd { get; set; } + public int expires { get; set; } + public int theater { get; set; } + } + + public class Files + { + public List image_poster { get; set; } + } + + public class Identifiers + { + public string imdb { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.CouchPotato/Models/CouchPotatoProfiles.cs b/src/Ombi.Api.CouchPotato/Models/CouchPotatoProfiles.cs new file mode 100644 index 000000000..44b1b817d --- /dev/null +++ b/src/Ombi.Api.CouchPotato/Models/CouchPotatoProfiles.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Ombi.Api.CouchPotato.Models +{ + public class ProfileList + { + public bool core { get; set; } + public bool hide { get; set; } + public string _rev { get; set; } + public List finish { get; set; } + public List qualities { get; set; } + public string _id { get; set; } + public string _t { get; set; } + public string label { get; set; } + public int minimum_score { get; set; } + public List stop_after { get; set; } + public List wait_for { get; set; } + public int order { get; set; } + [JsonProperty(PropertyName = "3d")] + public List threeD { get; set; } + } + + public class CouchPotatoProfiles + { + public List list { get; set; } + public bool success { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.CouchPotato/Models/CouchPotatoStatus.cs b/src/Ombi.Api.CouchPotato/Models/CouchPotatoStatus.cs new file mode 100644 index 000000000..4721f221f --- /dev/null +++ b/src/Ombi.Api.CouchPotato/Models/CouchPotatoStatus.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.CouchPotato.Models +{ + public class CouchPotatoStatus + { + public bool success { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj b/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj new file mode 100644 index 000000000..a3651df3c --- /dev/null +++ b/src/Ombi.Api.CouchPotato/Ombi.Api.CouchPotato.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + + diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index de1ec8caf..354f90d91 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -52,6 +52,7 @@ namespace Ombi.Api var receivedString = await data.ReadAsStringAsync(); if (request.ContentType == ContentType.Json) { + request.OnBeforeDeserialization?.Invoke(receivedString); return JsonConvert.DeserializeObject(receivedString, Settings); } else diff --git a/src/Ombi.Api/Request.cs b/src/Ombi.Api/Request.cs index 67453faf3..16dd38055 100644 --- a/src/Ombi.Api/Request.cs +++ b/src/Ombi.Api/Request.cs @@ -25,6 +25,8 @@ namespace Ombi.Api public string BaseUrl { get; } public HttpMethod HttpMethod { get; } + public Action OnBeforeDeserialization { get; set; } + private string FullUrl { get diff --git a/src/Ombi.Core/Senders/TvSender.cs b/src/Ombi.Core/Senders/TvSender.cs index 46fa14470..574cf6978 100644 --- a/src/Ombi.Core/Senders/TvSender.cs +++ b/src/Ombi.Core/Senders/TvSender.cs @@ -8,6 +8,7 @@ using Ombi.Api.Sonarr.Models; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; +using Ombi.Settings.Settings.Models.External; using Ombi.Store.Entities.Requests; namespace Ombi.Core.Senders diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 1e0ba1d80..1f3458b85 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -31,6 +31,7 @@ using Ombi.Store.Repository; using Ombi.Notifications.Agents; using Ombi.Schedule.Jobs.Radarr; using Ombi.Api; +using Ombi.Api.CouchPotato; using Ombi.Api.FanartTv; using Ombi.Api.Mattermost; using Ombi.Api.Pushbullet; @@ -95,6 +96,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } public static void RegisterStore(this IServiceCollection services) diff --git a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 124d81439..8dc69d646 100644 --- a/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/src/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index 5d6b17aa5..d74ca2556 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -8,6 +8,7 @@ namespace Ombi.Helpers public static EventId Api => new EventId(1000); public static EventId RadarrApi => new EventId(1001); + public static EventId CouchPotatoApi => new EventId(1002); public static EventId Cacher => new EventId(2000); public static EventId RadarrCacher => new EventId(2001); diff --git a/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs b/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs index 591f02747..d2687f432 100644 --- a/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs +++ b/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs @@ -8,6 +8,7 @@ using Ombi.Api.Sonarr; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; +using Ombi.Settings.Settings.Models.External; using Ombi.Store.Context; using Ombi.Store.Entities; diff --git a/src/Ombi.Settings/Settings/Models/External/CouchPotatoSettings.cs b/src/Ombi.Settings/Settings/Models/External/CouchPotatoSettings.cs new file mode 100644 index 000000000..19a79e1d7 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/External/CouchPotatoSettings.cs @@ -0,0 +1,13 @@ +using Ombi.Core.Settings.Models.External; + +namespace Ombi.Settings.Settings.Models.External +{ + public class CouchPotatoSettings : ExternalSettings + { + public bool Enabled { get; set; } + public string ApiKey { get; set; } + public string DefaultProfileId { get; set; } + public string Username { get; set; } + public string Password { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/External/EmbySettings.cs b/src/Ombi.Settings/Settings/Models/External/EmbySettings.cs index 5601ca20e..96df77281 100644 --- a/src/Ombi.Settings/Settings/Models/External/EmbySettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/EmbySettings.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ombi.Settings.Settings.Models.External; namespace Ombi.Core.Settings.Models.External { diff --git a/src/Ombi.Settings/Settings/Models/External/ExternalSettings.cs b/src/Ombi.Settings/Settings/Models/External/ExternalSettings.cs index 6504a32ba..e93f36483 100644 --- a/src/Ombi.Settings/Settings/Models/External/ExternalSettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/ExternalSettings.cs @@ -1,10 +1,9 @@ -using System; -using Newtonsoft.Json; +using Newtonsoft.Json; using Ombi.Helpers; -namespace Ombi.Core.Settings.Models.External +namespace Ombi.Settings.Settings.Models.External { - public abstract class ExternalSettings : Ombi.Settings.Settings.Models.Settings + public abstract class ExternalSettings : Models.Settings { public bool Ssl { get; set; } public string SubDir { get; set; } diff --git a/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs b/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs index 94963a03d..79a70c2f6 100644 --- a/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/PlexSettings.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Ombi.Settings.Settings.Models.External; namespace Ombi.Core.Settings.Models.External { diff --git a/src/Ombi.Settings/Settings/Models/External/SonarrSettings.cs b/src/Ombi.Settings/Settings/Models/External/SonarrSettings.cs index 6b2b0d3b0..789b8f384 100644 --- a/src/Ombi.Settings/Settings/Models/External/SonarrSettings.cs +++ b/src/Ombi.Settings/Settings/Models/External/SonarrSettings.cs @@ -1,4 +1,4 @@ -namespace Ombi.Core.Settings.Models.External +namespace Ombi.Settings.Settings.Models.External { public class SonarrSettings : ExternalSettings { diff --git a/src/Ombi.sln b/src/Ombi.sln index 111bfb95b..da9d4aac9 100644 --- a/src/Ombi.sln +++ b/src/Ombi.sln @@ -80,6 +80,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Pushover", "Ombi.A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Schedule.Tests", "Ombi.Schedule.Tests\Ombi.Schedule.Tests.csproj", "{BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.CouchPotato", "Ombi.Api.CouchPotato\Ombi.Api.CouchPotato.csproj", "{87D7897D-7C73-4856-A0AA-FF5948F4EA86}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -202,6 +204,10 @@ Global {BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Debug|Any CPU.Build.0 = Debug|Any CPU {BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C}.Release|Any CPU.Build.0 = Release|Any CPU + {87D7897D-7C73-4856-A0AA-FF5948F4EA86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87D7897D-7C73-4856-A0AA-FF5948F4EA86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87D7897D-7C73-4856-A0AA-FF5948F4EA86}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87D7897D-7C73-4856-A0AA-FF5948F4EA86}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -230,6 +236,7 @@ Global {737B2620-FE5A-4135-A017-79C269A7D36C} = {9293CA11-360A-4C20-A674-B9E794431BF5} {CA55DD4F-4EFF-4906-A848-35FCC7BD5654} = {9293CA11-360A-4C20-A674-B9E794431BF5} {BDD8B924-016E-4CDA-9FFA-50B0A34BCD3C} = {6F42AB98-9196-44C4-B888-D5E409F415A1} + {87D7897D-7C73-4856-A0AA-FF5948F4EA86} = {9293CA11-360A-4C20-A674-B9E794431BF5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {192E9BF8-00B4-45E4-BCCC-4C215725C869} diff --git a/src/Ombi/ClientApp/app/interfaces/ICouchPotato.ts b/src/Ombi/ClientApp/app/interfaces/ICouchPotato.ts new file mode 100644 index 000000000..fb22cd0c0 --- /dev/null +++ b/src/Ombi/ClientApp/app/interfaces/ICouchPotato.ts @@ -0,0 +1,25 @@ +export interface ICouchPotatoProfiles { + success: boolean; + list: IProfileList[]; +} + +export interface IProfileList { + core: boolean; + hide: boolean; + _rev: string; + finish: boolean[]; + qualities: string[]; + _id: string; + _t: string; + label: string; + minimum_score: number; + stop_after: number[]; + wait_for: object[]; + order: number; + threeD: object[]; +} + +export interface ICouchPotatoApiKey { + success: boolean; + apiKey: string; +} diff --git a/src/Ombi/ClientApp/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/app/interfaces/ISettings.ts index ce9dc5b37..678eb57df 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISettings.ts @@ -119,3 +119,11 @@ export interface IAbout { processArchitecture: string; applicationBasePath: string; } + +export interface ICouchPotatoSettings extends IExternalSettings { + enabled: boolean; + apiKey: string; + defaultProfileId: string; + username: string; + password: string; +} diff --git a/src/Ombi/ClientApp/app/interfaces/index.ts b/src/Ombi/ClientApp/app/interfaces/index.ts index 791a20b19..21427ec8c 100644 --- a/src/Ombi/ClientApp/app/interfaces/index.ts +++ b/src/Ombi/ClientApp/app/interfaces/index.ts @@ -1,4 +1,5 @@ export * from "./ICommon"; +export * from "./ICouchPotato"; export * from "./IImages"; export * from "./IMediaServerStatus"; export * from "./INotificationSettings"; diff --git a/src/Ombi/ClientApp/app/services/applications/couchpotato.service.ts b/src/Ombi/ClientApp/app/services/applications/couchpotato.service.ts new file mode 100644 index 000000000..a4e43ad85 --- /dev/null +++ b/src/Ombi/ClientApp/app/services/applications/couchpotato.service.ts @@ -0,0 +1,23 @@ +import { PlatformLocation } from "@angular/common"; +import { Injectable } from "@angular/core"; +import { AuthHttp } from "angular2-jwt"; +import { Observable } from "rxjs/Rx"; + +import { ServiceAuthHelpers } from "../service.helpers"; + +import { ICouchPotatoApiKey, ICouchPotatoProfiles, ICouchPotatoSettings } from "../../interfaces"; + +@Injectable() +export class CouchPotatoService extends ServiceAuthHelpers { + constructor(http: AuthHttp, public platformLocation: PlatformLocation) { + super(http, "/api/v1/CouchPotato/", platformLocation); + } + + public getProfiles(settings: ICouchPotatoSettings): Observable { + return this.http.post(`${this.url}profile`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + } + + public getApiKey(settings: ICouchPotatoSettings): Observable { + return this.http.post(`${this.url}apikey`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + } +} diff --git a/src/Ombi/ClientApp/app/services/applications/index.ts b/src/Ombi/ClientApp/app/services/applications/index.ts index 0026bc158..9433dfce0 100644 --- a/src/Ombi/ClientApp/app/services/applications/index.ts +++ b/src/Ombi/ClientApp/app/services/applications/index.ts @@ -1,4 +1,5 @@ -export * from "./emby.service"; +export * from "./couchpotato.service"; +export * from "./emby.service"; export * from "./plex.service"; export * from "./radarr.service"; export * from "./sonarr.service"; diff --git a/src/Ombi/ClientApp/app/services/settings.service.ts b/src/Ombi/ClientApp/app/services/settings.service.ts index 4ea75681d..57eb0c405 100644 --- a/src/Ombi/ClientApp/app/services/settings.service.ts +++ b/src/Ombi/ClientApp/app/services/settings.service.ts @@ -7,6 +7,7 @@ import { Observable } from "rxjs/Rx"; import { IAbout, IAuthenticationSettings, + ICouchPotatoSettings, ICustomizationSettings, IDiscordNotifcationSettings, IEmailNotificationSettings, @@ -195,4 +196,14 @@ export class SettingsService extends ServiceAuthHelpers { .post(`${this.url}/UserManagement`, JSON.stringify(settings), { headers: this.headers }) .map(this.extractData).catch(this.handleError); } + + public getCouchPotatoSettings(): Observable { + return this.httpAuth.get(`${this.url}/UserManagement`).map(this.extractData).catch(this.handleError); + } + + public saveCouchPotatoSettings(settings: ICouchPotatoSettings): Observable { + return this.httpAuth + .post(`${this.url}/UserManagement`, JSON.stringify(settings), { headers: this.headers }) + .map(this.extractData).catch(this.handleError); + } } diff --git a/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.html b/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.html new file mode 100644 index 000000000..6dd87155b --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.html @@ -0,0 +1,100 @@ + + +
+
+ CouchPotato Settings +
+
+
+
+ + +
+
+ + +
+ +
+ + The IP/Hostname is required +
+
+ +
+ + + + The Port is required +
+ + +
+ + + + + The API Key is required +
+
+
+ + + +
+
+
+ +
+ +
+
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ +
+
+
+ +
+ +
+
+ + + + +
+
+ +
+
+ + +
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.ts b/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.ts new file mode 100644 index 000000000..1d680600a --- /dev/null +++ b/src/Ombi/ClientApp/app/settings/couchpotato/couchpotato.component.ts @@ -0,0 +1,90 @@ +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; + +import { CouchPotatoService, NotificationService, SettingsService, TesterService } from "../../services"; + +import { ICouchPotatoProfiles } from "../../interfaces"; + +@Component({ + templateUrl: "./couchpotato.component.html", +}) +export class CouchPotatoComponent implements OnInit { + + public form: FormGroup; + public profiles: ICouchPotatoProfiles; + + public profilesRunning: boolean; + + constructor(private readonly settingsService: SettingsService, + private readonly fb: FormBuilder, + private readonly notificationService: NotificationService, + private readonly couchPotatoService: CouchPotatoService, + private readonly testerService: TesterService) { } + + public ngOnInit() { + this.settingsService.getCouchPotatoSettings().subscribe(x => { + this.form = this.fb.group({ + enabled: [x.enabled], + username: [x.username], + password: [x.password], + apiKey: [x.apiKey, Validators.required], + ip: [x.ip, Validators.required], + port: [x.port, Validators.required], + ssl: [x.ssl], + subDir: [x.subDir], + defaultProfileId: [x.defaultProfileId], + }); + }); + } + + public getProfiles(form: FormGroup) { + this.profilesRunning = true; + this.couchPotatoService.getProfiles(form.value).subscribe(x => { + this.profiles = x; + this.profilesRunning = false; + }); + } + + public onSubmit(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return; + } + + const settings = form.value; + + this.settingsService.saveCouchPotatoSettings(settings).subscribe(x => { + if (x) { + this.notificationService.success("Settings Saved", "Successfully saved the CouchPotato settings"); + } else { + this.notificationService.success("Settings Saved", "There was an error when saving the CouchPotato settings"); + } + }); + } + + public test(form: FormGroup) { + if (form.invalid) { + this.notificationService.error("Validation", "Please check your entered values"); + return; + } + const settings = form.value; + this.testerService.radarrTest(settings).subscribe(x => { + if (x === true) { + this.notificationService.success("Connected", "Successfully connected to Radarr!"); + } else { + this.notificationService.error("Connected", "We could not connect to Radarr!"); + } + }); + } + + public requestToken(form: FormGroup) { + this.couchPotatoService.getApiKey(form.value).subscribe(x => { + if (x.success === true) { + (this.form.controls.apiKey).setValue(x.apiKey); + this.notificationService.success("Api Key", "Successfully got the Api Key"); + } else { + this.notificationService.error("Api Key", "Could not get the Api Key"); + } + }); + } +} diff --git a/src/Ombi/ClientApp/app/settings/notifications/discord.component.html b/src/Ombi/ClientApp/app/settings/notifications/discord.component.html index b9822608e..991cfe45f 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/discord.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/discord.component.html @@ -13,15 +13,11 @@ -
-
The Webhook Url is required
-
-
- -
+ + The Webhook Url is required
diff --git a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html index 6c7a1259a..271166af8 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/emailnotification.component.html @@ -18,35 +18,27 @@
-
-
Host is required
-
The Port is required
-
The Email Sender Address is required
-
The Email Sender Address needs to be a valid email address
-
The Email Sender is required
-
The Admin Email needs to be a valid email address
-
The Username is required
-
The Password is required
-
-
-
- -
+ + + The Host is required
- + + The Port is required
- + + The Email Sender Address is required + The Email Sender Address needs to be a valid email address
@@ -58,24 +50,26 @@
-
- -
+ + The Admin Email Address is required + The Admin Email needs to be a valid email address +
-
- -
+ + + The Username is required +
-
- -
+ + + The Password is required
diff --git a/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.html b/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.html index a8400535b..0ff2a869a 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/mattermost.component.html @@ -13,16 +13,12 @@
-
-
The Incoming Webhook Url is required
-
-
Mattermost > Integrations > Incoming Webhook > Add Incoming Webhook. You will then have a Webhook -
- -
+ + + The Webhook Url is required
diff --git a/src/Ombi/ClientApp/app/settings/notifications/pushbullet.component.html b/src/Ombi/ClientApp/app/settings/notifications/pushbullet.component.html index 3b2dc30b8..5c40afbe5 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/pushbullet.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/pushbullet.component.html @@ -13,15 +13,12 @@
-
-
The Access Token is required
-
You can find this here: https://www.pushbullet.com/#settings/account
-
- -
+ + + The Access Token is required
diff --git a/src/Ombi/ClientApp/app/settings/notifications/pushover.component.html b/src/Ombi/ClientApp/app/settings/notifications/pushover.component.html index e07316583..0a03604e5 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/pushover.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/pushover.component.html @@ -13,14 +13,12 @@
-
-
The Access Token is required
-
+
-
- -
+ + + The Access Token is required
diff --git a/src/Ombi/ClientApp/app/settings/notifications/slack.component.html b/src/Ombi/ClientApp/app/settings/notifications/slack.component.html index be4504722..450838d2b 100644 --- a/src/Ombi/ClientApp/app/settings/notifications/slack.component.html +++ b/src/Ombi/ClientApp/app/settings/notifications/slack.component.html @@ -14,17 +14,15 @@
-
-
The Webhook Url is required
-
- +
Click Here and follow the guide. You will then have a Webhook Url - + + The Webhook Url is required
diff --git a/src/Ombi/ClientApp/app/settings/radarr/radarr.component.html b/src/Ombi/ClientApp/app/settings/radarr/radarr.component.html index 4ae9eade1..714355447 100644 --- a/src/Ombi/ClientApp/app/settings/radarr/radarr.component.html +++ b/src/Ombi/ClientApp/app/settings/radarr/radarr.component.html @@ -8,19 +8,6 @@
-
-
-
The IP/Hostname is required
-
The Port is required
-
The Api Key is required
-
-
-
A Default Quality Profile is required
-
A Default Root Path is required
-
A Default Minimum Availability is required
-
-
-
@@ -33,25 +20,24 @@
-
- -
+ + + The IP/Hostname is required
-
- -
+ + The Port is required
-
- -
+ + + The API Key is required
@@ -76,10 +62,11 @@
-
+ A Default Quality Profile is required
@@ -92,19 +79,22 @@
- -
+
+ A Default Root Path is required
-
+ + A Default Minimum Availability is required
diff --git a/src/Ombi/ClientApp/app/settings/settings.module.ts b/src/Ombi/ClientApp/app/settings/settings.module.ts index b3ef0a31a..938a2a7e0 100644 --- a/src/Ombi/ClientApp/app/settings/settings.module.ts +++ b/src/Ombi/ClientApp/app/settings/settings.module.ts @@ -8,10 +8,11 @@ import { ClipboardModule } from "ngx-clipboard/dist"; import { AuthGuard } from "../auth/auth.guard"; import { AuthModule } from "../auth/auth.module"; import { AuthService } from "../auth/auth.service"; -import { JobService, RadarrService, SonarrService, TesterService, ValidationService } from "../services"; +import { CouchPotatoService, JobService, RadarrService, SonarrService, TesterService, ValidationService } from "../services"; import { PipeModule } from "../pipes/pipe.module"; import { AboutComponent } from "./about/about.component"; +import { CouchPotatoComponent } from "./couchpotato/couchpotato.component"; import { CustomizationComponent } from "./customization/customization.component"; import { EmbyComponent } from "./emby/emby.component"; import { LandingPageComponent } from "./landingpage/landingpage.component"; @@ -51,6 +52,7 @@ const routes: Routes = [ { path: "Settings/Mattermost", component: MattermostComponent, canActivate: [AuthGuard] }, { path: "Settings/UserManagement", component: UserManagementComponent, canActivate: [AuthGuard] }, { path: "Settings/Update", component: UpdateComponent, canActivate: [AuthGuard] }, + { path: "Settings/CouchPotato", component: CouchPotatoComponent, canActivate: [AuthGuard] }, ]; @NgModule({ @@ -91,6 +93,7 @@ const routes: Routes = [ UpdateComponent, AboutComponent, WikiComponent, + CouchPotatoComponent, ], exports: [ RouterModule, @@ -103,6 +106,7 @@ const routes: Routes = [ ValidationService, TesterService, JobService, + CouchPotatoService, ], }) diff --git a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html index 813b8c49d..2237891ba 100644 --- a/src/Ombi/ClientApp/app/settings/settingsmenu.component.html +++ b/src/Ombi/ClientApp/app/settings/settingsmenu.component.html @@ -39,7 +39,7 @@ Movies
-
-
-
The IP/Hostname is required
-
The Port is required
-
The Api Key is required
-
-
-
A Default Quality Profile is required
-
A Default Root Path is required
-
-
+
@@ -29,25 +19,24 @@
-
- -
+ + + The IP/Hostname is required
-
- -
+ + The Port is required
-
- -
+ + + The API Key is required
@@ -72,10 +61,12 @@
-
+ A Default Quality Profile is required +
@@ -88,10 +79,12 @@
-
+ A Default Root Path is required +
diff --git a/src/Ombi/ClientApp/styles/base.scss b/src/Ombi/ClientApp/styles/base.scss index e1491e0b0..3342a75e7 100644 --- a/src/Ombi/ClientApp/styles/base.scss +++ b/src/Ombi/ClientApp/styles/base.scss @@ -816,3 +816,11 @@ a > h4 { a > h4:hover { text-decoration: underline; } + +.form-error { + border: 1px solid #d9534f; +} + +.error-text { + color: #d9534f; +} diff --git a/src/Ombi/Controllers/External/CouchPotatoController.cs b/src/Ombi/Controllers/External/CouchPotatoController.cs new file mode 100644 index 000000000..dd7a07a9d --- /dev/null +++ b/src/Ombi/Controllers/External/CouchPotatoController.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Ombi.Api.CouchPotato; +using Ombi.Api.CouchPotato.Models; +using Ombi.Attributes; +using Ombi.Settings.Settings.Models.External; + +namespace Ombi.Controllers.External +{ + [Admin] + [ApiV1] + [Produces("application/json")] + public class CouchPotatoController + { + public CouchPotatoController(ICouchPotatoApi api) + { + _api = api; + } + + private readonly ICouchPotatoApi _api; + + [HttpPost("profile")] + public async Task GetQualityProfiles([FromBody] CouchPotatoSettings settings) + { + var profiles = await _api.GetProfiles(settings.FullUri, settings.ApiKey); + + return profiles; + } + + [HttpPost("apikey")] + public async Task GetApiKey([FromBody] CouchPotatoSettings settings) + { + var apiKey = await _api.GetApiKey(settings.FullUri, settings.Username, settings.Password); + return apiKey; + } + } +} \ No newline at end of file diff --git a/src/Ombi/Controllers/External/EmbyController.cs b/src/Ombi/Controllers/External/EmbyController.cs index 9dfd6e5b4..df865be61 100644 --- a/src/Ombi/Controllers/External/EmbyController.cs +++ b/src/Ombi/Controllers/External/EmbyController.cs @@ -13,9 +13,6 @@ using Ombi.Models.External; namespace Ombi.Controllers.External { - /// - /// - /// [Admin] [ApiV1] [Produces("application/json")] diff --git a/src/Ombi/Controllers/External/SonarrController.cs b/src/Ombi/Controllers/External/SonarrController.cs index 765649e68..119010f81 100644 --- a/src/Ombi/Controllers/External/SonarrController.cs +++ b/src/Ombi/Controllers/External/SonarrController.cs @@ -7,6 +7,7 @@ using Ombi.Api.Sonarr.Models; using Ombi.Attributes; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; +using Ombi.Settings.Settings.Models.External; namespace Ombi.Controllers.External { diff --git a/src/Ombi/Controllers/SettingsController.cs b/src/Ombi/Controllers/SettingsController.cs index 7f3c4d2d5..ca3809866 100644 --- a/src/Ombi/Controllers/SettingsController.cs +++ b/src/Ombi/Controllers/SettingsController.cs @@ -343,6 +343,26 @@ namespace Ombi.Controllers return await Get(); } + /// + /// Gets the CouchPotatoSettings Settings. + /// + /// + [HttpGet("CouchPotato")] + public async Task CouchPotatoSettings() + { + return await Get(); + } + + /// + /// Save the CouchPotatoSettings settings. + /// + /// The settings. + /// + [HttpPost("CouchPotato")] + public async Task CouchPotatoSettings([FromBody]CouchPotatoSettings settings) + { + return await Save(settings); + } /// /// Saves the email notification settings.