【问题标题】:YouTube Data v3 API - How to request all videos from a channel?YouTube Data v3 API - 如何从频道请求所有视频?
【发布时间】:2021-06-03 16:29:25
【问题描述】:

我正在编写一个 Node.js 脚本,它将在 Lambda 中运行,以通过 YouTube Data v3 API 定期为我的组织的一个频道请求每个视频(公共、未列出或私有)的列表。为了做到这一点,似乎有两个步骤:

  1. 执行频道/列表调用https://developers.google.com/youtube/v3/docs/channels/list 以获取“上传”播放列表。
const channelResult = await google.youtube('v3').channels.list({
    auth: youtubeApiKey,
    part: ['snippet', 'contentDetails'],
    id: ["my_channel_id"]
});
  1. 执行 playlistItems/list https://developers.google.com/youtube/v3/docs/playlistItems/list 以查看所有视频。
const videosResult = await google.youtube('v3').playlistItems.list({
    auth: youtubeApiKey,
    part: ['snippet', 'status'],
    playlistId: "my_uploads_playlsit_id"
});

这只会作为运行云的脚本执行;没有用户界面或浏览器组件。当我将那里的唯一视频设置为公开时,这一切似乎都在我的测试频道中起作用。但如果我将其设置为私有,我会得到:

The playlist identified with the request's <code>playlistId</code> parameter cannot be found.

我必须做些什么才能仍然访问我频道的上传播放列表并显示私人视频?谢谢!

【问题讨论】:

  • 您的代码有点模棱两可。 auth: youtubeApiKey 是否将 API 密钥 传递给您的 API 调用?或者,否则,youtubeApiKey 是一个有效的凭证对象(例如,Node.js Quickstart 的示例代码所示)?请注意,要访问私有数据,您必须成功完成 OAuth 2 授权/身份验证流程,如提到的示例代码所示。
  • @stvar 好问题——它最初是一个 API 密钥,但后来我意识到显然我需要更好的身份验证来访问私有数据。所以我将传递给auth: 的值更改为new google.auth.OAuth2 客户端,我最终可以在本地机器上工作。但是我想知道当没有浏览器/人运行它并且它被 cron 触发时,我怎样才能让它在服务器端工作?
  • @stvar 非常好。一旦我得到它的工作,我会在这个问题的答案中描述必要的步骤。
  • 但您需要了解 Google 最近提出的以下要求:Python OAuth after few days fails refreshing tokens with “invalid_grant” error

标签: node.js youtube youtube-api youtube-data-api google-authentication


【解决方案1】:

在原始问题的 cmets 中 @stvar 的帮助下,我能够做到这一点。流程是这样的:

  1. 通过启用 API 和服务从 Google Developers Console 启用 YouTube 数据 API v3。
  2. 在 YouTube Data API v3 的“凭据”窗格下创建一个新的 OAuth 客户端 ID,然后选择桌面应用。
  3. 保存client_id 和client_secret。通过您喜欢的任何环境变量方法,让您的 Node 应用可以访问这些内容。
  4. 创建一个单独的脚本,专门用于通过 YouTube Data API v3 OAuth 获取 refresh_token
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);
  1. 将刷新令牌保存在另一个环境变量中,您的主数据获取脚本可以访问。像这样使用它:

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);
  1. 最后一个 .map() 函数,标有“根据需要处理文件”注释,将接收频道中的每个视频,无论是公开的、不公开的还是私有的。

注意:我还不知道给定的 refresh_token 会持续多久,但假设您经常需要再次运行第一个脚本并通过第二个脚本的环境变量更新使用的 refresh_token。

【讨论】:

    猜你喜欢
    • 2021-03-13
    • 2016-03-12
    • 2019-07-27
    • 2017-11-21
    • 2014-02-23
    • 2016-08-30
    • 2016-08-26
    • 2013-12-16
    • 2015-04-17
    相关资源
    最近更新 更多