feat(audio-recommendation): 추천 콘텐츠 제목 번역을 적용한다
This commit is contained in:
+40
-12
@@ -11,6 +11,7 @@ import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
|
||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType
|
||||
import kr.co.vividnext.sodalive.content.main.banner.QAudioContentBanner.audioContentBanner
|
||||
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
|
||||
import kr.co.vividnext.sodalive.content.translation.ContentTranslationRepository
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent
|
||||
import kr.co.vividnext.sodalive.event.EventItem
|
||||
@@ -38,6 +39,7 @@ import javax.persistence.EntityManager
|
||||
class DefaultAudioRecommendationQueryRepository(
|
||||
private val queryFactory: JPAQueryFactory,
|
||||
private val entityManager: EntityManager,
|
||||
private val contentTranslationRepository: ContentTranslationRepository,
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val cloudFrontHost: String
|
||||
) : AudioRecommendationQueryRepository {
|
||||
@@ -115,32 +117,35 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
canViewAdultContent: Boolean,
|
||||
now: LocalDateTime
|
||||
now: LocalDateTime,
|
||||
locale: String
|
||||
): List<AudioCard> {
|
||||
val rows = audioRows(memberId, canViewAdultContent, now) {
|
||||
orderBy(audioContent.releaseDate.desc(), audioContent.id.desc()).limit(limit.toLong())
|
||||
}
|
||||
return rows.toAudioCards(now, canViewAdultContent)
|
||||
return rows.toAudioCards(now, canViewAdultContent, locale)
|
||||
}
|
||||
|
||||
override fun findFreeAudios(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
canViewAdultContent: Boolean,
|
||||
now: LocalDateTime
|
||||
now: LocalDateTime,
|
||||
locale: String
|
||||
): List<AudioCard> {
|
||||
val randomTieBreaker = Expressions.numberTemplate(Double::class.java, "function('rand')")
|
||||
val rows = audioRows(memberId, canViewAdultContent, now, audioContent.price.eq(0)) {
|
||||
orderBy(randomTieBreaker.asc()).limit(limit.toLong())
|
||||
}
|
||||
return rows.toAudioCards(now, canViewAdultContent)
|
||||
return rows.toAudioCards(now, canViewAdultContent, locale)
|
||||
}
|
||||
|
||||
override fun findPointAudios(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
canViewAdultContent: Boolean,
|
||||
now: LocalDateTime
|
||||
now: LocalDateTime,
|
||||
locale: String
|
||||
): List<AudioCard> {
|
||||
val randomTieBreaker = Expressions.numberTemplate(Double::class.java, "function('rand')")
|
||||
val rows = audioRows(
|
||||
@@ -151,25 +156,27 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
) {
|
||||
orderBy(randomTieBreaker.asc()).limit(limit.toLong())
|
||||
}
|
||||
return rows.toAudioCards(now, canViewAdultContent)
|
||||
return rows.toAudioCards(now, canViewAdultContent, locale)
|
||||
}
|
||||
|
||||
override fun findAudioCardsByIds(
|
||||
contentIds: List<Long>,
|
||||
memberId: Long?,
|
||||
canViewAdultContent: Boolean,
|
||||
now: LocalDateTime
|
||||
now: LocalDateTime,
|
||||
locale: String
|
||||
): List<AudioCard> {
|
||||
if (contentIds.isEmpty()) return emptyList()
|
||||
val orderById = contentIds.withIndex().associate { it.value to it.index }
|
||||
val rows = audioRows(memberId, canViewAdultContent, now, audioContent.id.`in`(contentIds)) { this }
|
||||
return rows.toAudioCards(now, canViewAdultContent).sortedBy { orderById[it.audioContentId] ?: Int.MAX_VALUE }
|
||||
return rows.toAudioCards(now, canViewAdultContent, locale).sortedBy { orderById[it.audioContentId] ?: Int.MAX_VALUE }
|
||||
}
|
||||
|
||||
override fun findCommentedAudiosByIds(
|
||||
contentIds: List<Long>,
|
||||
memberId: Long?,
|
||||
canViewAdultContent: Boolean
|
||||
canViewAdultContent: Boolean,
|
||||
locale: String
|
||||
): List<CommentedAudio> {
|
||||
if (contentIds.isEmpty()) return emptyList()
|
||||
val contentOrder = contentIds.withIndex().associate { it.value to it.index }
|
||||
@@ -235,7 +242,7 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
)
|
||||
)
|
||||
""".trimIndent()
|
||||
return entityManager.createNativeQuery(sql)
|
||||
val commentedAudios = entityManager.createNativeQuery(sql)
|
||||
.setParameter("contentIds", contentIds)
|
||||
.setParameter("memberId", memberId)
|
||||
.setParameter("canViewAdultContent", canViewAdultContent)
|
||||
@@ -251,6 +258,11 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
?: "$cloudFrontHost/profile/default-profile.png"
|
||||
)
|
||||
}
|
||||
val translatedTitleByContentId = translatedTitles(commentedAudios.map { it.audioContentId }, locale)
|
||||
return commentedAudios
|
||||
.map { audio ->
|
||||
translatedTitleByContentId[audio.audioContentId]?.let { audio.copy(title = it) } ?: audio
|
||||
}
|
||||
.sortedBy { contentOrder[it.audioContentId] ?: Int.MAX_VALUE }
|
||||
}
|
||||
|
||||
@@ -455,18 +467,23 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
.fetch()
|
||||
}
|
||||
|
||||
private fun List<Tuple>.toAudioCards(now: LocalDateTime, canViewAdultContent: Boolean): List<AudioCard> {
|
||||
private fun List<Tuple>.toAudioCards(
|
||||
now: LocalDateTime,
|
||||
canViewAdultContent: Boolean,
|
||||
locale: String
|
||||
): List<AudioCard> {
|
||||
if (isEmpty()) return emptyList()
|
||||
val contentIds = map { it.get(audioContent.id)!! }
|
||||
val creatorIds = map { it.get(audioContent.member.id)!! }.distinct()
|
||||
val firstContentIdByCreatorId = firstAudioContentIds(creatorIds, now, canViewAdultContent)
|
||||
val isOriginalSeriesByContentId = originalSeriesFlags(contentIds)
|
||||
val translatedTitleByContentId = translatedTitles(contentIds, locale)
|
||||
return map { row ->
|
||||
val contentId = row.get(audioContent.id)!!
|
||||
val creatorId = row.get(audioContent.member.id)!!
|
||||
AudioCard(
|
||||
audioContentId = contentId,
|
||||
title = row.get(audioContent.title)!!,
|
||||
title = translatedTitleByContentId[contentId] ?: row.get(audioContent.title)!!,
|
||||
duration = row.get(audioContent.duration),
|
||||
imageUrl = row.get(audioContent.coverImage).toCdnUrl(cloudFrontHost),
|
||||
price = row.get(audioContent.price)!!,
|
||||
@@ -479,6 +496,17 @@ class DefaultAudioRecommendationQueryRepository(
|
||||
}
|
||||
}
|
||||
|
||||
private fun translatedTitles(contentIds: List<Long>, locale: String): Map<Long, String> {
|
||||
if (contentIds.isEmpty()) return emptyMap()
|
||||
return contentTranslationRepository.findByContentIdInAndLocale(contentIds, locale)
|
||||
.mapNotNull { translation ->
|
||||
translation.renderedPayload.title
|
||||
.takeIf { it.isNotBlank() }
|
||||
?.let { translation.contentId to it }
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
|
||||
private fun firstAudioContentIds(
|
||||
creatorIds: List<Long>,
|
||||
now: LocalDateTime,
|
||||
|
||||
Reference in New Issue
Block a user