Aller au contenu

Pipeline de recherche

Le pipeline de recherche est le cœur de Stream Fusion. Il orchestre la recherche de torrents à travers les 4 couches de cache avec une stratégie cache-first, et ne consulte les indexeurs externes que lorsque c'est nécessaire — économisant les appels API et assurant des réponses rapides.


Flux complet

graph TD
    REQ["Requête Stremio"] --> PARSE["Décodage config Fernet"]
    PARSE --> L1{"L1: Redis<br/>Cache stream<br/>~1ms"}
    L1 -->|"Hit"| RET["Réponse immédiate<br/>+ prefetch N+1"]
    L1 -->|"Miss"| L2{"L2: PostgreSQL<br/>Cache privé<br/>~5ms"}
    L2 -->|"Suffisant<br/>+ frais"| BG["Réponse + refresh async"]
    L2 -->|"Insuffisant"| PH["Recherche live<br/>par phases"]
    PH --> P1["Phase 1: Prioritaires<br/>C411, Torr9 + Public si activé"]
    P1 --> P2{"Résultats privés<br/>>= minCachedResults ?"}
    P2 -->|"Non"| P3["Phase 2: Intermédiaires<br/>LaCale, GenerationFree..."]
    P2 -->|"Oui"| SKIP2["Skip Phase 2"]
    P3 --> P4{"Résultats privés<br/>>= minCachedResults ?"}
    P4 -->|"Non"| P5["Phase 3: Fallback<br/>ABN, Zilean, Jackett"]
    P4 -->|"Oui"| SKIP3["Skip Phase 3"]
    P5 --> P6{"Public en Phase 1 ?"}
    P6 -->|"Non"| P7["Phase 4: Public<br/>U2P / MeiliCache"]
    P6 -->|"Oui"| FUSION
    P7 --> FUSION["Fusion + Filtrage"]
    SKIP2 --> FUSION
    SKIP3 --> FUSION
    FUSION --> DEBRID["Vérification debrid"]
    DEBRID --> CACHE["Mise en cache<br/>Redis + PostgreSQL"]
    CACHE --> RET2["Réponse"]
    BG --> RET3["Réponse"]

    style REQ fill:#311b92,color:#fff
    style RET fill:#1b5e20,color:#fff
    style RET2 fill:#1b5e20,color:#fff
    style RET3 fill:#1b5e20,color:#fff
    style L1 fill:#bf360c,color:#fff
    style L2 fill:#1b5e20,color:#fff
    style P1 fill:#311b92,color:#fff
    style P3 fill:#4a148c,color:#fff
    style P5 fill:#827717,color:#fff
    style P7 fill:#e65100,color:#fff

Stratégie par phases

Les indexeurs privés sont organisés en 3 niveaux de priorité, configurables par l'utilisateur depuis la page de configuration du plugin. Seuls les indexeurs nécessaires sont interrogés — si les phases précédentes retournent assez de résultats, les phases suivantes sont ignorées.

graph LR
    P1["Phase 1<br/>Prioritaires<br/>toujours interrogés"]
    P2["Phase 2<br/>Intermédiaires<br/>si résultats < seuil"]
    P3["Phase 3<br/>Fallback<br/>dernier recours"]
    P4["Phase 4<br/>Public<br/>MeiliCache / U2P"]

    P1 -->|"≥ minCachedResults"| OK["Arrêt"]
    P1 -->|"< seuil"| P2
    P2 -->|"≥ minCachedResults"| OK
    P2 -->|"< seuil"| P3
    P3 --> P4
    P4 --> OK

    style P1 fill:#311b92,color:#fff
    style P2 fill:#4a148c,color:#fff
    style P3 fill:#827717,color:#fff
    style P4 fill:#e65100,color:#fff
    style OK fill:#1b5e20,color:#fff

Niveaux de priorité par défaut

Niveau Indexeurs Comportement
Prioritaire C411, Torr9 Toujours interrogés
Intermédiaire LaCale, GenerationFree, G3mini, TheOldSchool Uniquement si résultats insuffisants
Fallback ABN, Zilean, Jackett Dernier recours
Public U2P / MeiliCache En Phase 1 si priorité activée, sinon en Phase 4

Configurer un maximum d'indexeurs n'impacte pas la vitesse

Les phases ultérieures ne sont interrogées que si les phases précédentes n'ont pas retourné assez de résultats. Configurer plus d'indexeurs améliore la complétude sans ralentir les recherches courantes. Seuls les indexeurs prioritaires sont toujours interrogés.


Couches de cache

L1 — Redis (cache hot, ~1ms)

Vérification immédiate avec une clé dérivée du type, ID, langue et préférences utilisateur. Si un résultat existe, il est retourné immédiatement et un préchargement de l'épisode suivant est lancé en arrière-plan.

L2 — PostgreSQL (cache privé, ~5ms)

Si Redis est vide, PostgreSQL est interrogé. Deux conditions déterminent si les résultats sont suffisants :

  • Quantité : nombre de résultats confirmés >= minPostgresResults (défaut: 5)
  • Fraîcheur : le résultat le plus récent date de moins de postgresMaxAgeDays (défaut: 7 jours)

Si les deux sont remplis → réponse immédiate + refresh asynchrone en arrière-plan pour mettre à jour le cache.

