We can now override language profiles for Sonarr v3 requests, we also added an option to specify the language profile for Anime requests

This commit is contained in:
tidusjar 2021-04-08 10:11:32 +01:00
parent 5bd85a3aac
commit 89e1e21c7c
31 changed files with 2741 additions and 68 deletions

View file

@ -164,7 +164,7 @@ namespace Ombi.Core.Engine
}; };
} }
if ((tv.RootFolderOverride.HasValue || tv.QualityPathOverride.HasValue) && !isAdmin) if ((tv.RootFolderOverride.HasValue || tv.QualityPathOverride.HasValue || tv.LanguageProfile.HasValue) && !isAdmin)
{ {
return new RequestEngineResult return new RequestEngineResult
{ {
@ -250,7 +250,7 @@ namespace Ombi.Core.Engine
} }
// This is a new request // This is a new request
var newRequest = tvBuilder.CreateNewRequest(tv, tv.RootFolderOverride.GetValueOrDefault(), tv.QualityPathOverride.GetValueOrDefault()); var newRequest = tvBuilder.CreateNewRequest(tv, tv.RootFolderOverride.GetValueOrDefault(), tv.QualityPathOverride.GetValueOrDefault(), tv.LanguageProfile.GetValueOrDefault());
return await AddRequest(newRequest.NewRequest, tv.RequestOnBehalf); return await AddRequest(newRequest.NewRequest, tv.RequestOnBehalf);
} }
@ -997,6 +997,10 @@ namespace Ombi.Core.Engine
request.QualityOverride = options.QualityOverride; request.QualityOverride = options.QualityOverride;
request.RootFolder = options.RootPathOverride; request.RootFolder = options.RootPathOverride;
if (options.LanguageProfile > 0)
{
request.LanguageProfile = options.LanguageProfile;
}
await TvRepository.Update(request); await TvRepository.Update(request);

View file

@ -217,7 +217,7 @@ namespace Ombi.Core.Helpers
} }
public TvShowRequestBuilderV2 CreateNewRequest(TvRequestViewModelV2 tv, int rootPathOverride, int qualityOverride) public TvShowRequestBuilderV2 CreateNewRequest(TvRequestViewModelV2 tv, int rootPathOverride, int qualityOverride, int langProfile)
{ {
int.TryParse(TheMovieDbRecord.ExternalIds?.TvDbId, out var tvdbId); int.TryParse(TheMovieDbRecord.ExternalIds?.TvDbId, out var tvdbId);
NewRequest = new TvRequests NewRequest = new TvRequests
@ -234,7 +234,8 @@ namespace Ombi.Core.Helpers
TotalSeasons = tv.Seasons.Count(), TotalSeasons = tv.Seasons.Count(),
Background = BackdropPath, Background = BackdropPath,
RootFolder = rootPathOverride, RootFolder = rootPathOverride,
QualityOverride = qualityOverride QualityOverride = qualityOverride,
LanguageProfile = langProfile
}; };
NewRequest.ChildRequests.Add(ChildRequest); NewRequest.ChildRequests.Add(ChildRequest);

View file

@ -5,5 +5,6 @@
public int RequestId { get; set; } public int RequestId { get; set; }
public int RootPathOverride { get; set; } public int RootPathOverride { get; set; }
public int QualityOverride { get; set; } public int QualityOverride { get; set; }
public int LanguageProfile { get; set; }
} }
} }

View file

@ -24,6 +24,7 @@ namespace Ombi.Core.Models.Requests
{ {
public bool RequestAll { get; set; } public bool RequestAll { get; set; }
public bool LatestSeason { get; set; } public bool LatestSeason { get; set; }
public int? LanguageProfile { get; set; }
public bool FirstSeason { get; set; } public bool FirstSeason { get; set; }
public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>(); public List<SeasonsViewModel> Seasons { get; set; } = new List<SeasonsViewModel>();
[JsonIgnore] [JsonIgnore]

View file

@ -158,6 +158,8 @@ namespace Ombi.Core.Senders
} }
int qualityToUse; int qualityToUse;
var sonarrV3 = s.V3;
var languageProfileId = s.LanguageProfile;
string rootFolderPath; string rootFolderPath;
string seriesType; string seriesType;
@ -167,8 +169,17 @@ namespace Ombi.Core.Senders
{ {
// Get the root path from the rootfolder selected. // Get the root path from the rootfolder selected.
// For some reason, if we haven't got one use the first root folder in Sonarr // For some reason, if we haven't got one use the first root folder in Sonarr
rootFolderPath = await GetSonarrRootPath(int.Parse(s.RootPathAnime), s); if (!int.TryParse(s.RootPathAnime, out int animePath))
int.TryParse(s.QualityProfileAnime, out qualityToUse); {
animePath = int.Parse(s.RootPath); // Set it to the main root folder if we have no anime folder.
}
rootFolderPath = await GetSonarrRootPath(animePath, s);
languageProfileId = s.LanguageProfileAnime > 0 ? s.LanguageProfileAnime : s.LanguageProfile;
if (!int.TryParse(s.QualityProfileAnime, out qualityToUse))
{
qualityToUse = int.Parse(s.QualityProfile);
}
if (profiles != null) if (profiles != null)
{ {
if (profiles.SonarrRootPathAnime > 0) if (profiles.SonarrRootPathAnime > 0)
@ -181,7 +192,6 @@ namespace Ombi.Core.Senders
} }
} }
seriesType = "anime"; seriesType = "anime";
} }
else else
{ {
@ -221,9 +231,14 @@ namespace Ombi.Core.Senders
} }
} }
// Are we using v3 sonarr? if (model.ParentRequest.LanguageProfile.HasValue)
var sonarrV3 = s.V3; {
var languageProfileId = s.LanguageProfile; var languageProfile = model.ParentRequest.LanguageProfile.Value;
if (languageProfile > 0)
{
languageProfileId = languageProfile;
}
}
try try
{ {
@ -264,6 +279,10 @@ namespace Ombi.Core.Senders
var seasonsToAdd = GetSeasonsToCreate(model); var seasonsToAdd = GetSeasonsToCreate(model);
newSeries.seasons = seasonsToAdd; newSeries.seasons = seasonsToAdd;
var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri); var result = await SonarrApi.AddSeries(newSeries, s.ApiKey, s.FullUri);
if (result?.ErrorMessages?.Any() ?? false)
{
throw new Exception(string.Join(',', result.ErrorMessages));
}
existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri); existingSeries = await SonarrApi.GetSeriesById(result.id, s.ApiKey, s.FullUri);
await SendToSonarr(model, existingSeries, s); await SendToSonarr(model, existingSeries, s);
} }
@ -407,7 +426,6 @@ namespace Ombi.Core.Senders
await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result); await SonarrApi.SeasonPass(s.ApiKey, s.FullUri, result);
} }
if (!s.AddOnly) if (!s.AddOnly)
{ {
await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate); await SearchForRequest(model, sonarrEpList, result, s, episodesToUpdate);

View file

@ -20,6 +20,7 @@
public bool AddOnly { get; set; } public bool AddOnly { get; set; }
public bool V3 { get; set; } public bool V3 { get; set; }
public int LanguageProfile { get; set; } public int LanguageProfile { get; set; }
public int LanguageProfileAnime { get; set; }
public bool ScanForAvailability { get; set; } public bool ScanForAvailability { get; set; }
} }
} }

View file

@ -16,6 +16,7 @@ namespace Ombi.Store.Entities.Requests
public string ImdbId { get; set; } public string ImdbId { get; set; }
public int? QualityOverride { get; set; } public int? QualityOverride { get; set; }
public int? RootFolder { get; set; } public int? RootFolder { get; set; }
public int? LanguageProfile { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string PosterPath { get; set; } public string PosterPath { get; set; }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Ombi.Store.Migrations.OmbiMySql
{
public partial class SonarrProfileOnRequest : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "LanguageProfile",
table: "TvRequests",
type: "int",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LanguageProfile",
table: "TvRequests");
}
}
}

View file

@ -771,6 +771,9 @@ namespace Ombi.Store.Migrations.OmbiMySql
b.Property<string>("ImdbId") b.Property<string>("ImdbId")
.HasColumnType("longtext"); .HasColumnType("longtext");
b.Property<int?>("LanguageProfile")
.HasColumnType("int");
b.Property<string>("Overview") b.Property<string>("Overview")
.HasColumnType("longtext"); .HasColumnType("longtext");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Ombi.Store.Migrations.OmbiSqlite
{
public partial class SonarrProfileOnRequest : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "LanguageProfile",
table: "TvRequests",
type: "INTEGER",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LanguageProfile",
table: "TvRequests");
}
}
}

