Added advanced options onto the TV page to stop mophawka bitchin'

pull/3816/head
tidusjar 4 years ago
parent 26b2a574be
commit 9e0986ce9f

@ -24,6 +24,6 @@ namespace Ombi.Core.Engine.Interfaces
Task<RequestsViewModel<MovieRequests>> GetUnavailableRequests(int count, int position, string sortProperty,
string sortOrder);
Task<RequestsViewModel<MovieRequests>> GetRequestsByStatus(int count, int position, string sortProperty, string sortOrder, RequestStatus status);
Task<RequestEngineResult> UpdateAdvancedOptions(MovieAdvancedOptions options);
Task<RequestEngineResult> UpdateAdvancedOptions(MediaAdvancedOptions options);
}
}

@ -26,5 +26,6 @@ namespace Ombi.Core.Engine.Interfaces
Task UpdateRootPath(int requestId, int rootPath);
Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
Task<RequestsViewModel<ChildRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder, RequestStatus status);
Task<RequestEngineResult> UpdateAdvancedOptions(MediaAdvancedOptions options);
}
}

@ -347,7 +347,7 @@ namespace Ombi.Core.Engine
}
public async Task<RequestEngineResult> UpdateAdvancedOptions(MovieAdvancedOptions options)
public async Task<RequestEngineResult> UpdateAdvancedOptions(MediaAdvancedOptions options)
{
var request = await MovieRepository.Find(options.RequestId);
if (request == null)

@ -852,5 +852,28 @@ namespace Ombi.Core.Engine
NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc),
};
}
public async Task<RequestEngineResult> UpdateAdvancedOptions(MediaAdvancedOptions options)
{
var request = await TvRepository.Find(options.RequestId);
if (request == null)
{
return new RequestEngineResult
{
Result = false,
ErrorMessage = "Request does not exist"
};
}
request.QualityOverride = options.QualityOverride;
request.RootFolder = options.RootPathOverride;
await TvRepository.Update(request);
return new RequestEngineResult
{
Result = true
};
}
}
}

