1

I am trying to make a request to the youtube analytics api. and am having some trouble forming the requests so they are accepted. I am using the Google APIs Node.js Client

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

and my code is as follows

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});

I keep getting the following error

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

I think its to do with my request object

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

but all the examples i've found say that this request object should work. Ive simplified it down as much as i could. My original request (the one that i actually want) was as follows.

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

after that i need to do another request to get all the associated info on the videos listed which uses a different api endpoint.

//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;
   }
});

So In Summary

I need to do a request to various google api's and am having trouble forming the request so they are accepted (I have not got past the first request from youtube analytics).

can someone point me in the right direction?

4

1 回答 1

0

弄清楚了。无法为此 API 执行服务帐户请求。我通过accounts-google设置帐户验证

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

使用帐户融合将其合并到基本帐户

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

这给了我一个附加到用户的访问令牌,然后进行了 OAuth 2.0 调用。也为 facebook 做了类似的事情。

我仍然遇到的一个问题是“获取视频的保留”部分效率非常低。每个视频打一个电话。有可用于 google api 的批处理请求,但我似乎无法使用“googleapis”包找到合适的示例。如果有人有一个非常感谢的例子。

这是新代码。

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});
于 2017-03-29T00:50:45.893 回答