import { Component, Input, computed } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterLink } from '@angular/router'; import { PROVIDERS, PROVIDER_MAP, type ProviderId } from '../../app/core/providers/provider-registry'; import type { SuggestionItem } from '../../app/search/search.service'; import { ChannelIdentityComponent } from '../../app/shared/components/channel-identity/channel-identity.component'; interface SuggestionSection { id: ProviderId; name: string; shortLabel: string; colorClass: string; items: SuggestionItem[]; supported: boolean; deepLinkProviders: string; } @Component({ selector: 'app-search-suggestions', standalone: true, imports: [CommonModule, RouterLink, ChannelIdentityComponent], templateUrl: './search-suggestions.component.html' }) export class SearchSuggestionsComponent { @Input() groups: Record = { yt: [], dm: [], tw: [], pt: [], od: [], ru: [] } as any; @Input() query: string = ''; // Providers that were actually requested; drives which sections render and // which unsupported providers get an explicit row (Step 6) @Input() activeProviders: ProviderId[] | 'all' = 'all'; readonly sections = computed(() => { const groups = this.groups || ({} as Record); const active = this.activeProviders === 'all' ? PROVIDERS.map(p => p.id) : (this.activeProviders || []).filter(id => PROVIDER_MAP.has(id)); return active.map(id => { const spec = PROVIDER_MAP.get(id)!; return { id, name: spec.displayName, shortLabel: spec.shortLabel, colorClass: spec.colorClass, items: Array.isArray(groups[id]) ? groups[id] : [], supported: !!spec.supports?.search, deepLinkProviders: id, } as SuggestionSection; }); }); /** ExternalId chaîne pour le lien /channel (null = non cliquable). */ channelExternalId(section: { id: ProviderId }, item: SuggestionItem): string | null { const raw = item as unknown as Record; if (section.id === 'pt') { // PeerTube : `instance|channel`, instance dérivée de l'URL vidéo. try { const url = String(raw?.['url'] || ''); const host = url ? new URL(url).hostname : ''; const channel = String(raw?.['channelId'] || ''); if (host && channel) return `${host}|${channel}`; } catch {} return null; } if (section.id === 'od') { const name = String(raw?.['uploaderName'] || ''); return name || null; } const ext = String(raw?.['channelExternalId'] || raw?.['channelId'] || ''); return ext || null; } channelAvatar(item: SuggestionItem): string | null { const raw = item as unknown as Record; return String(raw?.['uploaderAvatar'] || '') || null; } }