Files
NewTube/api/README.md
T
bruno f1f673040e
CI / build-and-test (push) Successful in 14m10s
feat(search): panneau de filtres unifié, clavier/focus du typeahead
Barre de recherche
- Panneau de filtres unifié (remplace le ProviderPicker) : sources, type
  (vidéos/shorts/direct/chaînes), période (heure/jour/semaine/mois/année),
  durée (<4 / 4-20 / >20 min) et tri. Pastilles + roving tabindex
  (←/→ dans un groupe, ↑/↓ entre groupes), focus trap, Échap, Ctrl/⌘+Maj+F,
  recherches récentes, « mémoriser par défaut », « Réinitialiser ».
- Pastilles des filtres actifs sous la barre (retrait en un clic) + compteur.
- Typeahead : un seul keydown (fin du double Enter), ↑/↓ bouclants,
  Home/End, PageUp/PageDown, Entrée valide la ligne surlignée (sinon
  recherche brute), Tab complète sans chercher, Échap ferme puis vide,
  ligne « Rechercher <q> », défilement de l'option active, aria à jour.
- Focus : le panneau se referme dès que le focus quitte la barre
  (focusout + relatedTarget + activeElement), pointerdown neutralisé sur les
  lignes pour garder le focus dans l'input (plus de scintillement).
- Opérateurs en clair : `linux live:`, `tuto today: long:` deviennent des
  filtres et sont retirés de la requête (autocomplétion après le `:`).

Filtres côté serveur
- Modèle partagé : src/app/search/filters.ts + server/search-filters.mjs.
- /api/search?type=&duration=&period=&sort= : InnerTube (upload_date, type,
  duration, features), Data API v3 (type, videoDuration, publishedAfter),
  yt-dlp --dateafter ; post-filtrage pour les providers sans filtre natif.
  Un champ manquant ne fait jamais disparaître un résultat.
- Filtres dans l'URL (partageables) + adapters + SearchService (clé de cache).
- Correction : la recherche Shorts renvoyait 0 (ShortsLockupView/GridShelfView
  non mappés, id/titre dans l'endpoint) -> mappage + shelf + vignette/vues.

Tests / docs
- 23 tests unitaires (clavier, focus, opérateurs, panneau de filtres),
  server/tests/search-filters.test.mjs (npm run test:filters) + CI,
  scénarios e2e des filtres, README/api/README/todo/MCP à jour.
2026-09-28 17:42:19 -04:00

2.5 KiB

NewTube Unified Search API

This document describes the unified search endpoint used by the frontend SearchBar and Search page.

Base URL

Endpoint

  • GET /api/search

Query parameters

  • q (string, required, min length 2)
  • providers (string, optional): Comma-separated list of provider ids. Allowed values: yt, dm, tw, pt, od, ru. Defaults to all when omitted or invalid.
  • page (integer, optional): Page index starting at 1. Default: 1.
  • pageSize (integer, optional): Page size, max 50. Default: 24.
  • sort (string, optional): relevance | date | views. Default: relevance.
  • type (string, optional): video | shorts | live | channel. Default: all.
  • duration (string, optional): short (< 4 min) | medium (4-20 min) | long (> 20 min). Default: all.
  • period (string, optional): hour | today | week | month | year (upload date). Default: all.

Response

{
  "q": "string",
  "providers": ["yt", "dm", "tw", "pt", "od", "ru"],
  "groups": {
    "yt": [
      { "id": "string", "title": "string", "thumbnail": "string", "uploaderName": "string", "url": "string", "type": "video" }
    ],
    "dm": [],
    "tw": [],
    "pt": [],
    "od": [],
    "ru": []
  },
  "page": 1,
  "pageSize": 24,
  "sort": "relevance",
  "filters": { "type": "live", "period": "week" }
}

filters echoes the active filters (default values are omitted). Unknown filter values are ignored (never a 4xx), so a typo silently degrades to "no filter".

Error responses

  • 400 { error: "invalid_query", details: "min_length_2" }
  • 500 { error: "search_failed", details: "..." }

Providers

  • yt: YouTube
  • dm: Dailymotion
  • tw: Twitch
  • pt: PeerTube
  • od: Odysee
  • ru: Rumble

Notes

  • Each provider is queried in parallel with a per-provider limit equal to pageSize.
  • The endpoint currently does not expose a total field; the frontend should offer a simple Next page affordance or infinite scroll when appropriate.
  • Filters are applied natively when the provider supports them (YouTube: InnerTube upload_date / type / duration / features, Data API v3 type / videoDuration / publishedAfter, yt-dlp --dateafter), and refined in post-processing otherwise (see server/search-filters.mjs).
  • A result whose metadata is missing is never dropped by a filter: only values that are present and out of range are filtered out.
  • The channel type is only enforced for YouTube (the only provider that returns channels as search results).
  • period=hour is not a native InnerTube filter: it is applied in post-processing.