diff --git a/Ombi/Ombi.Core/IMovieEngine.cs b/Ombi/Ombi.Core/IMovieEngine.cs new file mode 100644 index 000000000..fcd397093 --- /dev/null +++ b/Ombi/Ombi.Core/IMovieEngine.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Ombi.Core.Models.Search; + +namespace Ombi.Core +{ + public interface IMovieEngine + { + Task> NowPlayingMovies(); + Task> PopularMovies(); + Task> ProcessMovieSearch(string search); + Task> TopRatedMovies(); + Task> UpcomingMovies(); + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Core/Models/Search/SearchMovieViewModel.cs b/Ombi/Ombi.Core/Models/Search/SearchMovieViewModel.cs new file mode 100644 index 000000000..66fbf9ea2 --- /dev/null +++ b/Ombi/Ombi.Core/Models/Search/SearchMovieViewModel.cs @@ -0,0 +1,54 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: SearchMovieViewModel.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using System.Collections.Generic; + +namespace Ombi.Core.Models.Search +{ + public class SearchMovieViewModel : SearchViewModel + { + public bool Adult { get; set; } + public string BackdropPath { get; set; } + public List GenreIds { get; set; } + public int Id { get; set; } + public string OriginalLanguage { get; set; } + public string OriginalTitle { get; set; } + public string Overview { get; set; } + public double Popularity { get; set; } + public string PosterPath { get; set; } + public DateTime? ReleaseDate { get; set; } + public string Title { get; set; } + public bool Video { get; set; } + public double VoteAverage { get; set; } + public int VoteCount { get; set; } + public bool AlreadyInCp { get; set; } + public string Trailer { get; set; } + public string Homepage { get; set; } + public string ImdbId { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Core/Models/Search/SearchViewModel.cs b/Ombi/Ombi.Core/Models/Search/SearchViewModel.cs new file mode 100644 index 000000000..9bbea38eb --- /dev/null +++ b/Ombi/Ombi.Core/Models/Search/SearchViewModel.cs @@ -0,0 +1,36 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: SearchViewModel.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +namespace Ombi.Core.Models.Search +{ + public class SearchViewModel + { + public bool Approved { get; set; } + public bool Requested { get; set; } + public bool Available { get; set; } + public string PlexUrl { get; set; } + } +} \ No newline at end of file diff --git a/Ombi/Ombi.Core/MovieEngine.cs b/Ombi/Ombi.Core/MovieEngine.cs new file mode 100644 index 000000000..b0e1d52ec --- /dev/null +++ b/Ombi/Ombi.Core/MovieEngine.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Ombi.Core.Models.Search; +using Ombi.TheMovieDbApi.Models; + +namespace Ombi.Core +{ + public class MovieEngine : IMovieEngine + { + + public async Task> ProcessMovieSearch(string search) + { + var api = new TheMovieDbApi.TheMovieDbApi(); + var result = await api.SearchMovie(search); + if (result != null) + { + return await TransformMovieResultsToResponse(result.results); + } + return null; + } + public async Task> PopularMovies() + { + var api = new TheMovieDbApi.TheMovieDbApi(); + var result = await api.PopularMovies(); + if (result != null) + { + return await TransformMovieResultsToResponse(result.results); + } + return null; + } + + public async Task> TopRatedMovies() + { + var api = new TheMovieDbApi.TheMovieDbApi(); + var result = await api.TopRated(); + if (result != null) + { + return await TransformMovieResultsToResponse(result.results); + } + return null; + } + + public async Task> UpcomingMovies() + { + var api = new TheMovieDbApi.TheMovieDbApi(); + var result = await api.Upcoming(); + if (result != null) + { + return await TransformMovieResultsToResponse(result.results); + } + return null; + } + public async Task> NowPlayingMovies() + { + var api = new TheMovieDbApi.TheMovieDbApi(); + var result = await api.NowPlaying(); + if (result != null) + { + return await TransformMovieResultsToResponse(result.results); + } + return null; + } + + + private async Task> TransformMovieResultsToResponse(IEnumerable movies) + { + await Task.Yield(); + var viewMovies = new List(); + var counter = 0; + //Dictionary dbMovies = await RequestedMovies(); + foreach (var movie in movies) + { + var viewMovie = new SearchMovieViewModel + { + Adult = movie.adult, + BackdropPath = movie.backdrop_path, + Id = movie.id, + OriginalLanguage = movie.original_language, + OriginalTitle = movie.original_title, + Overview = movie.overview, + Popularity = movie.popularity, + PosterPath = movie.poster_path, + ReleaseDate = string.IsNullOrEmpty(movie.release_date) ? DateTime.MinValue : DateTime.Parse(movie.release_date), + Title = movie.title, + Video = movie.video, + VoteAverage = movie.vote_average, + VoteCount = movie.vote_count + }; + viewMovies.Add(viewMovie); + + //if (counter <= 5) // Let's only do it for the first 5 items + //{ + // var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id); + + // // TODO needs to be careful about this, it's adding extra time to search... + // // https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2 + // viewMovie.ImdbId = movieInfo?.imdb_id; + // viewMovie.Homepage = movieInfo?.homepage; + // var videoId = movieInfo?.video ?? false + // ? movieInfo?.videos?.results?.FirstOrDefault()?.key + // : string.Empty; + + // viewMovie.Trailer = string.IsNullOrEmpty(videoId) + // ? string.Empty + // : $"https://www.youtube.com/watch?v={videoId}"; + + // counter++; + //} + + // var canSee = CanUserSeeThisRequest(viewMovie.Id, Security.HasPermissions(User, Permissions.UsersCanViewOnlyOwnRequests), dbMovies); + + // var plexSettings = await PlexService.GetSettingsAsync(); + // var embySettings = await EmbySettings.GetSettingsAsync(); + // if (plexSettings.Enable) + // { + // var content = PlexContentRepository.GetAll(); + // var plexMovies = PlexChecker.GetPlexMovies(content); + + // var plexMovie = PlexChecker.GetMovie(plexMovies.ToArray(), movie.Title, + // movie.ReleaseDate?.Year.ToString(), + // viewMovie.ImdbId); + // if (plexMovie != null) + // { + // viewMovie.Available = true; + // viewMovie.PlexUrl = plexMovie.Url; + // } + // } + // if (embySettings.Enable) + // { + // var embyContent = EmbyContentRepository.GetAll(); + // var embyMovies = EmbyChecker.GetEmbyMovies(embyContent); + + // var embyMovie = EmbyChecker.GetMovie(embyMovies.ToArray(), movie.Title, + // movie.ReleaseDate?.Year.ToString(), viewMovie.ImdbId); + // if (embyMovie != null) + // { + // viewMovie.Available = true; + // } + // } + // if (dbMovies.ContainsKey(movie.Id) && canSee) // compare to the requests db + // { + // var dbm = dbMovies[movie.Id]; + + // viewMovie.Requested = true; + // viewMovie.Approved = dbm.Approved; + // viewMovie.Available = dbm.Available; + // } + // else if (canSee) + // { + // bool exists = IsMovieInCache(movie, viewMovie.ImdbId); + // viewMovie.Approved = exists; + // viewMovie.Requested = exists; + // } + // viewMovies.Add(viewMovie); + //} + + + } + return viewMovies; + } + } +} diff --git a/Ombi/Ombi.Core/MovieProcessor.cs b/Ombi/Ombi.Core/MovieProcessor.cs deleted file mode 100644 index b2816009f..000000000 --- a/Ombi/Ombi.Core/MovieProcessor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Ombi.Core -{ - public class MovieProcessor - { - } -} diff --git a/Ombi/Ombi.Core/Ombi.Core.csproj b/Ombi/Ombi.Core/Ombi.Core.csproj index 954020d10..714b40cd8 100644 --- a/Ombi/Ombi.Core/Ombi.Core.csproj +++ b/Ombi/Ombi.Core/Ombi.Core.csproj @@ -1,7 +1,11 @@ - + netstandard1.4 + + + + \ No newline at end of file diff --git a/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs b/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs index eada2c583..d8e4e5709 100644 --- a/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs +++ b/Ombi/Ombi.TheMovieDbApi/TheMovieDbApi.cs @@ -13,7 +13,7 @@ namespace Ombi.TheMovieDbApi Api = new Api.Api(); } private const string ApiToken = "b8eabaf5608b88d0298aa189dd90bf00"; - private static readonly Uri BaseUri = new Uri("https://api.themoviedb.org/3/"); + private static readonly Uri BaseUri = new Uri("http://api.themoviedb.org/3/"); public Api.Api Api { get; } public async Task GetMovieInformation(int movieId) @@ -31,6 +31,34 @@ namespace Ombi.TheMovieDbApi return await Api.Get>(url); } + public async Task> PopularMovies() + { + var url = BaseUri.ChangePath("movie/popular"); + url = AddHeaders(url); + return await Api.Get>(url); + } + + public async Task> TopRated() + { + var url = BaseUri.ChangePath("movie/top_rated"); + url = AddHeaders(url); + return await Api.Get>(url); + } + + public async Task> Upcoming() + { + var url = BaseUri.ChangePath("movie/upcoming"); + url = AddHeaders(url); + return await Api.Get>(url); + } + + public async Task> NowPlaying() + { + var url = BaseUri.ChangePath("movie/now_playing"); + url = AddHeaders(url); + return await Api.Get>(url); + } + private Uri AddHeaders(Uri url) { return url.AddQueryParameter("api_key", ApiToken); diff --git a/Ombi/Ombi/Controllers/SearchController.cs b/Ombi/Ombi/Controllers/SearchController.cs index fbe718ff3..45200cbd1 100644 --- a/Ombi/Ombi/Controllers/SearchController.cs +++ b/Ombi/Ombi/Controllers/SearchController.cs @@ -3,20 +3,48 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Ombi.TheMovieDbApi.Models; +using Ombi.Core; +using Ombi.Core.Models.Search; namespace Ombi.Controllers { public class SearchController : BaseApiController { - [HttpGet("movie/{searchTerm}")] - public async Task> SearchMovie(string searchTerm) + public SearchController(IMovieEngine movie) { - var api = new TheMovieDbApi.TheMovieDbApi(); - var result = await api.SearchMovie(searchTerm); - return result.results; + MovieEngine = movie; } - + private IMovieEngine MovieEngine { get; } + + [HttpGet("movie/{searchTerm}")] + public async Task> SearchMovie(string searchTerm) + { + return await MovieEngine.ProcessMovieSearch(searchTerm); + } + + [HttpGet("movie/popular")] + public async Task> Popular() + { + return await MovieEngine.PopularMovies(); + } + [HttpGet("movie/nowplaying")] + public async Task> NowPlayingMovies() + { + return await MovieEngine.NowPlayingMovies(); + } + [HttpGet("movie/toprated")] + public async Task> TopRatedMovies() + { + return await MovieEngine.TopRatedMovies(); + } + [HttpGet("movie/upcoming")] + public async Task> UpcomingMovies() + { + return await MovieEngine.UpcomingMovies(); + } + + + } } diff --git a/Ombi/Ombi/Ombi.csproj b/Ombi/Ombi/Ombi.csproj index 112a28415..6dd5183f2 100644 --- a/Ombi/Ombi/Ombi.csproj +++ b/Ombi/Ombi/Ombi.csproj @@ -17,10 +17,12 @@ + + diff --git a/Ombi/Ombi/Startup.cs b/Ombi/Ombi/Startup.cs index 66f46f4f9..a4ed7be34 100644 --- a/Ombi/Ombi/Startup.cs +++ b/Ombi/Ombi/Startup.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; +using Ombi.Core; namespace Ombi { @@ -33,6 +34,7 @@ namespace Ombi { // Add framework services. services.AddMvc(); + services.AddTransient(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/Ombi/Ombi/app/app.component.html b/Ombi/Ombi/app/app.component.html index 4f1832e3e..d20236536 100644 --- a/Ombi/Ombi/app/app.component.html +++ b/Ombi/Ombi/app/app.component.html @@ -13,7 +13,7 @@ diff --git a/Ombi/Ombi/app/search/interfaces/IMovieResult.ts b/Ombi/Ombi/app/search/interfaces/IMovieResult.ts deleted file mode 100644 index 141515fcd..000000000 --- a/Ombi/Ombi/app/search/interfaces/IMovieResult.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface IMovieResult { - poster_path: string, - adult: boolean, - overview: string, - release_date: string, - genre_ids: number[], - id: number, - original_title: string, - original_language: string, - title: string, - backdrop_path: string, - popularity: number, - vote_count: number, - video: boolean, - vote_average:number -} \ No newline at end of file diff --git a/Ombi/Ombi/app/search/interfaces/ISearchMovieResult.ts b/Ombi/Ombi/app/search/interfaces/ISearchMovieResult.ts new file mode 100644 index 000000000..4a308438f --- /dev/null +++ b/Ombi/Ombi/app/search/interfaces/ISearchMovieResult.ts @@ -0,0 +1,20 @@ +export interface ISearchMovieResult { + backdropPath: string, + adult: boolean, + overview: string, + releaseDate: Date, + genreIds: number[], + id: number, + originalTitle: string, + originalLanguage: string, + title: string, + posterPath: string, + popularity: number, + voteCount: number, + video: boolean, + voteAverage: number, + alreadyInCp: boolean, + trailer: string, + homepage: string, + imdbId:string +} \ No newline at end of file diff --git a/Ombi/Ombi/app/search/search.component.html b/Ombi/Ombi/app/search/search.component.html index e1f2f2e93..5178a9f71 100644 --- a/Ombi/Ombi/app/search/search.component.html +++ b/Ombi/Ombi/app/search/search.component.html @@ -1,48 +1,50 @@ -

Search

+

Search

Search Paragraph


- +
- + - + --> +
+
+
+ + + poster + +
+
+
+ +

{{result.title}} ({{result.releaseDate}})

+
+ + + Air Date: {{result.firstAired}} + + + Release Date: {{result.releaseDate}} + + @UI.Search_Available + + @UI.Search_Processing_Request + +
+ + + + + + + + HomePage + + Trailer + + +
+
+
+

{{result.overview}}

+
+ + +
+ + +
+ + +
+
+
+ View In Plex + +
+
+
+ + + + + + +
+ + +
+ +
+
+
diff --git a/Ombi/Ombi/app/search/search.component.ts b/Ombi/Ombi/app/search/search.component.ts index 22a96aa0d..ccee48c79 100644 --- a/Ombi/Ombi/app/search/search.component.ts +++ b/Ombi/Ombi/app/search/search.component.ts @@ -6,7 +6,7 @@ import 'rxjs/add/operator/map'; import { SearchService } from '../services/search.service'; -import { IMovieResult } from './interfaces/IMovieResult'; +import { ISearchMovieResult } from './interfaces/ISearchMovieResult'; @Component({ selector: 'ombi', @@ -18,16 +18,20 @@ export class SearchComponent implements OnInit { searchText: string; searchChanged: Subject = new Subject(); - movieResults: IMovieResult[]; + movieResults: ISearchMovieResult[]; constructor(private searchService: SearchService) { - //this.searchChanged - // .debounceTime(300) // wait 300ms after the last event before emitting last event - // .distinctUntilChanged() // only emit if value is different from previous value - // .subscribe(x => { - // this.searchText = x as string; - // - // }); + 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); + }); } ngOnInit(): void { @@ -36,8 +40,32 @@ export class SearchComponent implements OnInit { } search(text: any) { - //this.searchChanged.next(text); - this.searchService.searchMovie(text.target.value).subscribe(x => this.movieResults = x); + this.searchChanged.next(text.target.value); + } + + request(searchResult: ISearchMovieResult) { + console.log(searchResult); + } + + popularMovies() { + this.clearResults(); + this.searchService.popularMovies().subscribe(x => this.movieResults = x); + } + nowPlayingMovies() { + this.clearResults(); + this.searchService.nowPlayingMovies().subscribe(x => this.movieResults = x); + } + topRatedMovies() { + this.clearResults(); + this.searchService.topRatedMovies().subscribe(x => this.movieResults = x); + } + upcomingMovies() { + this.clearResults(); + this.searchService.upcomignMovies().subscribe(x => this.movieResults = x); + } + + private clearResults() { + this.movieResults = []; } } \ No newline at end of file diff --git a/Ombi/Ombi/app/services/search.service.ts b/Ombi/Ombi/app/services/search.service.ts index b47f46aff..6e401abe7 100644 --- a/Ombi/Ombi/app/services/search.service.ts +++ b/Ombi/Ombi/app/services/search.service.ts @@ -3,14 +3,27 @@ import { Http } from '@angular/http'; import { Observable } from 'rxjs/Rx'; import { ServiceHelpers } from './service.helpers'; -import { IMovieResult } from '../search/interfaces/IMovieResult'; +import { ISearchMovieResult } from '../search/interfaces/ISearchMovieResult'; @Injectable() export class SearchService { constructor(private http: Http) { } - searchMovie(searchTerm: string): Observable { + searchMovie(searchTerm: string): Observable { return this.http.get('/api/Search/Movie/' + searchTerm).map(ServiceHelpers.extractData); } + + popularMovies(): Observable { + return this.http.get('/api/Search/Movie/Popular').map(ServiceHelpers.extractData); + } + upcomignMovies(): Observable { + return this.http.get('/api/Search/Movie/upcoming').map(ServiceHelpers.extractData); + } + nowPlayingMovies(): Observable { + return this.http.get('/api/Search/Movie/nowplaying').map(ServiceHelpers.extractData); + } + topRatedMovies(): Observable { + return this.http.get('/api/Search/Movie/toprated').map(ServiceHelpers.extractData); + } } \ No newline at end of file