Jordan Lewallen
Jordan Lewallen

Reputation: 1851

How to query for total views of every video on a YouTube channel using YouTube Data API?

I am working on a small project that must query for every video on a YouTube channel and return the video title and total views for that video. I've figure out a way to handle this, but the quota cost is rather steep for a channel of over 1500 videos (about 300 quota points), so I was curious if there was a more efficient way to query for such information.

The steps I currently have to take are threefold:

  1. Query the current user and find their uploads playlist id using channels
  2. Use the playlist id to query for videos in that playlist using playlistItems (this step returns video information like title and videoId)
  3. Parse out the video ids from step 2 and query for a list of videos that returns the statistics for each video using videos

I then merge the results from 2 and 3 to create an object that contains both video information and statistics.

  {
    videoId: 'abc1-345dgh'
    title: 'Video Title',
    thumbnail: {
      img: 'image information'
    },
    views: 12345567
  }

Is there a better way to return a list of videos with video information and view statistics?

Here are the steps I have to take:

const channel = await youtubeAPI.channels.list({
    part: 'contentDetails',
    mine: true
  });

const playlistId = channel.data.items[0].contentDetails.relatedPlaylists.uploads;

const videos = await getPlaylistVideos(playlistId);

The playlistId of the users uploads playlist is sent to getPlaylistVideos() which iterates over each page of results from a playlistItems query.

var videos = [];
var videoStats = [];

async function getPlaylistVideos(playlistId, pageToken = null) {

  const res = await youtubeAPI.playlistItems.list({
    part: 'snippet',
    playlistId: playlistId,
    maxResults: 50,
    pageToken: pageToken
  });

  const mappedVideos = res.data.items.map((item) => {
    return {
      title: item.snippet.title,
      thumbnail: item.snippet.thumbnails.maxres,
      videoId: item.snippet.resourceId.videoId
    }
  })

  videos.push(...mappedVideos);
  // if there's another page to get results from
  if ('nextPageToken' in res.data) {
    return await getPlaylistVideos(playlistId, res.data.nextPageToken)
  } else {
    // we've queried for everything, return the videos
    return videos;
  }
}

Next, I filter out the video Ids returned from the videos array

const videoIds = videos.map((video) => {
    return video.videoId
  });

videoIdArray.push(...videoIds);

const videoStats = await getVideoStats(videoIdArray);

These ids get sent to getVideoStats() and I iterate through all video ids and return statistics for each video

var minId = 0;
var maxId = 50;

async function getVideoStats(videoIds) {

  // since we can only return 50 videos per query, I have to slice the
  // videoId array into segments
  const videoIdLength = videoIds.length;
  const subsetIds = videoIds.slice(minId, maxId);

  const res = await youtubeAPI.videos.list({
    part: 'statistics',
    id: subsetIds.join(","),
    maxResults: 50
  });

  const mappedVideoStats = res.data.items.map((item) => {
    return {
      videoId: item.id,
      views: item.statistics.viewCount
    }
  });

  videoStats.push(...mappedVideoStats);

  const diff = videoIdLength - (maxId + 1);

  if (diff > 0) {
    // if there are more videos to query, update the variables used 
    // in slice() to take 50 more videos
    minId += 50;
    maxId += 50;
    return await getVideoStats(videoIds);
  } else {
    return videoStats;
  }

}

Lastly, I merge the video information with the video statistics by looking for matching videoId properties in each object:

let mergedArray = [];

  videos.forEach((video, index) => {
    mergedArray.push(Object.assign({}, video, videoStats[index]))
  })

mergedArray finally stores the information that I need.

This is the info I need, I just feel like I had to jump through hoops to get to it. Is there a more efficient method for achieving the same task? Thanks!

Upvotes: 0

Views: 581

Answers (1)

Mauricio Arias Olave
Mauricio Arias Olave

Reputation: 2575

  • You can save some quota by changing the code you're using for retrieve the "uploads" playlist from a given channel. Check my answer about the change you have to make in the channel_id in order to get the uploads playlist.
  • My second option would be using Google Custom Search API (as I describe in my other answer) - since in YouTube Data API dwill always consume the same quota - no matter how many parameters/terms you use in each request.

These are just my two cents, but, might be worth try it.

Upvotes: 0

Related Questions