diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt index 6d44d725..6b038a0c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt @@ -131,15 +131,11 @@ class HomeService( isAdult = isAdult ) - // 오직 보이스온에서만 val originalAudioDramaList = seriesService.getOriginalAudioDramaList( isAdult = isAdult, - contentType = contentType, - orderByRandom = true + contentType = contentType ) - val translatedOriginalAudioDramaList = getTranslatedSeriesList(seriesList = originalAudioDramaList) - val auditionList = auditionService.getInProgressAuditionList(isAdult = isAdult) // 요일별 시리즈 @@ -214,7 +210,7 @@ class HomeService( latestContentList = latestContentList, bannerList = bannerList, eventBannerList = eventBannerList, - originalAudioDramaList = translatedOriginalAudioDramaList, + originalAudioDramaList = originalAudioDramaList, auditionList = auditionList, dayOfWeekSeriesList = translatedDayOfWeekSeriesList, popularCharacters = translatedPopularCharacters, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt index a1e682ac..8448f20f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt @@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.content.main.curation.QAudioContentCuration.audi import kr.co.vividnext.sodalive.content.main.curation.QAudioContentCurationItem.audioContentCurationItem import kr.co.vividnext.sodalive.content.series.content.GetSeriesContentMinMaxPriceResponse import kr.co.vividnext.sodalive.content.series.content.QGetSeriesContentMinMaxPriceResponse +import kr.co.vividnext.sodalive.content.series.translation.QSeriesTranslation.seriesTranslation 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.creator.admin.content.series.Series @@ -20,6 +21,7 @@ import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.QMember.member import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime interface ContentSeriesRepository : JpaRepository, ContentSeriesQueryRepository @@ -64,12 +66,13 @@ interface ContentSeriesQueryRepository { fun getSeriesContentMinMaxPrice(seriesId: Long): GetSeriesContentMinMaxPriceResponse fun getRecommendSeriesList(isAuth: Boolean, contentType: ContentType, limit: Long): List fun getOriginalAudioDramaList( + imageHost: String, isAdult: Boolean, contentType: ContentType, - orderByRandom: Boolean = false, + locale: String, offset: Long = 0, limit: Long = 20 - ): List + ): List fun getOriginalAudioDramaTotalCount(isAdult: Boolean, contentType: ContentType): Int fun getGenreList(isAdult: Boolean, memberId: Long, contentType: ContentType): List @@ -365,12 +368,13 @@ class ContentSeriesQueryRepositoryImpl( } override fun getOriginalAudioDramaList( + imageHost: String, isAdult: Boolean, contentType: ContentType, - orderByRandom: Boolean, + locale: String, offset: Long, limit: Long - ): List { + ): List { var where = series.isOriginal.isTrue .and(series.isActive.isTrue) @@ -392,20 +396,85 @@ class ContentSeriesQueryRepositoryImpl( } } - return queryFactory - .selectFrom(series) - .innerJoin(series.member, member) - .where(where) - .orderBy( - if (orderByRandom) { - Expressions.numberTemplate(Double::class.java, "function('rand')").asc() - } else { - series.id.desc() - } + val now = LocalDateTime.now() + val sevenDaysAgo = now.minusDays(7) + + val contentCountSubquery = queryFactory + .select(seriesContent.id.count()) + .from(seriesContent) + .innerJoin(seriesContent.content, audioContent) + .where( + seriesContent.series.id.eq(series.id), + audioContent.isActive.isTrue, + if (!isAdult) audioContent.isAdult.isFalse else null ) + + val isNewSubquery = queryFactory + .select(seriesContent.id) + .from(seriesContent) + .innerJoin(seriesContent.content, audioContent) + .where( + seriesContent.series.id.eq(series.id), + audioContent.isActive.isTrue, + if (!isAdult) audioContent.isAdult.isFalse else null, + audioContent.releaseDate.between(sevenDaysAgo, now) + ) + .limit(1) + + val results = queryFactory + .select( + series.id, + series.title, + seriesTranslation.renderedPayload, + series.coverImage, + series.state, + member.id, + member.nickname, + member.profileImage, + contentCountSubquery, + isNewSubquery.exists(), + series + ) + .from(series) + .innerJoin(series.member, member) + .leftJoin(seriesTranslation).on(series.id.eq(seriesTranslation.seriesId), seriesTranslation.locale.eq(locale)) + .where(where) + .having(contentCountSubquery.gt(0)) + .orderBy(series.id.desc()) .offset(offset) .limit(limit) .fetch() + + return results.map { row -> + val seriesId = row.get(series.id)!! + val originTitle = row.get(series.title)!! + val payload = row.get(seriesTranslation.renderedPayload) + val translatedTitle = payload?.title + val coverImage = row.get(series.coverImage) + val state = row.get(series.state) + val creatorId = row.get(member.id)!! + val nickname = row.get(member.nickname)!! + val profileImage = row.get(member.profileImage) + val numberOfContent = row.get(8, Long::class.java) ?: 0L + val isNew = row.get(9, Boolean::class.java) ?: false + val seriesEntity = row.get(series)!! + + GetSeriesListResponse.SeriesListItem( + seriesId = seriesId, + title = if (translatedTitle.isNullOrBlank()) originTitle else translatedTitle, + coverImage = "$imageHost/$coverImage", + publishedDaysOfWeek = "", // Service layer will fill this + isComplete = state == SeriesState.COMPLETE, + creator = GetSeriesListResponse.SeriesListItemCreator( + creatorId = creatorId, + nickname = nickname, + profileImage = "$imageHost/$profileImage" + ), + numberOfContent = numberOfContent.toInt(), + isNew = isNew, + rawPublishedDaysOfWeek = seriesEntity.publishedDaysOfWeek + ) + } } override fun getOriginalAudioDramaTotalCount(isAdult: Boolean, contentType: ContentType): Int { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt index bd7ced51..839eeffb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt @@ -55,12 +55,21 @@ class ContentSeriesService( fun getOriginalAudioDramaList( isAdult: Boolean, contentType: ContentType, - orderByRandom: Boolean = false, offset: Long = 0, limit: Long = 20 ): List { - val originalAudioDramaList = repository.getOriginalAudioDramaList(isAdult, contentType, orderByRandom, offset, limit) - return getTranslatedSeriesList(seriesToSeriesListItem(originalAudioDramaList, isAdult, contentType)) + val originalAudioDramaList = repository.getOriginalAudioDramaList( + imageHost = coverImageHost, + isAdult = isAdult, + contentType = contentType, + locale = langContext.lang.code, + offset = offset, + limit = limit + ) + + return originalAudioDramaList.map { item -> + item.copy(publishedDaysOfWeek = publishedDaysOfWeekText(item.rawPublishedDaysOfWeek)) + } } fun getGenreList(memberId: Long, isAdult: Boolean, contentType: ContentType): List { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/GetSeriesListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/GetSeriesListResponse.kt index f83b40c4..4df1264e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/GetSeriesListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/GetSeriesListResponse.kt @@ -1,10 +1,13 @@ package kr.co.vividnext.sodalive.content.series +import com.querydsl.core.annotations.QueryProjection +import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek + data class GetSeriesListResponse( val totalCount: Int, val items: List ) { - data class SeriesListItem( + data class SeriesListItem @QueryProjection constructor( val seriesId: Long, val title: String, val coverImage: String, @@ -13,10 +16,11 @@ data class GetSeriesListResponse( val creator: SeriesListItemCreator, var numberOfContent: Int = 0, var isNew: Boolean = false, - var isPopular: Boolean = false + var isPopular: Boolean = false, + val rawPublishedDaysOfWeek: Set = emptySet() ) - data class SeriesListItemCreator( + data class SeriesListItemCreator @QueryProjection constructor( val creatorId: Long, val nickname: String, val profileImage: String