Made a start on the advanced options

pull/4274/head
tidusjar 3 years ago
parent 7119407141
commit 83ee2dae1a

@ -26,7 +26,7 @@ namespace Ombi.Api.TheMovieDb
Task<List<MovieDbSearchResult>> UpcomingTv(string languageCode, int? page = null);
Task<List<MovieDbSearchResult>> SimilarMovies(int movieId, string langCode);
Task<FindResult> Find(string externalId, ExternalSource source);
Task<TvExternals> GetTvExternals(int theMovieDbId);
Task<TvExternals> GetTvExternals(int theMovieDbId);
Task<SeasonDetails> GetSeasonEpisodes(int theMovieDbId, int seasonNumber, CancellationToken token, string langCode = "en");
Task<TvInfo> GetTVInfo(string themoviedbid, string langCode = "en");
Task<TheMovieDbContainer<ActorResult>> SearchByActor(string searchTerm, string langCode);
@ -35,10 +35,10 @@ namespace Ombi.Api.TheMovieDb
Task<TheMovieDbContainer<DiscoverMovies>> DiscoverMovies(string langCode, int keywordId);
Task<FullMovieInfo> GetFullMovieInfo(int movieId, CancellationToken cancellationToken, string langCode);
Task<Collections> GetCollection(string langCode, int collectionId, CancellationToken cancellationToken);
Task<List<Keyword>> SearchKeyword(string searchTerm);
Task<Keyword> GetKeyword(int keywordId);
Task<List<TheMovidDbKeyValue>> SearchKeyword(string searchTerm);
Task<TheMovidDbKeyValue> GetKeyword(int keywordId);
Task<WatchProviders> GetMovieWatchProviders(int theMoviedbId, CancellationToken token);
Task<WatchProviders> GetTvWatchProviders(int theMoviedbId, CancellationToken token);
Task<List<Genre>> GetGenres(string media);
Task<List<Genre>> GetGenres(string media, CancellationToken cancellationToken);
}
}

