LoginSignup
26
28

More than 3 years have passed since last update.

YouTubeの再生リストを取得してjsで出力するサンプル(YouTube API活用編)

Last updated at Posted at 2016-01-20

前回投稿したサンプルだと、PCブラウザやAndroid端末で動画が同時再生できてしまっていたので、
それはあまりよろしくないと思い、一部コードを修正いたしました。

APIキーが必要になりますので、下記リンクを参考に、APIキーを取得してください。
YouTube API APIキーの取得方法

サンプルファイル

デモ
デモファイルDL

主な変更点

前回は、再生リストのjsonを取得するのに$.ajax()関数を使って取得していましたが、
jQuery依存度を少しでも低くしたかったので、Google純正のAPIであるAPI Client Library for JavaScript (Beta)を使って取得する方法に変更しました。
また、プレーヤーの動作状態を監視するために、プレーヤーの出力方法を<iframe>からYouTube IFrame APIを使用する方法に変更しました。

解説

ライブラリ使用準備

YouTube IFrame APIを使用するためにindex.js内に下記のコードを挿入し、APIを読み込みます。

index.js
// YouTube iframeAPIを読み込む
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

API Client Libraryを使用するために、index.htmlに下記のコードを挿入し、APIを読み込みます。

index.html
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>

パラメータに?onload=javascript関数名と記述すると、ライブラリファイルの読み込みが完了した直後に、指定した名前の関数が実行されます。
実行したい関数が読み込まれた後じゃないと、関数が見つからず、処理が実行されないため、別途実装したjsファイルは、ライブラリファイルよりも手前で読み込むようにしてください。

再生リストの取得

index.js
/*===================================
 YouTube Data API setting
===================================*/
var pageToken;

//YouTube Data APIに送るパラメータ
var apiOptions = {
  part:'snippet',
  playlistId:'',
  maxResults:REQ_QTY,
  pageToken:''
};

//clientライブラリを使う時に必要なパラメータ
var requestParam = {
  mine:false,
  path:'/youtube/v3/playlistItems',
  params:apiOptions
}

/**
 * google clientライブラリが読み込まれた直後に呼ばれる関数
 * APIキー等の情報を取得し、YouTube Data APIに再生リスト取得のリクエストを送る
 */
function googleApiClientReady(){
  //console.log('googleApiClientReady');
  getJsonData(YT_API_JSON_INFO_URL)
    .then(function(_jsonData){
    apiOptions.playlistId = _jsonData.listId;

    gapi.client.setApiKey(_jsonData.apiKey);
    gapi.client.load('youtube', 'v3', YTApiRequest);
  });
}

/**
 * YouTube Data APIを使って再生リストを取得する
 */
function YTApiRequest(){
  loadingFlg = true;
  if(pageToken){
    apiOptions.pageToken = pageToken;
  }

  var request=gapi.client.request(requestParam);

  request.execute(function(_res) {
    if(_res.error){ //エラーの時
      console.log('error!!!');
    }else{  //リクエスト成功の時
      totalResults = _res.pageInfo.totalResults;
      totalPage = Math.ceil(totalResults / REQ_QTY);
      addContent(_res);
      loadingFlg = false;
    }
  });
}

/**
 * jsonのデータを取得する
 * @param {String} JSONデータのURL
 * @return {$.Deferred}
 */
function getJsonData(_url){
  console.log('getJsonData()開始:'+_url);
  var $dfd = $.Deferred();
  $.ajax({
    url:_url,
    dataType:'json',
    cache:false,
    timeout:15000
  })
    .done(function(_data){
    console.log('json取得成功:'+_url);
    $dfd.resolve(_data);
  })
    .fail(function(_data){
    console.log('json取得error:'+_url);
    $dfd.reject(_data);
  })
    .always(function(_data){
    console.log('getJsonData()終了:'+_url);
  });
  return $dfd.promise();
}

API Client Libraryが読み込まれた直後にgoogleApiClientReady()が呼び出されるので、
googleApiClientReady()内のgetJsonData()関数で、APIキーや再生リストのIDなど、別途jsonファイルに持たせていた情報を取得し、
YouTube Data APIのパラメータとして値をセットします。

gapi.client.setApiKey(_jsonData.apiKey);
gapi.client.load('youtube', 'v3', YTApiRequest);

上記1行目でAPIキーをセットし、
2行目の第1、第2引数でインポートするライブラリファイルを指定(この場合、youtube Data apiのバージョン3を指定)。
第3引数でライブラリ読み込み完了時にコールバックされる関数を指定します。

/**
 * YouTube Data APIを使って再生リストを取得する
 */
function YTApiRequest(){
  loadingFlg = true;
  if(pageToken){
    apiOptions.pageToken = pageToken;
  }

  var request=gapi.client.request(requestParam);

  request.execute(function(_res) {
    if(_res.error){ //エラーの時
      console.log('error!!!');
    }else{  //リクエスト成功の時
      addContent(_res);
      loadingFlg = false;
    }
  });
}