L3/L4 — Meilisearch + Indexeurs live

Si le cache est insuffisant, la recherche live est déclenchée par phases (voir ci-dessus). Meilisearch agit comme un indexeur "public" et est interrogé selon sa priorité.


Tâches de fond déclenchées par une recherche

Chaque recherche peut déclencher des tâches de fond pour maintenir le cache à jour sans ralentir la réponse utilisateur.

Refresh asynchrone (background_db_refresh)

Après un hit sur le cache PostgreSQL, une tâche de fond est lancée pour rafraîchir les données auprès de tous les indexeurs stockés en base :

  • Délai de 2 secondes avant démarrage
  • Verrou par indexeur : chaque indexeur a un verrou Redis avec TTL de 6h (bg_refresh:{indexer}:{tmdb_id}:{season}{episode})
  • Si le verrou existe, l'indexeur est ignoré — pas de requête inutile
  • Si la requête échoue, le verrou est supprimé pour permettre un réessai
graph LR
    HIT["Cache PostgreSQL<br/>hit"] --> RET["Réponse immédiate"]
    HIT --> BG["background_db_refresh"]
    BG --> LOCK{"Verrou<br/>6h/indexer ?"}
    LOCK -->|"Oui"| SKIP["Skip"]
    LOCK -->|"Non"| FETCH["Requête indexer"]
    FETCH --> UPDATE["Mise à jour<br/>PostgreSQL"]

    style HIT fill:#1b5e20,color:#fff
    style RET fill:#311b92,color:#fff
    style SKIP fill:#827717,color:#fff

Préchargement d'épisodes (prefetch_next_episode)

Quand un utilisateur regarde l'épisode N, le système pré-charge les streams de l'épisode N+1 en arrière-plan :

  • Verrou par épisode : prefetch_next:{user}:{tmdb_id}:{S{season}E{episode}} avec TTL 20 min — empêche les préchargements en double
  • Limite de concurrence : max 2 tâches simultanées par utilisateur/saison
  • Cascade : si prefetch_depth >= 2, l'épisode N+2 est aussi préchargé
  • Le préchargement exécute le pipeline complet (metadata → indexeurs → filtres → debrid → streams) et met en cache le résultat

Assignation TMDB/IMDB rétroactive

Les torrents sans ID sont traités en tâche de fond :

  • tmdb_orphan_matching : matching par titre via l'API TMDB (toutes les 30 min)
  • imdb_orphan_matching : matching via DuckDB IMDB (toutes les 30 min)

Configuration utilisateur des indexeurs

Depuis la page de configuration du plugin Stremio (http://votre-domaine/), chaque utilisateur peut configurer :

Priorité des indexeurs

Pour chaque indexeur auquel il a accès, l'utilisateur choisit un niveau de priorité :

Niveau Description Impact
Prioritaire Toujours interrogé Utile pour les indexeurs rapides avec un bon cache FR
Intermédiaire Interrogé si résultats insuffisants Bon compromis entre couverture et performance
Fallback Dernier recours Pour les indexeurs lents ou avec un cache moins complet
Désactivé Jamais interrogé L'indexeur n'est pas utilisé

Autres paramètres de recherche

Paramètre Défaut Description
minCachedResults 8 Seuil de résultats privés pour déclarer une phase suffisante
minPostgresResults 5 Seuil pour le cache PostgreSQL fast-path
postgresMaxAgeDays 7 Âge max du cache PostgreSQL (en jours)
rdMinCachedBeforeCheck 3 Skip Real-Debrid si N résultats déjà en cache debrid
maxResults 30 Nombre max de streams vérifiés debrid
resultsPerQuality 10 Nombre max de résultats par résolution
sort quality Méthode de tri des résultats
languages fr, multi Langues souhaitées
exclusion cam Qualités exclues
utopeerPriority / meiliCachePriority True Public en Phase 1 (sinon Phase 4)

Conseil de configuration

Configurez un maximum d'indexeurs avec des identifiants personnels. La stratégie par phases garantit que seuls les indexeurs prioritaires sont interrogés en premier. Les indexeurs intermédiaires et fallback ne seront sollicités que si les résultats sont insuffisants — aucun impact sur la vitesse de chargement.


Vérification debrid

Après la fusion et le filtrage, chaque torrent est vérifié sur le(s) service(s) debrid configuré(s) :

  1. Cache debrid : vérification en bulk des hashes en cache (ultra-rapide)
  2. Requêtes live : pour les services non-cachés, vérification individuelle
  3. Real-Debrid conditionnel : si rdMinCachedBeforeCheck résultats sont déjà en cache debrid, la vérification RD est skippée (économie d'appels API)

Les résultats en cache debrid sont renommés "SF - Cache" pour indiquer la disponibilité instantanée.


Résumé des verrous et TTL

Verrou Redis TTL But
Stream cache 10-20 min Dédoublonnage des requêtes identiques
Media cache 7 jours Cache des résultats de recherche externes
bg_refresh:{indexer}:{id} 6h Éviter de re-requêter un indexer récemment rafraîchi
prefetch_next:{user}:{id}:{ep} 20 min Empêcher les préchargements en double
prefetch_active:{user}:{id}:{season} 120s Limiter à 2 prefetch simultanés par saison