サンプル アプリケーションをビルドする

このページでは、さまざまな API を使用してユーザーの YouTube 動画の再生に関する統計情報をグラフ化するアプリケーションの作成手順を説明します。このアプリケーションでは、以下のタスクを実行します。

  • YouTube Data API を使用して、現在認証されているユーザーがアップロードした動画のリストを取得し、動画タイトルを一覧表示します。
  • ユーザーが特定の動画をクリックすると、アプリケーションは YouTube Analytics API を呼び出して、その動画のアナリティクス データを取得します。
  • このアプリケーションは、Google Visualization API を使用して分析データをグラフに表示します。

以下の各ステップは、アプリケーションの作成プロセスを表したものです。ステップ 1 では、アプリケーションの HTML ファイルと CSS ファイルを作成します。ステップ 2 からステップ 5 では、アプリケーションが使用するさまざまな JavaScript のパーツを記述します。また、このドキュメントの最後には、サンプル コード全体を掲載しています。

  1. ステップ 1: HTML ページと CSS ファイルを作成する
  2. ステップ 2: OAuth 2.0 認証を有効にする
  3. ステップ 3: 現在ログインしているユーザーのデータを取得する
  4. ステップ 4: 動画のアナリティクス データをリクエストする
  5. ステップ 5: アナリティクスのデータをグラフで表示する

重要: アプリケーションの OAuth 2.0 クライアント ID を取得するには、Google にアプリケーションを登録する必要があります。

ステップ 1: HTML ページと CSS ファイルを作成する

このステップでは、アプリケーションで使用する JavaScript ライブラリを読み込む HTML ページを作成します。次の HTML は、このページで使用するコードを示したものです。


<!doctype html>
<html>
<head>
 
<title>Google I/O YouTube Codelab</title>
 
<link type="text/css" rel="stylesheet" href="index.css">
 
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
 
<script type="text/javascript" src="//www.google.com/jsapi"></script>
 
<script type="text/javascript" src="index.js"></script>
 
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=onJSClientLoad"></script>
</head>
<body>
 
<div id="login-container" class="pre-auth">This application requires access to your YouTube account.
    Please
<a href="#" id="login-link">authorize</a> to continue.
 
</div>
 
<div class="post-auth">
   
<div id="message"></div>
   
<div id="chart"></div>
   
<div>Choose a Video:</div>
   
<ul id="video-list"></ul>
 
</div>
</body>
</html>

サンプルページの <head> タグに示すように、このアプリケーションでは次のライブラリを使用しています。

  • jQuery: HTML ドキュメントの全探索、イベント処理、アニメーション化、Ajax の各操作を簡素化するためのヘルパー メソッドです。
  • Google API ローダーwww.google.com/jsapi)を使用すると、1 つ以上の Google API を簡単にインポートできます。このサンプル アプリケーションでは、API ローダーを使用して Google Visualization API を読み込み、取得したアナリティクス データをグラフに表示します。
  • index.js ライブラリには、サンプル アプリケーションに固有の関数が含まれています。これらの関数の作成手順については、このチュートリアルで説明します。
  • Google APIs Client Library for JavaScript: OAuth 2.0 認証を実装したり、YouTube Analytics API を呼び出したりできます。

サンプル アプリケーションには、index.css ファイルも含まれています。サンプルの CSS ファイルは以下に示すとおりです。このファイルは HTML ページと同じディレクトリに保存します。

body {
  font-family: Helvetica, sans-serif;
}

.pre-auth {
  display: none;
}

.post-auth {
  display: none;
}

#chart {
  width: 500px;
  height: 300px;
  margin-bottom: 1em;
}

#video-list {
  padding-left: 1em;
  list-style-type: none;
}
#video-list > li {
  cursor: pointer;
}
#video-list > li:hover {
  color: blue;
}

ステップ 2: OAuth 2.0 認証を有効化する

このステップでは、HTML ページから呼び出される index.js ファイルを作成します。これを念頭に置いて、HTML ページと同じディレクトリに index.js という名前のファイルを作成し、そのファイルに次のコードを挿入します。文字列 YOUR_CLIENT_ID は、登録済みのアプリのクライアント ID に置き換えます。

(function() {

 
// Retrieve your client ID from the Google API Console at
 
// https://console.cloud.google.com/.
 
var OAUTH2_CLIENT_ID = 'YOUR_CLIENT_ID';
 
var OAUTH2_SCOPES = [
   
'https://www.googleapis.com/auth/yt-analytics.readonly',
   
'https://www.googleapis.com/auth/youtube.readonly'
 
];

 
// Upon loading, the Google APIs JS client automatically invokes this callback.
 
// See https://developers.google.com/api-client-library/javascript/features/authentication
  window
.onJSClientLoad = function() {
    gapi
.auth.init(function() {
      window
.setTimeout(checkAuth, 1);
   
});
 
};

 
// Attempt the immediate OAuth 2.0 client flow as soon as the page loads.
 
// If the currently logged-in Google Account has previously authorized
 
// the client specified as the OAUTH2_CLIENT_ID, then the authorization
 
// succeeds with no user intervention. Otherwise, it fails and the
 
// user interface that prompts for authorization needs to display.
 
function checkAuth() {
    gapi
.auth.authorize({
      client_id
: OAUTH2_CLIENT_ID,
      scope
: OAUTH2_SCOPES,
      immediate
: true
   
}, handleAuthResult);
 
}

 
// Handle the result of a gapi.auth.authorize() call.
 
function handleAuthResult(authResult) {
   
if (authResult) {
     
// Authorization was successful. Hide authorization prompts and show
     
// content that should be visible after authorization succeeds.
      $
('.pre-auth').hide();
      $
('.post-auth').show();

      loadAPIClientInterfaces
();
   
} else {
     
// Authorization was unsuccessful. Show content related to prompting for
     
// authorization and hide content that should be visible if authorization
     
// succeeds.
      $
('.post-auth').hide();
      $
('.pre-auth').show();

     
// Make the #login-link clickable. Attempt a non-immediate OAuth 2.0
     
// client flow. The current function is called when that flow completes.
      $
('#login-link').click(function() {
        gapi
.auth.authorize({
          client_id
: OAUTH2_CLIENT_ID,
          scope
: OAUTH2_SCOPES,
          immediate
: false
       
}, handleAuthResult);
     
});
   
}
 
}

 
// This helper method displays a message on the page.
 
function displayMessage(message) {
    $
('#message').text(message).show();
 
}

 
// This helper method hides a previously displayed message on the page.
 
function hideMessage() {
    $
('#message').hide();
 
}
 
/* In later steps, add additional functions above this line. */
})();

ステップ 3: 現在ログイン中のユーザーのデータを取得する

このステップでは、YouTube Data API(v2.0)を使用して、現在ログインしているユーザーのアップロードした動画フィードを取得する関数を index.js ファイルに追加します。このフィードには、ユーザーの YouTube チャンネル ID が指定されます。この ID は、YouTube アナリティクス API を呼び出す際に必要になります。また、サンプルアプリでは、ユーザーがアップロードした動画が一覧表示されるため、ユーザーは個々の動画のアナリティクス データを取得できます。

index.js ファイルに次の変更を加えます。

  1. YouTube Analytics API と Data API のクライアント インターフェースを読み込む関数を追加します。これは、Google API JavaScript クライアントを使用するための前提条件です。

    両方の API クライアント インターフェースが読み込まれると、この関数は getUserChannel 関数を呼び出します。


     
    // Load the client interfaces for the YouTube Analytics and Data APIs, which
     
    // are required to use the Google APIs JS client. More info is available at
     
    // https://developers.google.com/api-client-library/javascript/dev/dev_jscript#loading-the-client-library-and-the-api
     
    function loadAPIClientInterfaces() {
        gapi
    .client.load('youtube', 'v3', function() {
          gapi
    .client.load('youtubeAnalytics', 'v1', function() {
           
    // After both client interfaces load, use the Data API to request
           
    // information about the authenticated user's channel.
            getUserChannel
    ();
         
    });
       
    });
     
    }
  2. channelId 変数と getUserChannel 関数を追加します。この関数は YouTube Data API(v3)を呼び出し、mine パラメータを含みます。これは、リクエストが現在認証されているユーザーのチャンネル情報に対するものであることを示します。channelId は Analytics API に送信され、アナリティクス データを取得するチャンネルを識別します。


     
    // Keep track of the currently authenticated user's YouTube channel ID.
     
    var channelId;

     
    // Call the Data API to retrieve information about the currently
     
    // authenticated user's YouTube channel.
     
    function getUserChannel() {
       
    // Also see: https://developers.google.com/youtube/v3/docs/channels/list
       
    var request = gapi.client.youtube.channels.list({
         
    // Setting the "mine" request parameter's value to "true" indicates that
         
    // you want to retrieve the currently authenticated user's channel.
          mine
    : true,
          part
    : 'id,contentDetails'
       
    });

        request
    .execute(function(response) {
         
    if ('error' in response) {
            displayMessage
    (response.error.message);
         
    } else {
           
    // We need the channel's channel ID to make calls to the Analytics API.
           
    // The channel ID value has the form "UCdLFeWKpkLhkguiMZUp8lWA".
            channelId
    = response.items[0].id;
           
    // Retrieve the playlist ID that uniquely identifies the playlist of
           
    // videos uploaded to the authenticated user's channel. This value has
           
    // the form "UUdLFeWKpkLhkguiMZUp8lWA".
           
    var uploadsListId = response.items[0].contentDetails.relatedPlaylists.uploads;
           
    // Use the playlist ID to retrieve the list of uploaded videos.
            getPlaylistItems
    (uploadsListId);
         
    }
       
    });
     
    }
  3. 指定したプレイリスト内のアイテムを取得する getPlaylistItems 関数を追加します。この場合、再生リストには、ユーザーのチャンネルにアップロード済みの動画が登録表示されています(以下のサンプル関数では、フィードの最初の 50 アイテムのみが取得されることに注意してください。アイテムをさらに取得するには、ページ設定を実装する必要があります)。

    再生リストアイテムのリストを取得した後、この関数は getVideoMetadata() 関数を呼び出します。getVideoMetadata() 関数は、リスト内の各動画のメタデータを取得します。また、この関数は、ユーザーに表示されるリストに各動画を追加します。


     
    // Call the Data API to retrieve the items in a particular playlist. In this
     
    // example, we are retrieving a playlist of the currently authenticated user's
     
    // uploaded videos. By default, the list returns the most recent videos first.
     
    function getPlaylistItems(listId) {
       
    // See https://developers.google.com/youtube/v3/docs/playlistitems/list
       
    var request = gapi.client.youtube.playlistItems.list({
          playlistId
    : listId,
          part
    : 'snippet'
       
    });

        request
    .execute(function(response) {
         
    if ('error' in response) {
            displayMessage
    (response.error.message);
         
    } else {
           
    if ('items' in response) {
             
    // The jQuery.map() function iterates through all of the items in
             
    // the response and creates a new array that only contains the
             
    // specific property we're looking for: videoId.
             
    var videoIds = $.map(response.items, function(item) {
               
    return item.snippet.resourceId.videoId;
             
    });

             
    // Now that we know the IDs of all the videos in the uploads list,
             
    // we can retrieve information about each video.
              getVideoMetadata
    (videoIds);
           
    } else {
              displayMessage
    ('There are no videos in your channel.');
           
    }
         
    }
       
    });
     
    }

     
    // Given an array of video IDs, this function obtains metadata about each
     
    // video and then uses that metadata to display a list of videos.
     
    function getVideoMetadata(videoIds) {
       
    // https://developers.google.com/youtube/v3/docs/videos/list
       
    var request = gapi.client.youtube.videos.list({
         
    // The 'id' property's value is a comma-separated string of video IDs.
          id
    : videoIds.join(','),
          part
    : 'id,snippet,statistics'
       
    });

        request
    .execute(function(response) {
         
    if ('error' in response) {
            displayMessage
    (response.error.message);
         
    } else {
           
    // Get the jQuery wrapper for the #video-list element before starting
           
    // the loop.
           
    var videoList = $('#video-list');
            $
    .each(response.items, function() {
             
    // Exclude videos that do not have any views, since those videos
             
    // will not have any interesting viewcount Analytics data.
             
    if (this.statistics.viewCount == 0) {
               
    return;
             
    }

             
    var title = this.snippet.title;
             
    var videoId = this.id;

             
    // Create a new <li> element that contains an <a> element.
             
    // Set the <a> element's text content to the video's title, and
             
    // add a click handler that will display Analytics data when invoked.
             
    var liElement = $('<li>');
             
    var aElement = $('<a>');
             
    // Setting the href value to '#' ensures that the browser renders the
             
    // <a> element as a clickable link.
              aElement
    .attr('href', '#');
              aElement
    .text(title);
              aElement
    .click(function() {
                displayVideoAnalytics
    (videoId);
             
    });

             
    // Call the jQuery.append() method to add the new <a> element to
             
    // the <li> element, and the <li> element to the parent
             
    // list, which is identified by the 'videoList' variable.
              liElement
    .append(aElement);
              videoList
    .append(liElement);
           
    });

           
    if (videoList.children().length == 0) {
             
    // Display a message if the channel does not have any viewed videos.
              displayMessage
    ('Your channel does not have any videos that have been viewed.');
           
    }
         
    }
       
    });
     
    }

