Fixed the issue with the tv search not working #1463

pull/1510/head
Jamie.Rees 7 years ago
parent cd8a44cab8
commit 9f164e4098

@ -7,15 +7,12 @@ namespace Ombi.Core.Engine.Interfaces
public interface ITvSearchEngine
{
Task<IEnumerable<SearchTvShowViewModel>> Search(string searchTerm);
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> SearchTreeNode(string searchTerm);
Task<TreeNode<SearchTvShowViewModel>> GetShowInformationTreeNode(int tvdbid);
Task<SearchTvShowViewModel> GetShowInformation(int tvdbid);
Task<IEnumerable<SearchTvShowViewModel>> Popular();
Task<IEnumerable<SearchTvShowViewModel>> Anticipated();
Task<IEnumerable<SearchTvShowViewModel>> MostWatches();
Task<IEnumerable<SearchTvShowViewModel>> Trending();
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Popular();
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Anticipated();
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatches();
Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Trending();
}
}

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Ombi.Core.Engine
{
public class TreeNode<T>
{
public string Label { get; set; }
public T Data { get; set; }
public List<TreeNode<T>> Children { get; set; }
public bool Leaf { get; set; }
public bool Expanded { get; set; }
}
}

@ -54,6 +54,11 @@ namespace Ombi.Core.Engine
return null;
}
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> SearchTreeNode(string searchTerm)
{
var result = await Search(searchTerm);
return result.Select(ParseIntoTreeNode).ToList();
}
public async Task<SearchTvShowViewModel> GetShowInformation(int tvdbid)
{
var show = await TvMazeApi.ShowLookupByTheTvDbId(tvdbid);
@ -77,7 +82,7 @@ namespace Ombi.Core.Engine
Title = e.name,
AirDate = DateTime.Parse(e.airstamp),
EpisodeNumber = e.number,
});
mapped.SeasonRequests.Add(newSeason);
}
@ -100,29 +105,55 @@ namespace Ombi.Core.Engine
return await ProcessResult(mapped, existingRequests, plexSettings, embySettings);
}
public async Task<IEnumerable<SearchTvShowViewModel>> Popular()
public async Task<TreeNode<SearchTvShowViewModel>> GetShowInformationTreeNode(int tvdbid)
{
var result = await GetShowInformation(tvdbid);
return ParseIntoTreeNode(result);
}
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Popular()
{
var result = await TraktApi.GetPopularShows();
return await ProcessResults(result);
var processed = await ProcessResults(result);
return processed.Select(ParseIntoTreeNode).ToList();
}
public async Task<IEnumerable<SearchTvShowViewModel>> Anticipated()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Anticipated()
{
var result = await TraktApi.GetAnticipatedShows();
return await ProcessResults(result);
var processed= await ProcessResults(result);
return processed.Select(ParseIntoTreeNode).ToList();
}
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatches()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatches()
{
var result = await TraktApi.GetMostWatchesShows();
return await ProcessResults(result);
var processed = await ProcessResults(result);
return processed.Select(ParseIntoTreeNode).ToList();
}
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Trending()
{
var result = await TraktApi.GetTrendingShows();
return await ProcessResults(result);
var processed = await ProcessResults(result);
return processed.Select(ParseIntoTreeNode).ToList();
}
private static TreeNode<SearchTvShowViewModel> ParseIntoTreeNode(SearchTvShowViewModel result)
{
return new TreeNode<SearchTvShowViewModel>
{
Data = result,
Children = new List<TreeNode<SearchTvShowViewModel>>
{
new TreeNode<SearchTvShowViewModel>
{
Data = result, Leaf = true
}
},
Leaf = false
};
}
private async Task<IEnumerable<SearchTvShowViewModel>> ProcessResults<T>(IEnumerable<T> items)
{
@ -180,13 +211,13 @@ namespace Ombi.Core.Engine
// Find the existing request season
var existingSeason =
existingRequestChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == season.SeasonNumber);
if(existingSeason == null) continue;
if (existingSeason == null) continue;
foreach (var ep in existingSeason.Episodes)
{
// Find the episode from what we are searching
var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber);
if(episodeSearching == null)
if (episodeSearching == null)
{
continue;
}

