# Movie Guessr

Devine le film à partir de captures issues de sa fiche IMDb, une image à la fois.
Clone jouable de [movieguessr.fr](https://movieguessr.fr/) : défi du jour, partie
classique, chrono, essais limités, révélation et classement. Backend **PHP 8 +
AJAX**, sans dépendance ni framework.

## Lancer

```bash
npm start        # http://127.0.0.1:3000
```

ou directement :

```bash
php -S 127.0.0.1:3000 -t public router.php
```

Prérequis : PHP 8.2+ avec les extensions `curl`, `json`, `mbstring` et `intl`
(translittération des accents). Aucune dépendance à installer, aucun build.

Sur Apache, `public/` est la racine du site et `public/.htaccess` réécrit
`/api/*` vers `api.php`. `PORT` et `HOST` n'ont plus d'effet : passez l'adresse
au serveur PHP.

## Déploiement (PHP-FPM)

Configurations prêtes dans `deploy/` : Nginx + PHP-FPM, Apache + `proxy_fcgi`,
pool FPM dédié et procédure Debian/Ubuntu. Voir [`deploy/README.md`](deploy/README.md).

Pour un **hébergement mutualisé OVH** (offre Pro), voir
[`deploy/ovh/README.md`](deploy/ovh/README.md) : `.ovhconfig` active PHP-FPM
fourni par OVH, avec `www/` comme racine web et le code hors racine.

Sous Windows, `php-fpm` n'existe pas : WAMP fournit `php-cgi.exe` (FastCGI).
Le serveur intégré `npm start` reste la solution locale.

Une connexion réseau est nécessaire : les films et les captures sont lus en direct
sur IMDb à chaque partie, rien n'est préparé à l'avance.

## Choix des films

Le serveur lit le classement **box-office mondial par recettes cumulées**
(Box Office Mojo, service d'IMDb) à chaque tirage, puis garde les 120 premiers.
Parmi eux, il ne retient que les films dont la fiche IMDb propose au moins
5 captures paysage (largeur > hauteur × 1,2 et largeur ≥ 700 px), ce qui écarte
les affiches et les fiches trop pauvres.

- **Défi du jour** : tirage déterministe à partir de la date de Paris
  (`daily:2026-11-10`), 5 films. Aucune sélection n'est enregistrée : le même
  jour donne le même tirage tant que le classement box-office ne bouge pas.
  Si le classement évolue en cours de journée, les films peuvent changer.
- **Classique** : 10 films tirés au hasard dans le même classement, hors classement.

Aucun fichier de catalogue, aucune liste de titres, aucun cache de sélection :
les films sont choisis dans le classement au moment de la partie.

## D'où viennent les images

Chaque capture est un plan du film, pris dans la galerie publique de sa fiche
IMDb via l'API GraphQL `https://api.graphql.imdb.com/`. La requête ne lit que la
catégorie **« Still Frame »** (`Title.imageTypes`) : les affiches, photos
d'événements, making-of, visuels publicitaires, artworks et logos sont donc
exclus. Les images sont ensuite filtrées en paysage, puis envoyées au navigateur
**sous forme d'URL IMDb directe** (`https://m.media-amazon.com/...`).

Aucun proxy, aucun téléchargement, aucun cache disque : le serveur ne conserve
aucune image, il ne fait que lire les métadonnées IMDb nécessaires au tirage
(titres, captures disponibles, affiche, réalisateur). Les URL sont simplement
réécrites vers une variante d'affichage raisonnable (`._V1_QL80_UX1600_.jpg`).

Les données IMDb sont utilisées dans un cadre personnel et non commercial.
Crédit : images © IMDb et ayants droit des films.

## Modes

| Mode | Films | Images | Chrono | Classement |
| --- | --- | --- | --- | --- |
| Défi du jour | 5, les mêmes pour tous (date de Paris) | 5 | 60 s | oui, une tentative par jour |
| Classique | 10, tirés au hasard | 5 | 60 s | non |

Barème : 100 / 83 / 65 / 48 / 30 points selon l'image, +20 si la réponse arrive
dans les 30 premières secondes. Une erreur coûte une image ; cinq erreurs ou 60
secondes épuisées donnent la réponse pour 0 point.

## Structure

```
public/                 accueil, jeu, styles, scripts (AJAX)
public/api.php          API JSON : sessions, réponses, classement, recherche
public/.htaccess        réécriture /api/* pour Apache
router.php              routeur du serveur PHP intégré
lib/http.php            helpers HTTP, aléatoire déterministe, validation
lib/boxoffice.php       lecture du classement box-office mondial
lib/imdb.php            client IMDb (GraphQL via cURL, curl_multi, recherche)
lib/game.php            sessions, essais, barème, résumés
lib/store.php           persistance JSON (classement, propositions)
lib/text.php            normalisation des titres (accents, articles, année)
legacy-node/            ancienne version Node, conservée comme référence
```

Le pseudo est stocké dans le navigateur, le score du défi du jour est envoyé au
serveur et conservé dans `data/leaderboard.json` (ignoré par Git). Les
propositions de films vont dans `data/proposals.json` après vérification de la
fiche IMDb (identifiant résolu, 5 captures paysage minimum). Les parties vivent
dans la session PHP, retrouvée par son identifiant transmis par l'API (cookie
facultatif, purge après 2 h) et disparaissent au redémarrage du serveur.
