diff --git a/src/Domain/Manga/Infrastructure/Service/FilenameAnalyzer.php b/src/Domain/Manga/Infrastructure/Service/FilenameAnalyzer.php
index f71818a..ae02a4b 100644
--- a/src/Domain/Manga/Infrastructure/Service/FilenameAnalyzer.php
+++ b/src/Domain/Manga/Infrastructure/Service/FilenameAnalyzer.php
@@ -33,6 +33,18 @@ readonly class FilenameAnalyzer implements FilenameAnalyzerInterface
private function extractTitle(string $fileName): string
{
+ // Pattern avec tirets complets : titre-volume-42-chapter-100 ou titre-chapitre-100-volume-42
+ $fullDashCombinedPattern = '/^(?P
.*?)-(?:volume|chapter|chapitre)-\d+-(?:volume|chapter|chapitre)-\d+/i';
+ if (preg_match($fullDashCombinedPattern, $fileName, $matches)) {
+ return trim($matches['title']);
+ }
+
+ // Pattern avec tirets complets : titre-volume-42 ou titre-chapter-100 ou titre-chapitre-100
+ $fullDashPattern = '/^(?P.*?)-(?:volume|chapter|chapitre)-\d+/i';
+ if (preg_match($fullDashPattern, $fileName, $matches)) {
+ return trim($matches['title']);
+ }
+
// Pattern principal : titre suivi de volume/chapitre (inspiré du CbzService)
// Supporte: vol, volume, tome, t, ch, chap, chapter, chapitre
$titlePattern = '/^(?P.+?)(?:\s*-\s*|\s+)?(?:(?:[Tt]ome|[Vv]ol(?:ume)?\.?|[Cc]h(?:ap(?:itre|ter)?)?|[Tt])\s*\d+)/';
@@ -70,6 +82,12 @@ readonly class FilenameAnalyzer implements FilenameAnalyzerInterface
return (int) $matches['volume'];
}
+ // Pattern avec tirets complets pour volume : volume-42
+ $fullDashVolumePattern = '/volume-(?P\d+)/i';
+ if (preg_match($fullDashVolumePattern, $fileName, $matches)) {
+ return (int) $matches['volume'];
+ }
+
return null;
}
@@ -81,6 +99,12 @@ readonly class FilenameAnalyzer implements FilenameAnalyzerInterface
return (float) $matches['chapter'];
}
+ // Pattern avec tirets complets pour chapitre : chapter-100 ou chapitre-100
+ $fullDashChapterPattern = '/(?:chapter|chapitre)-(?P\d+(?:\.\d+)?)/i';
+ if (preg_match($fullDashChapterPattern, $fileName, $matches)) {
+ return (float) $matches['chapter'];
+ }
+
// Pattern underscore à la fin : _123.cbz
$newFormatPattern = '/_ch(?P\d+(?:\.\d+)?)(?:\.\w+)?$/i';
if (preg_match($newFormatPattern, $fileName, $matches)) {
diff --git a/tests/Domain/Manga/Infrastructure/Service/FilenameAnalyzerTest.php b/tests/Domain/Manga/Infrastructure/Service/FilenameAnalyzerTest.php
index db16e0d..88defbb 100644
--- a/tests/Domain/Manga/Infrastructure/Service/FilenameAnalyzerTest.php
+++ b/tests/Domain/Manga/Infrastructure/Service/FilenameAnalyzerTest.php
@@ -233,4 +233,64 @@ class FilenameAnalyzerTest extends TestCase
"Should not have volume for: {$case['filename']}");
}
}
+
+ public function test_it_handles_full_dash_patterns(): void
+ {
+ $testCases = [
+ [
+ 'filename' => 'berserk-volume-42.cbz',
+ 'expectedTitle' => 'berserk',
+ 'expectedVolume' => 42.0,
+ ],
+ [
+ 'filename' => 'berserk-chapter-100.cbz',
+ 'expectedTitle' => 'berserk',
+ 'expectedChapter' => 100.0,
+ ],
+ [
+ 'filename' => 'berserk-chapitre-100.cbz',
+ 'expectedTitle' => 'berserk',
+ 'expectedChapter' => 100.0,
+ ],
+ [
+ 'filename' => 'berserk-volume-42-chapter-100.cbz',
+ 'expectedTitle' => 'berserk',
+ 'expectedVolume' => 42.0,
+ 'expectedChapter' => 100.0,
+ ],
+ [
+ 'filename' => 'berserk-chapitre-100-volume-42.cbz',
+ 'expectedTitle' => 'berserk',
+ 'expectedVolume' => 42.0,
+ 'expectedChapter' => 100.0,
+ ],
+ ];
+
+ foreach ($testCases as $case) {
+ $result = $this->analyzer->analyze($case['filename']);
+
+ $this->assertEquals($case['expectedTitle'], $result->getTitle()->getValue(),
+ "Failed title extraction for: {$case['filename']}");
+
+ if (isset($case['expectedVolume'])) {
+ $this->assertTrue($result->hasVolumeNumber(),
+ "Should have volume for: {$case['filename']}");
+ $this->assertEquals($case['expectedVolume'], $result->getVolumeNumber()->getValue(),
+ "Failed volume extraction for: {$case['filename']}");
+ } else {
+ $this->assertFalse($result->hasVolumeNumber(),
+ "Should not have volume for: {$case['filename']}");
+ }
+
+ if (isset($case['expectedChapter'])) {
+ $this->assertTrue($result->hasChapterNumber(),
+ "Should have chapter for: {$case['filename']}");
+ $this->assertEquals($case['expectedChapter'], $result->getChapterNumber()->getValue(),
+ "Failed chapter extraction for: {$case['filename']}");
+ } else {
+ $this->assertFalse($result->hasChapterNumber(),
+ "Should not have chapter for: {$case['filename']}");
+ }
+ }
+ }
}