mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 16:42:24 +01:00
fix: don't strip accents on input data and sort series title with unicode collation
This commit is contained in:
parent
860274079d
commit
c2c697fba7
11 changed files with 37 additions and 39 deletions
|
|
@ -155,7 +155,7 @@ class SeriesLifecycle(
|
|||
seriesMetadataRepository.insert(
|
||||
SeriesMetadata(
|
||||
title = series.name,
|
||||
titleSort = series.name.stripAccents(),
|
||||
titleSort = series.name,
|
||||
seriesId = series.id,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class BookDtoDao(
|
|||
private val sorts =
|
||||
mapOf(
|
||||
"name" to b.NAME.collate(SqliteUdfDataSource.COLLATION_UNICODE_3),
|
||||
"series" to sd.TITLE_SORT.noCase(),
|
||||
"series" to sd.TITLE_SORT.collate(SqliteUdfDataSource.COLLATION_UNICODE_3),
|
||||
"created" to b.CREATED_DATE,
|
||||
"createdDate" to b.CREATED_DATE,
|
||||
"lastModified" to b.LAST_MODIFIED_DATE,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import org.gotson.komga.infrastructure.jooq.SeriesSearchHelper
|
|||
import org.gotson.komga.infrastructure.jooq.csAlias
|
||||
import org.gotson.komga.infrastructure.jooq.inOrNoCondition
|
||||
import org.gotson.komga.infrastructure.jooq.insertTempStrings
|
||||
import org.gotson.komga.infrastructure.jooq.noCase
|
||||
import org.gotson.komga.infrastructure.jooq.selectTempStrings
|
||||
import org.gotson.komga.infrastructure.jooq.sortByValues
|
||||
import org.gotson.komga.infrastructure.jooq.toSortField
|
||||
|
|
@ -85,7 +84,7 @@ class SeriesDtoDao(
|
|||
|
||||
private val sorts =
|
||||
mapOf(
|
||||
"metadata.titleSort" to d.TITLE_SORT.noCase(),
|
||||
"metadata.titleSort" to d.TITLE_SORT.collate(SqliteUdfDataSource.COLLATION_UNICODE_3),
|
||||
"createdDate" to s.CREATED_DATE,
|
||||
"created" to s.CREATED_DATE,
|
||||
"lastModifiedDate" to s.LAST_MODIFIED_DATE,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import org.gotson.komga.infrastructure.metadata.BookMetadataProvider
|
|||
import org.gotson.komga.infrastructure.metadata.SeriesMetadataFromBookProvider
|
||||
import org.gotson.komga.infrastructure.metadata.comicrack.dto.ComicInfo
|
||||
import org.gotson.komga.infrastructure.metadata.comicrack.dto.Manga
|
||||
import org.gotson.komga.language.stripAccents
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
import java.net.URI
|
||||
|
|
@ -142,7 +141,7 @@ class ComicInfoProvider(
|
|||
|
||||
return SeriesMetadataPatch(
|
||||
title = series,
|
||||
titleSort = series?.stripAccents(),
|
||||
titleSort = series,
|
||||
status = null,
|
||||
summary = null,
|
||||
readingDirection = readingDirection,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import org.gotson.komga.domain.model.SeriesMetadataPatch
|
|||
import org.gotson.komga.infrastructure.mediacontainer.epub.getPackageFileContent
|
||||
import org.gotson.komga.infrastructure.metadata.BookMetadataProvider
|
||||
import org.gotson.komga.infrastructure.metadata.SeriesMetadataFromBookProvider
|
||||
import org.gotson.komga.language.stripAccents
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
import org.jsoup.safety.Safelist
|
||||
|
|
@ -138,7 +137,7 @@ class EpubMetadataProvider(
|
|||
|
||||
return SeriesMetadataPatch(
|
||||
title = series,
|
||||
titleSort = series?.stripAccents(),
|
||||
titleSort = series,
|
||||
status = null,
|
||||
readingDirection = direction,
|
||||
publisher = publisher,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import org.gotson.komga.domain.model.Sidecar
|
|||
import org.gotson.komga.infrastructure.metadata.SeriesMetadataProvider
|
||||
import org.gotson.komga.infrastructure.metadata.mylar.dto.Status
|
||||
import org.gotson.komga.infrastructure.sidecar.SidecarSeriesConsumer
|
||||
import org.gotson.komga.language.stripAccents
|
||||
import org.springframework.stereotype.Service
|
||||
import kotlin.io.path.notExists
|
||||
import org.gotson.komga.infrastructure.metadata.mylar.dto.Series as MylarSeries
|
||||
|
|
@ -47,7 +46,7 @@ class MylarSeriesProvider(
|
|||
|
||||
return SeriesMetadataPatch(
|
||||
title = title,
|
||||
titleSort = title.stripAccents(),
|
||||
titleSort = title,
|
||||
status =
|
||||
when (metadata.status) {
|
||||
Status.Ended -> SeriesMetadata.Status.ENDED
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ fun LocalDateTime.notEquals(
|
|||
precision: TemporalUnit = ChronoUnit.MILLIS,
|
||||
) = this.truncatedTo(precision) != other.truncatedTo(precision)
|
||||
|
||||
/**
|
||||
* Warning: This affects the Unicode code points of Korean Hangul.
|
||||
*/
|
||||
fun String.stripAccents(): String = StringUtils.stripAccents(this)
|
||||
|
||||
fun LocalDate.toDate(): Date = Date.from(this.atStartOfDay(ZoneId.of("Z")).toInstant())
|
||||
|
|
|
|||
|
|
@ -168,33 +168,6 @@ class SeriesLifecycleTest(
|
|||
assertThat(savedBooks.map { it.number }).containsExactly(1, 2, 3, 4, 5)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given series name with diacritics when creating series then diacritics are stripped from metadata titlesort`() {
|
||||
// given
|
||||
val series1 = makeSeries("À l'assaut", library.id)
|
||||
val series2 = makeSeries("Être ou ne pas être", library.id)
|
||||
val series3 = makeSeries("Écarlate", library.id)
|
||||
|
||||
// when
|
||||
val created1 = seriesLifecycle.createSeries(series1)
|
||||
val created2 = seriesLifecycle.createSeries(series2)
|
||||
val created3 = seriesLifecycle.createSeries(series3)
|
||||
|
||||
// then
|
||||
with(seriesMetadataRepository.findById(created1.id)) {
|
||||
assertThat(title).isEqualTo(series1.name)
|
||||
assertThat(titleSort).isEqualTo("A l'assaut")
|
||||
}
|
||||
with(seriesMetadataRepository.findById(created2.id)) {
|
||||
assertThat(title).isEqualTo(series2.name)
|
||||
assertThat(titleSort).isEqualTo("Etre ou ne pas etre")
|
||||
}
|
||||
with(seriesMetadataRepository.findById(created3.id)) {
|
||||
assertThat(title).isEqualTo(series3.name)
|
||||
assertThat(titleSort).isEqualTo("Ecarlate")
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class Transactions {
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -127,6 +127,32 @@ class SeriesDtoDaoTest(
|
|||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class SortCriteria {
|
||||
@Test
|
||||
fun `given series when sorting by title sort then results are ordered`() {
|
||||
// given
|
||||
seriesLifecycle.createSeries(makeSeries("Éb", library.id))
|
||||
seriesLifecycle.createSeries(makeSeries("Ea", library.id))
|
||||
seriesLifecycle.createSeries(makeSeries("Ec", library.id))
|
||||
|
||||
searchIndexLifecycle.rebuildIndex()
|
||||
Thread.sleep(500) // index rebuild is done asynchronously, and need a slight delay to be updated
|
||||
|
||||
// when
|
||||
val found =
|
||||
seriesDtoDao
|
||||
.findAll(
|
||||
SeriesSearch(),
|
||||
SearchContext(user),
|
||||
UnpagedSorted(Sort.by("metadata.titleSort")),
|
||||
).content
|
||||
|
||||
// then
|
||||
assertThat(found.map { it.metadata.title }).containsExactly("Ea", "Éb", "Ec")
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class ReadProgress {
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ class ComicInfoProviderTest {
|
|||
|
||||
with(patch) {
|
||||
assertThat(title).isEqualTo("séries")
|
||||
assertThat(titleSort).isEqualTo("series")
|
||||
assertThat(titleSort).isEqualTo("séries")
|
||||
assertThat(status).isNull()
|
||||
assertThat(collections).containsExactlyInAnyOrder("collections", "multiple")
|
||||
assertThat(publisher).isEqualTo("publisher")
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class MylarSeriesProviderTest {
|
|||
|
||||
with(patch) {
|
||||
assertThat(title).isEqualTo("Sàndman")
|
||||
assertThat(titleSort).isEqualTo("Sandman")
|
||||
assertThat(titleSort).isEqualTo("Sàndman")
|
||||
assertThat(status).isEqualTo(SeriesMetadata.Status.ENDED)
|
||||
assertThat(summary).isEqualTo("Sandman comics formatted")
|
||||
assertThat(readingDirection).isNull()
|
||||
|
|
|
|||
Loading…
Reference in a new issue