test #388

Merged
klaus merged 15 commits from test into main 2026-02-13 09:14:20 +00:00
4 changed files with 104 additions and 26 deletions
Showing only changes of commit ac0def6187 - Show all commits

View File

@@ -131,15 +131,11 @@ class HomeService(
isAdult = isAdult isAdult = isAdult
) )
// 오직 보이스온에서만
val originalAudioDramaList = seriesService.getOriginalAudioDramaList( val originalAudioDramaList = seriesService.getOriginalAudioDramaList(
isAdult = isAdult, isAdult = isAdult,
contentType = contentType, contentType = contentType
orderByRandom = true
) )
val translatedOriginalAudioDramaList = getTranslatedSeriesList(seriesList = originalAudioDramaList)
val auditionList = auditionService.getInProgressAuditionList(isAdult = isAdult) val auditionList = auditionService.getInProgressAuditionList(isAdult = isAdult)
// 요일별 시리즈 // 요일별 시리즈
@@ -214,7 +210,7 @@ class HomeService(
latestContentList = latestContentList, latestContentList = latestContentList,
bannerList = bannerList, bannerList = bannerList,
eventBannerList = eventBannerList, eventBannerList = eventBannerList,
originalAudioDramaList = translatedOriginalAudioDramaList, originalAudioDramaList = originalAudioDramaList,
auditionList = auditionList, auditionList = auditionList,
dayOfWeekSeriesList = translatedDayOfWeekSeriesList, dayOfWeekSeriesList = translatedDayOfWeekSeriesList,
popularCharacters = translatedPopularCharacters, popularCharacters = translatedPopularCharacters,

View File

@@ -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.main.curation.QAudioContentCurationItem.audioContentCurationItem
import kr.co.vividnext.sodalive.content.series.content.GetSeriesContentMinMaxPriceResponse 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.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.QSeries.series
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent
import kr.co.vividnext.sodalive.creator.admin.content.series.Series 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.QMember.member
import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember
import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaRepository
import java.time.LocalDateTime
interface ContentSeriesRepository : JpaRepository<Series, Long>, ContentSeriesQueryRepository interface ContentSeriesRepository : JpaRepository<Series, Long>, ContentSeriesQueryRepository
@@ -64,12 +66,13 @@ interface ContentSeriesQueryRepository {
fun getSeriesContentMinMaxPrice(seriesId: Long): GetSeriesContentMinMaxPriceResponse fun getSeriesContentMinMaxPrice(seriesId: Long): GetSeriesContentMinMaxPriceResponse
fun getRecommendSeriesList(isAuth: Boolean, contentType: ContentType, limit: Long): List<Series> fun getRecommendSeriesList(isAuth: Boolean, contentType: ContentType, limit: Long): List<Series>
fun getOriginalAudioDramaList( fun getOriginalAudioDramaList(
imageHost: String,
isAdult: Boolean, isAdult: Boolean,
contentType: ContentType, contentType: ContentType,
orderByRandom: Boolean = false, locale: String,
offset: Long = 0, offset: Long = 0,
limit: Long = 20 limit: Long = 20
): List<Series> ): List<GetSeriesListResponse.SeriesListItem>
fun getOriginalAudioDramaTotalCount(isAdult: Boolean, contentType: ContentType): Int fun getOriginalAudioDramaTotalCount(isAdult: Boolean, contentType: ContentType): Int
fun getGenreList(isAdult: Boolean, memberId: Long, contentType: ContentType): List<GetSeriesGenreListResponse> fun getGenreList(isAdult: Boolean, memberId: Long, contentType: ContentType): List<GetSeriesGenreListResponse>
@@ -365,12 +368,13 @@ class ContentSeriesQueryRepositoryImpl(
} }
override fun getOriginalAudioDramaList( override fun getOriginalAudioDramaList(
imageHost: String,
isAdult: Boolean, isAdult: Boolean,
contentType: ContentType, contentType: ContentType,
orderByRandom: Boolean, locale: String,
offset: Long, offset: Long,
limit: Long limit: Long
): List<Series> { ): List<GetSeriesListResponse.SeriesListItem> {
var where = series.isOriginal.isTrue var where = series.isOriginal.isTrue
.and(series.isActive.isTrue) .and(series.isActive.isTrue)
@@ -392,20 +396,85 @@ class ContentSeriesQueryRepositoryImpl(
} }
} }
return queryFactory val now = LocalDateTime.now()
.selectFrom(series) val sevenDaysAgo = now.minusDays(7)
.innerJoin(series.member, member)
.where(where) val contentCountSubquery = queryFactory
.orderBy( .select(seriesContent.id.count())
if (orderByRandom) { .from(seriesContent)
Expressions.numberTemplate(Double::class.java, "function('rand')").asc() .innerJoin(seriesContent.content, audioContent)
} else { .where(
series.id.desc() 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) .offset(offset)
.limit(limit) .limit(limit)
.fetch() .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 { override fun getOriginalAudioDramaTotalCount(isAdult: Boolean, contentType: ContentType): Int {

View File

@@ -55,12 +55,21 @@ class ContentSeriesService(
fun getOriginalAudioDramaList( fun getOriginalAudioDramaList(
isAdult: Boolean, isAdult: Boolean,
contentType: ContentType, contentType: ContentType,
orderByRandom: Boolean = false,
offset: Long = 0, offset: Long = 0,
limit: Long = 20 limit: Long = 20
): List<GetSeriesListResponse.SeriesListItem> { ): List<GetSeriesListResponse.SeriesListItem> {
val originalAudioDramaList = repository.getOriginalAudioDramaList(isAdult, contentType, orderByRandom, offset, limit) val originalAudioDramaList = repository.getOriginalAudioDramaList(
return getTranslatedSeriesList(seriesToSeriesListItem(originalAudioDramaList, isAdult, contentType)) 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<GetSeriesGenreListResponse> { fun getGenreList(memberId: Long, isAdult: Boolean, contentType: ContentType): List<GetSeriesGenreListResponse> {

View File

@@ -1,10 +1,13 @@
package kr.co.vividnext.sodalive.content.series 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( data class GetSeriesListResponse(
val totalCount: Int, val totalCount: Int,
val items: List<SeriesListItem> val items: List<SeriesListItem>
) { ) {
data class SeriesListItem( data class SeriesListItem @QueryProjection constructor(
val seriesId: Long, val seriesId: Long,
val title: String, val title: String,
val coverImage: String, val coverImage: String,
@@ -13,10 +16,11 @@ data class GetSeriesListResponse(
val creator: SeriesListItemCreator, val creator: SeriesListItemCreator,
var numberOfContent: Int = 0, var numberOfContent: Int = 0,
var isNew: Boolean = false, var isNew: Boolean = false,
var isPopular: Boolean = false var isPopular: Boolean = false,
val rawPublishedDaysOfWeek: Set<SeriesPublishedDaysOfWeek> = emptySet()
) )
data class SeriesListItemCreator( data class SeriesListItemCreator @QueryProjection constructor(
val creatorId: Long, val creatorId: Long,
val nickname: String, val nickname: String,
val profileImage: String val profileImage: String