pull/1425/head
Jamie.Rees 8 years ago
parent 596008b06c
commit 5b49d03f85

@ -17,7 +17,7 @@ namespace Ombi.Api
{ {
private TraktClient Client { get; } private TraktClient Client { get; }
private static readonly string Encrypted = "z/56wM/oEkkCWEvSIZCrzQyUvvqmafQ3njqf0UNK5xuKbNYh5Wz8ocoG2QDa5y1DBkozLaKsGxORmAB1XUvwbnom8DVNo9gE++9GTuwxmGlLDD318PXpRmYmpKqNwFSKRZgF6ewiY9qR4t3iG0pGQwPA08FK3+H7kpOKAGJNR9RMDP9wwB6Vl4DuOiZb9/DETjzZ+/zId0ZqimrbN+PLrg=="; private static readonly string Encrypted = "134e568350f7427511e257a6534026660480cf9b93c77f7378f340603b67381d";
private readonly string _apiKey = StringCipher.Decrypt(Encrypted, "ApiKey"); private readonly string _apiKey = StringCipher.Decrypt(Encrypted, "ApiKey");
public TraktApi() public TraktApi()
{ {

@ -0,0 +1,16 @@
//using System.Collections.Generic;
//using System.Threading.Tasks;
//using TraktApiSharp.Enums;
//using TraktApiSharp.Objects.Get.Shows;
//using TraktApiSharp.Objects.Get.Shows.Common;
//namespace Ombi.Api.Trakt
//{
// public interface ITraktApi
// {
// Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = default(int?), int? limitPerPage = default(int?));
// Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?));
// Task<IEnumerable<TraktShow>> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?));
// Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?));
// }
//}

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ombi.Api\Ombi.Api.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,49 @@
//using System;
//using System.Collections.Generic;
//using System.Threading.Tasks;
//using Ombi.Helpers;
//using TraktApiSharp;
//using TraktApiSharp.Enums;
//using TraktApiSharp.Objects.Get.Shows;
//using TraktApiSharp.Objects.Get.Shows.Common;
//using TraktApiSharp.Requests.Parameters;
//namespace Ombi.Api.Trakt
//{
// public class TraktApi : ITraktApi
// {
// private TraktClient Client { get; }
// private static readonly string Encrypted = "MTM0ZTU2ODM1MGY3NDI3NTExZTI1N2E2NTM0MDI2NjYwNDgwY2Y5YjkzYzc3ZjczNzhmMzQwNjAzYjY3MzgxZA==";
// private readonly string _apiKey = StringCipher.DecryptString(Encrypted, "ApiKey");
// public TraktApi()
// {
// Client = new TraktClient(_apiKey);
// }
// public async Task<IEnumerable<TraktShow>> GetPopularShows(int? page = null, int? limitPerPage = null)
// {
// var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
// return popular.Value;
// }
// public async Task<IEnumerable<TraktTrendingShow>> GetTrendingShows(int? page = null, int? limitPerPage = null)
// {
// var trendingShowsTop10 = await Client.Shows.GetTrendingShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
// return trendingShowsTop10.Value;
// }
// public async Task<IEnumerable<TraktMostAnticipatedShow>> GetAnticipatedShows(int? page = null, int? limitPerPage = null)
// {
// var anticipatedShows = await Client.Shows.GetMostAnticipatedShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
// return anticipatedShows.Value;
// }
// public async Task<IEnumerable<TraktMostWatchedShow>> GetMostWatchesShows(TraktTimePeriod period = null, int? page = null, int? limitPerPage = null)
// {
// var anticipatedShows = await Client.Shows.GetMostWatchedShowsAsync(period ?? TraktTimePeriod.Monthly, new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10);
// return anticipatedShows.Value;
// }
// }
//}

@ -20,7 +20,6 @@ namespace Ombi.Api.TvMaze
var request = new Request("search/shows", Uri, HttpMethod.Get); var request = new Request("search/shows", Uri, HttpMethod.Get);
request.AddQueryString("q", searchTerm); request.AddQueryString("q", searchTerm);
//request.ContentHeaders.Add("Content-Type", "application/json");
request.ContentHeaders.Add(new KeyValuePair<string, string>("Content-Type","application/json")); request.ContentHeaders.Add(new KeyValuePair<string, string>("Content-Type","application/json"));
return await Api.Request<List<TvMazeSearch>>(request); return await Api.Request<List<TvMazeSearch>>(request);

@ -5,76 +5,52 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Core.Claims; using Ombi.Core.Claims;
using Ombi.Core.Engine.Interfaces; using Ombi.Core.Engine.Interfaces;
using Ombi.Core.IdentityResolver;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Store.Entities;
namespace Ombi.Core.Engine namespace Ombi.Core.Engine
{ {
public abstract class BaseMediaEngine : BaseEngine public abstract class BaseMediaEngine : BaseEngine
{ {
protected BaseMediaEngine(IPrincipal identity, IRequestService service) : base(identity) protected BaseMediaEngine(IPrincipal identity, IRequestServiceMain requestService) : base(identity)
{ {
RequestService = service; RequestService = requestService;
} }
protected IRequestService RequestService { get; } protected IRequestServiceMain RequestService { get; }
protected IRequestService<MovieRequestModel> MovieRequestService => RequestService.MovieRequestService;
protected IRequestService<TvRequestModel> TvRequestService => RequestService.TvRequestService;
private long _dbMovieCacheTime = 0; private long _cacheTime = 0;
private Dictionary<int, RequestModel> _dbMovies; private Dictionary<int, MovieRequestModel> _dbMovies;
protected async Task<Dictionary<int, RequestModel>> GetRequests(RequestType type) private Dictionary<int, TvRequestModel> _dbTv;
protected async Task<Dictionary<int, MovieRequestModel>> GetMovieRequests()
{ {
long now = DateTime.Now.Ticks; long now = DateTime.Now.Ticks;
if (_dbMovies == null || (now - _dbMovieCacheTime) > 10000) if (_dbMovies == null || (now - _cacheTime) > 10000)
{ {
var allResults = await RequestService.GetAllAsync(); var allResults = await MovieRequestService.GetAllAsync();
allResults = allResults.Where(x => x.Type == type);
var distinctResults = allResults.DistinctBy(x => x.ProviderId); var distinctResults = allResults.DistinctBy(x => x.ProviderId);
_dbMovies = distinctResults.ToDictionary(x => x.ProviderId); _dbMovies = distinctResults.ToDictionary(x => x.ProviderId);
_dbMovieCacheTime = now; _cacheTime = now;
} }
return _dbMovies; return _dbMovies;
} }
public async Task<IEnumerable<RequestViewModel>> GetRequests() protected async Task<Dictionary<int, TvRequestModel>> GetTvRequests()
{ {
var allRequests = await RequestService.GetAllAsync(); long now = DateTime.Now.Ticks;
var viewModel = MapToVm(allRequests); if (_dbTv == null || (now - _cacheTime) > 10000)
return viewModel;
}
protected IEnumerable<RequestViewModel> MapToVm(IEnumerable<RequestModel> model)
{
return model.Select(movie => new RequestViewModel
{ {
ProviderId = movie.ProviderId, var allResults = await TvRequestService.GetAllAsync();
Type = movie.Type,
Status = movie.Status, var distinctResults = allResults.DistinctBy(x => x.ProviderId);
ImdbId = movie.ImdbId, _dbTv = distinctResults.ToDictionary(x => x.ProviderId);
Id = movie.Id, _cacheTime = now;
PosterPath = movie.PosterPath, }
ReleaseDate = movie.ReleaseDate, return _dbTv;
RequestedDate = movie.RequestedDate,
Released = DateTime.Now > movie.ReleaseDate,
Approved = movie.Available || movie.Approved,
Title = movie.Title,
Overview = movie.Overview,
RequestedUsers = movie.AllUsers.ToArray(),
ReleaseYear = movie.ReleaseDate.Year.ToString(),
Available = movie.Available,
Admin = HasRole(OmbiClaims.Admin),
IssueId = movie.IssueId,
Denied = movie.Denied,
DeniedReason = movie.DeniedReason,
//Qualities = qualities.ToArray(),
//HasRootFolders = rootFolders.Any(),
//RootFolders = rootFolders.ToArray(),
//CurrentRootPath = radarr.Enabled ? GetRootPath(movie.RootFolderSelected, radarr).Result : null
}).ToList();
} }
} }
} }

@ -10,10 +10,9 @@ namespace Ombi.Core.Engine
{ {
Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model); Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model);
bool ShouldAutoApprove(RequestType requestType); bool ShouldAutoApprove(RequestType requestType);
Task<IEnumerable<RequestViewModel>> GetRequests(); Task<IEnumerable<MovieRequestModel>> GetMovieRequests(int count, int position);
Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position); Task<IEnumerable<MovieRequestModel>> SearchMovieRequest(string search);
Task<IEnumerable<RequestViewModel>> SearchRequest(string search); Task RemoveMovieRequest(int requestId);
Task RemoveRequest(int requestId); Task<MovieRequestModel> UpdateMovieRequest(MovieRequestModel request);
Task<RequestViewModel> UpdateRequest(RequestViewModel request);
} }
} }

@ -7,5 +7,9 @@ namespace Ombi.Core.Engine
public interface ITvSearchEngine public interface ITvSearchEngine
{ {
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm); Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
//Task<IEnumerable<SearchTvShowViewModel>> Popular();
//Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
//Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
//Task<IEnumerable<SearchTvShowViewModel>> Trending();
} }
} }

