mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 13:23:20 -07:00
Merge pull request #2067 from tidusjar/develop
Develop into dynamic-webpack-base
This commit is contained in:
commit
1b8956e471
35 changed files with 672 additions and 328 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## (unreleased)
|
## v3.0.3000 (2018-03-09)
|
||||||
|
|
||||||
### **New Features**
|
### **New Features**
|
||||||
|
|
||||||
|
@ -8,6 +8,12 @@
|
||||||
|
|
||||||
- Added Pending Approval into the filters list. [tidusjar]
|
- Added Pending Approval into the filters list. [tidusjar]
|
||||||
|
|
||||||
|
- Added the ability to hide requests that have not been made by that user (#2052) [Jamie]
|
||||||
|
|
||||||
|
- Update README.md. [Jamie]
|
||||||
|
|
||||||
|
- Update README.md. [Louis Laureys]
|
||||||
|
|
||||||
### **Fixes**
|
### **Fixes**
|
||||||
|
|
||||||
- Fixed #2042. [Jamie]
|
- Fixed #2042. [Jamie]
|
||||||
|
|
|
@ -14,10 +14,11 @@ ___
|
||||||
|
|
||||||
[](https://forums.ombi.io/viewforum.php?f=10) [](https://forums.ombi.io/posting.php?mode=post&f=20)
|
[](https://forums.ombi.io/viewforum.php?f=10) [](https://forums.ombi.io/posting.php?mode=post&f=20)
|
||||||
|
|
||||||
| Service | V3 | Beta |
|
|
||||||
|
| Service | Stable | Develop |
|
||||||
|----------|:---------------------------:|:----------------------------:|
|
|----------|:---------------------------:|:----------------------------:|
|
||||||
| AppVeyor | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/master) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore) |
|
| AppVeyor | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/master) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/develop) |
|
||||||
| Download |[](https://github.com/tidusjar/Ombi/releases) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/DotNetCore/artifacts) |
|
| Download |[](https://github.com/tidusjar/Ombi/releases) | [](https://ci.appveyor.com/project/tidusjar/requestplex/branch/develop/artifacts) |
|
||||||
# Features
|
# Features
|
||||||
Here are some of the features Ombi V3 has:
|
Here are some of the features Ombi V3 has:
|
||||||
* Now working without crashes on Linux.
|
* Now working without crashes on Linux.
|
||||||
|
@ -91,7 +92,7 @@ Search the existing requests to see if your suggestion has already been submitte
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
[Click Here](https://github.com/tidusjar/Ombi/wiki/Installation)
|
[Installation Guide](https://github.com/tidusjar/Ombi/wiki/Installation)
|
||||||
[Here for Reverse Proxy Config Examples](https://github.com/tidusjar/Ombi/wiki/Reverse-Proxy-Examples)
|
[Here for Reverse Proxy Config Examples](https://github.com/tidusjar/Ombi/wiki/Reverse-Proxy-Examples)
|
||||||
[PlexGuide.com - Ombi Deployment & 101 Demonstration!](https://www.youtube.com/watch?v=QPNlqqkjNJw&feature=youtu.be)
|
[PlexGuide.com - Ombi Deployment & 101 Demonstration!](https://www.youtube.com/watch?v=QPNlqqkjNJw&feature=youtu.be)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Ombi.Api.Plex.Models
|
||||||
public int leafCount { get; set; }
|
public int leafCount { get; set; }
|
||||||
public int viewedLeafCount { get; set; }
|
public int viewedLeafCount { get; set; }
|
||||||
public int childCount { get; set; }
|
public int childCount { get; set; }
|
||||||
public int addedAt { get; set; }
|
public long addedAt { get; set; }
|
||||||
public int updatedAt { get; set; }
|
public int updatedAt { get; set; }
|
||||||
public Genre[] Genre { get; set; }
|
public Genre[] Genre { get; set; }
|
||||||
//public Role[] Role { get; set; }
|
//public Role[] Role { get; set; }
|
||||||
|
|
|
@ -14,6 +14,8 @@ using Ombi.Store.Repository.Requests;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -24,14 +26,18 @@ namespace Ombi.Core.Engine
|
||||||
private Dictionary<int, TvRequests> _dbTv;
|
private Dictionary<int, TvRequests> _dbTv;
|
||||||
|
|
||||||
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
|
protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService,
|
||||||
IRuleEvaluator rules, OmbiUserManager um) : base(identity, um, rules)
|
IRuleEvaluator rules, OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings) : base(identity, um, rules)
|
||||||
{
|
{
|
||||||
RequestService = requestService;
|
RequestService = requestService;
|
||||||
|
Cache = cache;
|
||||||
|
OmbiSettings = ombiSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IRequestServiceMain RequestService { get; }
|
protected IRequestServiceMain RequestService { get; }
|
||||||
protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
|
protected IMovieRequestRepository MovieRepository => RequestService.MovieRequestService;
|
||||||
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
|
protected ITvRequestRepository TvRepository => RequestService.TvRequestService;
|
||||||
|
protected readonly ICacheService Cache;
|
||||||
|
protected readonly ISettingsService<OmbiSettings> OmbiSettings;
|
||||||
|
|
||||||
protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests()
|
protected async Task<Dictionary<int, MovieRequests>> GetMovieRequests()
|
||||||
{
|
{
|
||||||
|
@ -99,5 +105,30 @@ namespace Ombi.Core.Engine
|
||||||
Pending = pendingMovies + pendingTv
|
Pending = pendingMovies + pendingTv
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task<HideResult> HideFromOtherUsers()
|
||||||
|
{
|
||||||
|
if (await IsInRole(OmbiRoles.Admin) || await IsInRole(OmbiRoles.PowerUser))
|
||||||
|
{
|
||||||
|
return new HideResult();
|
||||||
|
}
|
||||||
|
var settings = await Cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await OmbiSettings.GetSettingsAsync());
|
||||||
|
var result = new HideResult
|
||||||
|
{
|
||||||
|
Hide = settings.HideRequestsUsers
|
||||||
|
};
|
||||||
|
if (settings.HideRequestsUsers)
|
||||||
|
{
|
||||||
|
var user = await GetUser();
|
||||||
|
result.UserId = user.Id;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HideResult
|
||||||
|
{
|
||||||
|
public bool Hide { get; set; }
|
||||||
|
public string UserId { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using Ombi.Core.Rule;
|
using System;
|
||||||
|
using Ombi.Core.Rule;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Identity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.Interfaces
|
namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
|
@ -30,6 +32,13 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
private OmbiUser _user;
|
private OmbiUser _user;
|
||||||
protected async Task<OmbiUser> GetUser()
|
protected async Task<OmbiUser> GetUser()
|
||||||
{
|
{
|
||||||
|
if (IsApiUser)
|
||||||
|
{
|
||||||
|
return new OmbiUser
|
||||||
|
{
|
||||||
|
UserName = Username,
|
||||||
|
};
|
||||||
|
}
|
||||||
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.UserName == Username));
|
return _user ?? (_user = await UserManager.Users.FirstOrDefaultAsync(x => x.UserName == Username));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +49,10 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
|
|
||||||
protected async Task<bool> IsInRole(string roleName)
|
protected async Task<bool> IsInRole(string roleName)
|
||||||
{
|
{
|
||||||
|
if (IsApiUser && roleName != OmbiRoles.Disabled)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return await UserManager.IsInRoleAsync(await GetUser(), roleName);
|
return await UserManager.IsInRoleAsync(await GetUser(), roleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,5 +72,7 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
var ruleResults = await Rules.StartSpecificRules(model, rule);
|
var ruleResults = await Rules.StartSpecificRules(model, rule);
|
||||||
return ruleResults;
|
return ruleResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsApiUser => Username.Equals("Api", StringComparison.CurrentCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,6 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
|
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
|
||||||
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
Task<RequestEngineResult> ApproveMovieById(int requestId);
|
||||||
Task<RequestEngineResult> DenyMovieById(int modelId);
|
Task<RequestEngineResult> DenyMovieById(int modelId);
|
||||||
IEnumerable<MovieRequests> Filter(FilterViewModel vm);
|
Task<IEnumerable<MovieRequests>> Filter(FilterViewModel vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using Ombi.Api.TheMovieDb;
|
using Ombi.Api.TheMovieDb;
|
||||||
using Ombi.Core.Models.Requests;
|
using Ombi.Core.Models.Requests;
|
||||||
using Ombi.Core.Models.Search;
|
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
using Ombi.Store.Entities;
|
using Ombi.Store.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
@ -15,6 +14,8 @@ using Ombi.Api.TheMovieDb.Models;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Core.Engine.Interfaces;
|
using Ombi.Core.Engine.Interfaces;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
|
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
|
||||||
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
|
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
|
||||||
OmbiUserManager manager, IRepository<RequestLog> rl) : base(user, requestService, r, manager)
|
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings) : base(user, requestService, r, manager, cache, ombiSettings)
|
||||||
{
|
{
|
||||||
MovieApi = movieApi;
|
MovieApi = movieApi;
|
||||||
NotificationHelper = helper;
|
NotificationHelper = helper;
|
||||||
|
@ -126,7 +127,16 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
|
public async Task<IEnumerable<MovieRequests>> GetRequests(int count, int position)
|
||||||
{
|
{
|
||||||
var allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).ToListAsync();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<MovieRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).Skip(position).Take(count).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser().Skip(position).Take(count).ToListAsync();
|
||||||
|
}
|
||||||
allRequests.ForEach(x =>
|
allRequests.ForEach(x =>
|
||||||
{
|
{
|
||||||
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
|
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
|
||||||
|
@ -140,7 +150,16 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<MovieRequests>> GetRequests()
|
public async Task<IEnumerable<MovieRequests>> GetRequests()
|
||||||
{
|
{
|
||||||
var allRequests = await MovieRepository.GetWithUser().ToListAsync();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<MovieRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser().ToListAsync();
|
||||||
|
}
|
||||||
return allRequests;
|
return allRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +170,16 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
|
public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
|
||||||
{
|
{
|
||||||
var allRequests = await MovieRepository.GetWithUser().ToListAsync();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<MovieRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await MovieRepository.GetWithUser().ToListAsync();
|
||||||
|
}
|
||||||
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
|
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
|
||||||
results.ForEach(x =>
|
results.ForEach(x =>
|
||||||
{
|
{
|
||||||
|
@ -179,7 +207,7 @@ namespace Ombi.Core.Engine
|
||||||
request.Denied = true;
|
request.Denied = true;
|
||||||
// We are denying a request
|
// We are denying a request
|
||||||
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
|
NotificationHelper.Notify(request, NotificationType.RequestDeclined);
|
||||||
await MovieRepository.Update(request);
|
await MovieRepository.Update(request);
|
||||||
|
|
||||||
return new RequestEngineResult
|
return new RequestEngineResult
|
||||||
{
|
{
|
||||||
|
@ -339,9 +367,10 @@ namespace Ombi.Core.Engine
|
||||||
return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!" };
|
return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MovieRequests> Filter(FilterViewModel vm)
|
public async Task<IEnumerable<MovieRequests>> Filter(FilterViewModel vm)
|
||||||
{
|
{
|
||||||
var requests = MovieRepository.GetWithUser();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
var requests = shouldHide.Hide ? MovieRepository.GetWithUser(shouldHide.UserId) : MovieRepository.GetWithUser();
|
||||||
switch (vm.AvailabilityFilter)
|
switch (vm.AvailabilityFilter)
|
||||||
{
|
{
|
||||||
case FilterType.None:
|
case FilterType.None:
|
||||||
|
|
|
@ -12,26 +12,26 @@ using System.Threading.Tasks;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
|
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
|
||||||
{
|
{
|
||||||
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper,
|
||||||
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem)
|
ILogger<MovieSearchEngine> logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService<OmbiSettings> s)
|
||||||
: base(identity, service, r, um)
|
: base(identity, service, r, um, mem, s)
|
||||||
{
|
{
|
||||||
MovieApi = movApi;
|
MovieApi = movApi;
|
||||||
Mapper = mapper;
|
Mapper = mapper;
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
MemCache = mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMovieDbApi MovieApi { get; }
|
private IMovieDbApi MovieApi { get; }
|
||||||
private IMapper Mapper { get; }
|
private IMapper Mapper { get; }
|
||||||
private ILogger<MovieSearchEngine> Logger { get; }
|
private ILogger<MovieSearchEngine> Logger { get; }
|
||||||
private ICacheService MemCache { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lookups the imdb information.
|
/// Lookups the imdb information.
|
||||||
|
@ -85,7 +85,7 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
public async Task<IEnumerable<SearchMovieViewModel>> PopularMovies()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
@ -100,7 +100,7 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
public async Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
@ -115,7 +115,7 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
public async Task<IEnumerable<SearchMovieViewModel>> UpcomingMovies()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.UpcomingMovies, async () => await MovieApi.Upcoming(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () => await MovieApi.Upcoming(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
@ -130,7 +130,7 @@ namespace Ombi.Core.Engine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
public async Task<IEnumerable<SearchMovieViewModel>> NowPlayingMovies()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
Logger.LogDebug("Search Result: {result}", result);
|
||||||
|
|
|
@ -17,6 +17,8 @@ using Ombi.Core.Helpers;
|
||||||
using Ombi.Core.Rule;
|
using Ombi.Core.Rule;
|
||||||
using Ombi.Core.Rule.Interfaces;
|
using Ombi.Core.Rule.Interfaces;
|
||||||
using Ombi.Core.Senders;
|
using Ombi.Core.Senders;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
using Ombi.Store.Entities.Requests;
|
using Ombi.Store.Entities.Requests;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
|
public TvRequestEngine(ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user,
|
||||||
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
INotificationHelper helper, IRuleEvaluator rule, OmbiUserManager manager,
|
||||||
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl) : base(user, requestService, rule, manager)
|
ITvSender sender, IAuditRepository audit, IRepository<RequestLog> rl, ISettingsService<OmbiSettings> settings, ICacheService cache) : base(user, requestService, rule, manager, cache, settings)
|
||||||
{
|
{
|
||||||
TvApi = tvApi;
|
TvApi = tvApi;
|
||||||
NotificationHelper = helper;
|
NotificationHelper = helper;
|
||||||
|
@ -128,45 +130,136 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
public async Task<IEnumerable<TvRequests>> GetRequests(int count, int position)
|
public async Task<IEnumerable<TvRequests>> GetRequests(int count, int position)
|
||||||
{
|
{
|
||||||
var allRequests = await TvRepository.Get()
|
var shouldHide = await HideFromOtherUsers();
|
||||||
.Include(x => x.ChildRequests)
|
List<TvRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.Get(shouldHide.UserId)
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.Skip(position).Take(count).ToListAsync();
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
|
||||||
|
// Filter out children
|
||||||
|
|
||||||
|
FilterChildren(allRequests, shouldHide);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.Get()
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
return allRequests;
|
return allRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position)
|
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> GetRequestsTreeNode(int count, int position)
|
||||||
{
|
{
|
||||||
var allRequests = await TvRepository.Get()
|
var shouldHide = await HideFromOtherUsers();
|
||||||
.Include(x => x.ChildRequests)
|
List<TvRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.Get(shouldHide.UserId)
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
.ThenInclude(x => x.SeasonRequests)
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
.ThenInclude(x=>x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.Skip(position).Take(count).ToListAsync();
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
|
||||||
|
FilterChildren(allRequests, shouldHide);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.Get()
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.Skip(position).Take(count).ToListAsync();
|
||||||
|
}
|
||||||
return ParseIntoTreeNode(allRequests);
|
return ParseIntoTreeNode(allRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TvRequests>> GetRequests()
|
public async Task<IEnumerable<TvRequests>> GetRequests()
|
||||||
{
|
{
|
||||||
var allRequests = TvRepository.Get();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<TvRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get(shouldHide.UserId);
|
||||||
|
|
||||||
|
FilterChildren(allRequests, shouldHide);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get();
|
||||||
|
}
|
||||||
|
|
||||||
return await allRequests.ToListAsync();
|
return await allRequests.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void FilterChildren(IEnumerable<TvRequests> allRequests, HideResult shouldHide)
|
||||||
|
{
|
||||||
|
// Filter out children
|
||||||
|
foreach (var t in allRequests)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < t.ChildRequests.Count; j++)
|
||||||
|
{
|
||||||
|
var child = t.ChildRequests[j];
|
||||||
|
if (child.RequestedUserId != shouldHide.UserId)
|
||||||
|
{
|
||||||
|
t.ChildRequests.RemoveAt(j);
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId)
|
public async Task<IEnumerable<ChildRequests>> GetAllChldren(int tvId)
|
||||||
{
|
{
|
||||||
return await TvRepository.GetChild().Include(x => x.SeasonRequests).Where(x => x.ParentRequestId == tvId).ToListAsync();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
List<ChildRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.GetChild(shouldHide.UserId).Include(x => x.SeasonRequests).Where(x => x.ParentRequestId == tvId).ToListAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = await TvRepository.GetChild().Include(x => x.SeasonRequests).Where(x => x.ParentRequestId == tvId).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return allRequests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TvRequests>> SearchTvRequest(string search)
|
public async Task<IEnumerable<TvRequests>> SearchTvRequest(string search)
|
||||||
{
|
{
|
||||||
var allRequests = TvRepository.Get();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<TvRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get(shouldHide.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get();
|
||||||
|
}
|
||||||
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
|
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search)
|
public async Task<IEnumerable<TreeNode<TvRequests, List<ChildRequests>>>> SearchTvRequestTree(string search)
|
||||||
{
|
{
|
||||||
var allRequests = TvRepository.Get();
|
var shouldHide = await HideFromOtherUsers();
|
||||||
|
IQueryable<TvRequests> allRequests;
|
||||||
|
if (shouldHide.Hide)
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get(shouldHide.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allRequests = TvRepository.Get();
|
||||||
|
}
|
||||||
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
|
var results = await allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToListAsync();
|
||||||
return ParseIntoTreeNode(results);
|
return ParseIntoTreeNode(results);
|
||||||
}
|
}
|
||||||
|
@ -402,7 +495,7 @@ namespace Ombi.Core.Engine
|
||||||
var result = await TvSender.Send(model);
|
var result = await TvSender.Send(model);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
return new RequestEngineResult {Result = true};
|
return new RequestEngineResult { Result = true };
|
||||||
}
|
}
|
||||||
return new RequestEngineResult
|
return new RequestEngineResult
|
||||||
{
|
{
|
||||||
|
@ -418,7 +511,7 @@ namespace Ombi.Core.Engine
|
||||||
RequestType = RequestType.TvShow,
|
RequestType = RequestType.TvShow,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new RequestEngineResult {Result = true};
|
return new RequestEngineResult { Result = true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ using Ombi.Store.Repository.Requests;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Ombi.Core.Authentication;
|
using Ombi.Core.Authentication;
|
||||||
using Ombi.Helpers;
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine
|
namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
|
@ -26,8 +27,8 @@ namespace Ombi.Core.Engine
|
||||||
{
|
{
|
||||||
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, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um,
|
ISettingsService<EmbySettings> embySettings, IPlexContentRepository repo, IEmbyContentRepository embyRepo, ITraktApi trakt, IRuleEvaluator r, OmbiUserManager um,
|
||||||
ICacheService memCache)
|
ICacheService memCache, ISettingsService<OmbiSettings> s)
|
||||||
: base(identity, service, r, um)
|
: base(identity, service, r, um, memCache, s)
|
||||||
{
|
{
|
||||||
TvMazeApi = tvMaze;
|
TvMazeApi = tvMaze;
|
||||||
Mapper = mapper;
|
Mapper = mapper;
|
||||||
|
@ -36,7 +37,6 @@ namespace Ombi.Core.Engine
|
||||||
PlexContentRepo = repo;
|
PlexContentRepo = repo;
|
||||||
TraktApi = trakt;
|
TraktApi = trakt;
|
||||||
EmbyContentRepo = embyRepo;
|
EmbyContentRepo = embyRepo;
|
||||||
MemCache = memCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ITvMazeApi TvMazeApi { get; }
|
private ITvMazeApi TvMazeApi { get; }
|
||||||
|
@ -46,7 +46,6 @@ namespace Ombi.Core.Engine
|
||||||
private IPlexContentRepository PlexContentRepo { get; }
|
private IPlexContentRepository PlexContentRepo { get; }
|
||||||
private IEmbyContentRepository EmbyContentRepo { get; }
|
private IEmbyContentRepository EmbyContentRepo { get; }
|
||||||
private ITraktApi TraktApi { get; }
|
private ITraktApi TraktApi { get; }
|
||||||
private ICacheService MemCache { get; }
|
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm)
|
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm)
|
||||||
{
|
{
|
||||||
|
@ -124,54 +123,55 @@ namespace Ombi.Core.Engine
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> PopularTree()
|
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> PopularTree()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed.Select(ParseIntoTreeNode).ToList();
|
return processed.Select(ParseIntoTreeNode).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.PopularTv, async () => await TraktApi.GetPopularShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> AnticipatedTree()
|
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> AnticipatedTree()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed.Select(ParseIntoTreeNode).ToList();
|
return processed.Select(ParseIntoTreeNode).ToList();
|
||||||
}
|
}
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
|
||||||
|
var result = await Cache.GetOrAdd(CacheKeys.AnticipatedTv, async () => await TraktApi.GetAnticipatedShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatchesTree()
|
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatchesTree()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed.Select(ParseIntoTreeNode).ToList();
|
return processed.Select(ParseIntoTreeNode).ToList();
|
||||||
}
|
}
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.MostWatchesTv, async () => await TraktApi.GetMostWatchesShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> TrendingTree()
|
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> TrendingTree()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed.Select(ParseIntoTreeNode).ToList();
|
return processed.Select(ParseIntoTreeNode).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
|
||||||
{
|
{
|
||||||
var result = await MemCache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
var result = await Cache.GetOrAdd(CacheKeys.TrendingTv, async () => await TraktApi.GetTrendingShows(), DateTime.Now.AddHours(12));
|
||||||
var processed = await ProcessResults(result);
|
var processed = await ProcessResults(result);
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Ombi.Helpers
|
||||||
var version = Assembly.GetEntryAssembly()
|
var version = Assembly.GetEntryAssembly()
|
||||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
|
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
|
||||||
.InformationalVersion;
|
.InformationalVersion;
|
||||||
return version.Equals("1.0.0") ? "3.0.0-DotNetCore" : version;
|
return version.Equals("1.0.0") ? "3.0.0-develop" : version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -93,217 +93,155 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
foreach (var servers in plexSettings.Servers ?? new List<PlexServers>())
|
foreach (var servers in plexSettings.Servers ?? new List<PlexServers>())
|
||||||
{
|
{
|
||||||
|
try
|
||||||
Logger.LogInformation("Getting all content from server {0}", servers.Name);
|
|
||||||
var allContent = await GetAllContent(servers);
|
|
||||||
Logger.LogInformation("We found {0} items", allContent.Count);
|
|
||||||
|
|
||||||
// Let's now process this.
|
|
||||||
var contentToAdd = new List<PlexServerContent>();
|
|
||||||
foreach (var content in allContent)
|
|
||||||
{
|
{
|
||||||
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
Logger.LogInformation("Starting to cache the content on server {0}", servers.Name);
|
||||||
|
await ProcessServer(servers);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(LoggingEvents.PlexContentCacher, e, "Exception thrown when attempting to cache the Plex Content in server {0}", servers.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessServer(PlexServers servers)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Getting all content from server {0}", servers.Name);
|
||||||
|
var allContent = await GetAllContent(servers);
|
||||||
|
Logger.LogInformation("We found {0} items", allContent.Count);
|
||||||
|
|
||||||
|
// Let's now process this.
|
||||||
|
var contentToAdd = new HashSet<PlexServerContent>();
|
||||||
|
foreach (var content in allContent)
|
||||||
|
{
|
||||||
|
if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
// Process Shows
|
||||||
|
Logger.LogInformation("Processing TV Shows");
|
||||||
|
foreach (var show in content.Metadata ?? new Metadata[] { })
|
||||||
{
|
{
|
||||||
// Process Shows
|
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
|
||||||
Logger.LogInformation("Processing TV Shows");
|
show.ratingKey);
|
||||||
foreach (var show in content.Metadata ?? new Metadata[] { })
|
var seasonsContent = new List<PlexSeasonsContent>();
|
||||||
|
foreach (var season in seasonList.MediaContainer.Metadata)
|
||||||
{
|
{
|
||||||
var seasonList = await PlexApi.GetSeasons(servers.PlexAuthToken, servers.FullUri,
|
seasonsContent.Add(new PlexSeasonsContent
|
||||||
show.ratingKey);
|
|
||||||
var seasonsContent = new List<PlexSeasonsContent>();
|
|
||||||
foreach (var season in seasonList.MediaContainer.Metadata)
|
|
||||||
{
|
{
|
||||||
seasonsContent.Add(new PlexSeasonsContent
|
ParentKey = season.parentRatingKey,
|
||||||
{
|
SeasonKey = season.ratingKey,
|
||||||
ParentKey = season.parentRatingKey,
|
SeasonNumber = season.index,
|
||||||
SeasonKey = season.ratingKey,
|
PlexContentId = show.ratingKey
|
||||||
SeasonNumber = season.index,
|
});
|
||||||
PlexContentId = show.ratingKey
|
}
|
||||||
});
|
|
||||||
|
// Do we already have this item?
|
||||||
|
// Let's try and match
|
||||||
|
var existingContent = await Repo.GetFirstContentByCustom(x => x.Title == show.title
|
||||||
|
&& x.ReleaseYear == show.year.ToString()
|
||||||
|
&& x.Type == PlexMediaTypeEntity.Show);
|
||||||
|
|
||||||
|
// Just double check the rating key, since this is our unique constraint
|
||||||
|
var existingKey = await Repo.GetByKey(show.ratingKey);
|
||||||
|
|
||||||
|
if (existingKey != null)
|
||||||
|
{
|
||||||
|
// Damn son.
|
||||||
|
// Let's check if they match up
|
||||||
|
var doesMatch = show.title.Equals(existingKey.Title,
|
||||||
|
StringComparison.CurrentCulture);
|
||||||
|
if (!doesMatch)
|
||||||
|
{
|
||||||
|
// Something fucked up on Plex at somepoint... Damn, rebuild of lib maybe?
|
||||||
|
// Lets delete the matching key
|
||||||
|
await Repo.Delete(existingKey);
|
||||||
|
existingKey = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do we already have this item?
|
if (existingContent != null)
|
||||||
// Let's try and match
|
{
|
||||||
var existingContent = await Repo.GetFirstContentByCustom(x => x.Title == show.title
|
// Just check the key
|
||||||
&& x.ReleaseYear == show.year.ToString()
|
if (existingKey != null)
|
||||||
&& x.Type == PlexMediaTypeEntity.Show);
|
|
||||||
|
|
||||||
if (existingContent != null)
|
|
||||||
{
|
{
|
||||||
// Just check the key
|
// The rating key is all good!
|
||||||
var existingKey = await Repo.GetByKey(show.ratingKey);
|
|
||||||
if (existingKey != null)
|
|
||||||
{
|
|
||||||
// The rating key is all good!
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This means the rating key has changed somehow.
|
|
||||||
// Should probably delete this and get the new one
|
|
||||||
var oldKey = existingContent.Key;
|
|
||||||
Repo.DeleteWithoutSave(existingContent);
|
|
||||||
|
|
||||||
// Because we have changed the rating key, we need to change all children too
|
|
||||||
var episodeToChange = Repo.GetAllEpisodes().Where(x => x.GrandparentKey == oldKey);
|
|
||||||
if (episodeToChange.Any())
|
|
||||||
{
|
|
||||||
foreach (var e in episodeToChange)
|
|
||||||
{
|
|
||||||
Repo.DeleteWithoutSave(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Repo.SaveChangesAsync();
|
|
||||||
existingContent = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// The ratingKey keeps changing...
|
|
||||||
//var existingContent = await Repo.GetByKey(show.ratingKey);
|
|
||||||
if (existingContent != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logger.LogInformation("We already have show {0} checking for new seasons", existingContent.Title);
|
|
||||||
// Ok so we have it, let's check if there are any new seasons
|
|
||||||
var itemAdded = false;
|
|
||||||
foreach (var season in seasonsContent)
|
|
||||||
{
|
|
||||||
var seasonExists = existingContent.Seasons.FirstOrDefault(x => x.SeasonKey == season.SeasonKey);
|
|
||||||
|
|
||||||
if (seasonExists != null)
|
|
||||||
{
|
|
||||||
// We already have this season
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
existingContent.Seasons.Add(season);
|
|
||||||
itemAdded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemAdded) await Repo.Update(existingContent);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding new seasons to title {0}", existingContent.Title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
// This means the rating key has changed somehow.
|
||||||
|
// Should probably delete this and get the new one
|
||||||
|
var oldKey = existingContent.Key;
|
||||||
|
Repo.DeleteWithoutSave(existingContent);
|
||||||
|
|
||||||
|
// Because we have changed the rating key, we need to change all children too
|
||||||
|
var episodeToChange = Repo.GetAllEpisodes().Where(x => x.GrandparentKey == oldKey);
|
||||||
|
if (episodeToChange.Any())
|
||||||
{
|
{
|
||||||
|
foreach (var e in episodeToChange)
|
||||||
|
{
|
||||||
|
Repo.DeleteWithoutSave(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Repo.SaveChangesAsync();
|
||||||
|
existingContent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The ratingKey keeps changing...
|
||||||
|
//var existingContent = await Repo.GetByKey(show.ratingKey);
|
||||||
|
if (existingContent != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.LogInformation("We already have show {0} checking for new seasons",
|
||||||
|
existingContent.Title);
|
||||||
|
// Ok so we have it, let's check if there are any new seasons
|
||||||
|
var itemAdded = false;
|
||||||
|
foreach (var season in seasonsContent)
|
||||||
|
{
|
||||||
|
var seasonExists =
|
||||||
|
existingContent.Seasons.FirstOrDefault(x => x.SeasonKey == season.SeasonKey);
|
||||||
|
|
||||||
Logger.LogInformation("New show {0}, so add it", show.title);
|
if (seasonExists != null)
|
||||||
|
|
||||||
// Get the show metadata... This sucks since the `metadata` var contains all information about the show
|
|
||||||
// But it does not contain the `guid` property that we need to pull out thetvdb id...
|
|
||||||
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
|
||||||
show.ratingKey);
|
|
||||||
var providerIds = PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault().guid);
|
|
||||||
|
|
||||||
var item = new PlexServerContent
|
|
||||||
{
|
{
|
||||||
AddedAt = DateTime.Now,
|
// We already have this season
|
||||||
Key = show.ratingKey,
|
|
||||||
ReleaseYear = show.year.ToString(),
|
|
||||||
Type = PlexMediaTypeEntity.Show,
|
|
||||||
Title = show.title,
|
|
||||||
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey),
|
|
||||||
Seasons = new List<PlexSeasonsContent>()
|
|
||||||
};
|
|
||||||
if (providerIds.Type == ProviderType.ImdbId)
|
|
||||||
{
|
|
||||||
item.ImdbId = providerIds.ImdbId;
|
|
||||||
}
|
|
||||||
if (providerIds.Type == ProviderType.TheMovieDbId)
|
|
||||||
{
|
|
||||||
item.TheMovieDbId = providerIds.TheMovieDb;
|
|
||||||
}
|
|
||||||
if (providerIds.Type == ProviderType.TvDbId)
|
|
||||||
{
|
|
||||||
item.TvDbId = providerIds.TheTvDb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's just double check to make sure we do not have it now we have some id's
|
|
||||||
var existingImdb = false;
|
|
||||||
var existingMovieDbId = false;
|
|
||||||
var existingTvDbId = false;
|
|
||||||
if (item.ImdbId.HasValue())
|
|
||||||
{
|
|
||||||
existingImdb = await Repo.GetAll().AnyAsync(x =>
|
|
||||||
x.ImdbId == item.ImdbId && x.Type == PlexMediaTypeEntity.Show);
|
|
||||||
}
|
|
||||||
if (item.TheMovieDbId.HasValue())
|
|
||||||
{
|
|
||||||
existingMovieDbId = await Repo.GetAll().AnyAsync(x =>
|
|
||||||
x.TheMovieDbId == item.TheMovieDbId && x.Type == PlexMediaTypeEntity.Show);
|
|
||||||
}
|
|
||||||
if (item.TvDbId.HasValue())
|
|
||||||
{
|
|
||||||
existingTvDbId = await Repo.GetAll().AnyAsync(x =>
|
|
||||||
x.TvDbId == item.TvDbId && x.Type == PlexMediaTypeEntity.Show);
|
|
||||||
}
|
|
||||||
if (existingImdb || existingTvDbId || existingMovieDbId)
|
|
||||||
{
|
|
||||||
// We already have it!
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.Seasons.ToList().AddRange(seasonsContent);
|
existingContent.Seasons.Add(season);
|
||||||
|
itemAdded = true;
|
||||||
contentToAdd.Add(item);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding tv show {0}", show.title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemAdded) await Repo.Update(existingContent);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.PlexContentCacher, e,
|
||||||
|
"Exception when adding new seasons to title {0}", existingContent.Title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
Logger.LogInformation("Processing Movies");
|
|
||||||
foreach (var movie in content?.Metadata ?? new Metadata[] { })
|
|
||||||
{
|
{
|
||||||
// Let's check if we have this movie
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title
|
Logger.LogInformation("New show {0}, so add it", show.title);
|
||||||
&& x.ReleaseYear == movie.year.ToString()
|
|
||||||
&& x.Type == PlexMediaTypeEntity.Movie);
|
|
||||||
// The rating key keeps changing
|
|
||||||
//var existing = await Repo.GetByKey(movie.ratingKey);
|
|
||||||
if (existing != null)
|
|
||||||
{
|
|
||||||
Logger.LogInformation("We already have movie {0}", movie.title);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasSameKey = await Repo.GetByKey(movie.ratingKey);
|
// Get the show metadata... This sucks since the `metadata` var contains all information about the show
|
||||||
if (hasSameKey != null)
|
// But it does not contain the `guid` property that we need to pull out thetvdb id...
|
||||||
{
|
var showMetadata = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
||||||
await Repo.Delete(hasSameKey);
|
show.ratingKey);
|
||||||
}
|
var providerIds =
|
||||||
|
PlexHelper.GetProviderIdFromPlexGuid(showMetadata.MediaContainer.Metadata.FirstOrDefault()
|
||||||
Logger.LogInformation("Adding movie {0}", movie.title);
|
.guid);
|
||||||
var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
|
||||||
movie.ratingKey);
|
|
||||||
var providerIds = PlexHelper.GetProviderIdFromPlexGuid(metaData.MediaContainer.Metadata
|
|
||||||
.FirstOrDefault()
|
|
||||||
.guid);
|
|
||||||
|
|
||||||
var item = new PlexServerContent
|
var item = new PlexServerContent
|
||||||
{
|
{
|
||||||
AddedAt = DateTime.Now,
|
AddedAt = DateTime.Now,
|
||||||
Key = movie.ratingKey,
|
Key = show.ratingKey,
|
||||||
ReleaseYear = movie.year.ToString(),
|
ReleaseYear = show.year.ToString(),
|
||||||
Type = PlexMediaTypeEntity.Movie,
|
Type = PlexMediaTypeEntity.Show,
|
||||||
Title = movie.title,
|
Title = show.title,
|
||||||
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
|
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey),
|
||||||
Seasons = new List<PlexSeasonsContent>(),
|
Seasons = new List<PlexSeasonsContent>()
|
||||||
Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty
|
|
||||||
};
|
};
|
||||||
if (providerIds.Type == ProviderType.ImdbId)
|
if (providerIds.Type == ProviderType.ImdbId)
|
||||||
{
|
{
|
||||||
|
@ -317,26 +255,130 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
item.TvDbId = providerIds.TheTvDb;
|
item.TvDbId = providerIds.TheTvDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let's just double check to make sure we do not have it now we have some id's
|
||||||
|
var existingImdb = false;
|
||||||
|
var existingMovieDbId = false;
|
||||||
|
var existingTvDbId = false;
|
||||||
|
if (item.ImdbId.HasValue())
|
||||||
|
{
|
||||||
|
existingImdb = await Repo.GetAll().AnyAsync(x =>
|
||||||
|
x.ImdbId == item.ImdbId && x.Type == PlexMediaTypeEntity.Show);
|
||||||
|
}
|
||||||
|
if (item.TheMovieDbId.HasValue())
|
||||||
|
{
|
||||||
|
existingMovieDbId = await Repo.GetAll().AnyAsync(x =>
|
||||||
|
x.TheMovieDbId == item.TheMovieDbId && x.Type == PlexMediaTypeEntity.Show);
|
||||||
|
}
|
||||||
|
if (item.TvDbId.HasValue())
|
||||||
|
{
|
||||||
|
existingTvDbId = await Repo.GetAll().AnyAsync(x =>
|
||||||
|
x.TvDbId == item.TvDbId && x.Type == PlexMediaTypeEntity.Show);
|
||||||
|
}
|
||||||
|
if (existingImdb || existingTvDbId || existingMovieDbId)
|
||||||
|
{
|
||||||
|
// We already have it!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.Seasons.ToList().AddRange(seasonsContent);
|
||||||
|
|
||||||
contentToAdd.Add(item);
|
contentToAdd.Add(item);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding new Movie {0}", movie.title);
|
Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding tv show {0}",
|
||||||
|
show.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (contentToAdd.Count > 500)
|
||||||
if (contentToAdd.Count > 500)
|
{
|
||||||
{
|
await Repo.AddRange(contentToAdd);
|
||||||
await Repo.AddRange(contentToAdd);
|
contentToAdd.Clear();
|
||||||
contentToAdd = new List<PlexServerContent>();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Processing Movies");
|
||||||
|
foreach (var movie in content?.Metadata ?? new Metadata[] { })
|
||||||
|
{
|
||||||
|
// Let's check if we have this movie
|
||||||
|
|
||||||
if (contentToAdd.Any())
|
try
|
||||||
|
{
|
||||||
|
var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title
|
||||||
|
&& x.ReleaseYear == movie.year.ToString()
|
||||||
|
&& x.Type == PlexMediaTypeEntity.Movie);
|
||||||
|
// The rating key keeps changing
|
||||||
|
//var existing = await Repo.GetByKey(movie.ratingKey);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("We already have movie {0}", movie.title);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasSameKey = await Repo.GetByKey(movie.ratingKey);
|
||||||
|
if (hasSameKey != null)
|
||||||
|
{
|
||||||
|
await Repo.Delete(hasSameKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation("Adding movie {0}", movie.title);
|
||||||
|
var metaData = await PlexApi.GetMetadata(servers.PlexAuthToken, servers.FullUri,
|
||||||
|
movie.ratingKey);
|
||||||
|
var providerIds = PlexHelper.GetProviderIdFromPlexGuid(metaData.MediaContainer.Metadata
|
||||||
|
.FirstOrDefault()
|
||||||
|
.guid);
|
||||||
|
|
||||||
|
var item = new PlexServerContent
|
||||||
|
{
|
||||||
|
AddedAt = DateTime.Now,
|
||||||
|
Key = movie.ratingKey,
|
||||||
|
ReleaseYear = movie.year.ToString(),
|
||||||
|
Type = PlexMediaTypeEntity.Movie,
|
||||||
|
Title = movie.title,
|
||||||
|
Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey),
|
||||||
|
Seasons = new List<PlexSeasonsContent>(),
|
||||||
|
Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty
|
||||||
|
};
|
||||||
|
if (providerIds.Type == ProviderType.ImdbId)
|
||||||
|
{
|
||||||
|
item.ImdbId = providerIds.ImdbId;
|
||||||
|
}
|
||||||
|
if (providerIds.Type == ProviderType.TheMovieDbId)
|
||||||
|
{
|
||||||
|
item.TheMovieDbId = providerIds.TheMovieDb;
|
||||||
|
}
|
||||||
|
if (providerIds.Type == ProviderType.TvDbId)
|
||||||
|
{
|
||||||
|
item.TvDbId = providerIds.TheTvDb;
|
||||||
|
}
|
||||||
|
contentToAdd.Add(item);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(LoggingEvents.PlexContentCacher, e, "Exception when adding new Movie {0}",
|
||||||
|
movie.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentToAdd.Count > 500)
|
||||||
|
{
|
||||||
|
await Repo.AddRange(contentToAdd);
|
||||||
|
contentToAdd.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contentToAdd.Count > 500)
|
||||||
{
|
{
|
||||||
await Repo.AddRange(contentToAdd);
|
await Repo.AddRange(contentToAdd);
|
||||||
|
contentToAdd.Clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentToAdd.Any())
|
||||||
|
{
|
||||||
|
await Repo.AddRange(contentToAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
if (!Validate(settings))
|
if (!Validate(settings))
|
||||||
{
|
{
|
||||||
|
|
||||||
_log.LogWarning("Validation failed");
|
_log.LogWarning("Validation failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,21 +100,25 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
var currentPosition = 0;
|
var currentPosition = 0;
|
||||||
var resultCount = settings.EpisodeBatchSize == 0 ? 150 : settings.EpisodeBatchSize;
|
var resultCount = settings.EpisodeBatchSize == 0 ? 150 : settings.EpisodeBatchSize;
|
||||||
|
var currentEpisodes = _repo.GetAllEpisodes();
|
||||||
var episodes = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, resultCount);
|
var episodes = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, resultCount);
|
||||||
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.totalSize}");
|
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.totalSize}");
|
||||||
|
|
||||||
// Delete all the episodes because we cannot uniquly match an episode to series every time,
|
// Delete all the episodes because we cannot uniquly match an episode to series every time,
|
||||||
// see comment below.
|
// see comment below.
|
||||||
await _repo.ExecuteSql("DELETE FROM PlexEpisode");
|
|
||||||
|
|
||||||
await ProcessEpsiodes(episodes);
|
// 12.03.2017 - I think we should be able to match them now
|
||||||
|
//await _repo.ExecuteSql("DELETE FROM PlexEpisode");
|
||||||
|
|
||||||
|
await ProcessEpsiodes(episodes, currentEpisodes);
|
||||||
currentPosition += resultCount;
|
currentPosition += resultCount;
|
||||||
|
|
||||||
while (currentPosition < episodes.MediaContainer.totalSize)
|
while (currentPosition < episodes.MediaContainer.totalSize)
|
||||||
{
|
{
|
||||||
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
|
var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
|
||||||
resultCount);
|
resultCount);
|
||||||
await ProcessEpsiodes(ep);
|
|
||||||
|
await ProcessEpsiodes(ep, currentEpisodes);
|
||||||
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {resultCount} more episodes. Total Remaining {episodes.MediaContainer.totalSize - currentPosition}");
|
_log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {resultCount} more episodes. Total Remaining {episodes.MediaContainer.totalSize - currentPosition}");
|
||||||
currentPosition += resultCount;
|
currentPosition += resultCount;
|
||||||
}
|
}
|
||||||
|
@ -125,58 +128,56 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
await _repo.SaveChangesAsync();
|
await _repo.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessEpsiodes(PlexContainer episodes)
|
private async Task ProcessEpsiodes(PlexContainer episodes, IQueryable<PlexEpisode> currentEpisodes)
|
||||||
{
|
{
|
||||||
var ep = new HashSet<PlexEpisode>();
|
var ep = new HashSet<PlexEpisode>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
foreach (var episode in episodes?.MediaContainer?.Metadata ?? new Metadata[] { })
|
||||||
|
|
||||||
foreach (var episode in episodes?.MediaContainer?.Metadata ?? new Metadata[]{})
|
|
||||||
{
|
|
||||||
// I don't think we need to get the metadata, we only need to get the metadata if we need the provider id (TheTvDbid). Why do we need it for episodes?
|
|
||||||
// We have the parent and grandparent rating keys to link up to the season and series
|
|
||||||
//var metadata = _api.GetEpisodeMetaData(server.PlexAuthToken, server.FullUri, episode.ratingKey);
|
|
||||||
|
|
||||||
// This does seem to work, it looks like we can somehow get different rating, grandparent and parent keys with episodes. Not sure how.
|
|
||||||
//var epExists = currentEpisodes.Any(x => episode.ratingKey == x.Key &&
|
|
||||||
// episode.grandparentRatingKey == x.GrandparentKey);
|
|
||||||
//if (epExists)
|
|
||||||
//{
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Let's check if we have the parent
|
|
||||||
var seriesExists = await _repo.GetByKey(episode.grandparentRatingKey);
|
|
||||||
if (seriesExists == null)
|
|
||||||
{
|
{
|
||||||
// Ok let's try and match it to a title. TODO (This is experimental)
|
// I don't think we need to get the metadata, we only need to get the metadata if we need the provider id (TheTvDbid). Why do we need it for episodes?
|
||||||
var seriesMatch = await _repo.GetAll().FirstOrDefaultAsync(x =>
|
// We have the parent and grandparent rating keys to link up to the season and series
|
||||||
x.Title.Equals(episode.grandparentTitle, StringComparison.CurrentCultureIgnoreCase));
|
//var metadata = _api.GetEpisodeMetaData(server.PlexAuthToken, server.FullUri, episode.ratingKey);
|
||||||
if (seriesMatch == null)
|
|
||||||
|
// This does seem to work, it looks like we can somehow get different rating, grandparent and parent keys with episodes. Not sure how.
|
||||||
|
var epExists = currentEpisodes.Any(x => episode.ratingKey == x.Key &&
|
||||||
|
episode.grandparentRatingKey == x.GrandparentKey);
|
||||||
|
if (epExists)
|
||||||
{
|
{
|
||||||
_log.LogWarning(
|
|
||||||
"The episode title {0} we cannot find the parent series. The episode grandparentKey = {1}, grandparentTitle = {2}",
|
|
||||||
episode.title, episode.grandparentRatingKey, episode.grandparentTitle);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the rating key to the correct one
|
// Let's check if we have the parent
|
||||||
episode.grandparentRatingKey = seriesMatch.Key;
|
var seriesExists = await _repo.GetByKey(episode.grandparentRatingKey);
|
||||||
|
if (seriesExists == null)
|
||||||
|
{
|
||||||
|
// Ok let's try and match it to a title. TODO (This is experimental)
|
||||||
|
seriesExists = await _repo.GetAll().FirstOrDefaultAsync(x =>
|
||||||
|
x.Title.Equals(episode.grandparentTitle, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
if (seriesExists == null)
|
||||||
|
{
|
||||||
|
_log.LogWarning(
|
||||||
|
"The episode title {0} we cannot find the parent series. The episode grandparentKey = {1}, grandparentTitle = {2}",
|
||||||
|
episode.title, episode.grandparentRatingKey, episode.grandparentTitle);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the rating key to the correct one
|
||||||
|
episode.grandparentRatingKey = seriesExists.Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep.Add(new PlexEpisode
|
||||||
|
{
|
||||||
|
EpisodeNumber = episode.index,
|
||||||
|
SeasonNumber = episode.parentIndex,
|
||||||
|
GrandparentKey = episode.grandparentRatingKey,
|
||||||
|
ParentKey = episode.parentRatingKey,
|
||||||
|
Key = episode.ratingKey,
|
||||||
|
Title = episode.title
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.Add(new PlexEpisode
|
await _repo.AddRange(ep);
|
||||||
{
|
|
||||||
EpisodeNumber = episode.index,
|
|
||||||
SeasonNumber = episode.parentIndex,
|
|
||||||
GrandparentKey = episode.grandparentRatingKey,
|
|
||||||
ParentKey = episode.parentRatingKey,
|
|
||||||
Key = episode.ratingKey,
|
|
||||||
Title = episode.title
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await _repo.AddRange(ep);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -189,7 +190,7 @@ namespace Ombi.Schedule.Jobs.Plex
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
if (string.IsNullOrEmpty(settings.PlexAuthToken))
|
||||||
{
|
{
|
||||||
return false ;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -46,8 +46,7 @@ namespace Ombi.Schedule.Processor
|
||||||
if (masterBranch)
|
if (masterBranch)
|
||||||
{
|
{
|
||||||
latestRelease = doc.DocumentNode.Descendants("h2")
|
latestRelease = doc.DocumentNode.Descendants("h2")
|
||||||
.FirstOrDefault(x => x.InnerText == "(unreleased)");
|
.FirstOrDefault(x => x.InnerText != "(unreleased)");
|
||||||
// TODO: Change this to InnterText != "(unreleased)" once we go live and it's not a prerelease
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
public bool Wizard { get; set; }
|
public bool Wizard { get; set; }
|
||||||
public string ApiKey { get; set; }
|
public string ApiKey { get; set; }
|
||||||
public bool IgnoreCertificateErrors { get; set; }
|
public bool IgnoreCertificateErrors { get; set; }
|
||||||
public bool DoNotSendNotificationsForAutoApprove {get;set;}
|
public bool DoNotSendNotificationsForAutoApprove { get; set; }
|
||||||
|
public bool HideRequestsUsers { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,5 +11,7 @@ namespace Ombi.Store.Repository.Requests
|
||||||
Task Update(MovieRequests request);
|
Task Update(MovieRequests request);
|
||||||
Task Save();
|
Task Save();
|
||||||
IQueryable<MovieRequests> GetWithUser();
|
IQueryable<MovieRequests> GetWithUser();
|
||||||
|
IQueryable<MovieRequests> GetWithUser(string userId);
|
||||||
|
IQueryable<MovieRequests> GetAll(string userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,11 +14,13 @@ namespace Ombi.Store.Repository.Requests
|
||||||
Task Delete(TvRequests request);
|
Task Delete(TvRequests request);
|
||||||
Task DeleteChild(ChildRequests request);
|
Task DeleteChild(ChildRequests request);
|
||||||
IQueryable<TvRequests> Get();
|
IQueryable<TvRequests> Get();
|
||||||
|
IQueryable<TvRequests> Get(string userId);
|
||||||
Task<TvRequests> GetRequestAsync(int tvDbId);
|
Task<TvRequests> GetRequestAsync(int tvDbId);
|
||||||
TvRequests GetRequest(int tvDbId);
|
TvRequests GetRequest(int tvDbId);
|
||||||
Task Update(TvRequests request);
|
Task Update(TvRequests request);
|
||||||
Task UpdateChild(ChildRequests request);
|
Task UpdateChild(ChildRequests request);
|
||||||
IQueryable<ChildRequests> GetChild();
|
IQueryable<ChildRequests> GetChild();
|
||||||
|
IQueryable<ChildRequests> GetChild(string userId);
|
||||||
Task Save();
|
Task Save();
|
||||||
Task DeleteChildRange(IEnumerable<ChildRequests> request);
|
Task DeleteChildRange(IEnumerable<ChildRequests> request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,11 @@ namespace Ombi.Store.Repository.Requests
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IQueryable<MovieRequests> GetAll(string userId)
|
||||||
|
{
|
||||||
|
return GetWithUser().Where(x => x.RequestedUserId == userId);
|
||||||
|
}
|
||||||
|
|
||||||
public MovieRequests GetRequest(int theMovieDbId)
|
public MovieRequests GetRequest(int theMovieDbId)
|
||||||
{
|
{
|
||||||
return Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
return Db.MovieRequests.Where(x => x.TheMovieDbId == theMovieDbId)
|
||||||
|
@ -48,6 +53,16 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IQueryable<MovieRequests> GetWithUser(string userId)
|
||||||
|
{
|
||||||
|
return Db.MovieRequests
|
||||||
|
.Where(x => x.RequestedUserId == userId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.ThenInclude(x => x.NotificationUserIds)
|
||||||
|
.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Update(MovieRequests request)
|
public async Task Update(MovieRequests request)
|
||||||
{
|
{
|
||||||
if (Db.Entry(request).State == EntityState.Detached)
|
if (Db.Entry(request).State == EntityState.Detached)
|
||||||
|
|
|
@ -48,6 +48,18 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.ThenInclude(x => x.Episodes)
|
.ThenInclude(x => x.Episodes)
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IQueryable<TvRequests> Get(string userId)
|
||||||
|
{
|
||||||
|
return Db.TvRequests
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.RequestedUser)
|
||||||
|
.Include(x => x.ChildRequests)
|
||||||
|
.ThenInclude(x => x.SeasonRequests)
|
||||||
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.Where(x => x.ChildRequests.Any(a => a.RequestedUserId == userId))
|
||||||
|
.AsQueryable();
|
||||||
|
}
|
||||||
public IQueryable<ChildRequests> GetChild()
|
public IQueryable<ChildRequests> GetChild()
|
||||||
{
|
{
|
||||||
return Db.ChildRequests
|
return Db.ChildRequests
|
||||||
|
@ -58,6 +70,17 @@ namespace Ombi.Store.Repository.Requests
|
||||||
.AsQueryable();
|
.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IQueryable<ChildRequests> GetChild(string userId)
|
||||||
|
{
|
||||||
|
return Db.ChildRequests
|
||||||
|
.Where(x => x.RequestedUserId == userId)
|
||||||
|
.Include(x => x.RequestedUser)
|
||||||
|
.Include(x => x.ParentRequest)
|
||||||
|
.Include(x => x.SeasonRequests)
|
||||||
|
.ThenInclude(x => x.Episodes)
|
||||||
|
.AsQueryable();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Save()
|
public async Task Save()
|
||||||
{
|
{
|
||||||
await Db.SaveChangesAsync();
|
await Db.SaveChangesAsync();
|
||||||
|
|
|
@ -14,6 +14,7 @@ export interface IOmbiSettings extends ISettings {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
ignoreCertificateErrors: boolean;
|
ignoreCertificateErrors: boolean;
|
||||||
doNotSendNotificationsForAutoApprove: boolean;
|
doNotSendNotificationsForAutoApprove: boolean;
|
||||||
|
hideRequestsUsers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUpdateSettings extends ISettings {
|
export interface IUpdateSettings extends ISettings {
|
||||||
|
|
|
@ -13,15 +13,15 @@
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('issue.status')">
|
<th (click)="setOrder('status')">
|
||||||
<a [translate]="'Issues.Status'"></a>
|
<a [translate]="'Issues.Status'"></a>
|
||||||
<span *ngIf="order === 'issue.status'">
|
<span *ngIf="order === 'status'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('issue.reportedUser')">
|
<th (click)="setOrder('reportedUser')">
|
||||||
<a [translate]="'Issues.ReportedBy'"></a>
|
<a [translate]="'Issues.ReportedBy'"></a>
|
||||||
<span *ngIf="order === 'issue.reportedUser'">
|
<span *ngIf="order === 'reportedUser'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
|
|
|
@ -4,9 +4,49 @@
|
||||||
<input type="text" id="search" class="form-control form-control-custom searchwidth" placeholder="Search" (keyup)="search($event)">
|
<input type="text" id="search" class="form-control form-control-custom searchwidth" placeholder="Search" (keyup)="search($event)">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button id="filterBtn" class="btn btn-sm btn-info-outline" (click)="filterDisplay = !filterDisplay" >
|
<button id="filterBtn" class="btn btn-sm btn-info-outline" (click)="filterDisplay = !filterDisplay" >
|
||||||
<i class="fa fa-filter"></i> {{ 'Requests.Filter' | translate }}</button>
|
<i class="fa fa-filter"></i> {{ 'Requests.Filter' | translate }}
|
||||||
<!-- <button id="filterBtn" class="btn btn-sm btn-warning-outline" (click)="sortDisplay = !sortDisplay" >
|
</button>
|
||||||
<i class="fa fa-sort"></i> {{ 'Requests.Sort' | translate }}</button> -->
|
|
||||||
|
|
||||||
|
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||||
|
<i class="fa fa-sort"></i> {{ 'Requests.Sort' | translate }}
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
|
||||||
|
<li>
|
||||||
|
<a (click)="setOrder('requestedDate')">{{ 'Requests.SortRequestDate' | translate }}
|
||||||
|
<span *ngIf="order === 'requestedDate'">
|
||||||
|
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||||
|
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a (click)="setOrder('title')">{{ 'Requests.SortTitle' | translate}}
|
||||||
|
<span *ngIf="order === 'title'">
|
||||||
|
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||||
|
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a (click)="setOrder('releaseDate')">{{ 'Requests.TheatricalReleaseSort' | translate }}
|
||||||
|
<span *ngIf="order === 'releaseDate'">
|
||||||
|
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||||
|
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a (click)="setOrder('requestedUser.userAlias')">{{ 'Requests.SortRequestedBy' | translate }}
|
||||||
|
<span *ngIf="order === 'requestedUser.userAlias'">
|
||||||
|
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||||
|
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a (click)="setOrder('status')">{{ 'Requests.SortStatus' | translate }}
|
||||||
|
<span *ngIf="order === 'status'">
|
||||||
|
<span [hidden]="reverse"><small><i class="fa fa-arrow-down" aria-hidden="true"></i></small></span>
|
||||||
|
<span [hidden]="!reverse"><small><i class="fa fa-arrow-up" aria-hidden="true"></i></small></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +59,7 @@
|
||||||
<div infinite-scroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="100" (scrolled)="loadMore()">
|
<div infinite-scroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="100" (scrolled)="loadMore()">
|
||||||
|
|
||||||
|
|
||||||
<div *ngFor="let request of movieRequests">
|
<div *ngFor="let request of movieRequests | orderBy: order : reverse : 'case-insensitive'">
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -203,8 +243,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
<input type="radio" id="approved" name="Status" (click)="filterStatus(filterType.PendingApproval)">
|
<input type="radio" id="pendingApproval" name="Status" (click)="filterStatus(filterType.PendingApproval, $event)">
|
||||||
<label for="approved">{{ 'Filter.PendingApproval' | translate }}</label>
|
<label for="pendingApproval">{{ 'Filter.PendingApproval' | translate }}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@ export class MovieRequestsComponent implements OnInit {
|
||||||
public filter: IFilter;
|
public filter: IFilter;
|
||||||
public filterType = FilterType;
|
public filterType = FilterType;
|
||||||
|
|
||||||
public sortDisplay: boolean;
|
public order: string = "requestedDate";
|
||||||
|
public reverse = false;
|
||||||
|
|
||||||
private currentlyLoaded: number;
|
private currentlyLoaded: number;
|
||||||
private amountToLoad: number;
|
private amountToLoad: number;
|
||||||
|
@ -174,6 +175,14 @@ export class MovieRequestsComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setOrder(value: string) {
|
||||||
|
if (this.order === value) {
|
||||||
|
this.reverse = !this.reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.order = value;
|
||||||
|
}
|
||||||
|
|
||||||
private loadRequests(amountToLoad: number, currentlyLoaded: number) {
|
private loadRequests(amountToLoad: number, currentlyLoaded: number) {
|
||||||
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1)
|
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded + 1)
|
||||||
.subscribe(x => {
|
.subscribe(x => {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||||
|
import { OrderModule } from "ngx-order-pipe";
|
||||||
|
|
||||||
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ const routes: Routes = [
|
||||||
TreeTableModule,
|
TreeTableModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
SidebarModule,
|
SidebarModule,
|
||||||
|
OrderModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
RequestComponent,
|
RequestComponent,
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
<div class="col-sm-8 small-padding">
|
<div class="col-sm-8 small-padding">
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<a href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank">
|
<a *ngIf="node.data.imdbId" href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank">
|
||||||
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
|
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -53,6 +53,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" id="hideRequestsUsers" name="hideRequestsUsers" formControlName="hideRequestsUsers">
|
||||||
|
<label for="hideRequestsUsers">Hide requests from other users</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<input type="checkbox" id="ignoreCertificateErrors" name="ignoreCertificateErrors" formControlName="ignoreCertificateErrors">
|
<input type="checkbox" id="ignoreCertificateErrors" name="ignoreCertificateErrors" formControlName="ignoreCertificateErrors">
|
||||||
|
|
|
@ -24,6 +24,7 @@ export class OmbiComponent implements OnInit {
|
||||||
ignoreCertificateErrors: [x.ignoreCertificateErrors],
|
ignoreCertificateErrors: [x.ignoreCertificateErrors],
|
||||||
baseUrl: [x.baseUrl],
|
baseUrl: [x.baseUrl],
|
||||||
doNotSendNotificationsForAutoApprove: [x.doNotSendNotificationsForAutoApprove],
|
doNotSendNotificationsForAutoApprove: [x.doNotSendNotificationsForAutoApprove],
|
||||||
|
hideRequestsUsers: [x.hideRequestsUsers],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,44 +16,45 @@
|
||||||
</td>
|
</td>
|
||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('u.userName')">
|
<th (click)="setOrder('userName')">
|
||||||
<a>
|
<a>
|
||||||
Username
|
Username
|
||||||
</a>
|
</a>
|
||||||
<span *ngIf="order === 'u.userName'">
|
<span *ngIf="order === 'userName'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('u.alias')">
|
<th (click)="setOrder('alias')">
|
||||||
<a>
|
<a>
|
||||||
Alias
|
Alias
|
||||||
</a>
|
</a>
|
||||||
<span *ngIf="order === 'u.alias'">
|
<span *ngIf="order === 'alias'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('u.emailAddress')">
|
<th (click)="setOrder('emailAddress')">
|
||||||
<a>
|
<a>
|
||||||
Email
|
Email
|
||||||
</a>
|
</a>
|
||||||
<span *ngIf="order === 'u.emailAddress'">
|
<span *ngIf="order === 'emailAddress'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span>
|
||||||
|
<span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Roles
|
Roles
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('u.lastLoggedIn')">
|
<th (click)="setOrder('lastLoggedIn')">
|
||||||
<a> Last Logged In</a>
|
<a> Last Logged In</a>
|
||||||
<span *ngIf="order === 'u.lastLoggedIn'">
|
<span *ngIf="order === 'lastLoggedIn'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
<th (click)="setOrder('u.userType')">
|
<th (click)="setOrder('userType')">
|
||||||
<a>
|
<a>
|
||||||
User Type
|
User Type
|
||||||
</a>
|
</a>
|
||||||
<span *ngIf="order === 'u.userType'">
|
<span *ngIf="order === 'userType'">
|
||||||
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</th>
|
||||||
|
|
|
@ -13,7 +13,7 @@ export class UserManagementComponent implements OnInit {
|
||||||
public emailSettings: IEmailNotificationSettings;
|
public emailSettings: IEmailNotificationSettings;
|
||||||
public customizationSettings: ICustomizationSettings;
|
public customizationSettings: ICustomizationSettings;
|
||||||
|
|
||||||
public order: string = "u.userName";
|
public order: string = "userName";
|
||||||
public reverse = false;
|
public reverse = false;
|
||||||
|
|
||||||
public showBulkEdit = false;
|
public showBulkEdit = false;
|
||||||
|
|
|
@ -334,9 +334,9 @@ namespace Ombi.Controllers
|
||||||
/// <param name="vm"></param>
|
/// <param name="vm"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("movie/filter")]
|
[HttpPost("movie/filter")]
|
||||||
public IEnumerable<MovieRequests> Filter([FromBody] FilterViewModel vm)
|
public async Task<IEnumerable<MovieRequests>> Filter([FromBody] FilterViewModel vm)
|
||||||
{
|
{
|
||||||
return MovieRequestEngine.Filter(vm);
|
return await MovieRequestEngine.Filter(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
BIN
src/Ombi/Ombi.testdb
Normal file
BIN
src/Ombi/Ombi.testdb
Normal file
Binary file not shown.
6
src/Ombi/package-lock.json
generated
6
src/Ombi/package-lock.json
generated
|
@ -4972,9 +4972,9 @@
|
||||||
"integrity": "sha512-7lASze8zHSDdAAFO3VNop1TY60rs8A7sm8DzQfU33VNcJI27F6mtxwjILIH339s7m6HVC08AS7I64HBjBMw/QQ=="
|
"integrity": "sha512-7lASze8zHSDdAAFO3VNop1TY60rs8A7sm8DzQfU33VNcJI27F6mtxwjILIH339s7m6HVC08AS7I64HBjBMw/QQ=="
|
||||||
},
|
},
|
||||||
"ngx-order-pipe": {
|
"ngx-order-pipe": {
|
||||||
"version": "1.1.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ngx-order-pipe/-/ngx-order-pipe-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ngx-order-pipe/-/ngx-order-pipe-2.0.1.tgz",
|
||||||
"integrity": "sha512-hIfdUONbKG14/S5zEyGjr1ukAd2XdUUnUsvA80ct3pyoBCh5aQ7XhBz7N9jCsVzMGTGUPK6R59KYkEPB3n5hbQ=="
|
"integrity": "sha512-t0IUqoNs3705yZQeohmhUQvpiRTj5RX7AhFXkx3PMfq7G6h7GNNrR3x27XbXEsjKgBo5hPgfEfW5OljRYa1VVw=="
|
||||||
},
|
},
|
||||||
"ngx-window-token": {
|
"ngx-window-token": {
|
||||||
"version": "0.0.4",
|
"version": "0.0.4",
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"@angular/platform-browser-dynamic": "^5.1.2",
|
"@angular/platform-browser-dynamic": "^5.1.2",
|
||||||
"@angular/platform-server": "5.0.0",
|
"@angular/platform-server": "5.0.0",
|
||||||
"@angular/router": "^5.1.2",
|
"@angular/router": "^5.1.2",
|
||||||
"@auth0/angular-jwt": "^1.0.0-beta.9",
|
"@auth0/angular-jwt": "1.0.0-beta.9",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.8",
|
"@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.8",
|
||||||
"@ngx-translate/core": "^8.0.0",
|
"@ngx-translate/core": "^8.0.0",
|
||||||
"@ngx-translate/http-loader": "^2.0.1",
|
"@ngx-translate/http-loader": "^2.0.1",
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
"ng2-cookies": "^1.0.12",
|
"ng2-cookies": "^1.0.12",
|
||||||
"ngx-clipboard": "8.1.1",
|
"ngx-clipboard": "8.1.1",
|
||||||
"ngx-infinite-scroll": "^0.6.1",
|
"ngx-infinite-scroll": "^0.6.1",
|
||||||
"ngx-order-pipe": "^1.1.1",
|
"ngx-order-pipe": "^2.0.1",
|
||||||
"node-sass": "^4.7.2",
|
"node-sass": "^4.7.2",
|
||||||
"npm": "^5.6.0",
|
"npm": "^5.6.0",
|
||||||
"pace-progress": "^1.0.2",
|
"pace-progress": "^1.0.2",
|
||||||
|
|
|
@ -21,7 +21,11 @@
|
||||||
"Request": "Anmod",
|
"Request": "Anmod",
|
||||||
"Denied": "Afvist",
|
"Denied": "Afvist",
|
||||||
"Approve": "Godkendt",
|
"Approve": "Godkendt",
|
||||||
|
<<<<<<< HEAD
|
||||||
"PartlyAvailable": "Delvist tilgængelig",
|
"PartlyAvailable": "Delvist tilgængelig",
|
||||||
|
=======
|
||||||
|
"PartlyAvailable": "Partly Available",
|
||||||
|
>>>>>>> New translations en.json (Danish)
|
||||||
"Errors": {
|
"Errors": {
|
||||||
"Validation": "Tjek venligst dine indtastede værdier"
|
"Validation": "Tjek venligst dine indtastede værdier"
|
||||||
}
|
}
|
||||||
|
@ -87,6 +91,7 @@
|
||||||
"Trailer": "Trailer"
|
"Trailer": "Trailer"
|
||||||
},
|
},
|
||||||
"TvShows": {
|
"TvShows": {
|
||||||
|
<<<<<<< HEAD
|
||||||
"Popular": "Populære",
|
"Popular": "Populære",
|
||||||
"Trending": "Aktuelle",
|
"Trending": "Aktuelle",
|
||||||
"MostWatched": "Mest sete",
|
"MostWatched": "Mest sete",
|
||||||
|
@ -100,6 +105,18 @@
|
||||||
"SubmitRequest": "Send anmodning",
|
"SubmitRequest": "Send anmodning",
|
||||||
"Season": "Sæson: {{seasonNumber}}",
|
"Season": "Sæson: {{seasonNumber}}",
|
||||||
"SelectAllInSeason": "Vælg alle i sæson {{seasonNumber}}"
|
"SelectAllInSeason": "Vælg alle i sæson {{seasonNumber}}"
|
||||||
|
=======
|
||||||
|
"Popular": "Popular",
|
||||||
|
"Trending": "Trending",
|
||||||
|
"MostWatched": "Most Watched",
|
||||||
|
"MostAnticipated": "Most Anticipated",
|
||||||
|
"Results": "Results",
|
||||||
|
"AirDate": "Air Date:",
|
||||||
|
"AllSeasons": "All Seasons",
|
||||||
|
"FirstSeason": "First Season",
|
||||||
|
"LatestSeason": "Latest Season",
|
||||||
|
"Select": "Select ..."
|
||||||
|
>>>>>>> New translations en.json (Danish)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Requests": {
|
"Requests": {
|
||||||
|
|
|
@ -117,6 +117,7 @@
|
||||||
"RequestStatus": "Request status:",
|
"RequestStatus": "Request status:",
|
||||||
"Denied": " Denied:",
|
"Denied": " Denied:",
|
||||||
"TheatricalRelease": "Theatrical Release: {{date}}",
|
"TheatricalRelease": "Theatrical Release: {{date}}",
|
||||||
|
"TheatricalReleaseSort": "Theatrical Release",
|
||||||
"DigitalRelease": "Digital Release: {{date}}",
|
"DigitalRelease": "Digital Release: {{date}}",
|
||||||
"RequestDate": "Request Date:",
|
"RequestDate": "Request Date:",
|
||||||
"QualityOverride": "Quality Override:",
|
"QualityOverride": "Quality Override:",
|
||||||
|
@ -134,7 +135,11 @@
|
||||||
"ReportIssue":"Report Issue",
|
"ReportIssue":"Report Issue",
|
||||||
"Filter":"Filter",
|
"Filter":"Filter",
|
||||||
"Sort":"Sort",
|
"Sort":"Sort",
|
||||||
"SeasonNumberHeading":"Season: {seasonNumber}"
|
"SeasonNumberHeading":"Season: {seasonNumber}",
|
||||||
|
"SortTitle":"Title",
|
||||||
|
"SortRequestDate": "Request Date",
|
||||||
|
"SortRequestedBy":"Requested By",
|
||||||
|
"SortStatus":"Status"
|
||||||
},
|
},
|
||||||
"Issues":{
|
"Issues":{
|
||||||
"Title":"Issues",
|
"Title":"Issues",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue