From 7ba63a33ce1d17eab3f1ec85fd400357ce72d017 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 6 Oct 2020 14:17:01 +0100 Subject: [PATCH] Added the ability to filter the main search bar --- src/Ombi.Core/Engine/V2/IMultiSearchEngine.cs | 2 +- src/Ombi.Core/Engine/V2/MultiSearchEngine.cs | 15 +++--- .../Models/Search/V2/MultiSearchFilter.cs | 14 ++++++ src/Ombi/ClientApp/src/app/app.module.ts | 2 + .../ClientApp/src/app/my-nav/SearchFilter.ts | 7 +++ .../src/app/my-nav/my-nav.component.html | 15 +++++- .../src/app/my-nav/my-nav.component.scss | 7 +++ .../src/app/my-nav/my-nav.component.ts | 48 +++++++++++++++++-- .../src/app/my-nav/nav-search.component.ts | 6 ++- .../src/app/services/searchV2.service.ts | 21 ++++---- .../ClientApp/src/app/shared/shared.module.ts | 16 ++++--- src/Ombi/Controllers/V2/SearchController.cs | 7 +-- src/Ombi/wwwroot/translations/en.json | 8 +++- 13 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 src/Ombi.Core/Models/Search/V2/MultiSearchFilter.cs create mode 100644 src/Ombi/ClientApp/src/app/my-nav/SearchFilter.ts diff --git a/src/Ombi.Core/Engine/V2/IMultiSearchEngine.cs b/src/Ombi.Core/Engine/V2/IMultiSearchEngine.cs index e2313016b..1b78eaea5 100644 --- a/src/Ombi.Core/Engine/V2/IMultiSearchEngine.cs +++ b/src/Ombi.Core/Engine/V2/IMultiSearchEngine.cs @@ -8,6 +8,6 @@ namespace Ombi.Core.Engine.V2 { public interface IMultiSearchEngine { - Task> MultiSearch(string searchTerm, CancellationToken cancellationToken); + Task> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/V2/MultiSearchEngine.cs b/src/Ombi.Core/Engine/V2/MultiSearchEngine.cs index 404f775cc..60cd6377d 100644 --- a/src/Ombi.Core/Engine/V2/MultiSearchEngine.cs +++ b/src/Ombi.Core/Engine/V2/MultiSearchEngine.cs @@ -36,7 +36,7 @@ namespace Ombi.Core.Engine.V2 private readonly IMusicBrainzApi _musicApi; - public async Task> MultiSearch(string searchTerm, CancellationToken cancellationToken) + public async Task> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken) { var lang = await DefaultLanguageCode(null); var model = new List(); @@ -44,7 +44,7 @@ namespace Ombi.Core.Engine.V2 var movieDbData = (await _movieDbApi.MultiSearch(searchTerm, lang, cancellationToken)).results; var lidarrSettings = await _lidarrSettings.GetSettingsAsync(); - if (lidarrSettings.Enabled) + if (lidarrSettings.Enabled && filter.Music) { var artistResult = await _musicApi.SearchArtist(searchTerm); foreach (var artist in artistResult) @@ -66,7 +66,7 @@ namespace Ombi.Core.Engine.V2 Poster = multiSearch.poster_path }; - if (multiSearch.media_type.Equals("movie", StringComparison.InvariantCultureIgnoreCase)) + if (multiSearch.media_type.Equals("movie", StringComparison.InvariantCultureIgnoreCase) && filter.Movies) { if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate)) { @@ -78,7 +78,7 @@ namespace Ombi.Core.Engine.V2 } } - if (multiSearch.media_type.Equals("tv", StringComparison.InvariantCultureIgnoreCase)) + else if (multiSearch.media_type.Equals("tv", StringComparison.InvariantCultureIgnoreCase) && filter.TvShows) { if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate)) { @@ -89,11 +89,14 @@ namespace Ombi.Core.Engine.V2 result.Title = multiSearch.name; } } - - if (multiSearch.media_type.Equals("person", StringComparison.InvariantCultureIgnoreCase)) + else if (multiSearch.media_type.Equals("person", StringComparison.InvariantCultureIgnoreCase) && filter.People) { result.Title = multiSearch.name; } + else + { + continue; + } result.Id = multiSearch.id.ToString(); model.Add(result); diff --git a/src/Ombi.Core/Models/Search/V2/MultiSearchFilter.cs b/src/Ombi.Core/Models/Search/V2/MultiSearchFilter.cs new file mode 100644 index 000000000..8e12f1d24 --- /dev/null +++ b/src/Ombi.Core/Models/Search/V2/MultiSearchFilter.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Ombi.Core.Models.Search.V2 +{ + public class MultiSearchFilter + { + public bool Movies { get; set; } + public bool TvShows { get; set; } + public bool Music { get; set; } + public bool People { get; set; } + } +} diff --git a/src/Ombi/ClientApp/src/app/app.module.ts b/src/Ombi/ClientApp/src/app/app.module.ts index 1094ea7dc..2a9b6d802 100644 --- a/src/Ombi/ClientApp/src/app/app.module.ts +++ b/src/Ombi/ClientApp/src/app/app.module.ts @@ -64,6 +64,7 @@ import { NavSearchComponent } from "./my-nav/nav-search.component"; import { OverlayModule } from "@angular/cdk/overlay"; import { StorageService } from "./shared/storage/storage-service"; import { SignalRNotificationService } from "./services/signlarnotification.service"; +import { MatMenuModule } from "@angular/material/menu"; const routes: Routes = [ { path: "*", component: PageNotFoundComponent }, { path: "", redirectTo: "/discover", pathMatch: "full" }, @@ -126,6 +127,7 @@ export function JwtTokenGetter() { NavbarModule, MatCardModule, MatTooltipModule, + MatMenuModule, MatInputModule, MatTabsModule, ReactiveFormsModule, diff --git a/src/Ombi/ClientApp/src/app/my-nav/SearchFilter.ts b/src/Ombi/ClientApp/src/app/my-nav/SearchFilter.ts new file mode 100644 index 000000000..40af3af79 --- /dev/null +++ b/src/Ombi/ClientApp/src/app/my-nav/SearchFilter.ts @@ -0,0 +1,7 @@ + +export class SearchFilter { + movies: boolean; + tvShows: boolean; + music: boolean; + people: boolean; +} diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html index 0f9f02273..e95ceda1c 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.html @@ -49,17 +49,28 @@ menu -
+
- +
+
+ + + {{ 'NavigationBar.Filter.Movies' | translate}} + {{ 'NavigationBar.Filter.TvShows' | translate}} + {{ 'NavigationBar.Filter.Music' | translate}} + {{ 'NavigationBar.Filter.People' | translate}} + +
+ + diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss index d727ac697..ebc723472 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.scss @@ -55,6 +55,13 @@ font-weight:500; } +.slide-menu { + width: 100%; +} + +::ng-deep .smaller-panel { + max-width: 170px !important; +} .mat-drawer-content { position: relative; diff --git a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts index 9dd5b841a..cd919ce45 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts +++ b/src/Ombi/ClientApp/src/app/my-nav/my-nav.component.ts @@ -5,6 +5,15 @@ import { map } from 'rxjs/operators'; import { INavBar } from '../interfaces/ICommon'; import { StorageService } from '../shared/storage/storage-service'; import { SettingsService } from '../services'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { SearchFilter } from './SearchFilter'; + +export enum SearchFilterType { + Movie = 1, + TvShow = 2, + Music = 3, + People = 4 +} @Component({ selector: 'app-my-nav', @@ -27,20 +36,33 @@ export class MyNavComponent implements OnInit { public theme: string; public issuesEnabled: boolean = false; public navItems: INavBar[]; + public searchFilter: SearchFilter; + public SearchFilterType = SearchFilterType; constructor(private breakpointObserver: BreakpointObserver, - private settingsService: SettingsService, - private store: StorageService) { + private settingsService: SettingsService, + private store: StorageService) { } public async ngOnInit() { + this.searchFilter = { + movies: true, + music: false, + people: false, + tvShows: true + } + this.issuesEnabled = await this.settingsService.issueEnabled().toPromise(); const customizationSettings = await this.settingsService.getCustomization().toPromise(); console.log("issues enabled: " + this.issuesEnabled); this.theme = this.store.get("theme"); - if(!this.theme) { - this.store.save("theme","dark"); + if (!this.theme) { + this.store.save("theme", "dark"); + } + var filter = this.store.get("searchFilter"); + if (filter) { + this.searchFilter = Object.assign(new SearchFilter(), JSON.parse(filter)); } this.navItems = [ { name: "NavigationBar.Discover", icon: "find_replace", link: "/discover", requiresAdmin: false, enabled: true, faIcon: null }, @@ -73,4 +95,22 @@ export class MyNavComponent implements OnInit { this.themeChange.emit(newTheme); } } + + public changeFilter(event: MatSlideToggleChange, searchFilterType: SearchFilterType) { + switch (searchFilterType) { + case SearchFilterType.Movie: + this.searchFilter.movies = event.checked; + break; + case SearchFilterType.TvShow: + this.searchFilter.tvShows = event.checked; + break; + case SearchFilterType.Music: + this.searchFilter.music = event.checked; + break; + case SearchFilterType.People: + this.searchFilter.people = event.checked; + break; + } + this.store.save("searchFilter", JSON.stringify(this.searchFilter)); + } } diff --git a/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.ts b/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.ts index def528ac0..10fed25a4 100644 --- a/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.ts +++ b/src/Ombi/ClientApp/src/app/my-nav/nav-search.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, Input, OnInit } from "@angular/core"; import { Observable } from "rxjs"; import { debounceTime, @@ -14,6 +14,7 @@ import { IMultiSearchResult } from "../interfaces"; import { Router } from "@angular/router"; import { FormGroup, FormBuilder } from "@angular/forms"; import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete"; +import { SearchFilter } from "./SearchFilter"; @Component({ selector: "app-nav-search", @@ -21,6 +22,7 @@ import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete"; styleUrls: ["./nav-search.component.scss"], }) export class NavSearchComponent implements OnInit { + @Input() public filter: SearchFilter; public selectedItem: string; public results: IMultiSearchResult[]; public searching = false; @@ -46,7 +48,7 @@ export class NavSearchComponent implements OnInit { switchMap((value: string) => { if (value) { return this.searchService - .multiSearch(value) + .multiSearch(value, this.filter) .pipe(finalize(() => (this.searching = false))); } return empty().pipe(finalize(() => (this.searching = false))); diff --git a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts index f39755041..6536e3cf6 100644 --- a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts +++ b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts @@ -10,6 +10,7 @@ import { ServiceHelpers } from "./service.helpers"; import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2"; import { ISearchTvResultV2, IMovieCollectionsViewModel, IActorCredits } from "../interfaces/ISearchTvResultV2"; import { IArtistSearchResult, IAlbumArt } from "../interfaces/IMusicSearchResultV2"; +import { SearchFilter } from "../my-nav/SearchFilter"; @Injectable() export class SearchV2Service extends ServiceHelpers { @@ -17,8 +18,8 @@ export class SearchV2Service extends ServiceHelpers { super(http, "/api/v2/search", href); } - public multiSearch(searchTerm: string): Observable { - return this.http.get(`${this.url}/multi/${searchTerm}`); + public multiSearch(searchTerm: string, filter: SearchFilter): Observable { + return this.http.post(`${this.url}/multi/${searchTerm}`, filter); } public getFullMovieDetails(theMovieDbId: number): Observable { return this.http.get(`${this.url}/Movie/${theMovieDbId}`); @@ -27,7 +28,7 @@ export class SearchV2Service extends ServiceHelpers { public getMovieByImdbId(imdbId: string): Observable { return this.http.get(`${this.url}/Movie/imdb/${imdbId}`); } - + public getFullMovieDetailsByRequestId(requestId: number): Promise { return this.http.get(`${this.url}/Movie/request/${requestId}`).toPromise(); } @@ -35,7 +36,7 @@ export class SearchV2Service extends ServiceHelpers { public getFullMovieDetailsPromise(theMovieDbId: number): Promise { return this.http.get(`${this.url}/Movie/${theMovieDbId}`).toPromise(); } - + public similarMovies(theMovieDbId: number, langCode: string): Observable { return this.http.post(`${this.url}/Movie/similar`, {theMovieDbId, languageCode: langCode}); } @@ -62,11 +63,11 @@ export class SearchV2Service extends ServiceHelpers { public nowPlayingMoviesByPage(currentlyLoaded: number, toLoad: number): Promise { return this.http.get(`${this.url}/Movie/nowplaying/${currentlyLoaded}/${toLoad}`).toPromise(); } - + public topRatedMovies(): Observable { return this.http.get(`${this.url}/Movie/toprated`); } - + public popularTv(): Observable { return this.http.get(`${this.url}/Tv/popular`, { headers: this.headers }); } @@ -84,7 +85,7 @@ export class SearchV2Service extends ServiceHelpers { public anticipatedTvByPage(currentlyLoaded: number, toLoad: number): Promise { return this.http.get(`${this.url}/Tv/anticipated/${currentlyLoaded}/${toLoad}`, { headers: this.headers }).toPromise(); } - + public trendingTv(): Observable { return this.http.get(`${this.url}/Tv/trending`, { headers: this.headers }); } @@ -92,7 +93,7 @@ export class SearchV2Service extends ServiceHelpers { public trendingTvByPage(currentlyLoaded: number, toLoad: number): Promise { return this.http.get(`${this.url}/Tv/trending/${currentlyLoaded}/${toLoad}`, { headers: this.headers }).toPromise(); } - + public getTvInfo(tvdbid: number): Promise { return this.http.get(`${this.url}/Tv/${tvdbid}`, { headers: this.headers }).toPromise(); } @@ -100,11 +101,11 @@ export class SearchV2Service extends ServiceHelpers { public getTvInfoWithRequestId(requestId: number): Promise { return this.http.get(`${this.url}/Tv/request/${requestId}`, { headers: this.headers }).toPromise(); } - + public getTvInfoWithMovieDbId(theMovieDbId: number): Promise { return this.http.get(`${this.url}/Tv/moviedb/${theMovieDbId}`, { headers: this.headers }).toPromise(); } - + public getMovieCollections(collectionId: number): Promise { return this.http.get(`${this.url}/movie/collection/${collectionId}`, { headers: this.headers }).toPromise(); } diff --git a/src/Ombi/ClientApp/src/app/shared/shared.module.ts b/src/Ombi/ClientApp/src/app/shared/shared.module.ts index 30c7f4df8..543027bfd 100644 --- a/src/Ombi/ClientApp/src/app/shared/shared.module.ts +++ b/src/Ombi/ClientApp/src/app/shared/shared.module.ts @@ -21,6 +21,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSortModule } from '@angular/material/sort'; import { MatStepperModule } from '@angular/material/stepper'; import { MatTableModule } from '@angular/material/table'; +import {MatMenuModule} from '@angular/material/menu'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTreeModule } from '@angular/material/tree'; @@ -56,9 +57,10 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo MatButtonModule, MatNativeDateModule, MatChipsModule, - MatIconModule, - MatSidenavModule, - MatListModule, + MatIconModule, + MatMenuModule, + MatSidenavModule, + MatListModule, MatToolbarModule, MatCheckboxModule, TranslateModule, @@ -71,7 +73,6 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo MatTreeModule, MatStepperModule, MatSnackBarModule, - MatSlideToggleModule, ], entryComponents: [ EpisodeRequestComponent @@ -94,11 +95,12 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo MatChipsModule, MatButtonModule, MatNativeDateModule, - MatIconModule, + MatIconModule, + MatMenuModule, MatSnackBarModule, - MatSidenavModule, + MatSidenavModule, MatSelectModule, - MatListModule, + MatListModule, MatToolbarModule, MatTooltipModule, MatAutocompleteModule, diff --git a/src/Ombi/Controllers/V2/SearchController.cs b/src/Ombi/Controllers/V2/SearchController.cs index 587a5621e..652ff15eb 100644 --- a/src/Ombi/Controllers/V2/SearchController.cs +++ b/src/Ombi/Controllers/V2/SearchController.cs @@ -44,11 +44,12 @@ namespace Ombi.Controllers.V2 /// Show information using the MovieDbId. /// The search you want, this can be for a movie or TV show e.g. Star Wars will return /// all Star Wars movies and Star Wars Rebels the TV Sho + /// Filter for the search /// - [HttpGet("multi/{searchTerm}")] - public async Task> MultiSearch(string searchTerm) + [HttpPost("multi/{searchTerm}")] + public async Task> MultiSearch(string searchTerm, [FromBody] MultiSearchFilter filter) { - return await _multiSearchEngine.MultiSearch(searchTerm, Request.HttpContext.RequestAborted); + return await _multiSearchEngine.MultiSearch(searchTerm, filter, Request.HttpContext.RequestAborted); } /// diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index 4b198982a..c5e56964f 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -69,7 +69,13 @@ "Calendar": "Calendar", "UserPreferences": "Preferences", "FeatureSuggestion":"Feature Suggestion", - "FeatureSuggestionTooltip":"Have a great new idea? Suggest it here!" + "FeatureSuggestionTooltip":"Have a great new idea? Suggest it here!", + "Filter": { + "Movies":"Movies", + "TvShows":"TV Shows", + "Music":"Music", + "People":"People" + } }, "Search": { "Title": "Search",