diff --git a/src/Ombi.Core/Engine/Interfaces/IMovieEngineV2.cs b/src/Ombi.Core/Engine/Interfaces/IMovieEngineV2.cs index 746045ef3..c4bd0aa0e 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMovieEngineV2.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMovieEngineV2.cs @@ -27,5 +27,6 @@ namespace Ombi.Core.Engine.Interfaces Task GetMovieInfoByImdbId(string imdbId, CancellationToken requestAborted); Task> GetStreamInformation(int movieDbId, CancellationToken cancellationToken); + Task> RecentlyRequestedMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/V2/MovieSearchEngineV2.cs b/src/Ombi.Core/Engine/V2/MovieSearchEngineV2.cs index cb8ec0d3b..3714e58a8 100644 --- a/src/Ombi.Core/Engine/V2/MovieSearchEngineV2.cs +++ b/src/Ombi.Core/Engine/V2/MovieSearchEngineV2.cs @@ -8,11 +8,13 @@ using Ombi.Core.Engine.Interfaces; using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; using Ombi.Core.Models.Search.V2; +using Ombi.Core.Models.UI; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; using Ombi.Store.Repository; using System; using System.Collections.Generic; @@ -27,20 +29,21 @@ namespace Ombi.Core.Engine.V2 { public MovieSearchEngineV2(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, ILogger logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService s, IRepository sub, - ISettingsService customizationSettings) + ISettingsService customizationSettings, IMovieRequestEngine movieRequestEngine) : base(identity, service, r, um, mem, s, sub) { MovieApi = movApi; Mapper = mapper; Logger = logger; _customizationSettings = customizationSettings; + _movieRequestEngine = movieRequestEngine; } private IMovieDbApi MovieApi { get; } private IMapper Mapper { get; } private ILogger Logger { get; } private readonly ISettingsService _customizationSettings; - + private readonly IMovieRequestEngine _movieRequestEngine; public async Task GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null) { @@ -187,6 +190,41 @@ namespace Ombi.Core.Engine.V2 return await TransformMovieResultsToResponse(results); } + /// + /// Gets recently requested movies + /// + /// + public async Task> RecentlyRequestedMovies(int currentlyLoaded, int toLoad, CancellationToken cancellationToken) + { + var langCode = await DefaultLanguageCode(null); + + var results = new List(); + + var requestResult = await Cache.GetOrAdd(nameof(RecentlyRequestedMovies) + "Requests" + toLoad + langCode, + async () => + { + return await _movieRequestEngine.GetRequests(toLoad, currentlyLoaded, new Models.UI.OrderFilterModel + { + OrderType = OrderType.RequestedDateDesc + }); + }, DateTime.Now.AddMinutes(15), cancellationToken); + + var movieDBResults = await Cache.GetOrAdd(nameof(RecentlyRequestedMovies) + toLoad + langCode, + async () => + { + var responses = new List(); + foreach(var movie in requestResult.Collection) + { + responses.Add(await MovieApi.GetMovieInformation(movie.TheMovieDbId)); + } + return responses; + }, DateTime.Now.AddHours(12), cancellationToken); + + results.AddRange(movieDBResults); + + return await TransformMovieResultsToResponse(results); + } + /// /// Gets upcoming movies. @@ -269,8 +307,8 @@ namespace Ombi.Core.Engine.V2 return data; } - protected async Task> TransformMovieResultsToResponse( - IEnumerable movies) + protected async Task> TransformMovieResultsToResponse( + IEnumerable movies) where T: new() { var settings = await _customizationSettings.GetSettingsAsync(); var viewMovies = new List(); @@ -286,7 +324,7 @@ namespace Ombi.Core.Engine.V2 return viewMovies; } - private async Task ProcessSingleMovie(MovieDbSearchResult movie) + private async Task ProcessSingleMovie(T movie) where T : new() { var viewMovie = Mapper.Map(movie); return await ProcessSingleMovie(viewMovie); diff --git a/src/Ombi.Mapping/Profiles/MovieProfile.cs b/src/Ombi.Mapping/Profiles/MovieProfile.cs index 00d50fdc5..161cb1fda 100644 --- a/src/Ombi.Mapping/Profiles/MovieProfile.cs +++ b/src/Ombi.Mapping/Profiles/MovieProfile.cs @@ -4,6 +4,7 @@ using AutoMapper; using Ombi.Api.TheMovieDb.Models; using Ombi.Core.Models.Search; using Ombi.Core.Models.Search.V2; +using Ombi.Store.Entities.Requests; using Ombi.TheMovieDbApi.Models; using Keywords = Ombi.Core.Models.Search.V2.Keywords; using KeywordsValue = Ombi.Api.TheMovieDb.Models.KeywordsValue; @@ -76,6 +77,7 @@ namespace Ombi.Mapping.Profiles CreateMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap().ReverseMap(); diff --git a/src/Ombi/ClientApp/src/app/discover/components/carousel-list/carousel-list.component.ts b/src/Ombi/ClientApp/src/app/discover/components/carousel-list/carousel-list.component.ts index 6f35518fe..1c39f000d 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/carousel-list/carousel-list.component.ts +++ b/src/Ombi/ClientApp/src/app/discover/components/carousel-list/carousel-list.component.ts @@ -10,6 +10,7 @@ export enum DiscoverType { Upcoming, Trending, Popular, + RecentlyRequested, } @Component({ @@ -216,6 +217,8 @@ export class CarouselListComponent implements OnInit { case DiscoverType.Upcoming: this.movies = await this.searchService.upcomingMoviesByPage(this.currentlyLoaded, this.amountToLoad); break + case DiscoverType.RecentlyRequested: + this.movies = await this.searchService.recentlyRequestedMoviesByPage(this.currentlyLoaded, this.amountToLoad); } this.currentlyLoaded += this.amountToLoad; } diff --git a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html index 77083a436..fd114128e 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html +++ b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.html @@ -1,8 +1,6 @@
-
-
-

