- fix progressbar
- {slug} {chapterNumber} in Url
- activity toolbar
This commit is contained in:
Jérémy Guillot
2024-07-07 15:25:12 +02:00
parent 54c581b229
commit 4672886a67
15 changed files with 183 additions and 59 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Controller;
use App\Manager\Toolbar\Factory\ToolbarFactory;
use App\Manager\ToolbarManager;
use App\Message\DownloadChapter;
use App\Repository\ChapterRepository;
@@ -17,7 +18,7 @@ class ActivityController extends AbstractController
public function __construct(
private readonly Connection $connection,
private readonly ChapterRepository $chapterRepository,
private readonly ToolbarManager $toolbarManager
private readonly ToolbarFactory $toolbarFactory
)
{
@@ -38,7 +39,7 @@ class ActivityController extends AbstractController
return $this->render('activity/index.html.twig', [
'controller_name' => 'ActivityController',
'status' => $status,
'toolbarItems' => $this->toolbarManager->getToolbarItems(),
'toolbar' => $this->toolbarFactory->createToolbar('activity')->getGroups(),
]);
}

View File

@@ -49,13 +49,13 @@ class ImportController extends AbstractController
return $this->redirectToRoute('import_match');
} catch (FileException $e) {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Une erreur est survenue lors de l\'import du fichier.'
]);
}
} else {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Le fichier doit être au format CBZ.'
]);
}
@@ -79,7 +79,7 @@ class ImportController extends AbstractController
$metadata = $this->cbzService->extractMetadata($filePath, $originalFileName);
if($metadata['title'] === '' || is_null($metadata['title'])){
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Impossible de détecter le titre du manga.'
]);
return $this->redirectToRoute('app_manga_import');
@@ -108,10 +108,10 @@ class ImportController extends AbstractController
if(empty($mangas)) {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Aucun manga trouvé avec ce titre.'
]);
return $this->redirectToRoute('app_manga_new', ['query' => $metadata['title']]);
return $this->redirectToRoute('app_manga_search', ['query' => $metadata['title']]);
}
if ($request->isMethod('post')) {
@@ -142,7 +142,7 @@ class ImportController extends AbstractController
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
if (!$manga) {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Manga non trouvé.'
]);
return $this->redirectToRoute('app_manga_import');
@@ -151,7 +151,7 @@ class ImportController extends AbstractController
$filePath = $session->get('import_file_path');
if (!$filePath) {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Fichier d\'import non trouvé.'
]);
return $this->redirectToRoute('app_manga_import');
@@ -166,13 +166,13 @@ class ImportController extends AbstractController
$this->mangaImportService->importVolume($manga, (int)$volume, $filePath, $originalFileName);
} catch (\Exception $e) {
$this->notificationService->sendUpdate([
'type' => 'error',
'status' => 'error',
'message' => 'Erreur lors de l\'import : ' . $e->getMessage()
]);
}
$this->notificationService->sendUpdate([
'type' => 'success',
'status' => 'success',
'message' => 'Import confirmé avec succès.'
]);
@@ -187,7 +187,7 @@ class ImportController extends AbstractController
$session->remove('import_original_file_name');
$this->notificationService->sendUpdate([
'type' => 'info',
'status' => 'info',
'message' => 'Import refusé. Le fichier a été supprimé.'
]);
}

View File

