diff --git a/src/Ombi.Core/Models/TesterResultModel.cs b/src/Ombi.Core/Models/TesterResultModel.cs index f23e14d430..563fa5cb20 100644 --- a/src/Ombi.Core/Models/TesterResultModel.cs +++ b/src/Ombi.Core/Models/TesterResultModel.cs @@ -3,6 +3,7 @@ public class TesterResultModel { public bool IsValid { get; set; } + public string Version { get; set; } public string ExpectedSubDir { get; set; } } } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 388686548f..eb31a5c8f0 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -312,7 +312,7 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet { break; } - if (quality.Equals(existing.Quality)) + if (quality == null || quality.Equals(existing.Quality)) { // We got it continue; diff --git a/src/Ombi/ClientApp/src/app/interfaces/ISonarr.ts b/src/Ombi/ClientApp/src/app/interfaces/ISonarr.ts index ffe9e9b6d2..bd43e671b8 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ISonarr.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ISonarr.ts @@ -12,3 +12,8 @@ export interface ILanguageProfiles { name: string; id: number; } + +export interface ITag { + label: string; + id: number; +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/interfaces/ITester.ts b/src/Ombi/ClientApp/src/app/interfaces/ITester.ts index c61292be4c..b5615aae74 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ITester.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ITester.ts @@ -1,4 +1,5 @@ export interface ITesterResult { isValid: boolean; + version?: string; expectedSubDir?: string; } diff --git a/src/Ombi/ClientApp/src/app/services/applications/sonarr.service.ts b/src/Ombi/ClientApp/src/app/services/applications/sonarr.service.ts index 13a2076d47..ae41badf0e 100644 --- a/src/Ombi/ClientApp/src/app/services/applications/sonarr.service.ts +++ b/src/Ombi/ClientApp/src/app/services/applications/sonarr.service.ts @@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core"; import { HttpClient } from "@angular/common/http"; import { Observable } from "rxjs"; -import { ISonarrSettings } from "../../interfaces"; +import { ISonarrSettings, ITag } from "../../interfaces"; import { ILanguageProfiles, ISonarrProfile, ISonarrRootFolder } from "../../interfaces"; import { ServiceHelpers } from "../service.helpers"; @@ -36,6 +36,10 @@ export class SonarrService extends ServiceHelpers { return this.http.get(`${this.url}/v3/languageprofiles/`, {headers: this.headers}); } + public getTags(settings: ISonarrSettings): Observable { + return this.http.post(`${this.url}/tags/`, JSON.stringify(settings), {headers: this.headers}); + } + public isEnabled(): Promise { return this.http.get(`${this.url}/enabled/`, { headers: this.headers }).toPromise(); } diff --git a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.html b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.html index a3602b3936..cc4ce8d72f 100644 --- a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.html +++ b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.html @@ -57,14 +57,17 @@
- +
-
-
- -
-
+
+
+ +
+
+
+
+
Quality Profiles @@ -76,7 +79,7 @@
-
+
Quality Profiles (Anime) @@ -88,14 +91,18 @@
+
-
-
-
+
+
+
Default Root Folders @@ -107,7 +114,7 @@
-
+
Default Root Folders (Anime) @@ -118,21 +125,58 @@
+
+
+
+
+
+
+
+
+
+
+ + Default Tag + + {{tag.label}} + + +
+
+
+
+ + Anime Tags + + {{tag.label}} + + +
+
+
+ +
+ + + +
+
+
+
+
+
+
+
-
- -
-
-
-
- Language Profiles + Language Profiles {{lang.name}} @@ -141,19 +185,20 @@
-
+
- Language Profiles Anime + Anime {{lang.name}} A Language Profile Anime is required
-
+
+
@@ -170,18 +215,19 @@
+
- +
-
- +
+
diff --git a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts index f6c9d9e389..fcd5bc47e4 100644 --- a/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts @@ -1,7 +1,8 @@ import { Component, OnInit } from "@angular/core"; import { UntypedFormBuilder, FormControl, UntypedFormGroup, Validators } from "@angular/forms"; +import { finalize, map } from "rxjs"; -import { ILanguageProfiles, ISonarrProfile, ISonarrRootFolder } from "../../interfaces"; +import { ILanguageProfiles, ISonarrProfile, ISonarrRootFolder, ITag } from "../../interfaces"; import { ISonarrSettings } from "../../interfaces"; import { SonarrService } from "../../services"; @@ -21,14 +22,20 @@ export class SonarrComponent implements OnInit { public rootFoldersAnime: ISonarrRootFolder[]; public languageProfiles: ILanguageProfiles[]; public languageProfilesAnime: ILanguageProfiles[]; + + public tags: ITag[]; + public animeTags: ITag[]; + public selectedRootFolder: ISonarrRootFolder; public selectedQuality: ISonarrProfile; public selectedLanguageProfiles: ILanguageProfiles; public profilesRunning: boolean; public rootFoldersRunning: boolean; + public tagsRunning: boolean; public langRunning: boolean; public form: UntypedFormGroup; public advanced = false; + public sonarrVersion: string; formErrors: any; constructor(private settingsService: SettingsService, @@ -72,12 +79,29 @@ export class SonarrComponent implements OnInit { port: [x.port, [Validators.required]], addOnly: [x.addOnly], seasonFolders: [x.seasonFolders], - languageProfile: [x.languageProfile, [Validators.required, validateProfile]], + languageProfile: [x.languageProfile], languageProfileAnime: [x.languageProfileAnime], scanForAvailability: [x.scanForAvailability], - sendUserTags: [x.sendUserTags] + sendUserTags: [x.sendUserTags], + tag: [x.tag], + animeTag: [x.animeTag] }); + this.rootFolders = []; + this.qualities = []; + this.languageProfiles = []; + this.tags = []; + this.animeTags = []; + + if (x.enabled && this.form.valid) { + this.testerService.sonarrTest(x).subscribe(result => { + this.sonarrVersion = result.version[0]; + if (this.sonarrVersion === '3') { + this.form.controls.languageProfile.addValidators([Validators.required, validateProfile]); + } + }); + } + if (x.qualityProfile) { this.getProfiles(this.form); } @@ -87,6 +111,9 @@ export class SonarrComponent implements OnInit { if (x.languageProfile) { this.getLanguageProfiles(this.form); } + if (x.tag || x.animeTag) { + this.getTags(this.form); + } this.formErrors ={ apiKey: {}, @@ -97,12 +124,12 @@ export class SonarrComponent implements OnInit { }; this.onFormValuesChanged(); }); - this.rootFolders = []; - this.qualities = []; - this.languageProfiles = []; + this.rootFolders.push({ path: "Please Select", id: -1 }); this.qualities.push({ name: "Please Select", id: -1 }); this.languageProfiles.push({ name: "Please Select", id: -1 }); + this.animeTags.push({label: "None", id: -1}); + this.tags.push({label: "None", id: -1}); } public getProfiles(form: UntypedFormGroup) { @@ -142,14 +169,27 @@ export class SonarrComponent implements OnInit { }); } + public getTags(form: UntypedFormGroup) { + this.tagsRunning = true; + this.sonarrService.getTags(form.value).pipe( + finalize(() => { + this.tagsRunning = false; + this.animeTags.unshift({ label: "None", id: -1 }); + this.tags.unshift({ label: "None", id: -1 }); + this.notificationService.success("Successfully retrieved the Tags"); + }), + map(result => { + this.tags = result; + this.tags.forEach(val => this.animeTags.push(Object.assign({}, val))); + }) + ).subscribe() + } + public test(form: UntypedFormGroup) { - if (form.invalid) { - this.notificationService.error("Please check your entered values"); - return; - } const settings = form.value; this.testerService.sonarrTest(settings).subscribe(result => { if (result.isValid) { + this.sonarrVersion = result.version[0]; this.notificationService.success("Successfully connected to Sonarr!"); } else if (result.expectedSubDir) { this.notificationService.error("Your Sonarr Base URL must be set to " + result.expectedSubDir); @@ -179,6 +219,12 @@ export class SonarrComponent implements OnInit { this.notificationService.error("Please check your entered values"); } } + if (form.controls.animeTag.value == -1) { + form.controls.animeTag.setValue(null); + } + if (form.controls.tag.value == -1) { + form.controls.tag.setValue(null); + } this.settingsService.saveSonarr(form.value) .subscribe(x => { @@ -190,6 +236,7 @@ export class SonarrComponent implements OnInit { }); } } + function validateProfile(qualityProfile): { [key: string]:boolean } | null { if (qualityProfile.value !== undefined && (isNaN(qualityProfile.value) || qualityProfile.value == -1)) { diff --git a/src/Ombi/Controllers/V1/External/TesterController.cs b/src/Ombi/Controllers/V1/External/TesterController.cs index bedf207b1f..79a0083221 100644 --- a/src/Ombi/Controllers/V1/External/TesterController.cs +++ b/src/Ombi/Controllers/V1/External/TesterController.cs @@ -46,7 +46,7 @@ public class TesterController : Controller /// public TesterController(INotificationService service, IDiscordNotification notification, IEmailNotification emailN, IPushbulletNotification pushbullet, ISlackNotification slack, IPushoverNotification po, IMattermostNotification mm, - IPlexApi plex, IEmbyApiFactory emby, IRadarrV3Api radarr, ISonarrApi sonarr, ILogger log, IEmailProvider provider, + IPlexApi plex, IEmbyApiFactory emby, IRadarrV3Api radarr, ISonarrV3Api sonarr, ILogger log, IEmailProvider provider, ICouchPotatoApi cpApi, ITelegramNotification telegram, ISickRageApi srApi, INewsletterJob newsletter, ILegacyMobileNotification mobileNotification, ILidarrApi lidarrApi, IGotifyNotification gotifyNotification, IWhatsAppApi whatsAppApi, OmbiUserManager um, IWebhookNotification webhookNotification, IJellyfinApi jellyfinApi, IPrincipal user) @@ -90,7 +90,7 @@ public TesterController(INotificationService service, IDiscordNotification notif private IPlexApi PlexApi { get; } private IRadarrV3Api RadarrApi { get; } private IEmbyApiFactory EmbyApi { get; } - private ISonarrApi SonarrApi { get; } + private ISonarrV3Api SonarrApi { get; } private ICouchPotatoApi CouchPotatoApi { get; } private ILogger Log { get; } private IEmailProvider EmailProvider { get; } @@ -415,6 +415,7 @@ public async Task Sonarr([FromBody] SonarrSettings settings) return new TesterResultModel { IsValid = result.urlBase == settings.SubDir || string.IsNullOrEmpty(result.urlBase) && string.IsNullOrEmpty(settings.SubDir), + Version = result.version, ExpectedSubDir = result.urlBase }; }