mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-13 16:52:56 -07:00
Added the ability to specify a year when searching for movies
This commit is contained in:
parent
8154334dae
commit
53cdcdc23b
14 changed files with 2108 additions and 1019 deletions
|
@ -10,7 +10,7 @@ namespace Ombi.Core
|
||||||
|
|
||||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||||
|
|
||||||
Task<IEnumerable<SearchMovieViewModel>> Search(string search);
|
Task<IEnumerable<SearchMovieViewModel>> Search(string search, int? year);
|
||||||
|
|
||||||
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
Task<IEnumerable<SearchMovieViewModel>> TopRatedMovies();
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace Ombi.Core.Engine
|
||||||
private IMapper Mapper { get; }
|
private IMapper Mapper { get; }
|
||||||
private ILogger<MovieSearchEngine> Logger { get; }
|
private ILogger<MovieSearchEngine> Logger { get; }
|
||||||
|
|
||||||
|
private const int MovieLimit = 10;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lookups the imdb information.
|
/// Lookups the imdb information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -54,13 +56,13 @@ namespace Ombi.Core.Engine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="search">The search.</param>
|
/// <param name="search">The search.</param>
|
||||||
/// <returns></returns>
|
/// <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)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ namespace Ombi.Core.Engine
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
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;
|
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));
|
var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
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;
|
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));
|
var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +121,7 @@ namespace Ombi.Core.Engine
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Search Result: {result}", result);
|
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;
|
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));
|
var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12));
|
||||||
if (result != null)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ombi.Api.TheMovieDb
|
||||||
Task<MovieResponseDto> GetMovieInformationWithExtraInfo(int movieId);
|
Task<MovieResponseDto> GetMovieInformationWithExtraInfo(int movieId);
|
||||||
Task<List<MovieSearchResult>> NowPlaying();
|
Task<List<MovieSearchResult>> NowPlaying();
|
||||||
Task<List<MovieSearchResult>> PopularMovies();
|
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<TvSearchResult>> SearchTv(string searchTerm);
|
||||||
Task<List<MovieSearchResult>> TopRated();
|
Task<List<MovieSearchResult>> TopRated();
|
||||||
Task<List<MovieSearchResult>> Upcoming();
|
Task<List<MovieSearchResult>> Upcoming();
|
||||||
|
|
|
@ -83,11 +83,15 @@ namespace Ombi.Api.TheMovieDb
|
||||||
return Mapper.Map<MovieResponseDto>(result);
|
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);
|
var request = new Request($"search/movie", BaseUri, HttpMethod.Get);
|
||||||
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
|
request.FullUri = request.FullUri.AddQueryParameter("api_key", ApiToken);
|
||||||
request.FullUri = request.FullUri.AddQueryParameter("query", searchTerm);
|
request.FullUri = request.FullUri.AddQueryParameter("query", searchTerm);
|
||||||
|
if(year.HasValue && year.Value > 0)
|
||||||
|
{
|
||||||
|
request.FullUri = request.FullUri.AddQueryParameter("year", year.Value.ToString());
|
||||||
|
}
|
||||||
AddRetry(request);
|
AddRetry(request);
|
||||||
|
|
||||||
var result = await Api.Request<TheMovieDbContainer<SearchResult>>(request);
|
var result = await Api.Request<TheMovieDbContainer<SearchResult>>(request);
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class MusicRequestsComponent implements OnInit {
|
||||||
public rejectionReason: string;
|
public rejectionReason: string;
|
||||||
|
|
||||||
public totalAlbums: number = 100;
|
public totalAlbums: number = 100;
|
||||||
private currentlyLoaded: number;
|
public currentlyLoaded: number;
|
||||||
private amountToLoad: number;
|
private amountToLoad: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons"
|
<input id="search" type="text" class="form-control form-control-custom form-control-search form-control-withbuttons"
|
||||||
(keyup)="search($event)">
|
(keyup)="search($event)">
|
||||||
<div class="input-group-addon right-radius">
|
<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">
|
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||||
{{ 'Search.Suggestions' | translate }}
|
{{ 'Search.Suggestions' | translate }}
|
||||||
<i class="fa fa-chevron-down"></i>
|
<i class="fa fa-chevron-down"></i>
|
||||||
|
@ -16,10 +16,25 @@
|
||||||
<li><a (click)="topRatedMovies()" [translate]="'Search.Movies.TopRatedMovies'"></a></li>
|
<li><a (click)="topRatedMovies()" [translate]="'Search.Movies.TopRatedMovies'"></a></li>
|
||||||
<li><a (click)="nowPlayingMovies()" [translate]="'Search.Movies.NowPlayingMovies'"></a></li>
|
<li><a (click)="nowPlayingMovies()" [translate]="'Search.Movies.NowPlayingMovies'"></a></li>
|
||||||
</ul>
|
</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>
|
</div>
|
||||||
|
|
||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<remaining-requests [movie]="true" [quotaRefreshEvents]="movieRequested.asObservable()" #remainingFilms></remaining-requests>
|
||||||
|
|
||||||
|
@ -111,11 +126,15 @@
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<div *ngIf="result.available">
|
<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.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}"
|
||||||
<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>
|
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>
|
||||||
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
|
<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}}
|
<i class="fa fa-plus"></i> {{'Requests.ReportIssue' | translate}}
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { NotificationService, RequestService, SearchService } from "../services"
|
||||||
@Component({
|
@Component({
|
||||||
selector: "movie-search",
|
selector: "movie-search",
|
||||||
templateUrl: "./moviesearch.component.html",
|
templateUrl: "./moviesearch.component.html",
|
||||||
|
styleUrls: ["./search.component.scss"],
|
||||||
})
|
})
|
||||||
export class MovieSearchComponent implements OnInit {
|
export class MovieSearchComponent implements OnInit {
|
||||||
|
|
||||||
|
@ -22,6 +23,8 @@ export class MovieSearchComponent implements OnInit {
|
||||||
public result: IRequestEngineResult;
|
public result: IRequestEngineResult;
|
||||||
|
|
||||||
public searchApplied = false;
|
public searchApplied = false;
|
||||||
|
public refineSearchEnabled = false;
|
||||||
|
public searchYear?: number;
|
||||||
|
|
||||||
@Input() public issueCategories: IIssueCategory[];
|
@Input() public issueCategories: IIssueCategory[];
|
||||||
@Input() public issuesEnabled: boolean;
|
@Input() public issuesEnabled: boolean;
|
||||||
|
@ -46,14 +49,7 @@ export class MovieSearchComponent implements OnInit {
|
||||||
this.clearResults();
|
this.clearResults();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.searchService.searchMovie(this.searchText)
|
this.runSearch();
|
||||||
.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.defaultPoster = "../../../images/default_movie_poster.png";
|
this.defaultPoster = "../../../images/default_movie_poster.png";
|
||||||
const base = this.platformLocation.getBaseHrefFromDOM();
|
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() {
|
private getExtraInfo() {
|
||||||
|
|
||||||
this.movieResults.forEach((val, index) => {
|
this.movieResults.forEach((val, index) => {
|
||||||
|
@ -214,4 +221,15 @@ export class MovieSearchComponent implements OnInit {
|
||||||
this.movieResults = [];
|
this.movieResults = [];
|
||||||
this.searchApplied = false;
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/Ombi/ClientApp/app/search/search.component.scss
Normal file
10
src/Ombi/ClientApp/app/search/search.component.scss
Normal file
|
@ -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
|
// Movies
|
||||||
public searchMovie(searchTerm: string): Observable<ISearchMovieResult[]> {
|
public searchMovie(searchTerm: string, year?: number): Observable<ISearchMovieResult[]> {
|
||||||
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/` + searchTerm);
|
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[]> {
|
public similarMovies(theMovieDbId: number): Observable<ISearchMovieResult[]> {
|
||||||
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/${theMovieDbId}/similar`);
|
return this.http.get<ISearchMovieResult[]>(`${this.url}/Movie/${theMovieDbId}/similar`);
|
||||||
|
|
|
@ -46,7 +46,25 @@ namespace Ombi.Controllers
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Searching : {searchTerm}", searchTerm);
|
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>
|
<FileVersion>$(SemVer)</FileVersion>
|
||||||
<Version>$(FullVer)</Version>
|
<Version>$(FullVer)</Version>
|
||||||
<PackageVersion></PackageVersion>
|
<PackageVersion></PackageVersion>
|
||||||
<TypeScriptToolsVersion>3.0</TypeScriptToolsVersion>
|
<TypeScriptToolsVersion>3.1</TypeScriptToolsVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
"mini-css-extract-plugin": "^0.4.1",
|
"mini-css-extract-plugin": "^0.4.1",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.22.2",
|
||||||
|
"natives": "1.1.6",
|
||||||
"ng2-cookies": "^1.0.12",
|
"ng2-cookies": "^1.0.12",
|
||||||
"ngx-clipboard": "^11.1.1",
|
"ngx-clipboard": "^11.1.1",
|
||||||
"ngx-infinite-scroll": "^6.0.1",
|
"ngx-infinite-scroll": "^6.0.1",
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
"ViewOnEmby": "View On Emby",
|
"ViewOnEmby": "View On Emby",
|
||||||
"RequestAdded": "Request for {{title}} has been added successfully",
|
"RequestAdded": "Request for {{title}} has been added successfully",
|
||||||
"Similar":"Similar",
|
"Similar":"Similar",
|
||||||
|
"Refine":"Refine",
|
||||||
"Movies": {
|
"Movies": {
|
||||||
"PopularMovies": "Popular Movies",
|
"PopularMovies": "Popular Movies",
|
||||||
"UpcomingMovies": "Upcoming Movies",
|
"UpcomingMovies": "Upcoming Movies",
|
||||||
|
|
2994
src/Ombi/yarn.lock
2994
src/Ombi/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue