fix(rumble): un HTTP 404 net n'est pas un blocage Cloudflare
CI / build-and-test (push) Canceled after 0s

Probe live depuis le conteneur : rumble.com renvoie 404 (vraie page,
non-challenge) pour un id inexistant. fetchHtml les classait en échec
total, d'où deux régressions : 503 sur /video (les vidéos mortes ne
sont plus retirées des Shorts) et armement du cooldown 60 s pour toute
la maison au premier id bogus.

- fetchHtml retourne toute réponse nette non-challenge ; le statut est
  jugé par les appelants (tous dans le même fichier).
- rumbleFailureForStatus() exporté : 403 -> 503
  rumble_cloudflare_challenge (bandeau identique à la recherche),
  404/410 -> 404 rumble_not_found, 5xx -> 503 rumble_upstream_error.
  /video, /browse et /shorts passent par ce mapping.
- handler.search ne parse plus que du HTTP 200 : les pages 404 de
  Rumble embarquent des cartes de recommandation qui seraient
  autrement prises pour des résultats de recherche.
- Tests : 7 assertions sur le mapping (sans réseau), 64 au total.
This commit is contained in:
2026-10-02 08:49:44 -04:00
parent e48d76be57
commit 7fc1e1096d
3 changed files with 34 additions and 5 deletions
+1 -1
View File
@@ -126,7 +126,7 @@ curl "http://localhost:4000/api/details/youtube/dQw4w9WgXcQ" | jq '{title,upload
Tendances YT sans clé (scrape). Phase 1 : `yt` uniquement (`400` sinon), fallback `{ items:[] }` jamais 500.
### 5.5 Rumble dédié (`/api/rumble/…`)
`GET /browse?page=&limit=&sort=`, `GET /shorts?page=&limit=`, `GET /search?q=…&page=|offset=`, `GET /video/:videoId`, `GET /video/:videoId/preplay`. Rate-limit 20/min. Le scraping vit dans `server/providers/rumble.mjs` (cœur partagé avec `/api/search` : cache SQLite, negative cache, cookie jar Cloudflare) ; `/search` passe par le registre de providers. Réponses : `{ items, total, page, limit, nextCursor }` (liste), `{ videoId, title, …, embedUrl }` (vidéo). Erreurs : `503 { error:"rumble_cloudflare_challenge" }` = blocage Cloudflare (cooldown global 60 s côté serveur), `404 { error:"rumble_video_not_found" }` = vidéo réellement absente, `400 { error:"Query parameter required" }` (search sans q).
`GET /browse?page=&limit=&sort=`, `GET /shorts?page=&limit=`, `GET /search?q=…&page=|offset=`, `GET /video/:videoId`, `GET /video/:videoId/preplay`. Rate-limit 20/min. Le scraping vit dans `server/providers/rumble.mjs` (cœur partagé avec `/api/search` : cache SQLite, negative cache, cookie jar Cloudflare) ; `/search` passe par le registre de providers. Réponses : `{ items, total, page, limit, nextCursor }` (liste), `{ videoId, title, …, embedUrl }` (vidéo). Erreurs : `503 { error:"rumble_cloudflare_challenge" }` = blocage Cloudflare (cooldown global 60 s côté serveur), `404 { error:"rumble_not_found"|"rumble_video_not_found" }` = ressource réellement absente (HTTP 404 net côté Rumble, ou page 200 sans identité vidéo), `400 { error:"Query parameter required" }` (search sans q).
## 6. Référence REST — transcript détaillé