use fuzzykot library

This commit is contained in:
2026-08-09 18:23:35 +03:00
parent 2c0c244060
commit 70c64a9251
3 changed files with 7 additions and 16 deletions
+1
View File
@@ -35,6 +35,7 @@ dependencies {
implementation(libs.ktor.server.websockets.jvm) implementation(libs.ktor.server.websockets.jvm)
implementation(libs.ktor.server.cors) implementation(libs.ktor.server.cors)
implementation(libs.fuzzykot)
implementation(libs.androidx.datastore.preferences.core) implementation(libs.androidx.datastore.preferences.core)
implementation(libs.kxml2) implementation(libs.kxml2)
implementation(libs.jsoup) implementation(libs.jsoup)
@@ -1,5 +1,6 @@
package ru.shadowsparky.vbox.backend.data package ru.shadowsparky.vbox.backend.data
import com.github.terrakok.fuzzykot.Levenshtein
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
import ru.shadowsparky.vbox.shared.domain.model.VideoItem import ru.shadowsparky.vbox.shared.domain.model.VideoItem
@@ -12,9 +13,9 @@ class FuzzyMovieSearchFilter {
return original.map { movie -> return original.map { movie ->
val titleNormalized = movie.title.normalize() val titleNormalized = movie.title.normalize()
if (titleNormalized.contains(query)) { if (titleNormalized.contains(query)) {
return@map Pair(movie, 1.0) return@map Pair(movie, 100)
} }
val score = titleNormalized.fuzzySimilarity(query) val score = Levenshtein.tokenSortRatio(titleNormalized, query)
Pair(movie, score) Pair(movie, score)
}.filter { it.second >= THRESHOLD }.sortedByDescending { it.second }.map { it.first } }.filter { it.second >= THRESHOLD }.sortedByDescending { it.second }.map { it.first }
} }
@@ -47,20 +48,7 @@ class FuzzyMovieSearchFilter {
} }
} }
private fun String.fuzzySimilarity(other: String): Double {
if (this == other) return 1.0
if (this.isBlank() || other.isBlank()) return 0.0
val s1Pairs = this.windowed(2)
val s2Pairs = other.windowed(2).toMutableList()
if (s1Pairs.isEmpty() || s2Pairs.isEmpty()) return 0.0
var matches = 0
for (pair in s1Pairs) {
if (s2Pairs.remove(pair)) { matches++ }
}
return (2.0 * matches) / (s1Pairs.size + other.windowed(2).size)
}
private companion object { private companion object {
const val THRESHOLD: Double = 0.45 const val THRESHOLD = 55
} }
} }
+2
View File
@@ -8,6 +8,7 @@ compose-material-version = "1.11.0-alpha03"
compose-version = "1.11.1" compose-version = "1.11.1"
desugar_jdk_libs = "2.1.5" desugar_jdk_libs = "2.1.5"
foundation = "1.11.1" foundation = "1.11.1"
fuzzykot = "1.0.0"
haze = "1.7.2" haze = "1.7.2"
java-jwt = "4.6.0" java-jwt = "4.6.0"
kotlin-version = "2.4.10" kotlin-version = "2.4.10"
@@ -66,6 +67,7 @@ androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "sqlite" }
androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" } androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil-compose" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil-compose" }
com-android-application-gradle-plugin = { module = "com.android.application:com.android.application.gradle.plugin", version.ref = "agp" } com-android-application-gradle-plugin = { module = "com.android.application:com.android.application.gradle.plugin", version.ref = "agp" }
fuzzykot = { module = "com.github.terrakok:fuzzykot", version.ref = "fuzzykot" }
haze = { module = "dev.chrisbanes.haze:haze", version.ref = "haze" } haze = { module = "dev.chrisbanes.haze:haze", version.ref = "haze" }
haze-materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = "haze" } haze-materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref = "haze" }
java-jwt = { module = "com.auth0:java-jwt", version.ref = "java-jwt" } java-jwt = { module = "com.auth0:java-jwt", version.ref = "java-jwt" }