This commit is contained in:
InsanusMokrassar 2023-11-12 21:57:21 +06:00
parent ba3d054f0f
commit 58b1f26502
6 changed files with 65 additions and 21 deletions

View File

@ -1,5 +1,9 @@
# PlaguPoster # PlaguPoster
## 0.5.1
* Add opportunity to set unique
## 0.5.0 ## 0.5.0
* Dependencies update * Dependencies update

View File

@ -10,4 +10,4 @@ android.enableJetifier=true
# Project data # Project data
group=dev.inmo group=dev.inmo
version=0.5.0 version=0.5.1

View File

@ -1,5 +1,6 @@
package dev.inmo.plaguposter.ratings.selector package dev.inmo.plaguposter.ratings.selector
import dev.inmo.micro_utils.repos.KeyValueRepo
import korlibs.time.DateTime import korlibs.time.DateTime
import dev.inmo.plaguposter.posts.models.PostId import dev.inmo.plaguposter.posts.models.PostId
import dev.inmo.plaguposter.posts.repo.PostsRepo import dev.inmo.plaguposter.posts.repo.PostsRepo
@ -9,13 +10,14 @@ import dev.inmo.plaguposter.ratings.selector.models.SelectorConfig
class DefaultSelector ( class DefaultSelector (
private val config: SelectorConfig, private val config: SelectorConfig,
private val ratingsRepo: RatingsRepo, private val ratingsRepo: RatingsRepo,
private val postsRepo: PostsRepo private val postsRepo: PostsRepo,
private val latestChosenRepo: KeyValueRepo<PostId, DateTime>
) : Selector { ) : Selector {
override suspend fun take(n: Int, now: DateTime, exclude: List<PostId>): List<PostId> { override suspend fun take(n: Int, now: DateTime, exclude: List<PostId>): List<PostId> {
val result = mutableListOf<PostId>() val result = mutableListOf<PostId>()
do { do {
val selected = config.active(now.time) ?.rating ?.select(ratingsRepo, postsRepo, result + exclude, now) ?: break val selected = config.active(now.time) ?.rating ?.select(ratingsRepo, postsRepo, result + exclude, now, latestChosenRepo) ?: break
result.add(selected) result.add(selected)
} while (result.size < n) } while (result.size < n)

View File

@ -2,11 +2,9 @@ package dev.inmo.plaguposter.ratings.selector.models
import korlibs.time.DateTime import korlibs.time.DateTime
import korlibs.time.seconds import korlibs.time.seconds
import dev.inmo.micro_utils.pagination.FirstPagePagination
import dev.inmo.micro_utils.pagination.Pagination
import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging
import dev.inmo.micro_utils.repos.pagination.getAll import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.plaguposter.common.DateTimeSerializer import dev.inmo.micro_utils.repos.unset
import dev.inmo.plaguposter.posts.models.PostId import dev.inmo.plaguposter.posts.models.PostId
import dev.inmo.plaguposter.posts.repo.PostsRepo import dev.inmo.plaguposter.posts.repo.PostsRepo
import dev.inmo.plaguposter.ratings.models.Rating import dev.inmo.plaguposter.ratings.models.Rating
@ -25,17 +23,23 @@ data class RatingConfig(
val max: Rating? = null, val max: Rating? = null,
val prefer: Prefer = Prefer.Random, val prefer: Prefer = Prefer.Random,
val otherwise: RatingConfig? = null, val otherwise: RatingConfig? = null,
val postAge: Seconds? = null val postAge: Seconds? = null,
val uniqueCount: Int? = null
) { ) {
suspend fun select( suspend fun select(
ratingsRepo: RatingsRepo, ratingsRepo: RatingsRepo,
postsRepo: PostsRepo, postsRepo: PostsRepo,
exclude: List<PostId>, exclude: List<PostId>,
now: DateTime now: DateTime,
latestChosenRepo: KeyValueRepo<PostId, DateTime>
): PostId? { ): PostId? {
var reversed: Boolean = false var reversed: Boolean = false
var count: Int? = null var count: Int? = null
val allowedCreationTime = now - (postAge ?: 0).seconds val allowedCreationTime = now - (postAge ?: 0).seconds
val excludedByRepo = uniqueCount ?.let {
latestChosenRepo.getAll().toList().sortedBy { it.second }.takeLast(uniqueCount).map { it.first }
} ?: emptyList()
val resultExcluded = exclude + excludedByRepo
when (prefer) { when (prefer) {
Prefer.Max -> { Prefer.Max -> {
@ -59,40 +63,53 @@ data class RatingConfig(
ratingsRepo.getAllByWithNextPaging { keys(it) } ratingsRepo.getAllByWithNextPaging { keys(it) }
} }
else -> { else -> {
ratingsRepo.getPostsWithRatingLessEq(max, exclude = exclude).keys ratingsRepo.getPostsWithRatingLessEq(max, exclude = resultExcluded).keys
} }
} }
} }
else -> { else -> {
when (max) { when (max) {
null -> { null -> {
ratingsRepo.getPostsWithRatingGreaterEq(min, exclude = exclude).keys ratingsRepo.getPostsWithRatingGreaterEq(min, exclude = resultExcluded).keys
} }
else -> { else -> {
ratingsRepo.getPosts(min .. max, reversed, count, exclude = exclude).keys ratingsRepo.getPosts(min .. max, reversed, count, exclude = resultExcluded).keys
} }
} }
} }
}.filter { }.filter {
it !in exclude && (postsRepo.getPostCreationTime(it) ?.let { it < allowedCreationTime } ?: true) it !in resultExcluded && (postsRepo.getPostCreationTime(it) ?.let { it < allowedCreationTime } ?: true)
} }
return when (prefer) { val resultPosts: PostId = when (prefer) {
Prefer.Max, Prefer.Max,
Prefer.Min -> posts.firstOrNull() Prefer.Min -> posts.firstOrNull()
Prefer.Random -> posts.randomOrNull() Prefer.Random -> posts.randomOrNull()
} ?: otherwise ?.select(ratingsRepo, postsRepo, exclude, now) } ?: otherwise ?.select(ratingsRepo, postsRepo, resultExcluded, now, latestChosenRepo) ?: return null
val postsToKeep = uniqueCount ?.let {
(excludedByRepo + resultPosts).takeLast(it)
} ?: return resultPosts
val postsToRemoveFromKeep = excludedByRepo.filter { it !in postsToKeep }
latestChosenRepo.unset(postsToRemoveFromKeep)
val postsToAdd = postsToKeep.filter { it !in excludedByRepo }
latestChosenRepo.set(
postsToAdd.associateWith { DateTime.now() }
)
return resultPosts
} }
@Serializable(Prefer.Serializer::class) @Serializable(Prefer.Serializer::class)
sealed interface Prefer { sealed interface Prefer {
val type: String val type: String
@Serializable(Serializer::class) @Serializable(Serializer::class)
object Max : Prefer { override val type: String = "max" } data object Max : Prefer { override val type: String = "max" }
@Serializable(Serializer::class) @Serializable(Serializer::class)
object Min : Prefer { override val type: String = "min" } data object Min : Prefer { override val type: String = "min" }
@Serializable(Serializer::class) @Serializable(Serializer::class)
object Random : Prefer { override val type: String = "random" } data object Random : Prefer { override val type: String = "random" }
object Serializer : KSerializer<Prefer> { object Serializer : KSerializer<Prefer> {
override val descriptor: SerialDescriptor = String.serializer().descriptor override val descriptor: SerialDescriptor = String.serializer().descriptor

View File

@ -1,14 +1,33 @@
package dev.inmo.plaguposter.ratings.selector package dev.inmo.plaguposter.ratings.selector
import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.exposed.keyvalue.ExposedKeyValueRepo
import dev.inmo.micro_utils.repos.mappers.withMapper
import dev.inmo.plagubot.Plugin import dev.inmo.plagubot.Plugin
import dev.inmo.plaguposter.posts.models.PostId
import dev.inmo.plaguposter.ratings.selector.models.SelectorConfig import dev.inmo.plaguposter.ratings.selector.models.SelectorConfig
import korlibs.time.DateTime
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.koin.core.module.Module import org.koin.core.module.Module
import org.koin.core.qualifier.qualifier
object Plugin : Plugin { object Plugin : Plugin {
override fun Module.setupDI(database: Database, params: JsonObject) { override fun Module.setupDI(database: Database, params: JsonObject) {
single { get<Json>().decodeFromJsonElement(SelectorConfig.serializer(), params["selector"] ?: return@single null) } single { get<Json>().decodeFromJsonElement(SelectorConfig.serializer(), params["selector"] ?: return@single null) }
single<Selector> { DefaultSelector(get(), get(), get()) } single<KeyValueRepo<PostId, DateTime>>(qualifier("latestChosenRepo")) {
ExposedKeyValueRepo(
get(),
{ text("post_id") },
{ double("date_time") },
"LatestChosenRepo"
).withMapper(
{ string },
{ unixMillis },
{ PostId(this) },
{ DateTime(this) }
)
}
single<Selector> { DefaultSelector(get(), get(), get(), get(qualifier("latestChosenRepo"))) }
} }
} }

View File

@ -51,7 +51,8 @@
"to": "23:59" "to": "23:59"
}, },
"rating": { "rating": {
"prefer": "max" "prefer": "max",
"uniqueCount": 1
} }
}, },
{ {
@ -60,7 +61,8 @@
"to": "00:00" "to": "00:00"
}, },
"rating": { "rating": {
"prefer": "max" "prefer": "max",
"uniqueCount": 1
} }
} }
] ]