chapterRepository->getById($command->chapterId); $manga = $this->mangaRepository->getById($chapter->mangaId); $job = $this->jobRepository->get($command->jobId); $job->context['chapterId'] = $command->chapterId; $job->context['mangaTitle'] = $manga->getTitle(); $job->start(); $this->jobRepository->save($job); $this->eventBus->dispatch(new ChapterScrapingStarted($job->id, $manga->getTitle(), $chapter->chapterNumber)); $sources = $this->getSourcesToTry($manga); $slugsToTry = array_merge([$manga->getSlug()], $manga->getAlternativeSlugs()); $success = false; $lastException = null; foreach ($sources as $source) { foreach ($slugsToTry as $slug) { try { $job->context['sourceId'] = $source->getId()->getValue(); $job->context['slug'] = $slug; $this->jobRepository->save($job); $scrapingParameters = $source->getScrappingParameters(); $scrapingParameters['chapterNumber'] = $chapter->chapterNumber; $scrapingType = $scrapingParameters['scrapingType'] ?? 'html'; $scrapingRequest = new ScrapingRequest( $scrapingType, $source->buildChapterUrl($slug, $chapter->chapterNumber), $scrapingParameters ); $scraper = $this->scraperFactory->getScraperWithFallback($scrapingType); $scrapingResult = $scraper->scrape($scrapingRequest); $tempDir = new TempDirectory(); $downloadResults = $this->imageDownloader->downloadBatch( $scrapingResult->getImageUrls(), $tempDir, $job->id ); $localPaths = array_map(fn ($r) => $r->getLocalPath(), $downloadResults); $pagesDirectory = $this->imageStorage->storeChapterImages($command->chapterId, $localPaths); $pageCount = count($downloadResults); $job->complete(); $this->jobRepository->save($job); $this->eventBus->dispatch(new ChapterScraped($job->id, $command->chapterId, $pagesDirectory, $pageCount)); $tempDir->cleanup(); $success = true; break; } catch (\Exception $e) { $lastException = $e; } } if ($success) { break; } } if (!$success) { $errorMessage = $lastException?->getMessage() ?? 'Failed to scrape chapter from all available sources'; $job->fail($errorMessage); $this->jobRepository->save($job); $this->eventBus->dispatch(new ChapterScrapingFailed($job->id, $chapter->mangaId, $chapter->chapterNumber, $errorMessage)); } } /** * @param \App\Domain\Scraping\Domain\Model\Manga $manga * @return Source[] */ private function getSourcesToTry(\App\Domain\Scraping\Domain\Model\Manga $manga): array { if ($manga->hasPreferredSources()) { $preferredSources = []; foreach ($manga->getPreferredSources() as $sourceId) { $source = $this->sourceRepository->getById($sourceId); if ($source) { $preferredSources[] = $source; } if (count($preferredSources) >= 3) { break; } } if (!empty($preferredSources)) { return $preferredSources; } } return $this->sourceRepository->getAll(); } }