YTApiRequest()関数を実行してリクエストに成功すると、リクエストで取得した情報をaddContent()関数に渡し、プレーヤーの読み込み処理を実行します。

プレーヤーの埋め込み

index.js
/**
 * 再生リストの情報からDOMにコンテンツを追加する
 * @param {Object} _jsonData youtubeの再生リストのjsonデータ
 */
function addContent(_jsonData){
  pageToken = _jsonData.nextPageToken != undefined ? _jsonData.nextPageToken : '';
  var insHtmlTag = '';

  for(var i = 0; i < _jsonData.items.length; i++){
    var videoId = _jsonData.items[i].snippet.resourceId.videoId;
    var videoCount = videoIdList.length;
    insHtmlTag = 
      '<article>' +
      '<div class="videoPlayer">' +
      '<div id="' + videoId + '"></div>' +
      '</div>' +
      '<dl>' +
      '<dt class="videoTitle">' +_jsonData.items[i].snippet.title + '</dt>' +
      '<dd class="videoDesc">' + _jsonData.items[i].snippet.description + '</dd>' +
      '</dl>' +
      '</article>';
    $('#videoContainer').append(insHtmlTag);

    ytPlayer[videoCount] = new YT.Player(videoId, {
      height: ytHeight,
      width: ytWidth,
      videoId: videoId,
      events: {
        'onReady' : onPlayerReady,
        'onStateChange': onPlayerStateChange
      }
    });
    videoIdList.push(videoIdList)
  }
  currentPage++;
}

上記のaddContent()関数で、取得した再生リストのjsonをパースして、HTMLタグを生成します。
関数内の下記の部分でYouTube IFrame APIから動画プレーヤーの埋め込みを行っています。

動画のIDはプレーヤーの状態監視のために使用するため、別途配列に格納しておきます。

ytPlayer[videoCount] = new YT.Player('YouTube動画のID', {
  height: '動画の高さ(数値)',
  width: '動画の幅(数値)',
  videoId: 'YouTube動画のID',
  events: {
    'onReady' :'プレーヤー読み込み直後に呼ばれる関数',
    'onStateChange': 'プレーヤーの状態が変更になった時に呼ばれる関数(再生・停止等)'
  }
});
videoIdList.push(videoIdList);  //プレーヤーの状態監視用にIDを配列に格納する

プレーヤーの状態監視

前回は、プレーヤーを複数クリックすると、動画が同時再生していました。
同時再生をさせないために、プレーヤーの状態を監視する処理を加えます。

/**
 * プレーヤーの状態に変化があった時に実行
 */
function onPlayerStateChange(event) {
  // 各プレーヤーの状態を確認
  for(var i = 0; i < videoIdList.length; i++) {
    var thisState = ytPlayer[i].getPlayerState();
    if( thisState == 1 && ytPlaying == undefined) {
      ytPlaying = i;
    } else if(thisState == 1 && ytPlaying != i) {
      ytStop = ytPlaying;
      ytPlay = i;
    } else {
    }
  }
  // 同時再生があった場合、元々再生していた方を停止する
  if(ytStop != undefined) {
    ytPlayer[ytStop].pauseVideo();
    ytStop = undefined;
  }
  // 現在再生中のプレーヤー番号を保存しておく
  if(ytPlay != undefined) {
    ytPlaying = ytPlay;
    ytPlay = undefined;
  }
}

プレーヤーの状態が変更になると、onPlayerStateChange()関数が実行されるため、
この中で各プレーヤーの状態を確認し、直前に再生されていたプレーヤーの停止を行う処理を書きます。

無限スクロール処理

index.js
$(function(){
  $(window).bind('scroll', function(e) {
    if(currentPage == totalPage){
      $(window).unbind('scroll');
      return;
    }
    scrollHeight = $(document).height();
    scrollPosition = $(window).height() + $(window).scrollTop();
    if ((scrollHeight - scrollPosition) / scrollHeight <= 0.05){
      //スクロールの位置が下部5%の範囲に来た場合
      if(!loadingFlg){
        YTApiRequest();
      }
    }
  });
});

※前回からは、実行する関数名が変わったくらいで、処理自体に大きく変更はありません。

  1. スクロールをして、スクロール位置が下部5%の位置に来た時に、再びaddContent()関数を実行し、DOMの追加処理を行います。 この時、loadingFlg=trueの時はDOMへ追加する処理を行いません。
  2. ページの読み込みを進めて、現在のページが最後のページになった時は、スクロール処理をunbindします。

課題

GoogleのAPIを使用することで、ajax関連の処理をjQueryから切り離すことができた。
DOM追加やスクロール処理をReact.jsなどの別のライブラリでも書けるようにするのが今後の課題。

26
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
28