!wip added the lidarr settings ui

pull/2478/head
TidusJar 6 years ago
parent 0a4acb314c
commit eb1c2a6959

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ombi.Api.Lidarr.Models;
namespace Ombi.Api.Lidarr
{
public interface ILidarrApi
{
Task<List<AlbumLookup>> AlbumLookup(string searchTerm, string apiKey, string baseUrl);
Task<List<AlbumLookup>> ArtistLookup(string searchTerm, string apiKey, string baseUrl);
Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl);
Task<List<LidarrRootFolder>> GetRootFolders(string apiKey, string baseUrl);
}
}

@ -7,7 +7,7 @@ using Ombi.Api.Lidarr.Models;
namespace Ombi.Api.Lidarr
{
public class LidarrApi
public class LidarrApi : ILidarrApi
{
public LidarrApi(ILogger<LidarrApi> logger, IApi api)
{

@ -32,6 +32,7 @@ using Ombi.Api.CouchPotato;
using Ombi.Api.DogNzb;
using Ombi.Api.FanartTv;
using Ombi.Api.Github;
using Ombi.Api.Lidarr;
using Ombi.Api.Mattermost;
using Ombi.Api.Notifications;
using Ombi.Api.Pushbullet;
@ -117,6 +118,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<ISickRageApi, SickRageApi>();
services.AddTransient<IAppVeyorApi, AppVeyorApi>();
services.AddTransient<IOneSignalApi, OneSignalApi>();
services.AddTransient<ILidarrApi, LidarrApi>();
}
public static void RegisterStore(this IServiceCollection services) {

@ -21,6 +21,7 @@
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
<ProjectReference Include="..\Ombi.Api.Github\Ombi.Api.Github.csproj" />
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />

@ -18,6 +18,8 @@ namespace Ombi.Helpers
public const string NowPlayingMovies = nameof(NowPlayingMovies);
public const string RadarrRootProfiles = nameof(RadarrRootProfiles);
public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles);
public const string LidarrRootFolders = nameof(LidarrRootFolders);
public const string LidarrQualityProfiles = nameof(LidarrQualityProfiles);
public const string FanartTv = nameof(FanartTv);
}
}