ステップ 4: 動画のアナリティクス データをリクエストする

このステップでは、動画のタイトルをクリックしたときに、アプリケーションが YouTube Analytics API を呼び出してその動画のアナリティクス データを取得するように、サンプル アプリケーションを変更します。サンプル アプリケーションの変更方法は以下のとおりです。

  1. 取得したアナリティクス レポート データのデフォルトの期間を指定する変数を追加します。


     
    var ONE_MONTH_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 30;
  2. 日付オブジェクトの YYYY-MM-DD 文字列を作成し、日付の日付と月を 2 桁にパディングするコードを追加します。


     
    // This boilerplate code takes a Date object and returns a YYYY-MM-DD string.
     
    function formatDateString(date) {
       
    var yyyy = date.getFullYear().toString();
       
    var mm = padToTwoCharacters(date.getMonth() + 1);
       
    var dd = padToTwoCharacters(date.getDate());

       
    return yyyy + '-' + mm + '-' + dd;
     
    }

     
    // If number is a single digit, prepend a '0'. Otherwise, return the number
     
    //  as a string.
     
    function padToTwoCharacters(number) {
       
    if (number < 10) {
         
    return '0' + number;
       
    } else {
         
    return number.toString();
       
    }
     
    }
  3. 動画の YouTube アナリティクス データを取得する displayVideoAnalytics 関数を定義します。この関数は、ユーザーがリスト内の動画をクリックすると実行されます。ステップ 3 で定義した動画のリストを表示する getVideoMetadata 関数で、クリック イベント ハンドラを定義します。


     
    // This function requests YouTube Analytics data for a video and displays
     
    // the results in a chart.
     
    function displayVideoAnalytics(videoId) {
       
    if (channelId) {
         
    // To use a different date range, modify the ONE_MONTH_IN_MILLISECONDS
         
    // variable to a different millisecond delta as desired.
         
    var today = new Date();
         
    var lastMonth = new Date(today.getTime() - ONE_MONTH_IN_MILLISECONDS);

         
    var request = gapi.client.youtubeAnalytics.reports.query({
           
    // The start-date and end-date parameters must be YYYY-MM-DD strings.
           
    'start-date': formatDateString(lastMonth),
           
    'end-date': formatDateString(today),
           
    // At this time, you need to explicitly specify channel==channelId.
           
    // See https://developers.google.com/youtube/analytics/v1/#ids
            ids
    : 'channel==' + channelId,
            dimensions
    : 'day',
            sort
    : 'day',
           
    // See https://developers.google.com/youtube/analytics/v1/available_reports
           
    // for details about the different filters and metrics you can request
           
    // if the "dimensions" parameter value is "day".
            metrics
    : 'views',
            filters
    : 'video==' + videoId
         
    });

          request
    .execute(function(response) {
           
    // This function is called regardless of whether the request succeeds.
           
    // The response contains YouTube Analytics data or an error message.
           
    if ('error' in response) {
              displayMessage
    (response.error.message);
           
    } else {
              displayChart
    (videoId, response);
           
    }
         
    });
       
    } else {
         
    // The currently authenticated user's channel ID is not available.
          displayMessage
    ('The YouTube channel ID for the current user is not available.');
       
    }
     
    }

    取得可能なデータと、metricsdimensionsfilters パラメータの有効な値の組み合わせについて詳しくは、API ドキュメントの利用可能なレポート ページをご覧ください。

ステップ 5: アナリティクスのデータをグラフに表示する

