Fixed a bunch of issues on #1513

This commit is contained in:
tidusjar 2017-09-23 01:08:21 +01:00
parent 25d8f9b40d
commit 187d76ea77
24 changed files with 372 additions and 364 deletions

View file

@ -13,8 +13,10 @@ namespace Ombi.Core.Engine.Interfaces
Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv); Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv);
Task<IEnumerable<TvRequests>> SearchTvRequest(string search); Task<IEnumerable<TvRequests>> SearchTvRequest(string search);
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search);
Task<TvRequests> UpdateTvRequest(TvRequests request); Task<TvRequests> UpdateTvRequest(TvRequests request);
Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position);
Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId); Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId);
Task<ChildRequests> UpdateChildRequest(ChildRequests request); Task<ChildRequests> UpdateChildRequest(ChildRequests request);
Task RemoveTvChild(int requestId); Task RemoveTvChild(int requestId);

View file

@ -11,4 +11,13 @@ namespace Ombi.Core.Engine
public bool Leaf { get; set; } public bool Leaf { get; set; }
public bool Expanded { get; set; } public bool Expanded { get; set; }
} }
public class TreeNode<T,U>
{
public string Label { get; set; }
public T Data { get; set; }
public List<TreeNode<U>> Children { get; set; }
public bool Leaf { get; set; }
public bool Expanded { get; set; }
}
} }

View file

@ -122,6 +122,12 @@ namespace Ombi.Core.Engine
return allRequests; return allRequests;
} }
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position)
{
var allRequests = await TvRepository.Get().Skip(position).Take(count).ToListAsync();
return ParseIntoTreeNode(allRequests);
}
public async Task<IEnumerable<TvRequests>> GetRequests() public async Task<IEnumerable<TvRequests>> GetRequests()
{ {
var allRequests = TvRepository.Get(); var allRequests = TvRepository.Get();
@ -140,6 +146,13 @@ namespace Ombi.Core.Engine
return results; return results;
} }
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search)
{
var allRequests = TvRepository.Get();
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
return ParseIntoTreeNode(results);
}
public async Task<TvRequests> UpdateTvRequest(TvRequests request) public async Task<TvRequests> UpdateTvRequest(TvRequests request)
{ {
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username); await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
@ -201,6 +214,41 @@ namespace Ombi.Core.Engine
return await AfterRequest(model.ChildRequests.FirstOrDefault()); return await AfterRequest(model.ChildRequests.FirstOrDefault());
} }
private static List<TreeNode<TvRequests, List<ChildRequests>>> ParseIntoTreeNode(IEnumerable<TvRequests> result)
{
var node = new List<TreeNode<TvRequests, List<ChildRequests>>>();
foreach (var value in result)
{
node.Add(new TreeNode<TvRequests, List<ChildRequests>>
{
Data = value,
Children = new List<TreeNode<List<ChildRequests>>>
{
new TreeNode<List<ChildRequests>>
{
Data = SortEpisodes(value.ChildRequests),
Leaf = true
}
}
});
}
return node;
}
private static List<ChildRequests> SortEpisodes(List<ChildRequests> items)
{
foreach (var value in items)
{
foreach (var requests in value.SeasonRequests)
{
requests.Episodes.OrderBy(x => x.EpisodeNumber);
}
}
return items;
}
private async Task<RequestEngineResult> AfterRequest(ChildRequests model) private async Task<RequestEngineResult> AfterRequest(ChildRequests model)
{ {
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification); var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification);

View file

