var/cache/dev/twig/49/498d7eca4a0c8ecceb3cd872b12a222b.php line 44

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* pages/livreDetail.html.twig */
  16. class __TwigTemplate_c3889fffef3dd67a6c87a812f48f259c extends Template
  17. {
  18. private Source $source;
  19. /**
  20. * @var array<string, Template>
  21. */
  22. private array $macros = [];
  23. public function __construct(Environment $env)
  24. {
  25. parent::__construct($env);
  26. $this->source = $this->getSourceContext();
  27. $this->blocks = [
  28. 'body' => [$this, 'block_body'],
  29. 'javascripts' => [$this, 'block_javascripts'],
  30. ];
  31. }
  32. protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  33. {
  34. // line 1
  35. return "base.html.twig";
  36. }
  37. protected function doDisplay(array $context, array $blocks = []): iterable
  38. {
  39. $macros = $this->macros;
  40. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  41. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/livreDetail.html.twig"));
  42. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  43. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "pages/livreDetail.html.twig"));
  44. $this->parent = $this->loadTemplate("base.html.twig", "pages/livreDetail.html.twig", 1);
  45. yield from $this->parent->unwrap()->yield($context, array_merge($this->blocks, $blocks));
  46. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  47. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  48. }
  49. // line 3
  50. /**
  51. * @return iterable<null|scalar|\Stringable>
  52. */
  53. public function block_body(array $context, array $blocks = []): iterable
  54. {
  55. $macros = $this->macros;
  56. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  57. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
  58. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  59. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body"));
  60. // line 4
  61. yield "<div class=\"container-fluid px-4\">
  62. <!-- Bouton retour -->
  63. <div class=\"mb-3\">
  64. <a href=\"javascript:history.back()\" class=\"btn btn-outline-secondary btn-sm\">
  65. <i class=\"fas fa-arrow-left\"></i> Retour
  66. </a>
  67. </div>
  68. <!-- Card principale -->
  69. <div class=\"card shadow-sm\">
  70. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  71. <h4 class=\"mb-0 text-white\">
  72. <i class=\"fas fa-book\"></i> ";
  73. // line 16
  74. 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);
  75. yield "
  76. ";
  77. // line 17
  78. 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))) {
  79. // line 18
  80. yield " <span class=\"badge badge-light ml-2\">Tome ";
  81. 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);
  82. yield "</span>
  83. ";
  84. }
  85. // line 20
  86. yield " </h4>
  87. </div>
  88. <div class=\"card-body\">
  89. <div class=\"row\">
  90. <!-- Colonne Image -->
  91. <div class=\"col-md-4 text-center mb-4\">
  92. <div class=\"livre-cover-container\">
  93. <img id='img-";
  94. // line 28
  95. 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);
  96. yield "'
  97. class=\"img-fluid rounded shadow\"
  98. alt=\"";
  99. // line 30
  100. 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);
  101. yield "\"
  102. src=\"";
  103. // line 31
  104. 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);
  105. yield "\"
  106. style=\"max-height: 400px; object-fit: contain;\" />
  107. </div>
  108. ";
  109. // line 35
  110. if ($this->extensions['Symfony\Bridge\Twig\Extension\SecurityExtension']->isGranted("IS_AUTHENTICATED_FULLY")) {
  111. // line 36
  112. yield " <div class=\"mt-3\">
  113. ";
  114. // line 37
  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.', 37, $this->source); })()), "isbn", [], "any", false, false, false, 37)) {
  116. // line 38
  117. yield " <button type=\"button\" id=\"scrapeCoverBtn\" class=\"btn btn-primary btn-sm mb-2\" data-livre-id=\"";
  118. 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);
  119. yield "\">
  120. <i class=\"fas fa-magic\"></i> Scraper des images
  121. </button>
  122. <br>
  123. ";
  124. }
  125. // line 43
  126. yield "
  127. ";
  128. // line 44
  129. 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)) {
  130. // line 45
  131. yield " <span class=\"badge badge-info mb-2\"><i class=\"fas fa-link\"></i> Image externe</span>
  132. <br>
  133. <button type=\"button\" id=\"removeCoverUrlBtn\" class=\"btn btn-outline-danger btn-sm\">
  134. <i class=\"fas fa-undo\"></i> Image originale
  135. </button>
  136. ";
  137. } else {
  138. // line 51
  139. yield " ";
  140. 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)) {
  141. // line 52
  142. yield " <button type=\"button\" id=\"searchCoverBtn\" class=\"btn btn-outline-primary btn-sm\" data-livre-id=\"";
  143. 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);
  144. yield "\">
  145. <i class=\"fas fa-search\"></i> Chercher couverture
  146. </button>
  147. ";
  148. }
  149. // line 56
  150. yield " <button type=\"button\" id=\"manualUrlBtn\" class=\"btn btn-outline-secondary btn-sm\">
  151. <i class=\"fas fa-link\"></i> URL manuelle
  152. </button>
  153. ";
  154. }
  155. // line 60
  156. yield "
  157. <div id=\"coverSearchResult\" class=\"mt-2\" style=\"display: none;\">
  158. <div id=\"coverPreview\" class=\"mb-2\"></div>
  159. <button type=\"button\" id=\"applyCoverBtn\" class=\"btn btn-success btn-sm\" style=\"display: none;\">
  160. <i class=\"fas fa-check\"></i> Utiliser
  161. </button>
  162. <span id=\"coverMessage\" class=\"text-muted\"></span>
  163. </div>
  164. <div id=\"manualUrlForm\" class=\"mt-3 text-left\" style=\"display: none;\">
  165. <p class=\"small text-muted mb-2\">
  166. Rechercher sur :
  167. ";
  168. // line 72
  169. 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)) {
  170. // line 73
  171. yield " <a href=\"";
  172. 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);
  173. yield "\" target=\"_blank\" class=\"badge badge-warning\"><i class=\"fas fa-external-link-alt\"></i> Produit</a>
  174. ";
  175. }
  176. // line 75
  177. yield " ";
  178. 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)) {
  179. // line 76
  180. yield " <a href=\"https://www.amazon.fr/s?k=";
  181. 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);
  182. yield "\" target=\"_blank\" class=\"badge badge-secondary\">Amazon</a>
  183. <a href=\"https://www.google.com/search?tbm=isch&q=";
  184. // line 77
  185. 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);
  186. yield "+couverture\" target=\"_blank\" class=\"badge badge-success\">Google</a>
  187. ";
  188. }
  189. // line 79
  190. yield " </p>
  191. <div class=\"input-group input-group-sm\">
  192. <input type=\"url\" id=\"manualUrlInput\" class=\"form-control\" placeholder=\"URL de l'image...\">
  193. <div class=\"input-group-append\">
  194. <button type=\"button\" id=\"previewManualUrlBtn\" class=\"btn btn-primary\">
  195. <i class=\"fas fa-eye\"></i>
  196. </button>
  197. </div>
  198. </div>
  199. <div id=\"manualPreview\" class=\"mt-2\"></div>
  200. </div>
  201. </div>
  202. ";
  203. }
  204. // line 92
  205. yield " </div>
  206. <!-- Colonne Informations -->
  207. <div class=\"col-md-8\">
  208. <!-- Auteurs -->
  209. ";
  210. // line 97
  211. 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)) {
  212. // line 98
  213. yield " <div class=\"mb-3\">
  214. <h6 class=\"text-muted mb-2\"><i class=\"fas fa-pen-fancy\"></i> Auteur(s)</h6>
  215. <div>
  216. ";
  217. // line 101
  218. $context['_parent'] = $context;
  219. $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));
  220. foreach ($context['_seq'] as $context["_key"] => $context["auteur"]) {
  221. // line 102
  222. yield " <a href=\"";
  223. 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);
  224. yield "\" class=\"badge badge-primary mr-1 mb-1\" style=\"font-size: 0.9rem;\">
  225. ";
  226. // line 103
  227. 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);
  228. yield "
  229. </a>
  230. ";
  231. }
  232. $_parent = $context['_parent'];
  233. unset($context['_seq'], $context['_key'], $context['auteur'], $context['_parent']);
  234. $context = array_intersect_key($context, $_parent) + $_parent;
  235. // line 106
  236. yield " </div>
  237. </div>
  238. ";
  239. }
  240. // line 109
  241. yield "
  242. <!-- Infos principales -->
  243. <div class=\"row\">
  244. <div class=\"col-sm-6\">
  245. <div class=\"info-item mb-3\">
  246. <small class=\"text-muted d-block\"><i class=\"fas fa-building\"></i> Éditeur</small>
  247. <strong>";
  248. // line 115
  249. 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)) {
  250. 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);
  251. } else {
  252. yield "-";
  253. }
  254. yield "</strong>
  255. </div>
  256. </div>
  257. <div class=\"col-sm-6\">
  258. <div class=\"info-item mb-3\">
  259. <small class=\"text-muted d-block\"><i class=\"fas fa-calendar\"></i> Année</small>
  260. <strong>";
  261. // line 121
  262. 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)) {
  263. 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);
  264. } else {
  265. yield "-";
  266. }
  267. yield "</strong>
  268. </div>
  269. </div>
  270. <div class=\"col-sm-6\">
  271. <div class=\"info-item mb-3\">
  272. <small class=\"text-muted d-block\"><i class=\"fas fa-barcode\"></i> ISBN</small>
  273. <strong>";
  274. // line 127
  275. 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)) {
  276. 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);
  277. } else {
  278. yield "-";
  279. }
  280. yield "</strong>
  281. </div>
  282. </div>
  283. <div class=\"col-sm-6\">
  284. <div class=\"info-item mb-3\">
  285. <small class=\"text-muted d-block\"><i class=\"fas fa-euro-sign\"></i> Prix</small>
  286. <strong>";
  287. // line 133
  288. 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);
  289. yield " ";
  290. 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)) {
  291. 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);
  292. }
  293. yield "</strong>
  294. </div>
  295. </div>
  296. ";
  297. // line 136
  298. 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)) {
  299. // line 137
  300. yield " <div class=\"col-sm-6\">
  301. <div class=\"info-item mb-3\">
  302. <small class=\"text-muted d-block\"><i class=\"fas fa-layer-group\"></i> Collection</small>
  303. <strong>";
  304. // line 140
  305. 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);
  306. yield "</strong>
  307. </div>
  308. </div>
  309. ";
  310. }
  311. // line 144
  312. yield " ";
  313. 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)) {
  314. // line 145
  315. yield " <div class=\"col-sm-6\">
  316. <div class=\"info-item mb-3\">
  317. <small class=\"text-muted d-block\"><i class=\"fas fa-tag\"></i> Catégorie</small>
  318. <strong>";
  319. // line 148
  320. 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);
  321. yield "</strong>
  322. </div>
  323. </div>
  324. ";
  325. }
  326. // line 152
  327. yield " ";
  328. 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))) {
  329. // line 153
  330. yield " <div class=\"col-sm-6\">
  331. <div class=\"info-item mb-3\">
  332. <small class=\"text-muted d-block\"><i class=\"fas fa-file-alt\"></i> Pages</small>
  333. <strong>";
  334. // line 156
  335. 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);
  336. yield "</strong>
  337. </div>
  338. </div>
  339. ";
  340. }
  341. // line 160
  342. yield " ";
  343. 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)) {
  344. // line 161
  345. yield " <div class=\"col-sm-6\">
  346. <div class=\"info-item mb-3\">
  347. <small class=\"text-muted d-block\"><i class=\"fas fa-external-link-alt\"></i> Lien</small>
  348. <a href=\"";
  349. // line 164
  350. 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);
  351. yield "\" target=\"_blank\" class=\"btn btn-sm btn-outline-warning\">
  352. <i class=\"fas fa-shopping-cart\"></i> Voir le produit
  353. </a>
  354. </div>
  355. </div>
  356. ";
  357. }
  358. // line 170
  359. yield " </div>
  360. <!-- Synopsis -->
  361. ";
  362. // line 173
  363. 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)) {
  364. // line 174
  365. yield " <div class=\"mt-3\">
  366. <h6 class=\"text-muted mb-2\"><i class=\"fas fa-align-left\"></i> Synopsis</h6>
  367. <div class=\"bg-light p-3 rounded\" style=\"max-height: 200px; overflow-y: auto;\">
  368. ";
  369. // line 177
  370. 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));
  371. yield "
  372. </div>
  373. </div>
  374. ";
  375. }
  376. // line 181
  377. yield " </div>
  378. </div>
  379. </div>
  380. </div>
  381. <!-- Propriétaires -->
  382. ";
  383. // line 187
  384. 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)) {
  385. // line 188
  386. yield " <div class=\"card mt-4 shadow-sm\">
  387. <div class=\"card-header bg-dark text-white\">
  388. <h5 class=\"mb-0\"><i class=\"fas fa-users\"></i> Propriétaires (";
  389. // line 190
  390. 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);
  391. yield ")</h5>
  392. </div>
  393. <div class=\"card-body p-0\">
  394. <div class=\"table-responsive\">
  395. <table class=\"table table-hover mb-0\">
  396. <thead class=\"thead-light\">
  397. <tr>
  398. <th><i class=\"fas fa-user\"></i> Utilisateur</th>
  399. <th><i class=\"fas fa-calendar-alt\"></i> Date d'acquisition</th>
  400. <th><i class=\"fas fa-comment\"></i> Commentaire</th>
  401. </tr>
  402. </thead>
  403. <tbody>
  404. ";
  405. // line 203
  406. $context['_parent'] = $context;
  407. $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));
  408. foreach ($context['_seq'] as $context["_key"] => $context["lienuserLivre"]) {
  409. // line 204
  410. yield " <tr>
  411. <td>
  412. <strong>";
  413. // line 206
  414. 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);
  415. yield " ";
  416. 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);
  417. yield "</strong>
  418. </td>
  419. <td>
  420. ";
  421. // line 209
  422. if (CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "dateAchat", [], "any", false, false, false, 209)) {
  423. // line 210
  424. yield " ";
  425. 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);
  426. yield "
  427. ";
  428. } else {
  429. // line 212
  430. yield " <span class=\"text-muted\">-</span>
  431. ";
  432. }
  433. // line 214
  434. yield " </td>
  435. <td>
  436. ";
  437. // line 216
  438. if (CoreExtension::getAttribute($this->env, $this->source, $context["lienuserLivre"], "commentaire", [], "any", false, false, false, 216)) {
  439. // line 217
  440. yield " ";
  441. 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);
  442. yield "
  443. ";
  444. } else {
  445. // line 219
  446. yield " <span class=\"text-muted\">-</span>
  447. ";
  448. }
  449. // line 221
  450. yield " </td>
  451. </tr>
  452. ";
  453. }
  454. $_parent = $context['_parent'];
  455. unset($context['_seq'], $context['_key'], $context['lienuserLivre'], $context['_parent']);
  456. $context = array_intersect_key($context, $_parent) + $_parent;
  457. // line 224
  458. yield " </tbody>
  459. </table>
  460. </div>
  461. </div>
  462. </div>
  463. ";
  464. }
  465. // line 230
  466. yield "</div>
  467. <!-- Modale de sélection d'images scrapées -->
  468. <div class=\"modal fade\" id=\"scrapedImagesModal\" tabindex=\"-1\" role=\"dialog\">
  469. <div class=\"modal-dialog modal-xl\" role=\"document\">
  470. <div class=\"modal-content\">
  471. <div class=\"modal-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  472. <h5 class=\"modal-title text-white\">
  473. <i class=\"fas fa-images\"></i> Images trouvées
  474. </h5>
  475. <button type=\"button\" class=\"close text-white\" data-dismiss=\"modal\">
  476. <span>&times;</span>
  477. </button>
  478. </div>
  479. <div class=\"modal-body\">
  480. <div id=\"scrapedImagesLoading\" class=\"text-center py-5\">
  481. <i class=\"fas fa-spinner fa-spin fa-3x text-primary\"></i>
  482. <p class=\"mt-3\">Recherche en cours sur BDGuest, Fnac, Decitre, Amazon...</p>
  483. <small class=\"text-muted\">Cela peut prendre jusqu'à 2 minutes</small>
  484. </div>
  485. <div id=\"scrapedImagesContent\" style=\"display: none;\">
  486. <p class=\"text-muted mb-3\">
  487. <i class=\"fas fa-info-circle\"></i> Cliquez sur une image pour la sélectionner
  488. </p>
  489. <div id=\"scrapedImagesGrid\" class=\"row\"></div>
  490. </div>
  491. <div id=\"scrapedImagesError\" class=\"alert alert-warning\" style=\"display: none;\">
  492. <i class=\"fas fa-exclamation-triangle\"></i> <span id=\"scrapedImagesErrorMsg\"></span>
  493. </div>
  494. </div>
  495. </div>
  496. </div>
  497. </div>
  498. <style>
  499. .info-item {
  500. padding: 10px;
  501. background: #f8f9fa;
  502. border-radius: 8px;
  503. border-left: 3px solid #667eea;
  504. }
  505. .livre-cover-container {
  506. background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  507. padding: 20px;
  508. border-radius: 10px;
  509. }
  510. .scraped-image-card {
  511. cursor: pointer;
  512. transition: all 0.3s;
  513. border: 3px solid transparent;
  514. }
  515. .scraped-image-card:hover {
  516. transform: translateY(-5px);
  517. box-shadow: 0 8px 25px rgba(0,0,0,0.2);
  518. }
  519. .scraped-image-card.selected {
  520. border-color: #667eea;
  521. box-shadow: 0 0 20px rgba(102, 126, 234, 0.5);
  522. }
  523. .scraped-image-card img {
  524. max-height: 300px;
  525. object-fit: contain;
  526. width: 100%;
  527. }
  528. </style>
  529. ";
  530. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  531. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  532. yield from [];
  533. }
  534. // line 298
  535. /**
  536. * @return iterable<null|scalar|\Stringable>
  537. */
  538. public function block_javascripts(array $context, array $blocks = []): iterable
  539. {
  540. $macros = $this->macros;
  541. $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  542. $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
  543. $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  544. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "javascripts"));
  545. // line 299
  546. yield " ";
  547. yield from $this->yieldParentBlock("javascripts", $context, $blocks);
  548. yield "
  549. ";
  550. // line 300
  551. 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))) {
  552. // line 301
  553. yield " <script>
  554. \$(document).ready(function() {
  555. var foundImageUrl = null;
  556. var livreId = ";
  557. // line 304
  558. 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);
  559. yield ";
  560. \$('#searchCoverBtn').on('click', function() {
  561. var btn = \$(this);
  562. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Recherche en cours...');
  563. \$('#coverSearchResult').show();
  564. \$('#coverMessage').text('Recherche en cours...');
  565. \$('#coverPreview').empty();
  566. \$('#applyCoverBtn').hide();
  567. \$('#manualUrlForm').hide();
  568. \$.ajax({
  569. url: '/livre/' + livreId + '/rechercher-couverture',
  570. method: 'GET',
  571. success: function(response) {
  572. btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
  573. if (response.success && response.images && response.images.length > 0) {
  574. var html = '<p class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</p>';
  575. html += '<div class=\"row\">';
  576. response.images.forEach(function(img, index) {
  577. html += '<div class=\"col-4 col-md-3 mb-2\">';
  578. html += '<div class=\"card h-100\">';
  579. 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()\">';
  580. html += '<div class=\"card-body p-1 text-center\"><small class=\"text-muted\">' + img.source + '</small></div>';
  581. html += '</div></div>';
  582. });
  583. html += '</div>';
  584. html += '<p class=\"small text-muted mt-2\">Cliquez sur une image pour la sélectionner</p>';
  585. \$('#coverPreview').html(html);
  586. } else {
  587. \$('#coverMessage').html('<span class=\"text-warning\"><i class=\"fas fa-exclamation-triangle\"></i> ' + (response.message || 'Aucune image trouvée') + '</span>');
  588. }
  589. },
  590. error: function() {
  591. btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
  592. \$('#coverMessage').html('<span class=\"text-danger\"><i class=\"fas fa-times-circle\"></i> Erreur lors de la recherche</span>');
  593. }
  594. });
  595. });
  596. // Sélection d'une image dans la galerie
  597. \$(document).on('click', '.img-select-cover', function() {
  598. \$('.img-select-cover').removeClass('border-success').css('border-width', '1px');
  599. \$(this).addClass('border-success').css('border-width', '3px');
  600. foundImageUrl = \$(this).data('url');
  601. \$('#applyCoverBtn').show();
  602. });
  603. \$('#applyCoverBtn').on('click', function() {
  604. if (!foundImageUrl) return;
  605. var btn = \$(this);
  606. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
  607. \$.ajax({
  608. url: '/livre/' + livreId + '/mettre-a-jour-couverture',
  609. method: 'POST',
  610. data: { image_url: foundImageUrl },
  611. success: function(response) {
  612. if (response.success) {
  613. \$('#img-' + livreId).attr('src', response.imageUrl);
  614. \$('#coverSearchResult').html('<span class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</span>');
  615. setTimeout(function() { location.reload(); }, 1500);
  616. } else {
  617. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  618. \$('#coverMessage').html('<span class=\"text-danger\">' + response.message + '</span>');
  619. }
  620. },
  621. error: function() {
  622. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  623. \$('#coverMessage').html('<span class=\"text-danger\">Erreur lors de l\\'enregistrement</span>');
  624. }
  625. });
  626. });
  627. \$('#removeCoverUrlBtn').on('click', function() {
  628. if (!confirm('Revenir à l\\'image originale stockée en base ?')) return;
  629. var btn = \$(this);
  630. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Suppression...');
  631. \$.ajax({
  632. url: '/livre/' + livreId + '/supprimer-url-couverture',
  633. method: 'POST',
  634. success: function(response) {
  635. if (response.success) {
  636. location.reload();
  637. } else {
  638. btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
  639. alert(response.message);
  640. }
  641. },
  642. error: function() {
  643. btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
  644. alert('Erreur lors de la suppression');
  645. }
  646. });
  647. });
  648. // Saisie manuelle d'URL
  649. \$('#manualUrlBtn').on('click', function() {
  650. \$('#manualUrlForm').toggle();
  651. \$('#coverSearchResult').hide();
  652. });
  653. \$('#previewManualUrlBtn').on('click', function() {
  654. var url = \$('#manualUrlInput').val().trim();
  655. if (!url) {
  656. alert('Veuillez saisir une URL');
  657. return;
  658. }
  659. foundImageUrl = url;
  660. \$('#manualPreview').html(
  661. '<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>\\'\">' +
  662. '<br><button type=\"button\" id=\"applyManualUrlBtn\" class=\"btn btn-success btn-sm mt-2\"><i class=\"fas fa-check\"></i> Utiliser cette image</button>'
  663. );
  664. });
  665. \$(document).on('click', '#applyManualUrlBtn', function() {
  666. if (!foundImageUrl) return;
  667. var btn = \$(this);
  668. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
  669. \$.ajax({
  670. url: '/livre/' + livreId + '/mettre-a-jour-couverture',
  671. method: 'POST',
  672. data: { image_url: foundImageUrl },
  673. success: function(response) {
  674. if (response.success) {
  675. location.reload();
  676. } else {
  677. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  678. alert(response.message);
  679. }
  680. },
  681. error: function() {
  682. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  683. alert('Erreur lors de l\\'enregistrement');
  684. }
  685. });
  686. });
  687. // Scraper des images via Puppeteer
  688. \$('#scrapeCoverBtn').on('click', function() {
  689. var livreId = \$(this).data('livre-id');
  690. // Ouvrir la modale
  691. \$('#scrapedImagesModal').modal('show');
  692. // Réinitialiser l'état
  693. \$('#scrapedImagesLoading').show();
  694. \$('#scrapedImagesContent').hide();
  695. \$('#scrapedImagesError').hide();
  696. \$('#scrapedImagesGrid').empty();
  697. // Appeler le contrôleur qui va appeler Puppeteer
  698. \$.ajax({
  699. url: '/livre/' + livreId + '/scrape-covers',
  700. method: 'GET',
  701. dataType: 'json',
  702. timeout: 120000, // 2 minutes
  703. success: function(response) {
  704. \$('#scrapedImagesLoading').hide();
  705. if (response.images && response.images.length > 0) {
  706. \$('#scrapedImagesContent').show();
  707. // Afficher les images
  708. response.images.forEach(function(image) {
  709. var card = \$('<div class=\"col-md-4 mb-3\">' +
  710. '<div class=\"card scraped-image-card h-100\" data-image-url=\"' + image.url + '\">' +
  711. '<div class=\"card-body text-center p-2\">' +
  712. '<img src=\"' + image.url + '\" alt=\"Couverture\" class=\"img-fluid mb-2\" style=\"max-height: 300px; object-fit: contain;\">' +
  713. '<div class=\"mb-2\">' +
  714. '<span class=\"badge badge-primary\">' + image.source + '</span>' +
  715. '<span class=\"badge badge-secondary ml-1\">' + image.quality + '</span>' +
  716. '</div>' +
  717. '<button class=\"btn btn-success btn-sm btn-block select-image-btn\">Utiliser</button>' +
  718. '</div>' +
  719. '</div>' +
  720. '</div>');
  721. \$('#scrapedImagesGrid').append(card);
  722. });
  723. // Gérer la sélection d'image
  724. \$('.select-image-btn').on('click', function() {
  725. var imageUrl = \$(this).closest('.scraped-image-card').data('image-url');
  726. if (!confirm('Utiliser cette image comme couverture ?')) {
  727. return;
  728. }
  729. // Marquer comme sélectionnée
  730. \$('.scraped-image-card').removeClass('selected');
  731. \$(this).closest('.scraped-image-card').addClass('selected');
  732. \$(this).html('<i class=\"fas fa-spinner fa-spin\"></i>').prop('disabled', true);
  733. // Enregistrer l'URL
  734. \$.ajax({
  735. url: '/livre/' + livreId + '/update-cover-url',
  736. method: 'POST',
  737. data: { imageUrl: imageUrl },
  738. dataType: 'json',
  739. success: function(response) {
  740. if (response.success) {
  741. \$('#scrapedImagesModal').modal('hide');
  742. location.reload();
  743. } else {
  744. alert('Erreur: ' + (response.error || 'Erreur inconnue'));
  745. \$('.select-image-btn').html('Utiliser').prop('disabled', false);
  746. }
  747. },
  748. error: function(xhr) {
  749. var errorMsg = 'Erreur lors de l\\'enregistrement de l\\'image';
  750. if (xhr.responseJSON && xhr.responseJSON.error) {
  751. errorMsg = xhr.responseJSON.error;
  752. }
  753. alert(errorMsg);
  754. \$('.select-image-btn').html('Utiliser').prop('disabled', false);
  755. }
  756. });
  757. });
  758. } else {
  759. \$('#scrapedImagesError').show();
  760. \$('#scrapedImagesErrorMsg').text('Aucune image trouvée sur BDGuest, Fnac, Decitre et Amazon pour l\\'ISBN ' + response.isbn);
  761. }
  762. },
  763. error: function(xhr) {
  764. \$('#scrapedImagesLoading').hide();
  765. \$('#scrapedImagesError').show();
  766. var errorMsg = 'Erreur lors de la recherche d\\'images. Le service Puppeteer est-il démarré ?';
  767. if (xhr.responseJSON && xhr.responseJSON.error) {
  768. errorMsg = xhr.responseJSON.error;
  769. }
  770. \$('#scrapedImagesErrorMsg').text(errorMsg);
  771. }
  772. });
  773. });
  774. });
  775. </script>
  776. ";
  777. }
  778. $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  779. $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  780. yield from [];
  781. }
  782. /**
  783. * @codeCoverageIgnore
  784. */
  785. public function getTemplateName(): string
  786. {
  787. return "pages/livreDetail.html.twig";
  788. }
  789. /**
  790. * @codeCoverageIgnore
  791. */
  792. public function isTraitable(): bool
  793. {
  794. return false;
  795. }
  796. /**
  797. * @codeCoverageIgnore
  798. */
  799. public function getDebugInfo(): array
  800. {
  801. 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,);
  802. }
  803. public function getSourceContext(): Source
  804. {
  805. return new Source("{% extends 'base.html.twig' %}
  806. {% block body %}
  807. <div class=\"container-fluid px-4\">
  808. <!-- Bouton retour -->
  809. <div class=\"mb-3\">
  810. <a href=\"javascript:history.back()\" class=\"btn btn-outline-secondary btn-sm\">
  811. <i class=\"fas fa-arrow-left\"></i> Retour
  812. </a>
  813. </div>
  814. <!-- Card principale -->
  815. <div class=\"card shadow-sm\">
  816. <div class=\"card-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  817. <h4 class=\"mb-0 text-white\">
  818. <i class=\"fas fa-book\"></i> {{ livre.titre }}
  819. {% if livre.tome and livre.tome > 0 %}
  820. <span class=\"badge badge-light ml-2\">Tome {{ livre.tome }}</span>
  821. {% endif %}
  822. </h4>
  823. </div>
  824. <div class=\"card-body\">
  825. <div class=\"row\">
  826. <!-- Colonne Image -->
  827. <div class=\"col-md-4 text-center mb-4\">
  828. <div class=\"livre-cover-container\">
  829. <img id='img-{{ livre.id }}'
  830. class=\"img-fluid rounded shadow\"
  831. alt=\"{{ livre.titre }}\"
  832. src=\"{{ livre.getBestImage }}\"
  833. style=\"max-height: 400px; object-fit: contain;\" />
  834. </div>
  835. {% if is_granted('IS_AUTHENTICATED_FULLY') %}
  836. <div class=\"mt-3\">
  837. {% if livre.isbn %}
  838. <button type=\"button\" id=\"scrapeCoverBtn\" class=\"btn btn-primary btn-sm mb-2\" data-livre-id=\"{{ livre.id }}\">
  839. <i class=\"fas fa-magic\"></i> Scraper des images
  840. </button>
  841. <br>
  842. {% endif %}
  843. {% if livre.getImage2 %}
  844. <span class=\"badge badge-info mb-2\"><i class=\"fas fa-link\"></i> Image externe</span>
  845. <br>
  846. <button type=\"button\" id=\"removeCoverUrlBtn\" class=\"btn btn-outline-danger btn-sm\">
  847. <i class=\"fas fa-undo\"></i> Image originale
  848. </button>
  849. {% else %}
  850. {% if livre.isbn %}
  851. <button type=\"button\" id=\"searchCoverBtn\" class=\"btn btn-outline-primary btn-sm\" data-livre-id=\"{{ livre.id }}\">
  852. <i class=\"fas fa-search\"></i> Chercher couverture
  853. </button>
  854. {% endif %}
  855. <button type=\"button\" id=\"manualUrlBtn\" class=\"btn btn-outline-secondary btn-sm\">
  856. <i class=\"fas fa-link\"></i> URL manuelle
  857. </button>
  858. {% endif %}
  859. <div id=\"coverSearchResult\" class=\"mt-2\" style=\"display: none;\">
  860. <div id=\"coverPreview\" class=\"mb-2\"></div>
  861. <button type=\"button\" id=\"applyCoverBtn\" class=\"btn btn-success btn-sm\" style=\"display: none;\">
  862. <i class=\"fas fa-check\"></i> Utiliser
  863. </button>
  864. <span id=\"coverMessage\" class=\"text-muted\"></span>
  865. </div>
  866. <div id=\"manualUrlForm\" class=\"mt-3 text-left\" style=\"display: none;\">
  867. <p class=\"small text-muted mb-2\">
  868. Rechercher sur :
  869. {% if livre.amazon %}
  870. <a href=\"{{ livre.amazon }}\" target=\"_blank\" class=\"badge badge-warning\"><i class=\"fas fa-external-link-alt\"></i> Produit</a>
  871. {% endif %}
  872. {% if livre.isbn %}
  873. <a href=\"https://www.amazon.fr/s?k={{ livre.isbn }}\" target=\"_blank\" class=\"badge badge-secondary\">Amazon</a>
  874. <a href=\"https://www.google.com/search?tbm=isch&q={{ livre.isbn }}+couverture\" target=\"_blank\" class=\"badge badge-success\">Google</a>
  875. {% endif %}
  876. </p>
  877. <div class=\"input-group input-group-sm\">
  878. <input type=\"url\" id=\"manualUrlInput\" class=\"form-control\" placeholder=\"URL de l'image...\">
  879. <div class=\"input-group-append\">
  880. <button type=\"button\" id=\"previewManualUrlBtn\" class=\"btn btn-primary\">
  881. <i class=\"fas fa-eye\"></i>
  882. </button>
  883. </div>
  884. </div>
  885. <div id=\"manualPreview\" class=\"mt-2\"></div>
  886. </div>
  887. </div>
  888. {% endif %}
  889. </div>
  890. <!-- Colonne Informations -->
  891. <div class=\"col-md-8\">
  892. <!-- Auteurs -->
  893. {% if livre.listeAuteur|length > 0 %}
  894. <div class=\"mb-3\">
  895. <h6 class=\"text-muted mb-2\"><i class=\"fas fa-pen-fancy\"></i> Auteur(s)</h6>
  896. <div>
  897. {% for auteur in livre.listeAuteur %}
  898. <a href=\"{{ path('auteur_detail', {'id': auteur.auteur.id}) }}\" class=\"badge badge-primary mr-1 mb-1\" style=\"font-size: 0.9rem;\">
  899. {{ auteur.auteur.nom }}
  900. </a>
  901. {% endfor %}
  902. </div>
  903. </div>
  904. {% endif %}
  905. <!-- Infos principales -->
  906. <div class=\"row\">
  907. <div class=\"col-sm-6\">
  908. <div class=\"info-item mb-3\">
  909. <small class=\"text-muted d-block\"><i class=\"fas fa-building\"></i> Éditeur</small>
  910. <strong>{% if livre.edition %}{{ livre.edition.nom }}{% else %}-{% endif %}</strong>
  911. </div>
  912. </div>
  913. <div class=\"col-sm-6\">
  914. <div class=\"info-item mb-3\">
  915. <small class=\"text-muted d-block\"><i class=\"fas fa-calendar\"></i> Année</small>
  916. <strong>{% if livre.annee %}{{ livre.annee }}{% else %}-{% endif %}</strong>
  917. </div>
  918. </div>
  919. <div class=\"col-sm-6\">
  920. <div class=\"info-item mb-3\">
  921. <small class=\"text-muted d-block\"><i class=\"fas fa-barcode\"></i> ISBN</small>
  922. <strong>{% if livre.isbn %}{{ livre.isbn }}{% else %}-{% endif %}</strong>
  923. </div>
  924. </div>
  925. <div class=\"col-sm-6\">
  926. <div class=\"info-item mb-3\">
  927. <small class=\"text-muted d-block\"><i class=\"fas fa-euro-sign\"></i> Prix</small>
  928. <strong>{{ livre.prixBase|number_format(2) }} {% if livre.monnaie %}{{ livre.monnaie.symbole }}{% endif %}</strong>
  929. </div>
  930. </div>
  931. {% if livre.collection %}
  932. <div class=\"col-sm-6\">
  933. <div class=\"info-item mb-3\">
  934. <small class=\"text-muted d-block\"><i class=\"fas fa-layer-group\"></i> Collection</small>
  935. <strong>{{ livre.collection.nom }}</strong>
  936. </div>
  937. </div>
  938. {% endif %}
  939. {% if livre.category %}
  940. <div class=\"col-sm-6\">
  941. <div class=\"info-item mb-3\">
  942. <small class=\"text-muted d-block\"><i class=\"fas fa-tag\"></i> Catégorie</small>
  943. <strong>{{ livre.category.nom }}</strong>
  944. </div>
  945. </div>
  946. {% endif %}
  947. {% if livre.pages and livre.pages > 0 %}
  948. <div class=\"col-sm-6\">
  949. <div class=\"info-item mb-3\">
  950. <small class=\"text-muted d-block\"><i class=\"fas fa-file-alt\"></i> Pages</small>
  951. <strong>{{ livre.pages }}</strong>
  952. </div>
  953. </div>
  954. {% endif %}
  955. {% if livre.amazon %}
  956. <div class=\"col-sm-6\">
  957. <div class=\"info-item mb-3\">
  958. <small class=\"text-muted d-block\"><i class=\"fas fa-external-link-alt\"></i> Lien</small>
  959. <a href=\"{{ livre.amazon }}\" target=\"_blank\" class=\"btn btn-sm btn-outline-warning\">
  960. <i class=\"fas fa-shopping-cart\"></i> Voir le produit
  961. </a>
  962. </div>
  963. </div>
  964. {% endif %}
  965. </div>
  966. <!-- Synopsis -->
  967. {% if livre.resume %}
  968. <div class=\"mt-3\">
  969. <h6 class=\"text-muted mb-2\"><i class=\"fas fa-align-left\"></i> Synopsis</h6>
  970. <div class=\"bg-light p-3 rounded\" style=\"max-height: 200px; overflow-y: auto;\">
  971. {{ livre.resume|nl2br }}
  972. </div>
  973. </div>
  974. {% endif %}
  975. </div>
  976. </div>
  977. </div>
  978. </div>
  979. <!-- Propriétaires -->
  980. {% if livre.listeUser|length > 0 %}
  981. <div class=\"card mt-4 shadow-sm\">
  982. <div class=\"card-header bg-dark text-white\">
  983. <h5 class=\"mb-0\"><i class=\"fas fa-users\"></i> Propriétaires ({{ livre.listeUser|length }})</h5>
  984. </div>
  985. <div class=\"card-body p-0\">
  986. <div class=\"table-responsive\">
  987. <table class=\"table table-hover mb-0\">
  988. <thead class=\"thead-light\">
  989. <tr>
  990. <th><i class=\"fas fa-user\"></i> Utilisateur</th>
  991. <th><i class=\"fas fa-calendar-alt\"></i> Date d'acquisition</th>
  992. <th><i class=\"fas fa-comment\"></i> Commentaire</th>
  993. </tr>
  994. </thead>
  995. <tbody>
  996. {% for lienuserLivre in livre.listeUser %}
  997. <tr>
  998. <td>
  999. <strong>{{ lienuserLivre.user.name }} {{ lienuserLivre.user.lastName }}</strong>
  1000. </td>
  1001. <td>
  1002. {% if lienuserLivre.dateAchat %}
  1003. {{ lienuserLivre.dateAchat|date('d/m/Y') }}
  1004. {% else %}
  1005. <span class=\"text-muted\">-</span>
  1006. {% endif %}
  1007. </td>
  1008. <td>
  1009. {% if lienuserLivre.commentaire %}
  1010. {{ lienuserLivre.commentaire }}
  1011. {% else %}
  1012. <span class=\"text-muted\">-</span>
  1013. {% endif %}
  1014. </td>
  1015. </tr>
  1016. {% endfor %}
  1017. </tbody>
  1018. </table>
  1019. </div>
  1020. </div>
  1021. </div>
  1022. {% endif %}
  1023. </div>
  1024. <!-- Modale de sélection d'images scrapées -->
  1025. <div class=\"modal fade\" id=\"scrapedImagesModal\" tabindex=\"-1\" role=\"dialog\">
  1026. <div class=\"modal-dialog modal-xl\" role=\"document\">
  1027. <div class=\"modal-content\">
  1028. <div class=\"modal-header\" style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\">
  1029. <h5 class=\"modal-title text-white\">
  1030. <i class=\"fas fa-images\"></i> Images trouvées
  1031. </h5>
  1032. <button type=\"button\" class=\"close text-white\" data-dismiss=\"modal\">
  1033. <span>&times;</span>
  1034. </button>
  1035. </div>
  1036. <div class=\"modal-body\">
  1037. <div id=\"scrapedImagesLoading\" class=\"text-center py-5\">
  1038. <i class=\"fas fa-spinner fa-spin fa-3x text-primary\"></i>
  1039. <p class=\"mt-3\">Recherche en cours sur BDGuest, Fnac, Decitre, Amazon...</p>
  1040. <small class=\"text-muted\">Cela peut prendre jusqu'à 2 minutes</small>
  1041. </div>
  1042. <div id=\"scrapedImagesContent\" style=\"display: none;\">
  1043. <p class=\"text-muted mb-3\">
  1044. <i class=\"fas fa-info-circle\"></i> Cliquez sur une image pour la sélectionner
  1045. </p>
  1046. <div id=\"scrapedImagesGrid\" class=\"row\"></div>
  1047. </div>
  1048. <div id=\"scrapedImagesError\" class=\"alert alert-warning\" style=\"display: none;\">
  1049. <i class=\"fas fa-exclamation-triangle\"></i> <span id=\"scrapedImagesErrorMsg\"></span>
  1050. </div>
  1051. </div>
  1052. </div>
  1053. </div>
  1054. </div>
  1055. <style>
  1056. .info-item {
  1057. padding: 10px;
  1058. background: #f8f9fa;
  1059. border-radius: 8px;
  1060. border-left: 3px solid #667eea;
  1061. }
  1062. .livre-cover-container {
  1063. background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  1064. padding: 20px;
  1065. border-radius: 10px;
  1066. }
  1067. .scraped-image-card {
  1068. cursor: pointer;
  1069. transition: all 0.3s;
  1070. border: 3px solid transparent;
  1071. }
  1072. .scraped-image-card:hover {
  1073. transform: translateY(-5px);
  1074. box-shadow: 0 8px 25px rgba(0,0,0,0.2);
  1075. }
  1076. .scraped-image-card.selected {
  1077. border-color: #667eea;
  1078. box-shadow: 0 0 20px rgba(102, 126, 234, 0.5);
  1079. }
  1080. .scraped-image-card img {
  1081. max-height: 300px;
  1082. object-fit: contain;
  1083. width: 100%;
  1084. }
  1085. </style>
  1086. {% endblock %}
  1087. {% block javascripts %}
  1088. {{ parent() }}
  1089. {% if is_granted('IS_AUTHENTICATED_FULLY') and livre.isbn %}
  1090. <script>
  1091. \$(document).ready(function() {
  1092. var foundImageUrl = null;
  1093. var livreId = {{ livre.id }};
  1094. \$('#searchCoverBtn').on('click', function() {
  1095. var btn = \$(this);
  1096. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Recherche en cours...');
  1097. \$('#coverSearchResult').show();
  1098. \$('#coverMessage').text('Recherche en cours...');
  1099. \$('#coverPreview').empty();
  1100. \$('#applyCoverBtn').hide();
  1101. \$('#manualUrlForm').hide();
  1102. \$.ajax({
  1103. url: '/livre/' + livreId + '/rechercher-couverture',
  1104. method: 'GET',
  1105. success: function(response) {
  1106. btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
  1107. if (response.success && response.images && response.images.length > 0) {
  1108. var html = '<p class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</p>';
  1109. html += '<div class=\"row\">';
  1110. response.images.forEach(function(img, index) {
  1111. html += '<div class=\"col-4 col-md-3 mb-2\">';
  1112. html += '<div class=\"card h-100\">';
  1113. 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()\">';
  1114. html += '<div class=\"card-body p-1 text-center\"><small class=\"text-muted\">' + img.source + '</small></div>';
  1115. html += '</div></div>';
  1116. });
  1117. html += '</div>';
  1118. html += '<p class=\"small text-muted mt-2\">Cliquez sur une image pour la sélectionner</p>';
  1119. \$('#coverPreview').html(html);
  1120. } else {
  1121. \$('#coverMessage').html('<span class=\"text-warning\"><i class=\"fas fa-exclamation-triangle\"></i> ' + (response.message || 'Aucune image trouvée') + '</span>');
  1122. }
  1123. },
  1124. error: function() {
  1125. btn.prop('disabled', false).html('<i class=\"fas fa-search\"></i> Rechercher automatiquement');
  1126. \$('#coverMessage').html('<span class=\"text-danger\"><i class=\"fas fa-times-circle\"></i> Erreur lors de la recherche</span>');
  1127. }
  1128. });
  1129. });
  1130. // Sélection d'une image dans la galerie
  1131. \$(document).on('click', '.img-select-cover', function() {
  1132. \$('.img-select-cover').removeClass('border-success').css('border-width', '1px');
  1133. \$(this).addClass('border-success').css('border-width', '3px');
  1134. foundImageUrl = \$(this).data('url');
  1135. \$('#applyCoverBtn').show();
  1136. });
  1137. \$('#applyCoverBtn').on('click', function() {
  1138. if (!foundImageUrl) return;
  1139. var btn = \$(this);
  1140. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
  1141. \$.ajax({
  1142. url: '/livre/' + livreId + '/mettre-a-jour-couverture',
  1143. method: 'POST',
  1144. data: { image_url: foundImageUrl },
  1145. success: function(response) {
  1146. if (response.success) {
  1147. \$('#img-' + livreId).attr('src', response.imageUrl);
  1148. \$('#coverSearchResult').html('<span class=\"text-success\"><i class=\"fas fa-check-circle\"></i> ' + response.message + '</span>');
  1149. setTimeout(function() { location.reload(); }, 1500);
  1150. } else {
  1151. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  1152. \$('#coverMessage').html('<span class=\"text-danger\">' + response.message + '</span>');
  1153. }
  1154. },
  1155. error: function() {
  1156. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  1157. \$('#coverMessage').html('<span class=\"text-danger\">Erreur lors de l\\'enregistrement</span>');
  1158. }
  1159. });
  1160. });
  1161. \$('#removeCoverUrlBtn').on('click', function() {
  1162. if (!confirm('Revenir à l\\'image originale stockée en base ?')) return;
  1163. var btn = \$(this);
  1164. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Suppression...');
  1165. \$.ajax({
  1166. url: '/livre/' + livreId + '/supprimer-url-couverture',
  1167. method: 'POST',
  1168. success: function(response) {
  1169. if (response.success) {
  1170. location.reload();
  1171. } else {
  1172. btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
  1173. alert(response.message);
  1174. }
  1175. },
  1176. error: function() {
  1177. btn.prop('disabled', false).html('<i class=\"fas fa-undo\"></i> Revenir à l\\'image originale');
  1178. alert('Erreur lors de la suppression');
  1179. }
  1180. });
  1181. });
  1182. // Saisie manuelle d'URL
  1183. \$('#manualUrlBtn').on('click', function() {
  1184. \$('#manualUrlForm').toggle();
  1185. \$('#coverSearchResult').hide();
  1186. });
  1187. \$('#previewManualUrlBtn').on('click', function() {
  1188. var url = \$('#manualUrlInput').val().trim();
  1189. if (!url) {
  1190. alert('Veuillez saisir une URL');
  1191. return;
  1192. }
  1193. foundImageUrl = url;
  1194. \$('#manualPreview').html(
  1195. '<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>\\'\">' +
  1196. '<br><button type=\"button\" id=\"applyManualUrlBtn\" class=\"btn btn-success btn-sm mt-2\"><i class=\"fas fa-check\"></i> Utiliser cette image</button>'
  1197. );
  1198. });
  1199. \$(document).on('click', '#applyManualUrlBtn', function() {
  1200. if (!foundImageUrl) return;
  1201. var btn = \$(this);
  1202. btn.prop('disabled', true).html('<i class=\"fas fa-spinner fa-spin\"></i> Enregistrement...');
  1203. \$.ajax({
  1204. url: '/livre/' + livreId + '/mettre-a-jour-couverture',
  1205. method: 'POST',
  1206. data: { image_url: foundImageUrl },
  1207. success: function(response) {
  1208. if (response.success) {
  1209. location.reload();
  1210. } else {
  1211. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  1212. alert(response.message);
  1213. }
  1214. },
  1215. error: function() {
  1216. btn.prop('disabled', false).html('<i class=\"fas fa-check\"></i> Utiliser cette image');
  1217. alert('Erreur lors de l\\'enregistrement');
  1218. }
  1219. });
  1220. });
  1221. // Scraper des images via Puppeteer
  1222. \$('#scrapeCoverBtn').on('click', function() {
  1223. var livreId = \$(this).data('livre-id');
  1224. // Ouvrir la modale
  1225. \$('#scrapedImagesModal').modal('show');
  1226. // Réinitialiser l'état
  1227. \$('#scrapedImagesLoading').show();
  1228. \$('#scrapedImagesContent').hide();
  1229. \$('#scrapedImagesError').hide();
  1230. \$('#scrapedImagesGrid').empty();
  1231. // Appeler le contrôleur qui va appeler Puppeteer
  1232. \$.ajax({
  1233. url: '/livre/' + livreId + '/scrape-covers',
  1234. method: 'GET',
  1235. dataType: 'json',
  1236. timeout: 120000, // 2 minutes
  1237. success: function(response) {
  1238. \$('#scrapedImagesLoading').hide();
  1239. if (response.images && response.images.length > 0) {
  1240. \$('#scrapedImagesContent').show();
  1241. // Afficher les images
  1242. response.images.forEach(function(image) {
  1243. var card = \$('<div class=\"col-md-4 mb-3\">' +
  1244. '<div class=\"card scraped-image-card h-100\" data-image-url=\"' + image.url + '\">' +
  1245. '<div class=\"card-body text-center p-2\">' +
  1246. '<img src=\"' + image.url + '\" alt=\"Couverture\" class=\"img-fluid mb-2\" style=\"max-height: 300px; object-fit: contain;\">' +
  1247. '<div class=\"mb-2\">' +
  1248. '<span class=\"badge badge-primary\">' + image.source + '</span>' +
  1249. '<span class=\"badge badge-secondary ml-1\">' + image.quality + '</span>' +
  1250. '</div>' +
  1251. '<button class=\"btn btn-success btn-sm btn-block select-image-btn\">Utiliser</button>' +
  1252. '</div>' +
  1253. '</div>' +
  1254. '</div>');
  1255. \$('#scrapedImagesGrid').append(card);
  1256. });
  1257. // Gérer la sélection d'image
  1258. \$('.select-image-btn').on('click', function() {
  1259. var imageUrl = \$(this).closest('.scraped-image-card').data('image-url');
  1260. if (!confirm('Utiliser cette image comme couverture ?')) {
  1261. return;
  1262. }
  1263. // Marquer comme sélectionnée
  1264. \$('.scraped-image-card').removeClass('selected');
  1265. \$(this).closest('.scraped-image-card').addClass('selected');
  1266. \$(this).html('<i class=\"fas fa-spinner fa-spin\"></i>').prop('disabled', true);
  1267. // Enregistrer l'URL
  1268. \$.ajax({
  1269. url: '/livre/' + livreId + '/update-cover-url',
  1270. method: 'POST',
  1271. data: { imageUrl: imageUrl },
  1272. dataType: 'json',
  1273. success: function(response) {
  1274. if (response.success) {
  1275. \$('#scrapedImagesModal').modal('hide');
  1276. location.reload();
  1277. } else {
  1278. alert('Erreur: ' + (response.error || 'Erreur inconnue'));
  1279. \$('.select-image-btn').html('Utiliser').prop('disabled', false);
  1280. }
  1281. },
  1282. error: function(xhr) {
  1283. var errorMsg = 'Erreur lors de l\\'enregistrement de l\\'image';
  1284. if (xhr.responseJSON && xhr.responseJSON.error) {
  1285. errorMsg = xhr.responseJSON.error;
  1286. }
  1287. alert(errorMsg);
  1288. \$('.select-image-btn').html('Utiliser').prop('disabled', false);
  1289. }
  1290. });
  1291. });
  1292. } else {
  1293. \$('#scrapedImagesError').show();
  1294. \$('#scrapedImagesErrorMsg').text('Aucune image trouvée sur BDGuest, Fnac, Decitre et Amazon pour l\\'ISBN ' + response.isbn);
  1295. }
  1296. },
  1297. error: function(xhr) {
  1298. \$('#scrapedImagesLoading').hide();
  1299. \$('#scrapedImagesError').show();
  1300. var errorMsg = 'Erreur lors de la recherche d\\'images. Le service Puppeteer est-il démarré ?';
  1301. if (xhr.responseJSON && xhr.responseJSON.error) {
  1302. errorMsg = xhr.responseJSON.error;
  1303. }
  1304. \$('#scrapedImagesErrorMsg').text(errorMsg);
  1305. }
  1306. });
  1307. });
  1308. });
  1309. </script>
  1310. {% endif %}
  1311. {% endblock %}", "pages/livreDetail.html.twig", "/home/jla23/project/DEV/Bdd-Books-DEV/templates/pages/livreDetail.html.twig");
  1312. }
  1313. }