66 lines
2.5 KiB
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) {}
|
|
}
|