@ -19,7 +19,7 @@ namespace Ombi.Core.Engine
public class MovieSearchEngine : BaseMediaEngine, IMovieEngine public class MovieSearchEngine : BaseMediaEngine, IMovieEngine
{ {
public MovieSearchEngine(IPrincipal identity, IRequestService service, IMovieDbApi movApi, IMapper mapper, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings, public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings,
ILogger<MovieSearchEngine> logger) ILogger<MovieSearchEngine> logger)
: base(identity, service) : base(identity, service)
{ {
@ -46,7 +46,7 @@ namespace Ombi.Core.Engine
} }
var retVal = new List<SearchMovieViewModel>(); var retVal = new List<SearchMovieViewModel>();
Dictionary<int, RequestModel> dbMovies = await GetRequests(RequestType.Movie); Dictionary<int, MovieRequestModel> dbMovies = await GetMovieRequests();
var plexSettings = await PlexSettings.GetSettingsAsync(); var plexSettings = await PlexSettings.GetSettingsAsync();
@ -120,7 +120,7 @@ namespace Ombi.Core.Engine
private async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(IEnumerable<MovieSearchResult> movies) private async Task<List<SearchMovieViewModel>> TransformMovieResultsToResponse(IEnumerable<MovieSearchResult> movies)
{ {
var viewMovies = new List<SearchMovieViewModel>(); var viewMovies = new List<SearchMovieViewModel>();
Dictionary<int, RequestModel> dbMovies = await GetRequests(RequestType.Movie); Dictionary<int, MovieRequestModel> dbMovies = await GetMovieRequests();
var plexSettings = await PlexSettings.GetSettingsAsync(); var plexSettings = await PlexSettings.GetSettingsAsync();
var embySettings = await EmbySettings.GetSettingsAsync(); var embySettings = await EmbySettings.GetSettingsAsync();
@ -134,7 +134,7 @@ namespace Ombi.Core.Engine
} }
private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie, private async Task<SearchMovieViewModel> ProcessSingleMovie(SearchMovieViewModel viewMovie,
Dictionary<int, RequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) Dictionary<int, MovieRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
if (plexSettings.Enable) if (plexSettings.Enable)
{ {
@ -176,7 +176,7 @@ namespace Ombi.Core.Engine
return viewMovie; return viewMovie;
} }
private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieSearchResult movie, Dictionary<int, RequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) private async Task<SearchMovieViewModel> ProcessSingleMovie(MovieSearchResult movie, Dictionary<int, MovieRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
var viewMovie = Mapper.Map<SearchMovieViewModel>(movie); var viewMovie = Mapper.Map<SearchMovieViewModel>(movie);
return await ProcessSingleMovie(viewMovie, existingRequests, plexSettings, embySettings); return await ProcessSingleMovie(viewMovie, existingRequests, plexSettings, embySettings);

@ -6,6 +6,7 @@ using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire; using Hangfire;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
using Ombi.Api.TvMaze;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
@ -18,13 +19,15 @@ namespace Ombi.Core.Engine
{ {
public class RequestEngine : BaseMediaEngine, IRequestEngine public class RequestEngine : BaseMediaEngine, IRequestEngine
{ {
public RequestEngine(IMovieDbApi movieApi, IRequestService requestService, IPrincipal user, INotificationService notificationService) : base(user, requestService) public RequestEngine(IMovieDbApi movieApi, ITvMazeApi tvApi, IRequestServiceMain requestService, IPrincipal user, INotificationService notificationService) : base(user, requestService)
{ {
MovieApi = movieApi; MovieApi = movieApi;
TvApi = tvApi;
NotificationService = notificationService; NotificationService = notificationService;
} }
private IMovieDbApi MovieApi { get; } private IMovieDbApi MovieApi { get; }
private INotificationService NotificationService { get; } private INotificationService NotificationService { get; }
private ITvMazeApi TvApi { get; }
public async Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model) public async Task<RequestEngineResult> RequestMovie(SearchMovieViewModel model)
{ {
var movieInfo = await MovieApi.GetMovieInformation(model.Id); var movieInfo = await MovieApi.GetMovieInformation(model.Id);
@ -40,7 +43,7 @@ namespace Ombi.Core.Engine
var fullMovieName = var fullMovieName =
$"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}"; $"{movieInfo.Title}{(!string.IsNullOrEmpty(movieInfo.ReleaseDate) ? $" ({DateTime.Parse(movieInfo.ReleaseDate).Year})" : string.Empty)}";
var existingRequest = await RequestService.CheckRequestAsync(model.Id); var existingRequest = await MovieRequestService.CheckRequestAsync(model.Id);
if (existingRequest != null) if (existingRequest != null)
{ {
return new RequestEngineResult return new RequestEngineResult
@ -78,7 +81,7 @@ namespace Ombi.Core.Engine
// }); // });
//} //}
var requestModel = new RequestModel var requestModel = new MovieRequestModel
{ {
ProviderId = movieInfo.Id, ProviderId = movieInfo.Id,
Type = RequestType.Movie, Type = RequestType.Movie,
@ -130,7 +133,7 @@ namespace Ombi.Core.Engine
} }
return await AddRequest(requestModel, /*settings,*/ return await AddMovieRequest(requestModel, /*settings,*/
$"{fullMovieName} has been successfully added!"); $"{fullMovieName} has been successfully added!");
} }
@ -158,10 +161,58 @@ namespace Ombi.Core.Engine
return null; return null;
} }
public async Task<RequestEngineResult> RequestTvShow(SearchTvShowViewModel tv)
{
var showInfo = await TvApi.ShowLookupByTheTvDbId(tv.Id);
DateTime.TryParse(showInfo.premiered, out DateTime firstAir);
private async Task<RequestEngineResult> AddRequest(RequestModel model, string message) string fullShowName = $"{showInfo.name} ({firstAir.Year})";
// For some reason the poster path is always http
var posterPath = showInfo.image?.medium.Replace("http:", "https:");
var model = new TvRequestModel
{ {
await RequestService.AddRequestAsync(model); Type = RequestType.TvShow,
Overview = showInfo.summary.RemoveHtml(),
PosterPath = posterPath,
Title = showInfo.name,
ReleaseDate = firstAir,
Status = showInfo.status,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUsers = new List<string> { Username },
Issues = IssueState.None,
ImdbId = showInfo.externals?.imdb ?? string.Empty,
TvDbId = tv.Id.ToString(),
ProviderId = tv.Id,
SeasonsNumbersRequested = tv.SeasonNumbersRequested,
RequestAll = tv.RequestAll
};
var existingRequest = await TvRequestService.CheckRequestAsync(model.Id);
existingRequest?.ChildRequests.Add(model);
return null;
}
private IEnumerable<EpisodesModel> GetListDifferences(IEnumerable<EpisodesModel> existing, IEnumerable<EpisodesModel> request)
{
var newRequest = request
.Select(r =>
new EpisodesModel
{
SeasonNumber = r.SeasonNumber,
EpisodeNumber = r.EpisodeNumber
}).ToList();
return newRequest.Except(existing);
}
private async Task<RequestEngineResult> AddMovieRequest(MovieRequestModel model, string message)
{
await MovieRequestService.AddRequestAsync(model);
if (ShouldSendNotification(model.Type)) if (ShouldSendNotification(model.Type))
{ {
@ -196,53 +247,46 @@ namespace Ombi.Core.Engine
// await RequestLimitRepo.UpdateAsync(usersLimit); // await RequestLimitRepo.UpdateAsync(usersLimit);
//} //}
return new RequestEngineResult{RequestAdded = true}; return new RequestEngineResult { RequestAdded = true };
} }
public async Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position) public async Task<IEnumerable<MovieRequestModel>> GetMovieRequests(int count, int position)
{ {
var allRequests = await RequestService.GetAllAsync(count, position); var allRequests = await MovieRequestService.GetAllAsync(count, position);
var viewModel = MapToVm(allRequests); return allRequests;
return viewModel;
} }
public async Task<IEnumerable<RequestViewModel>> SearchRequest(string search) public async Task<IEnumerable<MovieRequestModel>> SearchMovieRequest(string search)
{ {
var allRequests = await RequestService.GetAllAsync(); var allRequests = await MovieRequestService.GetAllAsync();
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)); var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase));
var viewModel = MapToVm(results); return results;
return viewModel;
} }
public async Task<RequestViewModel> UpdateRequest(RequestViewModel request) public async Task<MovieRequestModel> UpdateMovieRequest(MovieRequestModel request)
{ {
var allRequests = await RequestService.GetAllAsync(); var allRequests = await MovieRequestService.GetAllAsync();
var results = allRequests.FirstOrDefault(x => x.Id == request.Id); var results = allRequests.FirstOrDefault(x => x.Id == request.Id);
results.Approved = request.Approved; results.Approved = request.Approved;
results.Available = request.Available; results.Available = request.Available;
results.Denied = request.Denied; results.Denied = request.Denied;
results.DeniedReason = request.DeniedReason; results.DeniedReason = request.DeniedReason;
//results.AdminNote = request.AdminNote; results.AdminNote = request.AdminNote;
results.ImdbId = request.ImdbId; results.ImdbId = request.ImdbId;
results.Episodes = request.Episodes?.ToList() ?? new List<EpisodesModel>();
results.IssueId = request.IssueId; results.IssueId = request.IssueId;
//results.Issues = request.Issues; results.Issues = request.Issues;
//results.OtherMessage = request.OtherMessage; results.OtherMessage = request.OtherMessage;
results.Overview = request.Overview; results.Overview = request.Overview;
results.PosterPath = request.PosterPath; results.PosterPath = request.PosterPath;
results.RequestedUsers = request.RequestedUsers?.ToList() ?? new List<string>(); results.RequestedUsers = request.RequestedUsers?.ToList() ?? new List<string>();
//results.RootFolderSelected = request.RootFolderSelected;
var model = RequestService.UpdateRequest(results); var model = MovieRequestService.UpdateRequest(results);
return MapToVm(new List<RequestModel>{model}).FirstOrDefault(); return model;
} }
public async Task RemoveRequest(int requestId) public async Task RemoveMovieRequest(int requestId)
{ {
await RequestService.DeleteRequestAsync(requestId); await MovieRequestService.DeleteRequestAsync(requestId);
} }
} }
} }

@ -3,8 +3,8 @@ using System.Linq;
using System.Security.Principal; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper; using AutoMapper;
//using Ombi.Api.Trakt;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Api.TvMaze.Models;
using Ombi.Core.Models.Requests; using Ombi.Core.Models.Requests;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Core.Requests.Models; using Ombi.Core.Requests.Models;
@ -17,19 +17,22 @@ namespace Ombi.Core.Engine
public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine public class TvSearchEngine : BaseMediaEngine, ITvSearchEngine
{ {
public TvSearchEngine(IPrincipal identity, IRequestService service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings, ISettingsService<EmbySettings> embySettings) public TvSearchEngine(IPrincipal identity, IRequestServiceMain service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService<PlexSettings> plexSettings,
ISettingsService<EmbySettings> embySettings/*, ITraktApi trakt*/)
: base(identity, service) : base(identity, service)
{ {
TvMazeApi = tvMaze; TvMazeApi = tvMaze;
Mapper = mapper; Mapper = mapper;
PlexSettings = plexSettings; PlexSettings = plexSettings;
EmbySettings = embySettings; EmbySettings = embySettings;
//TraktApi = trakt;
} }
private ITvMazeApi TvMazeApi { get; } private ITvMazeApi TvMazeApi { get; }
private IMapper Mapper { get; } private IMapper Mapper { get; }
private ISettingsService<PlexSettings> PlexSettings { get; } private ISettingsService<PlexSettings> PlexSettings { get; }
private ISettingsService<EmbySettings> EmbySettings { get; } private ISettingsService<EmbySettings> EmbySettings { get; }
//private ITraktApi TraktApi { get; }
public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm) public async Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm)
@ -43,9 +46,31 @@ namespace Ombi.Core.Engine
return null; return null;
} }
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults(IEnumerable<TvMazeSearch> items) //public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
//{
// var result = await TraktApi.GetPopularShows();
// return await ProcessResults(result);
//}
//public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
//{
// var result = await TraktApi.GetAnticipatedShows();
// return await ProcessResults(result);
//}
//public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
//{
// var result = await TraktApi.GetMostWatchesShows();
// return await ProcessResults(result);
//}
//public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
//{
// var result = await TraktApi.GetTrendingShows();
// return await ProcessResults(result);
//}
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
{ {
var existingRequests = await GetRequests(RequestType.TvShow); var existingRequests = await GetTvRequests();
var plexSettings = await PlexSettings.GetSettingsAsync(); var plexSettings = await PlexSettings.GetSettingsAsync();
var embySettings = await EmbySettings.GetSettingsAsync(); var embySettings = await EmbySettings.GetSettingsAsync();
@ -53,14 +78,14 @@ namespace Ombi.Core.Engine
var retVal = new List<SearchTvShowViewModel>(); var retVal = new List<SearchTvShowViewModel>();
foreach (var tvMazeSearch in items) foreach (var tvMazeSearch in items)
{ {
retVal.Add(ProcessResult(tvMazeSearch, existingRequests, plexSettings, embySettings)); var viewT = Mapper.Map<SearchTvShowViewModel>(tvMazeSearch);
retVal.Add(ProcessResult(viewT, existingRequests, plexSettings, embySettings));
} }
return retVal; return retVal;
} }
private SearchTvShowViewModel ProcessResult(TvMazeSearch item, Dictionary<int, RequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings) private SearchTvShowViewModel ProcessResult(SearchTvShowViewModel item, Dictionary<int, TvRequestModel> existingRequests, PlexSettings plexSettings, EmbySettings embySettings)
{ {
var viewT = Mapper.Map<SearchTvShowViewModel>(item);
if (embySettings.Enable) if (embySettings.Enable)
{ {
//var embyShow = EmbyChecker.GetTvShow(embyCached.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId); //var embyShow = EmbyChecker.GetTvShow(embyCached.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId);
@ -80,25 +105,25 @@ namespace Ombi.Core.Engine
//} //}
} }
if (item.show?.externals?.thetvdb != null && !viewT.Available) if (item.Id > 0 && item.Available)
{ {
var tvdbid = (int)item.show.externals.thetvdb; var tvdbid = item.Id;
if (existingRequests.ContainsKey(tvdbid)) if (existingRequests.ContainsKey(tvdbid))
{ {
var dbt = existingRequests[tvdbid]; var dbt = existingRequests[tvdbid];
viewT.Requested = true; item.Requested = true;
viewT.Episodes = dbt.Episodes.ToList(); item.EpisodesRequested = dbt.Episodes.ToList();
viewT.Approved = dbt.Approved; item.Approved = dbt.Approved;
} }
//if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid)) //if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid))
// // compare to the sonarr/sickrage db // // compare to the sonarr/sickrage db
//{ //{
// viewT.Requested = true; // item.Requested = true;
//} //}
} }
return viewT; return item;
} }
} }
} }

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Ombi.Store.Entities;
namespace Ombi.Core.Models.Requests
{
public class BaseRequestModel : Entity
{
public BaseRequestModel()
{
RequestedUsers = new List<string>();
}
public int ProviderId { get; set; }
public string Overview { get; set; }
public string Title { get; set; }
public string PosterPath { get; set; }
public DateTime ReleaseDate { get; set; }
public RequestType Type { get; set; }
public string Status { get; set; }
public bool Approved { get; set; }
public bool Admin { get; set; }
public DateTime RequestedDate { get; set; }
public bool Available { get; set; }
public IssueState Issues { get; set; }
public string OtherMessage { get; set; }
public string AdminNote { get; set; }
public List<string> RequestedUsers { get; set; }
public int IssueId { get; set; }
public bool Denied { get; set; }
public string DeniedReason { get; set; }
[JsonIgnore]
public bool Released => DateTime.UtcNow > ReleaseDate;
[JsonIgnore]
public IEnumerable<string> AllUsers
{
get
{
var u = new List<string>();
if (RequestedUsers != null && RequestedUsers.Any())
{
u.AddRange(RequestedUsers);
}
return u;
}
}
[JsonIgnore]
public bool CanApprove => !Approved && !Available;
public bool UserHasRequested(string username)
{
return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase));
}
}
}

@ -5,24 +5,24 @@ using Ombi.Store.Entities;
namespace Ombi.Core.Requests.Models namespace Ombi.Core.Requests.Models
{ {
public interface IRequestService public interface IRequestService<T> where T : BaseRequestModel
{ {
int AddRequest(RequestModel model); int AddRequest(T model);
Task<int> AddRequestAsync(RequestModel model); Task<int> AddRequestAsync(T model);
void BatchDelete(IEnumerable<RequestModel> model); void BatchDelete(IEnumerable<T> model);
void BatchUpdate(IEnumerable<RequestModel> model); void BatchUpdate(IEnumerable<T> model);
RequestModel CheckRequest(int providerId); T CheckRequest(int providerId);
RequestModel CheckRequest(string musicId); T CheckRequest(string musicId);
Task<RequestModel> CheckRequestAsync(int providerId); Task<T> CheckRequestAsync(int providerId);
Task<RequestModel> CheckRequestAsync(string musicId); Task<T> CheckRequestAsync(string musicId);
void DeleteRequest(RequestModel request); void DeleteRequest(T request);
Task DeleteRequestAsync(int request); Task DeleteRequestAsync(int request);
Task DeleteRequestAsync(RequestModel request); Task DeleteRequestAsync(T request);
RequestModel Get(int id); T Get(int id);
IEnumerable<RequestModel> GetAll(); IEnumerable<T> GetAll();
Task<IEnumerable<RequestModel>> GetAllAsync(); Task<IEnumerable<T>> GetAllAsync();
Task<IEnumerable<RequestModel>> GetAllAsync(int count, int position); Task<IEnumerable<T>> GetAllAsync(int count, int position);
Task<RequestModel> GetAsync(int id); Task<T> GetAsync(int id);
RequestModel UpdateRequest(RequestModel model); T UpdateRequest(T model);
} }
} }

