Fixed a bunch of issues on #1513

pull/1514/head
tidusjar 7 years ago
parent 25d8f9b40d
commit 187d76ea77

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

@ -11,4 +11,13 @@ namespace Ombi.Core.Engine
public bool Leaf { 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; }
}
}

@ -37,7 +37,7 @@ namespace Ombi.Core.Engine
private INotificationHelper NotificationHelper { get; }
private ITvMazeApi TvApi { get; }
private IMapper Mapper { get; }
private ITvSender TvSender {get;}
private ITvSender TvSender { get; }
private IAuditRepository Audit { get; }
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
@ -51,7 +51,7 @@ namespace Ombi.Core.Engine
.CreateChild(tv, user.Id);
await tvBuilder.BuildEpisodes(tv);
var ruleResults = await RunRequestRules(tvBuilder.ChildRequest);
var results = ruleResults as RuleResult[] ?? ruleResults.ToArray();
if (results.Any(x => !x.Success))
@ -122,6 +122,12 @@ namespace Ombi.Core.Engine
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()
{
var allRequests = TvRepository.Get();
@ -132,7 +138,7 @@ namespace Ombi.Core.Engine
{
return await TvRepository.GetChild().Where(x => x.ParentRequestId == tvId).ToListAsync();
}
public async Task<IEnumerable<TvRequests>> SearchTvRequest(string search)
{
var allRequests = TvRepository.Get();
@ -140,6 +146,13 @@ namespace Ombi.Core.Engine
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)
{
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
@ -154,7 +167,7 @@ namespace Ombi.Core.Engine
public async Task<ChildRequests> UpdateChildRequest(ChildRequests request)
{
await Audit.Record(AuditType.Updated, AuditArea.TvRequest, $"Updated Request {request.Title}", Username);
await TvRepository.UpdateChild(request);
return request;
}
@ -164,7 +177,7 @@ namespace Ombi.Core.Engine
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId);
var all = TvRepository.Db.TvRequests.Include(x => x.ChildRequests);
var parent = all.FirstOrDefault(x => x.Id == request.ParentRequestId);
// Is this the only child? If so delete the parent
if (parent.ChildRequests.Count <= 1)
{
@ -201,6 +214,41 @@ namespace Ombi.Core.Engine
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)
{
var sendRuleResult = await RunSpecificRule(model, SpecificRules.CanSendNotification);
@ -209,7 +257,7 @@ namespace Ombi.Core.Engine
NotificationHelper.NewRequest(model);
}
if(model.Approved)
if (model.Approved)
{
// Autosend
await TvSender.SendToSonarr(model);
@ -221,8 +269,8 @@ namespace Ombi.Core.Engine
//public async Task<IEnumerable<TvRequests>> GetApprovedRequests()
//{
// var allRequests = TvRepository.Get();
//}
//public async Task<IEnumerable<TvRequests>> GetNewRequests()

@ -19,13 +19,14 @@ using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests;
using Ombi.Store.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace Ombi.Core.Engine
{
public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine
{
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)
{
TvMazeApi = tvMaze;
@ -34,6 +35,7 @@ namespace Ombi.Core.Engine
EmbySettings = embySettings;
PlexContentRepo = repo;
TraktApi = trakt;
EmbyContentRepo = embyRepo;
}
private ITvMazeApi TvMazeApi { get; }
@ -41,6 +43,7 @@ namespace Ombi.Core.Engine
private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<EmbySettings> EmbySettings { get; }
private IPlexContentRepository PlexContentRepo { get; }
private IEmbyContentRepository EmbyContentRepo { get; }
private ITraktApi TraktApi { get; }
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm)
@ -175,11 +178,31 @@ namespace Ombi.Core.Engine
{
if (embySettings.Enable)
{
//var embyShow = EmbyChecker.GetTvShow(embyCached.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId);
//if (embyShow != null)
//{
// viewT.Available = true;
//}
var content = await EmbyContentRepo.Get(item.Id.ToString());
if (content != null)
{
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)
{
@ -190,6 +213,24 @@ namespace Ombi.Core.Engine
item.Available = true;
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)

@ -77,6 +77,12 @@ namespace Ombi.Schedule.Jobs.Emby
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);
if (epInfo?.ProviderIds?.Tvdb == null)
{

@ -108,31 +108,8 @@ namespace Ombi.Schedule.Jobs.Ombi
}
else
{
// Linux
if (desc.Contains("ubuntu", 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;
}
Logger.LogInformation(LoggingEvents.Updater, "We are linux");
download = updates.Downloads.FirstOrDefault(x => x.Name.Contains("linux", CompareOptions.IgnoreCase));
}
if (download == null)
{
@ -201,7 +178,7 @@ namespace Ombi.Schedule.Jobs.Ombi
{
UseShellExecute = false,
CreateNoWindow = true,
FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),"TempUpdate",$"Ombi.Updater{updaterExtension}"),
FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "TempUpdate", $"Ombi.Updater{updaterExtension}"),
Arguments = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + " " + extension
};
using (var proc = new Process { StartInfo = start })
@ -212,7 +189,7 @@ namespace Ombi.Schedule.Jobs.Ombi
}
}
catch (Exception e)
{
{
Ctx.WriteLine(e);
throw;
}

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

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

@ -9,7 +9,7 @@ include the remember me checkbox
<div class="card card-container">
<!-- <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]="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>
<form class="form-signin" novalidate [formGroup]="form" (ngSubmit)="onSubmit(form)">

@ -14,7 +14,6 @@ body, html {
height: 100% !important;
background-repeat: no-repeat !important;
background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33)) !important;
}
landingDiv {
@ -52,138 +51,147 @@ img.bg {
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width:100%;
width: 100%;
}
.btn {
font-weight: 700;
height: 36px;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
cursor: default;
}
/*
.btn {
font-weight: 700;
height: 36px;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
cursor: default;
}
/*
* Card component
*/
.card {
/*background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33)) !important;*/
background-color: $bg-colour;
/* just in case there no content*/
padding: 20px 25px 30px;
margin: 0 auto 25px;
margin-top: 50px;
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
/*-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
.card {
/*background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33)) !important;*/
background-color: $bg-colour;
/* just in case there no content*/
padding: 20px 25px 30px;
margin: 0 auto 25px;
margin-top: 50px;
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
/*-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);*/
}
.profile-img-card {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
/*
}
.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 {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
/*
* Form styles
*/
.profile-name-card {
font-size: 16px;
font-weight: bold;
text-align: center;
margin: 10px 0 0;
min-height: 1em;
}
.form-control {
color: black;
background-color: white !important;
}
.reauth-email {
display: block;
color: white;
line-height: 2;
margin-bottom: 10px;
font-size: 14px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.form-signin #inputEmail,
.form-signin #inputPassword {
direction: ltr;
height: 44px;
font-size: 16px;
}
.form-signin input[type=email],
.form-signin input[type=password],
.form-signin input[type=text],
.form-signin button {
width: 100%;
display: block;
margin-bottom: 10px;
z-index: 1;
position: relative;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.btn.btn-signin {
/*background-color: #4d90fe; */
background-color: rgb(104, 145, 162);
/* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/
padding: 0px;
font-weight: 700;
font-size: 14px;
height: 36px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
border: none;
-o-transition: all 0.218s;
-moz-transition: all 0.218s;
-webkit-transition: all 0.218s;
transition: all 0.218s;
}
.btn.btn-signin:hover,
.btn.btn-signin:active,
.btn.btn-signin:focus {
background-color: rgb(12, 97, 33);
}
.forgot-password {
color: rgb(104, 145, 162);
text-align:center;
}
.forgot-password:hover,
.forgot-password:active,
.forgot-password:focus {
color: rgb(12, 97, 33);
}
// Placeholders
.profile-name-card {
font-size: 16px;
font-weight: bold;
text-align: center;
margin: 10px 0 0;
min-height: 1em;
}
.form-control {
color: black;
background-color: white !important;
}
.reauth-email {
display: block;
color: white;
line-height: 2;
margin-bottom: 10px;
font-size: 14px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.form-signin #inputEmail,
.form-signin #inputPassword {
direction: ltr;
height: 44px;
font-size: 16px;
}
.form-signin input[type=email],
.form-signin input[type=password],
.form-signin input[type=text],
.form-signin button {
width: 100%;
display: block;
margin-bottom: 10px;
z-index: 1;
position: relative;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.btn.btn-signin {
/*background-color: #4d90fe; */
background-color: rgb(104, 145, 162);
/* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/
padding: 0px;
font-weight: 700;
font-size: 14px;
height: 36px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
border: none;
-o-transition: all 0.218s;
-moz-transition: all 0.218s;
-webkit-transition: all 0.218s;
transition: all 0.218s;
}
.btn.btn-signin:hover,
.btn.btn-signin:active,
.btn.btn-signin:focus {
background-color: rgb(12, 97, 33);
}
.forgot-password {
color: rgb(104, 145, 162);
text-align: center;
}
.forgot-password:hover,
.forgot-password:active,
.forgot-password:focus {
color: rgb(12, 97, 33);
}
// Placeholders
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color: $placeholder-colour;
@ -205,4 +213,4 @@ img.bg {
::-ms-input-placeholder { /* Microsoft Edge */
color: $placeholder-colour;
}
}

@ -10,13 +10,13 @@
<div class="col-md-1 col-md-push-9" *ngIf="isAdmin">
<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>
<button type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny"><i class="fa fa-times"></i> Deny</button>
</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>
</div>
</div>
@ -68,7 +68,7 @@
<span *ngIf="ep.available" class="label label-success">Available</span>
<span *ngIf="ep.approved && !ep.available" class="label label-info">Processing Request</span>
<div *ngIf="!ep.approved">
<div *ngIf="!ep.available"><span class="label label-warning">Pending Approval</span></div>
<div *ngIf="!ep.available"><span class="label label-warning">Pending Approval</span></div>
</div>
</td>
</tr>

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

@ -19,11 +19,6 @@
(scrolled)="loadMore()">-->
<div>
<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>
<ng-template let-col let-node="rowData" pTemplate="header">
@ -63,7 +58,7 @@
</div>
<!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf">
<tvrequests-children [childRequests]="node.data" [isAdmin] ="isAdmin"></tvrequests-children>
<tvrequests-children [childRequests]="node.data" [isAdmin] ="isAdmin" ></tvrequests-children>
</div>
</ng-template>
</p-column>

@ -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/distinctUntilChanged";
import "rxjs/add/operator/map";
import "rxjs/add/operator/takeUntil";
import { Subject } from "rxjs/Subject";
import "rxjs/add/operator/debounceTime";
@ -13,18 +12,14 @@ import { AuthService } from "../auth/auth.service";
import { RequestService } from "../services";
import { TreeNode } from "primeng/primeng";
import { IChildRequests, IEpisodesRequests, INewSeasonRequests, ITvRequests } from "../interfaces";
import { ITvRequests } from "../interfaces";
@Component({
selector: "tv-requests",
templateUrl: "./tvrequests.component.html",
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 searchChanged = new Subject<string>();
@ -35,23 +30,20 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
private currentlyLoaded: number;
private amountToLoad: number;
private subscriptions = new Subject<void>();
constructor(private requestService: RequestService,
private auth: AuthService) {
this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.takeUntil(this.subscriptions)
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.resetSearch();
return;
}
this.requestService.searchTvRequests(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(m => this.tvRequests = this.transformData(m));
this.requestService.searchTvRequestsTree(this.searchText)
.subscribe(m => this.tvRequests = m);
});
}
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() {
this.amountToLoad = 1000;
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
//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...
this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded + 1)
.takeUntil(this.subscriptions)
this.requestService.getTvRequestsTree(this.amountToLoad, this.currentlyLoaded + 1)
.subscribe(x => {
this.tvRequests.push.apply(this.tvRequests, this.transformData(x));
this.tvRequests = x;
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
});
}
@ -128,87 +96,15 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
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) {
this.selectedSeason = request;
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() {
this.requestService.getTvRequests(this.amountToLoad, 0)
.takeUntil(this.subscriptions)
this.requestService.getTvRequestsTree(this.amountToLoad, 0)
.subscribe(x => {
this.tvRequests = this.transformData(x);
this.tvRequests = x;
});
}
@ -216,11 +112,4 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
this.currentlyLoaded = 5;
this.loadInit();
}
private removeRequestFromUi(key: ITvRequests) {
const index = this.tvRequests.findIndex(x => x.data === key);
if (index > -1) {
this.tvRequests.splice(index, 1);
}
}
}

@ -55,14 +55,15 @@
</td>
<td>
<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.requested && !ep.approved && !ep.available"><span class="label label-warning">Pending Approval</span></ng-template>
<ng-template [ngIf]="ep.approved && !ep.available "><span class="label label-info">Processing Request</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>
</td>
<td>
<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)="addRequest(ep)" [disabled]="ep.available || ep.requested || ep.approved" class="btn btn-sm btn-primary-outline">Select</button>
<button *ngIf="ep.selected" (click)="removeRequest(ep)" class="btn btn-sm btn-primary-outline">Unselect</button>
</td>
</tr>
</tbody>

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

@ -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>
<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>

@ -3,6 +3,7 @@ import { Http } from "@angular/http";
import { AuthHttp } from "angular2-jwt";
import { Observable } from "rxjs/Rx";
import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces";
import { IChildRequests, IMovieRequests, IRequestCountModel, IRequestGrid, ITvRequests } from "../interfaces";
import { ISearchMovieResult } from "../interfaces";
@ -44,6 +45,11 @@ export class RequestService extends ServiceAuthHelpers {
.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[]> {
return this.http.get(`${this.url}tv/${requestId}/child`).map(this.extractData)
.catch(this.handleError);
@ -51,6 +57,10 @@ export class RequestService extends ServiceAuthHelpers {
public searchTvRequests(search: string): Observable<ITvRequests[]> {
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) {

@ -24,7 +24,7 @@
<ng-template ngbTabContent>
<br />
<br />
<div class="col-md-2 " style="float: right;">
<div class="col-md-2" style="float: right;">
<button type="submit" (click)="removeServer(server)" class="btn btn-danger-outline">Remove Server</button>
</div>
<br />
@ -76,23 +76,20 @@
</div>
<div class="form-group">
<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>
</ng-template>
</ngb-tab>
</div>
</ngb-tabset>
<div class="row">
<div class="col-md-1 col-md-push-5">
<div class="col-md-12">
<div class="form-group">
<div>
<button (click)="save()" type="submit" id="save" class="btn btn-primary-outline">Submit</button>
</div>
</div>
</div>
</div>
</fieldset>
</div>

@ -58,11 +58,10 @@ export class PushoverComponent implements OnInit {
this.testerService.pushoverTest(form.value).subscribe(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 {
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");
}
});
}
}

@ -36,58 +36,55 @@ namespace Ombi.Controllers
{
var model = new MediaSeverAvailibilityViewModel();
model.ServersAvailable = 3;
model.ServersUnavailable = 1;
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 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;
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;
}
}
}

@ -89,6 +89,18 @@ namespace Ombi.Controllers
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>
/// Gets the tv requests.
/// </summary>
@ -98,16 +110,7 @@ namespace Ombi.Controllers
[HttpGet("tv/{count:int}/{position:int}")]
public async Task<IEnumerable<TvRequests>> GetTvRequests(int count, int position)
{
try
{
return await TvRequestEngine.GetRequests(count, position);
}
catch (System.Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
return await TvRequestEngine.GetRequests(count, position);
}
/// <summary>
@ -142,6 +145,17 @@ namespace Ombi.Controllers
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>
/// Deletes the a specific tv request
/// </summary>

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

@ -19,11 +19,13 @@ namespace Ombi
int port = 0;
string host = string.Empty;
string storagePath = string.Empty;
Parser.Default.ParseArguments<Options>(args)
.WithParsed(o =>
{
port = o.Port;
host = o.Host;
storagePath = o.StoragePath;
});
UrlArgs = $"{host}:{port}";
@ -46,7 +48,7 @@ namespace Ombi
Type = ConfigurationTypes.Port,
Value = "5000"
};
ctx.ApplicationConfigurations.Add(url);
ctx.ApplicationConfigurations.Add(dbPort);
ctx.SaveChanges();
@ -87,5 +89,10 @@ namespace Ombi
[Option('p', "port", Required = false, HelpText = "The port, default is 5000", Default = 5000)]
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; }
}
}

Loading…
Cancel
Save