mirror of https://github.com/hykilpikonna/AquaDX
[+] Mai2 music ranking
parent
528960940c
commit
03b452e426
|
@ -13,6 +13,7 @@ plugins {
|
||||||
kotlin("plugin.jpa") version ktVer
|
kotlin("plugin.jpa") version ktVer
|
||||||
kotlin("plugin.serialization") version ktVer
|
kotlin("plugin.serialization") version ktVer
|
||||||
kotlin("plugin.allopen") version ktVer
|
kotlin("plugin.allopen") version ktVer
|
||||||
|
kotlin("kapt") version ktVer
|
||||||
id("io.freefair.lombok") version "8.6"
|
id("io.freefair.lombok") version "8.6"
|
||||||
id("org.springframework.boot") version "3.2.3"
|
id("org.springframework.boot") version "3.2.3"
|
||||||
id("com.github.ben-manes.versions") version "0.51.0"
|
id("com.github.ben-manes.versions") version "0.51.0"
|
||||||
|
@ -55,6 +56,8 @@ dependencies {
|
||||||
runtimeOnly("org.xerial:sqlite-jdbc:3.45.2.0")
|
runtimeOnly("org.xerial:sqlite-jdbc:3.45.2.0")
|
||||||
implementation("org.hibernate.orm:hibernate-core:6.4.4.Final")
|
implementation("org.hibernate.orm:hibernate-core:6.4.4.Final")
|
||||||
implementation("org.hibernate.orm:hibernate-community-dialects:6.4.4.Final")
|
implementation("org.hibernate.orm:hibernate-community-dialects:6.4.4.Final")
|
||||||
|
implementation("io.github.openfeign.querydsl:querydsl-jpa:6.10.1")
|
||||||
|
kapt("io.github.openfeign.querydsl:querydsl-apt:6.10.1:jpa")
|
||||||
|
|
||||||
// JSR305 for nullable
|
// JSR305 for nullable
|
||||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
|
@ -122,6 +125,11 @@ hibernate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kapt {
|
||||||
|
includeCompileClasspath = false
|
||||||
|
keepJavacAnnotationProcessors = true
|
||||||
|
}
|
||||||
|
|
||||||
allOpen {
|
allOpen {
|
||||||
annotation("jakarta.persistence.Entity")
|
annotation("jakarta.persistence.Entity")
|
||||||
annotation("jakarta.persistence.MappedSuperclass")
|
annotation("jakarta.persistence.MappedSuperclass")
|
||||||
|
@ -153,3 +161,9 @@ tasks.withType<Javadoc> {
|
||||||
tasks.getByName<Jar>("jar") {
|
tasks.getByName<Jar>("jar") {
|
||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java.srcDir("${layout.buildDirectory.get()}/generated/source/kapt/main")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Maimai2ServletController(
|
||||||
val getUserFavoriteItem: GetUserFavoriteItemHandler,
|
val getUserFavoriteItem: GetUserFavoriteItemHandler,
|
||||||
val getUserRivalMusic: GetUserRivalMusicHandler,
|
val getUserRivalMusic: GetUserRivalMusicHandler,
|
||||||
val getUserCharacter: GetUserCharacterHandler,
|
val getUserCharacter: GetUserCharacterHandler,
|
||||||
|
val getGameRanking: GetGameRankingHandler,
|
||||||
val repos: Mai2Repos
|
val repos: Mai2Repos
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -222,7 +223,6 @@ class Maimai2ServletController(
|
||||||
val getUserIntimate = UserReqHandler { _, uid -> mapOf("userId" to uid, "length" to 0, "userIntimateList" to empty) }
|
val getUserIntimate = UserReqHandler { _, uid -> mapOf("userId" to uid, "length" to 0, "userIntimateList" to empty) }
|
||||||
val getTransferFriend = UserReqHandler { _, uid -> mapOf("userId" to uid, "transferFriendList" to empty) }
|
val getTransferFriend = UserReqHandler { _, uid -> mapOf("userId" to uid, "transferFriendList" to empty) }
|
||||||
val getGameNgMusicId = BaseHandler { mapOf("length" to 0, "musicIdList" to empty) }
|
val getGameNgMusicId = BaseHandler { mapOf("length" to 0, "musicIdList" to empty) }
|
||||||
val getGameRanking = BaseHandler { mapOf("type" to it["type"].toString(), "gameRankingList" to empty) }
|
|
||||||
val getGameTournamentInfo = BaseHandler { mapOf("length" to 0, "gameTournamentInfoList" to empty) }
|
val getGameTournamentInfo = BaseHandler { mapOf("length" to 0, "gameTournamentInfoList" to empty) }
|
||||||
val getGameKaleidxScope = BaseHandler { mapOf("gameKaleidxScopeList" to empty) }
|
val getGameKaleidxScope = BaseHandler { mapOf("gameKaleidxScopeList" to empty) }
|
||||||
val getUserKaleidxScope = UserReqHandler { _, uid -> mapOf("userId" to uid, "userKaleidxScopeList" to empty) }
|
val getUserKaleidxScope = UserReqHandler { _, uid -> mapOf("userId" to uid, "userKaleidxScopeList" to empty) }
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package icu.samnyan.aqua.sega.maimai2.handler
|
||||||
|
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
|
import ext.logger
|
||||||
|
import ext.thread
|
||||||
|
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||||
|
import icu.samnyan.aqua.sega.maimai2.model.userdata.QMai2UserPlaylog
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import kotlin.concurrent.Volatile
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author samnyan (privateamusement@protonmail.com)
|
||||||
|
*/
|
||||||
|
@Component("Maimai2GetGameRankingHandler")
|
||||||
|
class GetGameRankingHandler(
|
||||||
|
private val queryFactory: JPAQueryFactory
|
||||||
|
) : BaseHandler {
|
||||||
|
private data class MusicRankingItem(val id: Int, val point: Long, val userName: String = "")
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var musicRankingCache: List<MusicRankingItem> = emptyList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
// To make sure the cache is initialized before the first request,
|
||||||
|
// not using `initialDelay = 0` in `@Scheduled`.
|
||||||
|
thread { refreshMusicRankingCache() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 3600_000)
|
||||||
|
private fun refreshMusicRankingCache() {
|
||||||
|
// Get the play count of each music in the last N days
|
||||||
|
val queryAfter = LocalDateTime.now().minusDays(LOOK_BACK_DAYS)
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||||
|
val queryAfterStr = queryAfter.format(formatter)
|
||||||
|
|
||||||
|
val qPlaylog = QMai2UserPlaylog.mai2UserPlaylog
|
||||||
|
val cMusicId = qPlaylog.musicId
|
||||||
|
val cUserCount = qPlaylog.user.id.countDistinct()
|
||||||
|
musicRankingCache = queryFactory
|
||||||
|
.select(cMusicId, cUserCount)
|
||||||
|
.from(qPlaylog)
|
||||||
|
.where(qPlaylog.userPlayDate.stringValue().goe(queryAfterStr))
|
||||||
|
.groupBy(cMusicId)
|
||||||
|
.orderBy(cUserCount.desc())
|
||||||
|
.limit(QUERY_LIMIT)
|
||||||
|
.fetch()
|
||||||
|
.map { MusicRankingItem(it.get(cMusicId)!!, it.get(cUserCount)!!) }
|
||||||
|
|
||||||
|
log.info("Refreshed music ranking cache: ${musicRankingCache.size} items")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(request: Map<String, Any>): Any = mapOf(
|
||||||
|
"type" to request["type"],
|
||||||
|
"gameRankingList" to when(request["type"]) {
|
||||||
|
1 -> musicRankingCache
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val log = logger()
|
||||||
|
|
||||||
|
const val LOOK_BACK_DAYS: Long = 7
|
||||||
|
const val QUERY_LIMIT: Long = 50
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package icu.samnyan.aqua.spring
|
||||||
|
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
|
import jakarta.persistence.EntityManager
|
||||||
|
import jakarta.persistence.PersistenceContext
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class QuerydslConfig {
|
||||||
|
@PersistenceContext
|
||||||
|
private lateinit var entityManager: EntityManager
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun jpaQueryFactory(): JPAQueryFactory {
|
||||||
|
return JPAQueryFactory(entityManager)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
CREATE INDEX idx_play_date_music_user
|
||||||
|
ON maimai2_user_playlog (user_play_date, music_id, user_id);
|
Loading…
Reference in New Issue