style: apply php-cs-fixer formatting (PSR-12)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dae215dd3d
commit
7506a7a3c1
@@ -14,5 +14,6 @@ readonly class TestScraperConfiguration
|
||||
public ?string $imageSelector = null,
|
||||
public ?string $nextPageSelector = null,
|
||||
public ?string $chapterSelector = null,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ readonly class ScrapeChapterHandler
|
||||
$chapter->volumeNumber,
|
||||
$chapter->chapterNumber,
|
||||
$tempDir,
|
||||
array_map(fn($r) => $r->getLocalPath(), $downloadResults)
|
||||
array_map(fn ($r) => $r->getLocalPath(), $downloadResults)
|
||||
);
|
||||
|
||||
$cbzPath = $this->cbzGenerator->generate($cbzRequest);
|
||||
|
||||
@@ -12,7 +12,8 @@ readonly class TestScraperConfigurationHandler
|
||||
{
|
||||
public function __construct(
|
||||
private ScraperFactoryInterface $scraperFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(TestScraperConfiguration $command): TestScraperConfigurationResponse
|
||||
{
|
||||
|
||||
@@ -11,7 +11,8 @@ readonly class TestScraperConfigurationResponse
|
||||
public string $testedUrl,
|
||||
public string $scrapingType,
|
||||
public array $errors = [],
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public static function success(array $imageUrls, string $testedUrl, string $scrapingType): self
|
||||
{
|
||||
|
||||
@@ -18,4 +18,4 @@ class CbzGenerationException extends \RuntimeException
|
||||
{
|
||||
return new self(sprintf('Impossible d\'ajouter le fichier à l\'archive : %s', $filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,6 @@ class Chapter
|
||||
public readonly float $chapterNumber,
|
||||
public readonly ?int $volumeNumber,
|
||||
public ?string $cbzPath,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,5 +77,6 @@ class GetMangaPreferredSourcesResource
|
||||
{
|
||||
public function __construct(
|
||||
public string $id
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@ class SetMangaPreferredSourcesResource
|
||||
new Assert\Type('string')
|
||||
])]
|
||||
public array $sourceIds = []
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,6 @@ readonly class TestScraperConfigurationRequest
|
||||
#[Assert\NotBlank(message: 'L\'URL de base est obligatoire')]
|
||||
#[Assert\Url(message: 'L\'URL de base doit être une URL valide')]
|
||||
public string $baseUrl,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Format d\'URL pour accéder aux chapitres. Utilisez {slug} pour le nom du manga et {chapter} pour le numéro de chapitre',
|
||||
example: 'https://mangasite.example.com/manga/{slug}/chapter/{chapter}',
|
||||
@@ -313,7 +312,6 @@ readonly class TestScraperConfigurationRequest
|
||||
)]
|
||||
#[Assert\NotBlank(message: 'Le format d\'URL de chapitre est obligatoire')]
|
||||
public string $chapterUrlFormat,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Type de scraping à utiliser. "html" pour les sites statiques, "javascript" pour les sites avec contenu dynamique',
|
||||
example: 'html',
|
||||
@@ -322,7 +320,6 @@ readonly class TestScraperConfigurationRequest
|
||||
#[Assert\NotBlank(message: 'Le type de scraping est obligatoire')]
|
||||
#[Assert\Choice(choices: ['html', 'javascript'], message: 'Le type de scraping doit être html ou javascript')]
|
||||
public string $scrapingType,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'URL complète d\'un chapitre existant à utiliser pour tester la configuration. Cette URL doit être accessible et contenir des images',
|
||||
example: 'https://mangasite.example.com/manga/one-piece/chapter/1',
|
||||
@@ -331,7 +328,6 @@ readonly class TestScraperConfigurationRequest
|
||||
#[Assert\NotBlank(message: 'L\'URL de test est obligatoire')]
|
||||
#[Assert\Url(message: 'L\'URL de test doit être une URL valide')]
|
||||
public string $testUrl,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Identifiant du manga utilisé dans les URLs (slug). Sera utilisé pour remplacer {slug} dans le format d\'URL',
|
||||
example: 'one-piece',
|
||||
@@ -339,7 +335,6 @@ readonly class TestScraperConfigurationRequest
|
||||
)]
|
||||
#[Assert\NotBlank(message: 'Le slug du manga est obligatoire')]
|
||||
public string $mangaSlug,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Numéro du chapitre à tester. Peut être décimal pour les chapitres spéciaux (ex: 1.5)',
|
||||
example: 1.0,
|
||||
@@ -349,7 +344,6 @@ readonly class TestScraperConfigurationRequest
|
||||
#[Assert\Type(type: 'numeric', message: 'Le numéro de chapitre doit être numérique')]
|
||||
#[Assert\Positive(message: 'Le numéro de chapitre doit être positif')]
|
||||
public float $chapterNumber,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Sélecteur CSS pour identifier les images du manga sur la page. Exemples: "img.manga-page", ".chapter img", "#reader img"',
|
||||
example: 'img.manga-page, .chapter-image img',
|
||||
@@ -357,7 +351,6 @@ readonly class TestScraperConfigurationRequest
|
||||
)]
|
||||
#[Assert\Length(min: 1, max: 500, minMessage: 'Le sélecteur d\'image ne peut pas être vide', maxMessage: 'Le sélecteur d\'image est trop long')]
|
||||
public ?string $imageSelector = null,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Sélecteur CSS pour le lien vers la page suivante (requis pour les lecteurs horizontaux). Exemples: "a.next", ".navigation .next-page"',
|
||||
example: 'a.next-page, .navigation .next',
|
||||
@@ -365,7 +358,6 @@ readonly class TestScraperConfigurationRequest
|
||||
)]
|
||||
#[Assert\Length(max: 500, maxMessage: 'Le sélecteur de page suivante est trop long')]
|
||||
public ?string $nextPageSelector = null,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Sélecteur CSS pour délimiter la zone contenant le chapitre (optionnel). Utile pour cibler une zone spécifique de la page',
|
||||
example: '.chapter-content, #manga-reader',
|
||||
@@ -373,5 +365,6 @@ readonly class TestScraperConfigurationRequest
|
||||
)]
|
||||
#[Assert\Length(max: 500, maxMessage: 'Le sélecteur de chapitre est trop long')]
|
||||
public ?string $chapterSelector = null,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ readonly class TestScraperConfigurationResource
|
||||
schema: ['type' => 'boolean']
|
||||
)]
|
||||
public bool $success,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Liste des URLs d\'images trouvées lors du scraping. Vide en cas d\'échec.',
|
||||
example: [
|
||||
@@ -29,28 +28,24 @@ readonly class TestScraperConfigurationResource
|
||||
]
|
||||
)]
|
||||
public array $imageUrls,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Nombre total d\'images trouvées',
|
||||
example: 2,
|
||||
schema: ['type' => 'integer', 'minimum' => 0]
|
||||
)]
|
||||
public int $totalImages,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'URL qui a été testée',
|
||||
example: 'https://mangasite.example.com/manga/one-piece/chapter/1',
|
||||
schema: ['type' => 'string', 'format' => 'uri']
|
||||
)]
|
||||
public string $testedUrl,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Type de scraping qui a été utilisé pour le test',
|
||||
example: 'html',
|
||||
schema: ['type' => 'string', 'enum' => ['html', 'javascript']]
|
||||
)]
|
||||
public string $scrapingType,
|
||||
|
||||
#[ApiProperty(
|
||||
description: 'Liste des erreurs détaillées en cas d\'échec. Vide en cas de succès. Chaque erreur contient un type, le champ concerné, un message et une suggestion.',
|
||||
example: [
|
||||
@@ -89,5 +84,6 @@ readonly class TestScraperConfigurationResource
|
||||
]
|
||||
)]
|
||||
public array $errors = [],
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ readonly class TestScraperConfigurationStateProcessor implements ProcessorInterf
|
||||
{
|
||||
public function __construct(
|
||||
private TestScraperConfigurationHandler $handler
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): TestScraperConfigurationResource
|
||||
{
|
||||
|
||||
@@ -15,7 +15,8 @@ class AutoScrapingListener
|
||||
private readonly ScrapeChapterHandler $scrapeChapterHandler,
|
||||
private readonly ChapterRepositoryInterface $chapterRepository,
|
||||
private readonly MangaRepositoryInterface $mangaRepository,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
#[AsMessageHandler]
|
||||
public function onChapterReadyForScraping(ChapterReadyForScraping $event): void
|
||||
|
||||
@@ -7,11 +7,13 @@ use App\Domain\Scraping\Domain\Exception\ChapterNotFoundException;
|
||||
use App\Domain\Scraping\Domain\Model\Chapter;
|
||||
use App\Entity\Chapter as EntityChapter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
readonly class LegacyChapterRepository implements ChapterRepositoryInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère un chapitre par son identifiant
|
||||
|
||||
@@ -71,7 +71,7 @@ readonly class LegacyMangaRepository implements MangaRepositoryInterface
|
||||
} else {
|
||||
// Valider que toutes les sources existent avant de les sauvegarder
|
||||
$sources = $this->entityManager->getRepository(ContentSource::class)->findBy(['id' => $sourceIds]);
|
||||
$existingSourceIds = array_map(fn($source) => (string) $source->getId(), $sources);
|
||||
$existingSourceIds = array_map(fn ($source) => (string) $source->getId(), $sources);
|
||||
|
||||
// Garder uniquement les sources qui existent et maintenir l'ordre
|
||||
$validSourceIds = array_values(array_intersect($sourceIds, $existingSourceIds));
|
||||
|
||||
@@ -89,7 +89,7 @@ class AdvancedHtmlScraper implements ScraperInterface
|
||||
return $this->cleanImageUrl($src);
|
||||
});
|
||||
|
||||
return array_filter($images, fn($url) => !empty($url));
|
||||
return array_filter($images, fn ($url) => !empty($url));
|
||||
}
|
||||
|
||||
private function scrapeHorizontalReader(ScrapingRequest $request): array
|
||||
@@ -143,7 +143,7 @@ class AdvancedHtmlScraper implements ScraperInterface
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return array_filter($pages, fn($url) => !empty($url));
|
||||
return array_filter($pages, fn ($url) => !empty($url));
|
||||
}
|
||||
|
||||
private function fetchHtmlWithRetry(string $url): string
|
||||
|
||||
@@ -16,7 +16,8 @@ class JavaScriptScraper implements ScraperInterface
|
||||
|
||||
public function __construct(
|
||||
private readonly string $projectDir
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function scrape(ScrapingRequest $request): ScrapingResult
|
||||
{
|
||||
@@ -44,7 +45,7 @@ class JavaScriptScraper implements ScraperInterface
|
||||
return 'javascript' === $sourceType;
|
||||
}
|
||||
|
||||
private function scrapeVerticalReader(ScrapingRequest $request, string $scriptPath): array
|
||||
private function scrapeVerticalReader(ScrapingRequest $request, string $scriptPath): array
|
||||
{
|
||||
$params = $request->getScrapingParameters();
|
||||
$processArgs = [
|
||||
@@ -70,7 +71,7 @@ class JavaScriptScraper implements ScraperInterface
|
||||
return $this->executeProcess($process);
|
||||
}
|
||||
|
||||
private function scrapeHorizontalReader(ScrapingRequest $request, string $scriptPath): array
|
||||
private function scrapeHorizontalReader(ScrapingRequest $request, string $scriptPath): array
|
||||
{
|
||||
$params = $request->getScrapingParameters();
|
||||
|
||||
@@ -143,10 +144,10 @@ class JavaScriptScraper implements ScraperInterface
|
||||
{
|
||||
return array_filter(
|
||||
array_map(
|
||||
fn($url) => $this->cleanImageUrl($url),
|
||||
fn ($url) => $this->cleanImageUrl($url),
|
||||
$urls
|
||||
),
|
||||
fn($url) => !empty($url) && filter_var($url, FILTER_VALIDATE_URL)
|
||||
fn ($url) => !empty($url) && filter_var($url, FILTER_VALIDATE_URL)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class ScraperFactory implements ScraperFactoryInterface
|
||||
public function getBestScraper(): ScraperInterface
|
||||
{
|
||||
$sortedTypes = array_keys(self::SCRAPER_PRIORITIES);
|
||||
usort($sortedTypes, fn($a, $b) => self::SCRAPER_PRIORITIES[$a] <=> self::SCRAPER_PRIORITIES[$b]);
|
||||
usort($sortedTypes, fn ($a, $b) => self::SCRAPER_PRIORITIES[$a] <=> self::SCRAPER_PRIORITIES[$b]);
|
||||
|
||||
return $this->scrapers[$sortedTypes[0]];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user