XMLHttpRequest()
とプロキシ。その後、ドキュメントの後半で、サンプルコードについて詳しく説明します。最初の例では、 Analytics API Brightcoveプレーヤーのコントロールバーで、現在プレーヤーにあるビデオの再生回数を取得して表示します。2番目の、もう少し複雑な例では、 Analytics API Brightcove Playerカタログと組み合わせて、アカウントから最も人気のある動画を取得し、再生リストに表示します。このドキュメントのコードの説明は、正しいRESTAPIから目的のデータを取得することに重点を置いています。ハイレベルビュー
REST API を使用するには、いくつかの部分が必要です。簡単に言うと、それらは次のとおりです。
- クライアントコード :クライアントコードは、特定のデータを要求し、アプリケーションの要件に応じて表示します。クライアントコードは、あなたが最も頻繁に書く必要があるものであるため、このドキュメントでは、ある程度の長さで説明します。
- プロキシサーバー :セキュリティ上の理由から、REST API はクライアントからのデータリクエストを直接受け付けません。これは、クライアント資格情報などの機密情報をクライアントから送信することを奨励します。これは、プロキシがクライアントと REST API 間の仲介として機能することを意味します。例で使用されているプロキシは PHP で記述され、このドキュメントの後半で説明します。プロキシは、ユーザーの制御下にあるサーバー上でセットアップする必要があり、任意の言語で記述できます。プロキシの推奨設定により、一度書き込み、任意の API で使用することができます。
- REST API :Brightcoveは、Brightcove プラットフォームをカスタマイズ、拡張、統合するための包括的な API セットを提供しています。概要を参照してください。詳細については、ビデオクラウド API ドキュメントを参照してください。
次の図は、Brightcoveの REST API の 1 つからデータを取得するための、プロセスの 3 つのコアエンティティ間の相互作用を示しています。
クライアント機能の概要
クライアント側のコードは、データを要求している API に応じて大きく変化します。上記のように、プロキシは一度書き込みであり、コードの一部を変更しません。API は Brightcove によって維持されています。このため、ドキュメントでは、API の 1 つから目的のデータを取得するためにクライアントコードを変更する方法を学ぶことに重点が置かれます。
以下の図は、クライアントコードの主要な部分に焦点を当てています。
HTTPRequest
をプロキシにする関数。あいまいさを避けるため、makeRequest()
関数には名前が付けられます。それは下の図の右側に写真です。- 要求に必要な情報を収集するコード。これは、図の左上に写真されています。このコードは、通常、非常に単純であり、最初のプログラマにもよく知られている概念を使用しています。
makeRequest()
前述の関数を実行する呼び出し。これは、図の左下に写真されています。呼び出しは、makeRequest()
関数をパラメータとしてに渡します。その後、makeRequest()
その関数で呼び出されます。これは、匿名で定義されたコールバック関数の例です。
「非同期アクティビティ」という図に、2 つのセクションがあります。図では 2 つの異なる場所で表されていますが、これは実際には同じ非同期アクティビティであり、必要な不明な時間を表します。
- プロキシに要求を送信するクライアント。
- API からデータを要求するプロキシ。
- 結果セットを構築し、それをプロキシに戻すための API。
- データをクライアントに戻すプロキシ。
呼び出すボックスmakeRequest()
(左下のボックス)からの論理フロー矢印は、コードが2つの異なる時間に実行されていることを示しているように見えます。これはまさにそうです。関数の呼び出しは行われますが、コールバック関数は、がジョブを実行し、makeRequest()
コールバック関数が実行されるまで実行されません。コールバック関数は、要求されたデータを関数呼び出しコードに返します。
サンプルコードチュートリアル
コードを1つの部分として見るのではなく、それはセクションで説明され、議論されます。セクションの一部は、上の図に関連します。
標準的なプレーヤーコード
このコードセクションには、基本的な Brightcove Player インページ埋め込みコードが含まれています。
- 11-21行:
id
属性を追加した標準の Brightcove Player コード。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
</head>
<body>
<video-js id="myPlayerID"
data-video-id="3851380732001"
data-account="1752604059001"
data-player="HkAzSmB0l"
data-embed="default"
data-application-id
class="video-js"
controls
width="640"
height="360"></video-js>
<script src="https://players.brightcove.net/1752604059001/HkAzSmB0l_default/index.min.js"></script>
電話をかける準備中
このコードセクションは変数を初期化し、を呼び出す準備が整いますmakeRequest()
。一般的に、読取りリクエストの場合は、次の情報を提供する必要があります。
- たとえば、使用するプロキシへの URL (もちろん、これはあなたの制御下でプロキシである必要があります):
https://solutions.brightcove.com/bcls/bcls-proxy/doc-samples-proxy-v2.php
- 実際のリクエストに必要な URL。通常は動的に構築されます。
https://analytics.api.brightcove.com/v1/alltime/accounts/1752604059001/videos/4825279519001
- 例えば、HTTPメソッド
GET
。
例を次に示します。
- 1 行目:プレーヤーが対話する準備ができるまで待つ標準コード。
- 2-4行目:コードの後半で必要な変数の値を作成/設定します。
- 7~12行目は次のとおりです。
loadstart
mediainfo
オブジェクトが読み込まれるまでイベントを待ちます。に必要な値を保持する変数を割り当てますAnalytics API終点。 - 13行目:呼び出しの HTTP メソッドを設定します。
videojs.getPlayer('myPlayerID').ready(function() {
var myPlayer = this,
accountId = myPlayer.bcinfo.accountId,
options = {};
// +++ Wait for loadstart event so can use mediainfo object +++
myPlayer.on('loadstart', function() {
var videoId = myPlayer.mediainfo.id,
baseURL = 'https://analytics.api.brightcove.com/v1/alltime/accounts/',
endPoint = accountId + '/videos/' + videoId;
options.proxyURL = "https://solutions.brightcove.com/bcls/bcls-proxy/doc-samples-proxy-v2.php";
options.url = baseURL + endPoint;
options.requestType = "GET";
電話するmakeRequest()
このコードセクションでは、makeRequest()
関数の呼び出しを行います。2 つのパラメータが渡されることに注意してください。1 つ目はエンドポイントの情報を保持するオプションオブジェクトで、2 つ目はコールバック関数です。これは非同期呼び出しであるため、匿名で定義されたコールバック関数は、データがREST makeRequest()
APIによって関数に返されるまでは呼び出されません。
- 1 行目:
makeRequest()
関数を呼び出し、options
オブジェクト内の呼び出しに必要な値を渡します。この場合、オブジェクトには次のものが含まれます。 - 3~13行目:コールバック関数は、無名関数として定義されます (黄色で強調表示)。この関数はパラメータであり、ここでは呼び出されず、後でコード内で呼び出されることに注意してください。
- 6、8、10 行目:
console.log()
次のステートメントが表示されます。- API 呼び出しによって返される未処理の JSON 文字列。
JSON.parse()
文字列からオブジェクトへの変換を行うメソッドによって生成された JSON オブジェクト。- 実際のビューは、
object.property
単純な表記法を使用してオブジェクトから抽出されます。
- 12行目です:コントロールバーのビュー数を表示する関数を呼び出します。
コンソールからの次のスクリーンショットは、console.log
ステートメントから実際に表示されているデータを示しています。
// +++ Make the request to the Analytics API +++
// Extract views from data returned by Analytics API
makeRequest(options, function(viewsRaw) {
var viewsCount;
// Remove console.log command for production code
console.log('viewsRaw', viewsRaw);
viewsObject = JSON.parse(viewsRaw);
console.log('viewsObject', viewsObject);
viewsCount = viewsObject.alltime_video_views;
console.log('views', viewsCount);
// Call function to place data in controlbar
placeCountInControlbar(viewsCount);
});
makeRequest()
実際の関数
この文書のこのセクションでは、makeRequest()
関数を実際に定義するコードを調べます。関数を定義するコードは、変更する必要がないように書かれていますが、そのまま繰り返し使用されます。これは真実ではないというエッジケースを見つけるかもしれませんが、大部分の用途ではこのコードを変更する必要はありません。
コードの 1 行ごとの説明を次に示します。
- 1 ~ 6 行目:関数定義と変数の作成重要な点は、
XMLHttpRequest
新しいオブジェクトが作成されることです。 - 8行目、26行目:
readyState
変更のためのイベントハンドラ関数を定義します。 - 9、23、25 行目:要求が高レベルで失敗した場合は、を使用します。
try-catch
- 10、11 行目:
if
ステートメントを使用して、リクエストが完了し(readyState
4)、正常に完了し、ステータスが 200 の範囲内にあることを確認します。以下に、のコンソールログを示します。readyState
そしてstatus
イベントハンドラー定義の値: - 18行目線:コールバック関数が実行されます。上記の「 call makeRequest () 」セクションで説明したように、API から返されたデータをコールバック関数に渡します。
- 33行目です:イベントのイベントハンドラを設定します
XMLHttpRequest.onreadystatechange
。 - 35行目線:プロキシへの要求を初期化します。
- 38行目線:要求を送信します。これは非同期です。
function makeRequest(options, callback) {
var httpRequest = new XMLHttpRequest(),
response,
requestParams,
dataString,
proxyURL = options.proxyURL,
// response handler
getResponse = function() {
try {
if (httpRequest.readyState === 4) {
if (httpRequest.status >= 200 && httpRequest.status < 300) {
response = httpRequest.responseText;
// some API requests return '{null}' for empty responses - breaks JSON.parse
if (response === '{null}') {
response = null;
}
// return the response
callback(response);
} else {
alert('There was a problem with the request. Request returned ' + httpRequest.status);
}
}
} catch (e) {
alert('Caught Exception: ' + e);
}
};
/**
* set up request data
* the proxy used here takes the following request body:
* JSON.stringify(options)
*/
// set response handler
httpRequest.onreadystatechange = getResponse;
// open the request
httpRequest.open('POST', proxyURL);
// set headers if there is a set header line, remove it
// open and send request
httpRequest.send(JSON.stringify(options));
}
返されたデータを表示する
このコードは、返されたデータをコントロールバーに配置する方法を示します。この関数は、上記の call makeRequest () セクションに示すように、コールバック関数の最後に呼び出されます。
- 5、16 行目:関数を定義します。
- 6行目:
spacer
コントロールバーの要素の変数を作成します。 - 7行目:
div
要素を動的に作成します。 - 9行目:
div
新しく作成した要素に、ラベルとビューの値を配置します。 - 11行目:JavaScript
document.getElementsByClassName()
のメソッドを使用して、spacer
コントロールバーの要素を取得します。 - 13行目:
spacer
をスタイル設定すると、全体ビューが右揃えに表示され、の上から 10 ピクセル下に表示されますspacer
。 - 15行目です:新しく作成され、設定され、スタイル設定された要素をに追加します
spacer
。
/**
* Dynamically build a div that is then
* placed in the controlbar's spacer element
*/
function placeCountInControlbar(viewsCount) {
var spacer,
newElement = document.createElement('div');
//Place data in div
newElement.innerHTML = "Total Views: " + viewsCount;
//Get the spacer in the controlbar
spacer = document.getElementsByClassName('vjs-spacer')[0];
//Right justify content in the spacer and add top margin
spacer.setAttribute('style', 'justify-content: flex-end; margin-top: 10px');
//Add the dynamically built div to the spacer in the controlbar
spacer.appendChild(newElement);
}
完全なコードリスト
完全な機能するコードは、この GitHub リポジトリにあります: display-views-in-controlbar.html 。
簡単なデバッグ
ご覧のとおり、REST API を使用する際には、いくつかの部分があります。これは、アプリが正常に機能していないときに課題が発生する可能性があります。デバッグ開始はどこですか?
このセクションでは、いくつかの簡単な提案を行い、デバッグの冒険を開始するのに最適な場所です。次の 2 つのセクションでは、必要な最も基本的な情報、呼び出しを行うために渡されるもの、返される内容を確認する方法を紹介します。
通話オプションの確認
このドキュメントで説明するクライアントサイドコードは、基本的にプロキシで使用する正しいオプションを提供することと、実際の API に関するものです。したがって、オプションが正しいことを知ることは、コードの正しい機能に不可欠です。これを行う簡単な方法は、オブジェクトが使用されるoptions
関数に渡される直前に、makeRequest
オブジェクトをコンソールに記録することです。
オプションオブジェクトに何が含まれているかは、あなたがしようとしていることによって異なりますが、いくつかの基本は常にそこにあります。
- アカウント ID。これは、別のプロパティ、または API エンドポイント URL の一部にすることができます。
- プロキシへの URL。プロキシの保存場所によって異なります。
- HTTP メソッドのタイプ(
GET
、POST
など)PATCH
。 - API から実際のリクエストを行うためにプロキシによって使用される API エンドポイント URL。例は次のとおりです。
https://players.api.brightcove.com/v2/accounts/57838016001/players https://edge.api.brightcove.com/playback/v1/accounts/1752604059001/videos/5842800655001 https://analytics.api.brightcove.com/v1/alltime/accounts/1752604059001/videos/4093643993001
API リクエストによっては、オプションオブジェクトでその他のプロパティが必要になる場合があります。以下に、特定のアカウントのすべてのプレイヤーにリクエストを送信するためのオプションオブジェクトのログ記録時にコンソールに表示される内容の例を示します。
プレイヤーを更新するときに使用されるもう少し複雑なログオプションオブジェクトは次のとおりです。
返されたデータの表示
返される内容は、リクエストしたデータと、エラーが返されたかどうかによって異なります。しかし、返されたデータが何であっても、返されるデータを確認することが最も多いでしょう。これを行う簡単な方法は、response
makeRequest
関数を呼び出した直後に生データをコンソールに記録することです。
返されるものは、ほぼ無限の可能性がありますが、以下はいくつかの例です。最初の画面は、アカウント内のすべてのプレイヤーを尋ねたときの応答の開始を示します。
PATCH
HTTPメソッドを使用して、プレーヤーを更新した後の応答は次のとおりです。
最初の応答のデータのよりきれいにフォーマットされたビューは次のとおりです。
{
"id": "1OHQdsTAr",
"preview_url": "http://preview-players.brightcove.net/v2/accounts/.../master/index.html",
"preview_embed_in_page": "http://preview-players.brightcove.net/v2/accounts/.../master/in_page.embed",
"preview_embed_code": "<iframe src='//preview-players.brightcove.net/v2/accounts/.../master/index.html' ...></iframe>"
}
最後に、エラーが発生したときからの非常に貴重な応答がここにあります。この場合、アカウントは適切な資格情報なしで使用されています。
その他のトラブルシューティングのヒント
あなたが問題を抱えている場合は、ここで探すべきいくつかの他のものがあります。
- 応答を得ない
- 空の応答を得ているかどうかを確認するには、いくつかのことがあります。
- API リファレンスをチェックして、リクエストが応答を返すことを確認します。いくつかは、コンテンツのない201または204応答を返すだけです(特に、DELETE要求だけでなく)。このケースを処理するには、コードを調整する必要があります。
- ブラウザの Developer Tools の [ネットワーク] セクションをチェックして、プロキシへの正常な呼び出しを確認します (そのサーバーは一時的に利用できない可能性があります)。
- 応答が表示されますが、
JSON.parse()
試してみると例外が発生します。 - ここでいくつかの可能性:
- 前の項目を参照してください-空のスティングを解析しようとすると、JSON例外がスローされます
-
レスポンスを見て、JSON 文字列 (
{
または a で始まる[
) であることを確認します。リクエストがJSONを返さない場合がいくつかあります- Analytics APIたとえば、format
パラメータをcsv
またxlxs
。繰り返しますが、このようなリクエストを行う場合は、JSON以外のレスポンスを処理するようにコードを調整する必要があります。 - ほとんどの場合、API によって返されるエラーも JSON 形式ですが、エラーがプレーンテキストまたは HTML として返される例外がいくつかあります。
プロキシコード
前述のように、プロキシは選択した言語で記述できます。Brightcove API ドキュメントの例では、PHP で書かれたプロキシを使用しています。プロキシの実装は言語に依存するため、以下のPHPコードはこの文書では詳しく分析しません。
プロキシが提供する基本的な機能には、次のものが含まれている必要があります。
- クライアント要求を受け入れます。
- OAuth API から認証トークンを取得します。
- 認証トークンとデータリクエスト(エンドポイント)を目的の API に送信します。
- API からデータを受け取り返します。
- データをクライアントに送り返します。
<?php
/**
* proxy for Brightcove RESTful APIs
* gets an access token, makes the request, and returns the response
* Accessing:
* (note you should **always** access the proxy via HTTPS)
* Method: POST
* request body (accessed via php://input) is a JSON object with the following properties
*
* {string} url - the URL for the API request
* {string} [requestType=GET] - HTTP method for the request
* {string} [requestBody] - JSON data to be sent with write requests
* {string} [client_id] - OAuth2 client id with sufficient permissions for the request
* {string} [client_secret] - OAuth2 client secret with sufficient permissions for the request
*
* Example:
* {
* "url": "https://cms.api.brightcove.com/v1/accounts/57838016001/video",
* "requestType": "PATCH",
* "client_id": "0072bebf-0616-442c-84de-7215bb176061",
* "client_secret": "7M0vMete8vP_Dmb9oIRdUN1S5lrqTvgtVvdfsasd",
* "requestBody": "{\"description\":\"Updated video description\"}"
* }
*
* if client_id and client_secret are not included in the request, default values will be used
*
* @returns {string} $response - JSON response received from the API
*/
// security checks
// if you want to do some basic security checks, such as checking the origin of the
// the request against some white list, this would be a good place to do it
// CORS enablement and other headers
header("Access-Control-Allow-Origin: *");
header("Content-type: application/json");
header("X-Content-Type-Options: nosniff");
header("X-XSS-Protection");
// default account values
// if you work on one Brightcove account, put in the values below
// if you do not provide defaults, the client id, and client secret must
// be sent in the request body for each request
$default_client_id = 'YOUR_CLIENT_ID';
$default_client_secret = 'YOUR_CLIENT_SECRET';
// get request body
$requestData = json_decode(file_get_contents('php://input'));
// set up access token request
// check to see if client id and secret were passed with the request
// and if so, use them instead of defaults
if (isset($requestData->client_id)) {
$client_id = $requestData->client_id;
}
if (isset($requestData->client_secret)) {
$client_secret = $requestData->client_secret;
}
$auth_string = "{$client_id}:{$client_secret}";
// make the request to get an access token
$request = "https://oauth.brightcove.com/v4/access_token?grant_type=client_credentials";
$curl = curl_init($request);
curl_setopt($curl, CURLOPT_USERPWD, $auth_string);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-type: application/x-www-form-urlencoded',
));
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
$php_log = array(
"php_error_info" => $curl_info
);
$curl_error = curl_error($curl);
curl_close($curl);
// Check for errors
// it's useful to log as much info as possible for debugging
if ($response === FALSE) {
log_error($php_log, $curl_error);
}
// Decode the response and get access token
$responseData = json_decode($response, TRUE);
$access_token = $responseData["access_token"];
// get request type or default to GET
$method = "GET";
if ($requestData->requestType) {
$method = $requestData->requestType;
}
// get the URL and authorization info from the form data
$request = $requestData->url;
// check for a request body sent with the request
if (isset($requestData->requestBody)) {
$data = $requestData->requestBody;
}
$curl = curl_init($request);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
"Authorization: Bearer {$access_token}"
));
switch ($method)
{
case "POST":
curl_setopt($curl, CURLOPT_POST, TRUE);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "PUT":
// don't use CURLOPT_PUT; it is not reliable
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "PATCH":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
case "DELETE":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
if ($requestData->requestBody) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
break;
default:
// GET request, nothing to do;
}
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
$php_log = array(
"php_error_info" => $curl_info
);
$curl_error = curl_error($curl);
curl_close($curl);
// Check for errors and log them if any
// note that logging will fail unless
// the file log.txt exists in the same
// directory as the proxy and is writable
if ($response === FALSE) {
log_error($php_log, $curl_error);
}
function log_error($php_log, $curl_error) {
$logEntry = "\nError:\n". "\n".date("Y-m-d H:i:s"). " UTC \n" .$curl_error. "\n".json_encode($php_log, JSON_PRETTY_PRINT);
$logFileLocation = "log.txt";
$fileHandle = fopen($logFileLocation, 'a') or die("-1");
fwrite($fileHandle, $logEntry);
fclose($fileHandle);
echo "Error: there was a problem with your API call"+
die(json_encode($php_log, JSON_PRETTY_PRINT));
}
// return the response to the AJAX caller
echo $response;
?>
プロキシサーバーのコード全体が上に示されていますが、GitHub リポジトリにも配置されています。サンプルプロキシアプリは php フォルダにあります。
例2
この2番目の例は、前に詳述した例よりも複雑です。次の使用例は、再生リストのアカウントから最も人気のある 10 本の動画を表示します。コードの主なステップは次のとおりです。
- からのリクエストAnalytics APIアカウントで最も多く再生された10本の動画。このステップでは、コールバック関数を使用した非同期呼び出しが含まれます。
- 返されたからAnalytics APIデータ、ビデオIDのみを抽出し、それらを配列に配置します。ヘルパー関数は、返されたデータから ID を抽出するために書き込まれます。
- 配列内の ID のリストの各ビデオについて、完全なビデオオブジェクトを要求します。このステップでは、アレイをループし、
player.catalog.getVideo()
を使用してビデオオブジェクトを要求します。もちろん、これには、を使用した複数の非同期呼び出しが含まれますcatalog
。ヘルパー関数は、ID に基づいてビデオオブジェクトを取得し、オブジェクトを配列に配置するために記述されています。 - 再生リストが有効なプレーヤーのプレイリストにビデオオブジェクトの配列を配置します。
API の呼び出し方法に関する多くの概念と特定のコードに慣れているので、makeRequest()
関数を呼び出すコードのみが詳しく説明されています。
- 2行目:引数として、REST API 呼び出しの成功に必要なオプションと、匿名で定義されたコールバック関数 (黄色で強調表示) を渡す関数を呼び出します。
makeRequest()
これは上から身近に聞こえるはずです。非常に重要なのは、makeRequest()
呼び出される関数は、前の例で使用された関数とまったく同じ関数です。あなたのコードで同じことをすることができます。makeRequest()
この関数は、Brightcove REST API の呼び出しで再利用されるように記述されています。 - 3行目:JSON 解析された返されたデータを保持する変数を作成します。
- 5行目:返されたデータを解析して、文字列からオブジェクトへの変換を行います。
- 7行目:ヘルパー関数を使用して、返されたデータからビデオ ID を抽出します。残念ながら、 Analytics API完全なビデオオブジェクトを返さないため、完全なオブジェクトにアクセスするにはIDが必要です。
- 9~12行目は次のとおりです。を呼び出す
getVideoData
コールバック関数を使用してデータを入力するヘルパー関数videoObjects
渡されたIDに基づく配列。 - 11行目:再生リストにビデオオブジェクトの配列を入力します。
// +++ Make the CMS API request to get matching video IDs +++
makeRequest(options, function(mostWatchedVideos) {
var JSONmostWatchedVideos;
// Convert response string into JSON
JSONmostWatchedVideos = JSON.parse(mostWatchedVideos);
// Extract the needed video IDs into an array
videoData = extractVideoData(JSONmostWatchedVideos);
// Get video objects based on array of video IDs
getVideoData(videoData, function(videoObjects) {
// Add the most watched videos list to the player as a playlist
myPlayer.playlist(videoObjects);
});
});
完全なコードリスト
完全な機能例は、この CodePen にあります。プレイリストのほとんどの視聴動画。