feat: comicrack read list matching will look for series with and without volume in brackets

Closes: #1075
This commit is contained in:
Gauthier Roebroeck 2023-03-07 18:21:34 +08:00
parent 53b1137d97
commit ac1e956890
9 changed files with 64 additions and 47 deletions

View file

@ -1,7 +1,9 @@
<template>
<tr v-if="match">
<slot/>
<td>{{ match.request.series }}</td>
<td>
<div v-for="s in match.request.series" :key="s">{{ s }}</div>
</td>
<td>{{ match.request.number }}</td>
<!-- Series picker -->
@ -130,7 +132,7 @@ export default Vue.extend({
if (match.matches.length === 1) {
seriesId = match.matches[0].seriesId
} else if (match.matches.length > 1) {
seriesId = match.matches.find((m) => m.bookIds.length > 1)?.seriesId
seriesId = match.matches.find((m) => m.bookIds.length > 0)?.seriesId
}
if (seriesId) {
this.selectedSeries = await this.$komgaSeries.getOneSeries(seriesId)

View file

@ -40,6 +40,11 @@ export interface ReadListRequestBookDto {
number: string,
}
export interface ReadListRequestBookV2Dto {
series: string[],
number: string,
}
export interface ReadListThumbnailDto {
id: string,
readListId: string,
@ -59,7 +64,7 @@ export interface ReadListMatchDto {
}
export interface ReadListRequestBookMatchesDto {
request: ReadListRequestBookDto,
request: ReadListRequestBookV2Dto,
matches: ReadListRequestBookMatchDto[],
}

View file

@ -9,7 +9,7 @@ data class ReadListRequest(
)
data class ReadListRequestBook(
val series: String,
val series: Set<String>,
val number: String,
)

View file

@ -35,7 +35,7 @@ class ReadListMatcher(
val unmatchedBooks = mutableListOf<ReadListRequestResultBook>()
request.books.forEach { book ->
val seriesMatches = seriesRepository.findAllByTitle(book.series)
val seriesMatches = seriesRepository.findAllByTitle(book.series.first())
when {
seriesMatches.size > 1 -> unmatchedBooks += ReadListRequestResultBook(book, "ERR_1011")
seriesMatches.isEmpty() -> unmatchedBooks += ReadListRequestResultBook(book, "ERR_1012")
@ -77,7 +77,7 @@ class ReadListMatcher(
else ReadListMatch(request.name)
val matches = request.books.map { book ->
val matches = seriesRepository.findAllByTitle(book.series).associateWith { series ->
val matches = book.series.flatMap { seriesRepository.findAllByTitle(it) }.associateWith { series ->
bookRepository.findAllBySeriesId(series.id)
.filter { (bookMetadataRepository.findById(it.id).number.trimStart('0') == book.number.trimStart('0')) }
}

View file

@ -29,7 +29,7 @@ class ReadListProvider(
val books = readingList.books.mapNotNull {
val series = computeSeriesFromSeriesAndVolume(it.series, it.volume)
if (!series.isNullOrBlank() && it.number != null)
ReadListRequestBook(series, it.number!!.trim())
ReadListRequestBook(setOf(series), it.number!!.trim())
else {
logger.warn { "Book is missing series or number, skipping: $it" }
null
@ -61,9 +61,9 @@ class ReadListProvider(
if (readingList.books.isEmpty()) throw ComicRackListException("ReadingList does not contain any Book element", "ERR_1029")
val books = readingList.books.map {
val series = computeSeriesFromSeriesAndVolume(it.series, it.volume)
if (series.isNullOrBlank() || it.number == null) throw ComicRackListException("Book is missing series or number: $it", "ERR_1031")
else ReadListRequestBook(series, it.number!!.trim())
if (it.series.isNullOrBlank() || it.number == null) throw ComicRackListException("Book is missing series or number: $it", "ERR_1031")
val series = setOfNotNull(computeSeriesFromSeriesAndVolume(it.series, it.volume), it.series?.ifBlank { null })
ReadListRequestBook(series, it.number!!.trim())
}
return ReadListRequest(name = readingList.name!!, books = books)

View file

@ -1,6 +1,7 @@
package org.gotson.komga.interfaces.api.rest.dto
import org.gotson.komga.domain.model.ReadListMatch
import org.gotson.komga.domain.model.ReadListRequestBook
import org.gotson.komga.domain.model.ReadListRequestMatch
data class ReadListRequestMatchDto(
@ -14,7 +15,7 @@ fun ReadListRequestMatch.toDto() =
readListMatch.toDto(),
matches.map {
ReadListRequestBookMatchesDto(
it.request.toDto(),
it.request.toDtoV2(),
it.matches.entries.map { (series, books) ->
ReadListRequestBookMatchDto(
series.id,
@ -31,10 +32,21 @@ data class ReadListMatchDto(
)
data class ReadListRequestBookMatchesDto(
val request: ReadListRequestBookDto,
val request: ReadListRequestBookV2Dto,
val matches: List<ReadListRequestBookMatchDto>,
)
data class ReadListRequestBookV2Dto(
val series: Set<String>,
val number: String,
)
fun ReadListRequestBook.toDtoV2() =
ReadListRequestBookV2Dto(
series = series,
number = number,
)
data class ReadListRequestBookMatchDto(
val seriesId: String,
val bookIds: List<String>,

View file

@ -37,6 +37,6 @@ fun ReadListRequestResultBook.toDto() =
fun ReadListRequestBook.toDto() =
ReadListRequestBookDto(
series = series,
series = series.first(),
number = number,
)

View file

@ -103,10 +103,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "readlist",
books = listOf(
ReadListRequestBook(series = "Batman: White Knight", number = "1"),
ReadListRequestBook(series = "joker", number = "02"),
ReadListRequestBook(series = "Batman: White Knight", number = "2"),
ReadListRequestBook(series = "joker", number = "25"),
ReadListRequestBook(series = setOf("Batman: White Knight"), number = "1"),
ReadListRequestBook(series = setOf("joker"), number = "02"),
ReadListRequestBook(series = setOf("Batman: White Knight"), number = "2"),
ReadListRequestBook(series = setOf("joker"), number = "25"),
),
)
@ -143,10 +143,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "my readlist",
books = listOf(
ReadListRequestBook(series = "batman: white knight", number = "1"),
ReadListRequestBook(series = "joker", number = "2"),
ReadListRequestBook(series = "BATMAN: WHITE KNIGHT", number = "2"),
ReadListRequestBook(series = "joker", number = "25"),
ReadListRequestBook(series = setOf("batman: white knight"), number = "1"),
ReadListRequestBook(series = setOf("joker"), number = "2"),
ReadListRequestBook(series = setOf("BATMAN: WHITE KNIGHT"), number = "2"),
ReadListRequestBook(series = setOf("joker"), number = "25"),
),
)
@ -194,10 +194,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "readlist",
books = listOf(
ReadListRequestBook(series = "tokyo ghost", number = "1"),
ReadListRequestBook(series = "batman", number = "3"),
ReadListRequestBook(series = "joker", number = "3"),
ReadListRequestBook(series = "batman", number = "2"),
ReadListRequestBook(series = setOf("tokyo ghost"), number = "1"),
ReadListRequestBook(series = setOf("batman"), number = "3"),
ReadListRequestBook(series = setOf("joker"), number = "3"),
ReadListRequestBook(series = setOf("batman"), number = "2"),
),
)
@ -241,9 +241,9 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "readlist",
books = listOf(
ReadListRequestBook(series = "batman", number = "1"),
ReadListRequestBook(series = "batman", number = "2"),
ReadListRequestBook(series = "batman", number = "2"),
ReadListRequestBook(series = setOf("batman"), number = "1"),
ReadListRequestBook(series = setOf("batman"), number = "2"),
ReadListRequestBook(series = setOf("batman"), number = "2"),
),
)
@ -315,10 +315,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "readlist",
books = listOf(
ReadListRequestBook(series = "Batman: White Knight", number = "1"),
ReadListRequestBook(series = "joker", number = "02"),
ReadListRequestBook(series = "Batman: White Knight", number = "2"),
ReadListRequestBook(series = "joker", number = "25"),
ReadListRequestBook(series = setOf("Batman: White Knight"), number = "1"),
ReadListRequestBook(series = setOf("joker"), number = "02"),
ReadListRequestBook(series = setOf("Batman: White Knight"), number = "2"),
ReadListRequestBook(series = setOf("joker"), number = "25"),
),
)
@ -381,10 +381,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "my readlist",
books = listOf(
ReadListRequestBook(series = "batman: white knight", number = "1"),
ReadListRequestBook(series = "joker", number = "2"),
ReadListRequestBook(series = "BATMAN: WHITE KNIGHT", number = "2"),
ReadListRequestBook(series = "joker", number = "25"),
ReadListRequestBook(series = setOf("batman: white knight"), number = "1"),
ReadListRequestBook(series = setOf("joker"), number = "2"),
ReadListRequestBook(series = setOf("BATMAN: WHITE KNIGHT"), number = "2"),
ReadListRequestBook(series = setOf("joker"), number = "25"),
),
)
@ -443,10 +443,10 @@ class ReadListMatcherTest(
val request = ReadListRequest(
name = "readlist",
books = listOf(
ReadListRequestBook(series = "tokyo ghost", number = "1"),
ReadListRequestBook(series = "batman", number = "3"),
ReadListRequestBook(series = "joker", number = "2"),
ReadListRequestBook(series = "batman", number = "2"),
ReadListRequestBook(series = setOf("tokyo ghost"), number = "1"),
ReadListRequestBook(series = setOf("batman"), number = "3"),
ReadListRequestBook(series = setOf("joker"), number = "2"),
ReadListRequestBook(series = setOf("batman"), number = "2"),
),
)

View file

@ -16,7 +16,6 @@ class ReadListProviderTest {
private val mockMapper = mockk<XmlMapper>()
private val readListProvider = ReadListProvider(mockMapper)
@Nested
inner class ImportFromCbl {
@Test
@ -49,12 +48,12 @@ class ReadListProviderTest {
assertThat(books).hasSize(2)
with(books[0]) {
assertThat(series).isEqualTo("series 1 (2005)")
assertThat(series).containsExactlyInAnyOrder("series 1 (2005)")
assertThat(number).isEqualTo("4")
}
with(books[1]) {
assertThat(series).isEqualTo("series 2")
assertThat(series).containsExactlyInAnyOrder("series 2")
assertThat(number).isEqualTo("1")
}
}
@ -189,18 +188,17 @@ class ReadListProviderTest {
val request = readListProvider.importFromCblV2(ByteArray(0))
// then
assertThat(request).isNotNull
with(request!!) {
with(request) {
assertThat(name).isEqualTo(cbl.name)
assertThat(books).hasSize(2)
with(books[0]) {
assertThat(series).isEqualTo("series 1 (2005)")
assertThat(series).containsExactlyInAnyOrder("series 1 (2005)", "series 1")
assertThat(number).isEqualTo("4")
}
with(books[1]) {
assertThat(series).isEqualTo("series 2")
assertThat(series).containsExactlyInAnyOrder("series 2")
assertThat(number).isEqualTo("1")
}
}