前回投稿したサンプルだと、PCブラウザやAndroid端末で動画が同時再生できてしまっていたので、
それはあまりよろしくないと思い、一部コードを修正いたしました。
APIキーが必要になりますので、下記リンクを参考に、APIキーを取得してください。
YouTube API APIキーの取得方法
- youtube_playlist
- sample2
- css :CSSファイル
- img :画像ファイル
- js :jsファイル
- lib :jsライブラリ(jQueryなど)
- index.js
- youtube_api_info.json
- index.html
- sample2
##主な変更点
前回は、再生リストのjsonを取得するのに$.ajax()
関数を使って取得していましたが、
jQuery依存度を少しでも低くしたかったので、Google純正のAPIであるAPI Client Library for JavaScript (Beta)を使って取得する方法に変更しました。
また、プレーヤーの動作状態を監視するために、プレーヤーの出力方法を<iframe>
からYouTube IFrame APIを使用する方法に変更しました。
##解説
###ライブラリ使用準備
YouTube IFrame APIを使用するためにindex.js
内に下記のコードを挿入し、APIを読み込みます。
// 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を読み込みます。
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
パラメータに?onload=javascript関数名
と記述すると、ライブラリファイルの読み込みが完了した直後に、指定した名前の関数が実行されます。
実行したい関数が読み込まれた後じゃないと、関数が見つからず、処理が実行されないため、別途実装した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()
関数に渡し、プレーヤーの読み込み処理を実行します。
###プレーヤーの埋め込み
/**
* 再生リストの情報から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()
関数が実行されるため、
この中で各プレーヤーの状態を確認し、直前に再生されていたプレーヤーの停止を行う処理を書きます。
###無限スクロール処理
$(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();
}
}
});
});
※前回からは、実行する関数名が変わったくらいで、処理自体に大きく変更はありません。
- スクロールをして、スクロール位置が下部5%の位置に来た時に、再び
addContent()
関数を実行し、DOMの追加処理を行います。
この時、loadingFlg=true
の時はDOMへ追加する処理を行いません。 - ページの読み込みを進めて、現在のページが最後のページになった時は、スクロール処理をunbindします。
##課題
GoogleのAPIを使用することで、ajax関連の処理をjQueryから切り離すことができた。
DOM追加やスクロール処理をReact.jsなどの別のライブラリでも書けるようにするのが今後の課題。