Files
Mangarr/src/Domain/Manga/Infrastructure/Service/FilenameAnalyzer.php
ext.jeremy.guillot@maxicoffee.domains 3170a7c60e feat: analyse import + all tests fixed
2025-10-15 16:14:15 +02:00

107 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Domain\Manga\Infrastructure\Service;
use App\Domain\Manga\Domain\Contract\Service\FilenameAnalyzerInterface;
use App\Domain\Manga\Domain\Model\AnalyzedFilename;
use App\Domain\Manga\Domain\Model\ValueObject\ChapterNumber;
use App\Domain\Manga\Domain\Model\ValueObject\MangaTitle;
use App\Domain\Manga\Domain\Model\ValueObject\VolumeNumber;
readonly class FilenameAnalyzer implements FilenameAnalyzerInterface
{
public function analyze(string $filename): AnalyzedFilename
{
// Enlever l'extension
$nameWithoutExtension = preg_replace('/\.(cbz|cbr)$/i', '', $filename);
// Extraire les informations en utilisant la logique du CbzService
$titleStr = $this->extractTitle($nameWithoutExtension);
$volumeNumber = $this->extractVolume($nameWithoutExtension);
$chapterNumber = $this->extractChapter($nameWithoutExtension);
$cleanedTitle = $this->cleanTitle($titleStr);
return new AnalyzedFilename(
title: new MangaTitle($cleanedTitle),
chapterNumber: $chapterNumber !== null ? new ChapterNumber($chapterNumber) : null,
volumeNumber: $volumeNumber !== null ? new VolumeNumber((float) $volumeNumber) : null
);
}
private function extractTitle(string $fileName): string
{
// Pattern principal : titre suivi de volume/chapitre (inspiré du CbzService)
// Supporte: vol, volume, tome, t, ch, chap, chapter, chapitre
$titlePattern = '/^(?P<title>.+?)(?:\s*-\s*|\s+)?(?:(?:[Tt]ome|[Vv]ol(?:ume)?\.?|[Cc]h(?:ap(?:itre|ter)?)?|[Tt])\s*\d+)/';
if (preg_match($titlePattern, $fileName, $matches)) {
return trim($matches['title']);
}
// Pattern underscore : titre_vol123 ou titre_ch456 ou titre_chapter_1094
$underscorePattern = '/^(?P<title>.*?)_(?:vol|tome|t|ch|chap|chapter|chapitre)[\s_-]*\d+/i';
if (preg_match($underscorePattern, $fileName, $matches)) {
return trim($matches['title']);
}
// Pattern avec tiret : titre-vol123 ou titre-ch456 ou titre-tome-50
$dashPattern = '/^(?P<title>.*?)-(?:vol|tome|t|ch|chap|chapter|chapitre)[\s_-]*\d+/i';
if (preg_match($dashPattern, $fileName, $matches)) {
return trim($matches['title']);
}
// Pattern underscore simple : titre_123
$newFormatPattern = '/^(?P<title>.*?)_\d+/';
if (preg_match($newFormatPattern, $fileName, $matches)) {
return trim($matches['title']);
}
// Si aucun pattern ne matche, retourner le nom sans extension
return $fileName;
}
private function extractVolume(string $fileName): ?int
{
// Pattern pour volume : vol123, volume123, tome123, t123, v123
$volumePattern = '/(?:[Tt]ome|[Vv]ol(?:ume)?\.?|[Tt]|[Vv])[\s\-_]*(?P<volume>\d+)/i';
if (preg_match($volumePattern, $fileName, $matches)) {
return (int) $matches['volume'];
}
return null;
}
private function extractChapter(string $fileName): ?float
{
// Pattern pour chapitre : ch123, chap123, chapter123, chapitre123
$chapterPattern = '/[Cc]h(?:ap(?:itre|ter)?)?[\s\-_]*(?P<chapter>\d+(?:\.\d+)?)/i';
if (preg_match($chapterPattern, $fileName, $matches)) {
return (float) $matches['chapter'];
}
// Pattern underscore à la fin : _123.cbz
$newFormatPattern = '/_ch(?P<chapter>\d+(?:\.\d+)?)(?:\.\w+)?$/i';
if (preg_match($newFormatPattern, $fileName, $matches)) {
return (float) $matches['chapter'];
}
return null;
}
private function cleanTitle(string $title): string
{
// Enlever les patterns communs (avec séparateurs possibles)
$cleanTitle = preg_replace('/[\s\-_]?(?:scan|raw|fr|en|jp|hq|lq)[\s\-_]?/i', ' ', $title);
// Enlever les caractères spéciaux en début/fin
$cleanTitle = trim($cleanTitle, ' -_.');
// Normaliser les espaces multiples
$cleanTitle = preg_replace('/\s+/', ' ', $cleanTitle);
return trim($cleanTitle);
}
}