From 8b64c18aceb39c25f0a85a02ca89a0b7ba86df96 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Mon, 24 Apr 2017 16:27:08 +0100 Subject: [PATCH] #865 --- Ombi/Ombi.Api.TvMaze/ITvMazeApi.cs | 15 ++ Ombi/Ombi.Api.TvMaze/Models/Search/Country.cs | 9 + .../Models/Search/Externals.cs | 9 + Ombi/Ombi.Api.TvMaze/Models/Search/Image.cs | 8 + Ombi/Ombi.Api.TvMaze/Models/Search/Links.cs | 9 + Ombi/Ombi.Api.TvMaze/Models/Search/Network.cs | 9 + .../Models/Search/Nextepisode.cs | 7 + .../Models/Search/Previousepisode.cs | 7 + Ombi/Ombi.Api.TvMaze/Models/Search/Rating.cs | 7 + .../Ombi.Api.TvMaze/Models/Search/Schedule.cs | 10 + Ombi/Ombi.Api.TvMaze/Models/Search/Self.cs | 7 + Ombi/Ombi.Api.TvMaze/Models/Search/Show.cs | 27 +++ .../Models/Search/TvMazeSearch.cs | 8 + Ombi/Ombi.Api.TvMaze/Models/TVMazeSeasons.cs | 7 + Ombi/Ombi.Api.TvMaze/Models/TvMazeEpisode.cs | 18 ++ Ombi/Ombi.Api.TvMaze/Models/TvMazeShow.cs | 89 +++++++++ Ombi/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj | 11 ++ Ombi/Ombi.Api.TvMaze/TvMazeApi.cs | 84 +++++++++ Ombi/Ombi.Api/Request.cs | 23 +++ Ombi/Ombi.Core/Claims/OmbiClaims.cs | 2 + Ombi/Ombi.Core/Engine/BaseMediaEngine.cs | 42 ++++- .../Ombi.Core/Engine/Interfaces/BaseEngine.cs | 50 ++++- .../{MovieEngine.cs => MovieSearchEngine.cs} | 38 ++-- Ombi/Ombi.Core/Engine/RequestEngine.cs | 101 +++-------- Ombi/Ombi.Core/Engine/RequestEngineResult.cs | 2 + Ombi/Ombi.Core/Engine/TvSearchEngine.cs | 29 +++ Ombi/Ombi.Core/Ombi.Core.csproj | 1 + .../Settings/Models/LandingPageSettings.cs | 22 +++ .../Ombi.DependencyInjection/IocExtensions.cs | 7 +- .../Ombi.DependencyInjection.csproj | 1 + Ombi/Ombi.Helpers/StringCipher.cs | 6 +- Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs | 2 +- Ombi/Ombi.sln | 12 +- Ombi/Ombi/Controllers/RequestController.cs | 1 + Ombi/Ombi/Controllers/SettingsController.cs | 13 +- Ombi/Ombi/Startup.cs | 10 +- Ombi/Ombi/wwwroot/app/app.module.ts | 4 +- Ombi/Ombi/wwwroot/app/interfaces/ISettings.ts | 11 ++ .../app/search/moviesearch.component.html | 154 ++++++++++++++++ .../app/search/moviesearch.component.ts | 110 +++++++++++ .../wwwroot/app/search/search.component.html | 171 +----------------- .../wwwroot/app/services/settings.service.ts | 9 +- .../landingpage/landingpage.component.html | 41 +++++ .../landingpage/landingpage.component.ts | 31 ++++ .../wwwroot/app/settings/settings.module.ts | 3 + .../createadmin/createadmin.component.ts | 6 +- 46 files changed, 960 insertions(+), 283 deletions(-) create mode 100644 Ombi/Ombi.Api.TvMaze/ITvMazeApi.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Country.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Externals.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Image.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Links.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Network.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Nextepisode.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Previousepisode.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Rating.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Schedule.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Self.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/Show.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/Search/TvMazeSearch.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/TVMazeSeasons.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/TvMazeEpisode.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Models/TvMazeShow.cs create mode 100644 Ombi/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj create mode 100644 Ombi/Ombi.Api.TvMaze/TvMazeApi.cs rename Ombi/Ombi.Core/Engine/{MovieEngine.cs => MovieSearchEngine.cs} (83%) create mode 100644 Ombi/Ombi.Core/Engine/TvSearchEngine.cs create mode 100644 Ombi/Ombi.Core/Settings/Models/LandingPageSettings.cs create mode 100644 Ombi/Ombi/wwwroot/app/search/moviesearch.component.html create mode 100644 Ombi/Ombi/wwwroot/app/search/moviesearch.component.ts create mode 100644 Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.html create mode 100644 Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.ts diff --git a/Ombi/Ombi.Api.TvMaze/ITvMazeApi.cs b/Ombi/Ombi.Api.TvMaze/ITvMazeApi.cs new file mode 100644 index 000000000..9a8688568 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/ITvMazeApi.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Ombi.Api.TvMaze.Models; + +namespace Ombi.Api.TvMaze +{ + public interface ITvMazeApi + { + Task> EpisodeLookup(int showId); + Task> GetSeasons(int id); + Task> Search(string searchTerm); + Task ShowLookup(int showId); + Task ShowLookupByTheTvDbId(int theTvDbId); + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Country.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Country.cs new file mode 100644 index 000000000..00fd2e0f6 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Country.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Country + { + public string code { get; set; } + public string name { get; set; } + public string timezone { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Externals.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Externals.cs new file mode 100644 index 000000000..5beac6558 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Externals.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Externals + { + public string imdb { get; set; } + public int? thetvdb { get; set; } + public int? tvrage { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Image.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Image.cs new file mode 100644 index 000000000..91b1cf182 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Image.cs @@ -0,0 +1,8 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Image + { + public string medium { get; set; } + public string original { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Links.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Links.cs new file mode 100644 index 000000000..6433e8b86 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Links.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Links + { + public Nextepisode nextepisode { get; set; } + public Previousepisode previousepisode { get; set; } + public Self self { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Network.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Network.cs new file mode 100644 index 000000000..6ba66788e --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Network.cs @@ -0,0 +1,9 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Network + { + public Country country { get; set; } + public int id { get; set; } + public string name { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Nextepisode.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Nextepisode.cs new file mode 100644 index 000000000..7c63f6cd2 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Nextepisode.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Nextepisode + { + public string href { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Previousepisode.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Previousepisode.cs new file mode 100644 index 000000000..be09e0da3 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Previousepisode.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Previousepisode + { + public string href { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Rating.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Rating.cs new file mode 100644 index 000000000..4c21c1957 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Rating.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Rating + { + public double? average { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Schedule.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Schedule.cs new file mode 100644 index 000000000..28315c265 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Schedule.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Ombi.Api.TvMaze.Models +{ + public class Schedule + { + public List days { get; set; } + public string time { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Self.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Self.cs new file mode 100644 index 000000000..1f048f302 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Self.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class Self + { + public string href { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/Show.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/Show.cs new file mode 100644 index 000000000..16b1eb065 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/Show.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Ombi.Api.TvMaze.Models +{ + public class Show + { + public Links _links { get; set; } + public Externals externals { get; set; } + public List genres { get; set; } + public int id { get; set; } + public Image image { get; set; } + public string language { get; set; } + public string name { get; set; } + public Network network { get; set; } + public string premiered { get; set; } + public Rating rating { get; set; } + public int? runtime { get; set; } + public Schedule schedule { get; set; } + public string status { get; set; } + public string summary { get; set; } + public string type { get; set; } + public int updated { get; set; } + public string url { get; set; } + public object webChannel { get; set; } + public int weight { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/Search/TvMazeSearch.cs b/Ombi/Ombi.Api.TvMaze/Models/Search/TvMazeSearch.cs new file mode 100644 index 000000000..1ce49955c --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/Search/TvMazeSearch.cs @@ -0,0 +1,8 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class TvMazeSearch + { + public double score { get; set; } + public Show show { get; set; } + } +} diff --git a/Ombi/Ombi.Api.TvMaze/Models/TVMazeSeasons.cs b/Ombi/Ombi.Api.TvMaze/Models/TVMazeSeasons.cs new file mode 100644 index 000000000..c6ec82d51 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/TVMazeSeasons.cs @@ -0,0 +1,7 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class TvMazeSeasons : TvMazeShow + { + public int number { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Models/TvMazeEpisode.cs b/Ombi/Ombi.Api.TvMaze/Models/TvMazeEpisode.cs new file mode 100644 index 000000000..6c5c75f31 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/TvMazeEpisode.cs @@ -0,0 +1,18 @@ +namespace Ombi.Api.TvMaze.Models +{ + public class TvMazeEpisodes + { + public int id { get; set; } + public string url { get; set; } + public string name { get; set; } + public int season { get; set; } + public int number { get; set; } + public string airdate { get; set; } + public string airtime { get; set; } + public string airstamp { get; set; } + public int runtime { get; set; } + public Image image { get; set; } + public string summary { get; set; } + public Links _links { get; set; } + } +} diff --git a/Ombi/Ombi.Api.TvMaze/Models/TvMazeShow.cs b/Ombi/Ombi.Api.TvMaze/Models/TvMazeShow.cs new file mode 100644 index 000000000..ce0572410 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Models/TvMazeShow.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; + +namespace Ombi.Api.TvMaze.Models +{ + public class TvMazeShow + { + public TvMazeShow() + { + Season = new List(); + } + public int id { get; set; } + public string url { get; set; } + public string name { get; set; } + public string type { get; set; } + public string language { get; set; } + public List genres { get; set; } + public string status { get; set; } + public double runtime { get; set; } + public string premiered { get; set; } + public Schedule schedule { get; set; } + public Rating rating { get; set; } + public int weight { get; set; } + public Network network { get; set; } + public object webChannel { get; set; } + public Externals externals { get; set; } + public Image image { get; set; } + public string summary { get; set; } + public int updated { get; set; } + public Links _links { get; set; } + public List Season { get; set; } + public Embedded _embedded { get; set; } + } + + public class TvMazeCustomSeason + { + public int SeasonNumber { get; set; } + public int EpisodeNumber { get; set; } + } + + public class Season + { + public int id { get; set; } + public string url { get; set; } + public int number { get; set; } + public string name { get; set; } + public int? episodeOrder { get; set; } + public string premiereDate { get; set; } + public string endDate { get; set; } + public Network2 network { get; set; } + public object webChannel { get; set; } + public Image2 image { get; set; } + public string summary { get; set; } + public Links2 _links { get; set; } + } + public class Country2 + { + public string name { get; set; } + public string code { get; set; } + public string timezone { get; set; } + } + + public class Network2 + { + public int id { get; set; } + public string name { get; set; } + public Country2 country { get; set; } + } + + public class Image2 + { + public string medium { get; set; } + public string original { get; set; } + } + + public class Self2 + { + public string href { get; set; } + } + + public class Links2 + { + public Self2 self { get; set; } + } + + public class Embedded + { + public List seasons { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj b/Ombi/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj new file mode 100644 index 000000000..a8c3e7a4c --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/Ombi.Api.TvMaze.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.6 + + + + + + + \ No newline at end of file diff --git a/Ombi/Ombi.Api.TvMaze/TvMazeApi.cs b/Ombi/Ombi.Api.TvMaze/TvMazeApi.cs new file mode 100644 index 000000000..0a9376943 --- /dev/null +++ b/Ombi/Ombi.Api.TvMaze/TvMazeApi.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Ombi.Api.TvMaze.Models; + +namespace Ombi.Api.TvMaze +{ + public class TvMazeApi : ITvMazeApi + { + public TvMazeApi() + { + Api = new Ombi.Api.Api(); + //Mapper = mapper; + } + private string Uri = "http://api.tvmaze.com"; + private Api Api { get; } + public async Task> Search(string searchTerm) + { + var request = new Request("search/shows", Uri, HttpMethod.Get); + + request.AddQueryString("q", searchTerm); + request.AddHeader("Content-Type", "application/json"); + + return await Api.Request>(request); + } + + public async Task ShowLookup(int showId) + { + var request = new Request($"shows/{showId}", Uri, HttpMethod.Get); + request.AddHeader("Content-Type", "application/json"); + + return await Api.Request(request); + } + + public async Task> EpisodeLookup(int showId) + { + + var request = new Request($"shows/{showId}/episodes", Uri, HttpMethod.Get); + + request.AddHeader("Content-Type", "application/json"); + + return await Api.Request>(request); + } + + public async Task ShowLookupByTheTvDbId(int theTvDbId) + { + var request = new Request($"lookup/shows?thetvdb={theTvDbId}", Uri, HttpMethod.Get); + request.AddHeader("Content-Type", "application/json"); + try + { + var obj = await Api.Request(request); + + var episodes = await EpisodeLookup(obj.id); + + foreach (var e in episodes) + { + obj.Season.Add(new TvMazeCustomSeason + { + SeasonNumber = e.season, + EpisodeNumber = e.number + }); + } + + return obj; + } + catch (Exception e) + { + // TODO + return null; + } + } + + public async Task> GetSeasons(int id) + { + var request = new Request($"shows/{id}/seasons", Uri, HttpMethod.Get); + + request.AddHeader("Content-Type", "application/json"); + + return await Api.Request>(request); + } + + } +} diff --git a/Ombi/Ombi.Api/Request.cs b/Ombi/Ombi.Api/Request.cs index 2a1881140..7d2a71319 100644 --- a/Ombi/Ombi.Api/Request.cs +++ b/Ombi/Ombi.Api/Request.cs @@ -78,6 +78,29 @@ namespace Ombi.Api ContentHeaders.Add(new KeyValuePair(key, value)); } + public void AddQueryString(string key, string value) + { + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) return; + + var builder = new UriBuilder(_modified); + var startingTag = string.Empty; + var hasQuery = false; + if (string.IsNullOrEmpty(builder.Query)) + { + startingTag = "?"; + } + else + { + hasQuery = true; + startingTag = builder.Query.Contains("?") ? "&" : "?"; + } + + builder.Query = hasQuery + ? $"{builder.Query}{startingTag}{key}={value}" + : $"{startingTag}{key}={value}"; + _modified = builder.Uri; + } + public void AddJsonBody(object obj) { JsonBody = obj; diff --git a/Ombi/Ombi.Core/Claims/OmbiClaims.cs b/Ombi/Ombi.Core/Claims/OmbiClaims.cs index fcfc682ec..3a82e82f6 100644 --- a/Ombi/Ombi.Core/Claims/OmbiClaims.cs +++ b/Ombi/Ombi.Core/Claims/OmbiClaims.cs @@ -29,6 +29,8 @@ namespace Ombi.Core.Claims public static class OmbiClaims { public const string Admin = nameof(Admin); + public const string AutoApproveMovie = nameof(AutoApproveMovie); + public const string AutoApproveTv = nameof(AutoApproveTv); } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Engine/BaseMediaEngine.cs b/Ombi/Ombi.Core/Engine/BaseMediaEngine.cs index 6a3df8195..4a82ed040 100644 --- a/Ombi/Ombi.Core/Engine/BaseMediaEngine.cs +++ b/Ombi/Ombi.Core/Engine/BaseMediaEngine.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Principal; using System.Threading.Tasks; +using Ombi.Core.Claims; using Ombi.Core.Engine.Interfaces; using Ombi.Core.IdentityResolver; using Ombi.Core.Models.Requests; @@ -13,7 +15,7 @@ namespace Ombi.Core.Engine { public abstract class BaseMediaEngine : BaseEngine { - protected BaseMediaEngine(IUserIdentityManager identity, IRequestService service) : base(identity) + protected BaseMediaEngine(IPrincipal identity, IRequestService service) : base(identity) { RequestService = service; } @@ -36,5 +38,43 @@ namespace Ombi.Core.Engine } return _dbMovies; } + + public async Task> GetRequests() + { + var allRequests = await RequestService.GetAllAsync(); + var viewModel = MapToVm(allRequests); + return viewModel; + } + + + protected IEnumerable MapToVm(IEnumerable model) + { + return model.Select(movie => new RequestViewModel + { + ProviderId = movie.ProviderId, + Type = movie.Type, + Status = movie.Status, + ImdbId = movie.ImdbId, + Id = movie.Id, + PosterPath = movie.PosterPath, + ReleaseDate = movie.ReleaseDate, + 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(); + } } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Engine/Interfaces/BaseEngine.cs b/Ombi/Ombi.Core/Engine/Interfaces/BaseEngine.cs index 39573d793..f5f0fb605 100644 --- a/Ombi/Ombi.Core/Engine/Interfaces/BaseEngine.cs +++ b/Ombi/Ombi.Core/Engine/Interfaces/BaseEngine.cs @@ -1,22 +1,56 @@ -using System.Threading.Tasks; -using Ombi.Core.IdentityResolver; -using Ombi.Core.Models; +using System.Security.Principal; +using Ombi.Core.Claims; +using Ombi.Core.Settings.Models; +using Ombi.Store.Entities; namespace Ombi.Core.Engine.Interfaces { public abstract class BaseEngine { - protected BaseEngine(IUserIdentityManager identity) + protected BaseEngine(IPrincipal user) { - UserIdentity = identity; + User = user; } + + protected IPrincipal User { get; } - protected IUserIdentityManager UserIdentity { get; } + protected string Username => User.Identity.Name; - protected async Task GetUser(string username) + protected bool HasRole(string roleName) { - + return User.IsInRole(roleName); } + protected bool ShouldSendNotification(RequestType type) + { + var sendNotification = !ShouldAutoApprove(type); /*|| !prSettings.IgnoreNotifyForAutoApprovedRequests;*/ + + if (HasRole(OmbiClaims.Admin)) + { + sendNotification = false; // Don't bother sending a notification if the user is an admin + + } + return sendNotification; + } + + public bool ShouldAutoApprove(RequestType requestType) + { + var admin = HasRole(OmbiClaims.Admin); + // if the user is an admin, they go ahead and allow auto-approval + if (admin) return true; + + // check by request type if the category requires approval or not + switch (requestType) + { + case RequestType.Movie: + return HasRole(OmbiClaims.AutoApproveMovie); + case RequestType.TvShow: + return HasRole(OmbiClaims.AutoApproveTv); + default: + return false; + } + } + + } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Engine/MovieEngine.cs b/Ombi/Ombi.Core/Engine/MovieSearchEngine.cs similarity index 83% rename from Ombi/Ombi.Core/Engine/MovieEngine.cs rename to Ombi/Ombi.Core/Engine/MovieSearchEngine.cs index 63c8f4e10..e67ca50fb 100644 --- a/Ombi/Ombi.Core/Engine/MovieEngine.cs +++ b/Ombi/Ombi.Core/Engine/MovieSearchEngine.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; using System.Threading.Tasks; using AutoMapper; using Ombi.Api.TheMovieDb; @@ -13,10 +15,10 @@ using Ombi.Store.Entities; namespace Ombi.Core.Engine { - public class MovieEngine : BaseMediaEngine, IMovieEngine + public class MovieSearchEngine : BaseMediaEngine, IMovieEngine { - public MovieEngine(IUserIdentityManager identity, IRequestService service, IMovieDbApi movApi, IMapper mapper, ISettingsService plexSettings, ISettingsService embySettings) + public MovieSearchEngine(IPrincipal identity, IRequestService service, IMovieDbApi movApi, IMapper mapper, ISettingsService plexSettings, ISettingsService embySettings) : base(identity, service) { MovieApi = movApi; @@ -32,14 +34,26 @@ namespace Ombi.Core.Engine public async Task> LookupImdbInformation(IEnumerable movies) { + var searchMovieViewModels + = movies as IList ?? movies.ToList(); + if (searchMovieViewModels == null || !searchMovieViewModels.Any()) + { + return new List(); + } + var retVal = new List(); Dictionary dbMovies = await GetRequests(RequestType.Movie); - foreach (var m in movies) + + + var plexSettings = await PlexSettings.GetSettingsAsync(); + var embySettings = await EmbySettings.GetSettingsAsync(); + + foreach (var m in searchMovieViewModels) { var movieInfo = await MovieApi.GetMovieInformationWithVideo(m.Id); var viewMovie = Mapper.Map(movieInfo); - retVal.Add(await ProcessSingleMovie(viewMovie, dbMovies)); + retVal.Add(await ProcessSingleMovie(viewMovie, dbMovies, plexSettings, embySettings)); } return retVal; } @@ -97,21 +111,21 @@ namespace Ombi.Core.Engine { var viewMovies = new List(); Dictionary dbMovies = await GetRequests(RequestType.Movie); + + var plexSettings = await PlexSettings.GetSettingsAsync(); + var embySettings = await EmbySettings.GetSettingsAsync(); foreach (var movie in movies) { - viewMovies.Add(await ProcessSingleMovie(movie, dbMovies)); + viewMovies.Add(await ProcessSingleMovie(movie, dbMovies, plexSettings, embySettings)); } return viewMovies; } private async Task ProcessSingleMovie(SearchMovieViewModel viewMovie, - Dictionary existingRequests) - { - - var plexSettings = await PlexSettings.GetSettingsAsync(); - var embySettings = await EmbySettings.GetSettingsAsync(); + Dictionary existingRequests, PlexSettings plexSettings, EmbySettings embySettings) + { if (plexSettings.Enable) { // var content = PlexContentRepository.GetAll(); @@ -152,10 +166,10 @@ namespace Ombi.Core.Engine return viewMovie; } - private async Task ProcessSingleMovie(MovieSearchResult movie, Dictionary existingRequests) + private async Task ProcessSingleMovie(MovieSearchResult movie, Dictionary existingRequests, PlexSettings plexSettings, EmbySettings embySettings) { var viewMovie = Mapper.Map(movie); - return await ProcessSingleMovie(viewMovie, existingRequests); + return await ProcessSingleMovie(viewMovie, existingRequests, plexSettings, embySettings); } } } diff --git a/Ombi/Ombi.Core/Engine/RequestEngine.cs b/Ombi/Ombi.Core/Engine/RequestEngine.cs index 2bbfa1c2f..ecc4834e4 100644 --- a/Ombi/Ombi.Core/Engine/RequestEngine.cs +++ b/Ombi/Ombi.Core/Engine/RequestEngine.cs @@ -2,26 +2,24 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Security.Principal; using System.Threading.Tasks; using Ombi.Api.TheMovieDb; using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; using Ombi.Core.Requests.Models; using Ombi.Store.Entities; -using Ombi.TheMovieDbApi; using Ombi.Helpers; namespace Ombi.Core.Engine { - public class RequestEngine : IRequestEngine + public class RequestEngine : BaseMediaEngine, IRequestEngine { - public RequestEngine(IMovieDbApi movieApi, IRequestService requestService) + public RequestEngine(IMovieDbApi movieApi, IRequestService requestService, IPrincipal user) : base(user, requestService) { MovieApi = movieApi; - RequestService = requestService; } private IMovieDbApi MovieApi { get; } - private IRequestService RequestService { get; } public async Task RequestMovie(SearchMovieViewModel model) { var movieInfo = await MovieApi.GetMovieInformation(model.Id); @@ -30,7 +28,8 @@ namespace Ombi.Core.Engine return new RequestEngineResult { RequestAdded = false, - Message = "There was an issue adding this movie!" + Message = "There was an issue adding this movie!", + ErrorMessage = $"TheMovieDb didn't have any information for ID {model.Id}" }; } var fullMovieName = @@ -42,7 +41,7 @@ namespace Ombi.Core.Engine return new RequestEngineResult { RequestAdded = false, - Message = "This has already been requested" + Message = $"{fullMovieName} has already been requested" }; } @@ -86,7 +85,7 @@ namespace Ombi.Core.Engine Status = movieInfo.Status, RequestedDate = DateTime.UtcNow, Approved = false, - //RequestedUsers = new List { Username }, + RequestedUsers = new List { Username }, Issues = IssueState.None, }; @@ -94,7 +93,7 @@ namespace Ombi.Core.Engine { if (ShouldAutoApprove(RequestType.Movie)) { - // model.Approved = true; + model.Approved = true; // var result = await MovieSender.Send(model); // if (result.Result) @@ -154,43 +153,24 @@ namespace Ombi.Core.Engine return null; } - public bool ShouldAutoApprove(RequestType requestType) - { - //var admin = Security.HasPermissions(Context.CurrentUser, Permissions.Administrator); - //// if the user is an admin, they go ahead and allow auto-approval - //if (admin) return true; - //// check by request type if the category requires approval or not - //switch (requestType) - //{ - // case RequestType.Movie: - // return Security.HasPermissions(User, Permissions.AutoApproveMovie); - // case RequestType.TvShow: - // return Security.HasPermissions(User, Permissions.AutoApproveTv); - // case RequestType.Album: - // return Security.HasPermissions(User, Permissions.AutoApproveAlbum); - // default: - // return false; - return false; - } - - private async Task AddRequest(RequestModel model, /*PlexRequestSettings settings,*/ string message) + private async Task AddRequest(RequestModel model, string message) { await RequestService.AddRequestAsync(model); - //if (ShouldSendNotification(model.Type, settings)) - //{ - // var notificationModel = new NotificationModel - // { - // Title = model.Title, - // User = Username, - // DateTime = DateTime.Now, - // NotificationType = NotificationType.NewRequest, - // RequestType = model.Type, - // ImgSrc = model.Type == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}" : model.PosterPath - // }; - // await NotificationService.Publish(notificationModel); - //} + if (ShouldSendNotification(model.Type)) + { + // var notificationModel = new NotificationModel + // { + // Title = model.Title, + // User = Username, + // DateTime = DateTime.Now, + // NotificationType = NotificationType.NewRequest, + // RequestType = model.Type, + // ImgSrc = model.Type == RequestType.Movie ? $"https://image.tmdb.org/t/p/w300/{model.PosterPath}" : model.PosterPath + // }; + // await NotificationService.Publish(notificationModel); + } //var limit = await RequestLimitRepo.GetAllAsync(); //var usersLimit = limit.FirstOrDefault(x => x.Username == Username && x.RequestType == model.Type); @@ -213,13 +193,6 @@ namespace Ombi.Core.Engine return new RequestEngineResult{RequestAdded = true}; } - public async Task> GetRequests() - { - var allRequests = await RequestService.GetAllAsync(); - var viewModel = MapToVm(allRequests); - return viewModel; - } - public async Task> GetRequests(int count, int position) { var allRequests = await RequestService.GetAllAsync(count, position); @@ -264,34 +237,6 @@ namespace Ombi.Core.Engine } - private IEnumerable MapToVm(IEnumerable model) - { - return model.Select(movie => new RequestViewModel - { - ProviderId = movie.ProviderId, - Type = movie.Type, - Status = movie.Status, - ImdbId = movie.ImdbId, - Id = movie.Id, - PosterPath = movie.PosterPath, - ReleaseDate = movie.ReleaseDate, - 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 = false, - 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(); - } + } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Engine/RequestEngineResult.cs b/Ombi/Ombi.Core/Engine/RequestEngineResult.cs index f2f2329a7..a31c52d40 100644 --- a/Ombi/Ombi.Core/Engine/RequestEngineResult.cs +++ b/Ombi/Ombi.Core/Engine/RequestEngineResult.cs @@ -4,5 +4,7 @@ { public bool RequestAdded { get; set; } public string Message { get; set; } + public bool IsError => !string.IsNullOrEmpty(ErrorMessage); + public string ErrorMessage { get; set; } } } \ No newline at end of file diff --git a/Ombi/Ombi.Core/Engine/TvSearchEngine.cs b/Ombi/Ombi.Core/Engine/TvSearchEngine.cs new file mode 100644 index 000000000..64589ba74 --- /dev/null +++ b/Ombi/Ombi.Core/Engine/TvSearchEngine.cs @@ -0,0 +1,29 @@ +using System.Security.Principal; +using AutoMapper; +using Ombi.Api.TvMaze; +using Ombi.Core.Requests.Models; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; + +namespace Ombi.Core.Engine +{ + public class TvSearchEngine : BaseMediaEngine + { + + public TvSearchEngine(IPrincipal identity, IRequestService service, ITvMazeApi tvMaze, IMapper mapper, ISettingsService plexSettings, ISettingsService embySettings) + : base(identity, service) + { + TvMazeApi = tvMaze; + Mapper = mapper; + PlexSettings = plexSettings; + EmbySettings = embySettings; + } + + private ITvMazeApi TvMazeApi { get; } + private IMapper Mapper { get; } + private ISettingsService PlexSettings { get; } + private ISettingsService EmbySettings { get; } + + + } +} diff --git a/Ombi/Ombi.Core/Ombi.Core.csproj b/Ombi/Ombi.Core/Ombi.Core.csproj index 706bf55a4..890c99c07 100644 --- a/Ombi/Ombi.Core/Ombi.Core.csproj +++ b/Ombi/Ombi.Core/Ombi.Core.csproj @@ -16,6 +16,7 @@ + diff --git a/Ombi/Ombi.Core/Settings/Models/LandingPageSettings.cs b/Ombi/Ombi.Core/Settings/Models/LandingPageSettings.cs new file mode 100644 index 000000000..a26d0a6ba --- /dev/null +++ b/Ombi/Ombi.Core/Settings/Models/LandingPageSettings.cs @@ -0,0 +1,22 @@ +using System; +using Newtonsoft.Json; + +namespace Ombi.Core.Settings.Models +{ + public class LandingPageSettings : Settings + { + public bool Enabled { get; set; } + public bool BeforeLogin { get; set; } + + [JsonIgnore] + public bool AfterLogin => !BeforeLogin; + + public bool NoticeEnabled => !string.IsNullOrEmpty(NoticeText); + public string NoticeText { get; set; } + public string NoticeBackgroundColor { get; set; } + + public bool TimeLimit { get; set; } + public DateTime StartDateTime { get; set; } + public DateTime EndDateTime { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.DependencyInjection/IocExtensions.cs b/Ombi/Ombi.DependencyInjection/IocExtensions.cs index f03f1ddec..3b9444c04 100644 --- a/Ombi/Ombi.DependencyInjection/IocExtensions.cs +++ b/Ombi/Ombi.DependencyInjection/IocExtensions.cs @@ -1,13 +1,16 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Security.Principal; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Ombi.Api.Emby; using Ombi.Api.Plex; using Ombi.Api.Sonarr; using Ombi.Api.TheMovieDb; +using Ombi.Api.TvMaze; using Ombi.Core; using Ombi.Core.Engine; using Ombi.Core.IdentityResolver; @@ -38,7 +41,7 @@ namespace Ombi.DependencyInjection public static IServiceCollection RegisterEngines(this IServiceCollection services) { - services.AddTransient(); + services.AddTransient(); services.AddTransient(); return services; } @@ -49,6 +52,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } @@ -80,6 +84,7 @@ namespace Ombi.DependencyInjection public static IServiceCollection RegisterIdentity(this IServiceCollection services) { + services.AddTransient(); services.AddAuthorization(auth => { diff --git a/Ombi/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj b/Ombi/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj index 48fbec61b..e623ef6d1 100644 --- a/Ombi/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj +++ b/Ombi/Ombi.DependencyInjection/Ombi.DependencyInjection.csproj @@ -14,6 +14,7 @@ + diff --git a/Ombi/Ombi.Helpers/StringCipher.cs b/Ombi/Ombi.Helpers/StringCipher.cs index f55238ca3..d08a3e1ad 100644 --- a/Ombi/Ombi.Helpers/StringCipher.cs +++ b/Ombi/Ombi.Helpers/StringCipher.cs @@ -86,13 +86,15 @@ namespace Ombi.Helpers public static string EncryptString(string text, string keyString) { - var result = AesEncryption.EncryptWithPassword(text, keyString); + var t = Encoding.UTF8.GetBytes(text); + var result = Convert.ToBase64String(t); return result; } public static string DecryptString(string cipherText, string keyString) { - var result = AesEncryption.DecryptWithPassword(cipherText, keyString); + var textAsBytes = Convert.FromBase64String(cipherText); + var result = Encoding.UTF8.GetString(textAsBytes); return result; } } diff --git a/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs b/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs index 4637958b3..d20f884a9 100644 --- a/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs +++ b/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs @@ -17,7 +17,7 @@ namespace Ombi.Api.TheMovieDb } private IMapper Mapper { get; } - private readonly string ApiToken = StringCipher.DecryptString("bqCrDAQABAC/mJT6JXNdlQ1boOjsHeQgyk7gcNv7tUFtwxoVEnYvqS+UdgfgoyXnBz2F6LJnKX8xGtXbzLsf6pbxDkxna6zvunivxAcAHewo2zTPjoUB5igeMB8d93fx0WO9IhGtq8oGXv++xfaXfTY3aN5NV7JmF6ziAAAAAD1e5VjRPSLOYTyJ3Hbw9bDsE/4FGxYIrvxVkqDMl1vAosOeTi+0kKPFloF6k2ptTw==", "Ombiv3SettingsEncryptionPassword"); + private readonly string ApiToken = "b8eabaf5608b88d0298aa189dd90bf00"; private static readonly string BaseUri ="http://api.themoviedb.org/3/"; private Ombi.Api.Api Api { get; } diff --git a/Ombi/Ombi.sln b/Ombi/Ombi.sln index 007325471..d7c88b370 100644 --- a/Ombi/Ombi.sln +++ b/Ombi/Ombi.sln @@ -42,7 +42,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Sonarr", "Ombi.Api EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6F42AB98-9196-44C4-B888-D5E409F415A1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{2836861C-1185-4E56-A0C2-F4EB541C74AE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.TvMaze", "Ombi.Api.TvMaze\Ombi.Api.TvMaze.csproj", "{0E8EF835-E4F0-4EE5-A2B6-678DEE973721}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -98,10 +98,10 @@ Global {CFB5E008-D0D0-43C0-AA06-89E49D17F384}.Debug|Any CPU.Build.0 = Debug|Any CPU {CFB5E008-D0D0-43C0-AA06-89E49D17F384}.Release|Any CPU.ActiveCfg = Release|Any CPU {CFB5E008-D0D0-43C0-AA06-89E49D17F384}.Release|Any CPU.Build.0 = Release|Any CPU - {2836861C-1185-4E56-A0C2-F4EB541C74AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2836861C-1185-4E56-A0C2-F4EB541C74AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2836861C-1185-4E56-A0C2-F4EB541C74AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2836861C-1185-4E56-A0C2-F4EB541C74AE}.Release|Any CPU.Build.0 = Release|Any CPU + {0E8EF835-E4F0-4EE5-A2B6-678DEE973721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E8EF835-E4F0-4EE5-A2B6-678DEE973721}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E8EF835-E4F0-4EE5-A2B6-678DEE973721}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E8EF835-E4F0-4EE5-A2B6-678DEE973721}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -114,6 +114,6 @@ Global {2E1A7B91-F29B-42BC-8F1E-1CF2DCC389BA} = {9293CA11-360A-4C20-A674-B9E794431BF5} {08FF107D-31E1-470D-AF86-E09B015CEE06} = {9293CA11-360A-4C20-A674-B9E794431BF5} {CFB5E008-D0D0-43C0-AA06-89E49D17F384} = {9293CA11-360A-4C20-A674-B9E794431BF5} - {2836861C-1185-4E56-A0C2-F4EB541C74AE} = {6F42AB98-9196-44C4-B888-D5E409F415A1} + {0E8EF835-E4F0-4EE5-A2B6-678DEE973721} = {9293CA11-360A-4C20-A674-B9E794431BF5} EndGlobalSection EndGlobal diff --git a/Ombi/Ombi/Controllers/RequestController.cs b/Ombi/Ombi/Controllers/RequestController.cs index 71e436122..3b5135d85 100644 --- a/Ombi/Ombi/Controllers/RequestController.cs +++ b/Ombi/Ombi/Controllers/RequestController.cs @@ -39,6 +39,7 @@ namespace Ombi.Controllers [HttpGet("search/{searchTerm}")] public async Task> Search(string searchTerm) { + return await RequestEngine.SearchRequest(searchTerm); } diff --git a/Ombi/Ombi/Controllers/SettingsController.cs b/Ombi/Ombi/Controllers/SettingsController.cs index e6a31bb19..e513c8e49 100644 --- a/Ombi/Ombi/Controllers/SettingsController.cs +++ b/Ombi/Ombi/Controllers/SettingsController.cs @@ -29,7 +29,6 @@ namespace Ombi.Controllers public async Task OmbiSettings([FromBody]OmbiSettings ombi) { return await Save(ombi); - } [HttpGet("plex")] @@ -56,6 +55,18 @@ namespace Ombi.Controllers return await Save(emby); } + [HttpGet("landingpage")] + public async Task LandingPageSettings() + { + return await Get(); + } + + [HttpPost("landingpage")] + public async Task LandingPageSettings([FromBody]LandingPageSettings settings) + { + return await Save(settings); + } + private async Task Get() { diff --git a/Ombi/Ombi/Startup.cs b/Ombi/Ombi/Startup.cs index f737b7633..6bd14cde8 100644 --- a/Ombi/Ombi/Startup.cs +++ b/Ombi/Ombi/Startup.cs @@ -1,10 +1,14 @@ -using AutoMapper; +using System; +using System.Configuration; +using System.Security.Principal; +using AutoMapper; using AutoMapper.EquivalencyExpression; using Hangfire; using Hangfire.MemoryStorage; using Hangfire.RecurringJobExtensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -42,6 +46,10 @@ namespace Ombi }); services.RegisterDependencies(); // Ioc and EF + services.AddSingleton(); + //services.AddTransient(new InjectionFactory(u => HttpContext.Current.User)); + services.AddScoped(sp => sp.GetService().HttpContext.User); + services.AddHangfire(x => { diff --git a/Ombi/Ombi/wwwroot/app/app.module.ts b/Ombi/Ombi/wwwroot/app/app.module.ts index e74ce4265..7d2d5fdf9 100644 --- a/Ombi/Ombi/wwwroot/app/app.module.ts +++ b/Ombi/Ombi/wwwroot/app/app.module.ts @@ -11,6 +11,7 @@ import { HttpModule } from '@angular/http'; import { InfiniteScrollModule } from 'ngx-infinite-scroll' import { SearchComponent } from './search/search.component'; +import { MovieSearchComponent } from './search/moviesearch.component'; import { RequestComponent } from './requests/request.component'; import { LoginComponent } from './login/login.component'; import { PageNotFoundComponent } from './errors/not-found.component'; @@ -64,7 +65,8 @@ const routes: Routes = [ PageNotFoundComponent, SearchComponent, RequestComponent, - LoginComponent + LoginComponent, + MovieSearchComponent ], providers: [ SearchService, diff --git a/Ombi/Ombi/wwwroot/app/interfaces/ISettings.ts b/Ombi/Ombi/wwwroot/app/interfaces/ISettings.ts index db94a0313..f3aa4e39c 100644 --- a/Ombi/Ombi/wwwroot/app/interfaces/ISettings.ts +++ b/Ombi/Ombi/wwwroot/app/interfaces/ISettings.ts @@ -36,4 +36,15 @@ export interface ISonarrSettings extends IExternalSettings { seasonFolders: boolean, rootPath: string, fullRootPath:string +} + +export interface ILandingPageSettings extends ISettings { + enabled: boolean, + beforeLogin: boolean, + afterLogin: boolean, + noticeText: string, + noticeBackgroundColor: string, + timeLimit: boolean, + startDateTime: Date, + endDateTime:Date, } \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/search/moviesearch.component.html b/Ombi/Ombi/wwwroot/app/search/moviesearch.component.html new file mode 100644 index 000000000..1dee2808f --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/search/moviesearch.component.html @@ -0,0 +1,154 @@ + +
+ +
+
+ +
+
+
+
+ + + poster + +
+
+
+ +