@ -8,14 +8,14 @@ using Ombi.Store.Repository;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
public class JsonRequestService : IRequestService public class JsonRequestService<T> : IRequestService<T> where T:BaseRequestModel
{ {
public JsonRequestService(IRequestRepository repo) public JsonRequestService(IRequestRepository repo)
{ {
Repo = repo; Repo = repo;
} }
private IRequestRepository Repo { get; } private IRequestRepository Repo { get; }
public int AddRequest(RequestModel model) public int AddRequest(T model)
{ {
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId }; var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId };
var id = Repo.Insert(entity); var id = Repo.Insert(entity);
@ -23,7 +23,7 @@ namespace Ombi.Core.Models.Requests
return id.Id; return id.Id;
} }
public async Task<int> AddRequestAsync(RequestModel model) public async Task<int> AddRequestAsync(T model)
{ {
var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId }; var entity = new RequestBlobs { Type = model.Type, Content = ByteConverterHelper.ReturnBytes(model), ProviderId = model.ProviderId };
var id = await Repo.InsertAsync(entity).ConfigureAwait(false); var id = await Repo.InsertAsync(entity).ConfigureAwait(false);
@ -31,43 +31,43 @@ namespace Ombi.Core.Models.Requests
return id.Id; return id.Id;
} }
public RequestModel CheckRequest(int providerId) public T CheckRequest(int providerId)
{ {
var blobs = Repo.GetAll(); var blobs = Repo.GetAll();
var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null) var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null)
{ {
return null; return null;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; model.Id = blob.Id;
return model; return model;
} }
public async Task<RequestModel> CheckRequestAsync(int providerId) public async Task<T> CheckRequestAsync(int providerId)
{ {
var blobs = await Repo.GetAllAsync().ConfigureAwait(false); var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null) var blob = blobs.FirstOrDefault(x => x.ProviderId == providerId); if (blob == null)
{ {
return null; return null;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; model.Id = blob.Id;
return model; return model;
} }
public RequestModel CheckRequest(string musicId) public T CheckRequest(string musicId)
{ {
var blobs = Repo.GetAll(); var blobs = Repo.GetAll();
var blob = blobs.FirstOrDefault(x => x.MusicId == musicId); if (blob == null) var blob = blobs.FirstOrDefault(x => x.MusicId == musicId); if (blob == null)
{ {
return null; return null;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; model.Id = blob.Id;
return model; return model;
} }
public async Task<RequestModel> CheckRequestAsync(string musicId) public async Task<T> CheckRequestAsync(string musicId)
{ {
var blobs = await Repo.GetAllAsync().ConfigureAwait(false); var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
var blob = blobs.FirstOrDefault(x => x.MusicId == musicId); var blob = blobs.FirstOrDefault(x => x.MusicId == musicId);
@ -76,18 +76,18 @@ namespace Ombi.Core.Models.Requests
{ {
return null; return null;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; model.Id = blob.Id;
return model; return model;
} }
public void DeleteRequest(RequestModel request) public void DeleteRequest(T request)
{ {
var blob = Repo.Get(request.Id); var blob = Repo.Get(request.Id);
Repo.Delete(blob); Repo.Delete(blob);
} }
public async Task DeleteRequestAsync(RequestModel request) public async Task DeleteRequestAsync(T request)
{ {
var blob = await Repo.GetAsync(request.Id).ConfigureAwait(false); var blob = await Repo.GetAsync(request.Id).ConfigureAwait(false);
Repo.Delete(blob); Repo.Delete(blob);
@ -98,7 +98,7 @@ namespace Ombi.Core.Models.Requests
Repo.Delete(blob); Repo.Delete(blob);
} }
public RequestModel UpdateRequest(RequestModel model) public T UpdateRequest(T model)
{ {
var b = Repo.Get(model.Id); var b = Repo.Get(model.Id);
b.Content = ByteConverterHelper.ReturnBytes(model); b.Content = ByteConverterHelper.ReturnBytes(model);
@ -107,34 +107,34 @@ namespace Ombi.Core.Models.Requests
} }
public RequestModel Get(int id) public T Get(int id)
{ {
var blob = Repo.Get(id); var blob = Repo.Get(id);
if (blob == null) if (blob == null)
{ {
return new RequestModel(); return default(T);
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; // They should always be the same, but for somereason a user didn't have it in the db https://github.com/tidusjar/Ombi/issues/862#issuecomment-269743847 model.Id = blob.Id; // They should always be the same, but for somereason a user didn't have it in the db https://github.com/tidusjar/Ombi/issues/862#issuecomment-269743847
return model; return model;
} }
public async Task<RequestModel> GetAsync(int id) public async Task<T> GetAsync(int id)
{ {
var blob = await Repo.GetAsync(id).ConfigureAwait(false); var blob = await Repo.GetAsync(id).ConfigureAwait(false);
if (blob == null) if (blob == null)
{ {
return new RequestModel(); return default(T);
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(blob.Content); var model = ByteConverterHelper.ReturnObject<T>(blob.Content);
model.Id = blob.Id; model.Id = blob.Id;
return model; return model;
} }
public IEnumerable<RequestModel> GetAll() public IEnumerable<T> GetAll()
{ {
var blobs = Repo.GetAll().ToList(); var blobs = Repo.GetAll().ToList();
var retVal = new List<RequestModel>(); var retVal = new List<T>();
foreach (var b in blobs) foreach (var b in blobs)
{ {
@ -142,17 +142,17 @@ namespace Ombi.Core.Models.Requests
{ {
continue; continue;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content); var model = ByteConverterHelper.ReturnObject<T>(b.Content);
model.Id = b.Id; model.Id = b.Id;
retVal.Add(model); retVal.Add(model);
} }
return retVal; return retVal;
} }
public async Task<IEnumerable<RequestModel>> GetAllAsync() public async Task<IEnumerable<T>> GetAllAsync()
{ {
var blobs = await Repo.GetAllAsync().ConfigureAwait(false); var blobs = await Repo.GetAllAsync().ConfigureAwait(false);
var retVal = new List<RequestModel>(); var retVal = new List<T>();
foreach (var b in blobs) foreach (var b in blobs)
{ {
@ -160,17 +160,17 @@ namespace Ombi.Core.Models.Requests
{ {
continue; continue;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content); var model = ByteConverterHelper.ReturnObject<T>(b.Content);
model.Id = b.Id; model.Id = b.Id;
retVal.Add(model); retVal.Add(model);
} }
return retVal; return retVal;
} }
public async Task<IEnumerable<RequestModel>> GetAllAsync(int count, int position) public async Task<IEnumerable<T>> GetAllAsync(int count, int position)
{ {
var blobs = await Repo.GetAllAsync(count, position).ConfigureAwait(false); var blobs = await Repo.GetAllAsync(count, position).ConfigureAwait(false);
var retVal = new List<RequestModel>(); var retVal = new List<T>();
foreach (var b in blobs) foreach (var b in blobs)
{ {
@ -178,20 +178,20 @@ namespace Ombi.Core.Models.Requests
{ {
continue; continue;
} }
var model = ByteConverterHelper.ReturnObject<RequestModel>(b.Content); var model = ByteConverterHelper.ReturnObject<T>(b.Content);
model.Id = b.Id; model.Id = b.Id;
retVal.Add(model); retVal.Add(model);
} }
return retVal; return retVal;
} }
public void BatchUpdate(IEnumerable<RequestModel> model) public void BatchUpdate(IEnumerable<T> model)
{ {
var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList(); var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList();
Repo.UpdateAll(entities); Repo.UpdateAll(entities);
} }
public void BatchDelete(IEnumerable<RequestModel> model) public void BatchDelete(IEnumerable<T> model)
{ {
var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList(); var entities = model.Select(m => new RequestBlobs { Type = m.Type, Content = ByteConverterHelper.ReturnBytes(m), ProviderId = m.ProviderId, Id = m.Id }).ToList();
Repo.DeleteAll(entities); Repo.DeleteAll(entities);

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Ombi.Store.Entities;
namespace Ombi.Core.Models.Requests
{
public class MovieRequestModel : BaseRequestModel
{
public string ImdbId { get; set; }
}
}

@ -1,78 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Ombi.Store.Entities; using Ombi.Store.Entities;
namespace Ombi.Core.Models.Requests namespace Ombi.Core.Models.Requests
{ {
public class RequestModel : Entity
{
public RequestModel()
{
RequestedUsers = new List<string>();
Episodes = new List<EpisodesModel>();
}
public int ProviderId { get; set; }
public string ImdbId { get; set; }
public string TvDbId { get; set; }
public string Overview { get; set; }
public string Title { get; set; }
public string PosterPath { get; set; }
public DateTime ReleaseDate { get; set; }
public RequestType Type { get; set; }
public string Status { get; set; }
public bool Approved { get; set; }
public DateTime RequestedDate { get; set; }
public bool Available { get; set; }
public IssueState Issues { get; set; }
public string OtherMessage { get; set; }
public string AdminNote { get; set; }
public int[] SeasonList { get; set; }
public int SeasonCount { get; set; }
public string SeasonsRequested { get; set; }
public List<string> RequestedUsers { get; set; }
public int IssueId { get; set; }
public List<EpisodesModel> Episodes { get; set; }
public bool Denied { get; set; }
public string DeniedReason { get; set; }
/// <summary>
/// For TV Shows with a custom root folder
/// </summary>
/// <value>
/// The root folder selected.
/// </value>
public int RootFolderSelected { get; set; }
[JsonIgnore]
public List<string> AllUsers
{
get
{
var u = new List<string>();
if (RequestedUsers != null && RequestedUsers.Any())
{
u.AddRange(RequestedUsers);
}
return u;
}
}
[JsonIgnore]
public bool CanApprove => !Approved && !Available;
public string ReleaseId { get; set; }
public bool UserHasRequested(string username)
{
return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase));
}
}
public static class RequestTypeDisplay public static class RequestTypeDisplay
{ {
public static string GetString(this RequestType type) public static string GetString(this RequestType type)

@ -0,0 +1,16 @@
using Ombi.Core.Requests.Models;
namespace Ombi.Core.Models.Requests
{
public class RequestService : IRequestServiceMain
{
public RequestService(IRequestService<TvRequestModel> tv, IRequestService<MovieRequestModel> movie)
{
TvRequestService = tv;
MovieRequestService = movie;
}
public IRequestService<TvRequestModel> TvRequestService { get; }
public IRequestService<MovieRequestModel> MovieRequestService { get; }
}
}

@ -0,0 +1,35 @@
using System.Collections.Generic;
namespace Ombi.Core.Models.Requests
{
public class TvRequestModel : BaseRequestModel
{
public TvRequestModel()
{
Episodes = new List<EpisodesModel>();
ChildRequests = new List<TvRequestModel>();
}
public string ImdbId { get; set; }
public string TvDbId { get; set; }
public bool RequestAll { get; set; }
public List<int> SeasonsNumbersRequested { get; set; }
public List<EpisodesModel> Episodes { get; set; }
/// <summary>
/// This is for TV requests, If there is more than 1 request for a show then it should be a child
/// e.g. Request 1 is for Season 1, Request 2 is for season 5. There should be two child items.
/// </summary>
public List<TvRequestModel> ChildRequests { get; set; }
public bool HasChildRequests => ChildRequests.Count > 0;
/// <summary>
/// For TV Shows with a custom root folder
/// </summary>
/// <value>
/// The root folder selected.
/// </value>
public int RootFolderSelected { get; set; }
}
}

@ -5,10 +5,6 @@ namespace Ombi.Core.Models.Search
{ {
public class SearchTvShowViewModel : SearchViewModel public class SearchTvShowViewModel : SearchViewModel
{ {
public SearchTvShowViewModel()
{
Episodes = new List<EpisodesModel>();
}
public int Id { get; set; } public int Id { get; set; }
public string SeriesName { get; set; } public string SeriesName { get; set; }
public List<string> Aliases { get; set; } public List<string> Aliases { get; set; }
@ -27,7 +23,6 @@ namespace Ombi.Core.Models.Search
public string Rating { get; set; } public string Rating { get; set; }
public string ImdbId { get; set; } public string ImdbId { get; set; }
public int SiteRating { get; set; } public int SiteRating { get; set; }
public List<EpisodesModel> Episodes { get; set; }
/// <summary> /// <summary>
/// This is used from the Trakt API /// This is used from the Trakt API
@ -43,5 +38,23 @@ namespace Ombi.Core.Models.Search
/// The trailer. /// The trailer.
/// </value> /// </value>
public string Homepage { get; set; } public string Homepage { get; set; }
/// <summary>
/// This is for when the users requests multiple seasons or a single season
/// </summary>
public List<int> SeasonNumbersRequested { get; set; } = new List<int>();
/// <summary>
/// If we have requested some episodes
/// </summary>
public List<EpisodesModel> EpisodesRequested { get; set; } = new List<EpisodesModel>();
/// <summary>
/// If we are requesting the entire series
/// </summary>
public bool RequestAll { get; set; }
public bool SpecificSeasonsRequested => SeasonNumbersRequested.Count > 0;
public bool SpecificEpisodesRequested => EpisodesRequested.Count > 0;
} }
} }

@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" /> <ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
<ProjectReference Include="..\Ombi.Api.Trakt\Ombi.Api.Trakt.csproj" />
<ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" /> <ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" /> <ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" /> <ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />

@ -0,0 +1,10 @@
using Ombi.Core.Requests.Models;
namespace Ombi.Core.Models.Requests
{
public interface IRequestServiceMain
{
IRequestService<MovieRequestModel> MovieRequestService { get; }
IRequestService<TvRequestModel> TvRequestService { get; }
}
}

@ -10,6 +10,7 @@ using Ombi.Api.Emby;
using Ombi.Api.Plex; using Ombi.Api.Plex;
using Ombi.Api.Sonarr; using Ombi.Api.Sonarr;
using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb;
//using Ombi.Api.Trakt;
using Ombi.Api.TvMaze; using Ombi.Api.TvMaze;
using Ombi.Core; using Ombi.Core;
using Ombi.Core.Engine; using Ombi.Core.Engine;
@ -57,6 +58,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<IEmbyApi, EmbyApi>(); services.AddTransient<IEmbyApi, EmbyApi>();
services.AddTransient<ISonarrApi, SonarrApi>(); services.AddTransient<ISonarrApi, SonarrApi>();
services.AddTransient<ITvMazeApi, TvMazeApi>(); services.AddTransient<ITvMazeApi, TvMazeApi>();
//services.AddTransient<ITraktApi, TraktApi>();
return services; return services;
} }
@ -74,7 +76,9 @@ namespace Ombi.DependencyInjection
} }
public static IServiceCollection RegisterServices(this IServiceCollection services) public static IServiceCollection RegisterServices(this IServiceCollection services)
{ {
services.AddTransient<IRequestService, JsonRequestService>();
services.AddTransient<IRequestServiceMain, RequestService>();
services.AddTransient(typeof(IRequestService<>), typeof(JsonRequestService<>));
services.AddSingleton<INotificationService, NotificationService>(); services.AddSingleton<INotificationService, NotificationService>();
return services; return services;

@ -14,6 +14,7 @@
<ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" /> <ProjectReference Include="..\Ombi.Api.Emby\Ombi.Api.Emby.csproj" />
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" /> <ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
<ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" /> <ProjectReference Include="..\Ombi.Api.Sonarr\Ombi.Api.Sonarr.csproj" />
<ProjectReference Include="..\Ombi.Api.Trakt\Ombi.Api.Trakt.csproj" />
<ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" /> <ProjectReference Include="..\Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj" />
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" /> <ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
<ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" /> <ProjectReference Include="..\Ombi.Notifications\Ombi.Notifications.csproj" />

@ -1,8 +1,11 @@
using System.Globalization; using System;
using System.Globalization;
using AutoMapper; using AutoMapper;
using Ombi.Api.TvMaze.Models; using Ombi.Api.TvMaze.Models;
using Ombi.Core.Models.Search; using Ombi.Core.Models.Search;
using Ombi.Helpers; using Ombi.Helpers;
//using TraktApiSharp.Objects.Get.Shows;
//using TraktApiSharp.Objects.Get.Shows.Common;
namespace Ombi.Mapping.Profiles namespace Ombi.Mapping.Profiles
{ {
@ -23,6 +26,58 @@ namespace Ombi.Mapping.Profiles
.ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.show.name)) .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.show.name))
.ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http","https") : string.Empty)) .ForMember(dest => dest.Banner, opts => opts.MapFrom(src => !string.IsNullOrEmpty(src.show.image.medium) ? src.show.image.medium.Replace("http","https") : string.Empty))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status)); .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.show.status));
//CreateMap<TraktShow, SearchTvShowViewModel>()
// .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Ids.Tvdb.ToString())))
// .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.FirstAired.HasValue ? src.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty))
// .ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.Ids.Imdb))
// .ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.Network))
// .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Overview.RemoveHtml()))
// .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Rating.ToString()))
// .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Runtime.ToString()))
// .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Title))
// .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Status.DisplayName))
// .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Trailer))
// .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Homepage));
//CreateMap<TraktTrendingShow, SearchTvShowViewModel>()
// .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Show.Ids.Tvdb.ToString())))
// .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.Show.FirstAired.HasValue ? src.Show.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty))
// .ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.Show.Ids.Imdb))
// .ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.Show.Network))
// .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml()))
// .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString()))
// .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString()))
// .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title))
// .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName))
// .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer))
// .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage));
//CreateMap<TraktMostAnticipatedShow, SearchTvShowViewModel>()
// .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Show.Ids.Tvdb.ToString())))
// .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.Show.FirstAired.HasValue ? src.Show.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty))
// .ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.Show.Ids.Imdb))
// .ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.Show.Network))
// .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml()))
// .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString()))
// .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString()))
// .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title))
// .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName))
// .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer))
// .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage));
//CreateMap<TraktMostWatchedShow, SearchTvShowViewModel>()
// .ForMember(dest => dest.Id, opts => opts.MapFrom(src => Convert.ToInt32(src.Show.Ids.Tvdb.ToString())))
// .ForMember(dest => dest.FirstAired, opts => opts.MapFrom(src => src.Show.FirstAired.HasValue ? src.Show.FirstAired.Value.ToString("yyyy-MM-ddTHH:mm:ss") : string.Empty))
// .ForMember(dest => dest.ImdbId, opts => opts.MapFrom(src => src.Show.Ids.Imdb))
// .ForMember(dest => dest.Network, opts => opts.MapFrom(src => src.Show.Network))
// .ForMember(dest => dest.Overview, opts => opts.MapFrom(src => src.Show.Overview.RemoveHtml()))
// .ForMember(dest => dest.Rating, opts => opts.MapFrom(src => src.Show.Rating.ToString()))
// .ForMember(dest => dest.Runtime, opts => opts.MapFrom(src => src.Show.Runtime.ToString()))
// .ForMember(dest => dest.SeriesName, opts => opts.MapFrom(src => src.Show.Title))
// .ForMember(dest => dest.Status, opts => opts.MapFrom(src => src.Show.Status.DisplayName))
// .ForMember(dest => dest.Trailer, opts => opts.MapFrom(src => src.Show.Trailer))
// .ForMember(dest => dest.Homepage, opts => opts.MapFrom(src => src.Show.Homepage));
} }
} }
} }

@ -56,6 +56,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Tests.Core", "Ombi.Tes
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -134,6 +136,10 @@ Global
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Release|Any CPU.Build.0 = Release|Any CPU {AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Release|Any CPU.Build.0 = Release|Any CPU
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -151,5 +157,6 @@ Global
{72DB97D7-2D60-4B96-8C57-6C0E20E892EB} = {EA30DD15-6280-4687-B370-2956EC2E54E5} {72DB97D7-2D60-4B96-8C57-6C0E20E892EB} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
{6EE01B17-0966-4E11-8BC1-A5318A92AB1D} = {EA30DD15-6280-4687-B370-2956EC2E54E5} {6EE01B17-0966-4E11-8BC1-A5318A92AB1D} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
{627A27A7-8879-4851-8140-38F8F5ADD6CD} = {6F42AB98-9196-44C4-B888-D5E409F415A1} {627A27A7-8879-4851-8140-38F8F5ADD6CD} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
{3880375C-1A7E-4D75-96EC-63B954C42FEA} = {9293CA11-360A-4C20-A674-B9E794431BF5}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

@ -31,7 +31,7 @@ namespace Ombi.Auth
/// The expiration time for the generated tokens. /// The expiration time for the generated tokens.
/// </summary> /// </summary>
/// <remarks>The default is 7 Days.</remarks> /// <remarks>The default is 7 Days.</remarks>
public TimeSpan Expiration { get; set; } = TimeSpan.FromDays(7); public TimeSpan Expiration { get; set; } = TimeSpan.FromDays(1);
/// <summary> /// <summary>
/// The signing key to use when generating tokens. /// The signing key to use when generating tokens.

@ -27,9 +27,9 @@ namespace Ombi.Controllers
private IMapper Mapper { get; } private IMapper Mapper { get; }
[HttpGet] [HttpGet]
public async Task<UserDto> GetUser() public async Task<UserViewModel> GetUser()
{ {
return await IdentityManager.GetUser(this.HttpContext.User.Identity.Name); return Mapper.Map<UserViewModel>(await IdentityManager.GetUser(this.HttpContext.User.Identity.Name));
} }

@ -18,16 +18,11 @@ namespace Ombi.Controllers
private IRequestEngine RequestEngine { get; } private IRequestEngine RequestEngine { get; }
[HttpGet]
public async Task<IEnumerable<RequestViewModel>> GetRequests()
{
return await RequestEngine.GetRequests();
}
[HttpGet("{count:int}/{position:int}", Name = "GetRequestsByCount")] [HttpGet("movie/{count:int}/{position:int}", Name = "GetRequestsByCount")]
public async Task<IEnumerable<RequestViewModel>> GetRequests(int count, int position) public async Task<IEnumerable<MovieRequestModel>> GetRequests(int count, int position)
{ {
return await RequestEngine.GetRequests(count, position); return await RequestEngine.GetMovieRequests(count, position);
} }
[HttpPost("movie")] [HttpPost("movie")]
@ -36,23 +31,29 @@ namespace Ombi.Controllers
return await RequestEngine.RequestMovie(movie); return await RequestEngine.RequestMovie(movie);
} }
[HttpGet("search/{searchTerm}")] //[HttpPost("tv")]
public async Task<IEnumerable<RequestViewModel>> Search(string searchTerm) //public async Task<RequestEngineResult> RequestTv([FromBody]SearchTvShowViewModel tv)
//{
// return await RequestEngine.RequestMovie();
//}
[HttpGet("movie/search/{searchTerm}")]
public async Task<IEnumerable<MovieRequestModel>> Search(string searchTerm)
{ {
return await RequestEngine.SearchRequest(searchTerm); return await RequestEngine.SearchMovieRequest(searchTerm);
} }
[HttpDelete("{requestId:int}")] [HttpDelete("movie/{requestId:int}")]
public async Task DeleteRequest(int requestId) public async Task DeleteRequest(int requestId)
{ {
await RequestEngine.RemoveRequest(requestId); await RequestEngine.RemoveMovieRequest(requestId);
} }
[HttpPost] [HttpPut("movie")]
public async Task<RequestViewModel> UpdateRequest([FromBody]RequestViewModel model) public async Task<MovieRequestModel> UpdateRequest([FromBody]MovieRequestModel model)
{ {
return await RequestEngine.UpdateRequest(model); return await RequestEngine.UpdateMovieRequest(model);
} }
} }
} }

@ -64,5 +64,26 @@ namespace Ombi.Controllers
{ {
return await TvEngine.Search(searchTerm); return await TvEngine.Search(searchTerm);
} }
//[HttpGet("tv/popular")]
//public async Task<IEnumerable<SearchTvShowViewModel>> PopularTv()
//{
// return await TvEngine.Popular();
//}
//[HttpGet("tv/anticiplated")]
//public async Task<IEnumerable<SearchTvShowViewModel>> AnticiplatedTv()
//{
// return await TvEngine.Anticipated();
//}
//[HttpGet("tv/mostwatched")]
//public async Task<IEnumerable<SearchTvShowViewModel>> MostWatched()
//{
// return await TvEngine.MostWatches();
//}
//[HttpGet("tv/trending")]
//public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
//{
// return await TvEngine.Trending();
//}
} }
} }

@ -16,7 +16,7 @@
"@angular/router": "^4.1.0", "@angular/router": "^4.1.0",
"@types/jquery": "^2.0.33", "@types/jquery": "^2.0.33",
"@types/systemjs": "^0.20.2", "@types/systemjs": "^0.20.2",
"angular2-jwt": "0.2.0", "angular2-jwt": "^0.2.0",
"angular2-moment": "^1.3.3", "angular2-moment": "^1.3.3",
"bootstrap": "3.3.6", "bootstrap": "3.3.6",
"core-js": "^2.4.1", "core-js": "^2.4.1",

