With help from @stvar in the original question's comments, I was able to achieve this. The flow is as such:
- Enable the YouTube Data API v3 from the Google Developers Console via the Enable APIs and Services.
- Create a new OAuth client ID under YouTube Data API v3's "Credentials" pane and select Desktop app.
- Save the client_id and client_secret. Make these accessible to your Node app via whatever environment variable method you prefer.
- Create a separate script specifically for getting a refresh_token via YouTube Data API v3 OAuth
-
import { google } from 'googleapis';
import prompts from 'prompts';
console.log("about to execute oauth");
const yt_client_id = process.env.YOUTUBE_CLIENT_ID;
const yt_client_secret = process.env.YOUTUBE_CLIENT_SECRET;
const oauthClient = new google.auth.OAuth2({
clientId: yt_client_id,
clientSecret: yt_client_secret,
redirectUri: 'http://localhost'
});
const authUrl = oauthClient.generateAuthUrl({
access_type: 'offline', //gives you the refresh_token
scope: 'https://www.googleapis.com/auth/youtube.readonly'
});
const codeUrl = await prompts({
type: 'text',
name: 'codeURl',
message: `Please go to \n\n${authUrl}\n\nand paste in resulting localhost uri`
});
const decodedUrl = decodeURIComponent(codeUrl.codeURl);
const code = decodedUrl.split('?code=')[1].split("&scope=")[0];
const token = (await oauthClient.getToken(code)).tokens;
const yt_refresh_token = token.refresh_token;
console.log(`Please save this value into the YOUTUBE_REFRESH_TOKEN env variable for future runs: ${yt_refresh_token}`);
await prompts({
type: 'text',
name: 'blank',
message: 'Hit enter to exit:'
});
process.exit(0);
Save the refresh token in another environment variable, accessible to your main data-fetching script. Use it as such:
-
import { google } from 'googleapis';
console.log("Beginning youtubeIndexer. Checking for valid oauth.");
const yt_refresh_token = process.env.YOUTUBE_REFRESH_TOKEN;
const yt_client_id = process.env.YOUTUBE_CLIENT_ID;
const yt_client_secret = process.env.YOUTUBE_CLIENT_SECRET;
const yt_channel_id = process.env.YOUTUBE_CHANNEL_ID;
const oauthClient = new google.auth.OAuth2({
clientId: yt_client_id,
clientSecret: yt_client_secret,
redirectUri: 'http://localhost'
});
oauthClient.setCredentials({
refresh_token: yt_refresh_token
});
const youtube = google.youtube("v3");
const channelResult = await youtube.channels.list({
auth: oauthClient,
part: ['snippet', 'contentDetails'],
id: [yt_channel_id]
});
let nextPageToken = undefined;
let videosFetched = 0;
do {
const videosResult = await youtube.playlistItems.list({
auth: oauthClient,
maxResults: 50,
pageToken: nextPageToken,
part: ['snippet', 'status'],
playlistId: channelResult.data.items[0].contentDetails.relatedPlaylists.uploads
});
videosFetched += videosResult.data.items.length;
nextPageToken = videosResult.data.nextPageToken;
videosResult.data.items.map((video, index) => {
//process the files as you need to.
});
} while (nextPageToken);
- This last .map() function, marked with the "process the files as you need to" comment will receive every video in the channel, whether it be public, unlisted, or private.
NOTE: I do not know yet how long a given refresh_token will last, but assume that you will regularly need to run the first script again and update the refresh_token used via the second script's environment variable.
auth: youtubeApiKey
passes to your API calls an API key? Or, else,youtubeApiKey
is a valid credentials object (like shown, for example by the sample code of Node.js Quickstart)? Do note that for accessing private data you have to run to successful completion an OAuth 2 authorization/authentication flow as shown by the sample code mentioned. – stvarauth:
to be a annew google.auth.OAuth2
client which I eventually got to work on my local machine. But I'm wondering how I can get this to work on the server side when there is no browser/person running this and it's getting triggered by cron? – John D.