@ -1,4 +1,4 @@
import { IIssueCategory, IUser, RequestType } from "./";
import { IIssueCategory, IUser, RequestType } from ".";
export interface IIssues {
id?: number;

@ -0,0 +1,9 @@
export interface ILidarrRootFolder {
id: number;
path: string;
}
export interface ILidarrProfile {
name: string;
id: number;
}

@ -1,4 +1,4 @@
import { ICheckbox } from "./index";
import { ICheckbox } from ".";
export interface IUser {
id: string;

@ -14,3 +14,4 @@ export * from "./ISonarr";
export * from "./IUser";
export * from "./IIssues";
export * from "./IRecentlyAdded";
export * from "./ILidarr";

@ -1,6 +1,6 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { IIssues, IPagenator, IssueStatus } from "./../interfaces";
import { IIssues, IPagenator, IssueStatus } from "../interfaces";
@Component({
selector: "issues-table",

@ -2,7 +2,7 @@ import { Component, OnInit } from "@angular/core";
import { NguCarouselConfig } from "@ngu/carousel";
import { ImageService, RecentlyAddedService } from "../services";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "./../interfaces";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "../interfaces";
@Component({
templateUrl: "recentlyAdded.component.html",

@ -1,8 +1,8 @@

import { Component, OnInit } from "@angular/core";
import { IIssueCategory } from "./../interfaces";
import { IssuesService, SettingsService } from "./../services";
import { IIssueCategory } from "../interfaces";
import { IssuesService, SettingsService } from "../services";
@Component({
templateUrl: "./request.component.html",

@ -7,7 +7,7 @@ import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { FilterType, IIssueCategory, IPagenator, IRequestsViewModel, ISonarrProfile, ISonarrRootFolder, ITvRequests, OrderType } from "../interfaces";
import { NotificationService, RequestService, SonarrService } from "../services";
import { ImageService } from "./../services/image.service";
import { ImageService } from "../services/image.service";
@Component({
selector: "tv-requests",

@ -0,0 +1,118 @@
<!-- Movie tab -->
<div role="tabpanel" class="tab-pane active" id="MoviesTab">
<div class="input-group">
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
<div class="input-group-addon right-radius">
<div class="btn-group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
{{ 'Search.Suggestions' | translate }}
<i class="fa fa-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li><a (click)="popularMovies()" [translate]="'Search.Movies.PopularMovies'"></a></li>
<li><a (click)="upcomingMovies()" [translate]="'Search.Movies.UpcomingMovies'"></a></li>
<li><a (click)="topRatedMovies()" [translate]="'Search.Movies.TopRatedMovies'"></a></li>
<li><a (click)="nowPlayingMovies()" [translate]="'Search.Movies.NowPlayingMovies'"></a></li>
</ul>
</div>
<i class="fa fa-search"></i>
</div>
</div>
<br />
<br />
<!-- Movie content -->
<div id="movieList">
<div *ngIf="searchApplied && movieResults?.length <= 0" class='no-search-results'>
<i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>
<div *ngFor="let result of movieResults">
<div class="row" >
<div class="myBg backdrop" [style.background-image]="result.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-2 small-padding">
<img *ngIf="result.posterPath" class="img-responsive poster" src="{{result.posterPath}}" alt="poster">
</div>
<div class="col-sm-8 small-padding">
<div>
<a href="https://www.themoviedb.org/movie/{{result.id}}/" target="_blank">
<h4>{{result.title}} ({{result.releaseDate | date: 'yyyy'}})</h4>
</a>
<span class="tags">
<span *ngIf="result.releaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.TheatricalRelease' | translate: {date: result.releaseDate | date: 'mediumDate'} }}</span>
<span *ngIf="result.digitalReleaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | date: 'mediumDate'} }}</span>
<a *ngIf="result.homepage" href="{{result.homepage}}" id="homePageLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.HomePage'"></span></a>
<a *ngIf="result.trailer" href="{{result.trailer}}" id="trailerLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.Trailer'"></span></a>
<span *ngIf="result.quality" id="qualityLabel" class="label label-success">{{result.quality}}p</span>
<ng-template [ngIf]="result.available"><span class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span></ng-template>
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span></ng-template>
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning" id="pendingApprovalLabel" [translate]="'Common.PendingApproval'"></span></ng-template>
<ng-template [ngIf]="!result.requested && !result.available && !result.approved"><span class="label label-danger" id="notRequestedLabel" [translate]="'Common.NotRequested'"></span></ng-template>
</span>
<br/>
</div>
<p style="font-size: 0.9rem !important">{{result.overview}}</p>
</div>
<div class="col-sm-2 small-padding">
<div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a>
</div>
</div>
<div *ngIf="result.available">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> {{ 'Common.Available' | translate }}</button>
</div>
<div *ngIf="!result.available">
<div *ngIf="result.requested || result.approved; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> {{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i>{{ 'Common.Request' | translate }}</button>
</ng-template>
</div>
<button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button>
<br/>
<div *ngIf="result.available">
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
<a *ngIf="result.embyUrl" style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline" href="{{result.embyUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Emby</a>
</div>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, result)">{{cat.value}}</a></li>
</ul>
</div>
</div>
</div>
<br/>
<br/>
</div>
</div>
</div>
<issue-report [movie]="true" [visible]="issuesBarVisible" (visibleChange)="issuesBarVisible = $event;" [title]="issueRequestTitle"
[issueCategory]="issueCategorySelected" [id]="issueRequestId" [providerId]="issueProviderId"></issue-report>

@ -0,0 +1,214 @@
import { PlatformLocation } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { TranslateService } from "@ngx-translate/core";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../interfaces";
import { NotificationService, RequestService, SearchService } from "../services";
@Component({
selector: "music-search",
templateUrl: "./music.component.html",
})
export class MusicSearchComponent implements OnInit {
public searchText: string;
public searchChanged: Subject<string> = new Subject<string>();
public movieResults: ISearchMovieResult[];
public result: IRequestEngineResult;
public searchApplied = false;
@Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean;
public issuesBarVisible = false;
public issueRequestTitle: string;
public issueRequestId: number;
public issueProviderId: string;
public issueCategorySelected: IIssueCategory;
public defaultPoster: string;
constructor(
private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService,
private readonly translate: TranslateService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMusic(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results.
this.getExtraInfo();
});
});
this.defaultPoster = "../../../images/default_movie_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
if (base) {
this.defaultPoster = "../../.." + base + "/images/default_movie_poster.png";
}
}
public ngOnInit() {
this.searchText = "";
this.movieResults = [];
this.result = {
message: "",
result: false,
errorMessage: "",
};
this.popularMovies();
}
public search(text: any) {
this.searchChanged.next(text.target.value);
}
public request(searchResult: ISearchMovieResult) {
searchResult.requested = true;
searchResult.requestProcessing = true;
searchResult.showSubscribe = false;
if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) {
searchResult.approved = true;
}
try {
this.requestService.requestMovie({ theMovieDbId: searchResult.id })
.subscribe(x => {
this.result = x;
if (this.result.result) {
this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => {
this.notificationService.success(x);
searchResult.processed = true;
});
} else {
if (this.result.errorMessage && this.result.message) {
this.notificationService.warning("Request Added", `${this.result.message} - ${this.result.errorMessage}`);
} else {
this.notificationService.warning("Request Added", this.result.message ? this.result.message : this.result.errorMessage);
}
searchResult.requested = false;
searchResult.approved = false;
searchResult.processed = false;
searchResult.requestProcessing = false;
}
});
} catch (e) {
searchResult.processed = false;
searchResult.requestProcessing = false;
this.notificationService.error(e);
}
}
public popularMovies() {
this.clearResults();
this.searchService.popularMovies()
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public nowPlayingMovies() {
this.clearResults();
this.searchService.nowPlayingMovies()
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public topRatedMovies() {
this.clearResults();
this.searchService.topRatedMovies()
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public upcomingMovies() {
this.clearResults();
this.searchService.upcomingMovies()
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public reportIssue(catId: IIssueCategory, req: ISearchMovieResult) {
this.issueRequestId = req.id;
this.issueRequestTitle = req.title + `(${req.releaseDate.getFullYear})`;
this.issueCategorySelected = catId;
this.issuesBarVisible = true;
this.issueProviderId = req.id.toString();
}
public similarMovies(theMovieDbId: number) {
this.clearResults();
this.searchService.similarMovies(theMovieDbId)
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public subscribe(r: ISearchMovieResult) {
r.subscribed = true;
this.requestService.subscribeToMovie(r.requestId)
.subscribe(x => {
this.notificationService.success("Subscribed To Movie!");
});
}
public unSubscribe(r: ISearchMovieResult) {
r.subscribed = false;
this.requestService.unSubscribeToMovie(r.requestId)
.subscribe(x => {
this.notificationService.success("Unsubscribed Movie!");
});
}
private getExtraInfo() {
this.movieResults.forEach((val, index) => {
if (val.posterPath === null) {
val.posterPath = this.defaultPoster;
} else {
val.posterPath = "https://image.tmdb.org/t/p/w300/" + val.posterPath;
}
val.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + "https://image.tmdb.org/t/p/w1280" + val.backdropPath + ")");
this.searchService.getMovieInformation(val.id)
.subscribe(m => {
this.updateItem(val, m);
});
});
}
private updateItem(key: ISearchMovieResult, updated: ISearchMovieResult) {
const index = this.movieResults.indexOf(key, 0);
if (index > -1) {
const copy = { ...this.movieResults[index] };
this.movieResults[index] = updated;
this.movieResults[index].background = copy.background;
this.movieResults[index].posterPath = copy.posterPath;
}
}
private clearResults() {
this.movieResults = [];
this.searchApplied = false;
}
}

@ -1,7 +1,7 @@
import { Component, OnInit } from "@angular/core";
import { IIssueCategory } from "./../interfaces";
import { IssuesService, SettingsService } from "./../services";
import { IIssueCategory } from "../interfaces";
import { IssuesService, SettingsService } from "../services";
@Component({
templateUrl: "./search.component.html",

@ -6,3 +6,4 @@ export * from "./sonarr.service";
export * from "./tester.service";
export * from "./plexoauth.service";
export * from "./plextv.service";
export * from "./lidarr.service";

@ -0,0 +1,29 @@
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { ILidarrProfile, ILidarrRootFolder } from "../../interfaces";
import { ILidarrSettings } from "../../interfaces";
import { ServiceHelpers } from "../service.helpers";
@Injectable()
export class LidarrService extends ServiceHelpers {
constructor(http: HttpClient, public platformLocation: PlatformLocation) {
super(http, "/api/v1/Lidarr", platformLocation);
}
public getRootFolders(settings: ILidarrSettings): Observable<ILidarrRootFolder[]> {
return this.http.post<ILidarrRootFolder[]>(`${this.url}/RootFolders/`, JSON.stringify(settings), {headers: this.headers});
}
public getQualityProfiles(settings: ILidarrSettings): Observable<ILidarrProfile[]> {
return this.http.post<ILidarrProfile[]>(`${this.url}/Profiles/`, JSON.stringify(settings), {headers: this.headers});
}
public getRootFoldersFromSettings(): Observable<ILidarrRootFolder[]> {
return this.http.get<ILidarrRootFolder[]>(`${this.url}/RootFolders/`, {headers: this.headers});
}
public getQualityProfilesFromSettings(): Observable<ILidarrProfile[]> {
return this.http.get<ILidarrProfile[]>(`${this.url}/Profiles/`, {headers: this.headers});
}
}

@ -4,7 +4,7 @@ import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { IMobileUsersViewModel } from "./../interfaces";
import { IMobileUsersViewModel } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";
@Injectable()

@ -4,7 +4,7 @@ import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { IMassEmailModel } from "./../interfaces";
import { IMassEmailModel } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";

@ -4,7 +4,7 @@ import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "./../interfaces";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";
@Injectable()

@ -68,4 +68,8 @@ export class SearchService extends ServiceHelpers {
public trendingTv(): Observable<ISearchTvResult[]> {
return this.http.get<ISearchTvResult[]>(`${this.url}/Tv/trending`, {headers: this.headers});
}
// Music
public searchMusic(searchTerm: string): Observable<ISearchMovieResult[]> {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Music/` + searchTerm);
}
}

@ -18,6 +18,7 @@ import {
IJobSettings,
IJobSettingsViewModel,
ILandingPageSettings,
ILidarrSettings,
IMattermostNotifcationSettings,
IMobileNotifcationSettings,
INewsletterNotificationSettings,

@ -3,7 +3,7 @@
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { NotificationService, SettingsService } from "../../services";
import { ICronTestModel } from "./../../interfaces";
import { ICronTestModel } from "../../interfaces";
@Component({
templateUrl: "./jobs.component.html",

@ -2,7 +2,7 @@
import { INewsletterNotificationSettings, NotificationType } from "../../interfaces";
import { JobService, NotificationService, SettingsService } from "../../services";
import { TesterService } from "./../../services/applications/tester.service";
import { TesterService } from "../../services/applications/tester.service";
@Component({
templateUrl: "./newsletter.component.html",

@ -8,7 +8,7 @@ import { ClipboardModule } from "ngx-clipboard";
import { AuthGuard } from "../auth/auth.guard";
import { AuthService } from "../auth/auth.service";
import {
CouchPotatoService, EmbyService, IssuesService, JobService, MobileService, NotificationMessageService, PlexService, RadarrService,
CouchPotatoService, EmbyService, IssuesService, JobService, LidarrService, MobileService, NotificationMessageService, PlexService, RadarrService,
SonarrService, TesterService, ValidationService,
} from "../services";
@ -22,6 +22,7 @@ import { EmbyComponent } from "./emby/emby.component";
import { IssuesComponent } from "./issues/issues.component";
import { JobsComponent } from "./jobs/jobs.component";
import { LandingPageComponent } from "./landingpage/landingpage.component";
import { LidarrComponent } from "./lidarr/lidarr.component";
import { MassEmailComponent } from "./massemail/massemail.component";
import { DiscordComponent } from "./notifications/discord.component";
import { EmailNotificationComponent } from "./notifications/emailnotification.component";
@ -36,7 +37,6 @@ import { TelegramComponent } from "./notifications/telegram.component";
import { OmbiComponent } from "./ombi/ombi.component";
import { PlexComponent } from "./plex/plex.component";
import { RadarrComponent } from "./radarr/radarr.component";
import { LidarrComponent } from "./lidarr/lidarr.component";
import { SickRageComponent } from "./sickrage/sickrage.component";
import { SonarrComponent } from "./sonarr/sonarr.component";
import { UpdateComponent } from "./update/update.component";
@ -145,6 +145,7 @@ const routes: Routes = [
EmbyService,
MobileService,
NotificationMessageService,
LidarrService,
],
})

@ -48,6 +48,15 @@
</ul>
</li>
<li class="dropdown" [routerLinkActive]="['active']">
<a href="ignore($event)" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-film" aria-hidden="true"></i> Music <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Lidarr']">Lidarr</a></li>
</ul>
</li>
<li class="dropdown" [routerLinkActive]="['active']">
<a href="ignore($event)" class="dropdown-toggle" data-toggle="dropdown">

@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { IIssueCategory, IIssues, IssueStatus, RequestType } from "./../interfaces";
import { IssuesService, NotificationService } from "./../services";
import { IIssueCategory, IIssues, IssueStatus, RequestType } from "../interfaces";
import { IssuesService, NotificationService } from "../services";
@Component({
selector: "issue-report",

@ -2,7 +2,7 @@
import { ActivatedRoute, Router } from "@angular/router";
import { IdentityService, PlexOAuthService } from "../../services";
import { AuthService } from "./../../auth/auth.service";
import { AuthService } from "../../auth/auth.service";
@Component({
templateUrl: "./plexoauth.component.html",

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Ombi.Api.Lidarr;
using Ombi.Api.Lidarr.Models;
using Ombi.Attributes;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models.External;
namespace Ombi.Controllers.External
{
[PowerUser]
[ApiV1]
[Produces("application/json")]
public class LidarrController : Controller
{
public LidarrController(ILidarrApi lidarr, ISettingsService<LidarrSettings> settings,
ICacheService mem)
{
_lidarrApi = lidarr;
_lidarrSettings = settings;
Cache = mem;
}
private readonly ILidarrApi _lidarrApi;
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private ICacheService Cache { get; }
/// <summary>
/// Gets the Lidarr profiles.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
[HttpPost("Profiles")]
public async Task<IEnumerable<LidarrProfile>> GetProfiles([FromBody] LidarrSettings settings)
{
return await _lidarrApi.GetProfiles(settings.ApiKey, settings.FullUri);
}
/// <summary>
/// Gets the Lidarr root folders.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
[HttpPost("RootFolders")]
public async Task<IEnumerable<LidarrRootFolder>> GetRootFolders([FromBody] LidarrSettings settings)
{
return await _lidarrApi.GetRootFolders(settings.ApiKey, settings.FullUri);
}
/// <summary>
/// Gets the Lidarr profiles using the saved settings
/// <remarks>The data is cached for an hour</remarks>
/// </summary>
/// <returns></returns>
[HttpGet("Profiles")]
public async Task<IEnumerable<LidarrProfile>> GetProfiles()
{
return await Cache.GetOrAdd(CacheKeys.LidarrQualityProfiles, async () =>
{
var settings = await _lidarrSettings.GetSettingsAsync();
if (settings.Enabled)
{
return await _lidarrApi.GetProfiles(settings.ApiKey, settings.FullUri);
}
return null;
}, DateTime.Now.AddHours(1));
}
/// <summary>
/// Gets the Lidarr root folders using the saved settings.
/// <remarks>The data is cached for an hour</remarks>
/// </summary>
/// <returns></returns>
[HttpGet("RootFolders")]
public async Task<IEnumerable<LidarrRootFolder>> GetRootFolders()
{
return await Cache.GetOrAdd(CacheKeys.LidarrRootFolders, async () =>
{
var settings = await _lidarrSettings.GetSettingsAsync();
if (settings.Enabled)
{
return await _lidarrApi.GetRootFolders(settings.ApiKey, settings.FullUri);
}
return null;
}, DateTime.Now.AddHours(1));
}
}
}

@ -40,7 +40,7 @@ namespace Ombi.Controllers.External
}
/// <summary>
/// Gets the Radar root folders.
/// Gets the Radarr root folders.
/// </summary>
/// <param name="settings">The settings.</param>
/// <returns></returns>
@ -70,7 +70,7 @@ namespace Ombi.Controllers.External
}
/// <summary>
/// Gets the Radar root folders using the saved settings.
/// Gets the Radarr root folders using the saved settings.
/// <remarks>The data is cached for an hour</remarks>
/// </summary>
/// <returns></returns>

@ -89,6 +89,7 @@
<ItemGroup>
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
<ProjectReference Include="..\Ombi.Api.Github\Ombi.Api.Github.csproj" />
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
<ProjectReference Include="..\Ombi.DependencyInjection\Ombi.DependencyInjection.csproj" />

Loading…
Cancel
Save