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