본문 바로가기

Playlist/Open API

TvSeriesApiService

*/domain/content/api/service

 

import com.codeit.playlist.domain.content.api.response.TvSeriesListResponse;
import com.codeit.playlist.domain.content.api.response.TvSeriesResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;

import java.time.Duration;

@Slf4j
@Service
@RequiredArgsConstructor
public class TvSeriesApiService {
    private final WebClient webClient;

    @Value("${TMDB_API_KEY}")
    private String apikey;

    private final int firstPage = 1;
    private final int maxPage = 5;

    private Mono<TvSeriesListResponse> callTheTvSeriesApi(String query, String path, int page) {
        log.info("[콘텐츠 데이터 관리] TvSeries API Mono 빌드 시작");
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .scheme("https")
                        .host("api.themoviedb.org")
                        .path(path)
                        .queryParam("api_key",apikey)
                        .query(query + "&page=" + page)
                        .build())
                .retrieve()
                .onStatus(s -> s.value() == 429, clientResponse -> clientResponse.createException().flatMap(Mono::error))
                .bodyToMono(TvSeriesListResponse.class)
                .retryWhen(
                        Retry.backoff(3, Duration.ofSeconds(2))
                                .filter(exception -> exception instanceof WebClientResponseException webClientResponseException && webClientResponseException.getStatusCode() == HttpStatus.TOO_MANY_REQUESTS)
                                .transientErrors(true)
                )
                .doOnError(WebClientResponseException.class,
                        e -> log.error("[콘텐츠 데이터 관리] TvSeries API Mono {} 수집 오류 : status = {}, body = {}", query, e.getStatusCode(), e.getResponseBodyAsString())
                );
    }

    private Flux<TvSeriesResponse> fluxingTvSeriesApi(String query, String path) {
        log.info("[콘텐츠 데이터 관리] TvSeries Api Flux 빌드 시작");
        return callTheTvSeriesApi(query, path, firstPage)
                .flatMapMany(firstPageResponse -> {
                    if(firstPageResponse.results() == null || firstPageResponse.results().isEmpty()) {
                        return Flux.empty();
                    }

                    int totalPages = firstPageResponse.totalPages();
                    int maxPages = Math.min(totalPages, maxPage);

                    Flux<TvSeriesResponse> firstFluxResult = Flux.fromIterable(firstPageResponse.results());
                    if(totalPages <= 1) {
                        return firstFluxResult;
                    }

                    Flux<TvSeriesResponse> afterFluxResult = Flux.range(2, maxPages -1)
                            .concatMap(page ->
                                    callTheTvSeriesApi(query, path, page)
                                            .flatMapMany(afterResponse -> {
                                                if(afterResponse.results() == null || afterResponse.results().isEmpty()) {
                                                    return Flux.empty();
                                                }
                                                return Flux.fromIterable(afterResponse.results());
                                            })
                            );
                    return Flux.concat(firstFluxResult, afterFluxResult);
                });
    }

    public Flux<TvSeriesResponse> getApiTv(String query) {
        return fluxingTvSeriesApi(query, "/3/discover/tv");
    }
}

 

'Playlist > Open API' 카테고리의 다른 글

TheSportApiService.java  (0) 2025.12.17
TmdbTagApiService.java  (0) 2025.12.17
TheMovieApiService  (0) 2025.12.17
Open API 사용하기 : The Movie (진행중)  (0) 2025.11.20
Open API : The Sports  (1) 2025.11.20