{{result.title}} ({{result.releaseDate | date: 'yyyy'}})

+
+ + + Air Date: {{result.firstAired | date: 'dd/MM/yyyy'}} + + + Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}} + + Available + Processing Request +
+ + + + + + + + HomePage + + Trailer + + +
+
+
+

{{result.overview}}

+
+ + +
+ + +
+ + +
+
+
+ View In Plex + +
+
+
+ + + + + + +
+
+ + + +
+ +
+ +
+
+
+ +
+
\ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/search/moviesearch.component.ts b/Ombi/Ombi/wwwroot/app/search/moviesearch.component.ts new file mode 100644 index 000000000..a72d2a058 --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/search/moviesearch.component.ts @@ -0,0 +1,110 @@ +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({ + selector: 'movie-search', + moduleId: module.id, + templateUrl: './moviesearch.component.html', +}) +export class MovieSearchComponent implements OnInit { + + searchText: string; + searchChanged: Subject = new Subject(); + movieResults: ISearchMovieResult[]; + result: IRequestEngineResult; + + 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 { + 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); + } + }); + } + + popularMovies() { + this.clearResults(); + 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() { + this.movieResults = []; + } + +} \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/search/search.component.html b/Ombi/Ombi/wwwroot/app/search/search.component.html index 464e08e31..23ec5eafc 100644 --- a/Ombi/Ombi/wwwroot/app/search/search.component.html +++ b/Ombi/Ombi/wwwroot/app/search/search.component.html @@ -30,32 +30,7 @@ - - - -
-
-
- - - poster - -
-
-
- -

{{result.title}} ({{result.releaseDate | date: 'yyyy'}})

-
- - - Air Date: {{result.firstAired | date: 'dd/MM/yyyy'}} - - - Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}} - - Available - Processing Request -
- - - - - - - - HomePage - Trailer - - -
-
-
-

{{result.overview}}

-
- - -
- - -
- - -
-
-
- View In Plex - -
-
-
- - - - - - -
- - -
- -
-
-
diff --git a/Ombi/Ombi/wwwroot/app/services/settings.service.ts b/Ombi/Ombi/wwwroot/app/services/settings.service.ts index d55333894..1327aa8f5 100644 --- a/Ombi/Ombi/wwwroot/app/services/settings.service.ts +++ b/Ombi/Ombi/wwwroot/app/services/settings.service.ts @@ -3,7 +3,7 @@ import { AuthHttp } from 'angular2-jwt'; import { Observable } from 'rxjs/Rx'; import { ServiceAuthHelpers } from './service.helpers'; -import { IOmbiSettings, IEmbySettings, IPlexSettings, ISonarrSettings } from '../interfaces/ISettings'; +import { IOmbiSettings, IEmbySettings, IPlexSettings, ISonarrSettings,ILandingPageSettings } from '../interfaces/ISettings'; @Injectable() export class SettingsService extends ServiceAuthHelpers { @@ -42,5 +42,12 @@ export class SettingsService extends ServiceAuthHelpers { saveSonarr(settings: ISonarrSettings): Observable { return this.http.post(`${this.url}/Sonarr`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); } + getLandingPage(): Observable { + return this.http.get(`${this.url}/LandingPage`).map(this.extractData); + } + + saveLandingPage(settings: ILandingPageSettings): Observable { + return this.http.post(`${this.url}/LandingPage`, JSON.stringify(settings), { headers: this.headers }).map(this.extractData); + } } \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.html b/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.html new file mode 100644 index 000000000..236b899d1 --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.html @@ -0,0 +1,41 @@ +
+
+ Landing Page Configuration + + +
+
+ + +
+
+ + + +
+
+ + +
+ If enabled then this will show the landing page before the login page, if this is disabled the user will log in first and then see the landing page. +
+ +

Notice Message

+
+
+ +
+
+ +

Notice Preview:

+
+
+
+ +
+
+ +
+
+
+
\ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.ts b/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.ts new file mode 100644 index 000000000..35506508a --- /dev/null +++ b/Ombi/Ombi/wwwroot/app/settings/landingpage/landingpage.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; + +import { ILandingPageSettings } from '../../interfaces/ISettings' +import { SettingsService } from '../../services/settings.service'; +import { NotificationService } from "../../services/notification.service"; + +@Component({ + selector: 'ombi', + moduleId: module.id, + templateUrl: './landingpage.component.html', +}) +export class LandingPageComponent implements OnInit { + + constructor(private settingsService: SettingsService, private notificationService: NotificationService) { } + + settings: ILandingPageSettings; + + ngOnInit(): void { + this.settingsService.getLandingPage().subscribe(x => this.settings = x); + } + + save() { + this.settingsService.saveLandingPage(this.settings).subscribe(x => { + if (x) { + this.notificationService.success("Settings Saved", "Successfully saved the Landing Page settings"); + } else { + this.notificationService.success("Settings Saved", "There was an error when saving the Landing Page settings"); + } + }); + } +} \ No newline at end of file diff --git a/Ombi/Ombi/wwwroot/app/settings/settings.module.ts b/Ombi/Ombi/wwwroot/app/settings/settings.module.ts index 10df7055f..525eb1706 100644 --- a/Ombi/Ombi/wwwroot/app/settings/settings.module.ts +++ b/Ombi/Ombi/wwwroot/app/settings/settings.module.ts @@ -11,6 +11,7 @@ import { SonarrService } from '../services/applications/sonarr.service'; import { OmbiComponent } from './ombi/ombi.component' import { PlexComponent } from './plex/plex.component' import { EmbyComponent } from './emby/emby.component' +import { LandingPageComponent } from './landingpage/landingpage.component' import { SettingsMenuComponent } from './settingsmenu.component'; @@ -20,6 +21,7 @@ const routes: Routes = [ { path: 'Settings/Ombi', component: OmbiComponent, canActivate: [AuthGuard] }, { path: 'Settings/Plex', component: PlexComponent, canActivate: [AuthGuard] }, { path: 'Settings/Emby', component: EmbyComponent, canActivate: [AuthGuard] }, + { path: 'Settings/LandingPage', component: LandingPageComponent, canActivate: [AuthGuard] }, ]; @NgModule({ @@ -37,6 +39,7 @@ const routes: Routes = [ OmbiComponent, PlexComponent, EmbyComponent, + LandingPageComponent, ], exports: [ RouterModule diff --git a/Ombi/Ombi/wwwroot/app/wizard/createadmin/createadmin.component.ts b/Ombi/Ombi/wwwroot/app/wizard/createadmin/createadmin.component.ts index 73cce5535..97a21bb4b 100644 --- a/Ombi/Ombi/wwwroot/app/wizard/createadmin/createadmin.component.ts +++ b/Ombi/Ombi/wwwroot/app/wizard/createadmin/createadmin.component.ts @@ -32,9 +32,11 @@ export class CreateAdminComponent { this.settings.getOmbi().subscribe(ombi => { ombi.wizard = true; - this.settings.saveOmbi(ombi).subscribe(); + this.settings.saveOmbi(ombi).subscribe(x => { + + this.router.navigate(['search']); + }); - this.router.navigate(['search']); }); });