Added:
- manga import - read from cbz - save cbz from scrapping - menu interactions
This commit is contained in:
18
src/Controller/CalendarController.php
Normal file
18
src/Controller/CalendarController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class CalendarController extends AbstractController
|
||||
{
|
||||
#[Route('/calendar', name: 'app_calendar')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('calendar/index.html.twig', [
|
||||
'controller_name' => 'CalendarController',
|
||||
]);
|
||||
}
|
||||
}
|
||||
197
src/Controller/ImportController.php
Normal file
197
src/Controller/ImportController.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\ChapterRepository;
|
||||
use App\Repository\MangaRepository;
|
||||
use App\Service\CbzService;
|
||||
use App\Service\MangaImportService;
|
||||
use App\Service\NotificationService;
|
||||
use Exception;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
|
||||
class ImportController extends AbstractController
|
||||
{
|
||||
private const UPLOADS_DIRECTORY = 'public/uploads';
|
||||
|
||||
public function __construct(
|
||||
private readonly string $projectDir,
|
||||
private readonly CbzService $cbzService,
|
||||
private readonly MangaImportService $mangaImportService,
|
||||
// private SluggerInterface $slugger,
|
||||
private NotificationService $notificationService,
|
||||
private MangaRepository $mangaRepository,
|
||||
private ChapterRepository $chapterRepository
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#[Route('/import', name: 'app_import')]
|
||||
public function index(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
if ($request->isMethod('post')) {
|
||||
$file = $request->files->get('file');
|
||||
if ($file && $file->getClientOriginalExtension() === 'cbz') {
|
||||
$originalFileName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$filename = uniqid() . '.' . $file->getClientOriginalExtension();
|
||||
|
||||
try {
|
||||
$file->move($this->projectDir . '/' . self::UPLOADS_DIRECTORY, $filename);
|
||||
$session->set('import_file_path', $this->projectDir . '/' .self::UPLOADS_DIRECTORY . '/' . $filename);
|
||||
$session->set('import_original_file_name', $originalFileName);
|
||||
return $this->redirectToRoute('import_match');
|
||||
} catch (FileException $e) {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Une erreur est survenue lors de l\'import du fichier.'
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Le fichier doit être au format CBZ.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('import/index.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route('/import/match', name: 'import_match')]
|
||||
public function match(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
$filePath = $session->get('import_file_path');
|
||||
$originalFileName = $session->get('import_original_file_name');
|
||||
if (!$filePath || !$originalFileName) {
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
|
||||
$metadata = $this->cbzService->extractMetadata($filePath, $originalFileName);
|
||||
if($metadata['title'] === '' || is_null($metadata['title'])){
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Impossible de détecter le titre du manga.'
|
||||
]);
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
|
||||
$mangas = $this->mangaRepository->findBySlug($metadata['title']);
|
||||
|
||||
$mangasChapters = [];
|
||||
foreach ($mangas as $manga) {
|
||||
if(!is_null($metadata['chapter'])){
|
||||
$chapters = $this->chapterRepository->findBy([
|
||||
'manga' => $manga,
|
||||
'number' => $metadata['chapter']
|
||||
]);
|
||||
$chapters = [$chapters[0]->getVolume() => $chapters];
|
||||
}else{
|
||||
$chapters = $this->chapterRepository->findBy([
|
||||
'manga' => $manga,
|
||||
'volume' => (int) $metadata['volume']
|
||||
]);
|
||||
|
||||
$chapters = [$metadata['volume'] => $chapters];
|
||||
}
|
||||
$mangasChapters[$manga->getSlug()] = $chapters;
|
||||
}
|
||||
|
||||
if(empty($mangas)) {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Aucun manga trouvé avec ce titre.'
|
||||
]);
|
||||
return $this->redirectToRoute('app_manga_new', ['query' => $metadata['title']]);
|
||||
}
|
||||
|
||||
if ($request->isMethod('post')) {
|
||||
$session->set('import_metadata', $request->request->all());
|
||||
return $this->redirectToRoute('import_confirm');
|
||||
}
|
||||
|
||||
return $this->render('import/match.html.twig', [
|
||||
'mangas' => $mangas,
|
||||
'volume' => $metadata['volume'],
|
||||
'chapters' => $mangasChapters
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/import/confirm', name: 'import_confirm')]
|
||||
public function confirm(Request $request, SessionInterface $session): Response
|
||||
{
|
||||
if (!$request->isMethod('POST')) {
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
|
||||
$action = $request->request->get('action');
|
||||
$mangaSlug = $request->request->get('manga_slug');
|
||||
$volume = $request->request->get('volume');
|
||||
|
||||
if ($action === 'confirm') {
|
||||
// Logique de confirmation
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
if (!$manga) {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Manga non trouvé.'
|
||||
]);
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
|
||||
$filePath = $session->get('import_file_path');
|
||||
if (!$filePath) {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Fichier d\'import non trouvé.'
|
||||
]);
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
$originalFileName = $session->get('import_original_file_name');
|
||||
|
||||
// Ici, vous pouvez ajouter la logique pour importer effectivement le fichier
|
||||
// Par exemple :
|
||||
// $this->mangaImportService->importVolume($manga, $volume, $filePath);
|
||||
|
||||
try {
|
||||
$this->mangaImportService->importVolume($manga, (int)$volume, $filePath, $originalFileName);
|
||||
} catch (\Exception $e) {
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'error',
|
||||
'message' => 'Erreur lors de l\'import : ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'success',
|
||||
'message' => 'Import confirmé avec succès.'
|
||||
]);
|
||||
|
||||
return $this->redirectToRoute('app_manga_show', ['mangaSlug' => $mangaSlug]);
|
||||
} elseif ($action === 'refuse') {
|
||||
// Logique de refus
|
||||
$filePath = $session->get('import_file_path');
|
||||
if ($filePath && file_exists($filePath)) {
|
||||
unlink($filePath); // Supprime le fichier temporaire
|
||||
}
|
||||
$session->remove('import_file_path');
|
||||
$session->remove('import_original_file_name');
|
||||
|
||||
$this->notificationService->sendUpdate([
|
||||
'type' => 'info',
|
||||
'message' => 'Import refusé. Le fichier a été supprimé.'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_import');
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use App\Entity\Manga;
|
||||
use App\Message\DownloadChapter;
|
||||
use App\Repository\ChapterRepository;
|
||||
use App\Repository\MangaRepository;
|
||||
use App\Service\CbzService;
|
||||
use App\Service\MangaExportService;
|
||||
use App\Service\LelScansProviderService;
|
||||
use App\Service\MangaScraperServiceOld;
|
||||
@@ -19,19 +20,20 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\String\Slugger\AsciiSlugger;
|
||||
|
||||
class MangaController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly MangaScraperServiceOld $mangaScraperService,
|
||||
private readonly MangaExportService $mangaExportService,
|
||||
private readonly LelScansProviderService $mangaProviderService,
|
||||
private readonly MangaRepository $mangaRepository,
|
||||
private ChapterRepository $chapterRepository,
|
||||
private MangaUpdatesMetadataProvider $mangaUpdatesDbProvider,
|
||||
private MessageBusInterface $bus
|
||||
private readonly MangaScraperServiceOld $mangaScraperService,
|
||||
private readonly MangaExportService $mangaExportService,
|
||||
private readonly LelScansProviderService $mangaProviderService,
|
||||
private readonly MangaRepository $mangaRepository,
|
||||
private readonly ChapterRepository $chapterRepository,
|
||||
private readonly MangaUpdatesMetadataProvider $mangaUpdatesDbProvider,
|
||||
private readonly MessageBusInterface $bus,
|
||||
private readonly CbzService $cbzService
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -39,6 +41,7 @@ class MangaController extends AbstractController
|
||||
#[Route('/manga', name: 'app_manga')]
|
||||
public function index(): Response
|
||||
{
|
||||
// phpinfo();
|
||||
$mangas = $this->mangaRepository->findAll();
|
||||
return $this->render('manga/index.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
@@ -49,7 +52,7 @@ class MangaController extends AbstractController
|
||||
/**
|
||||
* @throws NonUniqueResultException
|
||||
*/
|
||||
#[Route('/manga/{mangaSlug}', name: 'manga_show')]
|
||||
#[Route('/manga/chapters/{mangaSlug}', name: 'app_manga_show')]
|
||||
public function showChapters(string $mangaSlug): Response
|
||||
{
|
||||
// $manga = $this->mangaRepository->findOneWithChapterBy(['slug' => $mangaSlug]);
|
||||
@@ -88,8 +91,8 @@ class MangaController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/manga/{mangaSlug}/{chapterNumber}/{pageNumber}', name: 'read_chapter_page')]
|
||||
public function readChapterPage(string $mangaSlug, float $chapterNumber, int $pageNumber = 0): Response
|
||||
#[Route('/manga/read/{mangaSlug}/{chapterNumber}/{pageNumber}', name: 'app_manga_read')]
|
||||
public function readChapterPage(string $mangaSlug, float $chapterNumber, int $pageNumber = 1): Response
|
||||
{
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
if (!$manga) {
|
||||
@@ -101,20 +104,37 @@ class MangaController extends AbstractController
|
||||
throw $this->createNotFoundException("Le chapitre demandé n'existe pas.");
|
||||
}
|
||||
|
||||
$currentPage = $chapter->getPageByNumber($pageNumber);
|
||||
if (!$currentPage) {
|
||||
if (is_null($chapter->getCbzPath())) {
|
||||
$currentPage = $chapter->getPageByNumber($pageNumber);
|
||||
if (!$currentPage) {
|
||||
throw $this->createNotFoundException("La page demandée n'existe pas.");
|
||||
}
|
||||
|
||||
return $this->render('manga/manga_reader.html.twig', [
|
||||
'manga' => $manga,
|
||||
'chapter' => $chapter,
|
||||
'pages' => $chapter->getPagesLink(),
|
||||
'currentPage' => $currentPage,
|
||||
]);
|
||||
}
|
||||
|
||||
$pageContent = $this->cbzService->getPageContent($chapter->getCbzPath(), $pageNumber);
|
||||
if (!$pageContent) {
|
||||
throw $this->createNotFoundException("La page demandée n'existe pas.");
|
||||
}
|
||||
|
||||
$totalPages = $this->cbzService->getPageCount($chapter->getCbzPath());
|
||||
|
||||
return $this->render('manga/manga_reader.html.twig', [
|
||||
'manga' => $manga,
|
||||
'chapter' => $chapter,
|
||||
'pages' => $chapter->getPagesLink(),
|
||||
'currentPage' => $currentPage,
|
||||
'currentPage' => $pageNumber,
|
||||
'totalPages' => $totalPages,
|
||||
'pageContent' => base64_encode($pageContent),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/addNew/{query}', name: 'add_new_manga')]
|
||||
#[Route('/manga/new/{query}', name: 'app_manga_new')]
|
||||
public function addNew(string $query = ''): Response
|
||||
{
|
||||
return $this->render('manga/add_new.html.twig', [
|
||||
@@ -137,7 +157,7 @@ class MangaController extends AbstractController
|
||||
$chapter = $this->chapterRepository->find($id);
|
||||
if (!$chapter) {
|
||||
return new JsonResponse(['error' => 'Chapter Not Found.'], 400);
|
||||
} elseif ($chapter->getLocalPath() !== null) {
|
||||
} elseif ($chapter->getCbzPath() !== null) {
|
||||
return new JsonResponse(['error' => 'Chapter already scraped.'], 400);
|
||||
}
|
||||
|
||||
@@ -198,7 +218,7 @@ class MangaController extends AbstractController
|
||||
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
|
||||
return $this->redirectToRoute('manga_show', ['mangaSlug' => $mangaSlug, 'availableChapters' => $availableChapters]);
|
||||
return $this->redirectToRoute('app_manga_show', ['mangaSlug' => $mangaSlug, 'availableChapters' => $availableChapters]);
|
||||
}
|
||||
|
||||
#[Route('/manga/exportFrom/{mangaSlug}/{chapterNumber}', name: 'manga_export')]
|
||||
|
||||
50
src/Controller/SettingsController.php
Normal file
50
src/Controller/SettingsController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class SettingsController extends AbstractController
|
||||
{
|
||||
#[Route('/settings', name: 'app_settings')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('settings/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/settings/general', name: 'app_settings_general')]
|
||||
public function general(): Response
|
||||
{
|
||||
return $this->render('settings/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/settings/folders', name: 'app_settings_folders')]
|
||||
public function folders(): Response
|
||||
{
|
||||
return $this->render('settings/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/settings/scrappers', name: 'app_settings_scrappers')]
|
||||
public function scrappers(): Response
|
||||
{
|
||||
return $this->render('settings/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/settings/ui', name: 'app_settings_ui')]
|
||||
public function ui(): Response
|
||||
{
|
||||
return $this->render('settings/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
}
|
||||
50
src/Controller/SystemController.php
Normal file
50
src/Controller/SystemController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class SystemController extends AbstractController
|
||||
{
|
||||
#[Route('/system', name: 'app_system')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('system/index.html.twig', [
|
||||
'controller_name' => 'SystemController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/system/status', name: 'app_system_status')]
|
||||
public function status(): Response
|
||||
{
|
||||
return $this->render('system/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/system/backup', name: 'app_system_backup')]
|
||||
public function backup(): Response
|
||||
{
|
||||
return $this->render('system/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/system/logs', name: 'app_system_logs')]
|
||||
public function logs(): Response
|
||||
{
|
||||
return $this->render('system/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/system/updates', name: 'app_system_updates')]
|
||||
public function update(): Response
|
||||
{
|
||||
return $this->render('system/index.html.twig', [
|
||||
'controller_name' => 'SettingsController',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user