Ajout récupération de jaquette de jeux via api
This commit is contained in:
1 parent
b785db1b84
commit
df11d023f0
6 files changed
+209
-19
No files matched your search
+4
-2
@@ -1,7 +1,10 @@
|
|||||||
FROM php:8.3-apache
|
FROM php:8.3-apache
|
||||||
|
|
||||||
RUN a2enmod rewrite headers \
|
RUN a2enmod rewrite headers \
|
||||||
&& docker-php-ext-install opcache
|
&& apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends libcurl4-openssl-dev \
|
||||||
|
&& docker-php-ext-install opcache curl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY docker/apache.conf /etc/apache2/sites-available/000-default.conf
|
COPY docker/apache.conf /etc/apache2/sites-available/000-default.conf
|
||||||
COPY docker/php.ini /usr/local/etc/php/conf.d/jeuxvideotech.ini
|
COPY docker/php.ini /usr/local/etc/php/conf.d/jeuxvideotech.ini
|
||||||
@@ -11,7 +14,6 @@ WORKDIR /var/www/html
|
|||||||
COPY public /var/www/html/public
|
COPY public /var/www/html/public
|
||||||
COPY src /var/www/html/src
|
COPY src /var/www/html/src
|
||||||
COPY templates /var/www/html/templates
|
COPY templates /var/www/html/templates
|
||||||
COPY data /var/www/html/data
|
|
||||||
|
|
||||||
RUN mkdir -p /var/www/html/data/jaquettes /var/www/html/data/cache \
|
RUN mkdir -p /var/www/html/data/jaquettes /var/www/html/data/cache \
|
||||||
&& chown -R www-data:www-data /var/www/html/data
|
&& chown -R www-data:www-data /var/www/html/data
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ final class JeuController
|
|||||||
"titrePage" => $jeu["titre"],
|
"titrePage" => $jeu["titre"],
|
||||||
"utilisateur" => $utilisateur,
|
"utilisateur" => $utilisateur,
|
||||||
"jeu" => $jeu,
|
"jeu" => $jeu,
|
||||||
"console" => $console
|
"console" => $console,
|
||||||
|
"jaquetteAbsente" => Helpers::jaquetteAbsente($jeu["jaquette"] ?? null),
|
||||||
|
"apiDisponible" => $this->enrichissementService->estDisponible()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,7 @@ final class JeuController
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
$donnees = $this->collecterDonneesFormulaire();
|
$donnees = $this->collecterDonneesFormulaire();
|
||||||
|
$donnees = $this->completerJaquetteSiAbsente($donnees);
|
||||||
$jeu = $this->jeuService->creer($utilisateur["id"], $donnees);
|
$jeu = $this->jeuService->creer($utilisateur["id"], $donnees);
|
||||||
Flash::definir("success", "Jeu ajouté à votre bibliothèque.");
|
Flash::definir("success", "Jeu ajouté à votre bibliothèque.");
|
||||||
Helpers::rediriger("/jeux/" . $jeu["id"]);
|
Helpers::rediriger("/jeux/" . $jeu["id"]);
|
||||||
@@ -134,6 +137,7 @@ final class JeuController
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
$donnees = $this->collecterDonneesFormulaire();
|
$donnees = $this->collecterDonneesFormulaire();
|
||||||
|
$donnees = $this->completerJaquetteSiAbsente($donnees);
|
||||||
$jeu = $this->jeuService->modifier($id, $utilisateur["id"], $donnees);
|
$jeu = $this->jeuService->modifier($id, $utilisateur["id"], $donnees);
|
||||||
Flash::definir("success", "Jeu mis à jour.");
|
Flash::definir("success", "Jeu mis à jour.");
|
||||||
Helpers::rediriger("/jeux/" . $jeu["id"]);
|
Helpers::rediriger("/jeux/" . $jeu["id"]);
|
||||||
@@ -229,6 +233,76 @@ final class JeuController
|
|||||||
Helpers::rediriger($retour . $separateur . $query);
|
Helpers::rediriger($retour . $separateur . $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function recupererJaquette(string $id): void
|
||||||
|
{
|
||||||
|
$utilisateur = $this->auth->exigerConnexion();
|
||||||
|
Csrf::exiger();
|
||||||
|
|
||||||
|
$jeu = $this->jeuService->trouverPourUtilisateur($id, $utilisateur["id"]);
|
||||||
|
|
||||||
|
if ($jeu === null)
|
||||||
|
{
|
||||||
|
Flash::definir("danger", "Jeu introuvable.");
|
||||||
|
Helpers::rediriger("/jeux");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Helpers::jaquetteAbsente($jeu["jaquette"] ?? null))
|
||||||
|
{
|
||||||
|
Flash::definir("success", "Ce jeu a déjà une jaquette.");
|
||||||
|
Helpers::rediriger("/jeux/" . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->enrichissementService->estDisponible())
|
||||||
|
{
|
||||||
|
Flash::definir("warning", "Clé API RAWG absente : impossible de récupérer la jaquette.");
|
||||||
|
Helpers::rediriger("/jeux/" . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fichier = $this->enrichissementService->recupererJaquetteParTitre($jeu["titre"] ?? "");
|
||||||
|
|
||||||
|
if ($fichier === null)
|
||||||
|
{
|
||||||
|
Flash::definir("warning", "Aucune jaquette trouvée pour ce titre.");
|
||||||
|
Helpers::rediriger("/jeux/" . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->jeuService->modifier($id, $utilisateur["id"], array_merge($jeu, [
|
||||||
|
"jaquette" => $fichier,
|
||||||
|
"genres" => $jeu["genres"] ?? [],
|
||||||
|
"sourceEnrichissement" => ($jeu["sourceEnrichissement"] ?? "") === "manuel" ? "api" : ($jeu["sourceEnrichissement"] ?? "api")
|
||||||
|
]));
|
||||||
|
|
||||||
|
Flash::definir("success", "Jaquette récupérée depuis RAWG.");
|
||||||
|
Helpers::rediriger("/jeux/" . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function completerJaquetteSiAbsente(array $donnees): array
|
||||||
|
{
|
||||||
|
if (!Helpers::jaquetteAbsente($donnees["jaquette"] ?? null))
|
||||||
|
{
|
||||||
|
return $donnees;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->enrichissementService->estDisponible())
|
||||||
|
{
|
||||||
|
return $donnees;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fichier = $this->enrichissementService->recupererJaquetteParTitre($donnees["titre"] ?? "");
|
||||||
|
|
||||||
|
if ($fichier !== null)
|
||||||
|
{
|
||||||
|
$donnees["jaquette"] = $fichier;
|
||||||
|
|
||||||
|
if (($donnees["sourceEnrichissement"] ?? "manuel") === "manuel")
|
||||||
|
{
|
||||||
|
$donnees["sourceEnrichissement"] = "api";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $donnees;
|
||||||
|
}
|
||||||
|
|
||||||
private function collecterDonneesFormulaire(): array
|
private function collecterDonneesFormulaire(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
+21
-4
@@ -54,17 +54,34 @@ final class Helpers
|
|||||||
|
|
||||||
public static function urlJaquette(?string $chemin): string
|
public static function urlJaquette(?string $chemin): string
|
||||||
{
|
{
|
||||||
if ($chemin === null || $chemin === "")
|
if (self::jaquetteAbsente($chemin))
|
||||||
{
|
{
|
||||||
return "/assets/img/jaquette-manquante.svg";
|
return "/assets/img/jaquette-manquante.svg";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_starts_with($chemin, "http://") || str_starts_with($chemin, "https://"))
|
if (str_starts_with((string) $chemin, "http://") || str_starts_with((string) $chemin, "https://"))
|
||||||
{
|
{
|
||||||
return $chemin;
|
return (string) $chemin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "/jaquettes/" . ltrim($chemin, "/");
|
return "/jaquettes/" . ltrim((string) $chemin, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function jaquetteAbsente(?string $chemin): bool
|
||||||
|
{
|
||||||
|
if ($chemin === null || trim($chemin) === "")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($chemin, "http://") || str_starts_with($chemin, "https://"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fichier = Config::get("jaquettesPath") . "/" . basename($chemin);
|
||||||
|
|
||||||
|
return !is_file($fichier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function tronquer(string $texte, int $longueur = 140): string
|
public static function tronquer(string $texte, int $longueur = 140): string
|
||||||
|
|||||||
@@ -82,6 +82,50 @@ final class EnrichissementService
|
|||||||
return $detail;
|
return $detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cherche une jaquette RAWG pour un titre et la télécharge localement.
|
||||||
|
* Ne fait rien (retourne null) si l'API est indisponible ou aucun résultat.
|
||||||
|
*/
|
||||||
|
public function recupererJaquetteParTitre(string $titre): ?string
|
||||||
|
{
|
||||||
|
$titre = trim($titre);
|
||||||
|
|
||||||
|
if ($titre === "" || !$this->estDisponible())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resultats = $this->rechercher($titre, 5);
|
||||||
|
|
||||||
|
foreach ($resultats as $resultat)
|
||||||
|
{
|
||||||
|
$url = $resultat["jaquetteUrl"] ?? null;
|
||||||
|
|
||||||
|
if ($url === null || $url === "")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fichier = $this->telechargerJaquette($url);
|
||||||
|
|
||||||
|
if ($fichier !== null && !str_starts_with($fichier, "http"))
|
||||||
|
{
|
||||||
|
return $fichier;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fichier !== null)
|
||||||
|
{
|
||||||
|
return $fichier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Télécharge une image distante dans data/jaquettes/.
|
||||||
|
* En cas d'échec réseau, conserve l'URL distante comme repli.
|
||||||
|
*/
|
||||||
public function telechargerJaquette(?string $urlImage): ?string
|
public function telechargerJaquette(?string $urlImage): ?string
|
||||||
{
|
{
|
||||||
if ($urlImage === null || $urlImage === "")
|
if ($urlImage === null || $urlImage === "")
|
||||||
@@ -89,8 +133,15 @@ final class EnrichissementService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dossier = Config::get("jaquettesPath");
|
||||||
|
|
||||||
|
if (!is_dir($dossier))
|
||||||
|
{
|
||||||
|
mkdir($dossier, 0775, true);
|
||||||
|
}
|
||||||
|
|
||||||
$extension = pathinfo(parse_url($urlImage, PHP_URL_PATH) ?? "", PATHINFO_EXTENSION);
|
$extension = pathinfo(parse_url($urlImage, PHP_URL_PATH) ?? "", PATHINFO_EXTENSION);
|
||||||
$extension = $extension !== "" ? strtolower($extension) : "jpg";
|
$extension = $extension !== "" ? strtolower(explode("?", $extension)[0]) : "jpg";
|
||||||
|
|
||||||
if (!in_array($extension, ["jpg", "jpeg", "png", "webp", "gif"], true))
|
if (!in_array($extension, ["jpg", "jpeg", "png", "webp", "gif"], true))
|
||||||
{
|
{
|
||||||
@@ -98,18 +149,10 @@ final class EnrichissementService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$nomFichier = Helpers::genererId() . "." . $extension;
|
$nomFichier = Helpers::genererId() . "." . $extension;
|
||||||
$cheminLocal = Config::get("jaquettesPath") . "/" . $nomFichier;
|
$cheminLocal = $dossier . "/" . $nomFichier;
|
||||||
|
$contenu = $this->telechargerContenu($urlImage);
|
||||||
|
|
||||||
$contexte = stream_context_create([
|
if ($contenu === null || $contenu === "")
|
||||||
"http" => [
|
|
||||||
"timeout" => 10,
|
|
||||||
"header" => "User-Agent: JeuxVideoTech/1.0\r\n"
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$contenu = @file_get_contents($urlImage, false, $contexte);
|
|
||||||
|
|
||||||
if ($contenu === false)
|
|
||||||
{
|
{
|
||||||
return $urlImage;
|
return $urlImage;
|
||||||
}
|
}
|
||||||
@@ -122,6 +165,51 @@ final class EnrichissementService
|
|||||||
return $nomFichier;
|
return $nomFichier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function telechargerContenu(string $url): ?string
|
||||||
|
{
|
||||||
|
if (function_exists("curl_init"))
|
||||||
|
{
|
||||||
|
$curl = curl_init($url);
|
||||||
|
|
||||||
|
if ($curl !== false)
|
||||||
|
{
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_FOLLOWLOCATION => true,
|
||||||
|
CURLOPT_TIMEOUT => 15,
|
||||||
|
CURLOPT_USERAGENT => "JeuxVideoTech/1.0",
|
||||||
|
CURLOPT_SSL_VERIFYPEER => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contenu = curl_exec($curl);
|
||||||
|
$codeHttp = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
if ($contenu !== false && $codeHttp >= 200 && $codeHttp < 300)
|
||||||
|
{
|
||||||
|
return $contenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$contexte = stream_context_create([
|
||||||
|
"http" => [
|
||||||
|
"method" => "GET",
|
||||||
|
"timeout" => 15,
|
||||||
|
"follow_location" => 1,
|
||||||
|
"header" => "User-Agent: JeuxVideoTech/1.0\r\n"
|
||||||
|
],
|
||||||
|
"ssl" => [
|
||||||
|
"verify_peer" => true,
|
||||||
|
"verify_peer_name" => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contenu = @file_get_contents($url, false, $contexte);
|
||||||
|
|
||||||
|
return $contenu === false ? null : $contenu;
|
||||||
|
}
|
||||||
|
|
||||||
private function mapperResultatListe(array $jeu): array
|
private function mapperResultatListe(array $jeu): array
|
||||||
{
|
{
|
||||||
$genres = [];
|
$genres = [];
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ $router->post("/jeux/api/appliquer", [$jeuController, "appliquerEnrichissement"]
|
|||||||
$router->get("/jeux/{id}", [$jeuController, "detail"]);
|
$router->get("/jeux/{id}", [$jeuController, "detail"]);
|
||||||
$router->get("/jeux/{id}/modifier", [$jeuController, "modifier"]);
|
$router->get("/jeux/{id}/modifier", [$jeuController, "modifier"]);
|
||||||
$router->post("/jeux/{id}/modifier", [$jeuController, "modifier"]);
|
$router->post("/jeux/{id}/modifier", [$jeuController, "modifier"]);
|
||||||
|
$router->post("/jeux/{id}/jaquette", [$jeuController, "recupererJaquette"]);
|
||||||
$router->post("/jeux/{id}/supprimer", [$jeuController, "supprimer"]);
|
$router->post("/jeux/{id}/supprimer", [$jeuController, "supprimer"]);
|
||||||
|
|
||||||
$router->get("/admin/utilisateurs", [$adminController, "index"]);
|
$router->get("/admin/utilisateurs", [$adminController, "index"]);
|
||||||
|
|||||||
@@ -23,6 +23,14 @@
|
|||||||
<a href="/jeux/<?php print Helpers::echapper($jeu["id"]); ?>/modifier" class="btn btn-neon">
|
<a href="/jeux/<?php print Helpers::echapper($jeu["id"]); ?>/modifier" class="btn btn-neon">
|
||||||
<i class="mdi mdi-pencil"></i> Modifier
|
<i class="mdi mdi-pencil"></i> Modifier
|
||||||
</a>
|
</a>
|
||||||
|
<?php if (!empty($jaquetteAbsente) && !empty($apiDisponible)): ?>
|
||||||
|
<form method="post" action="/jeux/<?php print Helpers::echapper($jeu["id"]); ?>/jaquette">
|
||||||
|
<?php print Csrf::champCache(); ?>
|
||||||
|
<button type="submit" class="btn btn-outline-neon">
|
||||||
|
<i class="mdi mdi-image-search-outline"></i> Récupérer la jaquette
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
<form method="post" action="/jeux/<?php print Helpers::echapper($jeu["id"]); ?>/supprimer" onsubmit="return confirm('Supprimer ce jeu ?');">
|
<form method="post" action="/jeux/<?php print Helpers::echapper($jeu["id"]); ?>/supprimer" onsubmit="return confirm('Supprimer ce jeu ?');">
|
||||||
<?php print Csrf::champCache(); ?>
|
<?php print Csrf::champCache(); ?>
|
||||||
<button type="submit" class="btn btn-outline-danger">
|
<button type="submit" class="btn btn-outline-danger">
|
||||||
|
|||||||