构建示例应用

本页将引导您完成构建应用的步骤,该应用使用多个不同的 API 来绘制用户 YouTube 视频的观看统计信息图表。该应用执行以下任务:

  • 该 activity 使用 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 步:请求视频的 Google Analytics 数据
  5. 第 5 步:在图表中显示 Google Analytics 数据

重要提示:您需要向 Google 注册您的应用,才能为您的应用获取 OAuth 2.0 客户端 ID。

第 1 步:构建 HTML 网页和 CSS 文件

在此步骤中,您将创建一个 HTML 网页,用于加载应用将使用的 JavaScript 库。以下 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),您可以轻松导入一个或多个 Google API。此示例应用使用 API 加载器加载 Google Visualization API,该 API 用于绘制检索到的 Google Analytics 数据的图表。
  • index.js 库包含特定于示例应用的函数。本教程将引导您完成创建这些函数的步骤。
  • 适用于 JavaScript 的 Google API 客户端库可帮助您实现 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 步:检索当前登录用户的数据

在此步骤中,您将向 index.js 文件添加一个函数,该函数使用 YouTube Data API (v2.0) 检索当前已登录用户上传的视频 Feed。该 Feed 将指定用户的 YouTube 频道 ID,您在调用 YouTube Analytics API 时需要使用该 ID。此外,示例应用还会列出用户上传的视频,以便用户检索任何单个视频的 Google Analytics 数据。

index.js 文件进行以下更改:

  1. 添加一个用于加载 YouTube Analytics 和 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 将发送到 Google Analytics API,以便确定您要为哪个渠道检索 Google Analytics 数据。


     
    // 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 函数,用于检索指定播放列表中的项。在这种情况下,播放列表会列出上传到用户频道的视频。(请注意,以下示例函数仅会检索该 Feed 中的前 50 项,您需要实现分页才能提取其他项。)

    检索播放列表项列表后,该函数会调用 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 数据分析数据

在此步骤中,您将修改示例应用,以便在您点击视频的标题时,应用会调用 YouTube Analytics API 来检索该视频的数据分析数据。为此,请对示例应用进行以下更改:

  1. 添加一个变量,用于指定检索的 Google Analytics 报告数据的默认日期范围。


     
    var ONE_MONTH_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 30;
  2. 添加代码,用于为日期对象创建 YYYY-MM-DD 字符串,并将日期中的日期和月份数字补充为两位数:


     
    // 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. 定义 displayVideoAnalytics 函数,用于检索视频的 YouTube 数据分析数据。当用户点击列表中的视频时,系统会执行此函数。getVideoMetadata 函数用于输出视频列表,并在第 3 步中进行了定义,该函数定义了点击事件处理脚本。


     
    // 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 步:在图表中显示 Google Analytics 数据

在此步骤中,您将添加 displayChart 函数,该函数会将 YouTube 数据分析数据发送到 Google Visualization API。然后,该 API 会将信息绘制成图表。

  1. 加载 Google Visualization API,该 API 会以图表的形式显示您的数据。如需详细了解图表选项,请参阅 Visualization API 文档

    google.load('visualization', '1.0', {'packages': ['corechart']});
  2. 定义一个名为 displayChart 的新函数,该函数使用 Google Visualization API 动态生成一个显示 Google Analytics 数据的图表。


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