From 2012f8be98561d834009a4d73a0245c7b2da753c Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Mon, 19 Jul 2021 11:22:05 +0800 Subject: [PATCH] feat: import StoryArcNumber from ComicInfo.xml Closes #573 --- .../metadata/comicrack/ComicInfoProvider.kt | 15 +- .../metadata/comicrack/dto/ComicInfo.kt | 3 + .../comicrack/ComicInfoProviderTest.kt | 140 +++++++++++++++++- .../metadata/comicrack/dto/ComicInfoTest.kt | 11 ++ .../comicrack/ComicInfo_StoryArc.xml | 5 + 5 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 komga/src/test/resources/comicrack/ComicInfo_StoryArc.xml diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt index 759f4dab5..6772b163c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProvider.kt @@ -65,8 +65,19 @@ class ComicInfoProvider( } comicInfo.storyArc?.let { value -> - val arcs = value.split(",").mapNotNull { it.trim().ifBlank { null } } - readLists.addAll(arcs.map { BookMetadataPatch.ReadListEntry(it) }) + // get list of arcs and corresponding number, split by `,` + val arcs = value.split(",").map { it.trim().ifBlank { null } } + val numbers = comicInfo.storyArcNumber?.split(",")?.map { it.trim().toIntOrNull() } + + if (!numbers.isNullOrEmpty()) { + // if there is associated numbers, add each valid association as a read list entry + (arcs zip numbers).forEach { (arc, number) -> + if (arc != null && number != null) readLists.add(BookMetadataPatch.ReadListEntry(arc, number)) + } + } else { + // if there is no numbers, only use the arcs name + readLists.addAll(arcs.filterNotNull().map { BookMetadataPatch.ReadListEntry(it) }) + } } return BookMetadataPatch( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfo.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfo.kt index eec217cc0..46aa6313c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfo.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfo.kt @@ -111,6 +111,9 @@ class ComicInfo { @JsonProperty(value = "StoryArc") var storyArc: String? = null + @JsonProperty(value = "StoryArcNumber") + var storyArcNumber: String? = null + @JsonProperty(value = "SeriesGroup") var seriesGroup: String? = null diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProviderTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProviderTest.kt index 0c09ddfd9..8d2c6a214 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProviderTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/ComicInfoProviderTest.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper import io.mockk.every import io.mockk.mockk import org.assertj.core.api.Assertions.assertThat +import org.gotson.komga.domain.model.BookMetadataPatch import org.gotson.komga.domain.model.BookWithMedia import org.gotson.komga.domain.model.Media import org.gotson.komga.domain.model.SeriesMetadata @@ -62,14 +63,137 @@ class ComicInfoProviderTest { assertThat(number).isEqualTo("010") assertThat(numberSort).isEqualTo(10F) assertThat(releaseDate).isEqualTo(LocalDate.of(2020, 2, 1)) - with(readLists) { - assertThat(this).hasSize(4) - assertThat(this.map { it.name }).containsExactly("story arc", "one", "two", "three") - this.first { it.number != null }.let { - assertThat(it.name).isEqualTo("story arc") - assertThat(it.number).isEqualTo(5) - } - } + + assertThat(readLists).hasSize(4) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("story arc", 5), + BookMetadataPatch.ReadListEntry("one"), + BookMetadataPatch.ReadListEntry("two"), + BookMetadataPatch.ReadListEntry("three"), + ) + } + } + + @Test + fun `given comicInfo with StoryArcNumber when getting book metadata then metadata patch is valid`() { + val comicInfo = ComicInfo().apply { + storyArc = "one" + storyArcNumber = "6" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(1) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("one", 6) + ) + } + } + + @Test + fun `given comicInfo with multiple StoryArcNumber when getting book metadata then metadata patch is valid`() { + val comicInfo = ComicInfo().apply { + alternateSeries = "story arc" + alternateNumber = "5" + storyArc = "one, two, three" + storyArcNumber = "6, 7, 8" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(4) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("story arc", 5), + BookMetadataPatch.ReadListEntry("one", 6), + BookMetadataPatch.ReadListEntry("two", 7), + BookMetadataPatch.ReadListEntry("three", 8), + ) + } + } + + @Test + fun `given comicInfo with uneven StoryArcNumber when getting book metadata then metadata patch is valid`() { + val comicInfo = ComicInfo().apply { + storyArc = "one, two" + storyArcNumber = "6, 7, 8" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(2) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("one", 6), + BookMetadataPatch.ReadListEntry("two", 7), + ) + } + } + + @Test + fun `given another comicInfo with uneven StoryArcNumber when getting book metadata then metadata patch is valid`() { + val comicInfo = ComicInfo().apply { + storyArc = "one, two, three" + storyArcNumber = "6, 7" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(2) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("one", 6), + BookMetadataPatch.ReadListEntry("two", 7), + ) + } + } + + @Test + fun `given comicInfo with invalid StoryArcNumber when getting book metadata then invalid pairs are omitted`() { + val comicInfo = ComicInfo().apply { + storyArc = "one, two, three" + storyArcNumber = "6, x, 8" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(2) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("one", 6), + BookMetadataPatch.ReadListEntry("three", 8), + ) + } + } + + @Test + fun `given comicInfo with invalid StoryArc when getting book metadata then invalid pairs are omitted`() { + val comicInfo = ComicInfo().apply { + storyArc = "one, , three" + storyArcNumber = "6, 7, 8" + } + + every { mockMapper.readValue(any(), ComicInfo::class.java) } returns comicInfo + + val patch = comicInfoProvider.getBookMetadataFromBook(BookWithMedia(book, media)) + + with(patch!!) { + assertThat(readLists).hasSize(2) + assertThat(readLists).containsExactlyInAnyOrder( + BookMetadataPatch.ReadListEntry("one", 6), + BookMetadataPatch.ReadListEntry("three", 8), + ) } } diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfoTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfoTest.kt index 955fc6418..3f85f881d 100644 --- a/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfoTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/metadata/comicrack/dto/ComicInfoTest.kt @@ -72,4 +72,15 @@ class ComicInfoTest { assertThat(manga).isNull() } } + + @Test + fun `given valid xml file with StoryArc fields when deserializing then properties are available`() { + val file = ClassPathResource("comicrack/ComicInfo_StoryArc.xml") + val comicInfo = mapper.readValue(file.url) + + with(comicInfo) { + assertThat(storyArc).isEqualTo("Arc") + assertThat(storyArcNumber).isEqualTo("2") + } + } } diff --git a/komga/src/test/resources/comicrack/ComicInfo_StoryArc.xml b/komga/src/test/resources/comicrack/ComicInfo_StoryArc.xml new file mode 100644 index 000000000..588502170 --- /dev/null +++ b/komga/src/test/resources/comicrack/ComicInfo_StoryArc.xml @@ -0,0 +1,5 @@ + + + Arc + 2 +