feat(home): 홈 추천 통합 facade를 추가한다
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.application
|
||||
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.isAdultVisibleByPolicy
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeActiveCreatorItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeAiCharacterItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeBannerItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeCreatorItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeFirstAudioContentItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeGenreCreatorGroupItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeLiveItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomePopularCommunityItem
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeRecommendationPageResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.HomeRecommendationResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.imageUrl
|
||||
import kr.co.vividnext.sodalive.v2.api.home.dto.toUtcIso
|
||||
import kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryService
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeAiCharacterRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeBannerRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeCheerCreatorRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeFirstAudioContentRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeGenreCreatorRecommendationGroup
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomeLiveRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.HomePopularCommunityRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecentDebutCreatorRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommend.port.out.RecentlyActiveCreatorRecord
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Component
|
||||
class HomeRecommendationFacade(
|
||||
private val queryService: HomeRecommendationQueryService,
|
||||
private val memberContentPreferenceService: MemberContentPreferenceService,
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val cloudFrontHost: String
|
||||
) {
|
||||
fun getHomeRecommendations(member: Member?): HomeRecommendationResponse {
|
||||
val now = LocalDateTime.now()
|
||||
val includeAdult = resolveAdultVisibility(member)
|
||||
|
||||
return HomeRecommendationResponse(
|
||||
lives = queryService.findLiveRecommendations(
|
||||
limit = HOME_LIVE_LIMIT,
|
||||
includeAdultLives = includeAdult
|
||||
).map { it.toItem() },
|
||||
banners = queryService.findHomeBanners(HOME_BANNER_LIMIT).map { it.toItem() },
|
||||
recentlyActiveCreators = queryService.findRecentlyActiveCreators(HOME_ACTIVE_CREATOR_LIMIT, includeAdult)
|
||||
.map { it.toItem() },
|
||||
recentDebutCreators = queryService.findRecentDebutCreators(
|
||||
now,
|
||||
limit = HOME_RECENT_DEBUT_CREATOR_LIMIT,
|
||||
includeAdultContents = includeAdult
|
||||
)
|
||||
.map { it.toItem() },
|
||||
firstAudioContents = queryService.findFirstAudioContents(
|
||||
now,
|
||||
limit = HOME_FIRST_AUDIO_CONTENT_LIMIT,
|
||||
includeAdultContents = includeAdult
|
||||
)
|
||||
.map { it.toItem() },
|
||||
aiCharacters = queryService.findAiCharacterRecommendations(limit = HOME_AI_CHARACTER_LIMIT).map { it.toItem() },
|
||||
genreCreators = queryService.findGenreCreatorRecommendations(
|
||||
memberId = member?.id,
|
||||
includeAdultGenres = includeAdult,
|
||||
genreLimit = HOME_GENRE_CREATOR_GENRE_LIMIT,
|
||||
creatorLimit = HOME_GENRE_CREATOR_CREATOR_LIMIT
|
||||
).map { it.toItem() },
|
||||
cheerCreators = queryService.findCheerCreatorRecommendations(HOME_CHEER_CREATOR_LIMIT)
|
||||
.map { it.toCreatorItem() },
|
||||
popularCommunities = queryService.findPopularCommunityRecommendations(
|
||||
limit = HOME_POPULAR_COMMUNITY_LIMIT,
|
||||
includeAdultCommunities = includeAdult
|
||||
).map { it.toItem() }
|
||||
)
|
||||
}
|
||||
|
||||
fun getLives(member: Member, page: Int, size: Int): HomeRecommendationPageResponse<HomeLiveItem> {
|
||||
val fetched = queryService.findLiveRecommendations(
|
||||
offset = page.toOffset(size),
|
||||
limit = size + 1,
|
||||
includeAdultLives = resolveAdultVisibility(member)
|
||||
)
|
||||
return fetched.toPage(page, size) { it.toItem() }
|
||||
}
|
||||
|
||||
fun getRecentDebutCreators(member: Member, page: Int, size: Int): HomeRecommendationPageResponse<HomeCreatorItem> {
|
||||
val fetched = queryService.findRecentDebutCreators(
|
||||
now = LocalDateTime.now(),
|
||||
offset = page.toOffset(size),
|
||||
limit = size + 1,
|
||||
includeAdultContents = resolveAdultVisibility(member)
|
||||
)
|
||||
return fetched.toPage(page, size) { it.toItem() }
|
||||
}
|
||||
|
||||
fun getFirstAudioContents(member: Member, page: Int, size: Int): HomeRecommendationPageResponse<HomeFirstAudioContentItem> {
|
||||
val fetched = queryService.findFirstAudioContents(
|
||||
now = LocalDateTime.now(),
|
||||
offset = page.toOffset(size),
|
||||
limit = size + 1,
|
||||
includeAdultContents = resolveAdultVisibility(member)
|
||||
)
|
||||
return fetched.toPage(page, size) { it.toItem() }
|
||||
}
|
||||
|
||||
fun getAiCharacters(member: Member, page: Int, size: Int): HomeRecommendationPageResponse<HomeAiCharacterItem> {
|
||||
val fetched = queryService.findAiCharacterRecommendations(offset = page.toOffset(size), limit = size + 1)
|
||||
return fetched.toPage(page, size) { it.toItem() }
|
||||
}
|
||||
|
||||
private fun resolveAdultVisibility(member: Member?): Boolean {
|
||||
if (member == null) return false
|
||||
val preference = memberContentPreferenceService.initializeDefaultPreference(member)
|
||||
return isAdultVisibleByPolicy(member, preference.isAdultContentVisible)
|
||||
}
|
||||
|
||||
private fun Int.toOffset(size: Int): Int = this * size
|
||||
|
||||
private fun <S, T> List<S>.toPage(
|
||||
page: Int,
|
||||
size: Int,
|
||||
transform: (S) -> T
|
||||
): HomeRecommendationPageResponse<T> {
|
||||
val items = this.take(size).map(transform)
|
||||
val hasNext = this.size > size
|
||||
return HomeRecommendationPageResponse(items = items, page = page, size = size, hasNext = hasNext)
|
||||
}
|
||||
|
||||
private fun HomeLiveRecommendationRecord.toItem() = HomeLiveItem(
|
||||
liveRoomId = liveRoomId,
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage),
|
||||
title = title,
|
||||
coverImage = imageUrl(cloudFrontHost, coverImage),
|
||||
beginDateTime = beginDateTime.toUtcIso(),
|
||||
channelName = channelName
|
||||
)
|
||||
|
||||
private fun HomeBannerRecommendationRecord.toItem() = HomeBannerItem(
|
||||
bannerId = bannerId,
|
||||
type = type,
|
||||
thumbnailImage = imageUrl(cloudFrontHost, thumbnailImage),
|
||||
eventId = eventId,
|
||||
creatorId = creatorId,
|
||||
seriesId = seriesId,
|
||||
link = link
|
||||
)
|
||||
|
||||
private fun RecentlyActiveCreatorRecord.toItem() = HomeActiveCreatorItem(
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage),
|
||||
activityType = activityType.name,
|
||||
activityAt = activityAt.toUtcIso(),
|
||||
targetId = targetId
|
||||
)
|
||||
|
||||
private fun RecentDebutCreatorRecord.toItem() = HomeCreatorItem(
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage)
|
||||
)
|
||||
|
||||
private fun HomeFirstAudioContentRecord.toItem() = HomeFirstAudioContentItem(
|
||||
contentId = contentId,
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage),
|
||||
title = title,
|
||||
coverImage = imageUrl(cloudFrontHost, coverImage),
|
||||
releaseDate = releaseDate.toUtcIso()
|
||||
)
|
||||
|
||||
private fun HomeAiCharacterRecommendationRecord.toItem() = HomeAiCharacterItem(
|
||||
characterId = characterId,
|
||||
name = name,
|
||||
description = description,
|
||||
totalChatCount = totalChatCount,
|
||||
originalWorkTitle = originalWorkTitle
|
||||
)
|
||||
|
||||
private fun HomeGenreCreatorRecommendationGroup.toItem() = HomeGenreCreatorGroupItem(
|
||||
genreId = genreId,
|
||||
genreName = genreName,
|
||||
creators = creators.map {
|
||||
HomeCreatorItem(
|
||||
creatorId = it.creatorId,
|
||||
creatorNickname = it.creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, it.creatorProfileImage)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
private fun HomeCheerCreatorRecommendationRecord.toCreatorItem() = HomeCreatorItem(
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage)
|
||||
)
|
||||
|
||||
private fun HomePopularCommunityRecommendationRecord.toItem() = HomePopularCommunityItem(
|
||||
communityId = communityId,
|
||||
creatorId = creatorId,
|
||||
creatorNickname = creatorNickname,
|
||||
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage),
|
||||
content = content,
|
||||
createdAt = createdAt.toUtcIso(),
|
||||
likeCount = likeCount,
|
||||
commentCount = commentCount
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val HOME_LIVE_LIMIT = 20
|
||||
private const val HOME_BANNER_LIMIT = 20
|
||||
private const val HOME_ACTIVE_CREATOR_LIMIT = 10
|
||||
private const val HOME_RECENT_DEBUT_CREATOR_LIMIT = 10
|
||||
private const val HOME_FIRST_AUDIO_CONTENT_LIMIT = 10
|
||||
private const val HOME_AI_CHARACTER_LIMIT = 10
|
||||
private const val HOME_GENRE_CREATOR_GENRE_LIMIT = 5
|
||||
private const val HOME_GENRE_CREATOR_CREATOR_LIMIT = 8
|
||||
private const val HOME_CHEER_CREATOR_LIMIT = 8
|
||||
private const val HOME_POPULAR_COMMUNITY_LIMIT = 10
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user