@@ -84,6 +84,22 @@ class MangaController extends AbstractController
]);
}
#[Route('/manga/delete/{id}', name: 'app_manga_delete', methods: ['DELETE'])]
public function deleteManga(Manga $manga): JsonResponse
{
try {
foreach ($manga->getChapters() as $chapter) {
$this->entityManager->remove($chapter);
}
$this->entityManager->remove($manga);
$this->entityManager->flush();
return new JsonResponse(['success' => true]);
} catch (\Exception $e) {
return new JsonResponse(['success' => false, 'error' => 'Unable to delete manga.'], 500);
}
}
public function _chaptersByManga(int $id): Response
{
@@ -291,7 +307,7 @@ class MangaController extends AbstractController
]);
if (empty($volumeChapters)) {
$this->notificationService->sendUpdate(['error' => 'No chapters found for this volume.']);
$this->notificationService->sendUpdate(['status' => 'error', 'message' => 'No chapters found for this volume.']);
return new JsonResponse(['error' => 'No chapters found for this volume.'], 200);
}
@@ -309,13 +325,13 @@ class MangaController extends AbstractController
{
$chapter = $this->chapterRepository->find($chapterId);
if (!$chapter) {
$this->notificationService->sendUpdate(['error' => 'Chapitre non trouvé.']);
$this->notificationService->sendUpdate(['status' => 'error', 'message' => 'Chapitre non trouvé.']);
return new JsonResponse(['error' => 'Chapitre non trouvé.'], 200);
}
$cbzPath = $chapter->getCbzPath();
if (!$cbzPath || !file_exists($cbzPath)) {
$this->notificationService->sendUpdate(['error' => 'Le fichier CBZ n\'existe pas.']);
$this->notificationService->sendUpdate(['status' => 'error', 'message' => 'Le fichier CBZ n\'existe pas.']);
return new JsonResponse(['error' => 'Le fichier CBZ n\'existe pas.'], 200);
}
@@ -338,11 +354,11 @@ class MangaController extends AbstractController
]);
if (empty($volumeChapters)) {
$this->notificationService->sendUpdate(['error' => 'Aucun chapitre trouvé pour ce volume.']);
$this->notificationService->sendUpdate(['status' => 'error', 'message' => 'Aucun chapitre trouvé pour ce volume.']);
}
if (!$this->cbzService->doAllChaptersHaveCbz($volumeChapters)) {
$this->notificationService->sendUpdate(['error' => 'Tous les chapitres du volume ne sont pas scrapés.']);
$this->notificationService->sendUpdate(['status' => 'error', 'message' => 'Tous les chapitres du volume ne sont pas scrapés.']);
return new JsonResponse(['error' => 'Tous les chapitres du volume ne sont pas scrapés.'], 200);
}

View File

