first commit
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
|
||||
import { ChangeDetectionStrategy, Component, effect, inject, signal, untracked } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { YoutubeApiService } from '../../services/youtube-api.service';
|
||||
import { Video } from '../../models/video.model';
|
||||
import { InstanceService } from '../../services/instance.service';
|
||||
import { InfiniteAnchorComponent } from '../shared/infinite-anchor/infinite-anchor.component';
|
||||
import { formatRelativeFr } from '../../utils/date.util';
|
||||
import { TranslatePipe } from '../../pipes/translate.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, RouterLink, InfiniteAnchorComponent, TranslatePipe]
|
||||
})
|
||||
export class HomeComponent {
|
||||
private apiService = inject(YoutubeApiService);
|
||||
private instances = inject(InstanceService);
|
||||
|
||||
trendingVideos = signal<Video[]>([]);
|
||||
loading = signal(true);
|
||||
busyMore = signal(false);
|
||||
nextCursor = signal<string | null>(null);
|
||||
notice = signal<string | null>(null);
|
||||
|
||||
constructor() {
|
||||
this.reloadTrending();
|
||||
// React to provider/region changes to refresh trending automatically
|
||||
effect(() => {
|
||||
// Rerun when these signals change
|
||||
const provider = this.instances.selectedProvider();
|
||||
const region = this.instances.region();
|
||||
const ptInstance = this.instances.activePeerTubeInstance();
|
||||
|
||||
// Reset notice and trigger reload, but without re-triggering the effect
|
||||
untracked(() => {
|
||||
this.notice.set(null);
|
||||
this.reloadTrending();
|
||||
});
|
||||
}, { allowSignalWrites: true });
|
||||
}
|
||||
|
||||
reloadTrending() {
|
||||
const readiness = this.instances.getProviderReadiness();
|
||||
if (!readiness.ready) {
|
||||
this.notice.set(readiness.reason || 'Le provider sélectionné n\'est pas prêt.');
|
||||
this.trendingVideos.set([]);
|
||||
this.nextCursor.set(null);
|
||||
this.loading.set(false);
|
||||
return;
|
||||
}
|
||||
this.loading.set(true);
|
||||
this.trendingVideos.set([]);
|
||||
this.nextCursor.set(null);
|
||||
// Important: reset busy flag so a previous pending state doesn't block new loads
|
||||
this.busyMore.set(false);
|
||||
this.fetchNextPage();
|
||||
}
|
||||
|
||||
fetchNextPage() {
|
||||
if (this.busyMore()) return;
|
||||
const readiness = this.instances.getProviderReadiness();
|
||||
if (!readiness.ready) {
|
||||
if (!this.notice()) this.notice.set(readiness.reason || 'Le provider sélectionné n\'est pas prêt.');
|
||||
return;
|
||||
}
|
||||
this.busyMore.set(true);
|
||||
this.apiService.getTrendingPage(this.nextCursor()).subscribe(res => {
|
||||
const merged = [...this.trendingVideos(), ...res.items];
|
||||
this.trendingVideos.set(merged);
|
||||
this.nextCursor.set(res.nextCursor || null);
|
||||
this.busyMore.set(false);
|
||||
this.loading.set(false);
|
||||
const provider = this.instances.selectedProvider();
|
||||
if (merged.length === 0 && !this.notice()) {
|
||||
const readiness2 = this.instances.getProviderReadiness();
|
||||
if (!readiness2.ready) {
|
||||
this.notice.set(readiness2.reason || 'Le provider sélectionné n\'est pas prêt.');
|
||||
} else if (provider === 'youtube') {
|
||||
this.notice.set('Aucune vidéo tendance YouTube chargée. Vérifiez que votre YOUTUBE_API_KEY est valide et que les restrictions HTTP referrer incluent http://localhost:4200/*.');
|
||||
} else if (provider === 'peertube') {
|
||||
const inst = this.instances.activePeerTubeInstance();
|
||||
this.notice.set(`PeerTube: les vidéos ne sont pas disponibles depuis l'instance "${inst}" pour le moment. Essayez une autre instance dans l'en-tête.`);
|
||||
} else if (provider === 'rumble') {
|
||||
const label = this.instances.selectedProviderLabel();
|
||||
this.notice.set(`Les vidéos ne sont pas disponibles pour le provider "${label}" pour le moment. Réessayez plus tard ou choisissez un autre provider.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
formatViews(views: number): string {
|
||||
if (views >= 1_000_000_000) {
|
||||
return (views / 1_000_000_000).toFixed(1) + 'B';
|
||||
}
|
||||
if (views >= 1_000_000) {
|
||||
return (views / 1_000_000).toFixed(1) + 'M';
|
||||
}
|
||||
if (views >= 1_000) {
|
||||
return (views / 1_000).toFixed(1) + 'K';
|
||||
}
|
||||
return views.toString();
|
||||
}
|
||||
|
||||
// Relative date for cards (e.g., "il y a 2 heures")
|
||||
formatRelative(dateIso?: string): string {
|
||||
if (!dateIso) return '';
|
||||
return formatRelativeFr(dateIso);
|
||||
}
|
||||
|
||||
// Build query params for Watch page (provider + optional odysee slug)
|
||||
watchQueryParams(v: Video): Record<string, any> | null {
|
||||
const p = this.instances.selectedProvider();
|
||||
const qp: any = { p };
|
||||
if (p === 'odysee' && v.url?.startsWith('https://odysee.com/')) {
|
||||
let slug = v.url.substring('https://odysee.com/'.length);
|
||||
if (slug.startsWith('/')) slug = slug.slice(1);
|
||||
qp.slug = slug;
|
||||
}
|
||||
return qp;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user