View file

@ -770,6 +770,9 @@ namespace Ombi.Store.Migrations.OmbiSqlite
b.Property<string>("ImdbId") b.Property<string>("ImdbId")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<int?>("LanguageProfile")
.HasColumnType("INTEGER");
b.Property<string>("Overview") b.Property<string>("Overview")
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -1,5 +1,6 @@
import { IChildRequests, IMovieRequests } from "."; import { IChildRequests, IMovieRequests } from ".";
import { ITvRequests } from "./IRequestModel"; import { ITvRequests } from "./IRequestModel";
import { ILanguageProfiles } from "./ISonarr";
export interface IRadarrRootFolder { export interface IRadarrRootFolder {
id: number; id: number;
@ -27,6 +28,9 @@ export interface IAdvancedData {
rootFolder: IRadarrRootFolder; rootFolder: IRadarrRootFolder;
rootFolders: IRadarrRootFolder[]; rootFolders: IRadarrRootFolder[];
rootFolderId: number; rootFolderId: number;
language: ILanguageProfiles;
languages: ILanguageProfiles[];
languageId: number;
movieRequest: IMovieRequests; movieRequest: IMovieRequests;
tvRequest: ITvRequests; tvRequest: ITvRequests;
} }

View file

@ -26,6 +26,7 @@ export interface IMovieAdvancedOptions {
requestId: number; requestId: number;
qualityOverride: number; qualityOverride: number;
rootPathOverride: number; rootPathOverride: number;
languageProfile: number;
} }
export interface IAlbumRequest extends IBaseRequest { export interface IAlbumRequest extends IBaseRequest {
@ -110,6 +111,7 @@ export interface ITvRequests {
status: string; status: string;
childRequests: IChildRequests[]; childRequests: IChildRequests[];
qualityOverride: number; qualityOverride: number;
languageProfile: number;
background: any; background: any;
totalSeasons: number; totalSeasons: number;
tvDbId: number; // NO LONGER USED tvDbId: number; // NO LONGER USED
@ -119,6 +121,7 @@ export interface ITvRequests {
// For UI display // For UI display
qualityOverrideTitle: string; qualityOverrideTitle: string;
rootPathOverrideTitle: string; rootPathOverrideTitle: string;
languageOverrideTitle: string;
} }
export interface IChildRequests extends IBaseRequest { export interface IChildRequests extends IBaseRequest {

View file

@ -51,6 +51,7 @@ export interface ITvRequestViewModelBase extends BaseRequestOptions {
requestAll: boolean; requestAll: boolean;
firstSeason: boolean; firstSeason: boolean;
latestSeason: boolean; latestSeason: boolean;
languageProfile: number | undefined;
seasons: ISeasonsViewModel[]; seasons: ISeasonsViewModel[];
} }

View file

@ -103,6 +103,7 @@ export interface ISonarrSettings extends IExternalSettings {
addOnly: boolean; addOnly: boolean;
v3: boolean; v3: boolean;
languageProfile: number; languageProfile: number;
languageProfileAnime: number;
scanForAvailability: boolean; scanForAvailability: boolean;
} }

View file

@ -184,7 +184,7 @@ export class MovieDetailsComponent {
if (result) { if (result) {
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0]; result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0]; result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
await this.requestService2.updateMovieAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, requestId: this.movieRequest.id }).toPromise(); await this.requestService2.updateMovieAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, languageProfile: 0, requestId: this.movieRequest.id }).toPromise();
this.setAdvancedOptions(result); this.setAdvancedOptions(result);
} }
}); });

View file

