h-lab/src/main/java/com/hlab/yanalyst/domain/channel/SearchCollectionService.java

66 lines
2.5 KiB
Java

package com.hlab.yanalyst.domain.channel;
import com.hlab.yanalyst.web.dto.YoutubeSearchResultDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 조회수 검색 결과(YoutubeSearchResultDto)를 수집함(ChannelVideo, source=SEARCH)으로 영속화한다.
* 이미 수집된 videoId 는 건너뛴다(중복 방지).
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class SearchCollectionService {
private final ChannelVideoRepository channelVideoRepository;
@Transactional
public CollectResult collectFromSearch(List<YoutubeSearchResultDto> items) {
if (items == null || items.isEmpty()) {
return new CollectResult(0, 0, List.of());
}
int saved = 0;
int skipped = 0;
List<String> savedIds = new ArrayList<>();
for (YoutubeSearchResultDto dto : items) {
if (dto.getVideoId() == null || dto.getVideoId().isBlank()) {
skipped++;
continue;
}
if (channelVideoRepository.existsByVideoId(dto.getVideoId())) {
skipped++; // 이미 수집된 영상
continue;
}
BigDecimal viewsPerHour = VideoMetrics.viewsPerHour(dto.getViewCount(), dto.getPublishedAt());
BigDecimal viewsPerSubRatio = VideoMetrics.viewsPerSubRatio(dto.getViewCount(), dto.getSubscriberCount());
String hashtags = (dto.getHashtags() == null || dto.getHashtags().isEmpty())
? null : String.join(",", dto.getHashtags());
ChannelVideo video = ChannelVideo.fromSearch(
dto.getVideoId(), dto.getTitle(), dto.getThumbnailUrl(), dto.getPublishedAt(),
dto.getViewCount(), dto.getChannelId(), dto.getChannelTitle(), dto.getSubscriberCount(),
dto.getDurationSec(), viewsPerHour, viewsPerSubRatio, hashtags);
channelVideoRepository.save(video);
saved++;
savedIds.add(dto.getVideoId());
}
log.info("Search collection done. saved={}, skipped(duplicate/invalid)={}", saved, skipped);
return new CollectResult(saved, skipped, savedIds);
}
/** 수집 결과 요약. */
public record CollectResult(int saved, int skipped, List<String> savedVideoIds) {}
}