@ -9,10 +9,11 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<div *ngIf="customizationSettings">
<div *ngIf="customizationSettings.applicationName; then aplicationNameBlock; else ombiBlock"></div> <div *ngIf="customizationSettings.applicationName; then aplicationNameBlock; else ombiBlock"></div>
<ng-template #aplicationNameBlock><a class="navbar-brand" [routerLink]="['/']">{{customizationSettings.applicationName}}</a></ng-template> <ng-template #aplicationNameBlock><a class="navbar-brand" [routerLink]="['/']">{{customizationSettings.applicationName}}</a></ng-template>
<ng-template #ombiBlock><a class="navbar-brand" [routerLink]="['/']">Ombi</a></ng-template> <ng-template #ombiBlock><a class="navbar-brand" [routerLink]="['/']">Ombi</a></ng-template>
</div>
</div> </div>
@ -26,7 +27,7 @@
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Ombi']"><i class="fa fa-cog"></i> Settings</a></li> <li *ngIf="isAdmin" [routerLinkActive]="['active']"><a [routerLink]="['/Settings/Ombi']"><i class="fa fa-cog"></i> Settings</a></li>
<li [routerLinkActive]="['active']" class="dropdown"> <li [routerLinkActive]="['active']" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> Welcome {{username}} <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> Welcome {{username}} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">

@ -3,6 +3,7 @@ import { Router } from '@angular/router';
import { NotificationService } from './services/notification.service'; import { NotificationService } from './services/notification.service';
import { SettingsService } from './services/settings.service'; import { SettingsService } from './services/settings.service';
import { AuthService } from './auth/auth.service'; import { AuthService } from './auth/auth.service';
import { IdentityService } from './services/identity.service';
import { ICustomizationSettings } from './interfaces/ISettings'; import { ICustomizationSettings } from './interfaces/ISettings';
@ -13,7 +14,8 @@ import { ICustomizationSettings } from './interfaces/ISettings';
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
constructor(public notificationService: NotificationService, public authService: AuthService, private router: Router, private settingsService : SettingsService) { constructor(public notificationService: NotificationService, public authService: AuthService, private router: Router, private settingsService: SettingsService
, private identityService: IdentityService) {
} }
customizationSettings: ICustomizationSettings; customizationSettings: ICustomizationSettings;
@ -26,7 +28,8 @@ export class AppComponent implements OnInit {
this.showNav = this.authService.loggedIn(); this.showNav = this.authService.loggedIn();
}); });
this.isAdmin = this.identityService.hasRole("Admin");
this.isPowerUser = this.identityService.hasRole("PowerUser");
} }
@ -36,5 +39,7 @@ export class AppComponent implements OnInit {
} }
username:string; username:string;
showNav :boolean; showNav: boolean;
isAdmin: boolean;
isPowerUser:boolean;
} }

