mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 16:42:24 +01:00
fix(api): better matching of series name when importing books with metadata
This commit is contained in:
parent
ca93ed823e
commit
8b6d23e930
2 changed files with 86 additions and 2 deletions
|
|
@ -5,6 +5,9 @@ import org.gotson.komga.domain.model.Media
|
|||
import org.gotson.komga.domain.model.MediaNotReadyException
|
||||
import org.gotson.komga.domain.model.MediaProfile
|
||||
import org.gotson.komga.domain.model.PathContainedInPath
|
||||
import org.gotson.komga.domain.model.SearchCondition
|
||||
import org.gotson.komga.domain.model.SearchContext
|
||||
import org.gotson.komga.domain.model.SearchOperator
|
||||
import org.gotson.komga.domain.model.TransientBook
|
||||
import org.gotson.komga.domain.model.TypedBytes
|
||||
import org.gotson.komga.domain.model.toBookWithMedia
|
||||
|
|
@ -15,6 +18,7 @@ import org.gotson.komga.infrastructure.image.ImageType
|
|||
import org.gotson.komga.infrastructure.metadata.BookMetadataProvider
|
||||
import org.gotson.komga.infrastructure.metadata.SeriesMetadataFromBookProvider
|
||||
import org.springframework.beans.factory.annotation.Qualifier
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Service
|
||||
import java.nio.file.Paths
|
||||
|
||||
|
|
@ -64,7 +68,7 @@ class TransientBookLifecycle(
|
|||
fun getMetadata(transientBook: TransientBook): Pair<String?, Float?> {
|
||||
val bookWithMedia = transientBook.toBookWithMedia()
|
||||
val number = bookMetadataProviders.firstNotNullOfOrNull { it.getBookMetadataFromBook(bookWithMedia)?.numberSort }
|
||||
val series =
|
||||
val seriesNamesFromMetadata =
|
||||
seriesMetadataProviders
|
||||
.flatMap {
|
||||
buildList {
|
||||
|
|
@ -72,7 +76,16 @@ class TransientBookLifecycle(
|
|||
add(it.getSeriesMetadataFromBook(bookWithMedia, false)?.title)
|
||||
}
|
||||
}.filterNotNull()
|
||||
.firstNotNullOfOrNull { seriesRepository.findAllByTitleContaining(it).firstOrNull() }
|
||||
|
||||
val exactSearch = SearchCondition.AnyOfSeries(seriesNamesFromMetadata.map { SearchCondition.Title(SearchOperator.Is(it)) })
|
||||
val exactMatches = seriesRepository.findAll(exactSearch, SearchContext.ofAnonymousUser(), Pageable.unpaged())
|
||||
val series =
|
||||
if (!exactMatches.isEmpty) {
|
||||
exactMatches.content.first()
|
||||
} else {
|
||||
val containsSearch = SearchCondition.AnyOfSeries(seriesNamesFromMetadata.map { SearchCondition.Title(SearchOperator.Contains(it)) })
|
||||
seriesRepository.findAll(containsSearch, SearchContext.ofAnonymousUser(), Pageable.unpaged()).content.firstOrNull()
|
||||
}
|
||||
|
||||
return series?.id to number
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package org.gotson.komga.domain.service
|
||||
|
||||
import com.ninjasquad.springmockk.SpykBean
|
||||
import io.mockk.every
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.gotson.komga.domain.model.BookMetadataPatch
|
||||
import org.gotson.komga.domain.model.Media
|
||||
import org.gotson.komga.domain.model.SeriesMetadataPatch
|
||||
import org.gotson.komga.domain.model.TransientBook
|
||||
import org.gotson.komga.domain.model.makeBook
|
||||
import org.gotson.komga.domain.model.makeLibrary
|
||||
import org.gotson.komga.domain.model.makeSeries
|
||||
import org.gotson.komga.domain.persistence.LibraryRepository
|
||||
import org.gotson.komga.domain.persistence.SeriesRepository
|
||||
import org.gotson.komga.infrastructure.metadata.comicrack.ComicInfoProvider
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
|
||||
@SpringBootTest
|
||||
class TransientBookLifecycleTest(
|
||||
@Autowired private val seriesLifecycle: SeriesLifecycle,
|
||||
@Autowired private val seriesRepository: SeriesRepository,
|
||||
@Autowired private val libraryRepository: LibraryRepository,
|
||||
@Autowired private val transientBookLifecycle: TransientBookLifecycle,
|
||||
) {
|
||||
private val library = makeLibrary()
|
||||
|
||||
@SpykBean
|
||||
private lateinit var mockProvider: ComicInfoProvider
|
||||
|
||||
@BeforeAll
|
||||
fun `setup library`() {
|
||||
libraryRepository.insert(library)
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
fun teardown() {
|
||||
libraryRepository.deleteAll()
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun cleanup() {
|
||||
seriesLifecycle.deleteMany(seriesRepository.findAll())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when getting metadata for transient book then the most specific series name is matched first`() {
|
||||
seriesLifecycle.createSeries(makeSeries("Batman and Robin", libraryId = library.id))
|
||||
val seriesExact = makeSeries("Batman", libraryId = library.id)
|
||||
seriesLifecycle.createSeries(seriesExact)
|
||||
seriesLifecycle.createSeries(makeSeries("Batman and Robin (2022)", libraryId = library.id))
|
||||
|
||||
val book =
|
||||
TransientBook(
|
||||
makeBook("whatever"),
|
||||
Media(),
|
||||
)
|
||||
|
||||
every { mockProvider.getBookMetadataFromBook(any()) } returns BookMetadataPatch(null, null, null, 15F, null, null, null, null, null, emptyList())
|
||||
every { mockProvider.getSeriesMetadataFromBook(any(), any()) } returns SeriesMetadataPatch("BATMAN", null, null, null, null, null, null, null, null, null, emptySet())
|
||||
|
||||
val (seriesId, number) = transientBookLifecycle.getMetadata(book)
|
||||
|
||||
assertThat(seriesId).isEqualTo(seriesExact.id)
|
||||
assertThat(number).isEqualTo(15F)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue