mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-16 02:02:55 -07:00
!wip added the lidarr settings ui
This commit is contained in:
parent
0a4acb314c
commit
eb1c2a6959
32 changed files with 520 additions and 22 deletions
14
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
14
src/Ombi.Api.Lidarr/ILidarrApi.cs
Normal file
|
@ -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;
|
||||
|
|
9
src/Ombi/ClientApp/app/interfaces/ILidarr.ts
Normal file
9
src/Ombi/ClientApp/app/interfaces/ILidarr.ts
Normal file
|
@ -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",
|
||||
|
|
118
src/Ombi/ClientApp/app/search/music/musicsearch.component.html
Normal file
118
src/Ombi/ClientApp/app/search/music/musicsearch.component.html
Normal file
|
@ -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>
|
214
src/Ombi/ClientApp/app/search/music/musicsearch.component.ts
Normal file
214
src/Ombi/ClientApp/app/search/music/musicsearch.component.ts
Normal file
|
@ -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",
|
||||
|
|
91
src/Ombi/Controllers/External/LidarrController.cs
vendored
Normal file
91
src/Ombi/Controllers/External/LidarrController.cs
vendored
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue