建構範例應用程式

本頁面將逐步說明如何建構應用程式,使用多種不同的 API 繪製使用者 YouTube 影片的觀看統計資料圖表。應用程式會執行下列工作:

  • 這項 API 會使用 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:要求影片的 Analytics 資料
  5. 步驟 5:在圖表中顯示 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,用於繪製擷取的 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) 擷取目前登入使用者上傳的影片動態消息。該動態饋給會指定使用者的 YouTube 頻道 ID,您在呼叫 YouTube Analytics API 時需要使用這項資訊。此外,範例應用程式會列出使用者上傳的影片,方便使用者擷取個別影片的 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 會傳送至 Analytics API,用於識別您要擷取 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 函式,用於擷取指定播放清單中的項目。在這種情況下,播放清單會列出上傳至使用者頻道的影片。(請注意,下方範例函式只會擷取動態饋給中前 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:要求影片的 Analytics 資料

在這個步驟中,您將修改範例應用程式,讓應用程式在您點選影片標題時,呼叫 YouTube Analytics API 來擷取該影片的 Analytics 資料。如要這樣做,請對範例應用程式進行下列變更:

  1. 新增變數,指定擷取的 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:在圖表中顯示 Analytics 資料

在這個步驟中,您將新增 displayChart 函式,該函式會將 YouTube Analytics 資料傳送至 Google Visualization API。該 API 會將資訊製成圖表。

  1. 載入 Google Visualization API,以便在圖表中顯示資料。如要進一步瞭解圖表選項,請參閱 Visualization API 說明文件

    google.load('visualization', '1.0', {'packages': ['corechart']});
  2. 定義名為 displayChart 的新函式,使用 Google Visualization API 以動態方式產生顯示 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();
 
}
})();