Reputation: 1851
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:
channels
playlistItems
(this step returns video information like title and videoId)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
Reputation: 2575
channel_id
in order to get the uploads
playlist.These are just my two cents, but, might be worth try it.
Upvotes: 0