@ -5,7 +5,7 @@
<i class="fas fa-x7 fa-exclamation-triangle glyphicon"></i> <i class="fas fa-x7 fa-exclamation-triangle glyphicon"></i>
<span>{{'MediaDetails.AutoApproveOptionsTvShort' | translate }}</span> <span>{{'MediaDetails.AutoApproveOptionsTvShort' | translate }}</span>
</div> </div>
<mat-form-field> <mat-form-field *ngIf="sonarrEnabled">
<mat-label>{{'MediaDetails.QualityProfilesSelect' | translate }}</mat-label> <mat-label>{{'MediaDetails.QualityProfilesSelect' | translate }}</mat-label>
<mat-select [(value)]="data.profileId"> <mat-select [(value)]="data.profileId">
<mat-option *ngFor="let profile of sonarrProfiles" value="{{profile.id}}">{{profile.name}}</mat-option> <mat-option *ngFor="let profile of sonarrProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
@ -13,13 +13,21 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div mat-dialog-content> <div mat-dialog-content>
<mat-form-field> <mat-form-field *ngIf="sonarrEnabled">
<mat-label>{{'MediaDetails.RootFolderSelect' | translate }}</mat-label> <mat-label>{{'MediaDetails.RootFolderSelect' | translate }}</mat-label>
<mat-select [(value)]="data.rootFolderId"> <mat-select [(value)]="data.rootFolderId">
<mat-option *ngFor="let profile of sonarrRootFolders" value="{{profile.id}}">{{profile.path}}</mat-option> <mat-option *ngFor="let profile of sonarrRootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<div mat-dialog-content>
<mat-form-field *ngIf="sonarrEnabled">
<mat-label>{{'MediaDetails.LanguageProfileSelect' | translate }}</mat-label>
<mat-select [(value)]="data.languageId">
<mat-option *ngFor="let profile of sonarrLanguageProfiles" value="{{profile.id}}">{{profile.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-raised-button [mat-dialog-close]="" color="warn"><i class="fas fa-times"></i> {{ 'Common.Cancel' | translate }}</button> <button mat-raised-button [mat-dialog-close]="" color="warn"><i class="fas fa-times"></i> {{ 'Common.Cancel' | translate }}</button>
<button mat-raised-button [mat-dialog-close]="data" color="accent" cdkFocusInitial><i class="fas fa-plus"></i> {{ 'Common.Submit' | translate }}</button> <button mat-raised-button [mat-dialog-close]="data" color="accent" cdkFocusInitial><i class="fas fa-plus"></i> {{ 'Common.Submit' | translate }}</button>

View file

@ -1,34 +1,60 @@
import { Component, Inject, OnInit } from "@angular/core"; import { Component, Inject, OnInit } from "@angular/core";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { IAdvancedData, ISonarrProfile, ISonarrRootFolder } from "../../../../../interfaces"; import {
import { SonarrService } from "../../../../../services"; IAdvancedData,
ILanguageProfiles,
ISonarrProfile,
ISonarrRootFolder,
ISonarrSettings,
} from "../../../../../interfaces";
import { SettingsService, SonarrService } from "../../../../../services";
@Component({ @Component({
templateUrl: "./tv-advanced-options.component.html", templateUrl: "./tv-advanced-options.component.html",
selector: "tv-advanced-options", selector: "tv-advanced-options",
}) })
export class TvAdvancedOptionsComponent implements OnInit { export class TvAdvancedOptionsComponent implements OnInit {
public sonarrProfiles: ISonarrProfile[]; public sonarrProfiles: ISonarrProfile[];
public sonarrRootFolders: ISonarrRootFolder[]; public sonarrRootFolders: ISonarrRootFolder[];
public sonarrLanguageProfiles: ILanguageProfiles[];
public sonarrEnabled: boolean;
constructor(public dialogRef: MatDialogRef<TvAdvancedOptionsComponent>, @Inject(MAT_DIALOG_DATA) public data: IAdvancedData, constructor(
private sonarrService: SonarrService public dialogRef: MatDialogRef<TvAdvancedOptionsComponent>,
) { @Inject(MAT_DIALOG_DATA) public data: IAdvancedData,
} private sonarrService: SonarrService,
private settingsService: SettingsService
) {}
public async ngOnInit() { public async ngOnInit() {
this.sonarrService.getQualityProfilesWithoutSettings().subscribe(c => { this.settingsService.getSonarr().subscribe((settings: ISonarrSettings) => {
if (!settings.enabled) {
this.sonarrEnabled = false;
return;
}
this.sonarrEnabled = true;
this.sonarrService.getQualityProfilesWithoutSettings().subscribe((c) => {
this.sonarrProfiles = c; this.sonarrProfiles = c;
this.data.profiles = c; this.data.profiles = c;
this.setQualityOverrides(); this.setQualityOverrides();
}); });
this.sonarrService.getRootFoldersWithoutSettings().subscribe(c => { this.sonarrService.getRootFoldersWithoutSettings().subscribe((c) => {
this.sonarrRootFolders = c; this.sonarrRootFolders = c;
this.data.rootFolders = c; this.data.rootFolders = c;
this.setRootFolderOverrides(); this.setRootFolderOverrides();
}); });
if (settings.v3) {
this.sonarrService
.getV3LanguageProfiles(settings)
.subscribe((profiles: ILanguageProfiles[]) => {
this.sonarrLanguageProfiles = profiles;
this.data.languages = profiles;
this.setLanguageOverride();
});
}
});
} }
private setQualityOverrides(): void { private setQualityOverrides(): void {
@ -37,7 +63,7 @@ export class TvAdvancedOptionsComponent implements OnInit {
return p.id === this.data.tvRequest.qualityOverride; return p.id === this.data.tvRequest.qualityOverride;
}); });
if (profile.length > 0) { if (profile.length > 0) {
this.data.movieRequest.qualityOverrideTitle = profile[0].name; this.data.tvRequest.qualityOverrideTitle = profile[0].name;
} }
} }
} }
@ -48,7 +74,18 @@ export class TvAdvancedOptionsComponent implements OnInit {
return folder.id === this.data.tvRequest.rootFolder; return folder.id === this.data.tvRequest.rootFolder;
}); });
if (path.length > 0) { if (path.length > 0) {
this.data.movieRequest.rootPathOverrideTitle = path[0].path; this.data.tvRequest.rootPathOverrideTitle = path[0].path;
}
}
}
private setLanguageOverride(): void {
if (this.sonarrLanguageProfiles) {
const profile = this.sonarrLanguageProfiles.filter((p) => {
return p.id === this.data.tvRequest.languageProfile;
});
if (profile.length > 0) {
this.data.tvRequest.languageOverrideTitle = profile[0].name;
} }
} }
} }

View file

@ -67,6 +67,7 @@ export class TvRequestGridComponent {
viewModel.requestOnBehalf = result.username?.id; viewModel.requestOnBehalf = result.username?.id;
viewModel.qualityPathOverride = result?.sonarrPathId; viewModel.qualityPathOverride = result?.sonarrPathId;
viewModel.rootFolderOverride = result?.sonarrFolderId; viewModel.rootFolderOverride = result?.sonarrFolderId;
viewModel.languageProfile = result?.sonarrLanguageId;
const requestResult = await this.requestServiceV2.requestTv(viewModel).toPromise(); const requestResult = await this.requestServiceV2.requestTv(viewModel).toPromise();
this.postRequest(requestResult); this.postRequest(requestResult);

View file

@ -102,7 +102,8 @@ export class TvDetailsComponent implements OnInit {
// get the name and ids // get the name and ids
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0]; result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0]; result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
await this.requestService2.updateTvAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, requestId: this.showRequest.id }).toPromise(); result.language = result.languages.filter(x => x.id === +result.langaugeId)[0];
await this.requestService2.updateTvAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, languageProfile: result.languageId, requestId: this.showRequest.id }).toPromise();
this.setAdvancedOptions(result); this.setAdvancedOptions(result);
} }
}); });
@ -117,15 +118,20 @@ export class TvDetailsComponent implements OnInit {
if (data.profileId) { if (data.profileId) {
this.showRequest.rootPathOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path; this.showRequest.rootPathOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path;
} }
if (data.languageId) {
this.showRequest.languageOverrideTitle = data.languages.filter(x => x.id == data.languageId)[0].name;
}
} }
private loadAdvancedInfo() { private loadAdvancedInfo() {
const profile = this.sonarrService.getQualityProfilesWithoutSettings(); const profile = this.sonarrService.getQualityProfilesWithoutSettings();
const folders = this.sonarrService.getRootFoldersWithoutSettings(); const folders = this.sonarrService.getRootFoldersWithoutSettings();
const languages = this.sonarrService.getV3LanguageProfilesWithoutSettings();
forkJoin([profile, folders]).subscribe(x => { forkJoin([profile, folders, languages]).subscribe(x => {
const sonarrProfiles = x[0]; const sonarrProfiles = x[0];
const sonarrRootFolders = x[1]; const sonarrRootFolders = x[1];
const languageProfiles = x[2];
const profile = sonarrProfiles.filter((p) => { const profile = sonarrProfiles.filter((p) => {
return p.id === this.showRequest.qualityOverride; return p.id === this.showRequest.qualityOverride;
@ -141,6 +147,13 @@ export class TvDetailsComponent implements OnInit {
this.showRequest.rootPathOverrideTitle = path[0].path; this.showRequest.rootPathOverrideTitle = path[0].path;
} }
const lang = languageProfiles.filter((folder) => {
return folder.id === this.showRequest.languageProfile;
});
if (lang.length > 0) {
this.showRequest.languageOverrideTitle = lang[0].name;
}
}); });
} }
} }

View file

@ -32,6 +32,10 @@ export class SonarrService extends ServiceHelpers {
return this.http.post<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, JSON.stringify(settings), {headers: this.headers}); return this.http.post<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, JSON.stringify(settings), {headers: this.headers});
} }
public getV3LanguageProfilesWithoutSettings(): Observable<ILanguageProfiles[]> {
return this.http.get<ILanguageProfiles[]>(`${this.url}/v3/languageprofiles/`, {headers: this.headers});
}
public isEnabled(): Promise<boolean> { public isEnabled(): Promise<boolean> {
return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers }).toPromise(); return this.http.get<boolean>(`${this.url}/enabled/`, { headers: this.headers }).toPromise();
} }