@ -2,7 +2,7 @@
namespace Ombi.Api.TheMovieDb.Models
{
public sealed class Keyword
public sealed class TheMovidDbKeyValue
{
[DataMember(Name = "id")]
public int Id { get; set; }

@ -357,34 +357,34 @@ namespace Ombi.Api.TheMovieDb
return Mapper.Map<List<MovieDbSearchResult>>(result.results);
}
public async Task<List<Keyword>> SearchKeyword(string searchTerm)
public async Task<List<TheMovidDbKeyValue>> SearchKeyword(string searchTerm)
{
var request = new Request("search/keyword", BaseUri, HttpMethod.Get);
request.AddQueryString("api_key", ApiToken);
request.AddQueryString("query", searchTerm);
AddRetry(request);
var result = await Api.Request<TheMovieDbContainer<Keyword>>(request);
return result.results ?? new List<Keyword>();
var result = await Api.Request<TheMovieDbContainer<TheMovidDbKeyValue>>(request);
return result.results ?? new List<TheMovidDbKeyValue>();
}
public async Task<Keyword> GetKeyword(int keywordId)
public async Task<TheMovidDbKeyValue> GetKeyword(int keywordId)
{
var request = new Request($"keyword/{keywordId}", BaseUri, HttpMethod.Get);
request.AddQueryString("api_key", ApiToken);
AddRetry(request);
var keyword = await Api.Request<Keyword>(request);
var keyword = await Api.Request<TheMovidDbKeyValue>(request);
return keyword == null || keyword.Id == 0 ? null : keyword;
}
public async Task<List<Genre>> GetGenres(string media)
public async Task<List<Genre>> GetGenres(string media, CancellationToken cancellationToken)
{
var request = new Request($"genre/{media}/list", BaseUri, HttpMethod.Get);
request.AddQueryString("api_key", ApiToken);
AddRetry(request);
var result = await Api.Request<GenreContainer<Genre>>(request);
var result = await Api.Request<GenreContainer<Genre>>(request, cancellationToken);
return result.genres ?? new List<Genre>();
}

@ -1,73 +1,98 @@
import { CommonModule, PlatformLocation, APP_BASE_HREF } from "@angular/common";
import { HttpClient, HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
import { NgModule } from "@angular/core";
import { APP_BASE_HREF, CommonModule, PlatformLocation } from "@angular/common";
import { CardsFreeModule, MDBBootstrapModule, NavbarModule } from "angular-bootstrap-md";
import { CustomPageService, ImageService, RequestService, SettingsService } from "./services";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from "@angular/common/http";
import { IdentityService, IssuesService, JobService, MessageService, PlexTvService, SearchService, StatusService } from "./services";
import { RouterModule, Routes } from "@angular/router";
import { JwtModule } from "@auth0/angular-jwt";
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { CookieService } from "ng2-cookies";
import { AppComponent } from "./app.component";
import { AuthGuard } from "./auth/auth.guard";
import { AuthService } from "./auth/auth.service";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { BrowserModule } from "@angular/platform-browser";
import { ButtonModule } from "primeng/button";
import { ConfirmDialogModule } from "primeng/confirmdialog";
import { CookieComponent } from "./auth/cookie.component";
import { CookieService } from "ng2-cookies";
import { CustomPageComponent } from "./custompage/custompage.component";
import { DataViewModule } from "primeng/dataview";
import { DialogModule } from "primeng/dialog";
import { OverlayPanelModule } from "primeng/overlaypanel";
import { TooltipModule } from "primeng/tooltip";
import { SidebarModule } from "primeng/sidebar";
import { FilterService } from "./discover/services/filter-service";
import { JwtModule } from "@auth0/angular-jwt";
import { LandingPageComponent } from "./landingpage/landingpage.component";
import { LandingPageService } from "./services";
import { LayoutModule } from '@angular/cdk/layout';
import { LoginComponent } from "./login/login.component";
import { LoginOAuthComponent } from "./login/loginoauth.component";
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from "@angular/material/card";
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatNativeDateModule } from '@angular/material/core';
import { MatChipsModule } from "@angular/material/chips";
import { MatDialogModule } from "@angular/material/dialog";
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from "@angular/material/input";
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from "@angular/material/menu";
import { MatNativeDateModule } from '@angular/material/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatCardModule } from "@angular/material/card";
import { MatInputModule } from "@angular/material/input";
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTabsModule } from "@angular/material/tabs";
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from "@angular/material/tooltip";
import { MyNavComponent } from './my-nav/my-nav.component';
import { NavSearchComponent } from "./my-nav/nav-search.component";
import { NgModule } from "@angular/core";
import { NotificationService } from "./services";
import { OverlayModule } from "@angular/cdk/overlay";
import { OverlayPanelModule } from "primeng/overlaypanel";
import { PageNotFoundComponent } from "./errors/not-found.component";
import { RemainingRequestsComponent } from "./shared/remaining-requests/remaining-requests.component";
import { ResetPasswordComponent } from "./login/resetpassword.component";
import { SearchV2Service } from "./services/searchV2.service";
import { SidebarModule } from "primeng/sidebar";
import { SignalRNotificationService } from "./services/signlarnotification.service";
import { StorageService } from "./shared/storage/storage-service";
import { TokenResetPasswordComponent } from "./login/tokenresetpassword.component";
import { TooltipModule } from "primeng/tooltip";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { UnauthorizedInterceptor } from "./auth/unauthorized.interceptor";
// Components
import { MDBBootstrapModule, CardsFreeModule, NavbarModule } from "angular-bootstrap-md";
// Components
import { AppComponent } from "./app.component";
import { CookieComponent } from "./auth/cookie.component";
import { CustomPageComponent } from "./custompage/custompage.component";
import { PageNotFoundComponent } from "./errors/not-found.component";
import { LandingPageComponent } from "./landingpage/landingpage.component";
import { LoginComponent } from "./login/login.component";
import { LoginOAuthComponent } from "./login/loginoauth.component";
import { ResetPasswordComponent } from "./login/resetpassword.component";
import { TokenResetPasswordComponent } from "./login/tokenresetpassword.component";
// Services
import { AuthGuard } from "./auth/auth.guard";
import { AuthService } from "./auth/auth.service";
import { ImageService, SettingsService, CustomPageService, RequestService } from "./services";
import { LandingPageService } from "./services";
import { NotificationService } from "./services";
import { IssuesService, JobService, PlexTvService, StatusService, SearchService, IdentityService, MessageService } from "./services";
import { MyNavComponent } from './my-nav/my-nav.component';
import { LayoutModule } from '@angular/cdk/layout';
import { SearchV2Service } from "./services/searchV2.service";
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";
import { RemainingRequestsComponent } from "./shared/remaining-requests/remaining-requests.component";
import { UnauthorizedInterceptor } from "./auth/unauthorized.interceptor";
import { FilterService } from "./discover/services/filter-service";
const routes: Routes = [
{ path: "*", component: PageNotFoundComponent },
@ -135,6 +160,8 @@ export function JwtTokenGetter() {
MatMenuModule,
MatInputModule,
MatTabsModule,
MatChipsModule,
MatDialogModule,
ReactiveFormsModule,
MatAutocompleteModule,
TooltipModule,
@ -146,7 +173,6 @@ export function JwtTokenGetter() {
MatCheckboxModule,
MatProgressSpinnerModule,
MDBBootstrapModule.forRoot(),
// NbThemeModule.forRoot({ name: 'dark'}),
JwtModule.forRoot({
config: {
tokenGetter: JwtTokenGetter,

@ -1,4 +1,5 @@
<div class="small-middle-container" >
<div *ngIf="loadingFlag" class="row justify-content-md-center top-spacing loading-spinner">
<mat-spinner [color]="'accent'"></mat-spinner>
</div>

@ -78,6 +78,7 @@
<mat-slide-toggle id="filterMusic" class="mat-menu-item slide-menu" [checked]="searchFilter.music"
(click)="$event.stopPropagation()" (change)="changeFilter($event,SearchFilterType.Music)">
{{ 'NavigationBar.Filter.Music' | translate}}</mat-slide-toggle>
<button (click)="openAdvancedSearch()">Advanced Search</button>
<!-- <mat-slide-toggle class="mat-menu-item slide-menu" [checked]="searchFilter.people"
(click)="$event.stopPropagation()" (change)="changeFilter($event,SearchFilterType.People)">
{{ 'NavigationBar.Filter.People' | translate}}</mat-slide-toggle> -->

@ -3,9 +3,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { IUser, RequestType, UserType } from '../interfaces';
import { SettingsService, SettingsStateService } from '../services';
import { AdvancedSearchDialogComponent } from '../shared/advanced-search-dialog/advanced-search-dialog.component';
import { FilterService } from '../discover/services/filter-service';
import { ILocalUser } from '../auth/IUserLogin';
import { INavBar } from '../interfaces/ICommon';
import { MatDialog } from '@angular/material/dialog';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { Md5 } from 'ts-md5/dist/md5';
import { Observable } from 'rxjs';
@ -54,6 +56,7 @@ export class MyNavComponent implements OnInit {
private settingsService: SettingsService,
private store: StorageService,
private filterService: FilterService,
private dialogService: MatDialog,
private readonly settingState: SettingsStateService) {
}
@ -121,6 +124,10 @@ export class MyNavComponent implements OnInit {
this.store.save("searchFilter", JSON.stringify(this.searchFilter));
}
public openAdvancedSearch() {
this.dialogService.open(AdvancedSearchDialogComponent, null);
}
public getUserImage(): string {
var fallback = this.applicationLogo ? this.applicationLogo : 'https://raw.githubusercontent.com/Ombi-app/Ombi/gh-pages/img/android-chrome-512x512.png';
return `https://www.gravatar.com/avatar/${this.emailHash}?d=${fallback}`;

@ -7,7 +7,9 @@ import { catchError } from "rxjs/operators";
import { IMovieDbKeyword } from "../../interfaces";
import { ServiceHelpers } from "../service.helpers";
@Injectable()
@Injectable({
providedIn: 'root',
})
export class TheMovieDbService extends ServiceHelpers {
constructor(http: HttpClient, @Inject(APP_BASE_HREF) href:string) {
super(http, "/api/v1/TheMovieDb", href);

@ -1,13 +1,13 @@
import {COMMA, ENTER} from "@angular/cdk/keycodes";
import { Component, OnInit, ElementRef, ViewChild } from "@angular/core";
import { MatAutocomplete } from "@angular/material/autocomplete";
import { Component, ElementRef, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";
import { IMovieDbKeyword, ITheMovieDbSettings } from "../../interfaces";
import { debounceTime, switchMap } from "rxjs/operators";
import { ITheMovieDbSettings, IMovieDbKeyword } from "../../interfaces";
import { MatAutocomplete } from "@angular/material/autocomplete";
import { NotificationService } from "../../services";
import { SettingsService } from "../../services";
import { TheMovieDbService } from "../../services";
import { FormBuilder, FormGroup } from "@angular/forms";
import { debounceTime, switchMap } from "rxjs/operators";
interface IKeywordTag {
id: number;
@ -30,8 +30,6 @@ export class TheMovieDbComponent implements OnInit {
public filteredMovieGenres: IMovieDbKeyword[];
public filteredTvGenres: IMovieDbKeyword[];
@ViewChild('fruitInput') public fruitInput: ElementRef<HTMLInputElement>;
constructor(private settingsService: SettingsService,
private notificationService: NotificationService,
private tmdbService: TheMovieDbService,

@ -0,0 +1,58 @@
<form [formGroup]="form" *ngIf="form">
<h1 id="advancedOptionsTitle">
<i class="fas fa-sliders-h"></i> Advanced Search
</h1>
<hr />
<div class="alert alert-info" role="alert">
<i class="fas fa-x7 fa-exclamation-triangle glyphicon"></i>
<span>{{ "MediaDetails.AutoApproveOptions" | translate }}</span>
</div>
<div style="max-width: 0; max-height: 0; overflow: hidden">
<input autofocus="true" />
</div>
<div class="row">
<div class="col-md-6">
<div class="md-form-field">
<mat-radio-group formControlName="type" aria-label="Select an option">
<mat-radio-button value="movie">Movies </mat-radio-button>
<mat-radio-button style="padding-left: 5px;" value="tv">TV Shows </mat-radio-button>
</mat-radio-group>
</div>
</div>
<div class="col-md-6">
<mat-form-field appearance="outline" floatLabel=always>
<mat-label>Year</mat-label>
<input matInput id="releaseYear" name="releaseYear" formControlName="releaseYear">
</mat-form-field>
</div>
<div class="col-md-6">
<keyword-search [form]="form"></keyword-search>
</div>
<div class="col-md-6">
<genre-select [form]="form" [mediaType]="form.controls.type.value"></genre-select>
</div>
</div>
<div mat-dialog-actions class="right-buttons">
<button
mat-raised-button
id="cancelButton"
[mat-dialog-close]=""
color="warn"
>
<i class="fas fa-times"></i> {{ "Common.Cancel" | translate }}
</button>
<button
mat-raised-button
id="requestButton"
(click)="submitRequest()"
color="accent"
>
<i class="fas fa-plus"></i> {{ "Common.Request" | translate }}
</button>
</div>
</form>

@ -0,0 +1,8 @@
@import "~styles/variables.scss";
.alert-info {
background: $accent;
border-color: $ombi-background-primary;
color:white;
}

@ -0,0 +1,36 @@
import { Component, Inject, OnInit } from "@angular/core";
import { FormBuilder, FormGroup } from "@angular/forms";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
@Component({
selector: "advanced-search-dialog",
templateUrl: "advanced-search-dialog.component.html",
styleUrls: [ "advanced-search-dialog.component.scss" ]
})
export class AdvancedSearchDialogComponent implements OnInit {
constructor(
public dialogRef: MatDialogRef<AdvancedSearchDialogComponent, string>,
@Inject(MAT_DIALOG_DATA) public data: any,
private fb: FormBuilder
) {}
public form: FormGroup;
public async ngOnInit() {
this.form = this.fb.group({
keywords: [[]],
genres: [[]],
releaseYear: [],
type: ['movie'],
})
this.form.controls.type.valueChanges.subscribe(val => {
this.form.controls.genres.setValue([]);
});
}
}

@ -0,0 +1,25 @@
<mat-form-field class="example-chip-list" appearance="fill">
<mat-label>Genres</mat-label>
<mat-chip-list #chipList aria-label="Fruit selection">
<mat-chip
*ngFor="let word of form.controls.genres.value"
[removable]="true"
(removed)="remove(word)">
{{word.name}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<input
placeholder="Search Keyword"
#keywordInput
[formControl]="control"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"/>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let word of filteredKeywords | async" [value]="word">
{{word.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>

@ -0,0 +1,85 @@
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { debounceTime, distinctUntilChanged, map, startWith, switchMap } from "rxjs/operators";
import { IMovieDbKeyword } from "../../../interfaces";
import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete";
import { Observable } from "rxjs";
import { TheMovieDbService } from "../../../services";
@Component({
selector: "genre-select",
templateUrl: "genre-select.component.html"
})
export class GenreSelectComponent implements OnInit {
constructor(
private tmdbService: TheMovieDbService
) {}
@Input() public form: FormGroup;
private _mediaType: string;
@Input() set mediaType(type: string) {
this._mediaType = type;
this.tmdbService.getGenres(this._mediaType).subscribe((res) => {
this.genres = res;
this.filteredKeywords = this.control.valueChanges.pipe(
startWith(''),
map((genre: string | null) => genre ? this._filter(genre) : this.genres.slice()));
});
}
get mediaType(): string {
return this._mediaType;
}
public genres: IMovieDbKeyword[] = [];
public control = new FormControl();
public filteredTags: IMovieDbKeyword[];
public filteredKeywords: Observable<IMovieDbKeyword[]>;
@ViewChild('keywordInput') input: ElementRef<HTMLInputElement>;
async ngOnInit() {
// this.genres = await this.tmdbService.getGenres(this.mediaType).toPromise();
}
remove(word: IMovieDbKeyword): void {
const exisiting = this.form.controls.genres.value;
const index = exisiting.indexOf(word);
if (index >= 0) {
exisiting.splice(index, 1);
this.form.controls.genres.setValue(exisiting);
}
}
selected(event: MatAutocompleteSelectedEvent): void {
const val = event.option.value;
const exisiting = this.form.controls.genres.value;
if(exisiting.indexOf(val) < 0) {
exisiting.push(val);
}
this.form.controls.genres.setValue(exisiting);
this.input.nativeElement.value = '';
this.control.setValue(null);
}
private _filter(value: string|IMovieDbKeyword): IMovieDbKeyword[] {
if (typeof value === 'object') {
const filterValue = value.name.toLowerCase();
return this.genres.filter(g => g.name.toLowerCase().includes(filterValue));
} else if (typeof value === 'string') {
const filterValue = value.toLowerCase();
return this.genres.filter(g => g.name.toLowerCase().includes(filterValue));
}
return this.genres;
}
}

@ -0,0 +1,37 @@
<!-- <mat-form-field class="example-full-width">
<input type="text" placeholder="Excluded Keyword IDs for Movie & TV Suggestions" matInput
formControlName="input" [matAutocomplete]="auto"
matTooltip="Prevent movies with certain keywords from being suggested. May require a restart to take effect.">
<mat-autocomplete autoActiveFirstOption
#auto="matAutocomplete">
<mat-option *ngFor="let option of filteredTags" [value]="option">
{{option.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field> -->
<mat-form-field class="example-chip-list" appearance="fill">
<mat-label>Keywords</mat-label>
<mat-chip-list #chipList aria-label="Fruit selection">
<mat-chip
*ngFor="let word of form.controls.keywords.value"
[removable]="true"
(removed)="remove(word)">
{{word.name}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
<input
placeholder="Search Keyword"
#keywordInput
[formControl]="control"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"/>
</mat-chip-list>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let word of filteredKeywords | async" [value]="word">
{{word.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>

@ -0,0 +1,64 @@
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { debounceTime, distinctUntilChanged, startWith, switchMap } from "rxjs/operators";
import { IMovieDbKeyword } from "../../../interfaces";
import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete";
import { Observable } from "rxjs";
import { TheMovieDbService } from "../../../services";
@Component({
selector: "keyword-search",
templateUrl: "keyword-search.component.html"
})
export class KeywordSearchComponent implements OnInit {
constructor(
private tmdbService: TheMovieDbService
) {}
@Input() public form: FormGroup;
public control = new FormControl();
public filteredTags: IMovieDbKeyword[];
public filteredKeywords: Observable<IMovieDbKeyword[]>;
@ViewChild('keywordInput') input: ElementRef<HTMLInputElement>;
ngOnInit(): void {
this.filteredKeywords = this.control.valueChanges.pipe(
startWith(''),
debounceTime(400),
distinctUntilChanged(),
switchMap(val => {
return this.filter(val || '')
})
);
}
filter(val: string): Observable<any[]> {
return this.tmdbService.getKeywords(val);
};
remove(word: IMovieDbKeyword): void {
const exisiting = this.form.controls.keywords.value;
const index = exisiting.indexOf(word);
if (index >= 0) {
exisiting.splice(index, 1);
this.form.controls.keywords.setValue(exisiting);
}
}
selected(event: MatAutocompleteSelectedEvent): void {
const val = event.option.value;
const exisiting = this.form.controls.keywords.value;
if (exisiting.indexOf(val) < 0) {
exisiting.push(val);
}
this.form.controls.keywords.setValue(exisiting);
this.input.nativeElement.value = '';
this.control.setValue(null);
}
}

@ -1,43 +1,46 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { TranslateModule } from "@ngx-translate/core";
import { TruncateModule } from "@yellowspot/ng-truncate";
import { MomentModule } from "ngx-moment";
import { IssuesReportComponent } from "./issues-report.component";
import { SidebarModule } from "primeng/sidebar";
import { AdminRequestDialogComponent } from "./admin-request-dialog/admin-request-dialog.component";
import { AdvancedSearchDialogComponent } from "./advanced-search-dialog/advanced-search-dialog.component";
import { CommonModule } from "@angular/common";
import { DetailsGroupComponent } from "../issues/components/details-group/details-group.component";
import { EpisodeRequestComponent } from "./episode-request/episode-request.component";
import { GenreSelectComponent } from "./components/genre-select/genre-select.component";
import { InputSwitchModule } from "primeng/inputswitch";
import { IssuesReportComponent } from "./issues-report.component";
import { KeywordSearchComponent } from "./components/keyword-search/keyword-search.component";
import { MatAutocompleteModule } from "@angular/material/autocomplete";
import { MatButtonModule } from '@angular/material/button';
import { MatNativeDateModule } from '@angular/material/core';
import { MatCardModule } from "@angular/material/card";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatChipsModule } from "@angular/material/chips";
import { MatDialogModule } from "@angular/material/dialog";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from "@angular/material/input";
import { MatListModule } from '@angular/material/list';
import {MatMenuModule} from '@angular/material/menu';
import { MatNativeDateModule } from '@angular/material/core';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import {MatRadioModule} from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
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 { MatTabsModule } from "@angular/material/tabs";
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatTreeModule } from '@angular/material/tree';
import { MatAutocompleteModule } from "@angular/material/autocomplete";
import { MatCardModule } from "@angular/material/card";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { MatChipsModule } from "@angular/material/chips";
import { MatDialogModule } from "@angular/material/dialog";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatInputModule } from "@angular/material/input";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { MatSlideToggleModule } from "@angular/material/slide-toggle";
import { MatTabsModule } from "@angular/material/tabs";
import { EpisodeRequestComponent } from "./episode-request/episode-request.component";
import { DetailsGroupComponent } from "../issues/components/details-group/details-group.component";
import { AdminRequestDialogComponent } from "./admin-request-dialog/admin-request-dialog.component";
import { MomentModule } from "ngx-moment";
import { NgModule } from "@angular/core";
import { SidebarModule } from "primeng/sidebar";
import { TheMovieDbService } from "../services";
import { TranslateModule } from "@ngx-translate/core";
import { TruncateModule } from "@yellowspot/ng-truncate";
@NgModule({
declarations: [
@ -45,6 +48,9 @@ import { AdminRequestDialogComponent } from "./admin-request-dialog/admin-reques
EpisodeRequestComponent,
DetailsGroupComponent,
AdminRequestDialogComponent,
AdvancedSearchDialogComponent,
KeywordSearchComponent,
GenreSelectComponent,
],
imports: [
SidebarModule,
@ -59,6 +65,7 @@ import { AdminRequestDialogComponent } from "./admin-request-dialog/admin-reques
MatAutocompleteModule,
MatInputModule,
MatTabsModule,
MatRadioModule,
MatButtonModule,
MatNativeDateModule,
MatChipsModule,
@ -89,6 +96,9 @@ import { AdminRequestDialogComponent } from "./admin-request-dialog/admin-reques
IssuesReportComponent,
EpisodeRequestComponent,
AdminRequestDialogComponent,
AdvancedSearchDialogComponent,
GenreSelectComponent,
KeywordSearchComponent,
DetailsGroupComponent,
TruncateModule,
InputSwitchModule,

@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ombi.Api.TheMovieDb;
using Ombi.Api.TheMovieDb.Models;
using Ombi.Attributes;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -11,10 +11,10 @@ using Genre = Ombi.TheMovieDbApi.Models.Genre;
namespace Ombi.Controllers.External
{
[Admin]
[ApiV1]
[Authorize]
[Produces("application/json")]
public sealed class TheMovieDbController : Controller
public sealed class TheMovieDbController : ControllerBase
{
public TheMovieDbController(IMovieDbApi tmdbApi) => TmdbApi = tmdbApi;
@ -25,7 +25,7 @@ namespace Ombi.Controllers.External
/// </summary>
/// <param name="searchTerm">The search term.</param>
[HttpGet("Keywords")]
public async Task<IEnumerable<Keyword>> GetKeywords([FromQuery]string searchTerm) =>
public async Task<IEnumerable<TheMovidDbKeyValue>> GetKeywords([FromQuery]string searchTerm) =>
await TmdbApi.SearchKeyword(searchTerm);
/// <summary>
@ -36,15 +36,15 @@ namespace Ombi.Controllers.External
public async Task<IActionResult> GetKeywords(int keywordId)
{
var keyword = await TmdbApi.GetKeyword(keywordId);
return keyword == null ? NotFound() : (IActionResult)Ok(keyword);
return keyword == null ? NotFound() : Ok(keyword);
}
/// <summary>
/// Gets the genres for either Tv or Movies depending on media type
/// </summary>
/// <param name="media">Either `tv` or `movie`.</param>
/// <param name="media">Either `tv` or `movie`.</param>
[HttpGet("Genres/{media}")]
public async Task<IEnumerable<Genre>> GetGenres(string media) =>
await TmdbApi.GetGenres(media);
await TmdbApi.GetGenres(media, HttpContext.RequestAborted);
}
}

Loading…
Cancel
Save