Skip to content

Commit

Permalink
fix(sonarr): 🐛 Sonarr V4 should work now (#4810)
Browse files Browse the repository at this point in the history
* fix(sonarr): 🐛 Sonarr V4 should work now

Auto detect the sonarr version and adjust the UI depending on V3 or V4 (Lang profiles)

* fix: Fixed the load error
  • Loading branch information
tidusjar committed Nov 23, 2022
1 parent 5ad6ea3 commit 37655af
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 59 deletions.
8 changes: 6 additions & 2 deletions src/Ombi/ClientApp/src/app/app.module.ts
@@ -1,5 +1,5 @@
import { APP_BASE_HREF, CommonModule, PlatformLocation } from "@angular/common";
import { CustomPageService, ImageService, RequestService, SettingsService } from "./services";
import { CustomPageService, ImageService, RequestService, SettingsService, SonarrService } from "./services";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from "@angular/common/http";
import { IdentityService, IssuesService, JobService, MessageService, PlexTvService, SearchService, StatusService } from "./services";
Expand All @@ -13,6 +13,7 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { BrowserModule } from "@angular/platform-browser";
import { ButtonModule } from "primeng/button";
import { CUSTOMIZATION_INITIALIZER } from "./state/customization/customization-initializer";
import { SONARR_INITIALIZER } from "./state/sonarr/sonarr-initializer";
import { ConfirmDialogModule } from "primeng/confirmdialog";
import { CookieComponent } from "./auth/cookie.component";
import { CookieService } from "ng2-cookies";
Expand All @@ -22,6 +23,7 @@ import { DataViewModule } from "primeng/dataview";
import { DialogModule } from "primeng/dialog";
import { FEATURES_INITIALIZER } from "./state/features/features-initializer";
import { FeatureState } from "./state/features";
import { SonarrSettingsState } from "./state/sonarr";
import { JwtModule } from "@auth0/angular-jwt";
import { LandingPageComponent } from "./landingpage/landingpage.component";
import { LandingPageService } from "./services";
Expand Down Expand Up @@ -161,7 +163,7 @@ export function JwtTokenGetter() {
}),
SidebarModule,
MatNativeDateModule, MatIconModule, MatSidenavModule, MatListModule, MatToolbarModule, LayoutModule, MatSlideToggleModule,
NgxsModule.forRoot([CustomizationState, FeatureState], {
NgxsModule.forRoot([CustomizationState, FeatureState, SonarrSettingsState], {
developmentMode: !environment.production,
}),
...environment.production ? [] :
Expand Down Expand Up @@ -205,8 +207,10 @@ export function JwtTokenGetter() {
MessageService,
StorageService,
RequestService,
SonarrService,
SignalRNotificationService,
FEATURES_INITIALIZER,
SONARR_INITIALIZER,
CUSTOMIZATION_INITIALIZER,
{
provide: APP_BASE_HREF,
Expand Down
5 changes: 5 additions & 0 deletions src/Ombi/ClientApp/src/app/login/login.component.ts
Expand Up @@ -13,6 +13,7 @@ import { StatusService } from "../services";
import { StorageService } from "../shared/storage/storage-service";
import { MatSnackBar } from "@angular/material/snack-bar";
import { CustomizationFacade } from "../state/customization";
import { SonarrFacade } from "app/state/sonarr";

@Component({
templateUrl: "./login.component.html",
Expand Down Expand Up @@ -60,6 +61,7 @@ export class LoginComponent implements OnDestroy, OnInit {
private translate: TranslateService,
private plexTv: PlexTvService,
private store: StorageService,
private sonarrFacade: SonarrFacade,
private readonly notify: MatSnackBar
) {
this.href = href;
Expand Down Expand Up @@ -142,6 +144,7 @@ export class LoginComponent implements OnDestroy, OnInit {

if (this.authService.loggedIn()) {
this.ngOnDestroy();
this.sonarrFacade.load().subscribe();
this.router.navigate(["/"]);
} else {
this.notify.open(this.errorBody, "OK", {
Expand Down Expand Up @@ -218,6 +221,7 @@ export class LoginComponent implements OnDestroy, OnInit {
this.oAuthWindow.close();
}
this.oauthLoading = false;
this.sonarrFacade.load().subscribe();
this.router.navigate(["search"]);
return;
}
Expand Down Expand Up @@ -248,6 +252,7 @@ export class LoginComponent implements OnDestroy, OnInit {

if (this.authService.loggedIn()) {
this.ngOnDestroy();
this.sonarrFacade.load().subscribe();
this.router.navigate(["/"]);
} else {
this.notify.open(this.errorBody, "OK", {
Expand Down
@@ -1,5 +1,5 @@
import { Component, ViewEncapsulation, OnInit } from "@angular/core";
import { ImageService, SearchV2Service, MessageService, RequestService, SonarrService, SettingsStateService } from "../../../services";
import { SearchV2Service, MessageService, RequestService, SonarrService, SettingsStateService } from "../../../services";
import { ActivatedRoute } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser";
import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2";
Expand All @@ -11,9 +11,8 @@ import { AuthService } from "../../../auth/auth.service";
import { NewIssueComponent } from "../shared/new-issue/new-issue.component";
import { TvAdvancedOptionsComponent } from "./panels/tv-advanced-options/tv-advanced-options.component";
import { RequestServiceV2 } from "../../../services/requestV2.service";
import { RequestBehalfComponent } from "../shared/request-behalf/request-behalf.component";
import { forkJoin } from "rxjs";
import { TopBannerComponent } from "../shared/top-banner/top-banner.component";
import { SonarrFacade } from "app/state/sonarr";

@Component({
templateUrl: "./tv-details.component.html",
Expand All @@ -36,10 +35,15 @@ export class TvDetailsComponent implements OnInit {
private tvdbId: number;

constructor(private searchService: SearchV2Service, private route: ActivatedRoute,
private sanitizer: DomSanitizer, private imageService: ImageService,
public dialog: MatDialog, public messageService: MessageService, private requestService: RequestService,
private sanitizer: DomSanitizer,
public dialog: MatDialog,
public messageService: MessageService,
private requestService: RequestService,
private requestService2: RequestServiceV2,
private auth: AuthService, private sonarrService: SonarrService, private settingsState: SettingsStateService) {
private auth: AuthService,
private sonarrService: SonarrService,
private sonarrFacade: SonarrFacade,
private settingsState: SettingsStateService) {
this.route.params.subscribe((params: any) => {
this.tvdbId = params.tvdbId;
this.fromSearch = params.search;
Expand All @@ -58,7 +62,7 @@ export class TvDetailsComponent implements OnInit {
this.manageOwnRequests = this.auth.hasRole('ManageOwnRequests');

if (this.isAdmin) {
this.showAdvanced = await this.sonarrService.isEnabled();
this.showAdvanced = this.sonarrFacade.isEnabled();
}

// if (this.fromSearch) {
Expand Down Expand Up @@ -138,6 +142,7 @@ export class TvDetailsComponent implements OnInit {
this.tv.images.original = 'https://image.tmdb.org/t/p/w300/' + this.tv.images.original
};
}

private loadAdvancedInfo() {
const profile = this.sonarrService.getQualityProfilesWithoutSettings();
const folders = this.sonarrService.getRootFoldersWithoutSettings();
Expand Down
Expand Up @@ -40,7 +40,11 @@ export class SonarrService extends ServiceHelpers {
return this.http.post<ITag[]>(`${this.url}/tags/`, JSON.stringify(settings), {headers: this.headers});
}

public isEnabled(): Promise<boolean> {
return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers }).toPromise();
public isEnabled(): Observable<boolean> {
return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers });
}

public getVersion(): Observable<string> {
return this.http.get<string>(`${this.url}/version/`, { headers: this.headers });
}
}
Expand Up @@ -157,7 +157,7 @@
</div>
</div></div>

<div class="form-group col-md-12" *ngIf="sonarrVersion === '3'">
<div class="form-group col-md-12" *ngIf="sonarrVersion == '3'">
<label for="select" class="control-label">Language Profiles
<i *ngIf="form.get('languageProfile').hasError('required')" class="fas fa-exclamation-circle error-text" pTooltip="A Language Profile is required"></i>
</label>
Expand Down
71 changes: 34 additions & 37 deletions src/Ombi/ClientApp/src/app/settings/sonarr/sonarr.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from "@angular/core";
import { UntypedFormBuilder, FormControl, UntypedFormGroup, Validators } from "@angular/forms";
import { SonarrFacade } from "app/state/sonarr/sonarr.facade";
import { finalize, map } from "rxjs";

import { ILanguageProfiles, ISonarrProfile, ISonarrRootFolder, ITag } from "../../interfaces";
Expand All @@ -8,7 +9,6 @@ import { ISonarrSettings } from "../../interfaces";
import { SonarrService } from "../../services";
import { TesterService } from "../../services";
import { NotificationService } from "../../services";
import { SettingsService } from "../../services";

@Component({
templateUrl: "./sonarr.component.html",
Expand All @@ -22,7 +22,7 @@ export class SonarrComponent implements OnInit {
public rootFoldersAnime: ISonarrRootFolder[];
public languageProfiles: ILanguageProfiles[];
public languageProfilesAnime: ILanguageProfiles[];

public tags: ITag[];
public animeTags: ITag[];

Expand All @@ -38,11 +38,13 @@ export class SonarrComponent implements OnInit {
public sonarrVersion: string;
formErrors: any;

constructor(private settingsService: SettingsService,
private sonarrService: SonarrService,
public sonarrState$ = this.sonarrFacade.sonarrState$();

constructor(private sonarrService: SonarrService,
private notificationService: NotificationService,
private testerService: TesterService,
private fb: UntypedFormBuilder){}
private fb: UntypedFormBuilder,
private sonarrFacade: SonarrFacade){}

onFormValuesChanged()
{
Expand All @@ -64,27 +66,27 @@ export class SonarrComponent implements OnInit {
}

public ngOnInit() {
this.settingsService.getSonarr()
.subscribe(x => {
this.sonarrFacade.sonarrState$()
.subscribe(({settings, version}) => {
this.form = this.fb.group({
enabled: [x.enabled],
apiKey: [x.apiKey, [Validators.required]],
qualityProfile: [x.qualityProfile, [Validators.required, validateProfile]],
rootPath: [x.rootPath, [Validators.required, validateProfile]],
qualityProfileAnime: [x.qualityProfileAnime],
rootPathAnime: [x.rootPathAnime],
ssl: [x.ssl],
subDir: [x.subDir],
ip: [x.ip, [Validators.required]],
port: [x.port, [Validators.required]],
addOnly: [x.addOnly],
seasonFolders: [x.seasonFolders],
languageProfile: [x.languageProfile],
languageProfileAnime: [x.languageProfileAnime],
scanForAvailability: [x.scanForAvailability],
sendUserTags: [x.sendUserTags],
tag: [x.tag],
animeTag: [x.animeTag]
enabled: [settings.enabled],
apiKey: [settings.apiKey, [Validators.required]],
qualityProfile: [settings.qualityProfile, [Validators.required, validateProfile]],
rootPath: [settings.rootPath, [Validators.required, validateProfile]],
qualityProfileAnime: [settings.qualityProfileAnime],
rootPathAnime: [settings.rootPathAnime],
ssl: [settings.ssl],
subDir: [settings.subDir],
ip: [settings.ip, [Validators.required]],
port: [settings.port, [Validators.required]],
addOnly: [settings.addOnly],
seasonFolders: [settings.seasonFolders],
languageProfile: [settings.languageProfile],
languageProfileAnime: [settings.languageProfileAnime],
scanForAvailability: [settings.scanForAvailability],
sendUserTags: [settings.sendUserTags],
tag: [settings.tag],
animeTag: [settings.animeTag]
});

this.rootFolders = [];
Expand All @@ -93,25 +95,20 @@ export class SonarrComponent implements OnInit {
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 (version.length > 0) {
this.sonarrVersion = version[0];
}

if (x.qualityProfile) {
if (settings.qualityProfile) {
this.getProfiles(this.form);
}
if (x.rootPath) {
if (settings.rootPath) {
this.getRootFolders(this.form);
}
if (x.languageProfile) {
if (settings.languageProfile) {
this.getLanguageProfiles(this.form);
}
if (x.tag || x.animeTag) {
if (settings.tag || settings.animeTag) {
this.getTags(this.form);
}

Expand Down Expand Up @@ -226,7 +223,7 @@ export class SonarrComponent implements OnInit {
form.controls.tag.setValue(null);
}

this.settingsService.saveSonarr(form.value)
this.sonarrFacade.updateSettings(form.value)
.subscribe(x => {
if (x) {
this.notificationService.success("Successfully saved Sonarr settings");
Expand Down
Expand Up @@ -53,7 +53,7 @@ <h3>Sonarr Overrides</h3>
</mat-form-field>
</div>
<div>
<mat-form-field appearance="outline" floatLabel=auto>
<mat-form-field *ngIf="sonarrLanguageProfiles" appearance="outline" floatLabel=auto>
<mat-label>{{'MediaDetails.LanguageProfileSelect' | translate }}</mat-label>
<mat-select id="sonarrLanguageId" formControlName="sonarrLanguageId">
<mat-option id="sonarrLanguageId{{profile.id}}" *ngFor="let profile of sonarrLanguageProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
Expand Down
@@ -1,11 +1,11 @@
import { Component, Inject, OnInit } from "@angular/core";
import { UntypedFormBuilder, UntypedFormGroup } from "@angular/forms";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { SonarrFacade } from "app/state/sonarr";
import { firstValueFrom, Observable } from "rxjs";
import { startWith, map } from "rxjs/operators";
import { ILanguageProfiles, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, ISonarrSettings, IUserDropdown, RequestType } from "../../interfaces";
import { IdentityService, MessageService, RadarrService, RequestService, SettingsService, SonarrService } from "../../services";
import { RequestServiceV2 } from "../../services/requestV2.service";
import { ILanguageProfiles, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, IUserDropdown, RequestType } from "../../interfaces";
import { IdentityService, RadarrService, SonarrService } from "../../services";

export interface IAdminRequestDialogData {
type: RequestType,
Expand All @@ -23,9 +23,9 @@ export class AdminRequestDialogComponent implements OnInit {
@Inject(MAT_DIALOG_DATA) public data: IAdminRequestDialogData,
private identityService: IdentityService,
private sonarrService: SonarrService,
private settingsService: SettingsService,
private radarrService: RadarrService,
private fb: UntypedFormBuilder
private fb: UntypedFormBuilder,
private sonarrFacade: SonarrFacade
) {}

public form: UntypedFormGroup;
Expand Down Expand Up @@ -63,11 +63,14 @@ export class AdminRequestDialogComponent implements OnInit {
);

if (this.data.type === RequestType.tvShow) {
this.sonarrEnabled = await this.sonarrService.isEnabled();
this.sonarrEnabled = this.sonarrFacade.isEnabled();
if (this.sonarrEnabled) {
this.sonarrService.getV3LanguageProfilesWithoutSettings().subscribe((profiles: ILanguageProfiles[]) => {
this.sonarrLanguageProfiles = profiles;
})
console.log(this.sonarrFacade.version());
if (this.sonarrFacade.version()[0] === "3") {
this.sonarrService.getV3LanguageProfilesWithoutSettings().subscribe((profiles: ILanguageProfiles[]) => {
this.sonarrLanguageProfiles = profiles;
})
}
this.sonarrService.getQualityProfilesWithoutSettings().subscribe(c => {
this.sonarrProfiles = c;
});
Expand Down
4 changes: 4 additions & 0 deletions src/Ombi/ClientApp/src/app/state/sonarr/index.ts
@@ -0,0 +1,4 @@
export * from './sonarr.state';
export * from './sonarr.actions';
export * from './sonarr.facade';
export * from './sonarr.selectors';
12 changes: 12 additions & 0 deletions src/Ombi/ClientApp/src/app/state/sonarr/sonarr-initializer.ts
@@ -0,0 +1,12 @@
import { APP_INITIALIZER } from "@angular/core";
import { Observable } from "rxjs";
import { SonarrFacade } from "./sonarr.facade";

export const SONARR_INITIALIZER = {
provide: APP_INITIALIZER,
useFactory: (sonarrFacade: SonarrFacade) => (): Observable<unknown> => {
return sonarrFacade.load();
},
multi: true,
deps: [SonarrFacade],
};
10 changes: 10 additions & 0 deletions src/Ombi/ClientApp/src/app/state/sonarr/sonarr.actions.ts
@@ -0,0 +1,10 @@
import { ISonarrSettings } from "../../interfaces";

export class LoadSettings {
public static readonly type = '[Sonarr] LoadSettings';
}

export class UpdateSettings {
public static readonly type = '[Sonarr] UpdateSettings';
constructor(public settings: ISonarrSettings) { }
}

0 comments on commit 37655af

Please sign in to comment.