feat(discover): Add original language filter

pull/4619/head
sephrat 2 years ago
parent eea8663f7d
commit ef7ec861d8

@ -3,6 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Models.Search.V2;
using Ombi.TheMovieDbApi.Models;
// Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
@ -14,5 +15,6 @@ namespace Ombi.Core.Engine.V2
{
Task<List<MultiSearchResult>> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken);
Task<IEnumerable<Genre>> GetGenres(string media, CancellationToken requestAborted);
Task<IEnumerable<Language>> GetLanguages(CancellationToken requestAborted);
}
}

@ -17,6 +17,7 @@ using Ombi.Settings.Settings.Models;
using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities;
using Ombi.Store.Repository;
using Ombi.TheMovieDbApi.Models;
// Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
@ -124,5 +125,9 @@ namespace Ombi.Core.Engine.V2
var lang = await DefaultLanguageCode(null);
return await _movieDbApi.GetGenres(media, cancellationToken, lang);
}
public async Task<IEnumerable<Language>> GetLanguages(CancellationToken cancellationToken)
{
return await _movieDbApi.GetLanguages(cancellationToken);
}
}
}

@ -11,5 +11,7 @@ namespace Ombi.Core.Settings.Models.External
public List<int> ExcludedMovieGenreIds { get; set; }
public List<int> ExcludedTvGenreIds { get; set; }
public List<string> OriginalLanguages { get; set; }
}
}

@ -41,6 +41,7 @@ namespace Ombi.Api.TheMovieDb
Task<WatchProviders> GetMovieWatchProviders(int theMoviedbId, CancellationToken token);
Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token);
Task<List<Genre>> GetGenres(string media, CancellationToken cancellationToken, string languageCode);
Task<List<Language>> GetLanguages(CancellationToken cancellationToken);
Task<List<WatchProvidersResults>> SearchWatchProviders(string media, string searchTerm, CancellationToken cancellationToken);
Task<List<MovieDbSearchResult>> AdvancedSearch(DiscoverModel model, CancellationToken cancellationToken);
}

