Files
Mangarr/src/Domain/Manga/Infrastructure/Service/FileService.php

122 lines
3.7 KiB
PHP

<?php
namespace App\Domain\Manga\Infrastructure\Service;
use App\Domain\Manga\Domain\Contract\Service\FileServiceInterface;
use App\Domain\Manga\Domain\Exception\CbzFileNotFoundException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
readonly class FileService implements FileServiceInterface
{
public function __construct(
private string $cbzStoragePath = '/app/public/cbz'
) {}
public function downloadCbz(string $filePath, string $filename): Response
{
if (!$this->cbzExists($filePath)) {
throw new CbzFileNotFoundException($filePath);
}
$response = new BinaryFileResponse($filePath);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$filename
);
$response->headers->set('Content-Type', 'application/x-cbz');
return $response;
}
public function createVolumeCbz(array $cbzPaths, string $volumeName): Response
{
$tempCbzPath = sys_get_temp_dir() . '/' . $volumeName . '.cbz';
$cbz = new \ZipArchive();
if ($cbz->open($tempCbzPath, \ZipArchive::CREATE) !== true) {
throw new \RuntimeException('Cannot create CBZ file');
}
$imageCounter = 1;
foreach ($cbzPaths as $cbzPath) {
if (!$this->cbzExists($cbzPath)) {
continue;
}
$sourceCbz = new \ZipArchive();
if ($sourceCbz->open($cbzPath) !== true) {
continue; // Skip if we can't open the CBZ
}
// Extract all images from the current CBZ
for ($i = 0; $i < $sourceCbz->numFiles; $i++) {
$fileName = $sourceCbz->getNameIndex($i);
$fileInfo = $sourceCbz->statIndex($i);
// Skip directories and non-image files
if ($fileInfo['size'] === 0 || !$this->isImageFile($fileName)) {
continue;
}
// Get the file content
$imageContent = $sourceCbz->getFromIndex($i);
if ($imageContent === false) {
continue;
}
// Get file extension
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
// Create a new filename with proper ordering
$newFileName = sprintf('%04d.%s', $imageCounter, $extension);
// Add the image to the volume CBZ
$cbz->addFromString($newFileName, $imageContent);
$imageCounter++;
}
$sourceCbz->close();
}
$cbz->close();
$response = new BinaryFileResponse($tempCbzPath);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$volumeName . '.cbz'
);
$response->headers->set('Content-Type', 'application/x-cbz');
// Clean up temp file after sending
$response->deleteFileAfterSend();
return $response;
}
private function isImageFile(string $fileName): bool
{
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
$extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
return in_array($extension, $imageExtensions);
}
public function deleteCbzFile(string $filePath): bool
{
if (!$this->cbzExists($filePath)) {
return false;
}
return unlink($filePath);
}
public function cbzExists(string $filePath): bool
{
return file_exists($filePath) && is_readable($filePath);
}
}