Nouveau composant partage app-filter-toolbar, utilise tel quel par la page
de recherche ET les deux pages de themes (meme visuel, seul le cablage
differe : URL pour la recherche, signaux locaux pour les themes).
- Boutons : [Filtres] (pastilles de type, ligne Sources, selects periode /
duree / langue, filtres actifs) et [Tri] (Pertinence, Date de mise en
ligne, Vues, Note (likes), Duree).
- Page de recherche : le bouton oeil « filtres rapides » et le panneau de
selects disparaissent, tout est sous [Filtres] ; le tri a son bouton.
- Sources : boutons Toutes / Aucune. « Aucune » masque tout (la garde
« derniere source masquable » est retiree) et un bandeau vide dit de
reactiver au moins un fournisseur.
- /t/:theme : les 3 pastilles maison sont remplacees par la barre ; les
sources masquent des blocs entiers ; filtres et tri appliques sur les
blocs deja charges.
- /p/:provider/t/:theme : les 5 selects et les pastilles sont remplaces par
la barre ; signaux maison unifies sur le modele SearchFilters (defaut
relevance) ; les onglets Twitch lisent/ecrivent filters().type.
- Tri etendu : FilterSort + rating + duration. Les providers ne connaissent
que relevance/date/views (serveur inchange, repli relevance) : Note et
Duree sont reordonnes cote client via sortItems(), partage avec les pages
themes.
- Communs : sortItems / itemViews / itemRating / matchesLanguage /
formatCount extraits de filters.ts (3 copies d'heuristiques supprimees) ;
cles i18n fr+en (filters.sort.rating, filters.sort.duration,
filters.sortHint, filters.localHint, « Date de mise en ligne »).
Tests : test:search, test:filters, test:suggest, test:kind, test:section
verts + test:api 41/41, build ng OK.
Source unique de classification (video-kind.ts) + politique de section centralisee (section-policy.ts). Les composants ne portent plus de seuils ni de regles de type maison.
- section-policy.ts: sectionAccepts / routeForVideo / shortsFeedAccepts /
isPlayable + classifyOnce (enrichissement _kind a l'ingestion)
- watch-short: separe classification (shortsFeedAccepts) et jouabilite
(isPlayable: allowEmbed DM, live/channel Twitch, Rumble 404); supprime le
seuil Rumble 90 s et l'import YOUTUBE_SHORT_MAX_SECONDS du composant
- home: filtre sectionAccepts(...,'home') (plus de shorts dans le trending),
routeForVideo, pagination bouclee (min 20, max 5 iterations)
- themes: _kind pre-calcule une fois, sectionAccepts, capacites live lues
depuis le registre providers (fin de LIVE_PROVIDERS codes en dur)
- video-kind: helpers isNativeVerticalProvider / hasKnownDuration
- routes: alias /shorts/:id et /live/:id pour routeForVideo
- tests: section-policy.spec.ts + video-kind.spec.ts etendus; npm run test:section