@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Ombi.TheMovieDbApi.Models
{
public class Language
{
[JsonProperty("iso_639_1")]
public string Id { get; set; }
[JsonProperty("english_name")]
public string EnglishName { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
}

@ -438,6 +438,16 @@ namespace Ombi.Api.TheMovieDb
return result.genres ?? new List<Genre>();
}
public async Task<List<Language>> GetLanguages(CancellationToken cancellationToken)
{
var request = new Request($"/configuration/languages", BaseUri, HttpMethod.Get);
request.AddQueryString("api_key", ApiToken);
AddRetry(request);
var result = await Api.Request<List<Language>>(request, cancellationToken);
return result ?? new List<Language>();
}
public Task<TheMovieDbContainer<MultiSearch>> MultiSearch(string searchTerm, string languageCode, CancellationToken cancellationToken)
{
var request = new Request("search/multi", BaseUri, HttpMethod.Get);
@ -472,6 +482,10 @@ namespace Ombi.Api.TheMovieDb
{
request.AddQueryString("without_keywords", string.Join(",", settings.ExcludedKeywordIds));
}
if (settings.OriginalLanguages?.Any() == true)
{
request.AddQueryString("with_original_language", string.Join("|", settings.OriginalLanguages));
}
}
private async Task AddGenreFilter(Request request, string media_type)

@ -17,3 +17,8 @@ export interface IDiscoverModel {
watchProviders?: number[];
companies?: number[];
}
export interface ILanguage {
iso_639_1 : string;
english_name : string;
name : string;
}

@ -339,7 +339,8 @@ export interface ITheMovieDbSettings extends ISettings {
showAdultMovies: boolean;
excludedKeywordIds: number[];
excludedMovieGenreIds: number[];
excludedTvGenreIds: number[]
excludedTvGenreIds: number[];
originalLanguages: string[];
}
export interface IUpdateModel

@ -4,7 +4,7 @@ import { Injectable, Inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { IDiscoverModel, IMovieDbKeyword, IMultiSearchResult, ISearchMovieResult, ISearchTvResult } from "../interfaces";
import { IDiscoverModel, ILanguage, IMovieDbKeyword, IMultiSearchResult, ISearchMovieResult, ISearchTvResult } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";
import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
@ -23,11 +23,15 @@ export class SearchV2Service extends ServiceHelpers {
public multiSearch(searchTerm: string, filter: SearchFilter): Observable<IMultiSearchResult[]> {
return this.http.post<IMultiSearchResult[]>(`${this.url}/multi/${encodeURIComponent(searchTerm)}`, filter);
}
public getGenres(media: string): Observable<IMovieDbKeyword[]> {
return this.http.get<IMovieDbKeyword[]>(`${this.url}/Genres/${media}`, { headers: this.headers })
}
public getLanguages(): Observable<ILanguage[]> {
return this.http.get<ILanguage[]>(`${this.url}/Languages`, { headers: this.headers })
}
public getFullMovieDetails(theMovieDbId: number): Observable<ISearchMovieResultV2> {
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`);
}

@ -13,6 +13,14 @@
<div class="form-group">
<form [formGroup]='tagForm'>
<mat-form-field appearance="outline" >
<mat-label>Original languages</mat-label>
<mat-select multiple formControlName="originalLanguages" [(value)]="settings.originalLanguages" matTooltip="Filter content by original language.">
<mat-option *ngFor="let language of languages" [value]="language.iso_639_1">
{{language.english_name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="example-full-width">
<input type="text" placeholder="Excluded Keyword IDs for Movie & TV Suggestions" matInput
@ -33,7 +41,7 @@
<i matChipRemove class="fas fa-times fa-lg"></i>
</mat-chip>
</mat-chip-list>
<div class="md-form-field" style="margin-top:1em;">
<mat-form-field appearance="outline" >
<mat-label>Movie Genres</mat-label>
@ -51,7 +59,7 @@
{{key.name}}
<i matChipRemove class="fas fa-times fa-lg"></i>
</mat-chip>
</mat-chip-list>
</mat-chip-list>
<div class="md-form-field" style="margin-top:1em;">
<mat-form-field appearance="outline" >

@ -1,7 +1,7 @@
import {COMMA, ENTER} from "@angular/cdk/keycodes";
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";
import { IMovieDbKeyword, ITheMovieDbSettings } from "../../interfaces";
import { ILanguage, IMovieDbKeyword, ITheMovieDbSettings } from "../../interfaces";
import { debounceTime, switchMap } from "rxjs/operators";
import { MatAutocomplete } from "@angular/material/autocomplete";
@ -22,14 +22,17 @@ interface IKeywordTag {
export class TheMovieDbComponent implements OnInit {
public settings: ITheMovieDbSettings;
public originalLanguages: ILanguage[];
public excludedKeywords: IKeywordTag[];
public excludedMovieGenres: IKeywordTag[];
public excludedTvGenres: IKeywordTag[];
public tagForm: FormGroup;
public languages: ILanguage[];
public filteredTags: IMovieDbKeyword[];
public filteredMovieGenres: IMovieDbKeyword[];
public filteredTvGenres: IMovieDbKeyword[];
constructor(private settingsService: SettingsService,
private notificationService: NotificationService,
private tmdbService: TheMovieDbService,
@ -37,14 +40,30 @@ export class TheMovieDbComponent implements OnInit {
private fb: FormBuilder) { }
public ngOnInit() {
this.tagForm = this.fb.group({
input: null,
excludedMovieGenres: null,
excludedTvGenres: null,
});
this.settingsService.getTheMovieDbSettings().subscribe(settings => {
this.settings = settings;
this.tagForm = this.fb.group({
input: null,
originalLanguages: [this.settings.originalLanguages],
excludedMovieGenres: null,
excludedTvGenres: null,
});
this.tagForm
.get("input")
.valueChanges.pipe(
debounceTime(600),
switchMap((value: string) => {
if (value) {
return this.tmdbService.getKeywords(value);
}
return [];
})
)
.subscribe((r) => (this.filteredTags = r));
// Map Keyword ids -> keyword name
this.excludedKeywords = settings.excludedKeywordIds
? settings.excludedKeywordIds.map(id => ({
@ -82,8 +101,12 @@ export class TheMovieDbComponent implements OnInit {
}
});
});
});
});
this.searchService.getLanguages().subscribe((results) => {
this.languages = results.sort((a: ILanguage, b: ILanguage) => (a.english_name > b.english_name) ? 1 : -1);;
});
// Map Tv Genre ids -> genre name
this.excludedTvGenres = settings.excludedTvGenreIds
? settings.excludedTvGenreIds.map(id => ({
@ -102,22 +125,10 @@ export class TheMovieDbComponent implements OnInit {
genre.name = result.name;
}
});
});
});
});
});
this.tagForm
.get("input")
.valueChanges.pipe(
debounceTime(600),
switchMap((value: string) => {
if (value) {
return this.tmdbService.getKeywords(value);
}
return [];
})
)
.subscribe((r) => (this.filteredTags = r));
}
public remove(tag: IKeywordTag, tag_type: string): void {

@ -19,6 +19,7 @@ using Ombi.Helpers;
// Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
using Genre = Ombi.TheMovieDbApi.Models.Genre;
using Ombi.TheMovieDbApi.Models;
namespace Ombi.Controllers.V2
{
@ -69,6 +70,12 @@ namespace Ombi.Controllers.V2
return _multiSearchEngine.GetGenres(media, HttpContext.RequestAborted);
}
[HttpGet("Languages")]
public Task<IEnumerable<Language>> GetLanguages()
{
return _multiSearchEngine.GetLanguages(HttpContext.RequestAborted);
}
/// <summary>
/// Returns details for a single movie
/// </summary>

Loading…
Cancel
Save