mirror of https://github.com/Ombi-app/Ombi
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
12 KiB
357 lines
12 KiB
import { Component, OnInit, Input, ViewChild, Output, EventEmitter } from "@angular/core";
|
|
import { DiscoverOption, IDiscoverCardResult } from "../../interfaces";
|
|
import { ISearchMovieResult, ISearchTvResult, RequestType } from "../../../interfaces";
|
|
import { SearchV2Service } from "../../../services";
|
|
import { StorageService } from "../../../shared/storage/storage-service";
|
|
import { MatButtonToggleChange } from '@angular/material/button-toggle';
|
|
import { Carousel } from 'primeng/carousel';
|
|
import { FeaturesFacade } from "../../../state/features/features.facade";
|
|
|
|
export enum DiscoverType {
|
|
Upcoming,
|
|
Trending,
|
|
Popular,
|
|
RecentlyRequested,
|
|
Seasonal,
|
|
}
|
|
|
|
@Component({
|
|
selector: "carousel-list",
|
|
templateUrl: "./carousel-list.component.html",
|
|
styleUrls: ["./carousel-list.component.scss"],
|
|
})
|
|
export class CarouselListComponent implements OnInit {
|
|
|
|
@Input() public discoverType: DiscoverType;
|
|
@Input() public id: string;
|
|
@Input() public isAdmin: boolean;
|
|
@Output() public movieCount: EventEmitter<number> = new EventEmitter();
|
|
@ViewChild('carousel', {static: false}) carousel: Carousel;
|
|
|
|
public DiscoverOption = DiscoverOption;
|
|
public discoverOptions: DiscoverOption = DiscoverOption.Combined;
|
|
public discoverResults: IDiscoverCardResult[] = [];
|
|
public movies: ISearchMovieResult[] = [];
|
|
public tvShows: ISearchTvResult[] = [];
|
|
public responsiveOptions: any;
|
|
public RequestType = RequestType;
|
|
public loadingFlag: boolean;
|
|
public DiscoverType = DiscoverType;
|
|
public is4kEnabled = false;
|
|
|
|
get mediaTypeStorageKey() {
|
|
return "DiscoverOptions" + this.discoverType.toString();
|
|
};
|
|
private amountToLoad = 17;
|
|
private currentlyLoaded = 0;
|
|
|
|
constructor(private searchService: SearchV2Service,
|
|
private storageService: StorageService,
|
|
private featureFacade: FeaturesFacade) {
|
|
this.responsiveOptions = [
|
|
{
|
|
breakpoint: '4000px',
|
|
numVisible: 17,
|
|
numScroll: 16
|
|
},
|
|
{
|
|
breakpoint: '3800px',
|
|
numVisible: 16,
|
|
numScroll: 15
|
|
},
|
|
{
|
|
breakpoint: '3600px',
|
|
numVisible: 15,
|
|
numScroll: 14
|
|
},
|
|
{
|
|
breakpoint: '3400px',
|
|
numVisible: 14,
|
|
numScroll: 13
|
|
},
|
|
{
|
|
breakpoint: '3200px',
|
|
numVisible: 13,
|
|
numScroll: 12
|
|
},
|
|
{
|
|
breakpoint: '3000px',
|
|
numVisible: 12,
|
|
numScroll: 11
|
|
},
|
|
{
|
|
breakpoint: '2800px',
|
|
numVisible: 11,
|
|
numScroll: 10
|
|
},
|
|
{
|
|
breakpoint: '2600px',
|
|
numVisible: 10,
|
|
numScroll: 9
|
|
},
|
|
{
|
|
breakpoint: '2400px',
|
|
numVisible: 9,
|
|
numScroll: 8
|
|
},
|
|
{
|
|
breakpoint: '2200px',
|
|
numVisible: 8,
|
|
numScroll: 7
|
|
},
|
|
{
|
|
breakpoint: '2000px',
|
|
numVisible: 7,
|
|
numScroll: 6
|
|
},
|
|
{
|
|
breakpoint: '1800px',
|
|
numVisible: 6,
|
|
numScroll: 5
|
|
},
|
|
{
|
|
breakpoint: '1650px',
|
|
numVisible: 5,
|
|
numScroll: 4
|
|
},
|
|
{
|
|
breakpoint: '1500px',
|
|
numVisible: 4,
|
|
numScroll: 3
|
|
},
|
|
{
|
|
breakpoint: '768px',
|
|
numVisible: 3,
|
|
numScroll: 2
|
|
},
|
|
{
|
|
breakpoint: '660px',
|
|
numVisible: 2,
|
|
numScroll: 2
|
|
},
|
|
{
|
|
breakpoint: '480px',
|
|
numVisible: 1,
|
|
numScroll: 1
|
|
}
|
|
];
|
|
}
|
|
|
|
public async ngOnInit() {
|
|
this.is4kEnabled = this.featureFacade.is4kEnabled();
|
|
this.currentlyLoaded = 0;
|
|
const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey);
|
|
if (localDiscoverOptions) {
|
|
this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]];
|
|
}
|
|
|
|
let currentIteration = 0;
|
|
while (this.discoverResults.length <= 14 && currentIteration <= 3) {
|
|
currentIteration++;
|
|
await this.loadData(false);
|
|
}
|
|
}
|
|
|
|
public async toggleChanged(event: MatButtonToggleChange) {
|
|
await this.switchDiscoverMode(event.value);
|
|
}
|
|
|
|
public async newPage() {
|
|
// Note this is using the internal carousel APIs
|
|
// https://github.com/primefaces/primeng/blob/master/src/app/components/carousel/carousel.ts
|
|
if (!this.carousel?.page) {
|
|
return;
|
|
}
|
|
|
|
var end = this.carousel.page >= (this.carousel.totalDots() - 2) || this.carousel.totalDots() === 1;
|
|
if (end) {
|
|
var moviePromise: Promise<void>;
|
|
var tvPromise: Promise<void>;
|
|
switch (+this.discoverOptions) {
|
|
case DiscoverOption.Combined:
|
|
moviePromise = this.loadMovies();
|
|
tvPromise = this.loadTv();
|
|
break;
|
|
case DiscoverOption.Movie:
|
|
moviePromise = this.loadMovies();
|
|
break;
|
|
case DiscoverOption.Tv:
|
|
tvPromise = this.loadTv();
|
|
break;
|
|
}
|
|
await moviePromise;
|
|
await tvPromise;
|
|
|
|
this.createModel();
|
|
}
|
|
}
|
|
|
|
private async loadData(clearExisting: boolean = true) {
|
|
var moviePromise: Promise<void>;
|
|
var tvPromise: Promise<void>;
|
|
switch (+this.discoverOptions) {
|
|
case DiscoverOption.Combined:
|
|
moviePromise = this.loadMovies();
|
|
tvPromise = this.loadTv();
|
|
break;
|
|
case DiscoverOption.Movie:
|
|
moviePromise = this.loadMovies();
|
|
break;
|
|
case DiscoverOption.Tv:
|
|
tvPromise = this.loadTv();
|
|
break;
|
|
}
|
|
await moviePromise;
|
|
await tvPromise;
|
|
this.createInitialModel(clearExisting);
|
|
}
|
|
|
|
private async switchDiscoverMode(newMode: DiscoverOption) {
|
|
if (this.discoverOptions === newMode) {
|
|
return;
|
|
}
|
|
this.loading();
|
|
this.currentlyLoaded = 0;
|
|
this.discoverOptions = +newMode;
|
|
this.storageService.save(this.mediaTypeStorageKey, newMode.toString());
|
|
await this.loadData();
|
|
this.finishLoading();
|
|
}
|
|
|
|
private async loadMovies() {
|
|
switch (this.discoverType) {
|
|
case DiscoverType.Popular:
|
|
this.movies = await this.searchService.popularMoviesByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
case DiscoverType.Trending:
|
|
this.movies = await this.searchService.nowPlayingMoviesByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
case DiscoverType.Upcoming:
|
|
this.movies = await this.searchService.upcomingMoviesByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break
|
|
case DiscoverType.RecentlyRequested:
|
|
this.movies = await this.searchService.recentlyRequestedMoviesByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
case DiscoverType.Seasonal:
|
|
this.movies = await this.searchService.seasonalMoviesByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
}
|
|
this.movieCount.emit(this.movies.length);
|
|
this.currentlyLoaded += this.amountToLoad;
|
|
}
|
|
|
|
private async loadTv() {
|
|
switch (this.discoverType) {
|
|
case DiscoverType.Popular:
|
|
this.tvShows = await this.searchService.popularTvByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
case DiscoverType.Trending:
|
|
this.tvShows = await this.searchService.trendingTvByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break;
|
|
case DiscoverType.Upcoming:
|
|
this.tvShows = await this.searchService.anticipatedTvByPage(this.currentlyLoaded, this.amountToLoad);
|
|
break
|
|
case DiscoverType.RecentlyRequested:
|
|
// this.tvShows = await this.searchService.recentlyRequestedMoviesByPage(this.currentlyLoaded, this.amountToLoad); // TODO need to do some more mapping
|
|
break;
|
|
}
|
|
this.currentlyLoaded += this.amountToLoad;
|
|
}
|
|
|
|
private createInitialModel(clearExisting: boolean = true) {
|
|
if (clearExisting) {
|
|
this.clear();
|
|
}
|
|
this.createModel();
|
|
}
|
|
|
|
private createModel() {
|
|
const tempResults = <IDiscoverCardResult[]>[];
|
|
|
|
switch (+this.discoverOptions) {
|
|
case DiscoverOption.Combined:
|
|
tempResults.push(...this.mapMovieModel());
|
|
tempResults.push(...this.mapTvModel());
|
|
this.shuffle(tempResults);
|
|
break;
|
|
case DiscoverOption.Movie:
|
|
tempResults.push(...this.mapMovieModel());
|
|
break;
|
|
case DiscoverOption.Tv:
|
|
tempResults.push(...this.mapTvModel());
|
|
break;
|
|
}
|
|
|
|
this.discoverResults.push(...tempResults);
|
|
this.carousel.ngAfterContentInit();
|
|
|
|
this.finishLoading();
|
|
}
|
|
|
|
private mapMovieModel(): IDiscoverCardResult[] {
|
|
const tempResults = <IDiscoverCardResult[]>[];
|
|
this.movies.forEach(m => {
|
|
tempResults.push({
|
|
available: m.available,
|
|
posterPath: m.posterPath ? `https://image.tmdb.org/t/p/w500/${m.posterPath}` : "../../../images/default_movie_poster.png",
|
|
requested: m.requested,
|
|
title: m.title,
|
|
type: RequestType.movie,
|
|
id: m.id,
|
|
url: `http://www.imdb.com/title/${m.imdbId}/`,
|
|
rating: m.voteAverage,
|
|
overview: m.overview,
|
|
approved: m.approved,
|
|
imdbid: m.imdbId,
|
|
denied: false,
|
|
background: m.backdropPath
|
|
});
|
|
});
|
|
return tempResults;
|
|
}
|
|
|
|
private mapTvModel(): IDiscoverCardResult[] {
|
|
const tempResults = <IDiscoverCardResult[]>[];
|
|
this.tvShows.forEach(m => {
|
|
tempResults.push({
|
|
available: m.fullyAvailable,
|
|
posterPath: m.backdropPath ? `https://image.tmdb.org/t/p/w500/${m.backdropPath}` : "../../../images/default_tv_poster.png",
|
|
requested: m.requested,
|
|
title: m.title,
|
|
type: RequestType.tvShow,
|
|
id: m.id,
|
|
url: undefined,
|
|
rating: +m.rating,
|
|
overview: m.overview,
|
|
approved: m.approved || m.partlyAvailable,
|
|
imdbid: m.imdbId,
|
|
denied: false,
|
|
background: m.background
|
|
});
|
|
});
|
|
return tempResults;
|
|
}
|
|
|
|
private clear() {
|
|
this.discoverResults = [];
|
|
}
|
|
|
|
private shuffle(discover: IDiscoverCardResult[]): IDiscoverCardResult[] {
|
|
for (let i = discover.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[discover[i], discover[j]] = [discover[j], discover[i]];
|
|
}
|
|
return discover;
|
|
}
|
|
|
|
private loading() {
|
|
this.loadingFlag = true;
|
|
}
|
|
|
|
private finishLoading() {
|
|
this.loadingFlag = false;
|
|
}
|
|
|
|
|
|
}
|