- début refonte graphique
- début MangaDbProvider
This commit is contained in:
@@ -7,203 +7,227 @@ use App\Repository\MangaRepository;
|
||||
use App\Service\MangaExportService;
|
||||
use App\Service\LelScansProviderService;
|
||||
use App\Service\MangaScraperService;
|
||||
use App\Service\MangaUpdatesDbProvider;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\String\Slugger\AsciiSlugger;
|
||||
|
||||
class MangaController extends AbstractController
|
||||
{
|
||||
private MangaScraperService $mangaScraperService;
|
||||
private MangaExportService $mangaExportService;
|
||||
private LelScansProviderService $mangaProviderService;
|
||||
private MangaRepository $mangaRepository;
|
||||
|
||||
public function __construct(MangaScraperService $mangaScraperService, MangaExportService $mangaExportService, LelScansProviderService $mangaProviderService, MangaRepository $mangaRepository)
|
||||
{
|
||||
$this->mangaScraperService = $mangaScraperService;
|
||||
$this->mangaExportService = $mangaExportService;
|
||||
$this->mangaProviderService = $mangaProviderService;
|
||||
$this->mangaRepository = $mangaRepository;
|
||||
}
|
||||
public function __construct(
|
||||
private readonly MangaScraperService $mangaScraperService,
|
||||
private readonly MangaExportService $mangaExportService,
|
||||
private readonly LelScansProviderService $mangaProviderService,
|
||||
private readonly MangaRepository $mangaRepository,
|
||||
private MangaUpdatesDbProvider $mangaUpdatesDbProvider
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
#[Route('/manga', name: 'app_manga')]
|
||||
public function index(): Response
|
||||
{
|
||||
// $this->breadcrumbs->addItem("Accueil", $this->generateUrl("app_manga"));
|
||||
// $this->breadcrumbs->addItem("Mangas", $this->generateUrl("manga_show"));
|
||||
|
||||
$mangas = $this->mangaRepository->findAll();
|
||||
$mangas = $this->mangaRepository->findAll();
|
||||
return $this->render('manga/index.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
'mangas' => $mangas,
|
||||
'mangas' => $mangas,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/manga/{mangaSlug}', name: 'manga_show')]
|
||||
public function showChapters(string $mangaSlug): Response
|
||||
{
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
#[Route('/manga/{mangaSlug}', name: 'manga_show')]
|
||||
public function showChapters(string $mangaSlug): Response
|
||||
{
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
|
||||
if (!$manga) {
|
||||
$manga = new Manga();
|
||||
$manga->setSlug($mangaSlug);
|
||||
$manga->setTitle($this->slugToTitle($mangaSlug));
|
||||
$this->mangaRepository->save($manga, true);
|
||||
}
|
||||
if (!$manga) {
|
||||
throw new NotFoundHttpException("Le manga demandé n'existe pas.");
|
||||
}
|
||||
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
|
||||
return $this->render('manga/show_chapters.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
'manga' => $manga,
|
||||
'availableChapters' => $availableChapters,
|
||||
]);
|
||||
}
|
||||
return $this->render('manga/show_chapters.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
'manga' => $manga,
|
||||
'availableChapters' => $availableChapters,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/manga/{mangaSlug}/{chapterNumber}/{pageNumber}', name: 'read_chapter_page')]
|
||||
public function readChapterPage(string $mangaSlug, float $chapterNumber, int $pageNumber = 0): Response
|
||||
{
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
if (!$manga) {
|
||||
throw $this->createNotFoundException("Le manga demandé n'existe pas.");
|
||||
}
|
||||
public function readChapterPage(string $mangaSlug, float $chapterNumber, int $pageNumber = 0): Response
|
||||
{
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
if (!$manga) {
|
||||
throw $this->createNotFoundException("Le manga demandé n'existe pas.");
|
||||
}
|
||||
|
||||
$chapter = $manga->getChapterByNumber($chapterNumber);
|
||||
if (!$chapter) {
|
||||
throw $this->createNotFoundException("Le chapitre demandé n'existe pas.");
|
||||
}
|
||||
$chapter = $manga->getChapterByNumber($chapterNumber);
|
||||
if (!$chapter) {
|
||||
throw $this->createNotFoundException("Le chapitre demandé n'existe pas.");
|
||||
}
|
||||
|
||||
$currentPage = $chapter->getPageByNumber($pageNumber);
|
||||
if (!$currentPage) {
|
||||
throw $this->createNotFoundException("La page demandée n'existe pas.");
|
||||
}
|
||||
$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,
|
||||
]);
|
||||
}
|
||||
return $this->render('manga/manga_reader.html.twig', [
|
||||
'manga' => $manga,
|
||||
'chapter' => $chapter,
|
||||
'pages' => $chapter->getPagesLink(),
|
||||
'currentPage' => $currentPage,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/addNew', name: 'add_new_manga')]
|
||||
public function addNew(): Response
|
||||
{
|
||||
$availableManga = $this->mangaProviderService->getMangaList();
|
||||
|
||||
foreach ($availableManga as $key => $manga) {
|
||||
$availableManga[$key]['slug'] = $this->titleToSlug($manga['name']);
|
||||
}
|
||||
|
||||
$mangas = $this->mangaRepository->findAll();
|
||||
return $this->render('manga/add_new.html.twig', [
|
||||
'availableManga' => $availableManga,
|
||||
'mangas' => $mangas,
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(string $title): Response
|
||||
{
|
||||
$mangas = $this->mangaUpdatesDbProvider->search($title);
|
||||
|
||||
return $this->render('manga/add_new.html.twig', [
|
||||
'mangas' => $mangas,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/manga/{mangaSlug}/chapter/{chapterNumber}/download', name: 'download_chapter')]
|
||||
public function downloadChapter(string $mangaSlug, float $chapterNumber): BinaryFileResponse
|
||||
{
|
||||
$response = $this->mangaExportService->downloadCbz($this->slugToTitle($mangaSlug), $chapterNumber);
|
||||
public function downloadChapter(string $mangaSlug, float $chapterNumber): BinaryFileResponse
|
||||
{
|
||||
$response = $this->mangaExportService->downloadCbz($this->slugToTitle($mangaSlug), $chapterNumber);
|
||||
|
||||
if($response === false){
|
||||
throw $this->createNotFoundException("Le chapitre demandé n'existe pas.");
|
||||
}
|
||||
if ($response === false) {
|
||||
throw $this->createNotFoundException("Le chapitre demandé n'existe pas.");
|
||||
}
|
||||
|
||||
// Définir les en-têtes pour le téléchargement
|
||||
$response->headers->set('Content-Type', 'application/x-cbz');
|
||||
$response->setContentDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
"{$mangaSlug}_{$chapterNumber}.cbz"
|
||||
);
|
||||
// Définir les en-têtes pour le téléchargement
|
||||
$response->headers->set('Content-Type', 'application/x-cbz');
|
||||
$response->setContentDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
"{$mangaSlug}_{$chapterNumber}.cbz"
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Route('/scrape', name: 'manga_scrape', methods: 'POST')]
|
||||
public function scrapeByMangaAndChapter(Request $request): Response
|
||||
{
|
||||
$mangaSlug = $request->request->get('mangaSlug');
|
||||
$chapterNumber = $request->request->get('chapterNumber');
|
||||
#[Route('/scrape', name: 'manga_scrape', methods: 'POST')]
|
||||
public function scrapeByMangaAndChapter(Request $request): Response
|
||||
{
|
||||
$mangaSlug = $request->request->get('mangaSlug');
|
||||
$chapterNumber = $request->request->get('chapterNumber');
|
||||
|
||||
$response = $this->scrapeChapter($mangaSlug, $chapterNumber);
|
||||
$response = $this->scrapeChapter($mangaSlug, $chapterNumber);
|
||||
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
|
||||
return $this->render('manga/show_chapters.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
'manga' => $manga,
|
||||
'availableChapters' => $availableChapters,
|
||||
]);
|
||||
}
|
||||
return $this->render('manga/show_chapters.html.twig', [
|
||||
'controller_name' => 'MangaController',
|
||||
'manga' => $manga,
|
||||
'availableChapters' => $availableChapters,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/scrapeFrom', name: 'manga_scrape_from_chapter', methods: 'POST')]
|
||||
public function scrapeByMangaFromChapter(Request $request): Response
|
||||
{
|
||||
$mangaSlug = $request->request->get('mangaSlug');
|
||||
$chapterNumber = $request->request->get('chapterNumber');
|
||||
#[Route('/scrapeFrom', name: 'manga_scrape_from_chapter', methods: 'POST')]
|
||||
public function scrapeByMangaFromChapter(Request $request): Response
|
||||
{
|
||||
$mangaSlug = $request->request->get('mangaSlug');
|
||||
$chapterNumber = $request->request->get('chapterNumber');
|
||||
|
||||
do{
|
||||
$response = $this->scrapeChapter($mangaSlug, $chapterNumber);
|
||||
$chapterNumber++;
|
||||
}while($response !== false);
|
||||
do {
|
||||
$response = $this->scrapeChapter($mangaSlug, $chapterNumber);
|
||||
$chapterNumber++;
|
||||
} while ($response !== false);
|
||||
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
$availableChapters = $this->mangaProviderService->getChapterList($mangaSlug);
|
||||
|
||||
return $this->redirectToRoute('manga_show', ['mangaSlug' => $mangaSlug, 'availableChapters' => $availableChapters]);
|
||||
}
|
||||
return $this->redirectToRoute('manga_show', ['mangaSlug' => $mangaSlug, 'availableChapters' => $availableChapters]);
|
||||
}
|
||||
|
||||
#[Route('/manga/exportFrom/{mangaSlug}/{chapterNumber}', name: 'manga_export')]
|
||||
public function exportMangaCbz(string $mangaSlug, float $chapterNumber)
|
||||
{
|
||||
$response = $this->exportCbz($this->slugToTitle($mangaSlug), $chapterNumber);
|
||||
#[Route('/manga/exportFrom/{mangaSlug}/{chapterNumber}', name: 'manga_export')]
|
||||
public function exportMangaCbz(string $mangaSlug, float $chapterNumber)
|
||||
{
|
||||
$response = $this->exportCbz($this->slugToTitle($mangaSlug), $chapterNumber);
|
||||
|
||||
dd($response);
|
||||
}
|
||||
dd($response);
|
||||
}
|
||||
|
||||
#[Route('/getList', name: 'get_manga_list')]
|
||||
public function getMangaList()
|
||||
{
|
||||
$list = $this->mangaProviderService->getMangaList();
|
||||
#[Route('/getList', name: 'get_manga_list')]
|
||||
public function getMangaList()
|
||||
{
|
||||
$list = $this->mangaProviderService->getMangaList();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function scrapeChapter(string $mangaSlug, float $chapterNumber): array|bool
|
||||
{
|
||||
$url = 'https://lelscans.net/scan-' . $mangaSlug . '/' . $chapterNumber;
|
||||
private function scrapeChapter(string $mangaSlug, float $chapterNumber): array|bool
|
||||
{
|
||||
$url = 'https://lelscans.net/scan-' . $mangaSlug . '/' . $chapterNumber;
|
||||
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
$manga = $this->mangaRepository->findOneBy(['slug' => $mangaSlug]);
|
||||
|
||||
if(!is_null($manga)){
|
||||
$scrapedManga = $this->mangaScraperService->scrapeMangaChapter($url, $manga->getTitle(), $chapterNumber);
|
||||
}else{
|
||||
$title = $this->slugToTitle($mangaSlug);
|
||||
$manga = new Manga();
|
||||
$manga->setTitle($title);
|
||||
$manga->setSlug($mangaSlug);
|
||||
$this->mangaRepository->save($manga);
|
||||
$scrapedManga = $this->mangaScraperService->scrapeMangaChapter($url, $title, $chapterNumber);
|
||||
}
|
||||
if (!is_null($manga)) {
|
||||
$scrapedManga = $this->mangaScraperService->scrapeMangaChapter($url, $manga->getTitle(), $chapterNumber);
|
||||
} else {
|
||||
$title = $this->slugToTitle($mangaSlug);
|
||||
$manga = new Manga();
|
||||
$manga->setTitle($title);
|
||||
$manga->setSlug($mangaSlug);
|
||||
$this->mangaRepository->save($manga);
|
||||
$scrapedManga = $this->mangaScraperService->scrapeMangaChapter($url, $title, $chapterNumber);
|
||||
}
|
||||
|
||||
return $scrapedManga;
|
||||
}
|
||||
return $scrapedManga;
|
||||
}
|
||||
|
||||
private function exportCbz(string $mangaSlug, float $chapterNumber):array
|
||||
{
|
||||
$exported = [];
|
||||
do{
|
||||
$response = $this->mangaExportService->exportMangaChapter($mangaSlug, $chapterNumber);
|
||||
private function exportCbz(string $mangaSlug, float $chapterNumber): array
|
||||
{
|
||||
$exported = [];
|
||||
do {
|
||||
$response = $this->mangaExportService->exportMangaChapter($mangaSlug, $chapterNumber);
|
||||
|
||||
if($response === 'already_exported'){
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' ' . $response;
|
||||
}elseif($response === true){
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' exported';
|
||||
}else{
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' something went wrong';
|
||||
}
|
||||
if ($response === 'already_exported') {
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' ' . $response;
|
||||
} elseif ($response === true) {
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' exported';
|
||||
} else {
|
||||
$exported[] = $mangaSlug . ' - ' . $chapterNumber . ' something went wrong';
|
||||
}
|
||||
|
||||
$chapterNumber++;
|
||||
}while($response !== false);
|
||||
$chapterNumber++;
|
||||
} while ($response !== false);
|
||||
|
||||
return $exported;
|
||||
}
|
||||
return $exported;
|
||||
}
|
||||
|
||||
private function slugToTitle(string $slug): string
|
||||
{
|
||||
$slugger = new AsciiSlugger();
|
||||
$title = $slugger->slug($slug)->replace('-', ' ')->title(true)->toString();
|
||||
private function slugToTitle(string $slug): string
|
||||
{
|
||||
$slugger = new AsciiSlugger();
|
||||
$title = $slugger->slug($slug)->replace('-', ' ')->title(true)->toString();
|
||||
|
||||
return $title;
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
private function titleToSlug(string $title): string
|
||||
{
|
||||
$slugger = new AsciiSlugger();
|
||||
return $slugger->slug($title)->lower()->toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class MenuController extends AbstractController
|
||||
}
|
||||
|
||||
$mangas = $this->mangaRepository->findAll();
|
||||
return $this->render('menu/menu.html.twig', [
|
||||
return $this->render('menu/menu_old.html.twig', [
|
||||
'availableManga' => $availableManga,
|
||||
'mangas' => $mangas,
|
||||
]);
|
||||
@@ -44,4 +44,4 @@ class MenuController extends AbstractController
|
||||
$slugger = new AsciiSlugger();
|
||||
return $slugger->slug($title)->lower()->toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ class AppFixtures extends Fixture
|
||||
];
|
||||
});
|
||||
|
||||
$mangas = MangaFactory::createMany(5);
|
||||
$mangas = MangaFactory::createMany(25);
|
||||
|
||||
foreach ($mangas as $manga) {
|
||||
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$manga->addChapter(ChapterFactory::createOne([
|
||||
'manga' => $manga,
|
||||
'number' => $i
|
||||
@@ -33,7 +33,7 @@ class AppFixtures extends Fixture
|
||||
}
|
||||
|
||||
foreach ($manga->getChapters() as $chapter) {
|
||||
for ($i = 1; $i <= 15; $i++) {
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$chapter->addPagesLink(PageFactory::createOne([
|
||||
'chapter' => $chapter,
|
||||
'number' => $i
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Entity;
|
||||
use App\Repository\MangaRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: MangaRepository::class)]
|
||||
@@ -24,6 +25,18 @@ class Manga
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $slug = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $imageUrl = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $publicationYear = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $description = null;
|
||||
|
||||
#[ORM\Column(type: Types::ARRAY, nullable: true)]
|
||||
private ?array $genres = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->chapters = new ArrayCollection();
|
||||
@@ -55,14 +68,14 @@ class Manga
|
||||
}
|
||||
|
||||
public function getChapterByNumber(float $number): ?Chapter
|
||||
{
|
||||
foreach ($this->chapters as $chapter) {
|
||||
if ($chapter->getNumber() === $number) {
|
||||
return $chapter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
{
|
||||
foreach ($this->chapters as $chapter) {
|
||||
if ($chapter->getNumber() === $number) {
|
||||
return $chapter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function addChapter(Chapter $chapter): self
|
||||
{
|
||||
@@ -97,4 +110,52 @@ class Manga
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getImageUrl(): ?string
|
||||
{
|
||||
return $this->imageUrl;
|
||||
}
|
||||
|
||||
public function setImageUrl(?string $imageUrl): static
|
||||
{
|
||||
$this->imageUrl = $imageUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPublicationYear(): ?int
|
||||
{
|
||||
return $this->publicationYear;
|
||||
}
|
||||
|
||||
public function setPublicationYear(?int $publicationYear): static
|
||||
{
|
||||
$this->publicationYear = $publicationYear;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): static
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGenres(): ?array
|
||||
{
|
||||
return $this->genres;
|
||||
}
|
||||
|
||||
public function setGenres(?array $genres): static
|
||||
{
|
||||
$this->genres = $genres;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\EventListener;
|
||||
use App\Entity\Chapter;
|
||||
use App\Entity\Manga;
|
||||
use App\Entity\Page;
|
||||
use App\Event\MangaScrapedEvent;
|
||||
use App\EventSubscriber\MangaScrapedEvent;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
class MangaScrapedListener
|
||||
@@ -50,4 +50,4 @@ class MangaScrapedListener
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Factory;
|
||||
|
||||
use App\Entity\Manga;
|
||||
use App\Repository\MangaRepository;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
use Zenstruck\Foundry\ModelFactory;
|
||||
use Zenstruck\Foundry\Proxy;
|
||||
use Zenstruck\Foundry\RepositoryProxy;
|
||||
@@ -34,7 +35,7 @@ final class MangaFactory extends ModelFactory
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(private SluggerInterface $slugger)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -46,9 +47,11 @@ final class MangaFactory extends ModelFactory
|
||||
*/
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
$title = self::faker()->words(rand(1, 3), true);
|
||||
|
||||
return [
|
||||
'slug' => self::faker()->text(255),
|
||||
'title' => self::faker()->text(255),
|
||||
'slug' => $this->slugger->slug($title)->lower(),
|
||||
'title' => $title,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
10
src/Service/MangaDbProviderInterface.php
Normal file
10
src/Service/MangaDbProviderInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
||||
interface MangaDbProviderInterface
|
||||
{
|
||||
public function search(string $title): Collection;
|
||||
}
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Event\MangaScrapedEvent;
|
||||
use App\EventSubscriber\MangaScrapedEvent;
|
||||
use GuzzleHttp\Client;
|
||||
use PHPUnit\Util\PHP\AbstractPhpProcess;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
@@ -15,7 +14,7 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class MangaScraperService
|
||||
{
|
||||
const IMG_BASE_DIR = '/public/manga-images';
|
||||
const string IMG_BASE_DIR = '/public/manga-images';
|
||||
private string $projectDir;
|
||||
private EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
@@ -28,9 +27,10 @@ class MangaScraperService
|
||||
public function extractMangaPageData(string $html): array
|
||||
{
|
||||
$baseUrl = 'https://lelscans.net';
|
||||
|
||||
//pour éviter à PhpStorm de gueuler...
|
||||
$selector = 'img';
|
||||
$crawler = new Crawler($html);
|
||||
$imgUrl = $crawler->filter('img')->attr('src');
|
||||
$imgUrl = $crawler->filter($selector)->attr('src');
|
||||
$nextLink = $crawler->filter('a[title="Suivant"]');
|
||||
|
||||
if (!preg_match('/^https?:\/\//', $imgUrl)) {
|
||||
@@ -54,7 +54,10 @@ class MangaScraperService
|
||||
];
|
||||
}
|
||||
|
||||
public function scrapeMangaChapter(string $chapterUrl, string $mangaTitle, float $chapterNumber): array|bool
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function scrapeMangaChapter(string $chapterUrl, string $mangaTitle, float $chapterNumber): array|bool
|
||||
{
|
||||
if(!$this->isChapterAvailable($chapterUrl, $chapterNumber)){
|
||||
return false;
|
||||
@@ -101,7 +104,10 @@ class MangaScraperService
|
||||
return $pageData;
|
||||
}
|
||||
|
||||
private function fetchHtml(string $url): string
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
private function fetchHtml(string $url): string
|
||||
{
|
||||
$client = new Client();
|
||||
$response = $client->get($url);
|
||||
@@ -109,7 +115,10 @@ class MangaScraperService
|
||||
return (string) $response->getBody();
|
||||
}
|
||||
|
||||
private function downloadAndSaveImage(string $imageUrl, string $destinationPath): void
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
private function downloadAndSaveImage(string $imageUrl, string $destinationPath): void
|
||||
{
|
||||
$client = new Client();
|
||||
$response = $client->get($imageUrl);
|
||||
@@ -117,7 +126,10 @@ class MangaScraperService
|
||||
file_put_contents($destinationPath, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
private function isChapterAvailable(string $chapterUrl, float $chapterNumber): bool
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
private function isChapterAvailable(string $chapterUrl, float $chapterNumber): bool
|
||||
{
|
||||
$html = $this->fetchHtml($chapterUrl);
|
||||
$crawler = new Crawler($html);
|
||||
@@ -142,4 +154,4 @@ class MangaScraperService
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
67
src/Service/MangaUpdatesDbProvider.php
Normal file
67
src/Service/MangaUpdatesDbProvider.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\Manga;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Symfony\Component\BrowserKit\HttpBrowser;
|
||||
use Symfony\Component\String\Slugger\SluggerInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class MangaUpdatesDbProvider implements MangaDbProviderInterface
|
||||
{
|
||||
private Client $client;
|
||||
|
||||
public function __construct(private SluggerInterface $slugger)
|
||||
{
|
||||
$this->client = new Client();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function search(string $title): Collection
|
||||
{
|
||||
try {
|
||||
$response = $this->client->request('PUT', 'https://api.mangaupdates.com/v1/account/login', [
|
||||
'json' => [
|
||||
'username' => 'Colgora',
|
||||
'password' => '7TK5jv33NDn*SLV',
|
||||
]
|
||||
])
|
||||
->withHeader('Content-Type', 'application/json');
|
||||
|
||||
$jwt = json_decode($response->getBody()->getContents(), true)['context']['session_token'];
|
||||
|
||||
$results = $this->client->request('POST', 'https://api.mangaupdates.com/v1/series/search', [
|
||||
'json' => [
|
||||
'search' => $title,
|
||||
'orderby' => 'score',
|
||||
]
|
||||
])->withHeader('Authorization', 'Bearer ' . $jwt)
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->getBody()
|
||||
->getContents();
|
||||
|
||||
$mangas = [];
|
||||
foreach (json_decode($results, true)['results'] as $record) {
|
||||
$record = $record['record'];
|
||||
$mangas[] = (new Manga())
|
||||
->setTitle($record['title'])
|
||||
->setSlug($this->slugger->slug($record['title'])->lower())
|
||||
->setDescription($record['description'])
|
||||
->setImageUrl($record['image']['url']['original'])
|
||||
->setGenres($record['genres'])
|
||||
->setPublicationYear((int)$record['year']);
|
||||
}
|
||||
|
||||
return new ArrayCollection($mangas);
|
||||
} catch (GuzzleException $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user