@ -51,17 +51,12 @@
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
<span *ngIf="result.available" class="label label-success">Available</span>
<span *ngIf="result.quality" class="label label-success">{{result.quality}}p</span>
<span *ngIf="result.approved && !result.available" class="label label-info">Processing Request</span>
<span *ngIf="!result.approved">
<span *ngIf="result.requested && !result.available; then requested else notRequested"></span>
<ng-template #requested>
<span *ngIf="!result.available" class="label label-warning">Pending Approval</span>
</ng-template>
<ng-template #notRequested>
<span *ngIf="!result.available" class="label label-danger">Not Yet Requested</span>
</ng-template>
</span>
<ng-template [ngIf]="result.available"><span class="label label-success">Available</span></ng-template>
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info">Processing Request</span></ng-template>
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning">Pending Approval</span></ng-template>
<ng-template [ngIf]="!result.requested && !result.available"><span class="label label-danger">Not Requested</span></ng-template>

@ -54,16 +54,10 @@
{{ep.airDate | date: 'dd/MM/yyyy' }}
</td>
<td>
<span *ngIf="ep.available" class="label label-success">Available</span>
<span *ngIf="ep.approved && !ep.available" class="label label-info">Processing Request</span>
<div *ngIf="ep.requested && !ep.available; then requested else notRequested"></div>
<ng-template #requested>
<span *ngIf="!ep.available" class="label label-warning">Pending Approval</span>
</ng-template>
<ng-template #notRequested>
<span *ngIf="!ep.available" class="label label-danger">Not Yet Requested</span>
</ng-template>
<ng-template [ngIf]="ep.available"><span class="label label-success">Available</span></ng-template>
<ng-template [ngIf]="ep.approved && !ep.available"><span class="label label-info">Processing Request</span></ng-template>
<ng-template [ngIf]="ep.requested && !ep.approved && !ep.available"><span class="label label-warning">Pending Approval</span></ng-template>
<ng-template [ngIf]="!ep.requested && !ep.available"><span class="label label-danger">Not Requested</span></ng-template>
</td>
<td>

