Knocking out LC requirements in issue #2124 (#2125)

pull/2181/head
Anojh Thayaparan 7 years ago committed by Jamie
parent 0000ff1ce9
commit bc4db4184c

@ -1,6 +1,7 @@
using System; using System;
using AutoMapper; using AutoMapper;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Api.TheMovieDb;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Helpers; using Ombi.Helpers;
@ -26,11 +27,12 @@ namespace Ombi.Core.Engine
{ {
public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine public class TvRequestEngine : BaseMediaEngine, ITvRequestEngine
{ {
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user, public TvRequestEngine(ITvMazeApi tvApi, IMovieDbApi movApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager, INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache) : base(user, requestService, rule, manager, cache, settings) ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache) : base(user, requestService, rule, manager, cache, settings)
{ {
TvApi = tvApi; TvApi = tvApi;
MovieDbApi = movApi;
NotificationHelper = helper; NotificationHelper = helper;
TvSender = sender; TvSender = sender;
Audit = audit; Audit = audit;
@ -39,6 +41,7 @@ namespace Ombi.Core.Engine
private INotificationHelper NotificationHelper { get; } private INotificationHelper NotificationHelper { get; }
private ITvMazeApi TvApi { get; } private ITvMazeApi TvApi { get; }
private IMovieDbApi MovieDbApi { get; }
private ITvSender TvSender { get; } private ITvSender TvSender { get; }
private IAuditRepository Audit { get; } private IAuditRepository Audit { get; }
private readonly IRepository<RequestLog> _requestLog; private readonly IRepository<RequestLog> _requestLog;
@ -47,7 +50,7 @@ namespace Ombi.Core.Engine
{ {
var user = await GetUser(); var user = await GetUser();
var tvBuilder = new TvShowRequestBuilder(TvApi); var tvBuilder = new TvShowRequestBuilder(TvApi, MovieDbApi);
(await tvBuilder (await tvBuilder
.GetShowInfo(tv.TvDbId)) .GetShowInfo(tv.TvDbId))
.CreateTvList(tv) .CreateTvList(tv)

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Api.TheMovieDb;
using Ombi.Api.TvMaze.Models; using Ombi.Api.TvMaze.Models;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Helpers; using Ombi.Helpers;
@ -16,12 +18,14 @@ namespace Ombi.Core.Helpers
public class TvShowRequestBuilder public class TvShowRequestBuilder
{ {
public TvShowRequestBuilder(ITvMazeApi tvApi) public TvShowRequestBuilder(ITvMazeApi tvApi, IMovieDbApi movApi)
{ {
TvApi = tvApi; TvApi = tvApi;
MovieDbApi = movApi;
} }
private ITvMazeApi TvApi { get; } private ITvMazeApi TvApi { get; }
private IMovieDbApi MovieDbApi { get; }
public ChildRequests ChildRequest { get; set; } public ChildRequests ChildRequest { get; set; }
public List<SeasonsViewModel> TvRequests { get; protected set; } public List<SeasonsViewModel> TvRequests { get; protected set; }
@ -29,10 +33,20 @@ namespace Ombi.Core.Helpers
public DateTime FirstAir { get; protected set; } public DateTime FirstAir { get; protected set; }
public TvRequests NewRequest { get; protected set; } public TvRequests NewRequest { get; protected set; }
protected TvMazeShow ShowInfo { get; set; } protected TvMazeShow ShowInfo { get; set; }
protected List<TvSearchResult> Results { get; set; }
public async Task<TvShowRequestBuilder> GetShowInfo(int id) public async Task<TvShowRequestBuilder> GetShowInfo(int id)
{ {
ShowInfo = await TvApi.ShowLookupByTheTvDbId(id); ShowInfo = await TvApi.ShowLookupByTheTvDbId(id);
Results = await MovieDbApi.SearchTv(ShowInfo.name);
foreach (TvSearchResult result in Results) {
if (result.Name == ShowInfo.name)
{
var showIds = await MovieDbApi.GetTvExternals(result.Id);
ShowInfo.externals.imdb = showIds.imdb_id;
break;
}
}
DateTime.TryParse(ShowInfo.premiered, out var dt); DateTime.TryParse(ShowInfo.premiered, out var dt);

@ -24,6 +24,19 @@ namespace Ombi.Mapping.Profiles
.ForMember(dest => dest.VoteAverage, opts => opts.MapFrom(src => src.vote_average)) .ForMember(dest => dest.VoteAverage, opts => opts.MapFrom(src => src.vote_average))
.ForMember(dest => dest.VoteCount, opts => opts.MapFrom(src => src.vote_count)); .ForMember(dest => dest.VoteCount, opts => opts.MapFrom(src => src.vote_count));
CreateMap<SearchResult, TvSearchResult>()
.ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.backdrop_path))
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.id))
.ForMember(dest => dest.OriginalLanguage, opts => opts.MapFrom(src => src.original_language))
.ForMember(dest => dest.OriginalName, opts => opts.MapFrom(src => src.original_name))
.ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.overview))
.ForMember(dest => dest.Popularity, opts => opts.MapFrom(src => src.popularity))
.ForMember(dest => dest.PosterPath, opts => opts.MapFrom(src => src.poster_path))
.ForMember(dest => dest.ReleaseDate, opts => opts.MapFrom(src => src.first_air_date))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.name))
.ForMember(dest => dest.VoteAverage, opts => opts.MapFrom(src => src.vote_average))
.ForMember(dest => dest.VoteCount, opts => opts.MapFrom(src => src.vote_count));
CreateMap<MovieResponse, MovieResponseDto>() CreateMap<MovieResponse, MovieResponseDto>()
.ForMember(dest => dest.Adult, opts => opts.MapFrom(src => src.adult)) .ForMember(dest => dest.Adult, opts => opts.MapFrom(src => src.adult))
.ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.backdrop_path)) .ForMember(dest => dest.BackdropPath, opts => opts.MapFrom(src => src.backdrop_path))

@ -12,6 +12,7 @@ namespace Ombi.Api.TheMovieDb
Task<List<MovieSearchResult>> NowPlaying(); Task<List<MovieSearchResult>> NowPlaying();
Task<List<MovieSearchResult>> PopularMovies(); Task<List<MovieSearchResult>> PopularMovies();
Task<List<MovieSearchResult>> SearchMovie(string searchTerm); Task<List<MovieSearchResult>> SearchMovie(string searchTerm);
Task<List<TvSearchResult>> SearchTv(string searchTerm);
Task<List<MovieSearchResult>> TopRated(); Task<List<MovieSearchResult>> TopRated();
Task<List<MovieSearchResult>> Upcoming(); Task<List<MovieSearchResult>> Upcoming();
Task<List<MovieSearchResult>> SimilarMovies(int movieId); Task<List<MovieSearchResult>> SimilarMovies(int movieId);

@ -32,9 +32,12 @@ namespace Ombi.TheMovieDbApi.Models
public bool adult { get; set; } public bool adult { get; set; }
public string overview { get; set; } public string overview { get; set; }
public string release_date { get; set; } public string release_date { get; set; }
public string first_air_date { get; set; }
public int?[] genre_ids { get; set; } public int?[] genre_ids { get; set; }
public int id { get; set; } public int id { get; set; }
public string original_title { get; set; } public string original_title { get; set; }
public string original_name { get; set; }
public string name { get; set; }
public string original_language { get; set; } public string original_language { get; set; }
public string title { get; set; } public string title { get; set; }
public string backdrop_path { get; set; } public string backdrop_path { get; set; }

@ -0,0 +1,18 @@
namespace Ombi.Api.TheMovieDb.Models
{
public class TvSearchResult
{
public string PosterPath { get; set; }
public string Overview { get; set; }
public string ReleaseDate { get; set; }
public int?[] GenreIds { get; set; }
public int Id { get; set; }
public string OriginalName { get; set; }
public string OriginalLanguage { get; set; }
public string Name { get; set; }
public string BackdropPath { get; set; }
public float Popularity { get; set; }
public int VoteCount { get; set; }
public float VoteAverage { get; set; }
}
}

@ -43,6 +43,17 @@ namespace Ombi.Api.TheMovieDb
return await Api.Request<FindResult>(request); return await Api.Request<FindResult>(request);
} }
public async Task<List<TvSearchResult>> SearchTv(string searchTerm)
{
var request = new Request($"search/tv", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
request.FullUri = request.FullUri.AddQueryParameter("query", searchTerm);
AddRetry(request);
var result = await Api.Request<TheMovieDbContainer<SearchResult>>(request);
return Mapper.Map<List<TvSearchResult>>(result.results);
}
public async Task<TvExternals> GetTvExternals(int theMovieDbId) public async Task<TvExternals> GetTvExternals(int theMovieDbId)
{ {
var request = new Request($"/tv/{theMovieDbId}/external_ids", BaseUri, HttpMethod.Get); var request = new Request($"/tv/{theMovieDbId}/external_ids", BaseUri, HttpMethod.Get);

@ -1,5 +1,5 @@
<div *ngIf="issue"> <div *ngIf="issue">
<div class="row"> <div class="row issue-details">
<div class="myBg backdrop" [style.background-image]="backgroundPath"></div> <div class="myBg backdrop" [style.background-image]="backgroundPath"></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="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<h1>{{issue.title}} </h1> <h1>{{issue.title}} </h1>

@ -98,7 +98,11 @@ export class IssueDetailsComponent implements OnInit {
("url(" + x + ")"); ("url(" + x + ")");
}); });
this.imageService.getMoviePoster(issue.providerId).subscribe(x => { this.imageService.getMoviePoster(issue.providerId).subscribe(x => {
if (x.length === 0) {
this.posterPath = "../../../images/default_movie_poster.png";
} else {
this.posterPath = x.toString(); this.posterPath = x.toString();
}
}); });
} else { } else {
@ -107,7 +111,11 @@ export class IssueDetailsComponent implements OnInit {
("url(" + x + ")"); ("url(" + x + ")");
}); });
this.imageService.getTvPoster(Number(issue.providerId)).subscribe(x => { this.imageService.getTvPoster(Number(issue.providerId)).subscribe(x => {
if (x.length === 0) {
this.posterPath = "../../../images/default_tv_poster.png";
} else {
this.posterPath = x.toString(); this.posterPath = x.toString();
}
}); });
} }

@ -1,25 +1,25 @@
<table class="table table-striped table-hover table-responsive table-condensed"> <table class="table table-striped table-hover table-responsive table-condensed">
<thead> <thead>
<tr> <tr>
<th (click)="setOrder('title')"> <th (click)="setOrder('title', $event)">
<a [translate]="'Issues.ColumnTitle'"></a> <a [translate]="'Issues.ColumnTitle'"></a>
<span *ngIf="order === 'title'"> <span *ngIf="order === 'title'">
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span> <span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span> </span>
</th> </th>
<th (click)="setOrder('issueCategory.value')"> <th (click)="setOrder('issueCategory.value', $event)">
<a [translate]="'Issues.Category'"></a> <a [translate]="'Issues.Category'"></a>
<span *ngIf="order === 'issueCategory.value'"> <span *ngIf="order === 'issueCategory.value'">
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span> <span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span> </span>
</th> </th>
<th (click)="setOrder('status')"> <th (click)="setOrder('status', $event)">
<a [translate]="'Issues.Status'"></a> <a [translate]="'Issues.Status'"></a>
<span *ngIf="order === 'status'"> <span *ngIf="order === 'status'">
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span> <span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
</span> </span>
</th> </th>
<th (click)="setOrder('reportedUser')"> <th (click)="setOrder('reportedUser', $event)">
<a [translate]="'Issues.ReportedBy'"></a> <a [translate]="'Issues.ReportedBy'"></a>
<span *ngIf="order === 'reportedUser'"> <span *ngIf="order === 'reportedUser'">
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span> <span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>

@ -20,9 +20,23 @@ export class IssuesTableComponent {
public rowCount = 10; public rowCount = 10;
public setOrder(value: string) { public setOrder(value: string, el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
if (el.nodeName === "A") {
el = el.parentElement;
}
const parent = el.parentElement;
const previousFilter = parent.querySelector(".active");
if (this.order === value) { if (this.order === value) {
this.reverse = !this.reverse; this.reverse = !this.reverse;
} else {
if (previousFilter) {
previousFilter.className = "";
}
el.className = "active";
} }
this.order = value; this.order = value;

@ -67,7 +67,7 @@
<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="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"> <div class="col-sm-2 small-padding">
<img class="img-responsive poster" src="https://image.tmdb.org/t/p/w300/{{request.posterPath}}" alt="poster"> <img class="img-responsive poster" src="{{request.posterPath}}" alt="poster">
</div> </div>
@ -222,31 +222,32 @@
<p-sidebar [(visible)]="filterDisplay" styleClass="ui-sidebar-md side-back side-small"> <p-sidebar [(visible)]="filterDisplay" styleClass="ui-sidebar-md side-back side-small">
<h3>{{ 'Requests.Filter' | translate }}</h3> <h3>{{ 'Requests.Filter' | translate }}</h3>
<hr> <hr>
<div>
<h4>{{ 'Filter.FilterHeaderAvailability' | translate }}</h4> <h4>{{ 'Filter.FilterHeaderAvailability' | translate }}</h4>
<div class="form-group"> <div class="form-group">
<div class="radio"> <div class="radio">
<input type="radio" id="Available" name="Availability" (click)="filterAvailability(filterType.Available)"> <input type="radio" id="Available" name="Availability" (click)="filterAvailability(filterType.Available, $event)">
<label for="Available">{{ 'Common.Available' | translate }}</label> <label for="Available">{{ 'Common.Available' | translate }}</label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="radio"> <div class="radio">
<input type="radio" id="notAvailable" name="Availability" (click)="filterAvailability(filterType.NotAvailable)"> <input type="radio" id="notAvailable" name="Availability" (click)="filterAvailability(filterType.NotAvailable, $event)">
<label for="notAvailable">{{ 'Common.NotAvailable' | translate }}</label> <label for="notAvailable">{{ 'Common.NotAvailable' | translate }}</label>
</div> </div>
</div> </div>
</div>
<div>
<h4>{{ 'Filter.FilterHeaderRequestStatus' | translate }}</h4> <h4>{{ 'Filter.FilterHeaderRequestStatus' | translate }}</h4>
<div class="form-group"> <div class="form-group">
<div class="radio"> <div class="radio">
<input type="radio" id="approved" name="Status" (click)="filterStatus(filterType.Approved)"> <input type="radio" id="approved" name="Status" (click)="filterStatus(filterType.Approved, $event)">
<label for="approved">{{ 'Filter.Approved' | translate }}</label> <label for="approved">{{ 'Filter.Approved' | translate }}</label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="radio"> <div class="radio">
<input type="radio" id="Processing" name="Status" (click)="filterStatus(filterType.Processing)"> <input type="radio" id="Processing" name="Status" (click)="filterStatus(filterType.Processing, $event)">
<label for="Processing">{{ 'Common.ProcessingRequest' | translate }}</label> <label for="Processing">{{ 'Common.ProcessingRequest' | translate }}</label>
</div> </div>
</div> </div>
@ -256,8 +257,8 @@
<label for="pendingApproval">{{ 'Filter.PendingApproval' | translate }}</label> <label for="pendingApproval">{{ 'Filter.PendingApproval' | translate }}</label>
</div> </div>
</div> </div>
</div>
<button class="btn btn-sm btn-primary-outline" (click)="clearFilter($event)">
<button class="btn btn-sm btn-primary-outline" (click)="clearFilter()">
<i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button> <i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
</p-sidebar> </p-sidebar>

@ -149,7 +149,16 @@ export class MovieRequestsComponent implements OnInit {
event.preventDefault(); event.preventDefault();
} }
public clearFilter() { public clearFilter(el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
el = el.parentElement;
el = el.querySelectorAll("INPUT");
for (el of el) {
el.checked = false;
el.parentElement.classList.remove("active");
}
this.filterDisplay = false; this.filterDisplay = false;
this.filter.availabilityFilter = FilterType.None; this.filter.availabilityFilter = FilterType.None;
this.filter.statusFilter = FilterType.None; this.filter.statusFilter = FilterType.None;
@ -157,7 +166,8 @@ export class MovieRequestsComponent implements OnInit {
this.resetSearch(); this.resetSearch();
} }
public filterAvailability(filter: FilterType) { public filterAvailability(filter: FilterType, el: any) {
this.filterActiveStyle(el);
this.filter.availabilityFilter = filter; this.filter.availabilityFilter = filter;
this.requestService.filterMovies(this.filter) this.requestService.filterMovies(this.filter)
.subscribe(x => { .subscribe(x => {
@ -166,7 +176,8 @@ export class MovieRequestsComponent implements OnInit {
}); });
} }
public filterStatus(filter: FilterType) { public filterStatus(filter: FilterType, el: any) {
this.filterActiveStyle(el);
this.filter.statusFilter = filter; this.filter.statusFilter = filter;
this.requestService.filterMovies(this.filter) this.requestService.filterMovies(this.filter)
.subscribe(x => { .subscribe(x => {
@ -190,6 +201,24 @@ export class MovieRequestsComponent implements OnInit {
this.order = value; this.order = value;
} }
private filterActiveStyle(el: any) {
el = el.toElement || el.relatedTarget || el.target || el.srcElement;
el = el.parentElement; //gets radio div
el = el.parentElement; //gets form group div
el = el.parentElement; //gets status filter div
el = el.querySelectorAll("INPUT");
for (el of el) {
if (el.checked) {
if (!el.parentElement.classList.contains("active")) {
el.parentElement.className += " active";
}
} else {
el.parentElement.classList.remove("active");
}
}
}
private loadRequests(amountToLoad: number, currentlyLoaded: number) { private loadRequests(amountToLoad: number, currentlyLoaded: number) {
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1) this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1)
.subscribe(x => { .subscribe(x => {
@ -243,7 +272,8 @@ export class MovieRequestsComponent implements OnInit {
this.movieRequests = x; this.movieRequests = x;
this.movieRequests.forEach((req) => { this.movieRequests.forEach((req) => {
this.movieRequests.forEach((req) => this.setBackground(req)); this.setBackground(req);
this.setPoster(req);
}); });
this.radarrService.getQualityProfilesFromSettings().subscribe(c => { this.radarrService.getQualityProfilesFromSettings().subscribe(c => {
this.radarrProfiles = c; this.radarrProfiles = c;
@ -296,11 +326,20 @@ export class MovieRequestsComponent implements OnInit {
} }
private setOverride(req: IMovieRequests): void { private setOverride(req: IMovieRequests): void {
this.setPoster(req);
this.setBackground(req); this.setBackground(req);
this.setQualityOverrides(req); this.setQualityOverrides(req);
this.setRootFolderOverrides(req); this.setRootFolderOverrides(req);
} }
private setPoster(req: IMovieRequests): void {
if (req.posterPath === null) {
req.posterPath = "../../../images/default_movie_poster.png";
} else {
req.posterPath = "https://image.tmdb.org/t/p/w300/" + req.posterPath;
}
}
private setBackground(req: IMovieRequests): void { private setBackground(req: IMovieRequests): void {
req.backgroundPath = this.sanitizer.bypassSecurityTrustStyle req.backgroundPath = this.sanitizer.bypassSecurityTrustStyle
("url(" + "https://image.tmdb.org/t/p/w1280" + req.background + ")"); ("url(" + "https://image.tmdb.org/t/p/w1280" + req.background + ")");

@ -22,15 +22,7 @@
<button id="removeBtn" type="button" (click)="removeRequest(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> {{ 'Requests.Remove' | translate }}</button> <button id="removeBtn" type="button" (click)="removeRequest(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> {{ 'Requests.Remove' | translate }}</button>
</div> </div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issueBtn">
<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> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, child)">{{cat.value}}</a></li>
</ul>
</div>
</div> </div>
</div> </div>
@ -101,8 +93,3 @@
</div> </div>
</div> </div>
<issue-report [movie]="false" [visible]="issuesBarVisible" [title]="issueRequest?.title"
[issueCategory]="issueCategorySelected" [id]="issueRequest?.id" [providerId]="issueProviderId" (visibleChange)="issuesBarVisible = $event;"></issue-report>

@ -1,5 +1,5 @@
import { Component, EventEmitter, Input, Output } from "@angular/core"; import { Component, EventEmitter, Input, Output } from "@angular/core";
import { IChildRequests, IIssueCategory } from "../interfaces"; import { IChildRequests } from "../interfaces";
import { NotificationService, RequestService } from "../services"; import { NotificationService, RequestService } from "../services";
@ -13,13 +13,6 @@ export class TvRequestChildrenComponent {
@Output() public requestDeleted = new EventEmitter<number>(); @Output() public requestDeleted = new EventEmitter<number>();
@Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean;
@Input() public issueProviderId: string;
public issuesBarVisible = false;
public issueRequest: IChildRequests;
public issueCategorySelected: IIssueCategory;
constructor(private requestService: RequestService, constructor(private requestService: RequestService,
private notificationService: NotificationService) { } private notificationService: NotificationService) { }
@ -101,13 +94,6 @@ export class TvRequestChildrenComponent {
}); });
} }
public reportIssue(catId: IIssueCategory, req: IChildRequests) {
this.issueRequest = req;
this.issueCategorySelected = catId;
this.issuesBarVisible = true;
this.issueProviderId = req.id.toString();
}
private removeRequestFromUi(key: IChildRequests) { private removeRequestFromUi(key: IChildRequests) {
const index = this.childRequests.indexOf(key, 0); const index = this.childRequests.indexOf(key, 0);
if (index > -1) { if (index > -1) {

@ -69,7 +69,8 @@
<!--Sonarr Root Folder--> <!--Sonarr Root Folder-->
<div *ngIf="sonarrRootFolders" class="btn-group btn-split" id="rootFolderBtn"> <div *ngIf="sonarrRootFolders" class="btn-group btn-split" id="rootFolderBtn">
<button type="button" class="btn btn-sm btn-warning-outline"> <button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}</button> <i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span> <span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span> <span class="sr-only">Toggle Dropdown</span>
@ -84,7 +85,8 @@
<!--Sonarr Quality Profiles --> <!--Sonarr Quality Profiles -->
<div *ngIf="sonarrProfiles" class="btn-group btn-split" id="changeQualityBtn"> <div *ngIf="sonarrProfiles" class="btn-group btn-split" id="changeQualityBtn">
<button type="button" class="btn btn-sm btn-warning-outline"> <button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}</button> <i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span> <span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span> <span class="sr-only">Toggle Dropdown</span>
@ -97,18 +99,28 @@
</div> </div>
</div> </div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issueBtn">
<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> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, node.data)">{{cat.value}}</a></li>
</ul>
</div>
</div> </div>
</div> </div>
</div> </div>
<!--This is the section that holds the child seasons if they want to specify specific episodes--> <!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf"> <div *ngIf="node.leaf">
<tvrequests-children [childRequests]="node.data" [isAdmin] ="isAdmin" <tvrequests-children [childRequests]="node.data" [isAdmin] ="isAdmin"
(requestDeleted)="childRequestDeleted($event)" (requestDeleted)="childRequestDeleted($event)"></tvrequests-children>
[issueCategories]="issueCategories" [issuesEnabled]="issuesEnabled"
[issueProviderId]="node.data.tvDbId"></tvrequests-children>
</div> </div>
</ng-template> </ng-template>
</p-column> </p-column>
</p-treeTable> </p-treeTable>
</div> </div>
<issue-report [movie]="false" [visible]="issuesBarVisible" [title]="issueRequest?.title"
[issueCategory]="issueCategorySelected" [id]="issueRequest?.id" [providerId]="issueProviderId" (visibleChange)="issuesBarVisible = $event;"></issue-report>

@ -33,6 +33,9 @@ export class TvRequestsComponent implements OnInit {
@Input() public issueCategories: IIssueCategory[]; @Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean; @Input() public issuesEnabled: boolean;
public issueProviderId: string; public issueProviderId: string;
public issuesBarVisible = false;
public issueRequest: ITvRequests;
public issueCategorySelected: IIssueCategory;
public sonarrProfiles: ISonarrProfile[] = []; public sonarrProfiles: ISonarrProfile[] = [];
public sonarrRootFolders: ISonarrRootFolder[] = []; public sonarrRootFolders: ISonarrRootFolder[] = [];
@ -151,6 +154,13 @@ export class TvRequestsComponent implements OnInit {
this.updateRequest(searchResult); this.updateRequest(searchResult);
} }
public reportIssue(catId: IIssueCategory, req: ITvRequests) {
this.issueRequest = req;
this.issueCategorySelected = catId;
this.issuesBarVisible = true;
this.issueProviderId = req.id.toString();
}
private setOverride(req: ITvRequests): void { private setOverride(req: ITvRequests): void {
this.setQualityOverrides(req); this.setQualityOverrides(req);
this.setRootFolderOverrides(req); this.setRootFolderOverrides(req);
@ -191,6 +201,7 @@ export class TvRequestsComponent implements OnInit {
.subscribe(x => { .subscribe(x => {
this.tvRequests = x; this.tvRequests = x;
this.tvRequests.forEach((val, index) => { this.tvRequests.forEach((val, index) => {
this.setDefaults(val);
this.loadBackdrop(val); this.loadBackdrop(val);
this.setOverride(val.data); this.setOverride(val.data);
}); });
@ -209,6 +220,13 @@ export class TvRequestsComponent implements OnInit {
this.currentlyLoaded = 5; this.currentlyLoaded = 5;
this.loadInit(); this.loadInit();
} }
private setDefaults(val: any) {
if (val.data.posterPath === null) {
val.data.posterPath = "../../../images/default_tv_poster.png";
}
}
private loadBackdrop(val: TreeNode): void { private loadBackdrop(val: TreeNode): void {
this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => { this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
val.data.background = this.sanitizer.bypassSecurityTrustStyle val.data.background = this.sanitizer.bypassSecurityTrustStyle

@ -33,7 +33,7 @@
<div class="myBg backdrop" [style.background-image]="result.background"></div> <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="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"> <div class="col-sm-2 small-padding">
<img *ngIf="result.posterPath" class="img-responsive poster" src="https://image.tmdb.org/t/p/w300/{{result.posterPath}}" alt="poster"> <img *ngIf="result.posterPath" class="img-responsive poster" src="{{result.posterPath}}" alt="poster">
</div> </div>
<div class="col-sm-8 small-padding"> <div class="col-sm-8 small-padding">

@ -158,9 +158,12 @@ export class MovieSearchComponent implements OnInit {
private getExtraInfo() { private getExtraInfo() {
this.movieResults.forEach((val, index) => { this.movieResults.forEach((val, index) => {
if (val.posterPath === null) {
val.background = this.sanitizer. val.posterPath = "../../../images/default_movie_poster.png";
bypassSecurityTrustStyle } 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 + ")"); ("url(" + "https://image.tmdb.org/t/p/w1280" + val.backdropPath + ")");
this.searchService.getMovieInformation(val.id) this.searchService.getMovieInformation(val.id)
.subscribe(m => { .subscribe(m => {
@ -175,6 +178,7 @@ export class MovieSearchComponent implements OnInit {
const copy = { ...this.movieResults[index] }; const copy = { ...this.movieResults[index] };
this.movieResults[index] = updated; this.movieResults[index] = updated;
this.movieResults[index].background = copy.background; this.movieResults[index].background = copy.background;
this.movieResults[index].posterPath = copy.posterPath;
} }
} }
private clearResults() { private clearResults() {

@ -62,7 +62,7 @@
<div class="col-sm-8 small-padding"> <div class="col-sm-8 small-padding">
<div> <div>
<a *ngIf="node.data.imdbId" href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank"> <a *ngIf="node.data.imdbId" href="{{node.data.imdbId}}" target="_blank">
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4> <h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
</a> </a>

@ -130,7 +130,6 @@ export class TvSearchComponent implements OnInit {
public getExtraInfo() { public getExtraInfo() {
this.tvResults.forEach((val, index) => { this.tvResults.forEach((val, index) => {
this.imageService.getTvBanner(val.data.id).subscribe(x => { this.imageService.getTvBanner(val.data.id).subscribe(x => {
val.data.background = this.sanitizer. val.data.background = this.sanitizer.
bypassSecurityTrustStyle bypassSecurityTrustStyle
("url(" + x + ")"); ("url(" + x + ")");
@ -138,6 +137,7 @@ export class TvSearchComponent implements OnInit {
this.searchService.getShowInformationTreeNode(val.data.id) this.searchService.getShowInformationTreeNode(val.data.id)
.subscribe(x => { .subscribe(x => {
if (x.data) { if (x.data) {
this.setDefaults(x);
this.updateItem(val, x); this.updateItem(val, x);
} else { } else {
const index = this.tvResults.indexOf(val, 0); const index = this.tvResults.indexOf(val, 0);
@ -216,6 +216,7 @@ export class TvSearchComponent implements OnInit {
const index = this.tvResults.indexOf(key, 0); const index = this.tvResults.indexOf(key, 0);
if (index > -1) { if (index > -1) {
// Update certain properties, otherwise we will loose some data // Update certain properties, otherwise we will loose some data
this.tvResults[index].data.title = updated.data.title;
this.tvResults[index].data.banner = updated.data.banner; this.tvResults[index].data.banner = updated.data.banner;
this.tvResults[index].data.imdbId = updated.data.imdbId; this.tvResults[index].data.imdbId = updated.data.imdbId;
this.tvResults[index].data.seasonRequests = updated.data.seasonRequests; this.tvResults[index].data.seasonRequests = updated.data.seasonRequests;
@ -225,6 +226,18 @@ export class TvSearchComponent implements OnInit {
} }
} }
private setDefaults(x: any) {
if (x.data.banner === null) {
x.data.banner = "../../../images/default_tv_poster.png";
}
if (x.data.imdbId === null) {
x.data.imdbId = "https://www.tvmaze.com/shows/" + x.data.seriesId;
} else {
x.data.imdbId = "http://www.imdb.com/title/" + x.data.imdbId + "/";
}
}
private clearResults() { private clearResults() {
this.tvResults = []; this.tvResults = [];
this.searchApplied = false; this.searchApplied = false;

@ -351,5 +351,5 @@ button.list-group-item:focus {
position: absolute; position: absolute;
} }
table.table > thead > tr > th.active { table.table > thead > tr > th.active {
background-color: transparent; background-color: $primary-colour;
} }

@ -541,6 +541,10 @@ $border-radius: 10px;
cursor: pointer; cursor: pointer;
} }
.table-usermanagement {
margin-top: 20px;
}
.input-group-sm { .input-group-sm {
padding-top: 2px; padding-top: 2px;
padding-bottom: 2px; padding-bottom: 2px;

@ -11,7 +11,7 @@
"noUnusedLocals": true, "noUnusedLocals": true,
"noImplicitThis": true, "noImplicitThis": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"noImplicitAny": true, "noImplicitAny": false,
"suppressImplicitAnyIndexErrors": true, "suppressImplicitAnyIndexErrors": true,
"alwaysStrict": true, "alwaysStrict": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Loading…
Cancel
Save