mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -07:00
Merge branch 'feature/v4' of https://github.com/tidusjar/Ombi into feature/v4
This commit is contained in:
commit
a7f747cf46
24 changed files with 565 additions and 54 deletions
|
@ -23,5 +23,7 @@ namespace Ombi.Core.Engine
|
||||||
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
|
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
|
||||||
Task<bool> UserHasRequest(string userId);
|
Task<bool> UserHasRequest(string userId);
|
||||||
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||||
|
Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count, int position, string sort, string sortOrder, RequestStatus available);
|
||||||
|
Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sort, string sortOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@ using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Settings.Settings.Models.External;
|
using Ombi.Settings.Settings.Models.External;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -253,6 +254,28 @@ namespace Ombi.Core.Engine
|
||||||
return allRequests;
|
return allRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task CheckForSubscription(HideResult shouldHide, List<AlbumRequest> albumRequests)
|
||||||
|
{
|
||||||
|
var requestIds = albumRequests.Select(x => x.Id);
|
||||||
|
var sub = await _subscriptionRepository.GetAll().Where(s =>
|
||||||
|
s.UserId == shouldHide.UserId && requestIds.Contains(s.RequestId) && s.RequestType == RequestType.Movie)
|
||||||
|
.ToListAsync();
|
||||||
|
foreach (var x in albumRequests)
|
||||||
|
{
|
||||||
|
if (shouldHide.UserId == x.RequestedUserId)
|
||||||
|
{
|
||||||
|
x.ShowSubscribe = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x.ShowSubscribe = true;
|
||||||
|
var hasSub = sub.FirstOrDefault(r => r.RequestId == x.Id);
|
||||||
|
x.Subscribed = hasSub != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CheckForSubscription(HideResult shouldHide, AlbumRequest x)
|
private async Task CheckForSubscription(HideResult shouldHide, AlbumRequest x)
|
||||||
{
|
{
|
||||||
if (shouldHide.UserId == x.RequestedUserId)
|
if (shouldHide.UserId == x.RequestedUserId)
|
||||||
|
@ -500,6 +523,110 @@ namespace Ombi.Core.Engine
|
||||||
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!", RequestId = model.Id };
|
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!", RequestId = model.Id };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<AlbumRequest> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository.GetWithUser(shouldHide
|
||||||
|
.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository
|
||||||
|
.GetWithUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case RequestStatus.PendingApproval:
|
||||||
|
allRequests = allRequests.Where(x => !x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value));
|
||||||
|
break;
|
||||||
|
case RequestStatus.ProcessingRequest:
|
||||||
|
allRequests = allRequests.Where(x => x.Approved && !x.Available && (!x.Denied.HasValue || !x.Denied.Value));
|
||||||
|
break;
|
||||||
|
case RequestStatus.Available:
|
||||||
|
allRequests = allRequests.Where(x => x.Available);
|
||||||
|
break;
|
||||||
|
case RequestStatus.Denied:
|
||||||
|
allRequests = allRequests.Where(x => x.Denied.HasValue && x.Denied.Value && !x.Available);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find(sortProperty, true);
|
||||||
|
|
||||||
|
if (sortProperty.Contains('.'))
|
||||||
|
{
|
||||||
|
// This is a navigation property currently not supported
|
||||||
|
prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find("RequestedDate", true);
|
||||||
|
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||||
|
//var propType = firstProp.PropertyType;
|
||||||
|
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO fix this so we execute this on the server
|
||||||
|
var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
? allRequests.ToList().OrderBy(x => x.RequestedDate).ToList()
|
||||||
|
: allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList();
|
||||||
|
var total = requests.Count();
|
||||||
|
requests = requests.Skip(position).Take(count).ToList();
|
||||||
|
|
||||||
|
await CheckForSubscription(shouldHide, requests);
|
||||||
|
return new RequestsViewModel<AlbumRequest>
|
||||||
|
{
|
||||||
|
Collection = requests,
|
||||||
|
Total = total
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||||
|
{
|
||||||
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<AlbumRequest> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository.GetWithUser(shouldHide
|
||||||
|
.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests =
|
||||||
|
MusicRepository
|
||||||
|
.GetWithUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
var prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(sortProperty, true);
|
||||||
|
|
||||||
|
if (sortProperty.Contains('.'))
|
||||||
|
{
|
||||||
|
// This is a navigation property currently not supported
|
||||||
|
prop = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find("RequestedDate", true);
|
||||||
|
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||||
|
//var propType = firstProp.PropertyType;
|
||||||
|
//var secondProp = TypeDescriptor.GetProperties(propType).Find(properties[1], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO fix this so we execute this on the server
|
||||||
|
var requests = sortOrder.Equals("asc", StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
? allRequests.ToList().OrderBy(x => x.RequestedDate).ToList()
|
||||||
|
: allRequests.ToList().OrderByDescending(x => prop.GetValue(x)).ToList();
|
||||||
|
var total = requests.Count();
|
||||||
|
requests = requests.Skip(position).Take(count).ToList();
|
||||||
|
|
||||||
|
await CheckForSubscription(shouldHide, requests);
|
||||||
|
return new RequestsViewModel<AlbumRequest>
|
||||||
|
{
|
||||||
|
Collection = requests,
|
||||||
|
Total = total
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -81,7 +81,7 @@ namespace Ombi.Core.Engine.V2
|
||||||
|
|
||||||
var mapped = Mapper.Map<SearchFullInfoTvShowViewModel>(show);
|
var mapped = Mapper.Map<SearchFullInfoTvShowViewModel>(show);
|
||||||
|
|
||||||
foreach (var e in show._embedded.episodes)
|
foreach (var e in show._embedded?.episodes ?? new Api.TvMaze.Models.V2.Episode[0])
|
||||||
{
|
{
|
||||||
var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
|
var season = mapped.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == e.season);
|
||||||
if (season == null)
|
if (season == null)
|
||||||
|
|
|
@ -17,5 +17,34 @@ namespace Ombi.Store.Entities.Requests
|
||||||
public bool Subscribed { get; set; }
|
public bool Subscribed { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool ShowSubscribe { get; set; }
|
public bool ShowSubscribe { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string RequestStatus {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Available)
|
||||||
|
{
|
||||||
|
return "Common.Available";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Denied ?? false)
|
||||||
|
{
|
||||||
|
return "Common.Denied";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Approved & !Available)
|
||||||
|
{
|
||||||
|
return "Common.ProcessingRequest";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Approved && !Available)
|
||||||
|
{
|
||||||
|
return "Common.PendingApproval";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
<div *ngIf="movie && radarrEnabled" class="text-center">
|
<div *ngIf="movie && radarrEnabled" class="text-center">
|
||||||
<button mat-raised-button color="warn" class="text-center" (click)="openAdvancedOptions();">Advanced Options</button>
|
<button mat-raised-button color="warn" class="text-center" (click)="openAdvancedOptions();">{{'MediaDetails.AdvancedOptions' | translate }}</button>
|
||||||
</div>
|
</div>
|
|
@ -3,7 +3,7 @@
|
||||||
Advanced Options</h1>
|
Advanced Options</h1>
|
||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Radarr Quality Profile</mat-label>
|
<mat-label>{{'MediaDetails.RadarrProfile' | translate }}</mat-label>
|
||||||
<mat-select [(value)]="data.profileId">
|
<mat-select [(value)]="data.profileId">
|
||||||
<mat-option *ngFor="let profile of data.profiles" value="{{profile.id}}">{{profile.name}}</mat-option>
|
<mat-option *ngFor="let profile of data.profiles" value="{{profile.id}}">{{profile.name}}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-content>
|
<div mat-dialog-content>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Radarr Root Folders</mat-label>
|
<mat-label>{{'MediaDetails.RadarrFolder' | translate }}</mat-label>
|
||||||
<mat-select [(value)]="data.rootFolderId">
|
<mat-select [(value)]="data.rootFolderId">
|
||||||
<mat-option *ngFor="let profile of data.rootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
|
<mat-option *ngFor="let profile of data.rootFolders" value="{{profile.id}}">{{profile.path}}</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<div *ngIf="movie">
|
<div *ngIf="movie">
|
||||||
<div>
|
<div>
|
||||||
<strong>Status:</strong>
|
<strong>{{'MediaDetails.Status' | translate }}:</strong>
|
||||||
<div>{{movie.status}}</div>
|
<div>{{movie.status}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Availability</strong>
|
<strong>{{'MediaDetails.Availability' | translate }}</strong>
|
||||||
<div *ngIf="movie.available">{{'Common.Available' | translate}}</div>
|
<div *ngIf="movie.available">{{'Common.Available' | translate}}</div>
|
||||||
<div *ngIf="!movie.available">{{'Common.NotAvailable' | translate}}</div>
|
<div *ngIf="!movie.available">{{'Common.NotAvailable' | translate}}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<strong>Request Status</strong>
|
<strong>{{'MediaDetails.RequestStatus' | translate }}</strong>
|
||||||
<div *ngIf="movie.approved && !movie.available">{{'Common.ProcessingRequest' | translate}}</div>
|
<div *ngIf="movie.approved && !movie.available">{{'Common.ProcessingRequest' | translate}}</div>
|
||||||
<div *ngIf="movie.requested && !movie.approved && !movie.available">{{'Common.PendingApproval' | translate}}
|
<div *ngIf="movie.requested && !movie.approved && !movie.available">{{'Common.PendingApproval' | translate}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,21 +19,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="movie.quality">
|
<div *ngIf="movie.quality">
|
||||||
<strong>Quality:</strong>
|
<strong>{{'MediaDetails.Quality' | translate }}:</strong>
|
||||||
<div>{{movie.quality | quality}}</div>
|
<div>{{movie.quality | quality}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="advancedOptions">
|
<div *ngIf="advancedOptions">
|
||||||
<strong>Root Folder Override</strong>
|
<strong>{{'MediaDetails.RootFolderOverride' | translate }}</strong>
|
||||||
<div>{{advancedOptions.rootFolder.path}}</div>
|
<div>{{advancedOptions.rootFolder.path}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="advancedOptions">
|
<div *ngIf="advancedOptions">
|
||||||
<strong>Quality Override</strong>
|
<strong>{{'MediaDetails.QualityOverride' | translate }}</strong>
|
||||||
<div>{{advancedOptions.profile.name}}</div>
|
<div>{{advancedOptions.profile.name}}</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div *ngIf="movie.genres">
|
<div *ngIf="movie.genres">
|
||||||
<strong>Genres:</strong>
|
<strong>{{'MediaDetails.Genres' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
<mat-chip-list>
|
<mat-chip-list>
|
||||||
<mat-chip color="accent" selected *ngFor="let genre of movie.genres">
|
<mat-chip color="accent" selected *ngFor="let genre of movie.genres">
|
||||||
|
@ -44,45 +44,45 @@
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<strong>Theatrical Release:</strong>
|
<strong>{{'MediaDetails.TheatricalRelease' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
{{movie.releaseDate | date: 'mediumDate'}}
|
{{movie.releaseDate | date: 'mediumDate'}}
|
||||||
<div *ngIf="movie.digitalReleaseDate">
|
<div *ngIf="movie.digitalReleaseDate">
|
||||||
<strong>Digital Release:</strong>
|
<strong>{{'MediaDetails.DigitalRelease' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
{{movie.digitalReleaseDate | date: 'mediumDate'}}
|
{{movie.digitalReleaseDate | date: 'mediumDate'}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="movie.voteAverage">
|
<div *ngIf="movie.voteAverage">
|
||||||
<strong>User Score:</strong>
|
<strong>{{'MediaDetails.UserScore' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
{{movie.voteAverage | number:'1.0-1'}} / 10
|
{{movie.voteAverage | number:'1.0-1'}} / 10
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="movie.voteCount">
|
<div *ngIf="movie.voteCount">
|
||||||
<strong>Votes:</strong>
|
<strong>{{'MediaDetails.Votes' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
{{movie.voteCount | thousandShort: 1}}
|
{{movie.voteCount | thousandShort: 1}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Runtime:</strong>
|
<strong>{{'MediaDetails.Runtime' | translate }}:</strong>
|
||||||
<div>{{movie.runtime}} Minutes</div>
|
<div>{{'MediaDetails.Minutes' | translate:{runtime: movie.runtime} }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="movie.revenue">
|
<div *ngIf="movie.revenue">
|
||||||
<strong>Revenue:</strong>
|
<strong>{{'MediaDetails.Revenue' | translate }}:</strong>
|
||||||
<div> {{movie.revenue | currency: 'USD'}}</div>
|
<div> {{movie.revenue | currency: 'USD'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="movie.budget">
|
<div *ngIf="movie.budget">
|
||||||
<strong>Budget:</strong>
|
<strong>{{'MediaDetails.Budget' | translate }}:</strong>
|
||||||
<div> {{movie.budget | currency: 'USD'}}</div>
|
<div> {{movie.budget | currency: 'USD'}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<strong>Keywords/Tags:</strong>
|
<strong>{{'MediaDetails.Keywords' | translate }}:</strong>
|
||||||
<mat-chip-list>
|
<mat-chip-list>
|
||||||
<mat-chip color="accent" selected *ngFor="let keyword of movie.keywords.keywordsValue">
|
<mat-chip color="accent" selected *ngFor="let keyword of movie.keywords.keywordsValue">
|
||||||
{{keyword.name}}
|
{{keyword.name}}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div>
|
<div>
|
||||||
<div *ngIf="tv.status">
|
<div *ngIf="tv.status">
|
||||||
<strong>Status:</strong>
|
<strong>{{'MediaDetails.Status' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
{{tv.status}}
|
{{tv.status}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,15 +13,9 @@
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<strong>Status:</strong>
|
<strong>{{'MediaDetails.Runtime' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
{{tv.status}}
|
{{'MediaDetails.Minutes' | translate:{ runtime: tv.runtime} }}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<strong>Runtime:</strong>
|
|
||||||
<div>
|
|
||||||
{{tv.runtime}} Minutes
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="tv.rating">
|
<div *ngIf="tv.rating">
|
||||||
|
@ -38,7 +32,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="tv.genre">
|
<div *ngIf="tv.genre">
|
||||||
<strong>Genres:</strong>
|
<strong>{{'MediaDetails.Genres' | translate }}:</strong>
|
||||||
<div>
|
<div>
|
||||||
<span *ngFor="let genre of tv.genre">
|
<span *ngFor="let genre of tv.genre">
|
||||||
{{genre}} |
|
{{genre}} |
|
||||||
|
|
|
@ -2,6 +2,16 @@
|
||||||
<mat-spinner [color]="'accent'"></mat-spinner>
|
<mat-spinner [color]="'accent'"></mat-spinner>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="tv">
|
<div *ngIf="tv">
|
||||||
|
<div *ngIf="tv.id === 0; else main">
|
||||||
|
<div class="small-middle-container no-info">
|
||||||
|
<h1><i class="fa fa-frown-o" aria-hidden="true"></i></h1><h3> {{ 'MediaDetails.NotEnoughInfo' | translate }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<ng-template #main>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
<top-banner [background]="tv.background" [available]="tv.available" [title]="tv.title" [releaseDate]="tv.firstAired" [tagline]="tv.certification"></top-banner>
|
<top-banner [background]="tv.background" [available]="tv.available" [title]="tv.title" [releaseDate]="tv.firstAired" [tagline]="tv.certification"></top-banner>
|
||||||
|
|
||||||
|
@ -9,7 +19,7 @@
|
||||||
<div class="small-middle-container">
|
<div class="small-middle-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<media-poster [posterPath]="tv.images.medium"></media-poster>
|
<media-poster [posterPath]="tv.images?.medium"></media-poster>
|
||||||
|
|
||||||
<!--Next to poster-->
|
<!--Next to poster-->
|
||||||
<div class="col-12 col-lg-3 col-xl-3 media-row">
|
<div class="col-12 col-lg-3 col-xl-3 media-row">
|
||||||
|
@ -108,3 +118,5 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
|
@ -215,3 +215,8 @@
|
||||||
padding-top: 1%;
|
padding-top: 1%;
|
||||||
padding-bottom: 1%;
|
padding-bottom: 1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-info {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 15%;
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<grid-spinner [loading]="isLoadingResults"></grid-spinner>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <div class="row"> -->
|
||||||
|
<div class="row justify-content-md-center top-spacing">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.All)" [attr.color]="currentFilter === RequestFilter.All ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.All ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.AllRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Pending)" [attr.color]="currentFilter === RequestFilter.Pending ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Pending ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.PendingRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Processing)" [attr.color]="currentFilter === RequestFilter.Processing ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Processing ? 'mat-accent' : 'mat-primary'" mat-raised-button
|
||||||
|
class="btn grow">{{'Requests.ProcessingRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Available)" [attr.color]="currentFilter === RequestFilter.Available ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Available ? 'mat-accent' : 'mat-primary'" mat-raised-button
|
||||||
|
class="btn grow">{{'Requests.AvailableRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Denied)" [attr.color]="currentFilter === RequestFilter.Denied ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Denied ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.DeniedRequests' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2 offset-md-10">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-select placeholder="{{'Requests.RequestsToDisplay' | translate}}" [(value)]="gridCount" (selectionChange)="ngAfterViewInit()">
|
||||||
|
<mat-option value="10">10</mat-option>
|
||||||
|
<mat-option value="15">15</mat-option>
|
||||||
|
<mat-option value="30">30</mat-option>
|
||||||
|
<mat-option value="100">100</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- </div> -->
|
||||||
|
<table mat-table [dataSource]="dataSource" class="table" matSort [matSortActive]="defaultSort" matSortDisableClear [matSortDirection]="defaultOrder">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ng-container matColumnDef="artistName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.ArtistName' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.artistName}} </td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="title">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.AlbumName' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.title}} ({{element.releaseDate | amLocal | amDateFormat: 'YYYY'}}) </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestedUser.requestedBy">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'Requests.RequestedBy' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestedUser?.userAlias}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestedDate">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestDate' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestedDate | amLocal | amDateFormat: 'LL'}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestStatus">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestStatus' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestStatus | translate}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-raised-button color="accent" [routerLink]="'/details/artist/' + element.foreignArtistId">{{ 'Requests.Details' | translate}}</button>
|
||||||
|
<button mat-raised-button color="warn" (click)="openOptions(element)" *ngIf="isAdmin"> {{ 'Requests.Options' | translate}}</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [length]="resultsLength" [pageSize]="gridCount"></mat-paginator>
|
||||||
|
</div>
|
|
@ -0,0 +1,49 @@
|
||||||
|
@import "~styles/variables.scss";
|
||||||
|
|
||||||
|
.dark .mat-header-cell {
|
||||||
|
background: $accent-dark !important;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #303030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-form-field {
|
||||||
|
float:right;
|
||||||
|
margin-right:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*::ng-deep .dark .mat-form-field-label{
|
||||||
|
font-size: 1.2em;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
::ng-deep .mat-form-field-infix {
|
||||||
|
width: 8em;
|
||||||
|
margin-top:1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .dark .mat-tab-label-active{
|
||||||
|
background: $accent-dark !important;
|
||||||
|
color: #303030 !important;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-tab-label{
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .row {
|
||||||
|
margin-right:0;
|
||||||
|
margin-left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: normal !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1170px){
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
import { Component, AfterViewInit, ViewChild, EventEmitter, Output, ChangeDetectorRef, OnInit } from "@angular/core";
|
||||||
|
import { IRequestsViewModel, IAlbumRequest } from "../../../interfaces";
|
||||||
|
import { MatPaginator } from "@angular/material/paginator";
|
||||||
|
import { MatSort } from "@angular/material/sort";
|
||||||
|
import { merge, Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { RequestServiceV2 } from "../../../services/requestV2.service";
|
||||||
|
import { AuthService } from "../../../auth/auth.service";
|
||||||
|
import { StorageService } from "../../../shared/storage/storage-service";
|
||||||
|
import { RequestFilterType } from "../../models/RequestFilterType";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./albums-grid.component.html",
|
||||||
|
selector: "albums-grid",
|
||||||
|
styleUrls: ["./albums-grid.component.scss"]
|
||||||
|
})
|
||||||
|
export class AlbumsGridComponent implements OnInit, AfterViewInit {
|
||||||
|
public dataSource: IAlbumRequest[] = [];
|
||||||
|
public resultsLength: number;
|
||||||
|
public isLoadingResults = true;
|
||||||
|
public displayedColumns: string[] = ['artistName', 'title', 'requestedUser.requestedBy', 'requestStatus','requestedDate', 'actions'];
|
||||||
|
public gridCount: string = "15";
|
||||||
|
public isAdmin: boolean;
|
||||||
|
public defaultSort: string = "requestedDate";
|
||||||
|
public defaultOrder: string = "desc";
|
||||||
|
public currentFilter: RequestFilterType = RequestFilterType.All;
|
||||||
|
|
||||||
|
public RequestFilter = RequestFilterType;
|
||||||
|
|
||||||
|
|
||||||
|
private storageKey = "Albums_DefaultRequestListSort";
|
||||||
|
private storageKeyOrder = "Albums_DefaultRequestListSortOrder";
|
||||||
|
private storageKeyGridCount = "Albums_DefaultGridCount";
|
||||||
|
private storageKeyCurrentFilter = "Albums_DefaultFilter";
|
||||||
|
|
||||||
|
@Output() public onOpenOptions = new EventEmitter<{ request: any, filter: any, onChange: any }>();
|
||||||
|
|
||||||
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
|
constructor(private requestService: RequestServiceV2, private ref: ChangeDetectorRef,
|
||||||
|
private auth: AuthService, private storageService: StorageService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnInit() {
|
||||||
|
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
|
||||||
|
|
||||||
|
const defaultCount = this.storageService.get(this.storageKeyGridCount);
|
||||||
|
const defaultSort = this.storageService.get(this.storageKey);
|
||||||
|
const defaultOrder = this.storageService.get(this.storageKeyOrder);
|
||||||
|
const defaultFilter = +this.storageService.get(this.storageKeyCurrentFilter);
|
||||||
|
if (defaultSort) {
|
||||||
|
this.defaultSort = defaultSort;
|
||||||
|
}
|
||||||
|
if (defaultOrder) {
|
||||||
|
this.defaultOrder = defaultOrder;
|
||||||
|
}
|
||||||
|
if (defaultCount) {
|
||||||
|
this.gridCount = defaultCount;
|
||||||
|
}
|
||||||
|
if (defaultFilter) {
|
||||||
|
this.currentFilter = defaultFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ngAfterViewInit() {
|
||||||
|
|
||||||
|
this.storageService.save(this.storageKeyGridCount, this.gridCount);
|
||||||
|
this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString());
|
||||||
|
|
||||||
|
// If the user changes the sort order, reset back to the first page.
|
||||||
|
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
||||||
|
this.paginator.showFirstLastButtons = true;
|
||||||
|
|
||||||
|
merge(this.sort.sortChange, this.paginator.page, this.currentFilter)
|
||||||
|
.pipe(
|
||||||
|
startWith({}),
|
||||||
|
switchMap((value: any) => {
|
||||||
|
this.isLoadingResults = true;
|
||||||
|
if (value.active || value.direction) {
|
||||||
|
this.storageService.save(this.storageKey, value.active);
|
||||||
|
this.storageService.save(this.storageKeyOrder, value.direction);
|
||||||
|
}
|
||||||
|
return this.loadData();
|
||||||
|
}),
|
||||||
|
map((data: IRequestsViewModel<IAlbumRequest>) => {
|
||||||
|
// Flip flag to show that loading has finished.
|
||||||
|
this.isLoadingResults = false;
|
||||||
|
this.resultsLength = data.total;
|
||||||
|
|
||||||
|
return data.collection;
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
this.isLoadingResults = false;
|
||||||
|
return observableOf([]);
|
||||||
|
})
|
||||||
|
).subscribe(data => this.dataSource = data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadData(): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
switch(RequestFilterType[RequestFilterType[this.currentFilter]]) {
|
||||||
|
case RequestFilterType.All:
|
||||||
|
return this.requestService.getAlbumRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Pending:
|
||||||
|
return this.requestService.getAlbumPendingRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Available:
|
||||||
|
return this.requestService.getAlbumAvailableRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Processing:
|
||||||
|
return this.requestService.getAlbumProcessingRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Denied:
|
||||||
|
return this.requestService.getAlbumDeniedRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public openOptions(request: IAlbumRequest) {
|
||||||
|
const filter = () => {
|
||||||
|
this.dataSource = this.dataSource.filter((req) => {
|
||||||
|
return req.id !== request.id;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = () => {
|
||||||
|
this.ref.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onOpenOptions.emit({ request: request, filter: filter, onChange: onChange });
|
||||||
|
}
|
||||||
|
|
||||||
|
public switchFilter(type: RequestFilterType) {
|
||||||
|
this.currentFilter = type;
|
||||||
|
this.ngAfterViewInit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,15 @@ import { RequestService } from "../../services";
|
||||||
import { TvGridComponent } from "./tv-grid/tv-grid.component";
|
import { TvGridComponent } from "./tv-grid/tv-grid.component";
|
||||||
import { GridSpinnerComponent } from "./grid-spinner/grid-spinner.component";
|
import { GridSpinnerComponent } from "./grid-spinner/grid-spinner.component";
|
||||||
import { RequestOptionsComponent } from "./options/request-options.component";
|
import { RequestOptionsComponent } from "./options/request-options.component";
|
||||||
|
import { AlbumsGridComponent } from "./albums-grid/albums-grid.component";
|
||||||
|
|
||||||
export const components: any[] = [
|
export const components: any[] = [
|
||||||
RequestsListComponent,
|
RequestsListComponent,
|
||||||
MoviesGridComponent,
|
MoviesGridComponent,
|
||||||
TvGridComponent,
|
TvGridComponent,
|
||||||
GridSpinnerComponent,
|
GridSpinnerComponent,
|
||||||
RequestOptionsComponent
|
RequestOptionsComponent,
|
||||||
|
AlbumsGridComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
export const entryComponents: any[] = [
|
export const entryComponents: any[] = [
|
||||||
|
|
|
@ -72,6 +72,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
// If the user changes the sort order, reset back to the first page.
|
// If the user changes the sort order, reset back to the first page.
|
||||||
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
||||||
|
this.paginator.showFirstLastButtons = true;
|
||||||
|
|
||||||
merge(this.sort.sortChange, this.paginator.page, this.currentFilter)
|
merge(this.sort.sortChange, this.paginator.page, this.currentFilter)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -19,6 +19,9 @@ export class RequestOptionsComponent {
|
||||||
if (this.data.type === RequestType.tvShow) {
|
if (this.data.type === RequestType.tvShow) {
|
||||||
await this.requestService.deleteChild(this.data.id).toPromise();
|
await this.requestService.deleteChild(this.data.id).toPromise();
|
||||||
}
|
}
|
||||||
|
if (this.data.type === RequestType.album) {
|
||||||
|
await this.requestService.removeAlbumRequest(this.data.id).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
this.bottomSheetRef.dismiss({type: UpdateType.Delete});
|
this.bottomSheetRef.dismiss({type: UpdateType.Delete});
|
||||||
return;
|
return;
|
||||||
|
@ -31,6 +34,9 @@ export class RequestOptionsComponent {
|
||||||
if (this.data.type === RequestType.tvShow) {
|
if (this.data.type === RequestType.tvShow) {
|
||||||
await this.requestService.approveChild({id: this.data.id}).toPromise();
|
await this.requestService.approveChild({id: this.data.id}).toPromise();
|
||||||
}
|
}
|
||||||
|
if (this.data.type === RequestType.album) {
|
||||||
|
await this.requestService.approveAlbum({id: this.data.id}).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
this.bottomSheetRef.dismiss({type: UpdateType.Approve});
|
this.bottomSheetRef.dismiss({type: UpdateType.Approve});
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,8 +12,9 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab label="Albums">
|
<mat-tab label="Albums">
|
||||||
<h1>Coming soon</h1>
|
<ng-template matTabContent>
|
||||||
<p>...</p>
|
<albums-grid (onOpenOptions)="onOpenOptions($event)"></albums-grid>
|
||||||
|
</ng-template>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</div>
|
</div>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
|
|
@ -67,6 +67,7 @@ export class TvGridComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
this.storageService.save(this.storageKeyGridCount, this.gridCount);
|
this.storageService.save(this.storageKeyGridCount, this.gridCount);
|
||||||
this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString());
|
this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString());
|
||||||
|
this.paginator.showFirstLastButtons = true;
|
||||||
|
|
||||||
// If the user changes the sort order, reset back to the first page.
|
// If the user changes the sort order, reset back to the first page.
|
||||||
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core";
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
import { ServiceHelpers } from "./service.helpers";
|
import { ServiceHelpers } from "./service.helpers";
|
||||||
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions, IRequestEngineResult } from "../interfaces";
|
import { IRequestsViewModel, IMovieRequests, IChildRequests, IMovieAdvancedOptions, IRequestEngineResult, IAlbumRequest } from "../interfaces";
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -65,4 +65,23 @@ export class RequestServiceV2 extends ServiceHelpers {
|
||||||
return this.http.get<IRequestsViewModel<IChildRequests>>(`${this.url}tv/unavailable/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
return this.http.get<IRequestsViewModel<IChildRequests>>(`${this.url}tv/unavailable/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAlbumRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
return this.http.get<IRequestsViewModel<IAlbumRequest>>(`${this.url}Album/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAlbumAvailableRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
return this.http.get<IRequestsViewModel<IAlbumRequest>>(`${this.url}Album/available/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAlbumProcessingRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
return this.http.get<IRequestsViewModel<IAlbumRequest>>(`${this.url}Album/processing/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAlbumPendingRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
return this.http.get<IRequestsViewModel<IAlbumRequest>>(`${this.url}Album/pending/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAlbumDeniedRequests(count: number, position: number, sortProperty: string , order: string): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
return this.http.get<IRequestsViewModel<IAlbumRequest>>(`${this.url}Album/denied/${count}/${position}/${sortProperty}/${order}`, {headers: this.headers});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<settings-menu></settings-menu>
|
<settings-menu></settings-menu>
|
||||||
<div class="small-middle-container">
|
<div class="small-middle-container" *ngIf="settings">
|
||||||
<fieldset style="width:100%;">
|
<fieldset style="width:100%;">
|
||||||
<legend>Plex Configuration</legend>
|
<legend>Plex Configuration</legend>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -14,14 +14,17 @@ namespace Ombi.Controllers.V2
|
||||||
{
|
{
|
||||||
public class RequestsController : V2Controller
|
public class RequestsController : V2Controller
|
||||||
{
|
{
|
||||||
public RequestsController(IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine)
|
|
||||||
{
|
|
||||||
_movieRequestEngine = movieRequestEngine;
|
|
||||||
_tvRequestEngine = tvRequestEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly IMovieRequestEngine _movieRequestEngine;
|
private readonly IMovieRequestEngine _movieRequestEngine;
|
||||||
private readonly ITvRequestEngine _tvRequestEngine;
|
private readonly ITvRequestEngine _tvRequestEngine;
|
||||||
|
private readonly IMusicRequestEngine _musicRequestEngine;
|
||||||
|
|
||||||
|
public RequestsController(IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, IMusicRequestEngine musicRequestEngine)
|
||||||
|
{
|
||||||
|
_movieRequestEngine = movieRequestEngine;
|
||||||
|
_tvRequestEngine = tvRequestEngine;
|
||||||
|
_musicRequestEngine = musicRequestEngine;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets movie requests.
|
/// Gets movie requests.
|
||||||
|
@ -129,5 +132,35 @@ namespace Ombi.Controllers.V2
|
||||||
{
|
{
|
||||||
return await _movieRequestEngine.UpdateAdvancedOptions(options);
|
return await _movieRequestEngine.UpdateAdvancedOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("albums/available/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetAvailableAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||||
|
{
|
||||||
|
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.Available);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("album/processing/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetProcessingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||||
|
{
|
||||||
|
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.ProcessingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("album/pending/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetPendingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||||
|
{
|
||||||
|
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.PendingApproval);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("album/denied/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetDeniedAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||||
|
{
|
||||||
|
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.Denied);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("album/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||||
|
public async Task<RequestsViewModel<AlbumRequest>> GetAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||||
|
{
|
||||||
|
return await _musicRequestEngine.GetRequests(count, position, sort, sortOrder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -113,6 +113,8 @@
|
||||||
"Title": "Requests",
|
"Title": "Requests",
|
||||||
"Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.",
|
"Paragraph": "Below you can see yours and all other requests, as well as their download and approval status.",
|
||||||
"MoviesTab": "Movies",
|
"MoviesTab": "Movies",
|
||||||
|
"ArtistName": "Artist",
|
||||||
|
"AlbumName": "Album Name",
|
||||||
"TvTab": "TV Shows",
|
"TvTab": "TV Shows",
|
||||||
"MusicTab": "Music",
|
"MusicTab": "Music",
|
||||||
"RequestedBy": "Requested By",
|
"RequestedBy": "Requested By",
|
||||||
|
@ -226,6 +228,26 @@
|
||||||
"ClearSelection": "Clear Selection",
|
"ClearSelection": "Clear Selection",
|
||||||
"RequestSelectedAlbums": "Request Selected Albums",
|
"RequestSelectedAlbums": "Request Selected Albums",
|
||||||
"ViewCollection":"View Collection",
|
"ViewCollection":"View Collection",
|
||||||
|
"NotEnoughInfo": "Unfortunately there is not enough information about this show yet!",
|
||||||
|
"AdvancedOptions":"Advanced Options",
|
||||||
|
"RadarrProfile":"Radarr Quality Profile",
|
||||||
|
"RadarrFolder":"Radarr Root Folder",
|
||||||
|
"Status":"Status",
|
||||||
|
"Availability":"Availability",
|
||||||
|
"RequestStatus":"Request Status",
|
||||||
|
"Quality":"Quality",
|
||||||
|
"RootFolderOverride":"Root Folder Override",
|
||||||
|
"QualityOverride":"Quality Override",
|
||||||
|
"Genres":"Genres",
|
||||||
|
"TheatricalRelease":"Theatrical Release",
|
||||||
|
"DigitalRelease":"Digital Release",
|
||||||
|
"UserScore":"User Score",
|
||||||
|
"Votes":"Votes",
|
||||||
|
"Runtime":"Runtime",
|
||||||
|
"Minutes": "{{runtime}} Minutes",
|
||||||
|
"Revenue":"Revenue",
|
||||||
|
"Budget":"Budget",
|
||||||
|
"Keywords":"Keywords/Tags",
|
||||||
"Casts": {
|
"Casts": {
|
||||||
"CastTitle": "Cast",
|
"CastTitle": "Cast",
|
||||||
"Character": "Character",
|
"Character": "Character",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue