Make Episode picker similar to Requests Child view. #1457 #1463

pull/1496/head
Dhruv Bhavsar 7 years ago
parent d1da6ca9b4
commit 4215c77620

@ -4,12 +4,20 @@
</div> </div>
</div> </div>
<br /> <br />
<!--TODO: I believe this +1 is causing off by one error skipping loading of tv shows
When removed and scrolling very slowly everything works as expected, however
if you scroll really quickly then you start getting duplicates of movies
since it's async and some subsequent results return first and then incrementer
is increased so you see movies which had already been gotten show up...
Removing infinte-scroll and setting max to 1000 till we work out some sort of fix
<div infinite-scroll -->
<!--<div infinite-scroll
[infiniteScrollDistance]="1" [infiniteScrollDistance]="1"
[infiniteScrollThrottle]="100" [infiniteScrollThrottle]="100"
(scrolled)="loadMore()"> (scrolled)="loadMore()">-->
<!--<div>--> <div>
<p-treeTable [value]="tvRequests"> <p-treeTable [value]="tvRequests">
<!--<p-column> <!--<p-column>
<ng-template let-col let-node="rowData" pTemplate="body"> <ng-template let-col let-node="rowData" pTemplate="body">
@ -27,7 +35,7 @@
<div class="row"> <div class="row">
<div class="col-sm-2"> <div class="col-sm-2">
<img class="img-responsive poster" src="{{node.data.posterPath}}" alt="poster"> <img class="img-responsive poster" src="{{node.data.posterPath || null}}" alt="poster">
</div> </div>

@ -107,17 +107,22 @@ export class TvRequestsComponent implements OnInit, OnDestroy {
return items; return items;
} }
ngOnInit() { ngOnInit() {
this.amountToLoad = 5; this.amountToLoad = 1000;
this.currentlyLoaded = 5; this.currentlyLoaded = 5;
this.tvRequests = []; this.tvRequests = [];
this.loadInit(); this.loadInit();
} }
public loadMore() { public loadMore() {
this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded + 1) //TODO: I believe this +1 is causing off by one error skipping loading of tv shows
//When removed and scrolling very slowly everything works as expected, however
//if you scroll really quickly then you start getting duplicates of movies
//since it's async and some subsequent results return first and then incrementer
//is increased so you see movies which had already been gotten show up...
this.requestService.getTvRequests(this.amountToLoad, this.currentlyLoaded +1)
.takeUntil(this.subscriptions) .takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.tvRequests.push.apply(this.tvRequests, x); this.tvRequests.push.apply(this.tvRequests, this.transformData(x));
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad; this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
}); });
} }

@ -10,6 +10,8 @@ import { MovieSearchComponent } from './moviesearch.component';
import { TvSearchComponent } from './tvsearch.component'; import { TvSearchComponent } from './tvsearch.component';
import { SeriesInformationComponent } from './seriesinformation.component'; import { SeriesInformationComponent } from './seriesinformation.component';
import { TreeTableModule } from 'primeng/primeng';
import { SearchService } from '../services/search.service'; import { SearchService } from '../services/search.service';
import { RequestService } from '../services/request.service'; import { RequestService } from '../services/request.service';
@ -26,12 +28,13 @@ const routes: Routes = [
FormsModule, FormsModule,
RouterModule.forChild(routes), RouterModule.forChild(routes),
NgbModule.forRoot(), NgbModule.forRoot(),
TreeTableModule
], ],
declarations: [ declarations: [
SearchComponent, SearchComponent,
MovieSearchComponent, MovieSearchComponent,
TvSearchComponent, TvSearchComponent,
SeriesInformationComponent SeriesInformationComponent,
], ],
exports: [ exports: [
RouterModule RouterModule

@ -8,14 +8,8 @@
} }
</style> </style>
<div *ngIf="series"> <div *ngIf="series">
<!--<div class="row"> <button class="btn btn-sm btn-success pull-right" (click)="submitRequests()" title="Go to top">Submit Request</button>
<div class="col-md-6 col-md-push-2">
<div id="bannerimage" style="background-image: url('https://thetvdb.com/banners/graphical/121361-g19.jpg');">
</div>
</div>
</div>-->
<ngb-tabset> <ngb-tabset>
<div *ngFor="let season of series.seasonRequests"> <div *ngFor="let season of series.seasonRequests">
@ -83,9 +77,5 @@
</ngb-tab> </ngb-tab>
</div> </div>
</ngb-tabset> </ngb-tabset>
<button id="requestFloatingBtn" class="btn btn-sm btn-success" (click)="submitRequests()" title="Go to top">Submit Request</button>
</div> </div>