@ -39,7 +39,6 @@ export class SeriesInformationComponent implements OnInit, OnDestroy {
});
}
public submitRequests() {
this.series.requested = true;

@ -43,7 +43,7 @@
<div class="row">
<div class="col-sm-2">
<img *ngIf="node.data.banner" class="img-responsive poster" width="150" [src]="node.data.banner" alt="poster">
<img *ngIf="node?.data?.banner" class="img-responsive poster" width="150" [src]="node.data.banner" alt="poster">
</div>
<div class="col-sm-8">
@ -56,10 +56,7 @@
<span *ngIf="node.data.status" class="label label-primary" target="_blank">{{node.data.status}}</span>
<span *ngIf="node.data.firstAired" class="label label-info" target="_blank">Air Date: {{node.data.firstAired}}</span>
<span *ngIf="node.data.releaseDate" class="label label-info" target="_blank">Release Date: {{node.data.releaseDate | date: 'dd/MM/yyyy'}}</span>
<span *ngIf="node.data.firstAired" class="label label-info" target="_blank">Air Date: {{node.data.firstAired | date: 'dd/MM/yyyy'}}</span>
<span *ngIf="node.data.available" class="label label-success">Available</span>
<span *ngIf="node.data.approved && !node.data.available" class="label label-info">Processing Request</span>

@ -9,7 +9,7 @@ import { NotificationService } from '../services/notification.service';
import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
import { TreeNode } from "primeng/primeng";
import { TreeNode } from 'primeng/primeng';
@Component({
selector: 'tv-search',
@ -21,7 +21,7 @@ export class TvSearchComponent implements OnInit, OnDestroy {
private subscriptions = new Subject<void>();
searchText: string;
searchChanged = new Subject<string>();
tvResults: ISearchTvResult[];
tvResults: TreeNode[];
result: IRequestEngineResult;
searchApplied = false;
@ -38,16 +38,16 @@ export class TvSearchComponent implements OnInit, OnDestroy {
this.clearResults();
return;
}
this.searchService.searchTv(this.searchText)
this.searchService.searchTvTreeNode(this.searchText)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.tvResults = this.transformData(x);
this.tvResults = x;
this.searchApplied = true;
});
});
}
openClosestTab(el: any): void {
var rowclass = "undefined";
let rowclass = "undefined";
el = el.toElement;
while (el.className != rowclass) {
// Increment the loop to the parent node until we find the row we need
@ -59,9 +59,9 @@ export class TvSearchComponent implements OnInit, OnDestroy {
// the class you specified
// Then we loop through the children to find the caret which we want to click
var caretright = "ui-treetable-toggler fa fa-fw ui-clickable fa-caret-right";
var caretdown = "ui-treetable-toggler fa fa-fw ui-clickable fa-caret-down";
for (var value of el.children) {
let caretright = "ui-treetable-toggler fa fa-fw ui-clickable fa-caret-right";
let caretdown = "ui-treetable-toggler fa fa-fw ui-clickable fa-caret-down";
for (let value of el.children) {
// the caret from the ui has 2 class selectors depending on if expanded or not
// we search for both since we want to still toggle the clicking
if (value.className === caretright || value.className === caretdown) {
@ -72,20 +72,7 @@ export class TvSearchComponent implements OnInit, OnDestroy {
}
};
}
transformData(datain: ISearchTvResult[]): any {
var temp: TreeNode[] = [];
datain.forEach(function (value) {
temp.push({
"data": value,
"children": [{
"data": value, leaf: true
}],
leaf: false
});
}, this)
return <TreeNode[]>temp;
}
ngOnInit(): void {
this.searchText = "";
this.tvResults = [];
@ -143,12 +130,11 @@ export class TvSearchComponent implements OnInit, OnDestroy {
getExtraInfo() {
this.tvResults.forEach((val, index) => {
this.searchService.getShowInformation(val.id)
this.searchService.getShowInformationTreeNode(val.data.id)
.takeUntil(this.subscriptions)
.subscribe(x => {
this.updateItem(val, x);
this.updateItem(val.data, x);
});
});
}
@ -161,7 +147,6 @@ export class TvSearchComponent implements OnInit, OnDestroy {
.takeUntil(this.subscriptions)
.subscribe(x => {
this.result = x;
if (this.result.requestAdded) {
this.notificationService.success("Request Added",
`Request for ${searchResult.title} has been added successfully`);
@ -171,7 +156,6 @@ export class TvSearchComponent implements OnInit, OnDestroy {
});
}
allSeasons(searchResult: ISearchTvResult) {
searchResult.requestAll = true;
this.request(searchResult);
@ -191,11 +175,11 @@ export class TvSearchComponent implements OnInit, OnDestroy {
this.route.navigate(['/search/show', searchResult.id]);
}
private updateItem(key: ISearchTvResult, updated: ISearchTvResult) {
var index = this.tvResults.indexOf(key, 0);
if (index > -1) {
this.tvResults[index] = updated;
}
private updateItem(key: TreeNode, updated: TreeNode) {
let item = this.tvResults.filter((val) => {
return val.data == key;
});
item[0].data = updated.data;
}
private clearResults() {

@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Rx';
import { ServiceAuthHelpers } from './service.helpers';
import { ISearchMovieResult } from '../interfaces/ISearchMovieResult';
import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { TreeNode } from "primeng/primeng";
@Injectable()
export class SearchService extends ServiceAuthHelpers {
@ -37,21 +38,28 @@ export class SearchService extends ServiceAuthHelpers {
searchTv(searchTerm: string): Observable<ISearchTvResult[]> {
return this.http.get(`${this.url}/Tv/` + searchTerm).map(this.extractData);
}
searchTvTreeNode(searchTerm: string): Observable<TreeNode[]> {
return this.http.get(`${this.url}/Tv/${searchTerm}/tree`).map(this.extractData);
}
getShowInformationTreeNode(theTvDbId: number): Observable<TreeNode> {
return this.http.get(`${this.url}/Tv/info/${theTvDbId}/Tree`).map(this.extractData);
}
getShowInformation(theTvDbId: number): Observable<ISearchTvResult> {
return this.http.get(`${this.url}/Tv/info/${theTvDbId}`).map(this.extractData);
}
popularTv(): Observable<ISearchTvResult[]> {
popularTv(): Observable<TreeNode[]> {
return this.http.get(`${this.url}/Tv/popular`).map(this.extractData);
}
mostWatchedTv(): Observable<ISearchTvResult[]> {
mostWatchedTv(): Observable<TreeNode[]> {
return this.http.get(`${this.url}/Tv/mostwatched`).map(this.extractData);
}
anticipatedTv(): Observable<ISearchTvResult[]> {
anticipatedTv(): Observable<TreeNode[]> {
return this.http.get(`${this.url}/Tv/anticipated`).map(this.extractData);
}
trendingTv(): Observable<ISearchTvResult[]> {
trendingTv(): Observable<TreeNode[]> {
return this.http.get(`${this.url}/Tv/trending`).map(this.extractData);
}
}

@ -113,6 +113,30 @@ namespace Ombi.Controllers
return await TvEngine.Search(searchTerm);
}
/// <summary>
/// Searches for a Tv Show.
/// </summary>
/// <param name="searchTerm">The search term.</param>
/// <remarks>We use TvMaze as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/{searchTerm}/tree")]
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> SearchTvTreeNode(string searchTerm)
{
return await TvEngine.SearchTreeNode(searchTerm);
}
/// <summary>
/// Gets extra show information.
/// </summary>
/// <param name="tvdbId">The TVDB identifier.</param>
/// <remarks>We use TvMaze as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/info/{tvdbId}/tree")]
public async Task<TreeNode<SearchTvShowViewModel>> GetShowInfoTreeNode(int tvdbId)
{
return await TvEngine.GetShowInformationTreeNode(tvdbId);
}
/// <summary>
/// Gets extra show information.
/// </summary>
@ -131,7 +155,7 @@ namespace Ombi.Controllers
/// <remarks>We use Trakt.tv as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/popular")]
public async Task<IEnumerable<SearchTvShowViewModel>> PopularTv()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> PopularTv()
{
return await TvEngine.Popular();
}
@ -141,7 +165,7 @@ namespace Ombi.Controllers
/// <remarks>We use Trakt.tv as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/anticipated")]
public async Task<IEnumerable<SearchTvShowViewModel>> AnticiplatedTv()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> AnticiplatedTv()
{
return await TvEngine.Anticipated();
}
@ -151,7 +175,7 @@ namespace Ombi.Controllers
/// <remarks>We use Trakt.tv as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/mostwatched")]
public async Task<IEnumerable<SearchTvShowViewModel>> MostWatched()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> MostWatched()
{
return await TvEngine.MostWatches();
}
@ -161,7 +185,7 @@ namespace Ombi.Controllers
/// <remarks>We use Trakt.tv as the Provider</remarks>
/// <returns></returns>
[HttpGet("tv/trending")]
public async Task<IEnumerable<SearchTvShowViewModel>> Trending()
public async Task<IEnumerable<TreeNode<SearchTvShowViewModel>>> Trending()
{
return await TvEngine.Trending();
}

@ -4,7 +4,7 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
<RuntimeIdentifiers>win10-x64;osx.10.12-x64;ubuntu.16.04-x64;debian.8-x64;centos.7-x64;</RuntimeIdentifiers>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<TypeScriptToolsVersion>2.5</TypeScriptToolsVersion>
<TypeScriptToolsVersion>2.3</TypeScriptToolsVersion>
<AssemblyVersion>$(SemVer)</AssemblyVersion>
<FileVersion>$(SemVer)</FileVersion>
<Version>$(FullVer)</Version>

@ -9,6 +9,7 @@
bottom: 0;
left: 0;
right: 0;
background-color: #1f1f1f;
}
.app-loading {

Loading…
Cancel
Save