224 lines
6.8 KiB
PHP
224 lines
6.8 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;
|
|
use ZipArchive;
|
|
use App\Domain\Reader\Domain\Exception\PageNotFoundException;
|
|
use App\Domain\Reader\Domain\Model\PageContent;
|
|
|
|
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()
|
|
]);
|
|
|
|
$cbzPath = $chapter->getCbzPath();
|
|
|
|
if (!$cbzPath) {
|
|
return [];
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
$zip->open($cbzPath);
|
|
|
|
$pages = [];
|
|
$start = ($page - 1) * $itemsPerPage;
|
|
$end = min($start + $itemsPerPage, $zip->numFiles);
|
|
|
|
for ($i = $start; $i < $end; $i++) {
|
|
$stat = $zip->statIndex($i);
|
|
if ($stat === false) {
|
|
continue;
|
|
}
|
|
|
|
$imageContent = $zip->getFromIndex($i);
|
|
if ($imageContent === false) {
|
|
continue;
|
|
}
|
|
|
|
$imageSize = @getimagesizefromstring($imageContent);
|
|
if ($imageSize === false) {
|
|
continue;
|
|
}
|
|
|
|
$pages[] = new Page(
|
|
$stat['name'],
|
|
new PageNumber($i + 1),
|
|
sprintf('/api/chapters/%s/pages/%d', $chapterId->getValue(), $i + 1),
|
|
$imageSize[0],
|
|
$imageSize[1]
|
|
);
|
|
}
|
|
|
|
$zip->close();
|
|
return $pages;
|
|
}
|
|
|
|
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),
|
|
mangaTitle: $chapter->getManga()->getTitle(),
|
|
number: $chapter->getNumber(),
|
|
chapterTitle: $chapter->getTitle(),
|
|
cbzPath: $chapter->getCbzPath(),
|
|
volume: $chapter->getVolume(),
|
|
totalPages: 0,
|
|
isVisible: $chapter->isVisible(),
|
|
createdAt: new \DateTimeImmutable()
|
|
);
|
|
}
|
|
|
|
public function getTotalPagesForChapter(ChapterId $chapterId): int
|
|
{
|
|
$chapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
if (!$chapter) {
|
|
throw ChapterNotFoundException::forChapter($chapterId);
|
|
}
|
|
|
|
$cbzPath = $chapter->getCbzPath();
|
|
|
|
if (!$cbzPath) {
|
|
return 0;
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
$zip->open($cbzPath);
|
|
return $zip->numFiles;
|
|
}
|
|
|
|
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')
|
|
->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')
|
|
->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;
|
|
}
|
|
|
|
public function getPageContent(ChapterId $chapterId, PageNumber $pageNumber): PageContent
|
|
{
|
|
$chapter = $this->entityManager->getRepository(ChapterEntity::class)->findOneBy([
|
|
'id' => $chapterId->getValue()
|
|
]);
|
|
|
|
if (!$chapter) {
|
|
throw ChapterNotFoundException::forChapter($chapterId);
|
|
}
|
|
|
|
$cbzPath = $chapter->getCbzPath();
|
|
if (!$cbzPath || !file_exists($cbzPath)) {
|
|
throw ChapterNotFoundException::forChapter($chapterId);
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
$zip->open($cbzPath);
|
|
|
|
if ($pageNumber->getValue() > $zip->numFiles) {
|
|
$zip->close();
|
|
throw PageNotFoundException::forPage($chapterId, $pageNumber);
|
|
}
|
|
|
|
$index = $pageNumber->getValue() - 1;
|
|
$stat = $zip->statIndex($index);
|
|
|
|
if ($stat === false) {
|
|
$zip->close();
|
|
throw PageNotFoundException::forPage($chapterId, $pageNumber);
|
|
}
|
|
|
|
$imageContent = $zip->getFromIndex($index);
|
|
|
|
if ($imageContent === false) {
|
|
$zip->close();
|
|
throw PageNotFoundException::forPage($chapterId, $pageNumber);
|
|
}
|
|
|
|
$imageSize = @getimagesizefromstring($imageContent);
|
|
|
|
if ($imageSize === false) {
|
|
$zip->close();
|
|
throw PageNotFoundException::forPage($chapterId, $pageNumber);
|
|
}
|
|
|
|
$mimeType = $imageSize['mime'] ?? 'image/jpeg';
|
|
$zip->close();
|
|
|
|
return new PageContent(
|
|
$stat['name'],
|
|
$pageNumber,
|
|
base64_encode($imageContent),
|
|
$mimeType,
|
|
$imageSize[0],
|
|
$imageSize[1]
|
|
);
|
|
}
|
|
}
|