Added the ability to specify a year when searching for movies

pull/2728/head
tidusjar 6 years ago
parent 8154334dae
commit 53cdcdc23b

@ -10,7 +10,7 @@ namespace Ombi.Core
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
Task<IEnumerable<SearchMovieViewModel>> Search(string search);
Task<IEnumerable<SearchMovieViewModel>> Search(string search, int? year);
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();

@ -36,6 +36,8 @@ namespace Ombi.Core.Engine
private IMapper Mapper { get; }
private ILogger<MovieSearchEngine> Logger { get; }
private const int MovieLimit = 10;
/// <summary>
/// Lookups the imdb information.
/// </summary>
@ -54,13 +56,13 @@ namespace Ombi.Core.Engine
/// </summary>
/// <param name="search">The search.</param>
/// <returns></returns>
public async Task<IEnumerable<SearchMovieViewModel>> Search(string search)
public async Task<IEnumerable<SearchMovieViewModel>> Search(string search, int? year)
{
var result = await MovieApi.SearchMovie(search);
var result = await MovieApi.SearchMovie(search, year);
if (result != null)
{
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}
@ -76,7 +78,7 @@ namespace Ombi.Core.Engine
if (result != null)
{
Logger.LogDebug("Search Result: {result}", result);
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}
@ -90,7 +92,7 @@ namespace Ombi.Core.Engine
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12));
if (result != null)
{
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}
@ -104,7 +106,7 @@ namespace Ombi.Core.Engine
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12));
if (result != null)
{
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}
@ -119,7 +121,7 @@ namespace Ombi.Core.Engine
if (result != null)
{
Logger.LogDebug("Search Result: {result}", result);
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}
@ -133,7 +135,7 @@ namespace Ombi.Core.Engine
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12));
if (result != null)
{
return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API
return await TransformMovieResultsToResponse(result.Take(MovieLimit)); // Take x to stop us overloading the API
}
return null;
}

@ -11,7 +11,7 @@ namespace Ombi.Api.TheMovieDb
Task<MovieResponseDto> GetMovieInformationWithExtraInfo(int movieId);
Task<List<MovieSearchResult>> NowPlaying();
Task<List<MovieSearchResult>> PopularMovies();
Task<List<MovieSearchResult>> SearchMovie(string searchTerm);
Task<List<MovieSearchResult>> SearchMovie(string searchTerm, int? year);
Task<List<TvSearchResult>> SearchTv(string searchTerm);
Task<List<MovieSearchResult>> TopRated();
Task<List<MovieSearchResult>> Upcoming();

@ -83,11 +83,15 @@ namespace Ombi.Api.TheMovieDb
return Mapper.Map<MovieResponseDto>(result);
}
public async Task<List<MovieSearchResult>> SearchMovie(string searchTerm)
public async Task<List<MovieSearchResult>> SearchMovie(string searchTerm, int? year)
{
var request = new Request($"search/movie", BaseUri, HttpMethod.Get);
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
request.FullUri = request.FullUri.AddQueryParameter("query", searchTerm);
if(year.HasValue && year.Value > 0)
{
request.FullUri = request.FullUri.AddQueryParameter("year", year.Value.ToString());
}
AddRetry(request);
var result = await Api.Request<TheMovieDbContainer<SearchResult>>(request);

@ -39,7 +39,7 @@ export class MusicRequestsComponent implements OnInit {
public rejectionReason: string;
public totalAlbums: number = 100;
private currentlyLoaded: number;
public currentlyLoaded: number;
private amountToLoad: number;
constructor(

@ -5,7 +5,7 @@
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons"
(keyup)="search($event)">
<div class="input-group-addon right-radius">
<div class="btn-group">
<div class="btn-group" role="group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
{{ 'Search.Suggestions' | translate }}
<i class="fa fa-chevron-down"></i>
@ -16,10 +16,25 @@
<li><a (click)="topRatedMovies()" [translate]="'Search.Movies.TopRatedMovies'"></a></li>
<li><a (click)="nowPlayingMovies()" [translate]="'Search.Movies.NowPlayingMovies'"></a></li>
</ul>
<button class="btn btn-sm btn-primary-outline" (click)="refineOpen()">
{{ 'Search.Refine' | translate }}
<i class="fa" [ngClass]="{'fa-chevron-down': !refineSearchEnabled, 'fa-chevron-up': refineSearchEnabled}"></i>
</button>
</div>
<i class="fa fa-search"></i>
</div>
</div>
<!-- Refine search options -->
<div class="row top-spacing" *ngIf="refineSearchEnabled">
<div class="col-md-2">
<input [(ngModel)]="searchYear" class="form-control form-control-custom" placeholder="Year">
</div>
<div class="col-md-10">
<button class="btn pull-right btn-success-outline" (click)="applyRefinedSearch()">Apply</button>
</div>
</div>
<remaining-requests [movie]="true" [quotaRefreshEvents]="movieRequested.asObservable()" #remainingFilms></remaining-requests>
@ -111,11 +126,15 @@
<br />
<div *ngIf="result.available">
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnPlex' | translate}}</a>
<a *ngIf="result.embyUrl" style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline" href="{{result.embyUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnEmby' | translate}}</a>
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnPlex' | translate}}</a>
<a *ngIf="result.embyUrl" style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline"
href="{{result.embyUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnEmby' |
translate}}</a>
</div>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{'Requests.ReportIssue' | translate}}
<span class="caret"></span>
</button>

@ -12,6 +12,7 @@ import { NotificationService, RequestService, SearchService } from "../services"
@Component({
selector: "movie-search",
templateUrl: "./moviesearch.component.html",
styleUrls: ["./search.component.scss"],
})
export class MovieSearchComponent implements OnInit {
@ -22,6 +23,8 @@ export class MovieSearchComponent implements OnInit {
public result: IRequestEngineResult;
public searchApplied = false;
public refineSearchEnabled = false;
public searchYear?: number;
@Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean;
@ -46,14 +49,7 @@ export class MovieSearchComponent implements OnInit {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results.
this.getExtraInfo();
});
this.runSearch();
});
this.defaultPoster = "../../../images/default_movie_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
@ -184,6 +180,17 @@ export class MovieSearchComponent implements OnInit {
});
}
public refineOpen() {
this.refineSearchEnabled = !this.refineSearchEnabled;
if(!this.refineSearchEnabled) {
this.searchYear = undefined;
}
}
public applyRefinedSearch() {
this.runSearch();
}
private getExtraInfo() {
this.movieResults.forEach((val, index) => {
@ -214,4 +221,15 @@ export class MovieSearchComponent implements OnInit {
this.movieResults = [];
this.searchApplied = false;
}
private runSearch() {
this.searchService.searchMovie(this.searchText, this.searchYear)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results.
this.getExtraInfo();
});
}
}

@ -0,0 +1,10 @@
@media (max-width: 978px) {
.top-spacing {
padding-top: 5%
}
}
@media (min-width: 979px) {
.top-spacing {
padding-top: 2%
}
}

@ -17,8 +17,12 @@ export class SearchService extends ServiceHelpers {
}
// Movies
public searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/` + searchTerm);
public searchMovie(searchTerm: string, year?: number): Observable<ISearchMovieResult[]> {
if(year && year > 0) {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/${searchTerm}/${year}`);
} else {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/${searchTerm}`);
}
}
public similarMovies(theMovieDbId: number): Observable<ISearchMovieResult[]> {
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/${theMovieDbId}/similar`);

@ -46,7 +46,25 @@ namespace Ombi.Controllers
{
Logger.LogDebug("Searching : {searchTerm}", searchTerm);
return await MovieEngine.Search(searchTerm);
return await MovieEngine.Search(searchTerm, null);
}
}
/// <summary>
/// Searches for a movie.
/// </summary>
/// <remarks>We use TheMovieDb as the Movie Provider</remarks>
/// <param name="searchTerm">The search term.</param>
/// <param name="year">optional year parameter</param>
/// <returns></returns>
[HttpGet("movie/{searchTerm}/{year}")]
public async Task<IEnumerable<SearchMovieViewModel>> SearchMovie(string searchTerm, int? year)
{
using (MiniProfiler.Current.Step("SearchingMovie"))
{
Logger.LogDebug("Searching : {searchTerm}, Year: {year}", searchTerm, year);
return await MovieEngine.Search(searchTerm, year);
}
}

@ -8,7 +8,7 @@
<FileVersion>$(SemVer)</FileVersion>
<Version>$(FullVer)</Version>
<PackageVersion></PackageVersion>
<TypeScriptToolsVersion>3.0</TypeScriptToolsVersion>
<TypeScriptToolsVersion>3.1</TypeScriptToolsVersion>
</PropertyGroup>
<PropertyGroup>
<ServerGarbageCollection>false</ServerGarbageCollection>

@ -60,6 +60,7 @@
"jquery": "^3.3.1",
"mini-css-extract-plugin": "^0.4.1",
"moment": "^2.22.2",
"natives": "1.1.6",
"ng2-cookies": "^1.0.12",
"ngx-clipboard": "^11.1.1",
"ngx-infinite-scroll": "^6.0.1",

@ -78,6 +78,7 @@
"ViewOnEmby": "View On Emby",
"RequestAdded": "Request for {{title}} has been added successfully",
"Similar":"Similar",
"Refine":"Refine",
"Movies": {
"PopularMovies": "Popular Movies",
"UpcomingMovies": "Upcoming Movies",

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save