<?php
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\CoreExtension;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;
use Twig\TemplateWrapper;
/* pages/livreDetail.html.twig */
class __TwigTemplate_c3889fffef3dd67a6c87a812f48f259c extends Template
{
private Source $source;
/**
* @var array<string, Template>
*/
private array $macros = [];
public function __construct(Environment $env)
{
parent::__construct($env);
$this->source = $this->getSourceContext();
$this->blocks = [
'body' => [$this, 'block_body'],
'javascripts' => [$this, 'block_javascripts'],
];
}
protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
{
// line 1
return "base.html.twig";
}
protected function doDisplay(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/livreDetail.html.twig"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/livreDetail.html.twig"));
$this->parent = $this->loadTemplate("base.html.twig", "pages/livreDetail.html.twig", 1);
yield from $this->parent->unwrap()->yield($context, array_merge($this->blocks, $blocks));
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
}
// line 3
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_body(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
// line 4
yield "<div class=\"container-fluid px-4\">
<!-- Bouton retour -->
<div class=\"mb-3\">
<a href=\"javascript:history.back()\" class=\"btn btn-outline-secondary btn-sm\">
<i class=\"fas fa-arrow-left\"></i> Retour
</a>
</div>
<!-- Card principale -->
<div class=\"card shadow-sm\">
<div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
<h4 class=\"mb-0 text-white\">
<i class=\"fas fa-book\"></i> ";
// line 16
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 16, $this->source); })()), "titre", [], "any", false, false, false, 16), "html", null, true);
yield "
";
// line 17
if ((CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 17, $this->source); })()), "tome", [], "any", false, false, false, 17) && (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 17, $this->source); })()), "tome", [], "any", false, false, false, 17) > 0))) {
// line 18
yield " <span class=\"badge badge-light ml-2\">Tome ";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 18, $this->source); })()), "tome", [], "any", false, false, false, 18), "html", null, true);
yield "</span>
";
}
// line 20
yield " </h4>
</div>
<div class=\"card-body\">
<div class=\"row\">
<!-- Colonne Image -->
<div class=\"col-md-4 text-center mb-4\">
<div class=\"livre-cover-container\">
<img id='img-";
// line 28
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 28, $this->source); })()), "id", [], "any", false, false, false, 28), "html", null, true);
yield "'
class=\"img-fluid rounded shadow\"
alt=\"";
// line 30
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 30, $this->source); })()), "titre", [], "any", false, false, false, 30), "html", null, true);
yield "\"
src=\"";
// line 31
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 31, $this->source); })()), "getBestImage", [], "any", false, false, false, 31), "html", null, true);
yield "\"
style=\"max-height: 400px; object-fit: contain;\" />
</div>
";
// line 35
if ($this->extensions['Symfony\Bridge\Twig\Extension\SecurityExtension']->isGranted("IS_AUTHENTICATED_FULLY")) {
// line 36
yield " <div class=\"mt-3\">
";
// line 37
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 37, $this->source); })()), "isbn", [], "any", false, false, false, 37)) {
// line 38
yield " <button type=\"button\" id=\"scrapeCoverBtn\" class=\"btn btn-primary btn-sm mb-2\" data-livre-id=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 38, $this->source); })()), "id", [], "any", false, false, false, 38), "html", null, true);
yield "\">
<i class=\"fas fa-magic\"></i> Scraper des images
</button>
<br>
";
}
// line 43
yield "
";
// line 44
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 44, $this->source); })()), "getImage2", [], "any", false, false, false, 44)) {
// line 45
yield " <span class=\"badge badge-info mb-2\"><i class=\"fas fa-link\"></i> Image externe</span>
<br>
<button type=\"button\" id=\"removeCoverUrlBtn\" class=\"btn btn-outline-danger btn-sm\">
<i class=\"fas fa-undo\"></i> Image originale
</button>
";
} else {
// line 51
yield " ";
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 51, $this->source); })()), "isbn", [], "any", false, false, false, 51)) {
// line 52
yield " <button type=\"button\" id=\"searchCoverBtn\" class=\"btn btn-outline-primary btn-sm\" data-livre-id=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 52, $this->source); })()), "id", [], "any", false, false, false, 52), "html", null, true);
yield "\">
<i class=\"fas fa-search\"></i> Chercher couverture
</button>
";
}
// line 56
yield " <button type=\"button\" id=\"manualUrlBtn\" class=\"btn btn-outline-secondary btn-sm\">
<i class=\"fas fa-link\"></i> URL manuelle
</button>
";
}
// line 60
yield "
<div id=\"coverSearchResult\" class=\"mt-2\" style=\"display: none;\">
<div id=\"coverPreview\" class=\"mb-2\"></div>
<button type=\"button\" id=\"applyCoverBtn\" class=\"btn btn-success btn-sm\" style=\"display: none;\">
<i class=\"fas fa-check\"></i> Utiliser
</button>
<span id=\"coverMessage\" class=\"text-muted\"></span>
</div>
<div id=\"manualUrlForm\" class=\"mt-3 text-left\" style=\"display: none;\">
<p class=\"small text-muted mb-2\">
Rechercher sur :
";
// line 72
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 72, $this->source); })()), "amazon", [], "any", false, false, false, 72)) {
// line 73
yield " <a href=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 73, $this->source); })()), "amazon", [], "any", false, false, false, 73), "html", null, true);
yield "\" target=\"_blank\" class=\"badge badge-warning\"><i class=\"fas fa-external-link-alt\"></i> Produit</a>
";
}
// line 75
yield " ";
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 75, $this->source); })()), "isbn", [], "any", false, false, false, 75)) {
// line 76
yield " <a href=\"https://www.amazon.fr/s?k=";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 76, $this->source); })()), "isbn", [], "any", false, false, false, 76), "html", null, true);
yield "\" target=\"_blank\" class=\"badge badge-secondary\">Amazon</a>
<a href=\"https://www.google.com/search?tbm=isch&q=";
// line 77
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 77, $this->source); })()), "isbn", [], "any", false, false, false, 77), "html", null, true);
yield "+couverture\" target=\"_blank\" class=\"badge badge-success\">Google</a>
";
}
// line 79
yield " </p>
<div class=\"input-group input-group-sm\">
<input type=\"url\" id=\"manualUrlInput\" class=\"form-control\" placeholder=\"URL de l'image...\">
<div class=\"input-group-append\">
<button type=\"button\" id=\"previewManualUrlBtn\" class=\"btn btn-primary\">
<i class=\"fas fa-eye\"></i>
</button>
</div>
</div>
<div id=\"manualPreview\" class=\"mt-2\"></div>
</div>
</div>
";
}
// line 92
yield " </div>
<!-- Colonne Informations -->
<div class=\"col-md-8\">
<!-- Auteurs -->
";
// line 97
if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 97, $this->source); })()), "listeAuteur", [], "any", false, false, false, 97)) > 0)) {
// line 98
yield " <div class=\"mb-3\">
<h6 class=\"text-muted mb-2\"><i class=\"fas fa-pen-fancy\"></i> Auteur(s)</h6>
<div>
";
// line 101
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 101, $this->source); })()), "listeAuteur", [], "any", false, false, false, 101));
foreach ($context['_seq'] as $context["_key"] => $context["auteur"]) {
// line 102
yield " <a href=\"";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("auteur_detail", ["id" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["auteur"], "auteur", [], "any", false, false, false, 102), "id", [], "any", false, false, false, 102)]), "html", null, true);
yield "\" class=\"badge badge-primary mr-1 mb-1\" style=\"font-size: 0.9rem;\">
";
// line 103
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["auteur"], "auteur", [], "any", false, false, false, 103), "nom", [], "any", false, false, false, 103), "html", null, true);
yield "
</a>
";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['auteur'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 106
yield " </div>
</div>
";
}
// line 109
yield "
<!-- Infos principales -->
<div class=\"row\">
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-building\"></i> Éditeur</small>
<strong>";
// line 115
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 115, $this->source); })()), "edition", [], "any", false, false, false, 115)) {
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 115, $this->source); })()), "edition", [], "any", false, false, false, 115), "nom", [], "any", false, false, false, 115), "html", null, true);
} else {
yield "-";
}
yield "</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-calendar\"></i> Année</small>
<strong>";
// line 121
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 121, $this->source); })()), "annee", [], "any", false, false, false, 121)) {
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 121, $this->source); })()), "annee", [], "any", false, false, false, 121), "html", null, true);
} else {
yield "-";
}
yield "</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-barcode\"></i> ISBN</small>
<strong>";
// line 127
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 127, $this->source); })()), "isbn", [], "any", false, false, false, 127)) {
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 127, $this->source); })()), "isbn", [], "any", false, false, false, 127), "html", null, true);
} else {
yield "-";
}
yield "</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-euro-sign\"></i> Prix</small>
<strong>";
// line 133
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 133, $this->source); })()), "prixBase", [], "any", false, false, false, 133), 2), "html", null, true);
yield " ";
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 133, $this->source); })()), "monnaie", [], "any", false, false, false, 133)) {
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 133, $this->source); })()), "monnaie", [], "any", false, false, false, 133), "symbole", [], "any", false, false, false, 133), "html", null, true);
}
yield "</strong>
</div>
</div>
";
// line 136
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 136, $this->source); })()), "collection", [], "any", false, false, false, 136)) {
// line 137
yield " <div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-layer-group\"></i> Collection</small>
<strong>";
// line 140
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 140, $this->source); })()), "collection", [], "any", false, false, false, 140), "nom", [], "any", false, false, false, 140), "html", null, true);
yield "</strong>
</div>
</div>
";
}
// line 144
yield " ";
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 144, $this->source); })()), "category", [], "any", false, false, false, 144)) {
// line 145
yield " <div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-tag\"></i> Catégorie</small>
<strong>";
// line 148
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 148, $this->source); })()), "category", [], "any", false, false, false, 148), "nom", [], "any", false, false, false, 148), "html", null, true);
yield "</strong>
</div>
</div>
";
}
// line 152
yield " ";
if ((CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 152, $this->source); })()), "pages", [], "any", false, false, false, 152) && (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 152, $this->source); })()), "pages", [], "any", false, false, false, 152) > 0))) {
// line 153
yield " <div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-file-alt\"></i> Pages</small>
<strong>";
// line 156
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 156, $this->source); })()), "pages", [], "any", false, false, false, 156), "html", null, true);
yield "</strong>
</div>
</div>
";
}
// line 160
yield " ";
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 160, $this->source); })()), "amazon", [], "any", false, false, false, 160)) {
// line 161
yield " <div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-external-link-alt\"></i> Lien</small>
<a href=\"";
// line 164
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 164, $this->source); })()), "amazon", [], "any", false, false, false, 164), "html", null, true);
yield "\" target=\"_blank\" class=\"btn btn-sm btn-outline-warning\">
<i class=\"fas fa-shopping-cart\"></i> Voir le produit
</a>
</div>
</div>
";
}
// line 170
yield " </div>
<!-- Synopsis -->
";
// line 173
if (CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 173, $this->source); })()), "resume", [], "any", false, false, false, 173)) {
// line 174
yield " <div class=\"mt-3\">
<h6 class=\"text-muted mb-2\"><i class=\"fas fa-align-left\"></i> Synopsis</h6>
<div class=\"bg-light p-3 rounded\" style=\"max-height: 200px; overflow-y: auto;\">
";
// line 177
yield Twig\Extension\CoreExtension::nl2br($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 177, $this->source); })()), "resume", [], "any", false, false, false, 177), "html", null, true));
yield "
</div>
</div>
";
}
// line 181
yield " </div>
</div>
</div>
</div>
<!-- Propriétaires -->
";
// line 187
if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 187, $this->source); })()), "listeUser", [], "any", false, false, false, 187)) > 0)) {
// line 188
yield " <div class=\"card mt-4 shadow-sm\">
<div class=\"card-header bg-dark text-white\">
<h5 class=\"mb-0\"><i class=\"fas fa-users\"></i> Propriétaires (";
// line 190
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 190, $this->source); })()), "listeUser", [], "any", false, false, false, 190)), "html", null, true);
yield ")</h5>
</div>
<div class=\"card-body p-0\">
<div class=\"table-responsive\">
<table class=\"table table-hover mb-0\">
<thead class=\"thead-light\">
<tr>
<th><i class=\"fas fa-user\"></i> Utilisateur</th>
<th><i class=\"fas fa-calendar-alt\"></i> Date d'acquisition</th>
<th><i class=\"fas fa-comment\"></i> Commentaire</th>
</tr>
</thead>
<tbody>
";
// line 203
$context['_parent'] = $context;
$context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 203, $this->source); })()), "listeUser", [], "any", false, false, false, 203));
foreach ($context['_seq'] as $context["_key"] => $context["lienuserLivre"]) {
// line 204
yield " <tr>
<td>
<strong>";
// line 206
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "user", [], "any", false, false, false, 206), "name", [], "any", false, false, false, 206), "html", null, true);
yield " ";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "user", [], "any", false, false, false, 206), "lastName", [], "any", false, false, false, 206), "html", null, true);
yield "</strong>
</td>
<td>
";
// line 209
if (CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "dateAchat", [], "any", false, false, false, 209)) {
// line 210
yield " ";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "dateAchat", [], "any", false, false, false, 210), "d/m/Y"), "html", null, true);
yield "
";
} else {
// line 212
yield " <span class=\"text-muted\">-</span>
";
}
// line 214
yield " </td>
<td>
";
// line 216
if (CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "commentaire", [], "any", false, false, false, 216)) {
// line 217
yield " ";
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "commentaire", [], "any", false, false, false, 217), "html", null, true);
yield "
";
} else {
// line 219
yield " <span class=\"text-muted\">-</span>
";
}
// line 221
yield " </td>
</tr>
";
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_key'], $context['lienuserLivre'], $context['_parent']);
$context = array_intersect_key($context, $_parent) + $_parent;
// line 224
yield " </tbody>
</table>
</div>
</div>
</div>
";
}
// line 230
yield "</div>
<!-- Modale de sélection d'images scrapées -->
<div class=\"modal fade\" id=\"scrapedImagesModal\" tabindex=\"-1\" role=\"dialog\">
<div class=\"modal-dialog modal-xl\" role=\"document\">
<div class=\"modal-content\">
<div class=\"modal-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
<h5 class=\"modal-title text-white\">
<i class=\"fas fa-images\"></i> Images trouvées
</h5>
<button type=\"button\" class=\"close text-white\" data-dismiss=\"modal\">
<span>×</span>
</button>
</div>
<div class=\"modal-body\">
<div id=\"scrapedImagesLoading\" class=\"text-center py-5\">
<i class=\"fas fa-spinner fa-spin fa-3x text-primary\"></i>
<p class=\"mt-3\">Recherche en cours sur BDGuest, Fnac, Decitre, Amazon...</p>
<small class=\"text-muted\">Cela peut prendre jusqu'à 2 minutes</small>
</div>
<div id=\"scrapedImagesContent\" style=\"display: none;\">
<p class=\"text-muted mb-3\">
<i class=\"fas fa-info-circle\"></i> Cliquez sur une image pour la sélectionner
</p>
<div id=\"scrapedImagesGrid\" class=\"row\"></div>
</div>
<div id=\"scrapedImagesError\" class=\"alert alert-warning\" style=\"display: none;\">
<i class=\"fas fa-exclamation-triangle\"></i> <span id=\"scrapedImagesErrorMsg\"></span>
</div>
</div>
</div>
</div>
</div>
<style>
.info-item {
padding: 10px;
background: #f8f9fa;
border-radius: 8px;
border-left: 3px solid #667eea;
}
.livre-cover-container {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 20px;
border-radius: 10px;
}
.scraped-image-card {
cursor: pointer;
transition: all 0.3s;
border: 3px solid transparent;
}
.scraped-image-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0,0,0,0.2);
}
.scraped-image-card.selected {
border-color: #667eea;
box-shadow: 0 0 20px rgba(102, 126, 234, 0.5);
}
.scraped-image-card img {
max-height: 300px;
object-fit: contain;
width: 100%;
}
</style>
";
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
// line 298
/**
* @return iterable<null|scalar|\Stringable>
*/
public function block_javascripts(array $context, array $blocks = []): iterable
{
$macros = $this->macros;
$__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
$__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
$__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
// line 299
yield " ";
yield from $this->yieldParentBlock("javascripts", $context, $blocks);
yield "
";
// line 300
if (($this->extensions['Symfony\Bridge\Twig\Extension\SecurityExtension']->isGranted("IS_AUTHENTICATED_FULLY") && CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 300, $this->source); })()), "isbn", [], "any", false, false, false, 300))) {
// line 301
yield " <script>
\$(document).ready(function() {
var foundImageUrl = null;
var livreId = ";
// line 304
yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["livre"]) || array_key_exists("livre", $context) ? $context["livre"] : (function () { throw new RuntimeError('Variable "livre" does not exist.', 304, $this->source); })()), "id", [], "any", false, false, false, 304), "html", null, true);
yield ";
\$('#searchCoverBtn').on('click', function() {
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Recherche en cours...');
\$('#coverSearchResult').show();
\$('#coverMessage').text('Recherche en cours...');
\$('#coverPreview').empty();
\$('#applyCoverBtn').hide();
\$('#manualUrlForm').hide();
\$.ajax({
url: '/livre/' + livreId + '/rechercher-couverture',
method: 'GET',
success: function(response) {
btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
if (response.success && response.images && response.images.length > 0) {
var html = '<p class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</p>';
html += '<div class=\"row\">';
response.images.forEach(function(img, index) {
html += '<div class=\"col-4 col-md-3 mb-2\">';
html += '<div class=\"card h-100\">';
html += '<img src=\"' + img.url + '\" class=\"card-img-top img-select-cover\" style=\"height: 120px; object-fit: contain; cursor: pointer;\" data-url=\"' + img.url + '\" alt=\"Option ' + (index+1) + '\" onerror=\"this.parentElement.parentElement.remove()\">';
html += '<div class=\"card-body p-1 text-center\"><small class=\"text-muted\">' + img.source + '</small></div>';
html += '</div></div>';
});
html += '</div>';
html += '<p class=\"small text-muted mt-2\">Cliquez sur une image pour la sélectionner</p>';
\$('#coverPreview').html(html);
} else {
\$('#coverMessage').html('<span class=\"text-warning\"><i class=\"fas fa-exclamation-triangle\"></i> ' + (response.message || 'Aucune image trouvée') + '</span>');
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
\$('#coverMessage').html('<span class=\"text-danger\"><i class=\"fas fa-times-circle\"></i> Erreur lors de la recherche</span>');
}
});
});
// Sélection d'une image dans la galerie
\$(document).on('click', '.img-select-cover', function() {
\$('.img-select-cover').removeClass('border-success').css('border-width', '1px');
\$(this).addClass('border-success').css('border-width', '3px');
foundImageUrl = \$(this).data('url');
\$('#applyCoverBtn').show();
});
\$('#applyCoverBtn').on('click', function() {
if (!foundImageUrl) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
\$.ajax({
url: '/livre/' + livreId + '/mettre-a-jour-couverture',
method: 'POST',
data: { image_url: foundImageUrl },
success: function(response) {
if (response.success) {
\$('#img-' + livreId).attr('src', response.imageUrl);
\$('#coverSearchResult').html('<span class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</span>');
setTimeout(function() { location.reload(); }, 1500);
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
\$('#coverMessage').html('<span class=\"text-danger\">' + response.message + '</span>');
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
\$('#coverMessage').html('<span class=\"text-danger\">Erreur lors de l\\'enregistrement</span>');
}
});
});
\$('#removeCoverUrlBtn').on('click', function() {
if (!confirm('Revenir à l\\'image originale stockée en base ?')) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Suppression...');
\$.ajax({
url: '/livre/' + livreId + '/supprimer-url-couverture',
method: 'POST',
success: function(response) {
if (response.success) {
location.reload();
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
alert(response.message);
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
alert('Erreur lors de la suppression');
}
});
});
// Saisie manuelle d'URL
\$('#manualUrlBtn').on('click', function() {
\$('#manualUrlForm').toggle();
\$('#coverSearchResult').hide();
});
\$('#previewManualUrlBtn').on('click', function() {
var url = \$('#manualUrlInput').val().trim();
if (!url) {
alert('Veuillez saisir une URL');
return;
}
foundImageUrl = url;
\$('#manualPreview').html(
'<img src=\"' + url + '\" class=\"img-thumbnail\" style=\"max-height: 200px;\" alt=\"Prévisualisation\" onerror=\"this.parentElement.innerHTML=\\'<span class=text-danger>Image non accessible</span>\\'\">' +
'<br><button type=\"button\" id=\"applyManualUrlBtn\" class=\"btn btn-success btn-sm mt-2\"><i class=\"fas fa-check\"></i> Utiliser cette image</button>'
);
});
\$(document).on('click', '#applyManualUrlBtn', function() {
if (!foundImageUrl) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
\$.ajax({
url: '/livre/' + livreId + '/mettre-a-jour-couverture',
method: 'POST',
data: { image_url: foundImageUrl },
success: function(response) {
if (response.success) {
location.reload();
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
alert(response.message);
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
alert('Erreur lors de l\\'enregistrement');
}
});
});
// Scraper des images via Puppeteer
\$('#scrapeCoverBtn').on('click', function() {
var livreId = \$(this).data('livre-id');
// Ouvrir la modale
\$('#scrapedImagesModal').modal('show');
// Réinitialiser l'état
\$('#scrapedImagesLoading').show();
\$('#scrapedImagesContent').hide();
\$('#scrapedImagesError').hide();
\$('#scrapedImagesGrid').empty();
// Appeler le contrôleur qui va appeler Puppeteer
\$.ajax({
url: '/livre/' + livreId + '/scrape-covers',
method: 'GET',
dataType: 'json',
timeout: 120000, // 2 minutes
success: function(response) {
\$('#scrapedImagesLoading').hide();
if (response.images && response.images.length > 0) {
\$('#scrapedImagesContent').show();
// Afficher les images
response.images.forEach(function(image) {
var card = \$('<div class=\"col-md-4 mb-3\">' +
'<div class=\"card scraped-image-card h-100\" data-image-url=\"' + image.url + '\">' +
'<div class=\"card-body text-center p-2\">' +
'<img src=\"' + image.url + '\" alt=\"Couverture\" class=\"img-fluid mb-2\" style=\"max-height: 300px; object-fit: contain;\">' +
'<div class=\"mb-2\">' +
'<span class=\"badge badge-primary\">' + image.source + '</span>' +
'<span class=\"badge badge-secondary ml-1\">' + image.quality + '</span>' +
'</div>' +
'<button class=\"btn btn-success btn-sm btn-block select-image-btn\">Utiliser</button>' +
'</div>' +
'</div>' +
'</div>');
\$('#scrapedImagesGrid').append(card);
});
// Gérer la sélection d'image
\$('.select-image-btn').on('click', function() {
var imageUrl = \$(this).closest('.scraped-image-card').data('image-url');
if (!confirm('Utiliser cette image comme couverture ?')) {
return;
}
// Marquer comme sélectionnée
\$('.scraped-image-card').removeClass('selected');
\$(this).closest('.scraped-image-card').addClass('selected');
\$(this).html('<i class=\"fas fa-spinner fa-spin\"></i>').prop('disabled', true);
// Enregistrer l'URL
\$.ajax({
url: '/livre/' + livreId + '/update-cover-url',
method: 'POST',
data: { imageUrl: imageUrl },
dataType: 'json',
success: function(response) {
if (response.success) {
\$('#scrapedImagesModal').modal('hide');
location.reload();
} else {
alert('Erreur: ' + (response.error || 'Erreur inconnue'));
\$('.select-image-btn').html('Utiliser').prop('disabled', false);
}
},
error: function(xhr) {
var errorMsg = 'Erreur lors de l\\'enregistrement de l\\'image';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = xhr.responseJSON.error;
}
alert(errorMsg);
\$('.select-image-btn').html('Utiliser').prop('disabled', false);
}
});
});
} else {
\$('#scrapedImagesError').show();
\$('#scrapedImagesErrorMsg').text('Aucune image trouvée sur BDGuest, Fnac, Decitre et Amazon pour l\\'ISBN ' + response.isbn);
}
},
error: function(xhr) {
\$('#scrapedImagesLoading').hide();
\$('#scrapedImagesError').show();
var errorMsg = 'Erreur lors de la recherche d\\'images. Le service Puppeteer est-il démarré ?';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = xhr.responseJSON.error;
}
\$('#scrapedImagesErrorMsg').text(errorMsg);
}
});
});
});
</script>
";
}
$__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
$__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
yield from [];
}
/**
* @codeCoverageIgnore
*/
public function getTemplateName(): string
{
return "pages/livreDetail.html.twig";
}
/**
* @codeCoverageIgnore
*/
public function isTraitable(): bool
{
return false;
}
/**
* @codeCoverageIgnore
*/
public function getDebugInfo(): array
{
return array ( 591 => 304, 586 => 301, 584 => 300, 579 => 299, 566 => 298, 489 => 230, 481 => 224, 473 => 221, 469 => 219, 463 => 217, 461 => 216, 457 => 214, 453 => 212, 447 => 210, 445 => 209, 437 => 206, 433 => 204, 429 => 203, 413 => 190, 409 => 188, 407 => 187, 399 => 181, 392 => 177, 387 => 174, 385 => 173, 380 => 170, 371 => 164, 366 => 161, 363 => 160, 356 => 156, 351 => 153, 348 => 152, 341 => 148, 336 => 145, 333 => 144, 326 => 140, 321 => 137, 319 => 136, 309 => 133, 296 => 127, 283 => 121, 270 => 115, 262 => 109, 257 => 106, 248 => 103, 243 => 102, 239 => 101, 234 => 98, 232 => 97, 225 => 92, 210 => 79, 205 => 77, 200 => 76, 197 => 75, 191 => 73, 189 => 72, 175 => 60, 169 => 56, 161 => 52, 158 => 51, 150 => 45, 148 => 44, 145 => 43, 136 => 38, 134 => 37, 131 => 36, 129 => 35, 122 => 31, 118 => 30, 113 => 28, 103 => 20, 97 => 18, 95 => 17, 91 => 16, 77 => 4, 64 => 3, 41 => 1,);
}
public function getSourceContext(): Source
{
return new Source("{% extends 'base.html.twig' %}
{% block body %}
<div class=\"container-fluid px-4\">
<!-- Bouton retour -->
<div class=\"mb-3\">
<a href=\"javascript:history.back()\" class=\"btn btn-outline-secondary btn-sm\">
<i class=\"fas fa-arrow-left\"></i> Retour
</a>
</div>
<!-- Card principale -->
<div class=\"card shadow-sm\">
<div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
<h4 class=\"mb-0 text-white\">
<i class=\"fas fa-book\"></i> {{ livre.titre }}
{% if livre.tome and livre.tome > 0 %}
<span class=\"badge badge-light ml-2\">Tome {{ livre.tome }}</span>
{% endif %}
</h4>
</div>
<div class=\"card-body\">
<div class=\"row\">
<!-- Colonne Image -->
<div class=\"col-md-4 text-center mb-4\">
<div class=\"livre-cover-container\">
<img id='img-{{ livre.id }}'
class=\"img-fluid rounded shadow\"
alt=\"{{ livre.titre }}\"
src=\"{{ livre.getBestImage }}\"
style=\"max-height: 400px; object-fit: contain;\" />
</div>
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
<div class=\"mt-3\">
{% if livre.isbn %}
<button type=\"button\" id=\"scrapeCoverBtn\" class=\"btn btn-primary btn-sm mb-2\" data-livre-id=\"{{ livre.id }}\">
<i class=\"fas fa-magic\"></i> Scraper des images
</button>
<br>
{% endif %}
{% if livre.getImage2 %}
<span class=\"badge badge-info mb-2\"><i class=\"fas fa-link\"></i> Image externe</span>
<br>
<button type=\"button\" id=\"removeCoverUrlBtn\" class=\"btn btn-outline-danger btn-sm\">
<i class=\"fas fa-undo\"></i> Image originale
</button>
{% else %}
{% if livre.isbn %}
<button type=\"button\" id=\"searchCoverBtn\" class=\"btn btn-outline-primary btn-sm\" data-livre-id=\"{{ livre.id }}\">
<i class=\"fas fa-search\"></i> Chercher couverture
</button>
{% endif %}
<button type=\"button\" id=\"manualUrlBtn\" class=\"btn btn-outline-secondary btn-sm\">
<i class=\"fas fa-link\"></i> URL manuelle
</button>
{% endif %}
<div id=\"coverSearchResult\" class=\"mt-2\" style=\"display: none;\">
<div id=\"coverPreview\" class=\"mb-2\"></div>
<button type=\"button\" id=\"applyCoverBtn\" class=\"btn btn-success btn-sm\" style=\"display: none;\">
<i class=\"fas fa-check\"></i> Utiliser
</button>
<span id=\"coverMessage\" class=\"text-muted\"></span>
</div>
<div id=\"manualUrlForm\" class=\"mt-3 text-left\" style=\"display: none;\">
<p class=\"small text-muted mb-2\">
Rechercher sur :
{% if livre.amazon %}
<a href=\"{{ livre.amazon }}\" target=\"_blank\" class=\"badge badge-warning\"><i class=\"fas fa-external-link-alt\"></i> Produit</a>
{% endif %}
{% if livre.isbn %}
<a href=\"https://www.amazon.fr/s?k={{ livre.isbn }}\" target=\"_blank\" class=\"badge badge-secondary\">Amazon</a>
<a href=\"https://www.google.com/search?tbm=isch&q={{ livre.isbn }}+couverture\" target=\"_blank\" class=\"badge badge-success\">Google</a>
{% endif %}
</p>
<div class=\"input-group input-group-sm\">
<input type=\"url\" id=\"manualUrlInput\" class=\"form-control\" placeholder=\"URL de l'image...\">
<div class=\"input-group-append\">
<button type=\"button\" id=\"previewManualUrlBtn\" class=\"btn btn-primary\">
<i class=\"fas fa-eye\"></i>
</button>
</div>
</div>
<div id=\"manualPreview\" class=\"mt-2\"></div>
</div>
</div>
{% endif %}
</div>
<!-- Colonne Informations -->
<div class=\"col-md-8\">
<!-- Auteurs -->
{% if livre.listeAuteur|length > 0 %}
<div class=\"mb-3\">
<h6 class=\"text-muted mb-2\"><i class=\"fas fa-pen-fancy\"></i> Auteur(s)</h6>
<div>
{% for auteur in livre.listeAuteur %}
<a href=\"{{ path('auteur_detail', {'id': auteur.auteur.id}) }}\" class=\"badge badge-primary mr-1 mb-1\" style=\"font-size: 0.9rem;\">
{{ auteur.auteur.nom }}
</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Infos principales -->
<div class=\"row\">
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-building\"></i> Éditeur</small>
<strong>{% if livre.edition %}{{ livre.edition.nom }}{% else %}-{% endif %}</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-calendar\"></i> Année</small>
<strong>{% if livre.annee %}{{ livre.annee }}{% else %}-{% endif %}</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-barcode\"></i> ISBN</small>
<strong>{% if livre.isbn %}{{ livre.isbn }}{% else %}-{% endif %}</strong>
</div>
</div>
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-euro-sign\"></i> Prix</small>
<strong>{{ livre.prixBase|number_format(2) }} {% if livre.monnaie %}{{ livre.monnaie.symbole }}{% endif %}</strong>
</div>
</div>
{% if livre.collection %}
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-layer-group\"></i> Collection</small>
<strong>{{ livre.collection.nom }}</strong>
</div>
</div>
{% endif %}
{% if livre.category %}
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-tag\"></i> Catégorie</small>
<strong>{{ livre.category.nom }}</strong>
</div>
</div>
{% endif %}
{% if livre.pages and livre.pages > 0 %}
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-file-alt\"></i> Pages</small>
<strong>{{ livre.pages }}</strong>
</div>
</div>
{% endif %}
{% if livre.amazon %}
<div class=\"col-sm-6\">
<div class=\"info-item mb-3\">
<small class=\"text-muted d-block\"><i class=\"fas fa-external-link-alt\"></i> Lien</small>
<a href=\"{{ livre.amazon }}\" target=\"_blank\" class=\"btn btn-sm btn-outline-warning\">
<i class=\"fas fa-shopping-cart\"></i> Voir le produit
</a>
</div>
</div>
{% endif %}
</div>
<!-- Synopsis -->
{% if livre.resume %}
<div class=\"mt-3\">
<h6 class=\"text-muted mb-2\"><i class=\"fas fa-align-left\"></i> Synopsis</h6>
<div class=\"bg-light p-3 rounded\" style=\"max-height: 200px; overflow-y: auto;\">
{{ livre.resume|nl2br }}
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Propriétaires -->
{% if livre.listeUser|length > 0 %}
<div class=\"card mt-4 shadow-sm\">
<div class=\"card-header bg-dark text-white\">
<h5 class=\"mb-0\"><i class=\"fas fa-users\"></i> Propriétaires ({{ livre.listeUser|length }})</h5>
</div>
<div class=\"card-body p-0\">
<div class=\"table-responsive\">
<table class=\"table table-hover mb-0\">
<thead class=\"thead-light\">
<tr>
<th><i class=\"fas fa-user\"></i> Utilisateur</th>
<th><i class=\"fas fa-calendar-alt\"></i> Date d'acquisition</th>
<th><i class=\"fas fa-comment\"></i> Commentaire</th>
</tr>
</thead>
<tbody>
{% for lienuserLivre in livre.listeUser %}
<tr>
<td>
<strong>{{ lienuserLivre.user.name }} {{ lienuserLivre.user.lastName }}</strong>
</td>
<td>
{% if lienuserLivre.dateAchat %}
{{ lienuserLivre.dateAchat|date('d/m/Y') }}
{% else %}
<span class=\"text-muted\">-</span>
{% endif %}
</td>
<td>
{% if lienuserLivre.commentaire %}
{{ lienuserLivre.commentaire }}
{% else %}
<span class=\"text-muted\">-</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
</div>
<!-- Modale de sélection d'images scrapées -->
<div class=\"modal fade\" id=\"scrapedImagesModal\" tabindex=\"-1\" role=\"dialog\">
<div class=\"modal-dialog modal-xl\" role=\"document\">
<div class=\"modal-content\">
<div class=\"modal-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
<h5 class=\"modal-title text-white\">
<i class=\"fas fa-images\"></i> Images trouvées
</h5>
<button type=\"button\" class=\"close text-white\" data-dismiss=\"modal\">
<span>×</span>
</button>
</div>
<div class=\"modal-body\">
<div id=\"scrapedImagesLoading\" class=\"text-center py-5\">
<i class=\"fas fa-spinner fa-spin fa-3x text-primary\"></i>
<p class=\"mt-3\">Recherche en cours sur BDGuest, Fnac, Decitre, Amazon...</p>
<small class=\"text-muted\">Cela peut prendre jusqu'à 2 minutes</small>
</div>
<div id=\"scrapedImagesContent\" style=\"display: none;\">
<p class=\"text-muted mb-3\">
<i class=\"fas fa-info-circle\"></i> Cliquez sur une image pour la sélectionner
</p>
<div id=\"scrapedImagesGrid\" class=\"row\"></div>
</div>
<div id=\"scrapedImagesError\" class=\"alert alert-warning\" style=\"display: none;\">
<i class=\"fas fa-exclamation-triangle\"></i> <span id=\"scrapedImagesErrorMsg\"></span>
</div>
</div>
</div>
</div>
</div>
<style>
.info-item {
padding: 10px;
background: #f8f9fa;
border-radius: 8px;
border-left: 3px solid #667eea;
}
.livre-cover-container {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 20px;
border-radius: 10px;
}
.scraped-image-card {
cursor: pointer;
transition: all 0.3s;
border: 3px solid transparent;
}
.scraped-image-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0,0,0,0.2);
}
.scraped-image-card.selected {
border-color: #667eea;
box-shadow: 0 0 20px rgba(102, 126, 234, 0.5);
}
.scraped-image-card img {
max-height: 300px;
object-fit: contain;
width: 100%;
}
</style>
{% endblock %}
{% block javascripts %}
{{ parent() }}
{% if is_granted('IS_AUTHENTICATED_FULLY') and livre.isbn %}
<script>
\$(document).ready(function() {
var foundImageUrl = null;
var livreId = {{ livre.id }};
\$('#searchCoverBtn').on('click', function() {
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Recherche en cours...');
\$('#coverSearchResult').show();
\$('#coverMessage').text('Recherche en cours...');
\$('#coverPreview').empty();
\$('#applyCoverBtn').hide();
\$('#manualUrlForm').hide();
\$.ajax({
url: '/livre/' + livreId + '/rechercher-couverture',
method: 'GET',
success: function(response) {
btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
if (response.success && response.images && response.images.length > 0) {
var html = '<p class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</p>';
html += '<div class=\"row\">';
response.images.forEach(function(img, index) {
html += '<div class=\"col-4 col-md-3 mb-2\">';
html += '<div class=\"card h-100\">';
html += '<img src=\"' + img.url + '\" class=\"card-img-top img-select-cover\" style=\"height: 120px; object-fit: contain; cursor: pointer;\" data-url=\"' + img.url + '\" alt=\"Option ' + (index+1) + '\" onerror=\"this.parentElement.parentElement.remove()\">';
html += '<div class=\"card-body p-1 text-center\"><small class=\"text-muted\">' + img.source + '</small></div>';
html += '</div></div>';
});
html += '</div>';
html += '<p class=\"small text-muted mt-2\">Cliquez sur une image pour la sélectionner</p>';
\$('#coverPreview').html(html);
} else {
\$('#coverMessage').html('<span class=\"text-warning\"><i class=\"fas fa-exclamation-triangle\"></i> ' + (response.message || 'Aucune image trouvée') + '</span>');
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
\$('#coverMessage').html('<span class=\"text-danger\"><i class=\"fas fa-times-circle\"></i> Erreur lors de la recherche</span>');
}
});
});
// Sélection d'une image dans la galerie
\$(document).on('click', '.img-select-cover', function() {
\$('.img-select-cover').removeClass('border-success').css('border-width', '1px');
\$(this).addClass('border-success').css('border-width', '3px');
foundImageUrl = \$(this).data('url');
\$('#applyCoverBtn').show();
});
\$('#applyCoverBtn').on('click', function() {
if (!foundImageUrl) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
\$.ajax({
url: '/livre/' + livreId + '/mettre-a-jour-couverture',
method: 'POST',
data: { image_url: foundImageUrl },
success: function(response) {
if (response.success) {
\$('#img-' + livreId).attr('src', response.imageUrl);
\$('#coverSearchResult').html('<span class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</span>');
setTimeout(function() { location.reload(); }, 1500);
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
\$('#coverMessage').html('<span class=\"text-danger\">' + response.message + '</span>');
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
\$('#coverMessage').html('<span class=\"text-danger\">Erreur lors de l\\'enregistrement</span>');
}
});
});
\$('#removeCoverUrlBtn').on('click', function() {
if (!confirm('Revenir à l\\'image originale stockée en base ?')) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Suppression...');
\$.ajax({
url: '/livre/' + livreId + '/supprimer-url-couverture',
method: 'POST',
success: function(response) {
if (response.success) {
location.reload();
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
alert(response.message);
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
alert('Erreur lors de la suppression');
}
});
});
// Saisie manuelle d'URL
\$('#manualUrlBtn').on('click', function() {
\$('#manualUrlForm').toggle();
\$('#coverSearchResult').hide();
});
\$('#previewManualUrlBtn').on('click', function() {
var url = \$('#manualUrlInput').val().trim();
if (!url) {
alert('Veuillez saisir une URL');
return;
}
foundImageUrl = url;
\$('#manualPreview').html(
'<img src=\"' + url + '\" class=\"img-thumbnail\" style=\"max-height: 200px;\" alt=\"Prévisualisation\" onerror=\"this.parentElement.innerHTML=\\'<span class=text-danger>Image non accessible</span>\\'\">' +
'<br><button type=\"button\" id=\"applyManualUrlBtn\" class=\"btn btn-success btn-sm mt-2\"><i class=\"fas fa-check\"></i> Utiliser cette image</button>'
);
});
\$(document).on('click', '#applyManualUrlBtn', function() {
if (!foundImageUrl) return;
var btn = \$(this);
btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
\$.ajax({
url: '/livre/' + livreId + '/mettre-a-jour-couverture',
method: 'POST',
data: { image_url: foundImageUrl },
success: function(response) {
if (response.success) {
location.reload();
} else {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
alert(response.message);
}
},
error: function() {
btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
alert('Erreur lors de l\\'enregistrement');
}
});
});
// Scraper des images via Puppeteer
\$('#scrapeCoverBtn').on('click', function() {
var livreId = \$(this).data('livre-id');
// Ouvrir la modale
\$('#scrapedImagesModal').modal('show');
// Réinitialiser l'état
\$('#scrapedImagesLoading').show();
\$('#scrapedImagesContent').hide();
\$('#scrapedImagesError').hide();
\$('#scrapedImagesGrid').empty();
// Appeler le contrôleur qui va appeler Puppeteer
\$.ajax({
url: '/livre/' + livreId + '/scrape-covers',
method: 'GET',
dataType: 'json',
timeout: 120000, // 2 minutes
success: function(response) {
\$('#scrapedImagesLoading').hide();
if (response.images && response.images.length > 0) {
\$('#scrapedImagesContent').show();
// Afficher les images
response.images.forEach(function(image) {
var card = \$('<div class=\"col-md-4 mb-3\">' +
'<div class=\"card scraped-image-card h-100\" data-image-url=\"' + image.url + '\">' +
'<div class=\"card-body text-center p-2\">' +
'<img src=\"' + image.url + '\" alt=\"Couverture\" class=\"img-fluid mb-2\" style=\"max-height: 300px; object-fit: contain;\">' +
'<div class=\"mb-2\">' +
'<span class=\"badge badge-primary\">' + image.source + '</span>' +
'<span class=\"badge badge-secondary ml-1\">' + image.quality + '</span>' +
'</div>' +
'<button class=\"btn btn-success btn-sm btn-block select-image-btn\">Utiliser</button>' +
'</div>' +
'</div>' +
'</div>');
\$('#scrapedImagesGrid').append(card);
});
// Gérer la sélection d'image
\$('.select-image-btn').on('click', function() {
var imageUrl = \$(this).closest('.scraped-image-card').data('image-url');
if (!confirm('Utiliser cette image comme couverture ?')) {
return;
}
// Marquer comme sélectionnée
\$('.scraped-image-card').removeClass('selected');
\$(this).closest('.scraped-image-card').addClass('selected');
\$(this).html('<i class=\"fas fa-spinner fa-spin\"></i>').prop('disabled', true);
// Enregistrer l'URL
\$.ajax({
url: '/livre/' + livreId + '/update-cover-url',
method: 'POST',
data: { imageUrl: imageUrl },
dataType: 'json',
success: function(response) {
if (response.success) {
\$('#scrapedImagesModal').modal('hide');
location.reload();
} else {
alert('Erreur: ' + (response.error || 'Erreur inconnue'));
\$('.select-image-btn').html('Utiliser').prop('disabled', false);
}
},
error: function(xhr) {
var errorMsg = 'Erreur lors de l\\'enregistrement de l\\'image';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = xhr.responseJSON.error;
}
alert(errorMsg);
\$('.select-image-btn').html('Utiliser').prop('disabled', false);
}
});
});
} else {
\$('#scrapedImagesError').show();
\$('#scrapedImagesErrorMsg').text('Aucune image trouvée sur BDGuest, Fnac, Decitre et Amazon pour l\\'ISBN ' + response.isbn);
}
},
error: function(xhr) {
\$('#scrapedImagesLoading').hide();
\$('#scrapedImagesError').show();
var errorMsg = 'Erreur lors de la recherche d\\'images. Le service Puppeteer est-il démarré ?';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg = xhr.responseJSON.error;
}
\$('#scrapedImagesErrorMsg').text(errorMsg);
}
});
});
});
</script>
{% endif %}
{% endblock %}", "pages/livreDetail.html.twig", "/home/jla23/project/DEV/Bdd-Books-DEV/templates/pages/livreDetail.html.twig");
}
}