@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy, Input} from '@angular/core';
import { ActivatedRoute } from '@angular/router'; //import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import "rxjs/add/operator/takeUntil"; import "rxjs/add/operator/takeUntil";
@ -13,24 +13,19 @@ import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
import { IEpisodesRequests } from "../interfaces/IRequestModel"; import { IEpisodesRequests } from "../interfaces/IRequestModel";
@Component({ @Component({
selector: 'seriesinformation',
templateUrl: './seriesinformation.component.html', templateUrl: './seriesinformation.component.html',
styleUrls: ['./seriesinformation.component.scss'] styleUrls: ['./seriesinformation.component.scss']
}) })
export class SeriesInformationComponent implements OnInit, OnDestroy { export class SeriesInformationComponent implements OnInit, OnDestroy {
constructor(private searchService: SearchService, private route: ActivatedRoute, constructor(private searchService: SearchService, private requestService: RequestService, private notificationService: NotificationService) {
private requestService: RequestService, private notificationService: NotificationService) {
this.route.params
.takeUntil(this.subscriptions)
.subscribe(params => {
this.seriesId = +params['id']; // (+) converts string 'id' to a number
});
} }
private subscriptions = new Subject<void>(); private subscriptions = new Subject<void>();
public result : IRequestEngineResult; public result : IRequestEngineResult;
private seriesId: number; @Input() private seriesId: number;
public series: ISearchTvResult; public series: ISearchTvResult;
requestedEpisodes: IEpisodesRequests[] = []; requestedEpisodes: IEpisodesRequests[] = [];

@ -32,123 +32,133 @@
<div *ngIf="searchApplied && tvResults?.length <= 0" class='no-search-results'> <div *ngIf="searchApplied && tvResults?.length <= 0" class='no-search-results'>
<i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text'>Sorry, we didn't find any results!</div> <i class='fa fa-film no-search-results-icon'></i><div class='no-search-results-text'>Sorry, we didn't find any results!</div>
</div> </div>
<p-treeTable [value]="tvResults">
<div *ngFor="let result of tvResults"> <p-column>
<div class="row"> <ng-template let-col let-node="rowData" pTemplate="header">
<div class="col-sm-2"> Results
</ng-template>
<img *ngIf="result.banner" class="img-responsive poster" width="150" [src]="result.banner" alt="poster"> <ng-template let-col let-node="rowData" pTemplate="body">
<!--This is the section that holds the parent level search results set-->
</div> <div *ngIf="!node.leaf">
<div class="col-sm-8"> <div class="row">
<div> <div class="col-sm-2">
<a href="http://www.imdb.com/title/{{result.imdbId}}/" target="_blank"> <img *ngIf="node.data.banner" class="img-responsive poster" width="150" [src]="node.data.banner" alt="poster">
<h4>{{result.title}} ({{result.firstAired | date: 'yyyy'}})</h4>
</div>
</a> <div class="col-sm-8">
<div>
<span *ngIf="result.status" class="label label-primary" target="_blank">{{result.status}}</span>
<a href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank">
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
<span *ngIf="result.firstAired" class="label label-info" target="_blank">Air Date: {{result.firstAired}}</span>
</a>
<span *ngIf="node.data.status" class="label label-primary" target="_blank">{{node.data.status}}</span>
<span *ngIf="result.releaseDate" class="label label-info" target="_blank">Release Date: {{result.releaseDate | date: 'dd/MM/yyyy'}}</span>
<span *ngIf="result.available" class="label label-success">Available</span> <span *ngIf="node.data.firstAired" class="label label-info" target="_blank">Air Date: {{node.data.firstAired}}</span>
<span *ngIf="result.approved && !result.available" class="label label-info">Processing Request</span>
<div *ngIf="result.requested && !result.available; then requested else notRequested"></div>
<ng-template #requested> <span *ngIf="node.data.releaseDate" class="label label-info" target="_blank">Release Date: {{node.data.releaseDate | date: 'dd/MM/yyyy'}}</span>
<span *ngIf="!result.available" class="label label-warning">Pending Approval</span>
</ng-template> <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>
<ng-template #notRequested> <div *ngIf="node.data.requested && !node.data.available; then requested else notRequested"></div>
<span *ngIf="!result.available" class="label label-danger">Not Yet Requested</span> <ng-template #requested>
</ng-template> <span *ngIf="!node.data.available" class="label label-warning">Pending Approval</span>
</ng-template>
<span id="{{id}}netflixTab"></span> <ng-template #notRequested>
<span *ngIf="!node.data.available" class="label label-danger">Not Yet Requested</span>
<a *ngIf="result.homepage" href="{{result.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a> </ng-template>
<a *ngIf="result.trailer" href="{{result.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
<span id="{{id}}netflixTab"></span>
<br/> <a *ngIf="node.data.homepage" href="{{node.data.homepage}}" target="_blank"><span class="label label-info">HomePage</span></a>
<br/>
<a *ngIf="node.data.trailer" href="{{node.data.trailer}}" target="_blank"><span class="label label-info">Trailer</span></a>
<br />
<br />
</div>
<p style="font-size: 0.9rem !important">{{node.data.overview}}</p>
</div>
<div class="col-sm-2">
<input name="{{type}}Id" type="text" value="{{node.data.id}}" hidden="hidden" />
<!--<div *ngIf="node.data.requested; then requestedBtn else notRequestedBtn"></div>
<template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
</template>
<template #notRequestedBtn>
<button id="{{node.data.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
</template>-->
<!--{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}}
@*//TODO Not used yet*@
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br/>
{{else}}
{{#if_eq enableTvRequestsForOnlySeries true}}
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button>
{{else}}
-->
<div class="dropdown">
<button class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Request
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a (click)="allSeasons(node.data)">All Seasons</a></li>
<li><a (click)="firstSeason(node.data)">First Season</a></li>
<li><a (click)="latestSeason(node.data)">Latest Season</a></li>
<li><a (click)="openClosestTab($event)">Select ...</a></li>
</ul>
</div>
<!--
<br/>
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
-->
<br />
<div *ngIf="node.data.available">
<a *ngIf="node.data.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
<div class="dropdown">
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-exclamation"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a issue-select="0" class="dropdownIssue" href="#">WrongAudio</a></li>
<li><a issue-select="1" class="dropdownIssue" href="#">NoSubs</a></li>
<li><a issue-select="2" class="dropdownIssue" href="#">WrongContent</a></li>
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
</ul>
</div>-->
</div>
</div>
</div>
<hr />
</div> </div>
<p style="font-size: 0.9rem !important">{{result.overview}}</p> <!--This is the section that holds the child seasons if they want to specify specific episodes-->
</div> <div *ngIf="node.leaf">
<seriesinformation [seriesId]="node.data.id"></seriesinformation>
<div class="col-sm-2">
<input name="{{type}}Id" type="text" value="{{result.id}}" hidden="hidden"/>
<!--<div *ngIf="result.requested; then requestedBtn else notRequestedBtn"></div>
<template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> Requested</button>
</template>
<template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)"><i class="fa fa-plus"></i> Request</button>
</template>-->
<!--{{#if_eq type "tv"}}
{{#if_eq tvFullyAvailable true}}
@*//TODO Not used yet*@
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> @UI.Search_Available</button><br/>
{{else}}
{{#if_eq enableTvRequestsForOnlySeries true}}
<button id="{{id}}" style="text-align: right" class="btn {{#if available}}btn-success-outline{{else}}btn-primary-outline dropdownTv{{/if}} btn-primary-outline" season-select="0" type="button" {{#if available}} disabled{{/if}}><i class="fa fa-plus"></i> {{#if available}}@UI.Search_Available{{else}}@UI.Search_Request{{/if}}</button>
{{else}}
-->
<div class="dropdown">
<button class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Request
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a (click)="allSeasons(result)">All Seasons</a></li>
<li><a (click)="firstSeason(result)">First Season</a></li>
<li><a (click)="latestSeason(result)">Latest Season</a></li>
<li><a (click)="selectSeason(result)">Select ...</a></li>
</ul>
</div> </div>
</ng-template>
<!-- </p-column>
<br/> </p-treeTable>
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{url}}" target="_blank"><i class="fa fa-eye"></i> @UI.Search_ViewInPlex</a>
-->
<br/>
<div *ngIf="result.available">
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> View On Plex</a>
<!--<input name="providerId" type="text" value="{{id}}" hidden="hidden"/>
<input name="type" type="text" value="{{type}}" hidden="hidden"/>
<div class="dropdown">
<button class="btn btn-sm btn-danger-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-exclamation"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li><a issue-select="0" class="dropdownIssue" href="#">WrongAudio</a></li>
<li><a issue-select="1" class="dropdownIssue" href="#">NoSubs</a></li>
<li><a issue-select="2" class="dropdownIssue" href="#">WrongContent</a></li>
<li><a issue-select="3" class="dropdownIssue" href="#">Playback</a></li>
<li><a issue-select="4" class="dropdownIssue" href="#" data-toggle="modal" data-target="#issuesModal">Other</a></li>
</ul>
</div>-->
</div>
</div>
</div>
<hr/>
</div>
</div> </div>
</div> </div>

@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import { Subject } from 'rxjs/Subject'; import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/debounceTime';
@ -12,10 +12,16 @@ import { NotificationService } from '../services/notification.service';
import { ISearchTvResult } from '../interfaces/ISearchTvResult'; import { ISearchTvResult } from '../interfaces/ISearchTvResult';
import { IRequestEngineResult } from '../interfaces/IRequestEngineResult'; import { IRequestEngineResult } from '../interfaces/IRequestEngineResult';
import { TreeNode } from "primeng/primeng";
@Component({ @Component({
selector: 'tv-search', selector: 'tv-search',
templateUrl: './tvsearch.component.html', templateUrl: './tvsearch.component.html',
styleUrls: ['./../requests/tvrequests.component.scss'],
//Was required to turn off encapsulation since CSS only should be overridden for this component
//However when encapsulation is on angular injects prefixes to all classes so css selectors
//Stop working
encapsulation: ViewEncapsulation.None
}) })
export class TvSearchComponent implements OnInit, OnDestroy { export class TvSearchComponent implements OnInit, OnDestroy {
@ -41,11 +47,50 @@ export class TvSearchComponent implements OnInit, OnDestroy {
this.searchService.searchTv(this.searchText) this.searchService.searchTv(this.searchText)
.takeUntil(this.subscriptions) .takeUntil(this.subscriptions)
.subscribe(x => { .subscribe(x => {
this.tvResults = x; this.tvResults = this.transformData(x);
this.searchApplied = true; this.searchApplied = true;
}); });
}); });
} }
openClosestTab(el: any): void {
var rowclass = "undefined";
el = el.toElement;
while (el.className != rowclass) {
// Increment the loop to the parent node until we find the row we need
el = el.parentNode;
if (!el) {
}
}
// At this point, the while loop has stopped and `el` represents the element that has
// 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-c fa-caret-right";
var caretdown = "ui-treetable-toggler fa fa-fw ui-c fa-caret-down";
for (var 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) {
// Then we tell JS to click the element even though we hid it from the UI
value.click();
//Break from loop since we no longer need to continue looking
break;
}
};
}
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 { ngOnInit(): void {
this.searchText = ""; this.searchText = "";

Loading…
Cancel
Save