From 2976e87cc56d0cba73eef46c55de6ae29a46366f Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 18 Jan 2017 21:30:19 +0000 Subject: [PATCH 1/7] #951 --- Ombi.Services/Jobs/RecentlyAdded.cs | 2 +- Ombi.Services/Notification/EmailMessageNotification.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Ombi.Services/Jobs/RecentlyAdded.cs b/Ombi.Services/Jobs/RecentlyAdded.cs index 7e7293578..667ce542e 100644 --- a/Ombi.Services/Jobs/RecentlyAdded.cs +++ b/Ombi.Services/Jobs/RecentlyAdded.cs @@ -455,7 +455,7 @@ namespace Ombi.Services.Jobs if (!testEmail) { - var users = UserHelper.GetUsersWithFeature(Features.RequestAddedNotification); + var users = UserHelper.GetUsersWithFeature(Features.Newsletter); if (users != null) { foreach (var user in users) diff --git a/Ombi.Services/Notification/EmailMessageNotification.cs b/Ombi.Services/Notification/EmailMessageNotification.cs index f073dcf02..1de8ef7e6 100644 --- a/Ombi.Services/Notification/EmailMessageNotification.cs +++ b/Ombi.Services/Notification/EmailMessageNotification.cs @@ -244,9 +244,9 @@ namespace Ombi.Services.Notification var email = new EmailBasicTemplate(); var html = email.LoadTemplate( $"Ombi: {model.Title} is now available!", - $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)", + $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)", model.ImgSrc); - var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)" }; + var body = new BodyBuilder { HtmlBody = html, TextBody = $"Hello! You requested {model.Title} on Ombi! This is now available on Plex! :)" }; var message = new MimeMessage { From 80a9e54c4bb1a2802a02236baffbdaed44ad4b90 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Thu, 19 Jan 2017 08:19:23 +0000 Subject: [PATCH 2/7] Fixed #947 --- Ombi.UI/Modules/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ombi.UI/Modules/UserManagementModule.cs b/Ombi.UI/Modules/UserManagementModule.cs index 92d848606..af62f880e 100644 --- a/Ombi.UI/Modules/UserManagementModule.cs +++ b/Ombi.UI/Modules/UserManagementModule.cs @@ -420,7 +420,7 @@ namespace Ombi.UI.Modules FeaturesFormattedString = newUser ? "Processing..." : features.ToString(), Username = plexInfo.Title, Type = UserType.PlexUser, - EmailAddress = plexInfo.Email, + EmailAddress = string.IsNullOrEmpty(plexInfo.Email) ? dbUser.EmailAddress : plexInfo.Email, Alias = dbUser?.UserAlias ?? string.Empty, LastLoggedIn = lastLoggedIn, PlexInfo = new UserManagementPlexInformation From eec7d42a8894eec3e52662767bec96c934ed192a Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Thu, 19 Jan 2017 08:45:13 +0000 Subject: [PATCH 3/7] #956 --- Ombi.UI/Modules/UserLoginModule.cs | 32 ++++++++++++++++++- .../UserManagementSettings.cshtml | 4 +++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Ombi.UI/Modules/UserLoginModule.cs b/Ombi.UI/Modules/UserLoginModule.cs index 434892496..59c30a1aa 100644 --- a/Ombi.UI/Modules/UserLoginModule.cs +++ b/Ombi.UI/Modules/UserLoginModule.cs @@ -233,13 +233,28 @@ namespace Ombi.UI.Modules var result = await AuthenticationSetup(userId, username, dateTimeOffset, loginGuid, isOwner); + var landingSettings = await LandingPageSettings.GetSettingsAsync(); + + if (landingSettings.Enabled) + { + if (!landingSettings.BeforeLogin) // After Login + { + var uri = Linker.BuildRelativeUri(Context, "LandingPageIndex"); + if (loginGuid != Guid.Empty) + { + return CustomModuleExtensions.LoginAndRedirect(this, result.LoginGuid, null, uri.ToString()); + } + return Response.AsRedirect(uri.ToString()); + } + } + + var retVal = Linker.BuildRelativeUri(Context, "SearchIndex"); if (result.LoginGuid != Guid.Empty) { return CustomModuleExtensions.LoginAndRedirect(this, result.LoginGuid, null, retVal.ToString()); } return Response.AsJson(new { result = true, url = retVal.ToString() }); - } private async Task IsPlexUser(string username) @@ -318,6 +333,21 @@ namespace Ombi.UI.Modules var m = await AuthenticationSetup(userId, username, dateTimeOffset, loginGuid, isOwner); + var landingSettings = await LandingPageSettings.GetSettingsAsync(); + + if (landingSettings.Enabled) + { + if (!landingSettings.BeforeLogin) // After Login + { + var uri = Linker.BuildRelativeUri(Context, "LandingPageIndex"); + if (m.LoginGuid != Guid.Empty) + { + return CustomModuleExtensions.LoginAndRedirect(this, m.LoginGuid, null, uri.ToString()); + } + return Response.AsRedirect(uri.ToString()); + } + } + var retVal = Linker.BuildRelativeUri(Context, "SearchIndex"); if (m.LoginGuid != Guid.Empty) { diff --git a/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml b/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml index a48eae095..db0fae5f2 100644 --- a/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml +++ b/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml @@ -8,6 +8,10 @@ User Management Settings Here you can manage the default permissions and features that your users get + + Note: This will not update your users that are currently there, this is to set the default settings to any users added outside of Ombi e.g. You share your Plex Server with a new user, they will be added into Ombi + automatically and will take the permissions and features you have selected below. +

