Corrige l'import de chapitres/volumes CBZ qui stockait le chemin du fichier CBZ comme pagesDirectory. Le reader ne trouvait aucune image car LegacyChapterRepository attend un dossier d'images individuelles. - Déplace ImageStorageInterface dans Shared (storeChapterImages + extractFromCbz + countCbzImages) - Crée ImageStorageManager dans Shared/Infrastructure (extraction ZIP + copie) - Supprime LocalImageStorage et l'ancienne interface dans Scraping - Refactore ImportChapterHandler et ImportVolumeHandler pour utiliser ImageStorageInterface - Corrige LegacyChapterRepository : construit l'URL depuis basename(pagesDirectory) au lieu de chapterId (fix pour les volumes partagés)
166 lines
5.6 KiB
PHP
166 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Domain\Reader\Infrastructure\Persistence;
|
|
|
|
use App\Domain\Reader\Domain\Contract\Repository\ChapterRepositoryInterface;
|
|
use App\Domain\Reader\Domain\Exception\ChapterNotFoundException;
|
|
use App\Domain\Reader\Domain\Model\ChapterContext;
|
|
use App\Domain\Reader\Domain\Model\Page;
|
|
use App\Domain\Reader\Domain\ValueObject\ChapterId;
|
|
use App\Domain\Reader\Domain\ValueObject\PageNumber;
|
|
use App\Entity\Chapter as ChapterEntity;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
readonly class LegacyChapterRepository implements ChapterRepositoryInterface
|
|
{
|
|
public function __construct(
|
|
private EntityManagerInterface $entityManager
|
|
) {
|
|
}
|
|
|
|
public function getPagesForChapter(ChapterId $chapterId, int $page = 1, int $itemsPerPage = 20): array
|
|
{
|
|
$chapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
$pagesDirectory = $chapter->getPagesDirectory();
|
|
if ($pagesDirectory && is_dir($pagesDirectory)) {
|
|
return $this->getPagesFromDirectory($chapterId, $pagesDirectory, $page, $itemsPerPage);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
public function getChapterContext(ChapterId $chapterId): ChapterContext
|
|
{
|
|
/** @var ChapterEntity $chapter */
|
|
$chapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
if (!$chapter) {
|
|
throw ChapterNotFoundException::forChapter($chapterId);
|
|
}
|
|
|
|
return new ChapterContext(
|
|
id: $chapterId,
|
|
previousChapterId: $this->getPreviousChapterId($chapterId),
|
|
nextChapterId: $this->getNextChapterId($chapterId),
|
|
mangaId: (string) $chapter->getManga()->getId(),
|
|
mangaTitle: $chapter->getManga()->getTitle(),
|
|
number: $chapter->getNumber(),
|
|
chapterTitle: $chapter->getTitle(),
|
|
cbzPath: $chapter->getCbzPath(),
|
|
volume: $chapter->getVolume(),
|
|
totalPages: 0,
|
|
isVisible: $chapter->isVisible(),
|
|
createdAt: new \DateTimeImmutable(),
|
|
pagesDirectory: $chapter->getPagesDirectory(),
|
|
);
|
|
}
|
|
|
|
public function getTotalPagesForChapter(ChapterId $chapterId): int
|
|
{
|
|
$chapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
if (!$chapter) {
|
|
throw ChapterNotFoundException::forChapter($chapterId);
|
|
}
|
|
|
|
$pagesDirectory = $chapter->getPagesDirectory();
|
|
if ($pagesDirectory && is_dir($pagesDirectory)) {
|
|
return count($this->getImageFiles($pagesDirectory));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public function getPreviousChapterId(ChapterId $chapterId): ?ChapterId
|
|
{
|
|
$currentChapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
$qb = $this->entityManager->createQueryBuilder();
|
|
$qb->select('c')
|
|
->from(ChapterEntity::class, 'c')
|
|
->where('c.manga = :manga')
|
|
->andWhere('c.number < :number')
|
|
->andWhere('c.visible = true')
|
|
->andWhere('c.pagesDirectory IS NOT NULL OR c.cbzPath IS NOT NULL')
|
|
->orderBy('c.number', 'DESC')
|
|
->setMaxResults(1)
|
|
->setParameters([
|
|
'manga' => $currentChapter->getManga(),
|
|
'number' => $currentChapter->getNumber()
|
|
]);
|
|
|
|
$previousChapter = $qb->getQuery()->getOneOrNullResult();
|
|
|
|
return $previousChapter ? new ChapterId((string) $previousChapter->getId()) : null;
|
|
}
|
|
|
|
public function getNextChapterId(ChapterId $chapterId): ?ChapterId
|
|
{
|
|
$currentChapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
$qb = $this->entityManager->createQueryBuilder();
|
|
$qb->select('c')
|
|
->from(ChapterEntity::class, 'c')
|
|
->where('c.manga = :manga')
|
|
->andWhere('c.number > :number')
|
|
->andWhere('c.visible = true')
|
|
->andWhere('c.pagesDirectory IS NOT NULL OR c.cbzPath IS NOT NULL')
|
|
->orderBy('c.number', 'ASC')
|
|
->setMaxResults(1)
|
|
->setParameters([
|
|
'manga' => $currentChapter->getManga(),
|
|
'number' => $currentChapter->getNumber()
|
|
]);
|
|
|
|
$nextChapter = $qb->getQuery()->getOneOrNullResult();
|
|
|
|
return $nextChapter ? new ChapterId((string) $nextChapter->getId()) : null;
|
|
}
|
|
|
|
private function getImageFiles(string $pagesDirectory): array
|
|
{
|
|
$files = glob($pagesDirectory . '/*.{jpg,jpeg,png,webp,gif}', GLOB_BRACE) ?: [];
|
|
sort($files);
|
|
|
|
return $files;
|
|
}
|
|
|
|
private function getPagesFromDirectory(ChapterId $chapterId, string $pagesDirectory, int $page, int $itemsPerPage): array
|
|
{
|
|
$files = $this->getImageFiles($pagesDirectory);
|
|
$start = max(0, ($page - 1) * $itemsPerPage);
|
|
$end = min($start + $itemsPerPage, count($files));
|
|
$pages = [];
|
|
|
|
for ($i = $start; $i < $end; $i++) {
|
|
$imageSize = @getimagesize($files[$i]);
|
|
if ($imageSize === false) {
|
|
continue;
|
|
}
|
|
|
|
$pages[] = new Page(
|
|
basename($files[$i]),
|
|
new PageNumber($i + 1),
|
|
sprintf('/images/pages/%s/%s', basename($pagesDirectory), basename($files[$i])),
|
|
$imageSize[0],
|
|
$imageSize[1]
|
|
);
|
|
}
|
|
|
|
return $pages;
|
|
}
|
|
}
|