@ -19,13 +19,14 @@ using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests; using Ombi.Store.Repository.Requests;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine
{ {
public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings, public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, ITraktApi trakt, IRuleEvaluator r, UserManager<OmbiUser> um) ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, UserManager<OmbiUser> um)
: base(identity, service, r, um) : base(identity, service, r, um)
{ {
TvMazeApi = tvMaze; TvMazeApi = tvMaze;
@ -34,6 +35,7 @@ namespace Ombi.Core.Engine
EmbySettings = embySettings; EmbySettings = embySettings;
PlexContentRepo = repo; PlexContentRepo = repo;
TraktApi = trakt; TraktApi = trakt;
EmbyContentRepo = embyRepo;
} }
private ITvMazeApi TvMazeApi { get; } private ITvMazeApi TvMazeApi { get; }
@ -41,6 +43,7 @@ namespace Ombi.Core.Engine
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<EmbySettings> EmbySettings { get; } private ISettingsService<EmbySettings> EmbySettings { get; }
private IPlexContentRepository PlexContentRepo { get; } private IPlexContentRepository PlexContentRepo { get; }
private IEmbyContentRepository EmbyContentRepo { get; }
private ITraktApi TraktApi { get; } private ITraktApi TraktApi { get; }
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm) public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm)
@ -175,11 +178,31 @@ namespace Ombi.Core.Engine
{ {
if (embySettings.Enable) if (embySettings.Enable)
{ {
//var embyShow = EmbyChecker.GetTvShow(embyCached.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId); var content = await EmbyContentRepo.Get(item.Id.ToString());
//if (embyShow != null)
//{ if (content != null)
// viewT.Available = true; {
//} item.Available = true;
}
// Let's go through the episodes now
if (item.SeasonRequests.Any())
{
var allEpisodes = EmbyContentRepo.GetAllEpisodes().Include(x => x.Series);
foreach (var season in item.SeasonRequests)
{
foreach (var episode in season.Episodes)
{
var epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && item.Id.ToString() == x.Series.ProviderId);
if (epExists != null)
{
episode.Available = true;
}
}
}
}
} }
if (plexSettings.Enable) if (plexSettings.Enable)
{ {
@ -190,6 +213,24 @@ namespace Ombi.Core.Engine
item.Available = true; item.Available = true;
item.PlexUrl = content.Url; item.PlexUrl = content.Url;
} }
// Let's go through the episodes now
if (item.SeasonRequests.Any())
{
var allEpisodes = PlexContentRepo.GetAllEpisodes();
foreach (var season in item.SeasonRequests)
{
foreach (var episode in season.Episodes)
{
var epExists = await allEpisodes.FirstOrDefaultAsync(x =>
x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber);
if (epExists != null)
{
episode.Available = true;
}
}
}
}
} }
if (item.Id > 0) if (item.Id > 0)

View file

@ -77,6 +77,12 @@ namespace Ombi.Schedule.Jobs.Emby
foreach (var ep in allEpisodes.Items) foreach (var ep in allEpisodes.Items)
{ {
if (ep.LocationType.Equals("Virtual", StringComparison.CurrentCultureIgnoreCase))
{
// This means that we don't actully have the file, it's just Emby being nice and showing future stuff
continue;
}
var epInfo = await _api.GetEpisodeInformation(ep.Id, server.ApiKey, server.AdministratorId, server.FullUri); var epInfo = await _api.GetEpisodeInformation(ep.Id, server.ApiKey, server.AdministratorId, server.FullUri);
if (epInfo?.ProviderIds?.Tvdb == null) if (epInfo?.ProviderIds?.Tvdb == null)
{ {

View file

@ -108,31 +108,8 @@ namespace Ombi.Schedule.Jobs.Ombi
} }
else else
{ {
// Linux Logger.LogInformation(LoggingEvents.Updater, "We are linux");
if (desc.Contains("ubuntu", CompareOptions.IgnoreCase)) download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("linux", CompareOptions.IgnoreCase));
{
// Ubuntu
Logger.LogInformation(LoggingEvents.Updater, "We are ubuntu");
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("ubuntu", CompareOptions.IgnoreCase));
}
else if (desc.Contains("debian", CompareOptions.IgnoreCase))
{
// Debian
Logger.LogInformation(LoggingEvents.Updater, "We are debian");
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("debian", CompareOptions.IgnoreCase));
}
else if (desc.Contains("centos", CompareOptions.IgnoreCase))
{
// Centos
Logger.LogInformation(LoggingEvents.Updater, "We are centos");
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("centos",
CompareOptions.IgnoreCase));
}
else
{
return;
}
} }
if (download == null) if (download == null)
{ {

View file

@ -14,6 +14,7 @@ namespace Ombi.Store.Entities
Url, Url,
Port, Port,
FanartTv, FanartTv,
TheMovieDb TheMovieDb,
StoragePath
} }
} }

View file

@ -137,4 +137,5 @@ export interface IEpisodesRequests {
available: boolean; available: boolean;
requested: boolean; requested: boolean;
approved: boolean; approved: boolean;
selected:boolean; // This is for the UI only
} }

View file

@ -9,7 +9,7 @@ include the remember me checkbox
<div class="card card-container"> <div class="card card-container">
<!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> --> <!-- <img class="profile-img-card" src="//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" alt="" /> -->
<div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/ms-icon-150x150.png" /></div> <div *ngIf="!customizationSettings.logo"><img id="profile-img" class="profile-img-card" src="/images/ms-icon-150x150.png" /></div>
<div *ngIf="customizationSettings.logo"><img id="profile-img" class="profile-img-card" [src]="customizationSettings.logo" /></div> <div *ngIf="customizationSettings.logo"><img id="profile-img" class="profile-img-custom" [src]="customizationSettings.logo" /></div>
<p id="profile-name" class="profile-name-card"></p> <p id="profile-name" class="profile-name-card"></p>
<form class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)"> <form class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">

View file

@ -14,7 +14,6 @@ body, html {
height: 100% !important; height: 100% !important;
background-repeat: no-repeat !important; background-repeat: no-repeat !important;
background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33)) !important; background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33)) !important;
} }
landingDiv { landingDiv {
@ -85,6 +84,15 @@ img.bg {
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);*/ box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);*/
} }
.profile-img-custom {
width: 100%;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
.profile-img-card { .profile-img-card {
width: 96px; width: 96px;
height: 96px; height: 96px;

View file

@ -10,13 +10,13 @@
<div class="col-md-1 col-md-push-9" *ngIf="isAdmin"> <div class="col-md-1 col-md-push-9" *ngIf="isAdmin">
<form> <form>
<button style="text-align: right" *ngIf="child.CanApprove" (click)="approve(child)" class="btn btn-sm btn-success-outline" type="submit"><i class="fa fa-plus"></i> Approve</button> <button style="text-align: right" *ngIf="child.canApprove && !child.approved" (click)="approve(child)" class="btn btn-sm btn-success-outline" type="submit"><i class="fa fa-plus"></i> Approve</button>
</form> </form>
<form> <form>
<button type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Deny</button> <button type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Deny</button>
</form> </form>
<form> <form>
<button type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Remove</button> <button type="button" (click)="removeRequest(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Remove</button>
</form> </form>
</div> </div>
</div> </div>

View file

@ -36,6 +36,11 @@ export class TvRequestChildrenComponent {
public approve(request: IChildRequests) { public approve(request: IChildRequests) {
request.approved = true; request.approved = true;
request.denied = false; request.denied = false;
request.seasonRequests.forEach((season) => {
season.episodes.forEach((ep) => {
ep.approved = true;
});
});
this.requestService.updateChild(request) this.requestService.updateChild(request)
.subscribe(); .subscribe();
} }

View file

@ -19,11 +19,6 @@
(scrolled)="loadMore()">--> (scrolled)="loadMore()">-->
<div> <div>
<p-treeTable [value]="tvRequests"> <p-treeTable [value]="tvRequests">
<!--<p-column>
<ng-template let-col let-node="rowData" pTemplate="body">
<img src="{{node.data.data.banner}}" class="img-responsive poster" width="150" />
</ng-template>
</p-column>-->
<p-column> <p-column>
<ng-template let-col let-node="rowData" pTemplate="header"> <ng-template let-col let-node="rowData" pTemplate="header">

View file

@ -1,8 +1,7 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import "rxjs/add/operator/debounceTime"; import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged"; import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map"; import "rxjs/add/operator/map";
import "rxjs/add/operator/takeUntil";
import { Subject } from "rxjs/Subject"; import { Subject } from "rxjs/Subject";
import "rxjs/add/operator/debounceTime"; import "rxjs/add/operator/debounceTime";
@ -13,18 +12,14 @@ import { AuthService } from "../auth/auth.service";
import { RequestService } from "../services"; import { RequestService } from "../services";
import { TreeNode } from "primeng/primeng"; import { TreeNode } from "primeng/primeng";
import { IChildRequests, IEpisodesRequests, INewSeasonRequests, ITvRequests } from "../interfaces"; import { ITvRequests } from "../interfaces";
@Component({ @Component({
selector: "tv-requests", selector: "tv-requests",
templateUrl: "./tvrequests.component.html", templateUrl: "./tvrequests.component.html",
styleUrls: ["./tvrequests.component.scss"], styleUrls: ["./tvrequests.component.scss"],
//Was required to turn off encapsulation since CSS only should be overridden for this component
//However when encapsulation is on angular injects prefixes to all classes so css selectors
//Stop working
encapsulation: ViewEncapsulation.None,
}) })
export class TvRequestsComponent implements OnInit, OnDestroy { export class TvRequestsComponent implements OnInit {
public tvRequests: TreeNode[]; public tvRequests: TreeNode[];
public searchChanged = new Subject<string>(); public searchChanged = new Subject<string>();
@ -35,23 +30,20 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
private currentlyLoaded: number; private currentlyLoaded: number;
private amountToLoad: number; private amountToLoad: number;
private subscriptions = new Subject<void>();
constructor(private requestService: RequestService, constructor(private requestService: RequestService,
private auth: AuthService) { private auth: AuthService) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.resetSearch(); this.resetSearch();
return; return;
} }
this.requestService.searchTvRequests(this.searchText) this.requestService.searchTvRequestsTree(this.searchText)
.takeUntil(this.subscriptions) .subscribe(m => this.tvRequests = m);
.subscribe(m => this.tvRequests = this.transformData(m));
}); });
} }
public openClosestTab(el: any) { public openClosestTab(el: any) {
@ -78,30 +70,7 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
} }
} }
} }
public transformData(data: ITvRequests[]): TreeNode[] {
const temp: TreeNode[] = [];
data.forEach((value) => {
temp.push({
data: value,
children: [{
data: this.fixEpisodeSort(value.childRequests), leaf: true,
}],
leaf: false,
});
}, this);
return <TreeNode[]>temp;
}
public fixEpisodeSort(items: IChildRequests[]) {
items.forEach((value) => {
value.seasonRequests.forEach((requests: INewSeasonRequests) => {
requests.episodes.sort((a: IEpisodesRequests, b: IEpisodesRequests) => {
return a.episodeNumber - b.episodeNumber;
});
});
});
return items;
}
public ngOnInit() { public ngOnInit() {
this.amountToLoad = 1000; this.amountToLoad = 1000;
this.currentlyLoaded = 5; this.currentlyLoaded = 5;
@ -116,10 +85,9 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
//if you scroll really quickly then you start getting duplicates of movies //if you scroll really quickly then you start getting duplicates of movies
//since it's async and some subsequent results return first and then incrementer //since it's async and some subsequent results return first and then incrementer
//is increased so you see movies which had already been gotten show up... //is increased so you see movies which had already been gotten show up...
this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded + 1) this.requestService.getTvRequestsTree(this.amountToLoad, this.currentlyLoaded + 1)
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.tvRequests.push.apply(this.tvRequests, this.transformData(x)); this.tvRequests = x;
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad; this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
}); });
} }
@ -128,87 +96,15 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
this.searchChanged.next(text.target.value); this.searchChanged.next(text.target.value);
} }
public removeRequest(request: ITvRequests) {
this.requestService.removeTvRequest(request);
this.removeRequestFromUi(request);
}
public changeAvailability(request: IChildRequests, available: boolean) {
request.available = available;
//this.updateRequest(request);
}
//Was already here but not sure what's using it...'
//public approve(request: IChildRequests) {
// request.approved = true;
// request.denied = false;
// //this.updateRequest(request);
//}
public approve(request: IChildRequests) {
request.approved = true;
request.denied = false;
this.requestService.updateChild(request)
.subscribe();
}
//Was already here but not sure what's using it...'
//public deny(request: IChildRequests) {
// request.approved = false;
// request.denied = true;
// //this.updateRequest(request);
//}
public deny(request: IChildRequests) {
request.approved = false;
request.denied = true;
this.requestService.updateChild(request)
.subscribe();
}
public approveSeasonRequest(request: IChildRequests) {
request.approved = true;
request.denied = false;
this.requestService.updateTvRequest(this.selectedSeason)
.subscribe();
}
public denySeasonRequest(request: IChildRequests) {
request.approved = false;
request.denied = true;
this.requestService.updateTvRequest(this.selectedSeason)
.subscribe();
}
public showChildren(request: ITvRequests) { public showChildren(request: ITvRequests) {
this.selectedSeason = request; this.selectedSeason = request;
this.showChildDialogue = true; this.showChildDialogue = true;
} }
public getColour(ep: IEpisodesRequests): string {
if (ep.available) {
return "lime";
}
if (ep.approved) {
return "#00c0ff";
}
return "white";
}
public ngOnDestroy() {
this.subscriptions.next();
this.subscriptions.complete();
}
//private updateRequest(request: ITvRequests) {
// this.requestService.updateTvRequest(request)
// .takeUntil(this.subscriptions)
// .subscribe(x => request = x);
//}
private loadInit() { private loadInit() {
this.requestService.getTvRequests(this.amountToLoad, 0) this.requestService.getTvRequestsTree(this.amountToLoad, 0)
.takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.tvRequests = this.transformData(x); this.tvRequests = x;
}); });
} }
@ -216,11 +112,4 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
this.currentlyLoaded = 5; this.currentlyLoaded = 5;
this.loadInit(); this.loadInit();
} }
private removeRequestFromUi(key: ITvRequests) {
const index = this.tvRequests.findIndex(x => x.data === key);
if (index > -1) {
this.tvRequests.splice(index, 1);
}
}
} }

View file

@ -56,13 +56,14 @@
<td> <td>
<ng-template [ngIf]="ep.available"><span class="label label-success">Available</span></ng-template> <ng-template [ngIf]="ep.available"><span class="label label-success">Available</span></ng-template>
<ng-template [ngIf]="ep.approved && !ep.available "><span class="label label-info">Processing Request</span></ng-template> <ng-template [ngIf]="ep.approved && !ep.available "><span class="label label-info">Processing Request</span></ng-template>
<ng-template [ngIf]="ep.requested && !ep.approved && !ep.available"><span class="label label-warning">Pending Approval</span></ng-template> <ng-template [ngIf]="ep.selected"><span class="label label-info">Selected</span></ng-template>
<ng-template [ngIf]="ep.requested && !ep.approved && !ep.available && !ep.selected"><span class="label label-warning">Pending Approval</span></ng-template>
<ng-template [ngIf]="!ep.requested && !ep.available"><span class="label label-danger">Not Requested</span></ng-template> <ng-template [ngIf]="!ep.requested && !ep.available"><span class="label label-danger">Not Requested</span></ng-template>
</td> </td>
<td> <td>
<button *ngIf="!ep.selected" (click)="addRequest(ep)" [disabled]="ep.available || ep.requested || ep.approved" class="btn btn-sm btn-primary-outline">Select</button>
<button (click)="addRequest(ep)" [disabled]="ep.available || ep.requested || ep.approved" class="btn btn-sm btn-primary-outline">Add Request</button> <button *ngIf="ep.selected" (click)="removeRequest(ep)" class="btn btn-sm btn-primary-outline">Unselect</button>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View file

@ -54,10 +54,12 @@ export class SeriesInformationComponent implements OnInit, OnDestroy {
public addRequest(episode: IEpisodesRequests) { public addRequest(episode: IEpisodesRequests) {
episode.requested = true; episode.requested = true;
episode.selected = true;
} }
public removeRequest(episode: IEpisodesRequests) { public removeRequest(episode: IEpisodesRequests) {
episode.requested = false; episode.requested = false;
episode.selected = false;
} }
public ngOnDestroy() { public ngOnDestroy() {

View file

@ -59,7 +59,7 @@
<span *ngIf="node.data.firstAired" class="label label-info" target="_blank">Air Date: {{node.data.firstAired | date: 'dd/MM/yyyy'}}</span> <span *ngIf="node.data.firstAired" class="label label-info" target="_blank">Air Date: {{node.data.firstAired | date: 'dd/MM/yyyy'}}</span>
<ng-template [ngIf]="result.available"><span class="label label-success">Available</span></ng-template> <ng-template [ngIf]="node.data.available"><span class="label label-success">Available</span></ng-template>

View file

@ -3,6 +3,7 @@ import { Http } from "@angular/http";
import { AuthHttp } from "angular2-jwt"; import { AuthHttp } from "angular2-jwt";
import { Observable } from "rxjs/Rx"; import { Observable } from "rxjs/Rx";
import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces"; import { IRequestEngineResult } from "../interfaces";
import { IChildRequests, IMovieRequests, IRequestCountModel, IRequestGrid, ITvRequests } from "../interfaces"; import { IChildRequests, IMovieRequests, IRequestCountModel, IRequestGrid, ITvRequests } from "../interfaces";
import { ISearchMovieResult } from "../interfaces"; import { ISearchMovieResult } from "../interfaces";
@ -44,6 +45,11 @@ export class RequestService extends ServiceAuthHelpers {
.catch(this.handleError); .catch(this.handleError);
} }
public getTvRequestsTree(count: number, position: number): Observable<TreeNode[]> {
return this.http.get(`${this.url}tv/${count}/${position}/tree`).map(this.extractData)
.catch(this.handleError);
}
public getChildRequests(requestId: number): Observable<IChildRequests[]> { public getChildRequests(requestId: number): Observable<IChildRequests[]> {
return this.http.get(`${this.url}tv/${requestId}/child`).map(this.extractData) return this.http.get(`${this.url}tv/${requestId}/child`).map(this.extractData)
.catch(this.handleError); .catch(this.handleError);
@ -53,6 +59,10 @@ export class RequestService extends ServiceAuthHelpers {
return this.http.get(`${this.url}tv/search/${search}`).map(this.extractData); return this.http.get(`${this.url}tv/search/${search}`).map(this.extractData);
} }
public searchTvRequestsTree(search: string): Observable<TreeNode[]> {
return this.http.get(`${this.url}tv/search/${search}/tree`).map(this.extractData);
}
public removeTvRequest(request: ITvRequests) { public removeTvRequest(request: ITvRequests) {
this.http.delete(`${this.url}tv/${request.id}`).map(this.extractData).subscribe(); this.http.delete(`${this.url}tv/${request.id}`).map(this.extractData).subscribe();
} }

View file

@ -76,23 +76,20 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div> <div>
<button id="testPlex" type="submit" (click)="test()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button> <button id="testEmby" type="submit" (click)="test()" class="btn btn-primary-outline">Test Connectivity <div id="spinner"></div></button>
</div> </div>
</div> </div>
</div> </div>
</ng-template> </ng-template>
</ngb-tab> </ngb-tab>
</div> </div>
</ngb-tabset> </ngb-tabset>
<div class="row"> <div class="col-md-12">
<div class="col-md-1 col-md-push-5">
<div class="form-group"> <div class="form-group">
<div> <div>
<button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button> <button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div> </div>
</div> </div>
</div> </div>
</div>
</fieldset> </fieldset>
</div> </div>

View file

@ -58,11 +58,10 @@ export class PushoverComponent implements OnInit {
this.testerService.pushoverTest(form.value).subscribe(x => { this.testerService.pushoverTest(form.value).subscribe(x => {
if (x) { if (x) {
this.notificationService.success("Successful", "Successfully sent a Pushbullet message, please check the discord channel"); this.notificationService.success("Successful", "Successfully sent a Pushover message");
} else { } else {
this.notificationService.success("Error", "There was an error when sending the Pushbullet message. Please check your settings"); this.notificationService.success("Error", "There was an error when sending the Pushover message. Please check your settings");
} }
}); });
} }
} }

View file

@ -36,58 +36,55 @@ namespace Ombi.Controllers
{ {
var model = new MediaSeverAvailibilityViewModel(); var model = new MediaSeverAvailibilityViewModel();
model.ServersAvailable = 3; var plex = await _plexSettings.GetSettingsAsync();
model.ServersUnavailable = 1; if (plex.Enable)
{
foreach (var s in plex.Servers)
{
try
{
var result = await _plexApi.GetStatus(s.PlexAuthToken, s.FullUri);
if (!string.IsNullOrEmpty(result.MediaContainer?.version))
{
model.ServersAvailable++;
}
else
{
model.ServersUnavailable++;
}
}
catch (Exception)
{
model.ServersUnavailable++;
}
}
}
var emby = await _embySettings.GetSettingsAsync();
if (emby.Enable)
{
foreach (var server in emby.Servers)
{
try
{
var result = await _embyApi.GetUsers(server.FullUri, server.ApiKey);
if (result.Any())
{
model.ServersAvailable++;
}
else
{
model.ServersUnavailable++;
}
}
catch (Exception)
{
model.ServersUnavailable++;
}
}
}
return model; return model;
//var plex = await _plexSettings.GetSettingsAsync();
//if (plex.Enable)
//{
// foreach (var s in plex.Servers)
// {
// try
// {
// var result = await _plexApi.GetStatus(s.PlexAuthToken, s.FullUri);
// if (!string.IsNullOrEmpty(result.MediaContainer?.version))
// {
// model.ServersAvailable++;
// }
// else
// {
// model.ServersUnavailable++;
// }
// }
// catch (Exception)
// {
// model.ServersUnavailable++;
// }
// }
//}
//var emby = await _embySettings.GetSettingsAsync();
//if (emby.Enable)
//{
// foreach (var server in emby.Servers)
// {
// try
// {
// var result = await _embyApi.GetUsers(server.FullUri, server.ApiKey);
// if (result.Any())
// {
// model.ServersAvailable++;
// }
// else
// {
// model.ServersUnavailable++;
// }
// }
// catch (Exception)
// {
// model.ServersUnavailable++;
// }
// }
//}
//return model;
} }
} }
} }

View file

@ -89,6 +89,18 @@ namespace Ombi.Controllers
return await MovieRequestEngine.UpdateMovieRequest(model); return await MovieRequestEngine.UpdateMovieRequest(model);
} }
/// <summary>
/// Gets the tv requests.
/// </summary>
/// <param name="count">The count of items you want to return.</param>
/// <param name="position">The position.</param>
/// <returns></returns>
[HttpGet("tv/{count:int}/{position:int}/tree")]
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetTvRequestsTree(int count, int position)
{
return await TvRequestEngine.GetRequestsTreeNode(count, position);
}
/// <summary> /// <summary>
/// Gets the tv requests. /// Gets the tv requests.
/// </summary> /// </summary>
@ -98,17 +110,8 @@ namespace Ombi.Controllers
[HttpGet("tv/{count:int}/{position:int}")] [HttpGet("tv/{count:int}/{position:int}")]
public async Task<IEnumerable<TvRequests>> GetTvRequests(int count, int position) public async Task<IEnumerable<TvRequests>> GetTvRequests(int count, int position)
{ {
try
{
return await TvRequestEngine.GetRequests(count, position); return await TvRequestEngine.GetRequests(count, position);
} }
catch (System.Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
/// <summary> /// <summary>
/// Gets the tv requests. /// Gets the tv requests.
@ -142,6 +145,17 @@ namespace Ombi.Controllers
return await TvRequestEngine.SearchTvRequest(searchTerm); return await TvRequestEngine.SearchTvRequest(searchTerm);
} }
/// <summary>
/// Searches for a specific tv request
/// </summary>
/// <param name="searchTerm">The search term.</param>
/// <returns></returns>
[HttpGet("tv/search/{searchTerm}/tree")]
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvTree(string searchTerm)
{
return await TvRequestEngine.SearchTvRequestTree(searchTerm);
}
/// <summary> /// <summary>
/// Deletes the a specific tv request /// Deletes the a specific tv request
/// </summary> /// </summary>