Permissions

From 05fbdf2a384f6a07287d95ecef928d00f5df0499 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 20 Jan 2017 08:11:22 +0000 Subject: [PATCH 4/7] Fixed #955 --- Ombi.UI/Modules/RequestsModule.cs | 3 +++ Ombi.UI/Modules/SearchModule.cs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Ombi.UI/Modules/RequestsModule.cs b/Ombi.UI/Modules/RequestsModule.cs index f0c0934ac..9c5460323 100644 --- a/Ombi.UI/Modules/RequestsModule.cs +++ b/Ombi.UI/Modules/RequestsModule.cs @@ -235,6 +235,8 @@ namespace Ombi.UI.Modules } + + var canManageRequest = Security.HasAnyPermissions(User, Permissions.Administrator, Permissions.ManageRequests); var viewModel = dbTv.Select(tv => new RequestViewModel { @@ -243,6 +245,7 @@ namespace Ombi.UI.Modules Status = tv.Status, ImdbId = tv.ImdbId, Id = tv.Id, + //PosterPath = tv.PosterPath.Contains("http:") ? tv.PosterPath.Replace("http:", "https:") : tv.PosterPath, PosterPath = tv.PosterPath, ReleaseDate = tv.ReleaseDate, ReleaseDateTicks = tv.ReleaseDate.Ticks, diff --git a/Ombi.UI/Modules/SearchModule.cs b/Ombi.UI/Modules/SearchModule.cs index b64b586f8..10be9bfdb 100644 --- a/Ombi.UI/Modules/SearchModule.cs +++ b/Ombi.UI/Modules/SearchModule.cs @@ -693,11 +693,13 @@ namespace Ombi.UI.Modules DateTime.TryParse(showInfo.premiered, out firstAir); 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 RequestedModel { Type = RequestType.TvShow, Overview = showInfo.summary.RemoveHtml(), - PosterPath = showInfo.image?.medium, + PosterPath = posterPath, Title = showInfo.name, ReleaseDate = firstAir, Status = showInfo.status, From 7cbea541cef12d020243a18888883c9e0cc2865a Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 20 Jan 2017 08:13:19 +0000 Subject: [PATCH 5/7] Fixed --- Ombi.UI/Modules/RequestsModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Ombi.UI/Modules/RequestsModule.cs b/Ombi.UI/Modules/RequestsModule.cs index 9c5460323..4faefa206 100644 --- a/Ombi.UI/Modules/RequestsModule.cs +++ b/Ombi.UI/Modules/RequestsModule.cs @@ -245,8 +245,7 @@ namespace Ombi.UI.Modules Status = tv.Status, ImdbId = tv.ImdbId, Id = tv.Id, - //PosterPath = tv.PosterPath.Contains("http:") ? tv.PosterPath.Replace("http:", "https:") : tv.PosterPath, - PosterPath = tv.PosterPath, + PosterPath = tv.PosterPath.Contains("http:") ? tv.PosterPath.Replace("http:", "https:") : tv.PosterPath, // We make the poster path https on request, but this is just incase ReleaseDate = tv.ReleaseDate, ReleaseDateTicks = tv.ReleaseDate.Ticks, RequestedDate = tv.RequestedDate, From 9886c404992353191b58dfe9edfaedf65f5c2ee0 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Fri, 20 Jan 2017 15:56:49 +0000 Subject: [PATCH 6/7] Added a bunch of categories for tv search similar to what we have for movies. --- Ombi.Api.Interfaces/ITraktApi.cs | 16 + .../Ombi.Api.Interfaces.csproj | 9 + Ombi.Api.Interfaces/packages.config | 2 + Ombi.Api/Ombi.Api.csproj | 5 + Ombi.Api/TraktApi.cs | 51 ++ Ombi.Api/packages.config | 1 + Ombi.Helpers/DateTimeHelper.cs | 7 + Ombi.UI/Content/search.js | 59 +- Ombi.UI/Models/SearchTvShowViewModel.cs | 15 + Ombi.UI/Modules/SearchModule.cs | 211 +++++++- Ombi.UI/NinjectModules/ApiModule.cs | 1 + Ombi.UI/Ombi.UI.csproj | 4 + Ombi.UI/Views/Search/Index.cshtml | 508 +++++++++--------- Ombi.UI/packages.config | 1 + 14 files changed, 641 insertions(+), 249 deletions(-) create mode 100644 Ombi.Api.Interfaces/ITraktApi.cs create mode 100644 Ombi.Api/TraktApi.cs diff --git a/Ombi.Api.Interfaces/ITraktApi.cs b/Ombi.Api.Interfaces/ITraktApi.cs new file mode 100644 index 000000000..ed20f039c --- /dev/null +++ b/Ombi.Api.Interfaces/ITraktApi.cs @@ -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.Interfaces +{ + public interface ITraktApi + { + Task> GetAnticipatedShows(int? page = default(int?), int? limitPerPage = default(int?)); + Task> GetMostWatchesShows(TraktTimePeriod period = null, int? page = default(int?), int? limitPerPage = default(int?)); + Task> GetPopularShows(int? page = default(int?), int? limitPerPage = default(int?)); + Task> GetTrendingShows(int? page = default(int?), int? limitPerPage = default(int?)); + } +} \ No newline at end of file diff --git a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj index 1cc18964a..c8c1ca938 100644 --- a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj +++ b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj @@ -31,6 +31,10 @@ 4 + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True + ..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll True @@ -43,6 +47,10 @@ + + ..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll + True + @@ -58,6 +66,7 @@ + diff --git a/Ombi.Api.Interfaces/packages.config b/Ombi.Api.Interfaces/packages.config index a63cb4deb..5ac87cab2 100644 --- a/Ombi.Api.Interfaces/packages.config +++ b/Ombi.Api.Interfaces/packages.config @@ -1,4 +1,6 @@  + + \ No newline at end of file diff --git a/Ombi.Api/Ombi.Api.csproj b/Ombi.Api/Ombi.Api.csproj index 27a889451..b9e674cc2 100644 --- a/Ombi.Api/Ombi.Api.csproj +++ b/Ombi.Api/Ombi.Api.csproj @@ -66,12 +66,17 @@ ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll True + + ..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll + True + + diff --git a/Ombi.Api/TraktApi.cs b/Ombi.Api/TraktApi.cs new file mode 100644 index 000000000..ae2ff11b2 --- /dev/null +++ b/Ombi.Api/TraktApi.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Ombi.Api.Interfaces; +using Ombi.Helpers; +using TraktApiSharp; +using TraktApiSharp.Enums; +using TraktApiSharp.Objects.Get.Shows; +using TraktApiSharp.Objects.Get.Shows.Common; +using TraktApiSharp.Requests.Params; + +namespace Ombi.Api +{ + public class TraktApi : ITraktApi + { + private TraktClient Client { get; } + + private static readonly string Encrypted = "z/56wM/oEkkCWEvSIZCrzQyUvvqmafQ3njqf0UNK5xuKbNYh5Wz8ocoG2QDa5y1DBkozLaKsGxORmAB1XUvwbnom8DVNo9gE++9GTuwxmGlLDD318PXpRmYmpKqNwFSKRZgF6ewiY9qR4t3iG0pGQwPA08FK3+H7kpOKAGJNR9RMDP9wwB6Vl4DuOiZb9/DETjzZ+/zId0ZqimrbN+PLrg=="; + private readonly string _apiKey = StringCipher.Decrypt(Encrypted, "ApiKey"); + public TraktApi() + { + Client = new TraktClient(_apiKey); + } + + public async Task> GetPopularShows(int? page = null, int? limitPerPage = null) + { + var popular = await Client.Shows.GetPopularShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10); + return popular.Items; + } + + public async Task> GetTrendingShows(int? page = null, int? limitPerPage = null) + { + var trendingShowsTop10 = await Client.Shows.GetTrendingShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10); + return trendingShowsTop10.Items; + } + + public async Task> GetAnticipatedShows(int? page = null, int? limitPerPage = null) + { + var anticipatedShows = await Client.Shows.GetMostAnticipatedShowsAsync(new TraktExtendedInfo { Full = true }, null, page ?? 1, limitPerPage ?? 10); + return anticipatedShows.Items; + } + + public async Task> 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.Items; + } + } +} diff --git a/Ombi.Api/packages.config b/Ombi.Api/packages.config index ce5ccf24e..a20220585 100644 --- a/Ombi.Api/packages.config +++ b/Ombi.Api/packages.config @@ -8,4 +8,5 @@ + \ No newline at end of file diff --git a/Ombi.Helpers/DateTimeHelper.cs b/Ombi.Helpers/DateTimeHelper.cs index d8dbc681a..b25972ddf 100644 --- a/Ombi.Helpers/DateTimeHelper.cs +++ b/Ombi.Helpers/DateTimeHelper.cs @@ -46,5 +46,12 @@ namespace Ombi.Helpers dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); return dtDateTime; } + + public static long ToJavascriptTimestamp(this DateTime input) + { + var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var time = input.Subtract(new TimeSpan(epoch.Ticks)); + return (long)(time.Ticks / 10000); + } } } diff --git a/Ombi.UI/Content/search.js b/Ombi.UI/Content/search.js index 8b9c10109..14f675562 100644 --- a/Ombi.UI/Content/search.js +++ b/Ombi.UI/Content/search.js @@ -72,6 +72,25 @@ $(function () { moviesInTheaters(); }); + // TV DropDown + $('#popularShows').on('click', function (e) { + e.preventDefault(); + popularShows(); + }); + + $('#trendingShows').on('click', function (e) { + e.preventDefault(); + trendingTv(); + }); + $('#mostWatchedShows').on('click', function (e) { + e.preventDefault(); + mostwatchedTv(); + }); + $('#anticipatedShows').on('click', function (e) { + e.preventDefault(); + anticipatedTv(); + }); + // Type in TV search $("#tvSearchContent").on("input", function () { if (searchTimer) { @@ -293,6 +312,23 @@ $(function () { getMovies(url); } + function popularShows() { + var url = createBaseUrl(base, '/search/tv/popular'); + getTvShows(url, true); + } + function anticipatedTv() { + var url = createBaseUrl(base, '/search/tv/anticipated'); + getTvShows(url, true); + } + function trendingTv() { + var url = createBaseUrl(base, '/search/tv/trending'); + getTvShows(url, true); + } + function mostwatchedTv() { + var url = createBaseUrl(base, '/search/tv/mostwatched'); + getTvShows(url, true); + } + function getMovies(url) { resetMovies(); @@ -323,10 +359,10 @@ $(function () { var query = $("#tvSearchContent").val(); var url = createBaseUrl(base, '/search/tv/'); - query ? getTvShows(url + query) : resetTvShows(); + query ? getTvShows(url + query, false) : resetTvShows(); } - function getTvShows(url) { + function getTvShows(url, loadImage) { resetTvShows(); $('#tvSearchButton').attr("class", "fa fa-spinner fa-spin"); @@ -338,7 +374,9 @@ $(function () { $("#tvList").append(html); checkNetflix(context.title, context.id); - + if (loadImage) { + getTvPoster(result.id); + } }); } else { @@ -406,6 +444,16 @@ $(function () { }); }; + function getTvPoster(theTvDbId) { + + var url = createBaseUrl(base, '/search/tv/poster/'); + $.ajax(url + theTvDbId).success(function (result) { + if (result) { + $('#' + theTvDbId + "imgDiv").html(" poster"); + } + }); + }; + function buildMovieContext(result) { var date = new Date(result.releaseDate); var year = date.getFullYear(); @@ -432,6 +480,7 @@ $(function () { var date = new Date(result.firstAired); var year = date.getFullYear(); var context = { + status : result.status, posterPath: result.banner, id: result.id, title: result.seriesName, @@ -448,7 +497,9 @@ $(function () { tvPartialAvailable: result.tvPartialAvailable, disableTvRequestsByEpisode: result.disableTvRequestsByEpisode, disableTvRequestsBySeason: result.disableTvRequestsBySeason, - enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries + enableTvRequestsForOnlySeries: result.enableTvRequestsForOnlySeries, + trailer: result.trailer, + homepage: result.homepage }; return context; diff --git a/Ombi.UI/Models/SearchTvShowViewModel.cs b/Ombi.UI/Models/SearchTvShowViewModel.cs index faa6333ba..29380a835 100644 --- a/Ombi.UI/Models/SearchTvShowViewModel.cs +++ b/Ombi.UI/Models/SearchTvShowViewModel.cs @@ -58,5 +58,20 @@ namespace Ombi.UI.Models public bool DisableTvRequestsByEpisode { get; set; } public bool DisableTvRequestsBySeason { get; set; } public bool EnableTvRequestsForOnlySeries { get; set; } + + /// + /// This is used from the Trakt API + /// + /// + /// The trailer. + /// + public string Trailer { get; set; } + /// + /// This is used from the Trakt API + /// + /// + /// The trailer. + /// + public string Homepage { get; set; } } } \ No newline at end of file diff --git a/Ombi.UI/Modules/SearchModule.cs b/Ombi.UI/Modules/SearchModule.cs index 10be9bfdb..63cc4c03c 100644 --- a/Ombi.UI/Modules/SearchModule.cs +++ b/Ombi.UI/Modules/SearchModule.cs @@ -58,6 +58,7 @@ using Ombi.Store.Repository; using Ombi.UI.Helpers; using Ombi.UI.Models; using TMDbLib.Objects.General; +using TraktApiSharp.Objects.Get.Shows; using Action = Ombi.Helpers.Analytics.Action; using EpisodesModel = Ombi.Store.EpisodesModel; using ISecurityExtensions = Ombi.Core.ISecurityExtensions; @@ -76,7 +77,7 @@ namespace Ombi.UI.Modules ISettingsService plexService, ISettingsService auth, IRepository u, ISettingsService email, IIssueService issue, IAnalytics a, IRepository rl, ITransientFaultQueue tfQueue, IRepository content, - ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher) + ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher, ITraktApi traktApi) : base("search", prSettings, security) { Auth = auth; @@ -109,6 +110,7 @@ namespace Ombi.UI.Modules MovieSender = movieSender; WatcherCacher = watcherCacher; RadarrCacher = radarrCacher; + TraktApi = traktApi; Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad(); @@ -120,6 +122,13 @@ namespace Ombi.UI.Modules Get["movie/upcoming", true] = async (x, ct) => await UpcomingMovies(); Get["movie/playing", true] = async (x, ct) => await CurrentlyPlayingMovies(); + Get["tv/popular", true] = async (x, ct) => await ProcessShows(ShowSearchType.Popular); + Get["tv/trending", true] = async (x, ct) => await ProcessShows(ShowSearchType.Trending); + Get["tv/mostwatched", true] = async (x, ct) => await ProcessShows(ShowSearchType.MostWatched); + Get["tv/anticipated", true] = async (x, ct) => await ProcessShows(ShowSearchType.Anticipated); + + Get["tv/poster/{id}"] = p => GetTvPoster((int)p.id); + Post["request/movie", true] = async (x, ct) => await RequestMovie((int)Request.Form.movieId); Post["request/tv", true] = async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons); @@ -129,6 +138,7 @@ namespace Ombi.UI.Modules Get["/seasons"] = x => GetSeasons(); Get["/episodes", true] = async (x, ct) => await GetEpisodes(); } + private ITraktApi TraktApi { get; } private IWatcherCacher WatcherCacher { get; } private IMovieSender MovieSender { get; } private IRepository PlexContentRepository { get; } @@ -190,6 +200,17 @@ namespace Ombi.UI.Modules return await ProcessMovies(MovieSearchType.Search, searchTerm); } + private Response GetTvPoster(int theTvDbId) + { + var result = TvApi.ShowLookupByTheTvDbId(theTvDbId); + + var banner = result.image?.medium; + if (!string.IsNullOrEmpty(banner)) + { + banner = banner.Replace("http", "https"); // Always use the Https banners + } + return banner; + } private async Task ProcessMovies(MovieSearchType searchType, string searchTerm) { List apiMovies; @@ -322,6 +343,186 @@ namespace Ombi.UI.Modules return true; } + private async Task ProcessShows(ShowSearchType type) + { + var shows = new List(); + var prSettings = await PrService.GetSettingsAsync(); + switch (type) + { + case ShowSearchType.Popular: + Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Popular", Username, CookieHelper.GetAnalyticClientId(Cookies)); + var popularShows = await TraktApi.GetPopularShows(); + + foreach (var popularShow in popularShows) + { + var theTvDbId = int.Parse(popularShow.Ids.Tvdb.ToString()); + + var model = new SearchTvShowViewModel + { + FirstAired = popularShow.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"), + Id = theTvDbId, + ImdbId = popularShow.Ids.Imdb, + Network = popularShow.Network, + Overview = popularShow.Overview.RemoveHtml(), + Rating = popularShow.Rating.ToString(), + Runtime = popularShow.Runtime.ToString(), + SeriesName = popularShow.Title, + Status = popularShow.Status.DisplayName, + DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode, + DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason, + EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason), + Trailer = popularShow.Trailer, + Homepage = popularShow.Homepage + }; + shows.Add(model); + } + shows = await MapToTvModel(shows, prSettings); + break; + case ShowSearchType.Anticipated: + Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Anticipated", Username, CookieHelper.GetAnalyticClientId(Cookies)); + var anticipated = await TraktApi.GetAnticipatedShows(); + foreach (var anticipatedShow in anticipated) + { + var show = anticipatedShow.Show; + var theTvDbId = int.Parse(show.Ids.Tvdb.ToString()); + + var model = new SearchTvShowViewModel + { + FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"), + Id = theTvDbId, + ImdbId = show.Ids.Imdb, + Network = show.Network ?? string.Empty, + Overview = show.Overview?.RemoveHtml() ?? string.Empty, + Rating = show.Rating.ToString(), + Runtime = show.Runtime.ToString(), + SeriesName = show.Title, + Status = show.Status?.DisplayName ?? string.Empty, + DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode, + DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason, + EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason), + Trailer = show.Trailer, + Homepage = show.Homepage + }; + shows.Add(model); + } + shows = await MapToTvModel(shows, prSettings); + break; + case ShowSearchType.MostWatched: + Analytics.TrackEventAsync(Category.Search, Action.TvShow, "MostWatched", Username, CookieHelper.GetAnalyticClientId(Cookies)); + var mostWatched = await TraktApi.GetMostWatchesShows(); + foreach (var watched in mostWatched) + { + var show = watched.Show; + var theTvDbId = int.Parse(show.Ids.Tvdb.ToString()); + var model = new SearchTvShowViewModel + { + FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"), + Id = theTvDbId, + ImdbId = show.Ids.Imdb, + Network = show.Network, + Overview = show.Overview.RemoveHtml(), + Rating = show.Rating.ToString(), + Runtime = show.Runtime.ToString(), + SeriesName = show.Title, + Status = show.Status.DisplayName, + DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode, + DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason, + EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason), + Trailer = show.Trailer, + Homepage = show.Homepage + }; + shows.Add(model); + } + shows = await MapToTvModel(shows, prSettings); + break; + case ShowSearchType.Trending: + Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Trending", Username, CookieHelper.GetAnalyticClientId(Cookies)); + var trending = await TraktApi.GetTrendingShows(); + foreach (var watched in trending) + { + var show = watched.Show; + var theTvDbId = int.Parse(show.Ids.Tvdb.ToString()); + var model = new SearchTvShowViewModel + { + FirstAired = show.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"), + Id = theTvDbId, + ImdbId = show.Ids.Imdb, + Network = show.Network, + Overview = show.Overview.RemoveHtml(), + Rating = show.Rating.ToString(), + Runtime = show.Runtime.ToString(), + SeriesName = show.Title, + Status = show.Status.DisplayName, + DisableTvRequestsByEpisode = prSettings.DisableTvRequestsByEpisode, + DisableTvRequestsBySeason = prSettings.DisableTvRequestsBySeason, + EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason), + Trailer = show.Trailer, + Homepage = show.Homepage + }; + shows.Add(model); + } + shows = await MapToTvModel(shows, prSettings); + break; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + + + return Response.AsJson(shows); + } + + private async Task> MapToTvModel(List shows, PlexRequestSettings prSettings) + { + + var plexSettings = await PlexService.GetSettingsAsync(); + + var providerId = string.Empty; + // Get the requests + var allResults = await RequestService.GetAllAsync(); + allResults = allResults.Where(x => x.Type == RequestType.TvShow); + var distinctResults = allResults.DistinctBy(x => x.ProviderId); + var dbTv = distinctResults.ToDictionary(x => x.ProviderId); + + // Check the external applications + var sonarrCached = SonarrCacher.QueuedIds().ToList(); + var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays + var content = PlexContentRepository.GetAll(); + var plexTvShows = Checker.GetPlexTvShows(content).ToList(); + + foreach (var show in shows) + { + if (plexSettings.AdvancedSearch) + { + providerId = show.Id.ToString(); + } + + var plexShow = Checker.GetTvShow(plexTvShows.ToArray(), show.SeriesName, show.FirstAired?.Substring(0, 4), + providerId); + if (plexShow != null) + { + show.Available = true; + show.PlexUrl = plexShow.Url; + } + else + { + if (dbTv.ContainsKey(show.Id)) + { + var dbt = dbTv[show.Id]; + + show.Requested = true; + show.Episodes = dbt.Episodes.ToList(); + show.Approved = dbt.Approved; + } + if (sonarrCached.Select(x => x.TvdbId).Contains(show.Id) || sickRageCache.Contains(show.Id)) + // compare to the sonarr/sickrage db + { + show.Requested = true; + } + } + } + return shows; + } + private async Task SearchTvShow(string searchTerm) { @@ -1401,5 +1602,13 @@ namespace Ombi.UI.Modules return false; } } + + private enum ShowSearchType + { + Popular, + Anticipated, + MostWatched, + Trending + } } } diff --git a/Ombi.UI/NinjectModules/ApiModule.cs b/Ombi.UI/NinjectModules/ApiModule.cs index 873a3c527..1a45764c7 100644 --- a/Ombi.UI/NinjectModules/ApiModule.cs +++ b/Ombi.UI/NinjectModules/ApiModule.cs @@ -49,6 +49,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); } } } \ No newline at end of file diff --git a/Ombi.UI/Ombi.UI.csproj b/Ombi.UI/Ombi.UI.csproj index ce3f1453b..22dd6175d 100644 --- a/Ombi.UI/Ombi.UI.csproj +++ b/Ombi.UI/Ombi.UI.csproj @@ -206,6 +206,10 @@ ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll True + + ..\packages\TraktApiSharp.0.8.0\lib\portable-net45+netcore45+wpa81\TraktApiSharp.dll + True + diff --git a/Ombi.UI/Views/Search/Index.cshtml b/Ombi.UI/Views/Search/Index.cshtml index 59fc41464..ec31261e1 100644 --- a/Ombi.UI/Views/Search/Index.cshtml +++ b/Ombi.UI/Views/Search/Index.cshtml @@ -75,9 +75,20 @@ } - + - - - - - - - - + {{/if_eq}} + {{/if_eq}} -