Merge pull request #4619 from sephrat/original-language

Add original language filter
pull/4625/head
Jamie 3 years ago committed by GitHub
commit b57cd31817
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,6 +3,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ombi.Api.TheMovieDb.Models; using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Models.Search.V2; using Ombi.Core.Models.Search.V2;
using Ombi.TheMovieDbApi.Models;
// Due to conflicting Genre models in // Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models // 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<List<MultiSearchResult>> MultiSearch(string searchTerm, MultiSearchFilter filter, CancellationToken cancellationToken);
Task<IEnumerable<Genre>> GetGenres(string media, CancellationToken requestAborted); 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.Settings.Settings.Models.External;
using Ombi.Store.Entities; using Ombi.Store.Entities;
using Ombi.Store.Repository; using Ombi.Store.Repository;
using Ombi.TheMovieDbApi.Models;
// Due to conflicting Genre models in // Due to conflicting Genre models in
// Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models // Ombi.TheMovieDbApi.Models and Ombi.Api.TheMovieDb.Models
@ -124,5 +125,9 @@ namespace Ombi.Core.Engine.V2
var lang = await DefaultLanguageCode(null); var lang = await DefaultLanguageCode(null);
return await _movieDbApi.GetGenres(media, cancellationToken, lang); 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> ExcludedMovieGenreIds { get; set; }
public List<int> ExcludedTvGenreIds { 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> GetMovieWatchProviders(int theMoviedbId, CancellationToken token);
Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token); Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token);
Task<List<Genre>> GetGenres(string media, CancellationToken cancellationToken, string languageCode); 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<WatchProvidersResults>> SearchWatchProviders(string media, string searchTerm, CancellationToken cancellationToken);
Task<List<MovieDbSearchResult>> AdvancedSearch(DiscoverModel model, 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>(); 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) public Task<TheMovieDbContainer<MultiSearch>> MultiSearch(string searchTerm, string languageCode, CancellationToken cancellationToken)
{ {
var request = new Request("search/multi", BaseUri, HttpMethod.Get); 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)); 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) private async Task AddGenreFilter(Request request, string media_type)

@ -17,3 +17,8 @@ export interface IDiscoverModel {
watchProviders?: number[]; watchProviders?: number[];
companies?: 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; showAdultMovies: boolean;
excludedKeywordIds: number[]; excludedKeywordIds: number[];
excludedMovieGenreIds: number[]; excludedMovieGenreIds: number[];
excludedTvGenreIds: number[] excludedTvGenreIds: number[];
originalLanguages: string[];
} }
export interface IUpdateModel export interface IUpdateModel

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

@ -13,6 +13,14 @@
<div class="form-group"> <div class="form-group">
<form [formGroup]='tagForm'> <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"> <mat-form-field class="example-full-width">
<input type="text" placeholder="Excluded Keyword IDs for Movie & TV Suggestions" matInput <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> <i matChipRemove class="fas fa-times fa-lg"></i>
</mat-chip> </mat-chip>
</mat-chip-list> </mat-chip-list>
<div class="md-form-field" style="margin-top:1em;"> <div class="md-form-field" style="margin-top:1em;">
<mat-form-field appearance="outline" > <mat-form-field appearance="outline" >
<mat-label>Movie Genres</mat-label> <mat-label>Movie Genres</mat-label>
@ -51,7 +59,7 @@
{{key.name}} {{key.name}}
<i matChipRemove class="fas fa-times fa-lg"></i> <i matChipRemove class="fas fa-times fa-lg"></i>
</mat-chip> </mat-chip>
</mat-chip-list> </mat-chip-list>
<div class="md-form-field" style="margin-top:1em;"> <div class="md-form-field" style="margin-top:1em;">
<mat-form-field appearance="outline" > <mat-form-field appearance="outline" >

@ -1,7 +1,7 @@
import {COMMA, ENTER} from "@angular/cdk/keycodes"; import {COMMA, ENTER} from "@angular/cdk/keycodes";
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core"; import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms"; import { FormBuilder, FormGroup } from "@angular/forms";
import { IMovieDbKeyword, ITheMovieDbSettings } from "../../interfaces"; import { ILanguage, IMovieDbKeyword, ITheMovieDbSettings } from "../../interfaces";
import { debounceTime, switchMap } from "rxjs/operators"; import { debounceTime, switchMap } from "rxjs/operators";
import { MatAutocomplete } from "@angular/material/autocomplete"; import { MatAutocomplete } from "@angular/material/autocomplete";
@ -22,14 +22,17 @@ interface IKeywordTag {
export class TheMovieDbComponent implements OnInit { export class TheMovieDbComponent implements OnInit {
public settings: ITheMovieDbSettings; public settings: ITheMovieDbSettings;
public originalLanguages: ILanguage[];
public excludedKeywords: IKeywordTag[]; public excludedKeywords: IKeywordTag[];
public excludedMovieGenres: IKeywordTag[]; public excludedMovieGenres: IKeywordTag[];
public excludedTvGenres: IKeywordTag[]; public excludedTvGenres: IKeywordTag[];
public tagForm: FormGroup; public tagForm: FormGroup;
public languages: ILanguage[];
public filteredTags: IMovieDbKeyword[]; public filteredTags: IMovieDbKeyword[];
public filteredMovieGenres: IMovieDbKeyword[]; public filteredMovieGenres: IMovieDbKeyword[];
public filteredTvGenres: IMovieDbKeyword[]; public filteredTvGenres: IMovieDbKeyword[];
constructor(private settingsService: SettingsService, constructor(private settingsService: SettingsService,
private notificationService: NotificationService, private notificationService: NotificationService,
private tmdbService: TheMovieDbService, private tmdbService: TheMovieDbService,
@ -37,14 +40,30 @@ export class TheMovieDbComponent implements OnInit {
private fb: FormBuilder) { } private fb: FormBuilder) { }
public ngOnInit() { public ngOnInit() {
this.tagForm = this.fb.group({
input: null,
excludedMovieGenres: null,
excludedTvGenres: null,
});
this.settingsService.getTheMovieDbSettings().subscribe(settings => { this.settingsService.getTheMovieDbSettings().subscribe(settings => {
this.settings = 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 // Map Keyword ids -> keyword name
this.excludedKeywords = settings.excludedKeywordIds this.excludedKeywords = settings.excludedKeywordIds
? settings.excludedKeywordIds.map(id => ({ ? 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 // Map Tv Genre ids -> genre name
this.excludedTvGenres = settings.excludedTvGenreIds this.excludedTvGenres = settings.excludedTvGenreIds
? settings.excludedTvGenreIds.map(id => ({ ? settings.excludedTvGenreIds.map(id => ({
@ -102,22 +125,10 @@ export class TheMovieDbComponent implements OnInit {
genre.name = result.name; 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 { public remove(tag: IKeywordTag, tag_type: string): void {
@ -162,7 +173,7 @@ export class TheMovieDbComponent implements OnInit {
this.settingsService.saveTheMovieDbSettings(this.settings).subscribe(x => { this.settingsService.saveTheMovieDbSettings(this.settings).subscribe(x => {
if (x) { if (x) {
this.notificationService.success("Successfully saved The Movie Database settings"); this.notificationService.success("Successfully saved The Movie Database settings. Restart the server to refresh the cache.");
} else { } else {
this.notificationService.success("There was an error when saving The Movie Database settings"); this.notificationService.success("There was an error when saving The Movie Database settings");
} }

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

Loading…
Cancel
Save