안녕하세요

2주차 유튜브 API(8) - 채널의 최신영상: Youtube API 할당량 최적화 필요 본문

복습스터디과제

2주차 유튜브 API(8) - 채널의 최신영상: Youtube API 할당량 최적화 필요

sakuraop 2023. 1. 29. 12:49

채널의 최신 영상을 가져옵니다.

구독한 채널별로 컴포넌트를 만들어 channelId를 전달한다.

      {subscribeList.map((subscribedChannel, index) => {
          <div key={index}>
            <a href={channelHref(subscribedChannel.channelId)} target="_blank" rel="noreferrer">
              {subscribedChannel.title}
            </a>
            <RecentVideos channelId={subscribedChannel.channelId} />
          </div>
       )}

=> map을 통해서 <RecentVideos> 컴포넌트를 불러온다.

 

전달받은 channelId를 이용하여 해당 채널의 최신 영상을 불러온다.

    useEffect(() => {
      (async () => {
        const recentVideoData = await getChannelRecentVideos(channelId, VIDEO_AMOUNT);
        setVideoArray([...recentVideoData]);
        console.log(videoArray);
      })();
    }, []);

=> 각 <RecentVideos> 컴포넌트가 Api 요청을 보내고 있다.

axios.defaults.baseURL = "https://youtube.googleapis.com/youtube/v3";

const apiKey = process.env.REACT_APP_API_KEY;

/**
 * @param {string} channelId
 * @param {number} amount
 * @returns res.data.items
 */
const getChannelRecentVideos = async (channelId, amount) => {
  const params = {
    key: apiKey,
    part: "snippet",
    channelId: channelId,
    order: "date",
    maxResults: amount,
  };

  try {
    const response = await axios.get("/search", { params });
    return response.data.items;
  } catch (error) {
    console.log("error", error);
  }
};

=> 최신 비디오 API 요청을 하는 함수

 

=> mockData로 구현해서 채널과 비디오 내용은 관련이 없음


포인트 1. API 요청에서 요구하는 part가 많을 수록 비효율적이다.

=> useEffect에 dependency를 잘못 주었다가 무한 요청을 하는 바람에 일일 할당량이 1초만에 고갈되어 버렸다.

비단 무한 요청의 탓 만이 아닌 것이 이전의 그래프를 보더라도 사용량이 적지 않다는 것을 알 수 있다.

이렇게 한 대 맞고 나서 아래의 문서를 찾아보게 된다.

Youtube API 할당량 사용 문서 보기

=> 요청마다 할당량이 다르고, part를 늘릴수록 비용이 커진다. (나는 지금 part=snippet만 찾은 경우이다.)

 

Youtube API 요청별 비용 문서 보기

=> 요청별 할당량 표를 보면 videos > list (mostPopularVideos)의 경우 1의 비용이 필요하지만,

 

  const params = {
    key: apiKey,
    part: "snippet",
    channelId: channelId,
    order: "date",
    maxResults: amount,
  };

  try {
    const response = await axios.get("/search", { params });
    console.log(response.data.items);
    return response.data.items;
  } catch (error) {
    console.log("error", error);
  }

=> 지금 찾고 있는 조건인 search > list (channelRecentVideos)의 경우 100의 비용이 필요하다.

=> /search 로 요청은 압수

 

즉, 채널의 최근 비디오 검색 요청은 100을 먹는다. 이거 쓰면 안된다.


포인트 2. 요청 컴포넌트의 숫자에 따라 트래픽이 증가하게 된다.

컴포넌트 당 100의 비용을 할당한다고 가정할 때,

구독 10개를 하게 되면 컴포넌트가 10개이니 회당 1000의 비용을 필요로 하게 된다.

(개인적으로는 지금이 가장 최적화 된 방법이다.)

 

/search에 대한 요청을 멈추고 다른 방법을 찾아야 한다.

모든 문서 내용을 읽어 본 결론😨

/search 요청 이외에는 최근 업로드 된 동영상을 찾을 방법이 없다.

따라서 1의 비용을 요구하는 playlist 를 활용하는 것이 차선책이다.

왜 차선책이냐면, 재생 목록을 업데이트 하지 않은 동영상의 경우에는 이용을 못한다.

 

어떻게 해서든 최근 업로드 된 동영상을 렌더링하고 싶다 라면 search를 이용하는 것이 불가피하다.

 

재생목록에 최신 영상을 업데이트 하는 채널의 경우에는 제외 하는 등의 방법으로

구독한 search를 이용할 채널의 수를 한정하고,

일정 주기마다 search 요청을 보내는 것이 최선책으로 보인다.

10개의 채널이 구독 목록에 있다고 가정하면 10회 검색에 할당량을 초과하므로

 

24시간 / 10 => 2.4 시간마다 요청을 보내는 것이다.

 

어떻게..?

 

setInterval로 GET 요청을 보내는 함수를 만들면 어떨까 (지금 실력으로 가능한지 모름)

 

탐색setInterval로 하루에 한 번 search를 이용해 새로운 채널 탐색, 중복이 없을 경우 구독한 채널 배열에 추가 =>

최근영상setInterval로 일정 시간( ( 24- {search 부가비용} ) / 구독한 채널 배열 ) 마다 새롭게 구독한 채널로 GET요청 =>

구독한 채널 정보가 DB에 있는가? 없는가? =>

DB에 새롭게 구독한 채널 데이터를 저장 =>

DB에서 가져온 데이터로 렌더링

 

위의 과정을 서버를 구현해 반복시킨다. 

=> 최근영상setInterval로 반복

=> 하루 지나면 탐색setInterval로 반복

 

찾았다

"/channels.contentDetails" (1P * channel db.length) 

playlist 정보

      "contentDetails": {
        "relatedPlaylists": {
          "likes": "",
          "uploads": "UUzmd0IzkyCG1zpHbneTrtYQ"
        }
      },

=> uploads 속성 이용하면 업로드한 모든 영상을 담은 재생목록 반환


일단은 search가 아닌 재생목록으로 구현해보도록 하자

사전 구현단계 설계

구독한 채널 id를 저장한 배열 만들기 =>

구독한 채널 id에서 제공하는 재생목록 찾기(재생목록 찾는 방법은 또 찾아봐야함) =>

재생목록에 날짜 데이터가 있는가? 없는가? 재생목록은 최근 업로드 된 순서대로 나열되는가? =>

  • 있다면? : 재생목록의 날짜 데이터로, 가장 최근에 추가된 재생목록의 동영상을 추가
  • 없다면? : 재생 목록에 있는 동영상의 날짜 데이터로, 가장 최근에 추가된 동영상을 추가
  • 최근 업로드 된 순서대로 나열된다면? : 최근 4개 재생목록의 최근 동영상을 4,3,2,1개씩 배열에 저장 =>
    배열의 요소를 시간 순으로 정렬 =>
    빠른 순으로 동영상을 추가

=> 추가된 동영상을 구독한 채널 목록에 위에서 구현한 것과 동일한 방식으로 출력하기