View file

@ -24,12 +24,16 @@
<ItemGroup> <ItemGroup>
<!-- Files not to show in IDE --> <!-- Files not to show in IDE -->
<Compile Remove="Styles\**" />
<Compile Remove="wwwroot\dist\**" /> <Compile Remove="wwwroot\dist\**" />
<!-- Files not to publish (note that the 'dist' subfolders are re-added below) --> <!-- Files not to publish (note that the 'dist' subfolders are re-added below) -->
<Content Remove="ClientApp\**" /> <Content Remove="ClientApp\**" />
<Content Remove="Styles\**" />
<Content Remove="wwwroot\dist\**" /> <Content Remove="wwwroot\dist\**" />
<EmbeddedResource Remove="Styles\**" />
<EmbeddedResource Remove="wwwroot\dist\**" /> <EmbeddedResource Remove="wwwroot\dist\**" />
<None Remove="Styles\**" />
<None Remove="wwwroot\dist\**" /> <None Remove="wwwroot\dist\**" />
</ItemGroup> </ItemGroup>
@ -77,11 +81,6 @@
<ProjectReference Include="..\Ombi.Updater\Ombi.Updater.csproj" /> <ProjectReference Include="..\Ombi.Updater\Ombi.Updater.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Styles\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="wwwroot\loading.css" /> <None Include="wwwroot\loading.css" />
</ItemGroup> </ItemGroup>

View file

@ -19,11 +19,13 @@ namespace Ombi
int port = 0; int port = 0;
string host = string.Empty; string host = string.Empty;
string storagePath = string.Empty;
Parser.Default.ParseArguments<Options>(args) Parser.Default.ParseArguments<Options>(args)
.WithParsed(o => .WithParsed(o =>
{ {
port = o.Port; port = o.Port;
host = o.Host; host = o.Host;
storagePath = o.StoragePath;
}); });
UrlArgs = $"{host}:{port}"; UrlArgs = $"{host}:{port}";
@ -87,5 +89,10 @@ namespace Ombi
[Option('p', "port", Required = false, HelpText = "The port, default is 5000", Default = 5000)] [Option('p', "port", Required = false, HelpText = "The port, default is 5000", Default = 5000)]
public int Port { get; set; } public int Port { get; set; }
[Option('s', "storage", Required = false, HelpText = "Storage path, where we save the logs and database")]
public string StoragePath { get; set; }
} }
} }