@@ -6,6 +6,7 @@ use App\Entity\ContentSource;
use App\Form\ContentSourceType;
use App\Repository\ContentSourceRepository;
use App\Service\MangaScraperService;
use App\Service\NotificationService;
use Doctrine\ORM\EntityManagerInterface;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -18,7 +19,8 @@ class SettingsController extends AbstractController
{
public function __construct(
private MangaScraperService $mangaScraperService,
private EntityManagerInterface $entityManager
private EntityManagerInterface $entityManager,
private NotificationService $notificationService
)
{
@@ -70,7 +72,7 @@ class SettingsController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($contentSource);
$this->entityManager->flush();
$this->addFlash('success', ($isNew ? 'New scrapper configuration saved' : 'Scrapper configuration updated') . ' successfully.');
$this->notificationService->sendUpdate(['status' => 'success', 'message' => ($isNew ? 'New scrapper configuration saved' : 'Scrapper configuration updated') . ' successfully.']);
return $this->redirectToRoute('app_settings_scrappers_list');
}
@@ -94,7 +96,15 @@ class SettingsController extends AbstractController
$mangaSlug = $request->request->get('mangaSlug');
$chapterNumber = $request->request->get('chapterNumber');
$scrapedData = $this->mangaScraperService->testScrapingHtml($mangaSlug, $chapterNumber, $contentSource);
try {
$scrapedData = $this->mangaScraperService->testScrapingHtml($mangaSlug, $chapterNumber, $contentSource);
}catch (\Exception $e){
$this->notificationService->sendUpdate(['status' => 'error', 'message' => $e->getMessage()]);
return new JsonResponse([
'success' => false,
'message' => $e->getMessage(),
]);
}
return new JsonResponse([
'success' => true,

View File

@@ -3,11 +3,16 @@
namespace App\Entity;
use App\Repository\ContentSourceRepository;
use App\Service\ChapterUrlGenerator;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ContentSourceRepository::class)]
class ContentSource
{
public function __construct()
{
}
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
@@ -83,7 +88,8 @@ class ContentSource
public function getChapterUrl(string $mangaTitle, float $chapterNumber): string
{
return sprintf($this->chapterUrlFormat, $mangaTitle, $chapterNumber);
$urlGenerator = new ChapterUrlGenerator($this->chapterUrlFormat);
return $urlGenerator->getChapterUrl($mangaTitle, $chapterNumber);
}
public function getScrapingType(): ?string

View File

@@ -66,7 +66,7 @@ class QueueStatusSubscriber implements EventSubscriberInterface
public function onPageScrapingProgress(PageScrappingProgressEvent $event): void
{
$data = [
'status' => 'Page scraping progress',
'status' => 'scrapping.progress',
'chapterId' => $event->getChapterId(),
'pageIndex' => $event->getPageIndex(),
'totalPages' => $event->getTotalPages(),

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Manager\Toolbar\Definition;
use App\Manager\Toolbar\Element\ToolbarButton;
use App\Manager\Toolbar\Element\ToolbarDivider;
class ActivityToolbar extends Toolbar
{
public function __construct(array $contextData = [])
{
$this
->addToLeftGroup(new ToolbarButton('arrows-rotate', 'Refresh', 'toolbar#refreshActivity'))
->addToLeftGroup(new ToolbarDivider())
->addToLeftGroup(new ToolbarButton('trash-can', 'Remove Selected', 'toolbar#removeActivity'))
->addToRightGroup(new ToolbarButton('th-large', 'Options', 'toolbar#optionActivity'))
;
}
}

View File

@@ -10,17 +10,17 @@ class ChapterListToolbar extends Toolbar
public function __construct(array $contextData = [])
{
$this
->addToLeftGroup(new ToolbarButton('arrows-rotate', 'Refresh metadata', 'refreshMetadata', $contextData))
->addToLeftGroup(new ToolbarButton('arrows-rotate', 'Refresh metadata', 'toolbar#refreshMetadata', $contextData))
->addToLeftGroup(new ToolbarDivider())
->addToLeftGroup(new ToolbarButton('keyboard', 'Rename chapters', 'renameChapters'))
->addToLeftGroup(new ToolbarButton('file-zipper', 'Manage cbz', 'manageCbz', $contextData))
->addToLeftGroup(new ToolbarButton('history', 'History', 'history', $contextData))
->addToLeftGroup(new ToolbarButton('keyboard', 'Rename chapters', 'toolbar#renameChapters'))
->addToLeftGroup(new ToolbarButton('file-zipper', 'Manage cbz', 'toolbar#manageCbz', $contextData))
->addToLeftGroup(new ToolbarButton('history', 'History', 'toolbar#history', $contextData))
->addToRightGroup(new ToolbarButton('bookmark', 'Monitoring', 'monitoring', $contextData))
->addToRightGroup(new ToolbarButton('wrench', 'Edit', 'editManga', $contextData))
->addToRightGroup(new ToolbarButton('trash-can', 'Delete', 'deleteManga', $contextData))
->addToRightGroup(new ToolbarButton('bookmark', 'Monitoring', 'toolbar#monitoring', $contextData))
->addToRightGroup(new ToolbarButton('wrench', 'Edit', 'toolbar#editManga', $contextData))
->addToRightGroup(new ToolbarButton('trash-can', 'Delete', 'toolbar#deleteManga', $contextData))
->addToRightGroup(new ToolbarDivider())
->addToRightGroup(new ToolbarButton('chevron-down', 'Expand all', 'expandAll'));
->addToRightGroup(new ToolbarButton('chevron-down', 'Expand all', 'toolbar#expandAll'));
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Manager\Toolbar\Factory;
use App\Manager\Toolbar\Definition\ActivityToolbar;
use App\Manager\Toolbar\Definition\ChapterListToolbar;
use App\Manager\Toolbar\Definition\MangaListToolbar;
use App\Manager\Toolbar\Definition\Toolbar;
@@ -13,6 +14,7 @@ class ToolbarFactory
return match ($type) {
'manga_list' => new MangaListToolbar(),
'chapter_list' => new ChapterListToolbar($context),
'activity' => new ActivityToolbar($context),
default => throw new \InvalidArgumentException("Unknown toolbar type: $type"),
};
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Service;
use Symfony\Component\HttpClient\Exception\InvalidArgumentException;
class ChapterUrlGenerator
{
private string $chapterUrlFormat;
public function __construct(string $chapterUrlFormat)
{
$this->chapterUrlFormat = $chapterUrlFormat;
$this->validateUrlFormat($chapterUrlFormat);
}
public function getChapterUrl(string $mangaTitle, float $chapterNumber): string
{
$placeholders = [
'{chapterNumber}' => $chapterNumber,
'{slug}' => $mangaTitle,
];
return str_replace(array_keys($placeholders), array_values($placeholders), $this->chapterUrlFormat);
}
private function validateUrlFormat(string $format): void
{
if (!str_contains($format, '{slug}') || !str_contains($format, '{chapterNumber}')) {
throw new InvalidArgumentException("The URL format must contain both {slug} and {chapterNumber} placeholders.");
}
}
}