สร้างแอปพลิเคชันตัวอย่าง

หน้านี้จะอธิบายถึงขั้นตอนการสร้างแอปพลิเคชันที่ใช้ 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: ขอข้อมูล Analytics สําหรับวิดีโอ
  5. ขั้นตอนที่ 5: แสดงข้อมูล Analytics ในแผนภูมิ

สำคัญ: คุณต้องลงทะเบียนแอปพลิเคชันกับ Google เพื่อรับรหัสไคลเอ็นต์ OAuth 2.0 สําหรับแอปพลิเคชัน

ขั้นตอนที่ 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 อย่างน้อย 1 รายการได้อย่างง่ายดาย แอปพลิเคชันตัวอย่างนี้ใช้โปรแกรมโหลด API เพื่อโหลด Google Visualization API ซึ่งใช้ในการสร้างแผนภูมิจากข้อมูล Analytics ที่ดึงมา
  • คลัง index.js มีฟังก์ชันเฉพาะสำหรับแอปพลิเคชันตัวอย่าง บทแนะนํานี้จะอธิบายขั้นตอนการสร้างฟังก์ชันเหล่านั้น
  • ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ 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

ในขั้นตอนนี้ คุณจะเริ่มสร้างไฟล์ index.js ที่หน้า HTML เรียกใช้ ด้วยเหตุนี้ ให้สร้างไฟล์ชื่อ index.js ในไดเรกทอรีเดียวกับหน้า HTML แล้วแทรกโค้ดต่อไปนี้ในไฟล์นั้น แทนที่สตริง YOUR_CLIENT_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 ของผู้ใช้ ซึ่งคุณต้องใช้เมื่อเรียกใช้ YouTube Analytics API นอกจากนี้ แอปตัวอย่างจะแสดงวิดีโอที่ผู้ใช้อัปโหลดเพื่อให้ผู้ใช้เรียกข้อมูล Analytics ของวิดีโอแต่ละรายการได้

ทำการเปลี่ยนแปลงต่อไปนี้ในไฟล์ index.js

  1. เพิ่มฟังก์ชันที่โหลดอินเทอร์เฟซไคลเอ็นต์สําหรับ YouTube Analytics และ Data API ขั้นตอนนี้เป็นข้อกําหนดเบื้องต้นในการใช้ไคลเอ็นต์ JavaScript ของ Google APIs

    เมื่อโหลดอินเทอร์เฟซไคลเอ็นต์ API ทั้ง 2 รายการแล้ว ฟังก์ชันนี้จะเรียกใช้ฟังก์ชัน 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 สําหรับออบเจ็กต์วันที่ และเพิ่มตัวเลขวันและเดือนในวันที่เป็น 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. กำหนดฟังก์ชัน displayVideoAnalytics ซึ่งดึงข้อมูล YouTube Analytics ของวิดีโอ ฟังก์ชันนี้จะทำงานเมื่อผู้ใช้คลิกวิดีโอในรายการ ฟังก์ชัน 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.');
        }
      }

    ดูหน้ารายงานที่ใช้ได้ในเอกสารประกอบของ API เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อมูลที่สามารถดึงมาและชุดค่าผสมของค่าที่ถูกต้องสำหรับพารามิเตอร์ metrics, dimensions และ filters

ขั้นตอนที่ 5: แสดงข้อมูล Analytics ในแผนภูมิ

ในขั้นตอนนี้ คุณจะเพิ่มฟังก์ชัน displayChart ซึ่งจะส่งข้อมูลวิเคราะห์ YouTube ไปยัง Google Visualization API จากนั้น API ดังกล่าวจะสร้างแผนภูมิข้อมูล

  1. โหลด Google Visualization API ซึ่งจะแสดงข้อมูลของคุณในแผนภูมิ ดูรายละเอียดเพิ่มเติมเกี่ยวกับตัวเลือกแผนภูมิได้ในเอกสารประกอบของ Visualisation 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 ด้วยรหัสไคลเอ็นต์สำหรับแอปพลิเคชันที่ลงทะเบียนของคุณ

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