Home API에서 api 마다 languageCode를 별도로 받던 것을 LangContext를 사용하도록 리팩토링
This commit is contained in:
@@ -17,7 +17,6 @@ class HomeController(private val service: HomeService) {
|
||||
@GetMapping
|
||||
fun fetchData(
|
||||
@RequestParam timezone: String,
|
||||
@RequestParam(required = false) languageCode: String? = null,
|
||||
@RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null,
|
||||
@RequestParam("contentType", required = false) contentType: ContentType? = null,
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
@@ -25,7 +24,6 @@ class HomeController(private val service: HomeService) {
|
||||
ApiResponse.ok(
|
||||
service.fetchData(
|
||||
timezone = timezone,
|
||||
languageCode = languageCode,
|
||||
isAdultContentVisible = isAdultContentVisible ?: true,
|
||||
contentType = contentType ?: ContentType.ALL,
|
||||
member
|
||||
@@ -36,7 +34,6 @@ class HomeController(private val service: HomeService) {
|
||||
@GetMapping("/latest-content")
|
||||
fun getLatestContentByTheme(
|
||||
@RequestParam("theme") theme: String,
|
||||
@RequestParam(required = false) languageCode: String? = null,
|
||||
@RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null,
|
||||
@RequestParam("contentType", required = false) contentType: ContentType? = null,
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
@@ -44,7 +41,6 @@ class HomeController(private val service: HomeService) {
|
||||
ApiResponse.ok(
|
||||
service.getLatestContentByTheme(
|
||||
theme = theme,
|
||||
languageCode = languageCode,
|
||||
isAdultContentVisible = isAdultContentVisible ?: true,
|
||||
contentType = contentType ?: ContentType.ALL,
|
||||
member
|
||||
@@ -74,15 +70,13 @@ class HomeController(private val service: HomeService) {
|
||||
fun getRecommendContents(
|
||||
@RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null,
|
||||
@RequestParam("contentType", required = false) contentType: ContentType? = null,
|
||||
@RequestParam(required = false) languageCode: String? = null,
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
) = run {
|
||||
ApiResponse.ok(
|
||||
service.getRecommendContentList(
|
||||
isAdultContentVisible = isAdultContentVisible ?: true,
|
||||
contentType = contentType ?: ContentType.ALL,
|
||||
member = member,
|
||||
languageCode = languageCode
|
||||
member = member
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.api.home
|
||||
|
||||
import kr.co.vividnext.sodalive.audition.AuditionService
|
||||
import kr.co.vividnext.sodalive.chat.character.dto.Character
|
||||
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService
|
||||
import kr.co.vividnext.sodalive.chat.character.translate.AiCharacterTranslationRepository
|
||||
import kr.co.vividnext.sodalive.content.AudioContentMainItem
|
||||
@@ -16,6 +17,7 @@ import kr.co.vividnext.sodalive.content.translation.ContentTranslationRepository
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.event.GetEventResponse
|
||||
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoomService
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -52,6 +54,8 @@ class HomeService(
|
||||
private val contentTranslationRepository: ContentTranslationRepository,
|
||||
private val aiCharacterTranslationRepository: AiCharacterTranslationRepository,
|
||||
|
||||
private val langContext: LangContext,
|
||||
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val imageHost: String
|
||||
) {
|
||||
@@ -62,7 +66,6 @@ class HomeService(
|
||||
|
||||
fun fetchData(
|
||||
timezone: String,
|
||||
languageCode: String?,
|
||||
isAdultContentVisible: Boolean,
|
||||
contentType: ContentType,
|
||||
member: Member?
|
||||
@@ -117,36 +120,7 @@ class HomeService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* latestContentList 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 latestContentList의 title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedLatestContentList = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = latestContentList.map { it.contentId }
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
latestContentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
latestContentList
|
||||
}
|
||||
} else {
|
||||
latestContentList
|
||||
}
|
||||
val translatedLatestContentList = getTranslatedContentList(contentList = latestContentList)
|
||||
|
||||
val eventBannerList = GetEventResponse(
|
||||
totalCount = 0,
|
||||
@@ -175,39 +149,7 @@ class HomeService(
|
||||
)
|
||||
|
||||
// 인기 캐릭터 조회
|
||||
val popularCharacters = characterService.getPopularCharacters()
|
||||
|
||||
/**
|
||||
* popularCharacters 캐릭터 이름 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* aiCharacterTranslationRepository 이용해 번역 콘텐츠를 조회한다. - characterId, locale
|
||||
*
|
||||
* 한 번에 조회하고 characterId 매핑하여 popularCharacters의 캐릭터 이름을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedPopularCharacters = if (!languageCode.isNullOrBlank()) {
|
||||
val characterIds = popularCharacters.map { it.characterId }
|
||||
|
||||
if (characterIds.isNotEmpty()) {
|
||||
val translations = aiCharacterTranslationRepository
|
||||
.findByCharacterIdInAndLocale(characterIds = characterIds, locale = languageCode)
|
||||
.associateBy { it.characterId }
|
||||
|
||||
popularCharacters.map { character ->
|
||||
val translatedName = translations[character.characterId]?.renderedPayload?.name
|
||||
val translatedDesc = translations[character.characterId]?.renderedPayload?.description
|
||||
if (translatedName.isNullOrBlank() || translatedDesc.isNullOrBlank()) {
|
||||
character
|
||||
} else {
|
||||
character.copy(name = translatedName, description = translatedDesc)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
popularCharacters
|
||||
}
|
||||
} else {
|
||||
popularCharacters
|
||||
}
|
||||
val translatedPopularCharacters = getTranslatedAiCharacterList(aiCharacterList = characterService.getPopularCharacters())
|
||||
|
||||
val currentDateTime = LocalDateTime.now()
|
||||
val startDate = currentDateTime
|
||||
@@ -228,32 +170,19 @@ class HomeService(
|
||||
sort = ContentRankingSortType.REVENUE
|
||||
)
|
||||
|
||||
/**
|
||||
* contentRanking 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 contentRanking title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedContentRanking = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = contentRanking.map { it.contentId }
|
||||
val contentRankingContentIds = contentRanking.map { it.contentId }
|
||||
val translatedContentRanking = if (contentRankingContentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentRankingContentIds, locale = langContext.lang.code)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
contentRanking.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
contentRanking.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
} else {
|
||||
contentRanking
|
||||
}
|
||||
} else {
|
||||
contentRanking
|
||||
@@ -273,31 +202,27 @@ class HomeService(
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 recommendChannelList의 콘텐츠 title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedRecommendChannelList = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = recommendChannelList
|
||||
.flatMap { it.contentList }
|
||||
.map { it.contentId }
|
||||
.distinct()
|
||||
val channelContentIds = recommendChannelList
|
||||
.flatMap { it.contentList }
|
||||
.map { it.contentId }
|
||||
.distinct()
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
val translatedRecommendChannelList = if (channelContentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = channelContentIds, locale = langContext.lang.code)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
recommendChannelList.map { channel ->
|
||||
val translatedContentList = channel.contentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
recommendChannelList.map { channel ->
|
||||
val translatedContentList = channel.contentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
|
||||
channel.copy(contentList = translatedContentList)
|
||||
}
|
||||
} else {
|
||||
recommendChannelList
|
||||
|
||||
channel.copy(contentList = translatedContentList)
|
||||
}
|
||||
} else {
|
||||
recommendChannelList
|
||||
@@ -321,36 +246,7 @@ class HomeService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* freeContentList 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 freeContentList title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedFreeContentList = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = freeContentList.map { it.contentId }
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
freeContentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
freeContentList
|
||||
}
|
||||
} else {
|
||||
freeContentList
|
||||
}
|
||||
val translatedFreeContentList = getTranslatedContentList(contentList = freeContentList)
|
||||
|
||||
// 포인트 사용가능 콘텐츠 리스트 - 랜덤으로 가져오기 (DB에서 isPointAvailable 조건 적용)
|
||||
val pointAvailableContentList = contentService.getLatestContentByTheme(
|
||||
@@ -368,36 +264,7 @@ class HomeService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pointAvailableContentList 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 pointAvailableContentList title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedPointAvailableContentList = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = pointAvailableContentList.map { it.contentId }
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
pointAvailableContentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pointAvailableContentList
|
||||
}
|
||||
} else {
|
||||
pointAvailableContentList
|
||||
}
|
||||
val translatedPointAvailableContentList = getTranslatedContentList(contentList = pointAvailableContentList)
|
||||
|
||||
val curationList = curationService.getContentCurationList(
|
||||
tabId = 3L, // 기존에 사용하던 단편 탭의 큐레이션을 사용
|
||||
@@ -424,8 +291,7 @@ class HomeService(
|
||||
recommendContentList = getRecommendContentList(
|
||||
isAdultContentVisible = isAdultContentVisible,
|
||||
contentType = contentType,
|
||||
member = member,
|
||||
languageCode = languageCode
|
||||
member = member
|
||||
),
|
||||
curationList = curationList
|
||||
)
|
||||
@@ -433,7 +299,6 @@ class HomeService(
|
||||
|
||||
fun getLatestContentByTheme(
|
||||
theme: String,
|
||||
languageCode: String?,
|
||||
isAdultContentVisible: Boolean,
|
||||
contentType: ContentType,
|
||||
member: Member?
|
||||
@@ -464,38 +329,7 @@ class HomeService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* contentList 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 contentList title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedContentList = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = contentList.map { it.contentId }
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
contentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
contentList
|
||||
}
|
||||
} else {
|
||||
contentList
|
||||
}
|
||||
|
||||
return translatedContentList
|
||||
return getTranslatedContentList(contentList = contentList)
|
||||
}
|
||||
|
||||
fun getDayOfWeekSeriesList(
|
||||
@@ -571,8 +405,7 @@ class HomeService(
|
||||
fun getRecommendContentList(
|
||||
isAdultContentVisible: Boolean,
|
||||
contentType: ContentType,
|
||||
member: Member?,
|
||||
languageCode: String? = null
|
||||
member: Member?
|
||||
): List<AudioContentMainItem> {
|
||||
val memberId = member?.id
|
||||
val isAdult = member?.auth != null && isAdultContentVisible
|
||||
@@ -607,37 +440,76 @@ class HomeService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 추천 콘텐츠 번역 데이터 조회
|
||||
*
|
||||
* languageCode != null
|
||||
* contentTranslationRepository를 이용해 번역 콘텐츠를 조회한다. - contentId, locale
|
||||
*
|
||||
* 한 번에 조회하고 contentId를 매핑하여 result의 title을 번역 데이터로 변경한다
|
||||
*/
|
||||
val translatedResult = if (!languageCode.isNullOrBlank()) {
|
||||
val contentIds = result.map { it.contentId }
|
||||
return getTranslatedContentList(contentList = result)
|
||||
}
|
||||
|
||||
if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = languageCode)
|
||||
.associateBy { it.contentId }
|
||||
/**
|
||||
* 콘텐츠 리스트의 제목을 현재 언어(locale)에 맞춰 일괄 번역한다.
|
||||
*
|
||||
* 처리 절차:
|
||||
* - 입력된 콘텐츠들의 contentId 집합을 만들고, 요청 언어 코드(langContext.lang.code)로
|
||||
* contentTranslationRepository에서 번역 데이터를 한 번에 조회한다.
|
||||
* - 각 항목에 대해 번역된 제목이 존재하고 비어있지 않으면 title만 번역 값으로 교체한다.
|
||||
* - 번역이 없거나 공백이면 원본 항목을 그대로 반환한다.
|
||||
*
|
||||
* 성능:
|
||||
* - N건의 항목을 1회의 조회로 해결하기 위해 IN 쿼리를 사용한다.
|
||||
*
|
||||
* @param contentList 번역 대상 AudioContentMainItem 목록
|
||||
* @return 제목이 가능한 항목은 번역된 목록(불변 사본), 그 외는 원본 항목 유지
|
||||
*/
|
||||
private fun getTranslatedContentList(contentList: List<AudioContentMainItem>): List<AudioContentMainItem> {
|
||||
val contentIds = contentList.map { it.contentId }
|
||||
|
||||
result.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
return if (contentIds.isNotEmpty()) {
|
||||
val translations = contentTranslationRepository
|
||||
.findByContentIdInAndLocale(contentIds = contentIds, locale = langContext.lang.code)
|
||||
.associateBy { it.contentId }
|
||||
|
||||
contentList.map { item ->
|
||||
val translatedTitle = translations[item.contentId]?.renderedPayload?.title
|
||||
if (translatedTitle.isNullOrBlank()) {
|
||||
item
|
||||
} else {
|
||||
item.copy(title = translatedTitle)
|
||||
}
|
||||
} else {
|
||||
result
|
||||
}
|
||||
} else {
|
||||
result
|
||||
contentList
|
||||
}
|
||||
}
|
||||
|
||||
return translatedResult
|
||||
/**
|
||||
* AI 캐릭터 리스트의 이름/설명을 현재 언어(locale)에 맞춰 일괄 번역한다.
|
||||
*
|
||||
* 처리 절차:
|
||||
* - characterId 목록을 추출하고, 요청 언어 코드로 aiCharacterTranslationRepository에서
|
||||
* 번역 데이터를 한 번에 조회한다.
|
||||
* - 각 캐릭터에 대해 name과 description 모두 번역 값이 존재하고 비어있지 않을 때에만
|
||||
* 해당 필드를 교체한다. 둘 중 하나라도 없으면 원본 캐릭터를 그대로 유지한다.
|
||||
*
|
||||
* @param aiCharacterList 번역 대상 캐릭터 목록
|
||||
* @return 가능한 경우 name/description이 번역된 캐릭터 목록, 그 외는 원본 유지
|
||||
*/
|
||||
private fun getTranslatedAiCharacterList(aiCharacterList: List<Character>): List<Character> {
|
||||
val characterIds = aiCharacterList.map { it.characterId }
|
||||
|
||||
return if (characterIds.isNotEmpty()) {
|
||||
val translations = aiCharacterTranslationRepository
|
||||
.findByCharacterIdInAndLocale(characterIds = characterIds, locale = langContext.lang.code)
|
||||
.associateBy { it.characterId }
|
||||
|
||||
aiCharacterList.map { character ->
|
||||
val translatedName = translations[character.characterId]?.renderedPayload?.name
|
||||
val translatedDesc = translations[character.characterId]?.renderedPayload?.description
|
||||
if (translatedName.isNullOrBlank() || translatedDesc.isNullOrBlank()) {
|
||||
character
|
||||
} else {
|
||||
character.copy(name = translatedName, description = translatedDesc)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aiCharacterList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user