bastien-mrq/multi-twitch / README.md
README.md
Code Preview
# Multi-Twitch — ZEvent
Front local pour regarder **plusieurs streams Twitch en même temps**, pensé pour le ZEvent :
tout l'écran est utilisé (pas de scroll, pas de gap), un seul fichier HTML, zéro dépendance.

## Démarrage rapide
```sh
./start.sh # sert l'app sur http://localhost:8123 et ouvre le navigateur
./start.sh 9000 # autre port si besoin
```
⚠️ Il faut passer par `http://localhost` : le player Twitch exige un paramètre `parent`
et refuse de se charger depuis un fichier ouvert en `file://`.
## Technologie
- **Un seul fichier `index.html`** : HTML + CSS + JavaScript vanilla, sans framework,
sans build, sans npm.
- Seule brique externe : le **SDK officiel du player Twitch**
(`player.twitch.tv/js/embed/v1.js`), qui affiche les streams et expose l'API JS
(`play/pause`, `setMuted`, `setVolume`, `setQuality`, `getPlaybackStats`…).
- **CSS Grid** pour la disposition, **localStorage** pour retenir chaînes et volumes.
- Serveur : n'importe quel serveur statique (`python3 -m http.server`), aucune logique
côté serveur.
## Fonctionnalités
- **Recherche ⌘K** avec autocomplétion sur un annuaire d'habitués du ZEvent
(constante `KNOWN` dans `index.html`, modifiable). N'importe quel pseudo Twitch
peut être tapé pour ajouter une chaîne hors annuaire.
- **Grille sans scroll** : le découpage lignes × colonnes est recalculé à chaque
redimensionnement pour maximiser la surface vidéo 16:9 (fonction `bestGrid`).
- **Trois modes** : grille / plein écran avec colonne latérale (`F`) / plein écran (`⌘⇧K`).
- **Bandeau au survol uniquement** : nom, numéro, boutons (🔊 son solo, slider de volume,
⏯ play/pause, ⛶ plein écran, ✕ fermer). Le reste du temps, 100 % vidéo.
- **Mixeur de son** : un slider de volume par stream — plusieurs streams audibles en même
temps à des niveaux différents. Les touches `1`–`9`/`A` restent le mode « solo »
(le son sur un seul stream). Volumes mémorisés.
- **Jamais de pause** : relance automatique sur événement pause + chien de garde toutes
les 2 s + relance à chaque changement de disposition. La pause volontaire (⏯/`Espace`)
est respectée (badge « ⏸ PAUSE »).
- **Anti-gel** : un flux à 0 fps pendant ~6 s alors qu'il devrait jouer voit son player
reconstruit automatiquement. La détection ne s'arme qu'après un premier démarrage réel
(sinon elle tuerait les streams en cours de chargement).
- **Anti-pub (best effort)** : pub détectée sur le stream qui a le son → le son (et la
mise en avant) bascule sur le stream suivant sans pub, puis revient à la fin.
Twitch n'expose pas officiellement cet événement sur les embeds (détection par écoute
des messages internes du player), donc `P` fait la même bascule manuellement.
- **Qualité adaptative** : en mode plein écran/colonne, les petits streams passent en
basse qualité pour ne pas saturer le décodeur vidéo (cause classique de vignettes
figées) ; le stream principal reste en auto.
- **Turbo / compte Twitch** : rien à configurer — le player embarqué utilise la session
twitch.tv du navigateur (cookies tiers requis : OK sur Chrome par défaut, bloqué sur
Safari). Connecté avec Turbo = plus de pubs. Aucun risque de ban : c'est l'usage
officiel des embeds.
## Raccourcis clavier
| Touche | Action |
|---|---|
| `⌘K` | Recherche / autocomplétion (re-focus si déjà ouverte) |
| `⌘⇧K` | Plein écran du stream sélectionné (aller-retour) |
| `F` | Plein écran ⇄ plein écran + colonne latérale |
| `Entrée` | Met le stream sélectionné en avant |
| `1`–`9` | Son solo sur le stream n° N |
| `←` `→` `↑` `↓` | Déplace la sélection dans la grille |
| `A` | Son solo sur le stream sélectionné |
| `−` / `+` | Volume du stream sélectionné dans le mix |
| `Espace` | Play/pause du stream sélectionné |
| `P` | Pub sur le stream audio → passe au suivant |
| `M` ou `0` | Coupe tout le son |
| `X` ou `Suppr` | Ferme le stream sélectionné |
| `R` | Tout recharger (reconstruit les players, débloque les flux figés) |
| `Échap` | Retour à la grille |
Tous les raccourcis sont rappelés dans la barre en bas de l'écran.
Si tu cliques **dans** un player, l'iframe Twitch capte le clavier : le focus est
automatiquement rendu à la page après ~2,5 s.
## Le piège à connaître : la politique de visibilité de Twitch
La leçon durement apprise de ce projet : **Twitch bloque l'autoplay d'un player
recouvert par un autre élément, même totalement transparent** (erreur console
« Autoplay disabled — minimum requirements not met: style visibility »).
Conséquences dans le code :
- les liserés de sélection/son sont des **bordures** de la tuile, jamais des calques
posés sur la vidéo ;
- le bandeau au survol est en `display: none` (pas `opacity: 0`) tant qu'il n'est
pas affiché ;
- en plein écran, les autres streams ne sont pas cachés derrière le principal mais
gardés sur une **bande visible de 8 px** au bord droit.
Si tu modifies le CSS, ne pose jamais d'élément permanent au-dessus des players.
## Debug
- `window.__mt` en console expose `tiles`, `state`, `playAll`, `addChannel` pour
inspecter l'état réel des players (`__mt.tiles.zerator.player.getPlaybackStats()`).
- Le comportement a été validé par des tests automatisés en Chrome headless
(puppeteer-core) : autoplay, fps > 0 sur chaînes live, absence d'avertissements.
## Fichiers
- `index.html` — toute l'application (CSS + JS inclus)
- `start.sh` — lance un serveur statique et ouvre le navigateur
- `README.md` — ce fichier