mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 21:33:15 -07:00
perf(discover): ⚡ Improve the loading performance on the discover page
This commit is contained in:
parent
cfeee39978
commit
97d5167db6
7 changed files with 189 additions and 62 deletions
|
@ -5,13 +5,17 @@
|
||||||
<mat-button-toggle id="{{id}}Tv" [ngClass]="{'button-active': discoverOptions === DiscoverOption.Tv}" value="{{DiscoverOption.Tv}}" class="discover-filter-button">{{'Discovery.Tv' | translate}}</mat-button-toggle>
|
<mat-button-toggle id="{{id}}Tv" [ngClass]="{'button-active': discoverOptions === DiscoverOption.Tv}" value="{{DiscoverOption.Tv}}" class="discover-filter-button">{{'Discovery.Tv' | translate}}</mat-button-toggle>
|
||||||
</mat-button-toggle-group>
|
</mat-button-toggle-group>
|
||||||
</div>
|
</div>
|
||||||
@defer (when discoverResults.length > 0) {
|
@defer (when discoverResults.length > 0; prefetch on idle) {
|
||||||
<p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="discoverResults" [responsiveOptions]="responsiveOptions" (onPage)="newPage()">
|
<p-carousel #carousel [numVisible]="10" [numScroll]="10" [page]="0" [value]="discoverResults" [responsiveOptions]="responsiveOptions" (onPage)="newPage()">
|
||||||
<ng-template let-result pTemplate="item">
|
<ng-template let-result pTemplate="item">
|
||||||
<discover-card [discoverType]="discoverType" [isAdmin]="isAdmin" [result]="result" [is4kEnabled]="is4kEnabled"></discover-card>
|
<discover-card [discoverType]="discoverType" [isAdmin]="isAdmin" [result]="result" [is4kEnabled]="is4kEnabled"></discover-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-carousel>
|
</p-carousel>
|
||||||
}
|
}
|
||||||
@placeholder(minimum 500) {
|
@placeholder(minimum 300) {
|
||||||
<p-skeleton width="100%" height="18rem"></p-skeleton>
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
|
@ -105,6 +105,30 @@
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container .col-2 {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: calc(10% - 9px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(50% - 5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(100% - 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width:755px){
|
@media (min-width:755px){
|
||||||
::ng-deep .p-carousel-item{
|
::ng-deep .p-carousel-item{
|
||||||
flex: 1 0 200px !important;
|
flex: 1 0 200px !important;
|
||||||
|
|
|
@ -43,7 +43,7 @@ export class CarouselListComponent implements OnInit {
|
||||||
get mediaTypeStorageKey() {
|
get mediaTypeStorageKey() {
|
||||||
return "DiscoverOptions" + this.discoverType.toString();
|
return "DiscoverOptions" + this.discoverType.toString();
|
||||||
};
|
};
|
||||||
private amountToLoad = 17;
|
private amountToLoad = 10;
|
||||||
private currentlyLoaded = 0;
|
private currentlyLoaded = 0;
|
||||||
private baseUrl: string = "";
|
private baseUrl: string = "";
|
||||||
|
|
||||||
|
@ -148,6 +148,7 @@ export class CarouselListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ngOnInit() {
|
public async ngOnInit() {
|
||||||
|
|
||||||
this.is4kEnabled = this.featureFacade.is4kEnabled();
|
this.is4kEnabled = this.featureFacade.is4kEnabled();
|
||||||
this.currentlyLoaded = 0;
|
this.currentlyLoaded = 0;
|
||||||
const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey);
|
const localDiscoverOptions = +this.storageService.get(this.mediaTypeStorageKey);
|
||||||
|
@ -155,11 +156,15 @@ export class CarouselListComponent implements OnInit {
|
||||||
this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]];
|
this.discoverOptions = DiscoverOption[DiscoverOption[localDiscoverOptions]];
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentIteration = 0;
|
// Load initial data - just enough to fill the first carousel page
|
||||||
while (this.discoverResults.length <= 14 && currentIteration <= 3) {
|
// This reduces initial API calls and improves loading performance
|
||||||
currentIteration++;
|
await this.loadData(false);
|
||||||
|
|
||||||
|
// If we don't have enough results to fill the carousel, load one more batch
|
||||||
|
if (this.discoverResults.length < 10) {
|
||||||
await this.loadData(false);
|
await this.loadData(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toggleChanged(event: MatButtonToggleChange) {
|
public async toggleChanged(event: MatButtonToggleChange) {
|
||||||
|
|
|
@ -1,46 +1,108 @@
|
||||||
<div class="small-middle-container">
|
<div class="small-middle-container">
|
||||||
<div class="section">
|
@defer (on viewport; prefetch on idle) {
|
||||||
<h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2>
|
<div class="section">
|
||||||
<genre-button-select class="collapse show" id="genreCollapse"></genre-button-select>
|
<h2 id="genreHeading" data-toggle="collapse" href="#genreCollapse" role="button">{{ 'Discovery.Genres' | translate }}</h2>
|
||||||
</div>
|
<genre-button-select class="collapse show" id="genreCollapse"></genre-button-select>
|
||||||
<div class="section">
|
|
||||||
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
|
|
||||||
<div>
|
|
||||||
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.Genres' | translate }}</h2>
|
||||||
<div class="section" [hidden]="!showSeasonal">
|
<p-skeleton width="100%" height="60px"></p-skeleton>
|
||||||
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
|
|
||||||
<div>
|
|
||||||
<carousel-list
|
|
||||||
[id]="'seasonal'"
|
|
||||||
[isAdmin]="isAdmin"
|
|
||||||
[discoverType]="DiscoverType.Seasonal"
|
|
||||||
(movieCount)="setSeasonalMovieCount($event)"
|
|
||||||
></carousel-list>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
<div class="section">
|
@defer (on viewport; prefetch on idle) {
|
||||||
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
|
<div class="section">
|
||||||
<div>
|
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
|
||||||
<carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
|
<div>
|
||||||
|
<ombi-recently-list [id]="'recentlyRequested'"></ombi-recently-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.RecentlyRequestedTab' | translate }}</h2>
|
||||||
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="section">
|
@defer (on viewport; prefetch on idle) {
|
||||||
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
|
<div class="section" [hidden]="!showSeasonal">
|
||||||
<div>
|
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
|
||||||
<carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
|
<div>
|
||||||
|
<carousel-list
|
||||||
|
[id]="'seasonal'"
|
||||||
|
[isAdmin]="isAdmin"
|
||||||
|
[discoverType]="DiscoverType.Seasonal"
|
||||||
|
(movieCount)="setSeasonalMovieCount($event)"
|
||||||
|
></carousel-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.SeasonalTab' | translate }}</h2>
|
||||||
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="section">
|
@defer (on viewport; prefetch on idle) {
|
||||||
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
|
<div class="section">
|
||||||
<div>
|
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
|
||||||
<carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
|
<div>
|
||||||
|
<carousel-list [id]="'popular'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Popular"></carousel-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.PopularTab' | translate }}</h2>
|
||||||
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@defer (on viewport; prefetch on idle) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
|
||||||
|
<div>
|
||||||
|
<carousel-list [id]="'trending'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Trending"></carousel-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.TrendingTab' | translate }}</h2>
|
||||||
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@defer (on viewport; prefetch on idle) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
|
||||||
|
<div>
|
||||||
|
<carousel-list [id]="'upcoming'" [isAdmin]="isAdmin" [discoverType]="DiscoverType.Upcoming"></carousel-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} @placeholder(minimum 300) {
|
||||||
|
<div class="section">
|
||||||
|
<h2>{{ 'Discovery.UpcomingTab' | translate }}</h2>
|
||||||
|
<div class="row loading-container">
|
||||||
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||||
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,3 +10,27 @@ h2{
|
||||||
margin-left:40px;
|
margin-left:40px;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container .col-2 {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: calc(10% - 9px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(50% - 5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(100% - 0px);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
@defer (when requests()) {
|
@defer (when requests(); prefetch on idle) {
|
||||||
<div *ngIf="requests().length > 0">
|
<div *ngIf="requests().length > 0">
|
||||||
<p-carousel #carousel [value]="requests()" [numVisible]="3" [numScroll]="1"
|
<p-carousel #carousel [value]="requests()" [numVisible]="3" [numScroll]="1"
|
||||||
[responsiveOptions]="responsiveOptions" [page]="0">
|
[responsiveOptions]="responsiveOptions" [page]="0">
|
||||||
|
@ -13,21 +13,9 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-carousel>
|
</p-carousel>
|
||||||
</div>
|
</div>
|
||||||
}@placeholder(minimum 500) {
|
}@placeholder(minimum 300) {
|
||||||
<div class="row loading-container">
|
<div class="row loading-container">
|
||||||
<div class="col-2">
|
<div class="col-2" *ngFor="let item of [1,2,3,4,5]">
|
||||||
<p-skeleton width="100%" height="270px"></p-skeleton>
|
|
||||||
</div>
|
|
||||||
<div class="col-2">
|
|
||||||
<p-skeleton width="100%" height="270px"></p-skeleton>
|
|
||||||
</div>
|
|
||||||
<div class="col-2">
|
|
||||||
<p-skeleton width="100%" height="270px"></p-skeleton>
|
|
||||||
</div>
|
|
||||||
<div class="col-2">
|
|
||||||
<p-skeleton width="100%" height="270px"></p-skeleton>
|
|
||||||
</div>
|
|
||||||
<div class="col-2">
|
|
||||||
<p-skeleton width="100%" height="270px"></p-skeleton>
|
<p-skeleton width="100%" height="270px"></p-skeleton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -105,12 +105,32 @@
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container .col-2 {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: calc(20% - 8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(50% - 5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.loading-container .col-2 {
|
||||||
|
width: calc(100% - 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width:755px){
|
@media (min-width:755px){
|
||||||
::ng-deep .p-carousel-item{
|
::ng-deep .p-carousel-item{
|
||||||
flex: 1 0 200px !important;
|
flex: 1 0 200px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-container {
|
|
||||||
margin-left: 10rem;
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue