0

我正在尝试向YouTube分析API发出请求。并且在形成请求时遇到一些麻烦,所以他们被接受。我使用的是谷歌的API Node.js的客户Youtube Analytics - 创建请求

https://github.com/google/google-api-nodejs-client

,我的代码如下

import { Meteor } from 'meteor/meteor'; 
import google from 'googleapis'; 
import KEY_FILE from './keyFile.json'; 
import { CHANNEL_ID } from './channelId.js'; 

//api's 
const analytics = google.youtubeAnalytics('v1'); 

//fetch youtube analytics 
export function youtubeAnalytics(start, end){ 
    //initalise request data 
    const startDate = `${start.getFullYear()}-${('0'+(start.getMonth()+1)).slice(-2)}-${('0'+(start.getDate())).slice(-2)}`; 
    const endDate = `${end.getFullYear()}-${('0'+(end.getMonth()+1)).slice(-2)}-${('0'+(end.getDate())).slice(-2)}`; 
    const scopes = [ 
    'https://www.googleapis.com/auth/youtube', 
    'https://www.googleapis.com/auth/youtube.readonly', 
    'https://www.googleapis.com/auth/yt-analytics-monetary.readonly', 
    'https://www.googleapis.com/auth/yt-analytics-monetary.readonly' 
    ]; 

    //generate authorisation token 
    var AUTH = new google.auth.JWT(
    KEY_FILE.client_email, 
    null, 
    KEY_FILE.private_key, 
    scopes, 
    null 
    ); 

    //authorize request 
    AUTH.authorize(function (err, tokens) { 
    if (err) { 
     console.log(err); 
     return; 
    } 

    //create request 
    const analyticsRequest = { 
     auth: AUTH, 
     'start-date': startDate, 
     'end-date': endDate, 
     ids: `channel==${CHANNEL_ID}`, 
     metrics: 'views', 
    }; 

    //make request 
    analytics.reports.query(analyticsRequest, function (err, data) { 
     if (err) { 
     console.error('Error: ' + err); 
     return false; 
     } 
     if (data) { 
     console.log(data); 
     return data; 
     } 
    }); 
    }); 
    return false; 
} 

Meteor.methods({youtubeAnalytics}); 

我不断收到以下错误

Error: Error: Invalid query. Query did not conform to the expectations. 

我认为它做与我的要求对象

const analyticsRequest = { 
    auth: AUTH, 
    'start-date': startDate, 
    'end-date': endDate, 
    ids: `channel==${CHANNEL_ID}`, 
    metrics: 'views', 
}; 

但我发现的所有例子都说这个请求对象应该工作。我尽可能地简化了它。我原来的要求(我真正想要的那个)如下。

const analyticsRequest = { 
    auth: AUTH, 
    'start-date': startDate, 
    'end-date': endDate, 
    ids: `channel==${CHANNEL_ID}`, 
    metrics: 'views', 
    dimensions: 'video', 
    sort: '-views', 
    'max-results': '200' 
} 

后,我需要做的另一个请求得到它使用不同的API端点列出的影片的所有相关信息。

//api's 
const youtube = google.youtube('v3'); 

/* 
    do processing of analytics data to create batchRequest 
    which is a string of comma separated video ids 
*/ 

videoRequest = { 
    auth: AUTH, 
    part: 'id,snippet', 
    id: batchRequest; 
} 

youtubeApiData.search.list(videosRequest, function (err, data) { 
    if (err) { 
     console.error('Error: ' + err); 
     return false; 
    } 
    if (data) { 
     console.log(data); 
     return data; 
    } 
}); 

因此,在总结

我需要做不同的谷歌API的请求,并让他们接受我有麻烦形成请求(我还没有过去YouTube数据分析的第一个请求) 。

有人能指出我正确的方向吗?

回答

0

想通了。无法为此API做一个服务帐户请求。通过我的设置帐户验证帐户,谷歌

https://guide.meteor.com/accounts.html

使用账户合并合并它的基本帐户

https://atmospherejs.com/splendido/accounts-meld

,给了我连接到用户,然后做了OAuth的一个访问令牌2.0改为拨打。为facebook做了类似的事情。

我仍然存在的一个问题是'视频的抓取保留'部分超级低效。它为每个视频拨打一个电话。有批量的请求可用于谷歌的API,但我似乎无法找到一个正确的例子使用'谷歌'的包。如果有人有一个例子,将不胜感激。

这里是新的代码。

import { Meteor } from 'meteor/meteor'; 
import google from 'googleapis'; 
import { CHANNEL_ID, USER_ID, KEY_FILE, API_KEY, CLIENT_ID, CLIENT_SECRET } from './keys.js'; 

//api's 
const fetchAnalytics = google.youtubeAnalytics('v1'); 
const fetchYoutube = google.youtube('v3'); 
const OAuth2 = google.auth.OAuth2; 

export function youtubeAnalytics(start, end){ 
    //requires login to generate authorisation 
    const user = Meteor.user(); 
    if(user && user.services && user.services.google && user.services.google.accessToken){ 
    //-------------------- general setup -------------------- // 

    //convert async functions to sync functions 
    const fetchYoutubeSync = Meteor.wrapAsync(fetchYoutube.search.list); 
    const fetchAnalyticsSync = Meteor.wrapAsync(fetchAnalytics.reports.query); 

    // set up default values 
    const analytics = {views: [], retention: []}; 
    const videos = []; 

    const startDate = `${start.getFullYear()}-${('0'+(start.getMonth()+1)).slice(-2)}-${('0'+(start.getDate())).slice(-2)}`; 
    const endDate = `${end.getFullYear()}-${('0'+(end.getMonth()+1)).slice(-2)}-${('0'+(end.getDate())).slice(-2)}`; 
    const startDateLong = `${start.getFullYear()}-${('0'+(start.getMonth()+1)).slice(-2)}-${('0'+(start.getDate())).slice(-2)}T00:00:00.0+00:00`; 
    const endDateLong = `${end.getFullYear()}-${('0'+(end.getMonth()+1)).slice(-2)}-${('0'+(end.getDate())).slice(-2)}T00:00:00.0+00:00`; 

    // generate authorisation tokens 
    const oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET,''); 
    oauth2Client.setCredentials({access_token: user.services.google.accessToken}); 
    google.options({ 
     auth: oauth2Client 
    }); 

    //-------------------- fetch videos between dates -------------------- // 

    let fetch = true; 
    let next = ''; 
    while (fetch) { 
     //create video request 
     let videosRequest = { 
     auth: oauth2Client, 
     part: 'id,snippet', 
     type: 'video', 
     channelId: CHANNEL_ID, 
     publishedAfter: startDateLong, 
     publishedBefore: endDateLong, 
     maxResults: 50, 
     pageToken: next, 
     } 
     //make video request 
     let response = fetchYoutubeSync(videosRequest); 
     //store video request 
     videos.push.apply(videos, response.items); 
     //check if more data is available 
     if(response.nextPageToken){ next = response.nextPageToken; } 
     else{ fetch = false;} 
    } 

    //-------------------- create batch request objects -------------------- // 
    if(videos.length > 0){ 
     //process videos 
     let batchRequestViews = ''; 
     let batchRequestRetention = []; 
     let first = true; 
     for(let i = 0; i < videos.length; i += 1){ 
     let id = false; 
     if(videos[i].id.kind === 'youtube#video'){ id = videos[i].id.videoId;} 
     if(id){ 
      //views processing 
      if(first){ first = false; batchRequestViews = id;} 
      else{ batchRequestViews = `${batchRequestViews},${id}`} 
      //retention processing 
      let request = { 
      auth: oauth2Client, 
      'start-date': startDate, 
      'end-date': endDate, 
      ids: `channel==${CHANNEL_ID}`, 
      metrics: 'audienceWatchRatio', 
      dimensions: 'elapsedVideoTimeRatio', 
      filters: `video==${id}` 
      }; 
      batchRequestRetention.push(request); 
     } 
     } 

     //-------------------- fetch views for videos -------------------- // 

     // create views request 
     const analyticsRequestViews = { 
     auth: oauth2Client, 
     'start-date': startDate, 
     'end-date': endDate, 
     ids: `channel==${CHANNEL_ID}`, 
     metrics: 'views', 
     dimensions: 'video', 
     filters: `video==${batchRequestViews}` 
     }; 
     // make and store views request 
     analytics.views = fetchAnalyticsSync(analyticsRequestViews).rows; 

     //-------------------- fetch retention for videos -------------------- // 

     //make retention batch request 
     if(batchRequestRetention && batchRequestRetention.length > 0){ 
     for(let i = 0; i < batchRequestRetention.length; i += 1){ 
      //fetch retention request 
      let request = batchRequestRetention[i]; 
      //make retention request 
      let response = fetchAnalyticsSync(request); 
      //store response 
      analytics.retention.push({id: request.filters.substring(7), response}); 
     } 
     } 

     //-------------------- return results -------------------- // 
     return {videos, analytics}; 
    } 
    } 
    return false; 
} 

Meteor.methods({youtubeAnalytics});