chore: update Angular cache and TypeScript build info files
This commit is contained in:
@@ -11,13 +11,16 @@ import { Title } from '@angular/platform-browser';
|
||||
import { TranslatePipe } from '../../pipes/translate.pipe';
|
||||
import { LikeButtonComponent } from '../shared/components/like-button/like-button.component';
|
||||
import { AddToPlaylistComponent } from '../shared/components/add-to-playlist/add-to-playlist.component';
|
||||
import { SearchSuggestionsComponent } from './search-suggestions.component';
|
||||
import { SearchService, type SearchResponse } from '../../app/search/search.service';
|
||||
import type { ProviderId } from '../../app/core/providers/provider-registry';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
standalone: true,
|
||||
templateUrl: './search.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, RouterLink, InfiniteAnchorComponent, TranslatePipe, LikeButtonComponent, AddToPlaylistComponent]
|
||||
imports: [CommonModule, RouterLink, InfiniteAnchorComponent, TranslatePipe, LikeButtonComponent, AddToPlaylistComponent, SearchSuggestionsComponent]
|
||||
})
|
||||
export class SearchComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
@@ -25,6 +28,7 @@ export class SearchComponent {
|
||||
private instances = inject(InstanceService);
|
||||
private history = inject(HistoryService);
|
||||
private title = inject(Title);
|
||||
private unified = inject(SearchService);
|
||||
|
||||
q = signal<string>('');
|
||||
loading = signal<boolean>(false);
|
||||
@@ -41,6 +45,11 @@ export class SearchComponent {
|
||||
notice = signal<string | null>(null);
|
||||
providerParam = signal<Provider | null>(null);
|
||||
themeParam = signal<string | null>(null);
|
||||
providersListParam = signal<ProviderId[] | 'all' | null>(null);
|
||||
|
||||
// Unified multi-provider response (grouped suggestions)
|
||||
groups = signal<Record<ProviderId, any[]>>({} as any);
|
||||
showUnified = signal<boolean>(false);
|
||||
|
||||
hasQuery = computed(() => this.q().length > 0);
|
||||
providerLabel = computed(() => {
|
||||
@@ -63,16 +72,51 @@ export class SearchComponent {
|
||||
filteredResults = computed(() => {
|
||||
const tag = this.filterTag();
|
||||
const provider = this.selectedProviderForView();
|
||||
|
||||
// Use unified results if available
|
||||
if (this.showUnified()) {
|
||||
const groups = this.groups();
|
||||
const list: Video[] = [];
|
||||
|
||||
// Convert unified groups to Video objects
|
||||
Object.entries(groups).forEach(([providerId, items]) => {
|
||||
items.forEach((item: any) => {
|
||||
list.push({
|
||||
videoId: item.id,
|
||||
title: item.title,
|
||||
thumbnail: item.thumbnail || '',
|
||||
uploaderName: item.uploaderName || 'Unknown',
|
||||
uploaderAvatar: '',
|
||||
views: 0,
|
||||
uploaded: Date.now(),
|
||||
uploadedDate: new Date().toISOString(),
|
||||
duration: 0,
|
||||
url: item.url || '',
|
||||
type: 'video',
|
||||
provider: providerId as 'youtube'|'dailymotion'|'twitch'|'rumble'|'odysee'|'peertube'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Apply tag filtering to unified results
|
||||
if (provider === 'twitch') return list; // Not used for Twitch (separate sections)
|
||||
if (tag === 'all') return list;
|
||||
|
||||
// For now, return all results since we don't have duration/uploaded info from unified search
|
||||
return list;
|
||||
}
|
||||
|
||||
// Fallback to legacy results
|
||||
const list = this.results();
|
||||
if (provider === 'twitch') return list; // Not used for Twitch (separate sections)
|
||||
if (tag === 'all') return list;
|
||||
|
||||
|
||||
const now = Date.now();
|
||||
const oneDay = 24 * 60 * 60 * 1000;
|
||||
const sevenDays = 7 * oneDay;
|
||||
const thirtyDays = 30 * oneDay;
|
||||
const oneYear = 365 * oneDay;
|
||||
|
||||
|
||||
// Duration filters
|
||||
if (tag === 'short') return list.filter(v => {
|
||||
const d = Number(v.duration || 0);
|
||||
@@ -86,7 +130,7 @@ export class SearchComponent {
|
||||
const d = Number(v.duration || 0);
|
||||
return d >= 20 * 60;
|
||||
});
|
||||
|
||||
|
||||
// Date filters
|
||||
if (tag === 'today') return list.filter(v => {
|
||||
const uploadTime = typeof v.uploaded === 'number' ? v.uploaded : 0;
|
||||
@@ -104,7 +148,7 @@ export class SearchComponent {
|
||||
const uploadTime = typeof v.uploaded === 'number' ? v.uploaded : 0;
|
||||
return uploadTime > 0 && (now - uploadTime) <= oneYear;
|
||||
});
|
||||
|
||||
|
||||
return list;
|
||||
});
|
||||
|
||||
@@ -113,8 +157,34 @@ export class SearchComponent {
|
||||
const provider = this.selectedProviderForView();
|
||||
const tags: { key: string; label: string; show: boolean }[] = [];
|
||||
const now = Date.now();
|
||||
const list = this.results();
|
||||
|
||||
|
||||
// Use unified results if available
|
||||
const list = this.showUnified() ?
|
||||
(() => {
|
||||
const groups = this.groups();
|
||||
const results: Video[] = [];
|
||||
Object.entries(groups).forEach(([_, items]) => {
|
||||
items.forEach((item: any) => {
|
||||
results.push({
|
||||
videoId: item.id,
|
||||
title: item.title,
|
||||
thumbnail: item.thumbnail || '',
|
||||
uploaderName: item.uploaderName || 'Unknown',
|
||||
uploaderAvatar: '',
|
||||
views: 0,
|
||||
uploaded: Date.now(),
|
||||
uploadedDate: new Date().toISOString(),
|
||||
duration: 0,
|
||||
url: item.url || '',
|
||||
type: 'video',
|
||||
provider: 'youtube' as any
|
||||
});
|
||||
});
|
||||
});
|
||||
return results;
|
||||
})() :
|
||||
this.results();
|
||||
|
||||
if (provider === 'twitch') {
|
||||
const hasLive = this.twitchChannels().length > 0;
|
||||
const hasVods = this.twitchVods().length > 0;
|
||||
@@ -132,20 +202,20 @@ export class SearchComponent {
|
||||
const sevenDays = 7 * oneDay;
|
||||
const thirtyDays = 30 * oneDay;
|
||||
const oneYear = 365 * oneDay;
|
||||
|
||||
let hasShort = false, hasMedium = false, hasLong = false,
|
||||
|
||||
let hasShort = false, hasMedium = false, hasLong = false,
|
||||
hasToday = false, hasThisWeek = false, hasThisMonth = false, hasThisYear = false;
|
||||
|
||||
|
||||
for (const v of list) {
|
||||
const d = Number(v.duration || 0);
|
||||
const uploadTime = typeof v.uploaded === 'number' ? v.uploaded : 0;
|
||||
const timeDiff = now - uploadTime;
|
||||
|
||||
|
||||
// Duration filters
|
||||
if (d > 0 && d < 4 * 60) hasShort = true;
|
||||
else if (d >= 4 * 60 && d < 20 * 60) hasMedium = true;
|
||||
else if (d >= 20 * 60) hasLong = true;
|
||||
|
||||
|
||||
// Date filters
|
||||
if (uploadTime > 0) {
|
||||
if (timeDiff <= oneDay) hasToday = true;
|
||||
@@ -160,13 +230,13 @@ export class SearchComponent {
|
||||
tags.push({ key: 'short', label: 'Moins de 4 min', show: hasShort });
|
||||
tags.push({ key: 'medium', label: 'De 4 à 20 min', show: hasMedium });
|
||||
tags.push({ key: 'long', label: '20 min et plus', show: hasLong });
|
||||
|
||||
|
||||
// Add date filters
|
||||
tags.push({ key: 'today', label: 'Aujourd\'hui', show: hasToday });
|
||||
tags.push({ key: 'this_week', label: 'Cette semaine', show: hasThisWeek });
|
||||
tags.push({ key: 'this_month', label: 'Ce mois-ci', show: hasThisMonth });
|
||||
tags.push({ key: 'this_year', label: 'Cette année', show: hasThisYear });
|
||||
|
||||
|
||||
return tags.filter(t => t.show);
|
||||
});
|
||||
|
||||
@@ -176,24 +246,54 @@ export class SearchComponent {
|
||||
this.title.setTitle(this.pageHeading());
|
||||
});
|
||||
|
||||
// Subscribe once to unified multi-provider results and reflect to UI
|
||||
this.unified.request$.subscribe({
|
||||
next: (resp: SearchResponse) => {
|
||||
this.groups.set(resp.groups as any);
|
||||
this.loading.set(false);
|
||||
},
|
||||
error: () => {
|
||||
this.groups.set({} as any);
|
||||
this.loading.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to query param changes (so subsequent searches update)
|
||||
this.route.queryParamMap.subscribe((pm) => {
|
||||
const q = (pm.get('q') || '').trim();
|
||||
this.q.set(q);
|
||||
const prov = (pm.get('provider') as Provider) || null;
|
||||
const theme = pm.get('theme');
|
||||
const providersParam = (pm.get('providers') || '').trim();
|
||||
// Parse providers CSV if present
|
||||
let providersList: ProviderId[] | 'all' | null = null;
|
||||
if (providersParam) {
|
||||
const arr = providersParam.split(',').map(s => s.trim()).filter(Boolean) as ProviderId[];
|
||||
providersList = (arr.length > 0) ? arr : 'all';
|
||||
}
|
||||
this.providerParam.set(prov);
|
||||
this.themeParam.set(theme);
|
||||
this.providersListParam.set(providersList);
|
||||
|
||||
if (q) {
|
||||
this.notice.set(null);
|
||||
// Reset active tag on new query
|
||||
const provider = (prov || this.instances.selectedProvider());
|
||||
const provider = prov || this.instances.selectedProvider();
|
||||
this.filterTag.set(provider === 'twitch' ? 'twitch_all' : 'all');
|
||||
this.reloadSearch();
|
||||
|
||||
// Use unified search in all cases
|
||||
const providersToUse = providersList || [provider as ProviderId];
|
||||
this.unified.setQuery(q);
|
||||
this.unified.setProviders(providersToUse);
|
||||
this.showUnified.set(true);
|
||||
this.loading.set(true);
|
||||
this.groups.set({} as any); // Clear previous results
|
||||
} else {
|
||||
this.results.set([]);
|
||||
this.nextCursor.set(null);
|
||||
this.loading.set(false);
|
||||
this.groups.set({} as any);
|
||||
this.showUnified.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -206,8 +306,18 @@ export class SearchComponent {
|
||||
untracked(() => {
|
||||
// If provider is explicitly specified in query, do not override it with global changes
|
||||
if (this.providerParam()) return;
|
||||
if (this.q()) {
|
||||
this.notice.set(null);
|
||||
if (!this.q()) return;
|
||||
this.notice.set(null);
|
||||
// If unified mode is active, re-emit providers to trigger a refresh instead of legacy reload
|
||||
if (this.showUnified()) {
|
||||
const provParam = this.providersListParam();
|
||||
const provider = this.instances.selectedProvider();
|
||||
const providersToUse = (provParam && (provParam === 'all' || (Array.isArray(provParam) && provParam.length > 0)))
|
||||
? (provParam as any)
|
||||
: [provider as unknown as ProviderId];
|
||||
this.unified.setProviders(providersToUse);
|
||||
this.loading.set(true);
|
||||
} else {
|
||||
this.reloadSearch();
|
||||
}
|
||||
});
|
||||
@@ -354,11 +464,6 @@ export class SearchComponent {
|
||||
return qp;
|
||||
}
|
||||
|
||||
// Update active filter tag from the template
|
||||
setFilterTag(key: string) {
|
||||
this.filterTag.set(key);
|
||||
}
|
||||
|
||||
@ViewChild('searchInput') searchInput?: ElementRef<HTMLInputElement>;
|
||||
|
||||
onSearchEnter(event: Event) {
|
||||
@@ -366,8 +471,16 @@ export class SearchComponent {
|
||||
keyboardEvent.preventDefault();
|
||||
const query = this.q().trim();
|
||||
if (query) {
|
||||
// Utiliser reloadSearch() pour effectuer une nouvelle recherche
|
||||
this.reloadSearch();
|
||||
// Route unified search regardless of providers param
|
||||
const provParam = this.providersListParam();
|
||||
const provider = this.providerParam() || this.instances.selectedProvider();
|
||||
const providersToUse = (provParam && (provParam === 'all' || (Array.isArray(provParam) && provParam.length > 0)))
|
||||
? (provParam as any)
|
||||
: [provider as unknown as ProviderId];
|
||||
this.unified.setQuery(query);
|
||||
this.unified.setProviders(providersToUse);
|
||||
this.showUnified.set(true);
|
||||
this.loading.set(true);
|
||||
this.closeSearchResults();
|
||||
// Retirer le focus de l'input
|
||||
if (this.searchInput) {
|
||||
@@ -389,8 +502,8 @@ export class SearchComponent {
|
||||
// Vous pouvez ajouter ici la logique de recherche au fur et à mesure si nécessaire
|
||||
}
|
||||
|
||||
performSearch(query: string) {
|
||||
// Cette méthode sera appelée pour effectuer la recherche
|
||||
// Vous pouvez ajouter ici la logique de recherche
|
||||
// Update active filter tag from the template
|
||||
setFilterTag(key: string) {
|
||||
this.filterTag.set(key);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user