@ -1,6 +1,6 @@
namespace Ombi.Core.Models.Requests
{
public class MovieAdvancedOptions
public class MediaAdvancedOptions
{
public int RequestId { get; set; }
public int RootPathOverride { get; set; }

@ -6,7 +6,7 @@ using Ombi.Store.Entities.Requests;
namespace Ombi.Store.Repository.Requests
{
public interface ITvRequestRepository
public interface ITvRequestRepository : IRepository<TvRequests>
{
OmbiContext Db { get; }
Task<TvRequests> Add(TvRequests request);

@ -11,13 +11,14 @@ import { DenyDialogComponent } from "./shared/deny-dialog/deny-dialog.component"
import { TvRequestsPanelComponent } from "./tv/panels/tv-requests/tv-requests-panel.component";
import { MovieAdminPanelComponent } from "./movie/panels/movie-admin-panel/movie-admin-panel.component";
import { MovieAdvancedOptionsComponent } from "./movie/panels/movie-advanced-options/movie-advanced-options.component";
import { SearchService, RequestService, RadarrService, IssuesService } from "../../services";
import { SearchService, RequestService, RadarrService, IssuesService, SonarrService } from "../../services";
import { RequestServiceV2 } from "../../services/requestV2.service";
import { NewIssueComponent } from "./shared/new-issue/new-issue.component";
import { ArtistDetailsComponent } from "./artist/artist-details.component";
import { ArtistInformationPanel } from "./artist/panels/artist-information-panel/artist-information-panel.component";
import { ArtistReleasePanel } from "./artist/panels/artist-release-panel/artist-release-panel.component";
import { IssuesPanelComponent } from "./shared/issues-panel/issues-panel.component";
import { TvAdminPanelComponent } from "./tv/panels/tv-admin-panel/tv-admin-panel.component";
export const components: any[] = [
MovieDetailsComponent,
@ -38,6 +39,7 @@ export const components: any[] = [
ArtistInformationPanel,
ArtistReleasePanel,
IssuesPanelComponent,
TvAdminPanelComponent,
];
export const entryComponents: any[] = [
@ -53,4 +55,5 @@ export const providers: any[] = [
RadarrService,
RequestServiceV2,
IssuesService,
SonarrService,
];

@ -83,7 +83,7 @@
<mat-card class="mat-elevation-z8">
<mat-card-content class="medium-font">
<movie-information-panel [movie]="movie" [request]="movieRequest"></movie-information-panel>
<movie-information-panel [movie]="movie" [request]="movieRequest" [advancedOptions]="showAdvanced"></movie-information-panel>
</mat-card-content>
</mat-card>

@ -3,7 +3,7 @@
Advanced Options</h1>
<div mat-dialog-content>
<mat-form-field>
<mat-label>{{'MediaDetails.RadarrProfile' | translate }}</mat-label>
<mat-label>{{'MediaDetails.QualityProfilesSelect' | translate }}</mat-label>
<mat-select [(value)]="data.profileId">
<mat-option *ngFor="let profile of data.profiles" value="{{profile.id}}">{{profile.name}}</mat-option>
</mat-select>
@ -11,7 +11,7 @@
</div>
<div mat-dialog-content>
<mat-form-field>
<mat-label>{{'MediaDetails.RadarrFolder' | translate }}</mat-label>
<mat-label>{{'MediaDetails.RootFolderSelect' | translate }}</mat-label>
<mat-select [(value)]="data.rootFolderId">
<mat-option *ngFor="let profile of data.rootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
</mat-select>

@ -11,4 +11,5 @@ import { IAdvancedData, IMovieRequests } from "../../../../interfaces";
export class MovieInformationPanelComponent {
@Input() public movie: ISearchMovieResultV2;
@Input() public request: IMovieRequests;
@Input() public advancedOptions: boolean;
}

@ -0,0 +1,3 @@
<div *ngIf="tv && sonarrEnabled" class="text-center">
<button mat-raised-button color="warn" class="text-center" (click)="openAdvancedOptions();">{{'MediaDetails.AdvancedOptions' | translate }}</button>
</div>

@ -0,0 +1,83 @@
import { Component, Input, OnInit, EventEmitter, Output } from "@angular/core";
import { RadarrService, SonarrService } from "../../../../../services";
import { IRadarrProfile, IRadarrRootFolder, IAdvancedData, ITvRequests, ISonarrProfile, ISonarrRootFolder } from "../../../../../interfaces";
import { MatDialog } from "@angular/material/dialog";
import { RequestServiceV2 } from "../../../../../services/requestV2.service";
import { MovieAdvancedOptionsComponent } from "../../../movie/panels/movie-advanced-options/movie-advanced-options.component";
@Component({
templateUrl: "./tv-admin-panel.component.html",
selector: "tv-admin-panel",
})
export class TvAdminPanelComponent implements OnInit {
@Input() public tv: ITvRequests;
@Output() public advancedOptionsChanged = new EventEmitter<IAdvancedData>();
@Output() public sonarrEnabledChange = new EventEmitter<boolean>();
public sonarrEnabled: boolean;
public radarrProfiles: IRadarrProfile[];
public selectedRadarrProfile: IRadarrProfile;
public radarrRootFolders: IRadarrRootFolder[];
public selectRadarrRootFolders: IRadarrRootFolder;
public sonarrProfiles: ISonarrProfile[];
public sonarrRootFolders: ISonarrRootFolder[];
constructor(private sonarrService: SonarrService, private requestService: RequestServiceV2, private dialog: MatDialog) { }
public async ngOnInit() {
this.sonarrEnabled = await this.sonarrService.isEnabled();
if (this.sonarrEnabled) {
this.sonarrService.getQualityProfilesWithoutSettings()
.subscribe(x => {
this.sonarrProfiles = x;
this.setQualityOverrides();
});
this.sonarrService.getRootFoldersWithoutSettings()
.subscribe(x => {
this.sonarrRootFolders = x;
this.setRootFolderOverrides();
});
}
this.sonarrEnabledChange.emit(this.sonarrEnabled);
}
public async openAdvancedOptions() {
const dialog = this.dialog.open(MovieAdvancedOptionsComponent, { width: "700px", data: <IAdvancedData>{ profiles: this.sonarrProfiles, rootFolders: this.sonarrRootFolders }, panelClass: 'modal-panel' })
await dialog.afterClosed().subscribe(async result => {
if (result) {
// get the name and ids
result.rootFolder = result.rootFolders.filter(f => f.id === +result.rootFolderId)[0];
result.profile = result.profiles.filter(f => f.id === +result.profileId)[0];
await this.requestService.updateTvAdvancedOptions({ qualityOverride: result.profileId, rootPathOverride: result.rootFolderId, requestId: this.tv.id }).toPromise();
this.advancedOptionsChanged.emit(result);
}
});
}
private setQualityOverrides(): void {
if (this.sonarrProfiles) {
const profile = this.sonarrProfiles.filter((p) => {
return p.id === this.tv.qualityOverride;
});
if (profile.length > 0) {
this.tv.qualityOverrideTitle = profile[0].name;
}
}
}
private setRootFolderOverrides(): void {
if (this.sonarrRootFolders) {
const path = this.sonarrRootFolders.filter((folder) => {
return folder.id === this.tv.rootFolder;
});
if (path.length > 0) {
this.tv.rootPathOverrideTitle = path[0].path;
}
}
}
}

@ -11,6 +11,14 @@
</div>
</div>
<div *ngIf="advancedOptions && request.rootPathOverrideTitle">
<strong>{{'MediaDetails.RootFolderOverride' | translate }}</strong>
<div>{{request.rootPathOverrideTitle}}</div>
</div>
<div *ngIf="advancedOptions && request.qualityOverrideTitle">
<strong>{{'MediaDetails.QualityOverride' | translate }}</strong>
<div>{{request.qualityOverrideTitle}}</div>
</div>
<div>
<strong>{{'MediaDetails.Runtime' | translate }}:</strong>

@ -1,4 +1,5 @@
import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core";
import { ITvRequests } from "../../../../../interfaces";
import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
@Component({
@ -9,6 +10,8 @@ import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
})
export class TvInformationPanelComponent implements OnInit {
@Input() public tv: ISearchTvResultV2;
@Input() public request: ITvRequests;
@Input() public advancedOptions: boolean;
public seasonCount: number;
public totalEpisodes: number = 0;

@ -48,10 +48,16 @@
<div class="row">
<div class="col-12 col-md-2">
<mat-card class="mat-elevation-z8 spacing-below" *ngIf="isAdmin && showRequest" [ngStyle]="{'display': showAdvanced ? '' : 'none' }">
<mat-card-content class="medium-font">
<tv-admin-panel [tv]="showRequest" (sonarrEnabledChange)="showAdvanced = $event" (advancedOptionsChanged)="setAdvancedOptions($event)">
</tv-admin-panel>
</mat-card-content>
</mat-card>
<mat-card class="mat-elevation-z8">
<mat-card-content class="medium-font">
<tv-information-panel [tv]="tv"></tv-information-panel>
<tv-information-panel [tv]="tv" [request]="showRequest" [advancedOptions]="showAdvanced"></tv-information-panel>
</mat-card-content>
</mat-card>

@ -1,12 +1,12 @@
import { Component, ViewEncapsulation, OnInit } from "@angular/core";
import { ImageService, SearchV2Service, MessageService, RequestService } from "../../../services";
import { ImageService, SearchV2Service, MessageService, RequestService, SonarrService } from "../../../services";
import { ActivatedRoute } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser";
import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2";
import { MatDialog } from "@angular/material/dialog";
import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component";
import { EpisodeRequestComponent } from "../../../shared/episode-request/episode-request.component";
import { IChildRequests, RequestType } from "../../../interfaces";
import { IAdvancedData, IChildRequests, ISonarrProfile, ISonarrRootFolder, ITvRequests, RequestType } from "../../../interfaces";
import { AuthService } from "../../../auth/auth.service";
import { NewIssueComponent } from "../shared/new-issue/new-issue.component";
@ -19,15 +19,18 @@ export class TvDetailsComponent implements OnInit {
public tv: ISearchTvResultV2;
public tvRequest: IChildRequests[];
public showRequest: ITvRequests;
public fromSearch: boolean;
public isAdmin: boolean;
public advancedOptions: IAdvancedData;
public showAdvanced: boolean; // Set on the UI
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 auth: AuthService) {
private auth: AuthService, private sonarrService: SonarrService) {
this.route.params.subscribe((params: any) => {
this.tvdbId = params.tvdbId;
this.fromSearch = params.search;
@ -50,6 +53,7 @@ export class TvDetailsComponent implements OnInit {
if (this.tv.requestId) {
this.tvRequest = await this.requestService.getChildRequests(this.tv.requestId).toPromise();
this.showRequest = this.tvRequest.length > 0 ? this.tvRequest[0].parentRequest : undefined;
}
const tvBanner = await this.imageService.getTvBanner(this.tvdbId).toPromise();
@ -63,12 +67,11 @@ export class TvDetailsComponent implements OnInit {
public async issue() {
const dialogRef = this.dialog.open(NewIssueComponent, {
width: '500px',
data: {requestId: this.tvRequest ? this.tv.requestId : null, requestType: RequestType.tvShow, providerId: this.tv.theTvDbId, title: this.tv.title}
});
data: { requestId: this.tvRequest ? this.tv.requestId : null, requestType: RequestType.tvShow, providerId: this.tv.theTvDbId, title: this.tv.title }
});
}
public openDialog() {
debugger;
let trailerLink = this.tv.trailer;
trailerLink = trailerLink.split('?v=')[1];
@ -77,4 +80,15 @@ export class TvDetailsComponent implements OnInit {
data: trailerLink
});
}
public setAdvancedOptions(data: IAdvancedData) {
this.advancedOptions = data;
console.log(this.advancedOptions);
if (data.rootFolderId) {
this.showRequest.qualityOverrideTitle = data.rootFolders.filter(x => x.id == data.rootFolderId)[0].path;
}
if (data.profileId) {
this.showRequest.rootPathOverrideTitle = data.profiles.filter(x => x.id == data.profileId)[0].name;
}
}
}

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

@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { ServiceHelpers } from "./service.helpers";
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions, IRequestEngineResult, IAlbumRequest } from "../interfaces";
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions as IMediaAdvancedOptions, IRequestEngineResult, IAlbumRequest } from "../interfaces";
@Injectable()
@ -53,10 +53,14 @@ export class RequestServiceV2 extends ServiceHelpers {
return this.http.get<IRequestsViewModel<IChildRequests>>(`${this.url}tv/denied/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
}
public updateMovieAdvancedOptions(options: IMovieAdvancedOptions): Observable<IRequestEngineResult> {
public updateMovieAdvancedOptions(options: IMediaAdvancedOptions): Observable<IRequestEngineResult> {
return this.http.post<IRequestEngineResult>(`${this.url}movie/advancedoptions`, options, {headers: this.headers});
}
public updateTvAdvancedOptions(options: IMediaAdvancedOptions): Observable<IRequestEngineResult> {
return this.http.post<IRequestEngineResult>(`${this.url}tv/advancedoptions`, options, {headers: this.headers});
}
public getMovieUnavailableRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IMovieRequests>> {
return this.http.get<IRequestsViewModel<IMovieRequests>>(`${this.url}movie/unavailable/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
}

@ -143,5 +143,13 @@ namespace Ombi.Controllers.V1.External
return await SonarrV3Api.LanguageProfiles(settings.ApiKey, settings.FullUri);
}
[HttpGet("enabled")]
[PowerUser]
public async Task<bool> Enabled()
{
var settings = await SonarrSettings.GetSettingsAsync();
return settings.Enabled;
}
}
}

@ -128,11 +128,17 @@ namespace Ombi.Controllers.V2
}
[HttpPost("movie/advancedoptions")]
public async Task<RequestEngineResult> UpdateAdvancedOptions([FromBody] MovieAdvancedOptions options)
public async Task<RequestEngineResult> UpdateAdvancedOptions([FromBody] MediaAdvancedOptions options)
{
return await _movieRequestEngine.UpdateAdvancedOptions(options);
}
[HttpPost("tv/advancedoptions")]
public async Task<RequestEngineResult> UpdateTvAdvancedOptions([FromBody] MediaAdvancedOptions options)
{
return await _tvRequestEngine.UpdateAdvancedOptions(options);
}
[HttpGet("albums/available/{count:int}/{position:int}/{sort}/{sortOrder}")]
public async Task<RequestsViewModel<AlbumRequest>> GetAvailableAlbumRequests(int count, int position, string sort, string sortOrder)
{

@ -22,7 +22,7 @@
},
"Ombi": {
"commandName": "Project",
"commandLineArgs": "--host http://localhost:3577",
"commandLineArgs": "--host http://localhost:3577 --baseurl /ombi",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},

@ -164,7 +164,7 @@ namespace Ombi
var baseUrl = appConfig.Get(ConfigurationTypes.BaseUrl);
if (baseUrl != null)
{
if (baseUrl.Value.HasValue())
if (baseUrl.Value.HasValue() && settings.BaseUrl != baseUrl.Value)
{
settings.BaseUrl = baseUrl.Value;
ombiService.SaveSettings(settings);

@ -238,8 +238,8 @@
"ViewCollection":"View Collection",
"NotEnoughInfo": "Unfortunately there is not enough information about this show yet!",
"AdvancedOptions":"Advanced Options",
"RadarrProfile":"Radarr Quality Profile",
"RadarrFolder":"Radarr Root Folder",
"QualityProfilesSelect":"Select A Quality Profile",
"RootFolderSelect":"Select A Root Folder",
"Status":"Status",
"Availability":"Availability",
"RequestStatus":"Request Status",

Loading…
Cancel
Save