Compare commits

...

2 Commits

2 changed files with 65 additions and 23 deletions

View File

@@ -5,7 +5,6 @@ import kr.co.vividnext.sodalive.chat.character.dto.Character
import kr.co.vividnext.sodalive.content.AudioContentMainItem
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
import kr.co.vividnext.sodalive.content.main.banner.GetAudioContentBannerResponse
import kr.co.vividnext.sodalive.content.main.tab.GetContentCurationResponse
import kr.co.vividnext.sodalive.content.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.event.GetEventResponse
import kr.co.vividnext.sodalive.explorer.GetExplorerSectionCreatorResponse
@@ -27,6 +26,5 @@ data class GetHomeResponse(
val recommendChannelList: List<RecommendChannelResponse>,
val freeContentList: List<AudioContentMainItem>,
val pointAvailableContentList: List<AudioContentMainItem>,
val recommendContentList: List<AudioContentMainItem>,
val curationList: List<GetContentCurationResponse>
val recommendContentList: List<AudioContentMainItem>
)

View File

@@ -10,7 +10,6 @@ import kr.co.vividnext.sodalive.content.ContentType
import kr.co.vividnext.sodalive.content.SortType
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerService
import kr.co.vividnext.sodalive.content.main.curation.AudioContentCurationService
import kr.co.vividnext.sodalive.content.series.ContentSeriesService
import kr.co.vividnext.sodalive.content.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.content.series.translation.SeriesTranslationRepository
@@ -43,7 +42,6 @@ class HomeService(
private val seriesService: ContentSeriesService,
private val contentService: AudioContentService,
private val bannerService: AudioContentBannerService,
private val curationService: AudioContentCurationService,
private val contentThemeService: AudioContentThemeService,
private val recommendChannelService: RecommendChannelQueryService,
@@ -237,29 +235,28 @@ class HomeService(
recommendChannelList
}
val freeContentList = contentService.getLatestContentByTheme(
val freeContentList = getRandomizedContentList(
memberId = memberId,
isAdult = isAdult,
contentType = contentType,
theme = contentThemeService.getActiveThemeOfContent(
isAdult = isAdult,
isFree = true,
contentType = contentType
),
contentType = contentType,
isFree = true,
isAdult = isAdult,
orderByRandom = true
isPointAvailableOnly = false
)
val translatedFreeContentList = getTranslatedContentList(contentList = freeContentList)
// 포인트 사용가능 콘텐츠 리스트 - 랜덤으로 가져오기 (DB에서 isPointAvailable 조건 적용)
val pointAvailableContentList = contentService.getLatestContentByTheme(
val pointAvailableContentList = getRandomizedContentList(
memberId = memberId,
theme = emptyList(),
contentType = contentType,
isFree = false,
isAdult = isAdult,
orderByRandom = true,
contentType = contentType,
theme = emptyList(),
isFree = false,
isPointAvailableOnly = true
)
@@ -270,13 +267,6 @@ class HomeService(
translatedContentRanking.map { it.contentId }
).distinct()
val curationList = curationService.getContentCurationList(
tabId = 3L, // 기존에 사용하던 단편 탭의 큐레이션을 사용
isAdult = isAdult,
contentType = contentType,
memberId = memberId
)
return GetHomeResponse(
liveList = liveList,
creatorRanking = creatorRanking,
@@ -297,8 +287,7 @@ class HomeService(
contentType = contentType,
member = member,
excludeContentIds = excludeContentIds
),
curationList = curationList
)
)
}
@@ -501,6 +490,61 @@ class HomeService(
return candidates.lastIndex
}
private fun getRandomizedContentList(
memberId: Long?,
isAdult: Boolean,
contentType: ContentType,
theme: List<String>,
isFree: Boolean,
isPointAvailableOnly: Boolean,
targetSize: Int = 20
): List<AudioContentMainItem> {
val buckets = listOf(
RecommendBucket(offset = 0L, limit = 50L),
RecommendBucket(offset = 50L, limit = 100L),
RecommendBucket(offset = 150L, limit = 150L)
)
val result = mutableListOf<AudioContentMainItem>()
val seenIds = mutableSetOf<Long>()
repeat(RECOMMEND_MAX_ATTEMPTS) {
if (result.size >= targetSize) return@repeat
val remaining = targetSize - result.size
val targetPerBucket = maxOf(1, (remaining + buckets.size - 1) / buckets.size)
for (bucket in buckets) {
if (result.size >= targetSize) break
val batch = contentService.getLatestContentByTheme(
memberId = memberId,
theme = theme,
contentType = contentType,
offset = bucket.offset,
limit = bucket.limit,
sortType = SortType.NEWEST,
isFree = isFree,
isAdult = isAdult,
orderByRandom = false,
isPointAvailableOnly = isPointAvailableOnly,
excludeContentIds = seenIds.toList()
)
val selected = pickByTimeDecay(
batch = batch,
targetSize = minOf(targetPerBucket, targetSize - result.size),
seenIds = seenIds
)
if (selected.isNotEmpty()) {
result.addAll(selected)
}
}
}
return getTranslatedContentList(contentList = result.take(targetSize).shuffled())
}
/**
* 콘텐츠 리스트의 제목을 현재 언어(locale)에 맞춰 일괄 번역한다.
*