View file

@ -140,6 +140,18 @@
</div> </div>
</div> </div>
<div id="langaugeProfileAnime">
<div class="md-form-field" style="display:contents;">
<mat-form-field appearance="outline">
<mat-label>Language Profiles Anime</mat-label>
<mat-select formControlName="languageProfileAnime">
<mat-option *ngFor="let lang of languageProfiles" [value]="lang.id">{{lang.name}}</mat-option>
</mat-select>
<mat-error>A Language Profile Anime is required</mat-error>
</mat-form-field>
</div>
</div>
</div> </div>

View file

@ -20,6 +20,7 @@ export class SonarrComponent implements OnInit {
public rootFolders: ISonarrRootFolder[]; public rootFolders: ISonarrRootFolder[];
public rootFoldersAnime: ISonarrRootFolder[]; public rootFoldersAnime: ISonarrRootFolder[];
public languageProfiles: ILanguageProfiles[]; public languageProfiles: ILanguageProfiles[];
public languageProfilesAnime: ILanguageProfiles[];
public selectedRootFolder: ISonarrRootFolder; public selectedRootFolder: ISonarrRootFolder;
public selectedQuality: ISonarrProfile; public selectedQuality: ISonarrProfile;
public selectedLanguageProfiles: ILanguageProfiles; public selectedLanguageProfiles: ILanguageProfiles;
@ -73,7 +74,8 @@ export class SonarrComponent implements OnInit {
seasonFolders: [x.seasonFolders], seasonFolders: [x.seasonFolders],
v3: [x.v3], v3: [x.v3],
languageProfile: [x.languageProfile], languageProfile: [x.languageProfile],
scanForAvailability: [x.scanForAvailability] languageProfileAnime: [x.languageProfileAnime],
scanForAvailability: [x.scanForAvailability],
}); });
if (x.qualityProfile) { if (x.qualityProfile) {
@ -82,20 +84,27 @@ export class SonarrComponent implements OnInit {
if (x.rootPath) { if (x.rootPath) {
this.getRootFolders(this.form); this.getRootFolders(this.form);
} }
if(x.languageProfile) { if (x.languageProfile) {
this.getLanguageProfiles(this.form); this.getLanguageProfiles(this.form);
} }
if(x.v3) { if (x.v3) {
this.form.controls.languageProfile.setValidators([Validators.required]); this.form.controls.languageProfile.setValidators([Validators.required]);
} }
this.form.controls.v3.valueChanges.subscribe((val: boolean) => {
if (val) {
this.form.controls.languageProfile.setValidators([Validators.required, validateProfile]);
} else {
this.form.controls.languageProfile.clearValidators();
}
});
this.formErrors ={ this.formErrors ={
apiKey: {}, apiKey: {},
qualityProfile: {}, qualityProfile: {},
rootPath: {}, rootPath: {},
ip: {}, ip: {},
port: {}, port: {},
}; };
this.onFormValuesChanged(); this.onFormValuesChanged();
}); });
@ -104,7 +113,6 @@ export class SonarrComponent implements OnInit {
this.languageProfiles = []; this.languageProfiles = [];
this.rootFolders.push({ path: "Please Select", id: -1 }); this.rootFolders.push({ path: "Please Select", id: -1 });
this.qualities.push({ name: "Please Select", id: -1 }); this.qualities.push({ name: "Please Select", id: -1 });
this.languageProfiles.push({ name: "Please Select", id: -1 });
} }
public getProfiles(form: FormGroup) { public getProfiles(form: FormGroup) {
@ -137,11 +145,14 @@ export class SonarrComponent implements OnInit {
this.sonarrService.getV3LanguageProfiles(form.value) this.sonarrService.getV3LanguageProfiles(form.value)
.subscribe(x => { .subscribe(x => {
this.languageProfiles = x; this.languageProfiles = x;
this.languageProfiles.unshift({ name: "Please Select", id: -1 }); this.languageProfilesAnime = x;
this.langRunning = false; this.langRunning = false;
this.notificationService.success("Successfully retrieved the Language Profiles"); this.notificationService.success("Successfully retrieved the Language Profiles");
}); });
if (this.form.controls.v3.value) {
this.form.controls.languageProfile.setValidators([Validators.required]);
}
} }
public test(form: FormGroup) { public test(form: FormGroup) {
@ -176,6 +187,11 @@ export class SonarrComponent implements OnInit {
this.notificationService.error("Please check your entered values"); this.notificationService.error("Please check your entered values");
} }
} }
if (form.controls.v3.value && form.controls.languageProfile) {
if (form.controls.languageProfile.value === "Please Select") {
this.notificationService.error("Please check your entered values");
}
}
this.settingsService.saveSonarr(form.value) this.settingsService.saveSonarr(form.value)
.subscribe(x => { .subscribe(x => {

View file

@ -52,6 +52,14 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<div>
<mat-form-field 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>
</mat-select>
</mat-form-field>
</div>
</div> </div>
<!-- End Sonarr--> <!-- End Sonarr-->

View file

@ -3,8 +3,8 @@ import { FormBuilder, FormGroup } from "@angular/forms";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog"; import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
import { startWith, map } from "rxjs/operators"; import { startWith, map } from "rxjs/operators";
import { IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, IUserDropdown, RequestType } from "../../interfaces"; import { ILanguageProfiles, IRadarrProfile, IRadarrRootFolder, ISonarrProfile, ISonarrRootFolder, ISonarrSettings, IUserDropdown, RequestType } from "../../interfaces";
import { IdentityService, MessageService, RadarrService, RequestService, SonarrService } from "../../services"; import { IdentityService, MessageService, RadarrService, RequestService, SettingsService, SonarrService } from "../../services";
import { RequestServiceV2 } from "../../services/requestV2.service"; import { RequestServiceV2 } from "../../services/requestV2.service";
export interface IAdminRequestDialogData { export interface IAdminRequestDialogData {
@ -23,6 +23,7 @@ export class AdminRequestDialogComponent implements OnInit {
@Inject(MAT_DIALOG_DATA) public data: IAdminRequestDialogData, @Inject(MAT_DIALOG_DATA) public data: IAdminRequestDialogData,
private identityService: IdentityService, private identityService: IdentityService,
private sonarrService: SonarrService, private sonarrService: SonarrService,
private settingsService: SettingsService,
private radarrService: RadarrService, private radarrService: RadarrService,
private fb: FormBuilder private fb: FormBuilder
) {} ) {}
@ -39,6 +40,7 @@ export class AdminRequestDialogComponent implements OnInit {
public sonarrProfiles: ISonarrProfile[]; public sonarrProfiles: ISonarrProfile[];
public sonarrRootFolders: ISonarrRootFolder[]; public sonarrRootFolders: ISonarrRootFolder[];
public sonarrLanguageProfiles: ILanguageProfiles[];
public radarrProfiles: IRadarrProfile[]; public radarrProfiles: IRadarrProfile[];
public radarrRootFolders: IRadarrRootFolder[]; public radarrRootFolders: IRadarrRootFolder[];
@ -48,6 +50,7 @@ export class AdminRequestDialogComponent implements OnInit {
username: [null], username: [null],
sonarrPathId: [null], sonarrPathId: [null],
sonarrFolderId: [null], sonarrFolderId: [null],
sonarrLanguageId: [null],
radarrPathId: [null], radarrPathId: [null],
radarrFolderId: [null] radarrFolderId: [null]
}) })
@ -62,6 +65,13 @@ export class AdminRequestDialogComponent implements OnInit {
if (this.data.type === RequestType.tvShow) { if (this.data.type === RequestType.tvShow) {
this.sonarrEnabled = await this.sonarrService.isEnabled(); this.sonarrEnabled = await this.sonarrService.isEnabled();
if (this.sonarrEnabled) { if (this.sonarrEnabled) {
this.settingsService.getSonarr().subscribe((settings: ISonarrSettings) => {
if (settings.v3) {
this.sonarrService.getV3LanguageProfiles(settings).subscribe((profiles: ILanguageProfiles[]) => {
this.sonarrLanguageProfiles = profiles;
})
}
});
this.sonarrService.getQualityProfilesWithoutSettings().subscribe(c => { this.sonarrService.getQualityProfilesWithoutSettings().subscribe(c => {
this.sonarrProfiles = c; this.sonarrProfiles = c;
}); });
@ -106,6 +116,7 @@ export class AdminRequestDialogComponent implements OnInit {
model.radarrRootFolderTitle = this.radarrRootFolders?.filter(x => x.id == model.radarrFolderId)[0]?.path; model.radarrRootFolderTitle = this.radarrRootFolders?.filter(x => x.id == model.radarrFolderId)[0]?.path;
model.sonarrRootFolderTitle = this.sonarrRootFolders?.filter(x => x.id == model.sonarrFolderId)[0]?.path; model.sonarrRootFolderTitle = this.sonarrRootFolders?.filter(x => x.id == model.sonarrFolderId)[0]?.path;
model.sonarrQualityOverrideTitle = this.sonarrProfiles?.filter(x => x.id == model.sonarrPathId)[0]?.name; model.sonarrQualityOverrideTitle = this.sonarrProfiles?.filter(x => x.id == model.sonarrPathId)[0]?.name;
model.sonarrLanguageProfileTitle = this.sonarrLanguageProfiles?.filter(x => x.id == model.sonarrLanguageId)[0]?.name;
this.dialogRef.close(model); this.dialogRef.close(model);
} }
} }

View file

@ -66,6 +66,7 @@ export class EpisodeRequestComponent {
viewModel.requestOnBehalf = result.username?.id; viewModel.requestOnBehalf = result.username?.id;
viewModel.qualityPathOverride = result?.sonarrPathId; viewModel.qualityPathOverride = result?.sonarrPathId;
viewModel.rootFolderOverride = result?.sonarrFolderId; viewModel.rootFolderOverride = result?.sonarrFolderId;
viewModel.languageProfile = result?.sonarrLanguageId;
const requestResult = await this.requestService.requestTv(viewModel).toPromise(); const requestResult = await this.requestService.requestTv(viewModel).toPromise();
this.postRequest(requestResult); this.postRequest(requestResult);

View file

@ -6,8 +6,8 @@
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion> <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<!-- <PublishTrimmed>true</PublishTrimmed> <!-- <PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun> --> <PublishReadyToRun>true</PublishReadyToRun> -->
<AssemblyVersion>$(SemVer)</AssemblyVersion> <AssemblyVersion>4.0.1328.0</AssemblyVersion>
<FileVersion>$(SemVer)</FileVersion> <FileVersion>4.0.1328.0</FileVersion>
<Version>$(FullVer)</Version> <Version>$(FullVer)</Version>
<PackageVersion></PackageVersion> <PackageVersion></PackageVersion>
<TypeScriptToolsVersion>3.1</TypeScriptToolsVersion> <TypeScriptToolsVersion>3.1</TypeScriptToolsVersion>
@ -97,6 +97,10 @@
<ProjectReference Include="..\Ombi.Updater\Ombi.Updater.csproj" /> <ProjectReference Include="..\Ombi.Updater\Ombi.Updater.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Controllers\External\" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') "> <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<Exec Command="node --version" ContinueOnError="true"> <Exec Command="node --version" ContinueOnError="true">

View file

@ -259,6 +259,7 @@
"AutoApproveOptionsTvShort":"You can configure the request here, once requested it will be send to your DVR application! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it!", "AutoApproveOptionsTvShort":"You can configure the request here, once requested it will be send to your DVR application! If the request is already in Sonarr, we will not change the root folder or quality profile if you set it!",
"QualityProfilesSelect":"Select A Quality Profile", "QualityProfilesSelect":"Select A Quality Profile",
"RootFolderSelect":"Select A Root Folder", "RootFolderSelect":"Select A Root Folder",
"LanguageProfileSelect":"Select A Language Profile",
"Status":"Status", "Status":"Status",
"Availability":"Availability", "Availability":"Availability",
"RequestStatus":"Request Status", "RequestStatus":"Request Status",