このステップでは、YouTube アナリティクスのデータを Google Visualization API に送信する displayChart 関数を追加します。その API が情報をグラフに表示します。

  1. Google Visualization API を読み込み、データをグラフに表示します。グラフ表示オプションの詳細については、Visualization API のドキュメントをご覧ください。

    google.load('visualization', '1.0', {'packages': ['corechart']});
  2. Google Visualization API を使用してアナリティクス データを示すグラフを動的に生成する displayChart という名前の新しい関数を定義します。


     
    // Call the Google Chart Tools API to generate a chart of Analytics data.
     
    function displayChart(videoId, response) {
       
    if ('rows' in response) {
          hideMessage
    ();

         
    // The columnHeaders property contains an array of objects representing
         
    // each column's title -- e.g.: [{name:"day"},{name:"views"}]
         
    // We need these column titles as a simple array, so we call jQuery.map()
         
    // to get each element's "name" property and create a new array that only
         
    // contains those values.
         
    var columns = $.map(response.columnHeaders, function(item) {
           
    return item.name;
         
    });
         
    // The google.visualization.arrayToDataTable() function wants an array
         
    // of arrays. The first element is an array of column titles, calculated
         
    // above as "columns". The remaining elements are arrays that each
         
    // represent a row of data. Fortunately, response.rows is already in
         
    // this format, so it can just be concatenated.
         
    // See https://developers.google.com/chart/interactive/docs/datatables_dataviews#arraytodatatable
         
    var chartDataArray = [columns].concat(response.rows);
         
    var chartDataTable = google.visualization.arrayToDataTable(chartDataArray);

         
    var chart = new google.visualization.LineChart(document.getElementById('chart'));
          chart
    .draw(chartDataTable, {
           
    // Additional options can be set if desired as described at:
           
    // https://developers.google.com/chart/interactive/docs/reference#visdraw
            title
    : 'Views per Day of Video ' + videoId
         
    });
       
    } else {
          displayMessage
    ('No data available for video ' + videoId);
       
    }
     
    }

index.js ファイル全体を表示する

以下の index.js ファイルには、上記のステップで行った変更がすべて含まれています。なお、文字列 YOUR_CLIENT_ID は、登録済みのアプリのクライアント ID に置き換える必要があります。