@ -3,7 +3,11 @@ import { Http, RequestOptions } from '@angular/http';
import { AuthHttp, AuthConfig } from 'angular2-jwt'; import { AuthHttp, AuthConfig } from 'angular2-jwt';
export function authHttpServiceFactory(http: Http, options: RequestOptions) { export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig(), http, options); return new AuthHttp(new AuthConfig({
tokenName: 'id_token',
tokenGetter: (() => localStorage.getItem('id_token')),
globalHeaders: [{ 'Content-Type': 'application/json' }],
}), http, options);
} }
@NgModule({ @NgModule({

@ -23,7 +23,7 @@ export class AuthService extends ServiceHelpers {
} }
loggedIn() { loggedIn() {
return tokenNotExpired(); return tokenNotExpired('id_token');
} }
logout() { logout() {

@ -1,24 +1,41 @@
export interface IRequestModel { import { IEpisodeModel }from "./ISearchTvResult";
export interface IMediaBase {
id: number, id: number,
providerId: number, providerId: number,
imdbId: string,
overview: string,
title: string, title: string,
overview: string,
posterPath: string, posterPath: string,
releaseDate: Date, releaseDate: Date,
released: boolean,
type: RequestType,
status: string, status: string,
approved: boolean,
requestedUsers: string[],
requestedDate: Date, requestedDate: Date,
releaseYear: string, approved: boolean,
type: RequestType,
requested: boolean,
available: boolean, available: boolean,
otherMessage: string,
adminNote: string,
requestedUser: string[],
issueId: number, issueId: number,
denied: boolean, denied: boolean,
deniedReason: string, deniedReason: string,
released:boolean
}
export interface IMovieRequestModel extends IMediaBase {
imdbId: string,
}
export interface ITvRequestModel extends IMediaBase {
imdbId: string,
tvDbId: string,
requestAll: boolean,
seasonNumbersRequested: number[],
episodes: IEpisodeModel[],
childRequests: ITvRequestModel[],
hasChildRequests: boolean,
rootFolderSelected: number,
firstAired:string,
} }
export enum RequestType { export enum RequestType {

@ -19,7 +19,14 @@
siteRating: number, siteRating: number,
trailer: string, trailer: string,
homepage:string, homepage:string,
episodes:IEpisodeModel[], episodesRequested: IEpisodeModel[],
seasonNumbersRequested: number[],
requestAll:boolean,
approved: boolean,
requested: boolean,
available: boolean,
plexUrl: string,
} }
export interface IEpisodeModel { export interface IEpisodeModel {

@ -3,6 +3,7 @@ import { Router } from '@angular/router';
import { AuthService } from '../auth/auth.service'; import { AuthService } from '../auth/auth.service';
import { StatusService } from '../services/status.service'; import { StatusService } from '../services/status.service';
import { IdentityService } from '../services/identity.service';
import { NotificationService } from '../services/notification.service'; import { NotificationService } from '../services/notification.service';
@Component({ @Component({
@ -11,7 +12,7 @@ import { NotificationService } from '../services/notification.service';
templateUrl: './login.component.html', templateUrl: './login.component.html',
}) })
export class LoginComponent { export class LoginComponent {
constructor(private authService: AuthService, private router: Router, private notify: NotificationService, private status: StatusService) { constructor(private authService: AuthService, private router: Router, private notify: NotificationService, private status: StatusService, private identityService: IdentityService) {
this.status.getWizardStatus().subscribe(x => { this.status.getWizardStatus().subscribe(x => {
if (!x.result) { if (!x.result) {
this.router.navigate(['Wizard']); this.router.navigate(['Wizard']);
@ -30,11 +31,18 @@ export class LoginComponent {
localStorage.setItem("id_token", x.access_token); localStorage.setItem("id_token", x.access_token);
localStorage.setItem('currentUser', this.username); localStorage.setItem('currentUser', this.username);
this.identityService.getUser().subscribe(r => {
localStorage.setItem("roles", JSON.stringify(r.claims));
localStorage.setItem("user", JSON.stringify(r));
if (this.authService.loggedIn()) { if (this.authService.loggedIn()) {
this.router.navigate(['search']); this.router.navigate(['search']);
} else { } else {
this.notify.error("Could not log in", "Incorrect username or password"); this.notify.error("Could not log in", "Incorrect username or password");
} }
});
}, err => this.notify.error("Could not log in", "Incorrect username or password")); }, err => this.notify.error("Could not log in", "Incorrect username or password"));

@ -13,7 +13,7 @@
(scrolled)="loadMore()"> (scrolled)="loadMore()">
<div *ngFor="let request of requests"> <div *ngFor="let request of movieRequests">
<div class="row"> <div class="row">
@ -62,7 +62,7 @@
{{/if}} {{/if}}
{{/if_eq}}--> {{/if_eq}}-->
<div *ngIf="request.requestedUsers">Requested By: {{request.requestedUsers}}</div> <div *ngIf="request.requestedUsers">Requested By: <span *ngFor="let user of request.requestedUsers">{{user}} </span></div>
<div>Requested Date: {{request.requestedDate | date}}</div> <div>Requested Date: {{request.requestedDate | date}}</div>
<!--{{#if admin}} <!--{{#if admin}}
@ -79,7 +79,7 @@
</div>--> </div>-->
</div> </div>
<div class="col-sm-3 col-sm-push-3"> <div class="col-sm-3 col-sm-push-3">
<div *ngIf="request.admin"> <div *ngIf="isAdmin">
<div *ngIf="!request.approved"> <div *ngIf="!request.approved">
<form> <form>
<input name="requestId" type="text" value="{{request.requestId}}" hidden="hidden" /> <input name="requestId" type="text" value="{{request.requestId}}" hidden="hidden" />

@ -10,8 +10,9 @@ import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
import { IdentityService } from '../services/identity.service';
import { IRequestModel } from '../interfaces/IRequestModel'; import { IMovieRequestModel, ITvRequestModel } from '../interfaces/IRequestModel';
@Component({ @Component({
selector: 'ombi', selector: 'ombi',
@ -19,7 +20,7 @@ import { IRequestModel } from '../interfaces/IRequestModel';
templateUrl: './request.component.html' templateUrl: './request.component.html'
}) })
export class RequestComponent implements OnInit { export class RequestComponent implements OnInit {
constructor(private requestService: RequestService) { constructor(private requestService: RequestService, private identityService: IdentityService) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
@ -29,15 +30,18 @@ export class RequestComponent implements OnInit {
this.resetSearch(); this.resetSearch();
return; return;
} }
this.requestService.searchRequests(this.searchText).subscribe(x => this.requests = x); this.requestService.searchRequests(this.searchText).subscribe(x => this.movieRequests = x);
}); });
} }
requests: IRequestModel[]; movieRequests: IMovieRequestModel[];
tvRequests: ITvRequestModel[];
searchChanged: Subject<string> = new Subject<string>(); searchChanged: Subject<string> = new Subject<string>();
searchText: string; searchText: string;
isAdmin : boolean;
private currentlyLoaded: number; private currentlyLoaded: number;
private amountToLoad : number; private amountToLoad : number;
@ -47,9 +51,11 @@ export class RequestComponent implements OnInit {
this.loadInit(); this.loadInit();
} }
loadMore() { loadMore() {
this.requestService.getRequests(this.amountToLoad, this.currentlyLoaded + 1).subscribe(x => { this.requestService.getRequests(this.amountToLoad, this.currentlyLoaded + 1).subscribe(x => {
this.requests.push.apply(this.requests, x); this.movieRequests.push.apply(this.movieRequests, x);
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad; this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
}); });
} }
@ -58,35 +64,36 @@ export class RequestComponent implements OnInit {
this.searchChanged.next(text.target.value); this.searchChanged.next(text.target.value);
} }
removeRequest(request: IRequestModel) { removeRequest(request: IMovieRequestModel) {
this.requestService.removeRequest(request).subscribe(); this.requestService.removeMovieRequest(request);
this.removeRequestFromUi(request); this.removeRequestFromUi(request);
} }
changeAvailability(request: IRequestModel, available: boolean) { changeAvailability(request: IMovieRequestModel, available: boolean) {
request.available = available; request.available = available;
this.updateRequest(request); this.updateRequest(request);
} }
approve(request: IRequestModel) { approve(request: IMovieRequestModel) {
request.approved = true; request.approved = true;
request.denied = false; request.denied = false;
this.updateRequest(request); this.updateRequest(request);
} }
deny(request: IRequestModel) { deny(request: IMovieRequestModel) {
request.approved = false; request.approved = false;
request.denied = true; request.denied = true;
this.updateRequest(request); this.updateRequest(request);
} }
private updateRequest(request: IRequestModel) { private updateRequest(request: IMovieRequestModel) {
this.requestService.updateRequest(request).subscribe(x => request = x); this.requestService.updateRequest(request).subscribe(x => request = x);
} }
private loadInit() { private loadInit() {
this.requestService.getRequests(this.amountToLoad, 0).subscribe(x => this.requests = x); this.requestService.getRequests(this.amountToLoad, 0).subscribe(x => this.movieRequests = x);
this.isAdmin = this.identityService.hasRole("Admin");
} }
private resetSearch() { private resetSearch() {
@ -94,10 +101,10 @@ export class RequestComponent implements OnInit {
this.loadInit(); this.loadInit();
} }
private removeRequestFromUi(key : IRequestModel) { private removeRequestFromUi(key: IMovieRequestModel) {
var index = this.requests.indexOf(key, 0); var index = this.movieRequests.indexOf(key, 0);
if (index > -1) { if (index > -1) {
this.requests.splice(index, 1); this.movieRequests.splice(index, 1);
} }
} }
} }

@ -7,7 +7,7 @@
<ul id="nav-tabs" class="nav nav-tabs" role="tablist"> <ul id="nav-tabs" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"> <li role="presentation" class="active">
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectTab('movies')"><i class="fa fa-film"></i> Movies</a> <a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-film"></i> Movies</a>
</li> </li>
<!--<li role="presentation"> <!--<li role="presentation">
@ -16,7 +16,7 @@
</li>--> </li>-->
<li role="presentation"> <li role="presentation">
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTab('tv')"><i class="fa fa-television"></i> TV Shows</a> <a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTab()"><i class="fa fa-television"></i> TV Shows</a>
</li> </li>
<!-- <!--
@ -29,7 +29,7 @@
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
<div *ngIf="showMovie"> <div [hidden]="!showMovie">
<movie-search></movie-search> <movie-search></movie-search>
</div> </div>
@ -52,7 +52,7 @@
</div>--> </div>-->
<div *ngIf="showTv"> <div [hidden]="!showTv">
<tv-search></tv-search> <tv-search></tv-search>
</div> </div>

@ -1,131 +1,23 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map';
import { SearchService } from '../services/search.service';
import { RequestService } from '../services/request.service';
import { NotificationService } from '../services/notification.service';
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
@Component({ @Component({
selector: 'ombi', selector: 'ombi',
moduleId: module.id, moduleId: module.id,
templateUrl: './search.component.html', templateUrl: './search.component.html',
}) })
export class SearchComponent implements OnInit { export class SearchComponent implements OnInit {
searchText: string;
searchChanged: Subject<string> = new Subject<string>();
movieResults: ISearchMovieResult[];
result: IRequestEngineResult;
tabSelected: string;
showTv: boolean;
showMovie:boolean;
constructor(private searchService: SearchService, private requestService: RequestService, private notificationService : NotificationService) {
this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText).subscribe(x => {
this.movieResults = x;
// Now let's load some exta info including IMDBId
// This way the search is fast at displaying results.
this.getExtaInfo();
});
});
}
ngOnInit(): void { ngOnInit(): void {
this.selectTab("movies");
this.searchText = "";
this.movieResults = [];
this.result = {
message: "",
requestAdded:false
}
}
search(text: any) {
this.searchChanged.next(text.target.value);
}
request(searchResult: ISearchMovieResult) {
searchResult.requested = true;
this.requestService.requestMovie(searchResult).subscribe(x => {
this.result = x;
if (this.result.requestAdded) {
this.notificationService.success("Request Added",
`Request for ${searchResult.title} has been added successfully`);
} else {
this.notificationService.warning("Request Added", this.result.message);
}
});
}
selectTab(tabName: string) {
console.log(tabName);
this.tabSelected = tabName;
if (tabName === 'movies') {
this.showMovie = true; this.showMovie = true;
this.showTv = false; this.showTv = false;
} else {
this.showMovie = false;
this.showTv = true;
}
} }
popularMovies() { showTv : boolean;
this.clearResults(); showMovie: boolean;
this.searchService.popularMovies().subscribe(x => {
this.movieResults = x;
this.getExtaInfo();
});
}
nowPlayingMovies() {
this.clearResults();
this.searchService.nowPlayingMovies().subscribe(x => {
this.movieResults = x;
this.getExtaInfo();
});
}
topRatedMovies() {
this.clearResults();
this.searchService.topRatedMovies().subscribe(x => {
this.movieResults = x;
this.getExtaInfo();
});
}
upcomingMovies() {
this.clearResults();
this.searchService.upcomignMovies().subscribe(x => {
this.movieResults = x;
this.getExtaInfo();
});
}
private getExtaInfo() {
this.searchService.extraInfo(this.movieResults).subscribe(m => this.movieResults = m);
}
private clearResults() { selectTab() {
this.movieResults = []; this.showMovie = !this.showMovie;
this.showTv = !this.showTv;
} }
} }

@ -9,10 +9,10 @@
<i class="fa fa-chevron-down"></i> <i class="fa fa-chevron-down"></i>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a id="popularShows">Popular Shows</a></li> <li><a (click)="popularShows()">Popular Shows</a></li>
<li><a id="trendingShows">Trending Shows</a></li> <li><a (click)="trendingShows()">Trending Shows</a></li>
<li><a id="mostWatchedShows">Most Watched Shows</a></li> <li><a (click)="mostWatchedShows()">Most Watched Shows</a></li>
<li><a id="anticipatedShows">Most Anticipated Shows</a></li> <li><a (click)="anticipatedShows()">Most Anticipated Shows</a></li>
</ul> </ul>
</div><i id="tvSearchButton" class="fa fa-search"></i> </div><i id="tvSearchButton" class="fa fa-search"></i>
</div> </div>

@ -5,8 +5,8 @@ import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import { SearchService } from '../services/search.service'; import { SearchService } from '../services/search.service';
//import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
//import { NotificationService } from '../services/notification.service'; import { NotificationService } from '../services/notification.service';
import { ISearchTvResult } from '../interfaces/ISearchTvResult'; import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult'; import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
@ -19,11 +19,11 @@ import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
export class TvSearchComponent implements OnInit { export class TvSearchComponent implements OnInit {
searchText: string; searchText: string;
searchChanged: Subject<string> = new Subject<string>(); searchChanged = new Subject<string>();
tvResults: ISearchTvResult[]; tvResults: ISearchTvResult[];
result: IRequestEngineResult; result: IRequestEngineResult;
constructor(private searchService: SearchService/*, private requestService: RequestService, private notificationService: NotificationService*/) { constructor(private searchService: SearchService, private requestService: RequestService, private notificationService: NotificationService) {
this.searchChanged this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event .debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value .distinctUntilChanged() // only emit if value is different from previous value
@ -53,6 +53,48 @@ export class TvSearchComponent implements OnInit {
} }
popularShows() {
this.clearResults();
this.searchService.popularTv().subscribe(x => {
this.tvResults = x;
});
}
trendingShows() {
this.clearResults();
this.searchService.trendingTv().subscribe(x => {
this.tvResults = x;
});
}
mostWatchedShows() {
this.clearResults();
this.searchService.mostWatchedTv().subscribe(x => {
this.tvResults = x;
});
}
anticipatedShows() {
this.clearResults();
this.searchService.anticiplatedTv().subscribe(x => {
this.tvResults = x;
});
}
request(searchResult: ISearchTvResult) {
searchResult.requested = true;
this.requestService.requestTv(searchResult).subscribe(x => {
this.result = x;
if (this.result.requestAdded) {
this.notificationService.success("Request Added",
`Request for ${searchResult.seriesName} has been added successfully`);
} else {
this.notificationService.warning("Request Added", this.result.message);
}
});
}
private clearResults() { private clearResults() {
this.tvResults = []; this.tvResults = [];

@ -4,19 +4,34 @@ import { Http } from '@angular/http';
import { Observable } from 'rxjs/Rx'; import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from './service.helpers'; import { ServiceAuthHelpers } from './service.helpers';
import {IUser} from '../interfaces/IUser'; import { IUser } from '../interfaces/IUser';
@Injectable() @Injectable()
export class IdentityService extends ServiceAuthHelpers { export class IdentityService extends ServiceAuthHelpers {
constructor(http: AuthHttp, private regularHttp : Http) { constructor(http: AuthHttp, private regularHttp: Http) {
super(http, '/api/v1/Identity/'); super(http, '/api/v1/Identity/');
} }
createWizardUser(username:string,password:string): Observable<boolean> { createWizardUser(username: string, password: string): Observable<boolean> {
return this.regularHttp.post(`${this.url}/Wizard/`, JSON.stringify({username:username, password:password}), { headers: this.headers }).map(this.extractData); return this.regularHttp.post(`${this.url}/Wizard/`, JSON.stringify({ username: username, password: password }), { headers: this.headers }).map(this.extractData);
}
getUser(): Observable<IUser> {
return this.http.get(this.url).map(this.extractData);
} }
getUsers(): Observable<IUser[]> { getUsers(): Observable<IUser[]> {
return this.http.get(`${this.url}/Users`).map(this.extractData); return this.http.get(`${this.url}/Users`).map(this.extractData);
} }
hasRole(role: string): boolean {
var roles = localStorage.getItem("roles") as string[];
if (roles) {
if (roles.indexOf(role) > -1) {
return true;
}
return false;
}
return false;
}
} }

@ -5,7 +5,8 @@ import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from './service.helpers'; import { ServiceAuthHelpers } from './service.helpers';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult'; import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult'; import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
import { IRequestModel } from '../interfaces/IRequestModel'; import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { IMovieRequestModel } from '../interfaces/IRequestModel';
@Injectable() @Injectable()
export class RequestService extends ServiceAuthHelpers { export class RequestService extends ServiceAuthHelpers {
@ -17,23 +18,23 @@ export class RequestService extends ServiceAuthHelpers {
return this.http.post(`${this.url}/Movie/`, JSON.stringify(movie), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}/Movie/`, JSON.stringify(movie), { headers: this.headers }).map(this.extractData);
} }
getAllRequests(): Observable<IRequestModel[]> { requestTv(tv: ISearchTvResult): Observable<IRequestEngineResult> {
return this.http.get(this.url).map(this.extractData); return this.http.post(`${this.url}/TV/`, JSON.stringify(tv), { headers: this.headers }).map(this.extractData);
} }
getRequests(count: number, position: number): Observable<IRequestModel[]> { getRequests(count: number, position: number): Observable<IMovieRequestModel[]> {
return this.http.get(`${this.url}/${count}/${position}`).map(this.extractData); return this.http.get(`${this.url}/movie/${count}/${position}`).map(this.extractData);
} }
searchRequests(search: string): Observable<IRequestModel[]> { searchRequests(search: string): Observable<IMovieRequestModel[]> {
return this.http.get(`${this.url}/search/${search}`).map(this.extractData); return this.http.get(`${this.url}/movie/search/${search}`).map(this.extractData);
} }
removeRequest(request: IRequestModel): Observable<void> { removeMovieRequest(request: IMovieRequestModel) {
return this.http.delete(`${this.url}/${request.id}`).map(this.extractData); this.http.delete(`${this.url}/movie/${request.id}`).map(this.extractData).subscribe();
} }
updateRequest(request: IRequestModel) : Observable<IRequestModel> { updateRequest(request: IMovieRequestModel): Observable<IMovieRequestModel> {
return this.http.post(`${this.url}/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}/movie/`, JSON.stringify(request), { headers: this.headers }).map(this.extractData);
} }
} }

@ -12,6 +12,7 @@ export class SearchService extends ServiceAuthHelpers {
super(http, "/api/v1/search"); super(http, "/api/v1/search");
} }
// Movies
searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> { searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> {
return this.http.get(`${this.url}/Movie/` + searchTerm).map(this.extractData); return this.http.get(`${this.url}/Movie/` + searchTerm).map(this.extractData);
} }
@ -32,7 +33,20 @@ export class SearchService extends ServiceAuthHelpers {
return this.http.post(`${this.url}/Movie/extrainfo`, JSON.stringify(movies), { headers: this.headers }).map(this.extractData); return this.http.post(`${this.url}/Movie/extrainfo`, JSON.stringify(movies), { headers: this.headers }).map(this.extractData);
} }
// TV
searchTv(searchTerm: string): Observable<ISearchTvResult[]> { searchTv(searchTerm: string): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/` + searchTerm).map(this.extractData); return this.http.get(`${this.url}/Tv/` + searchTerm).map(this.extractData);
} }
popularTv(): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/popular`).map(this.extractData);
}
mostWatchedTv(): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/mostwatched`).map(this.extractData);
}
anticiplatedTv(): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/anticipated`).map(this.extractData);
}
trendingTv(): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/trending`).map(this.extractData);
}
} }
Loading…
Cancel
Save