Popular

+

{{'Discovery.PopularTab' | translate}}

@@ -10,7 +8,7 @@
-

Trending

+

{{'Discovery.TrendingTab' | translate}}

@@ -18,10 +16,15 @@
-

Upcoming

+

{{'Discovery.UpcomingTab' | translate}}

-
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.ts b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.ts index 7b4fc291b..f9af8c573 100644 --- a/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.ts +++ b/src/Ombi/ClientApp/src/app/discover/components/discover/discover.component.ts @@ -1,344 +1,15 @@ -import { Component, OnInit, Inject } from "@angular/core"; -import { SearchV2Service } from "../../../services"; -import { ISearchMovieResult, ISearchTvResult, RequestType } from "../../../interfaces"; -import { IDiscoverCardResult, DiscoverOption, DisplayOption } from "../../interfaces"; -import { trigger, transition, style, animate } from "@angular/animations"; -import { StorageService } from "../../../shared/storage/storage-service"; -import { DOCUMENT } from "@angular/common"; -import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2"; +import { Component } from "@angular/core"; import { DiscoverType } from "../carousel-list/carousel-list.component"; @Component({ templateUrl: "./discover.component.html", styleUrls: ["./discover.component.scss"], - animations: [ - trigger('slideIn', [ - transition(':enter', [ - style({ transform: 'translateX(100%)' }), - animate('200ms ease-in', style({ transform: 'translateY(0%)' })) - ]) - ]) - ], }) -export class DiscoverComponent implements OnInit { +export class DiscoverComponent { - public upcomingMovies: IDiscoverCardResult[] = []; - public trendingMovies: IDiscoverCardResult[] = []; - - public discoverResults: IDiscoverCardResult[] = []; - public movies: ISearchMovieResult[] = []; - public tvShows: ISearchTvResult[] = []; - - public discoverOptions: DiscoverOption = DiscoverOption.Combined; public DiscoverType = DiscoverType; - public DiscoverOption = DiscoverOption; - public displayOption: DisplayOption = DisplayOption.Card; - public DisplayOption = DisplayOption; - - public defaultTvPoster: string; - - public popularActive: boolean = true; - public trendingActive: boolean; - public upcomingActive: boolean; - - public loadingFlag: boolean; - public scrollDisabled: boolean; - - private amountToLoad = 14; - - private contentLoaded: number; - private isScrolling: boolean = false; - private mediaTypeStorageKey = "DiscoverOptions"; - private displayOptionsKey = "DiscoverDisplayOptions"; - - - - constructor(private searchService: SearchV2Service, - private storageService: StorageService, - @Inject(DOCUMENT) private container: Document) { } - - - public async ngOnInit() { - this.loading() - // this.upcomingMovies = this.mapTvModel(await this.searchService.popularTvByPage(0, 14)); - // this.trendingMovies = this.mapMovieModel(await this.searchService.popularMoviesByPage(0, 14)); -this.finishLoading(); - // const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey); - // if (localDiscoverOptions) { - // this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]]; - // } - // const localDisplayOptions = +this.storageService.get(this.displayOptionsKey); - // if (localDisplayOptions) { - // this.displayOption = DisplayOption[DisplayOption[localDisplayOptions]]; - // } - // this.scrollDisabled = true; - // switch (this.discoverOptions) { - // case DiscoverOption.Combined: - // this.movies = await this.searchService.popularMoviesByPage(0, this.amountToLoad); - // this.tvShows = await this.searchService.popularTvByPage(0, this.amountToLoad); - // break; - // case DiscoverOption.Movie: - // this.movies = await this.searchService.popularMoviesByPage(0, this.amountToLoad); - // break; - // case DiscoverOption.Tv: - // this.tvShows = await this.searchService.popularTvByPage(0, this.amountToLoad); - // break; - // } - - // this.contentLoaded = this.amountToLoad; - - // this.createInitialModel(); - // this.scrollDisabled = false; - // if (!this.containerHasScrollBar()) { - // await this.onScroll(); - // } - } - - public async onScroll() { - console.log("scrolled"); - if (!this.contentLoaded) { - return; - } - if (!this.isScrolling) { - this.isScrolling = true; - this.loading(); - if (this.popularActive) { - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.popularMoviesByPage(this.contentLoaded, this.amountToLoad); - this.tvShows = await this.searchService.popularTvByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.popularMoviesByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.popularTvByPage(this.contentLoaded, this.amountToLoad); - break; - } - } - if (this.trendingActive) { - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.nowPlayingMoviesByPage(this.contentLoaded, this.amountToLoad); - this.tvShows = await this.searchService.trendingTvByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.nowPlayingMoviesByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.trendingTvByPage(this.contentLoaded, this.amountToLoad); - break; - } - } - if (this.upcomingActive) { - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.upcomingMoviesByPage(this.contentLoaded, this.amountToLoad); - this.tvShows = await this.searchService.anticipatedTvByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.upcomingMoviesByPage(this.contentLoaded, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.anticipatedTvByPage(this.contentLoaded, this.amountToLoad); - break; - } - } - this.contentLoaded += 12; - - this.createModel(); - this.isScrolling = false; - } - } - - public async popular() { - this.clear(); - this.scrollDisabled = true; - this.isScrolling = false; - this.contentLoaded = 12; - this.loading() - this.popularActive = true; - this.trendingActive = false; - this.upcomingActive = false; - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.popularMoviesByPage(0, this.amountToLoad); - this.tvShows = await this.searchService.popularTvByPage(0, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.popularMoviesByPage(0, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.popularTvByPage(0, this.amountToLoad); - break; - } - - this.createModel(); - this.scrollDisabled = false; - } - - public async trending() { - this.clear(); - - this.scrollDisabled = true; - this.isScrolling = false; - this.contentLoaded = 12; - this.loading() - this.popularActive = false; - this.trendingActive = true; - this.upcomingActive = false; - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.nowPlayingMoviesByPage(0, this.amountToLoad); - this.tvShows = await this.searchService.trendingTvByPage(0, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.nowPlayingMoviesByPage(0, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.trendingTvByPage(0, this.amountToLoad); - break; - } - - this.createModel(); - this.scrollDisabled = false; - } - - public async upcoming() { - this.clear(); - this.scrollDisabled = true; - this.isScrolling = false; - this.contentLoaded = 12; - this.loading() - this.popularActive = false; - this.trendingActive = false; - this.upcomingActive = true; - switch (this.discoverOptions) { - case DiscoverOption.Combined: - this.movies = await this.searchService.upcomingMoviesByPage(0, this.amountToLoad); - this.tvShows = await this.searchService.anticipatedTvByPage(0, this.amountToLoad); - break; - case DiscoverOption.Movie: - this.movies = await this.searchService.upcomingMoviesByPage(0, this.amountToLoad); - break; - case DiscoverOption.Tv: - this.tvShows = await this.searchService.anticipatedTvByPage(0, this.amountToLoad); - break; - } - - this.createModel(); - this.scrollDisabled = false; - } - - public async switchDiscoverMode(newMode: DiscoverOption) { - this.loading(); - this.clear(); - this.discoverOptions = newMode; - this.storageService.save(this.mediaTypeStorageKey, newMode.toString()); - await this.ngOnInit(); - this.finishLoading(); - } - - public changeView(view: DisplayOption) { - this.displayOption = view; - this.storageService.save(this.displayOptionsKey, view.toString()); - } - - private createModel() { - const tempResults = []; - - // switch (this.discoverOptions) { - // case DiscoverOption.Combined: - // tempResults.push(...this.mapMovieModel()); - // tempResults.push(...this.mapTvModel()); - // break; - // case DiscoverOption.Movie: - // tempResults.push(...this.mapMovieModel()); - // break; - // case DiscoverOption.Tv: - // tempResults.push(...this.mapTvModel()); - // break; - // } - - this.shuffle(tempResults); - this.discoverResults.push(...tempResults); - - this.finishLoading(); - } - - private mapMovieModel(movies: ISearchMovieResult[]): IDiscoverCardResult[] { - const tempResults = []; - movies.forEach(m => { - tempResults.push({ - available: m.available, - posterPath: m.posterPath ? `https://image.tmdb.org/t/p/w500/${m.posterPath}` : "../../../images/default_movie_poster.png", - requested: m.requested, - title: m.title, - type: RequestType.movie, - id: m.id, - url: `http://www.imdb.com/title/${m.imdbId}/`, - rating: m.voteAverage, - overview: m.overview, - approved: m.approved, - imdbid: m.imdbId, - denied: false, - background: m.backdropPath - }); - }); - return tempResults; - } - - private mapTvModel(tv: ISearchTvResult[]): IDiscoverCardResult[] { - const tempResults = []; - tv.forEach(m => { - tempResults.push({ - available: m.available, - posterPath: "../../../images/default_tv_poster.png", - requested: m.requested, - title: m.title, - type: RequestType.tvShow, - id: m.id, - url: undefined, - rating: +m.rating, - overview: m.overview, - approved: m.approved || m.partlyAvailable, - imdbid: m.imdbId, - denied: false, - background: m.background - }); - }); - return tempResults; - } - - private createInitialModel() { - this.clear(); - this.createModel(); - } - - private shuffle(discover: IDiscoverCardResult[]): IDiscoverCardResult[] { - for (let i = discover.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [discover[i], discover[j]] = [discover[j], discover[i]]; - } - return discover; - } - - private loading() { - this.loadingFlag = true; - } - - private clear() { - this.discoverResults = []; - } - private finishLoading() { - this.loadingFlag = false; - } + constructor() { } - private containerHasScrollBar(): boolean { - return this.container.documentElement.scrollHeight > this.container.documentElement.clientHeight; - // div.scrollHeight > div.clientHeight; - // this.container.documentElement.scrollHeight > (window.innerHeight + window.pageYOffset); - } } diff --git a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts index f02b4aa30..f7c287fd2 100644 --- a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts +++ b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts @@ -59,6 +59,10 @@ export class SearchV2Service extends ServiceHelpers { return this.http.get(`${this.url}/Movie/upcoming/${currentlyLoaded}/${toLoad}`).toPromise(); } + public recentlyRequestedMoviesByPage(currentlyLoaded: number, toLoad: number): Promise { + return this.http.get(`${this.url}/Movie/requested/${currentlyLoaded}/${toLoad}`).toPromise(); + } + public nowPlayingMovies(): Observable { return this.http.get(`${this.url}/Movie/nowplaying`); } diff --git a/src/Ombi/Controllers/V1/RequestController.cs b/src/Ombi/Controllers/V1/RequestController.cs index 537959eb5..206391b07 100644 --- a/src/Ombi/Controllers/V1/RequestController.cs +++ b/src/Ombi/Controllers/V1/RequestController.cs @@ -286,6 +286,7 @@ namespace Ombi.Controllers.V1 /// The tv. /// [HttpPost("tv")] + [Obsolete("This method is obsolete, please use v2 API")] public async Task RequestTv([FromBody] TvRequestViewModel tv) { tv.RequestedByAlias = GetApiAlias(); diff --git a/src/Ombi/Controllers/V2/SearchController.cs b/src/Ombi/Controllers/V2/SearchController.cs index 8e6202700..16847630b 100644 --- a/src/Ombi/Controllers/V2/SearchController.cs +++ b/src/Ombi/Controllers/V2/SearchController.cs @@ -167,6 +167,19 @@ namespace Ombi.Controllers.V2 return await _movieEngineV2.PopularMovies(currentPosition, amountToLoad, Request.HttpContext.RequestAborted); } + /// + /// Returns Recently Requested Movies using Paging + /// + /// We use TheMovieDb as the Movie Provider + /// + [HttpGet("movie/requested/{currentPosition}/{amountToLoad}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesDefaultResponseType] + public async Task> RecentlyRequestedMovies(int currentPosition, int amountToLoad) + { + return await _movieEngineV2.RecentlyRequestedMovies(currentPosition, amountToLoad, Request.HttpContext.RequestAborted); + } + /// /// Returns Now Playing Movies /// diff --git a/src/Ombi/Startup.cs b/src/Ombi/Startup.cs index 5f71fec11..bb10c22a2 100644 --- a/src/Ombi/Startup.cs +++ b/src/Ombi/Startup.cs @@ -181,11 +181,11 @@ namespace Ombi { if (settings.BaseUrl.HasValue()) { - c.SwaggerEndpoint($"{settings.BaseUrl}/swagger/v1/swagger.json", "My API V1"); + c.SwaggerEndpoint($"{settings.BaseUrl}/swagger/v1/swagger.json", "Ombi API"); } else { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ombi API"); } }); diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index 3e8ff96c8..d5c66828f 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -287,6 +287,7 @@ "PopularTab": "Popular", "TrendingTab": "Trending", "UpcomingTab": "Upcoming", + "RecentlyRequestedTab": "Recently Requested", "Movies": "Movies", "Combined": "Combined", "Tv": "TV",