(function() {
 
// Retrieve your client ID from the Google API Console at
 
// https://console.cloud.google.com/.
 
var OAUTH2_CLIENT_ID = 'YOUR_CLIENT_ID';
 
var OAUTH2_SCOPES = [
   
'https://www.googleapis.com/auth/yt-analytics.readonly',
   
'https://www.googleapis.com/auth/youtube.readonly'
 
];

 
var ONE_MONTH_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 30;

 
// Keep track of the currently authenticated user's YouTube channel ID.
 
var channelId;

 
// For information about the Google Chart Tools API, see:
 
// https://developers.google.com/chart/interactive/docs/quick_start
  google
.load('visualization', '1.0', {'packages': ['corechart']});

 
// Upon loading, the Google APIs JS client automatically invokes this callback.
 
// See https://developers.google.com/api-client-library/javascript/features/authentication
  window
.onJSClientLoad = function() {
    gapi
.auth.init(function() {
      window
.setTimeout(checkAuth, 1);
   
});
 
};

 
// Attempt the immediate OAuth 2.0 client flow as soon as the page loads.
 
// If the currently logged-in Google Account has previously authorized
 
// the client specified as the OAUTH2_CLIENT_ID, then the authorization
 
// succeeds with no user intervention. Otherwise, it fails and the
 
// user interface that prompts for authorization needs to display.
 
function checkAuth() {
    gapi
.auth.authorize({
      client_id
: OAUTH2_CLIENT_ID,
      scope
: OAUTH2_SCOPES,
      immediate
: true
   
}, handleAuthResult);
 
}

 
// Handle the result of a gapi.auth.authorize() call.
 
function handleAuthResult(authResult) {
   
if (authResult) {
     
// Authorization was successful. Hide authorization prompts and show
     
// content that should be visible after authorization succeeds.
      $
('.pre-auth').hide();
      $
('.post-auth').show();

      loadAPIClientInterfaces
();
   
} else {
     
// Authorization was unsuccessful. Show content related to prompting for
     
// authorization and hide content that should be visible if authorization
     
// succeeds.
      $
('.post-auth').hide();
      $
('.pre-auth').show();

     
// Make the #login-link clickable. Attempt a non-immediate OAuth 2.0
     
// client flow. The current function is called when that flow completes.
      $
('#login-link').click(function() {
        gapi
.auth.authorize({
          client_id
: OAUTH2_CLIENT_ID,
          scope
: OAUTH2_SCOPES,
          immediate
: false
       
}, handleAuthResult);
     
});
   
}
 
}

 
// Load the client interfaces for the YouTube Analytics and Data APIs, which
 
// are required to use the Google APIs JS client. More info is available at
 
// https://developers.google.com/api-client-library/javascript/dev/dev_jscript#loading-the-client-library-and-the-api
 
function loadAPIClientInterfaces() {
    gapi
.client.load('youtube', 'v3', function() {
      gapi
.client.load('youtubeAnalytics', 'v1', function() {
       
// After both client interfaces load, use the Data API to request
       
// information about the authenticated user's channel.
        getUserChannel
();
     
});
   
});
 
}

 
// Call the Data API to retrieve information about the currently
 
// authenticated user's YouTube channel.
 
function getUserChannel() {
   
// Also see: https://developers.google.com/youtube/v3/docs/channels/list
   
var request = gapi.client.youtube.channels.list({
     
// Setting the "mine" request parameter's value to "true" indicates that
     
// you want to retrieve the currently authenticated user's channel.
      mine
: true,
      part
: 'id,contentDetails'
   
});

    request
.execute(function(response) {
     
if ('error' in response) {
        displayMessage
(response.error.message);
     
} else {
       
// We need the channel's channel ID to make calls to the Analytics API.
       
// The channel ID value has the form "UCdLFeWKpkLhkguiMZUp8lWA".
        channelId
= response.items[0].id;
       
// Retrieve the playlist ID that uniquely identifies the playlist of
       
// videos uploaded to the authenticated user's channel. This value has
       
// the form "UUdLFeWKpkLhkguiMZUp8lWA".
       
var uploadsListId = response.items[0].contentDetails.relatedPlaylists.uploads;
       
// Use the playlist ID to retrieve the list of uploaded videos.
        getPlaylistItems
(uploadsListId);
     
}
   
});
 
}

 
// Call the Data API to retrieve the items in a particular playlist. In this
 
// example, we are retrieving a playlist of the currently authenticated user's
 
// uploaded videos. By default, the list returns the most recent videos first.
 
function getPlaylistItems(listId) {
   
// See https://developers.google.com/youtube/v3/docs/playlistitems/list
   
var request = gapi.client.youtube.playlistItems.list({
      playlistId
: listId,
      part
: 'snippet'
   
});

    request
.execute(function(response) {
     
if ('error' in response) {
        displayMessage
(response.error.message);
     
} else {
       
if ('items' in response) {
         
// The jQuery.map() function iterates through all of the items in
         
// the response and creates a new array that only contains the
         
// specific property we're looking for: videoId.
         
var videoIds = $.map(response.items, function(item) {
           
return item.snippet.resourceId.videoId;
         
});

         
// Now that we know the IDs of all the videos in the uploads list,
         
// we can retrieve information about each video.
          getVideoMetadata
(videoIds);
       
} else {
          displayMessage
('There are no videos in your channel.');
       
}
     
}
   
});
 
}

 
// Given an array of video IDs, this function obtains metadata about each
 
// video and then uses that metadata to display a list of videos.
 
function getVideoMetadata(videoIds) {
   
// https://developers.google.com/youtube/v3/docs/videos/list
   
var request = gapi.client.youtube.videos.list({
     
// The 'id' property's value is a comma-separated string of video IDs.
      id
: videoIds.join(','),
      part
: 'id,snippet,statistics'
   
});

    request
.execute(function(response) {
     
if ('error' in response) {
        displayMessage
(response.error.message);
     
} else {
       
// Get the jQuery wrapper for the #video-list element before starting
       
// the loop.
       
var videoList = $('#video-list');
        $
.each(response.items, function() {
         
// Exclude videos that do not have any views, since those videos
         
// will not have any interesting viewcount Analytics data.
         
if (this.statistics.viewCount == 0) {
           
return;
         
}

         
var title = this.snippet.title;
         
var videoId = this.id;

         
// Create a new <li> element that contains an <a> element.
         
// Set the <a> element's text content to the video's title, and
         
// add a click handler that will display Analytics data when invoked.
         
var liElement = $('<li>');
         
var aElement = $('<a>');
         
// Setting the href value to '#' ensures that the browser renders the
         
// <a> element as a clickable link.
          aElement
.attr('href', '#');
          aElement
.text(title);
          aElement
.click(function() {
            displayVideoAnalytics
(videoId);
         
});

         
// Call the jQuery.append() method to add the new <a> element to
         
// the <li> element, and the <li> element to the parent
         
// list, which is identified by the 'videoList' variable.
          liElement
.append(aElement);
          videoList
.append(liElement);
       
});

       
if (videoList.children().length == 0) {
         
// Display a message if the channel does not have any viewed videos.
          displayMessage
('Your channel does not have any videos that have been viewed.');
       
}
     
}
   
});
 
}

 
// This function requests YouTube Analytics data for a video and displays
 
// the results in a chart.
 
function displayVideoAnalytics(videoId) {
   
if (channelId) {
     
// To use a different date range, modify the ONE_MONTH_IN_MILLISECONDS
     
// variable to a different millisecond delta as desired.
     
var today = new Date();
     
var lastMonth = new Date(today.getTime() - ONE_MONTH_IN_MILLISECONDS);

     
var request = gapi.client.youtubeAnalytics.reports.query({
       
// The start-date and end-date parameters must be YYYY-MM-DD strings.
       
'start-date': formatDateString(lastMonth),
       
'end-date': formatDateString(today),
       
// At this time, you need to explicitly specify channel==channelId.
       
// See https://developers.google.com/youtube/analytics/v1/#ids
        ids
: 'channel==' + channelId,
        dimensions
: 'day',
        sort
: 'day',
       
// See https://developers.google.com/youtube/analytics/v1/available_reports
       
// for details about the different filters and metrics you can request
       
// if the "dimensions" parameter value is "day".
        metrics
: 'views',
        filters
: 'video==' + videoId
     
});

      request
.execute(function(response) {
       
// This function is called regardless of whether the request succeeds.
       
// The response contains YouTube Analytics data or an error message.
       
if ('error' in response) {
          displayMessage
(response.error.message);
       
} else {
          displayChart
(videoId, response);
       
}
     
});
   
} else {
     
// The currently authenticated user's channel ID is not available.
      displayMessage
('The YouTube channel ID for the current user is not available.');
   
}
 
}

 
// This boilerplate code takes a Date object and returns a YYYY-MM-DD string.
 
function formatDateString(date) {
   
var yyyy = date.getFullYear().toString();
   
var mm = padToTwoCharacters(date.getMonth() + 1);
   
var dd = padToTwoCharacters(date.getDate());

   
return yyyy + '-' + mm + '-' + dd;
 
}

 
// If number is a single digit, prepend a '0'. Otherwise, return the number
 
//  as a string.
 
function padToTwoCharacters(number) {
   
if (number < 10) {
     
return '0' + number;
   
} else {
     
return number.toString();
   
}
 
}

 
// Call the Google Chart Tools API to generate a chart of Analytics data.
 
function displayChart(videoId, response) {
   
if ('rows' in response) {
      hideMessage
();

     
// The columnHeaders property contains an array of objects representing
     
// each column's title -- e.g.: [{name:"day"},{name:"views"}]
     
// We need these column titles as a simple array, so we call jQuery.map()
     
// to get each element's "name" property and create a new array that only
     
// contains those values.
     
var columns = $.map(response.columnHeaders, function(item) {
       
return item.name;
     
});
     
// The google.visualization.arrayToDataTable() function wants an array
     
// of arrays. The first element is an array of column titles, calculated
     
// above as "columns". The remaining elements are arrays that each
     
// represent a row of data. Fortunately, response.rows is already in
     
// this format, so it can just be concatenated.
     
// See https://developers.google.com/chart/interactive/docs/datatables_dataviews#arraytodatatable
     
var chartDataArray = [columns].concat(response.rows);
     
var chartDataTable = google.visualization.arrayToDataTable(chartDataArray);

     
var chart = new google.visualization.LineChart(document.getElementById('chart'));
      chart
.draw(chartDataTable, {
       
// Additional options can be set if desired as described at:
       
// https://developers.google.com/chart/interactive/docs/reference#visdraw
        title
: 'Views per Day of Video ' + videoId
     
});
   
} else {
      displayMessage
('No data available for video ' + videoId);
   
}
 
}

 
// This helper method displays a message on the page.
 
function displayMessage(message) {
    $
('#message').text(message).show();
 
}

 
// This helper method hides a previously displayed message on the page.
 
function hideMessage() {
    $
('#message').hide();
 
}
})();