WebOS Goodies

WebOS の未来を模索する、ゲームプログラマあがりの Web 開発者のブログ。

WebOS Goodies へようこそ! WebOS はインターネットの未来形。あらゆる Web サイトが繋がり、共有し、協力して創り上げる、ひとつの巨大な情報システムです。そこでは、あらゆる情報がネットワーク上に蓄積され、我々はいつでも、どこからでも、多彩なデバイスを使ってそれらにアクセスできます。 WebOS Goodies は、さまざまな情報提供やツール開発を通して、そんな世界の実現に少しでも貢献するべく活動していきます。
Subscribe       

oEmbed でメディア共有サイトのコンテンツを簡単埋め込み

先日、 YouTube API Blog に oEmbed によるコンテンツの埋め込み方法が説明されていました。 oEmbed とは初耳だったので仕様書を読んでみると、どうやらメディア共有サイトがコンテンツの埋め込みコードをサードパーティーの Web アプリケーションに提供するための API のようです。 API のエンドポイントにコンテンツの URL を渡すと、それを埋め込むための HTML コードやメタデータを XML もしくは JSON 形式で返してくれるという具合。

使い方としては、例えば Twitter クライアントでメッセージ中に画像・動画コンテンツの URL があったときに、それを自動的にインライン表示するときに便利そうです。 oEmbed を使うと YouTube だけでなく Flickr, Hulu, My Opera など多数のサイトに同じコードで対応できるのが嬉しいです。

それでは、以下で詳しい使い方をご紹介します。

概要

oEmbed の使い方は簡単。例えば YouTube の場合なら、以下のような URL に HTTP リクエストを投げます。

http://www.youtube.com/oembed?url=http%3A//www.youtube.com/watch%3Fv%3DbDOYN-6gdRE&format=json

すると、以下のように JSON 形式のレスポンスが返ります(読みやすいように整形してあります)。

{
  "provider_url": "http://www.youtube.com/",
  "title": "Auto-Tune the News #8: dragons. geese. Michael Vick. (ft. T-Pain)",
  "html": "<object width=\"425\" height=\"344\"><param name=\"movie\" value=\"http://www.youtube.com/v/bDOYN-6gdRE&fs=1\"></param><param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param><embed src=\"http://www.youtube.com/v/bDOYN-6gdRE&fs=1\" type=\"application/x-shockwave-flash\" width=\"425\" height=\"344\" allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed></object>",
  "author_name": "schmoyoho",
  "height": 344,
  "width": 425,
  "version": "1.0",
  "author_url": "http://www.youtube.com/user/schmoyoho",
  "provider_name": "YouTube",
  "type": "video"
}

あとは、これを解析して html フィールドの値をページに挿入してやれば、その場所に指定した動画が表示されます。

詳細

YouTube に関しては上記の使い方でほとんどすべてなのですが、他のサイトに対応する方法やリクエスト時のオプションなどをもう少し詳しくご紹介します。

API エンドポイント

oEmbed の機能を呼び出すためのリクエスト URL (API エンドポイント)は、各対応サイトごとに異なっています。それらは、仕様書のセクション 7.1「Providers」にリストアップされています。だいたい以下のような感じで書いてありますが、

Flickr (http://www.flickr.com/)
  ・URL scheme: http://*.flickr.com/* 
  ・API endpoint: http://www.flickr.com/services/oembed/ 
  ・Example: http://flickr.com/services/oembed?url=http%3A//flickr.com/photos/bees/2362225867/

この「API endpoint」が oEmbed リクエストのベース URL になります。これに url など必要なパラメータを付加してリクエストすることで、前述のような情報が得られるわけです。

なお、サイトの中には、以下のような API エンドポイントを持つものがあります。

http://qik.com/api/oembed.{format}

このような API エンドポイントは、 {format} の部分を後述の URL パラメータ「format」の値で置き換えてください。この場合、 URL パラメータの format は無視されます。

URL パラメータ

リクエスト URL に付加できる URL パラメータには以下のものがあります。

url (必須)
表示するコンテンツの URL を指定します。
maxwidth (省略可)
埋め込みコンテンツの最大の横幅を指定します。
maxheight (省略可)
埋め込みコンテンツの最大の高さを指定します。
format (省略可)
レスポンスの形式を xml, json のいずれかで指定します。残念ながら JSONP サポートは標準ではなく、サイトごとに対応が異なります。

maxwidth, maxheight は無視するサイトもあるようなので気をつけてください(^^;。また、これらのパラメータを渡すときは、値を URL エンコードするのを忘れないでください。

URL スキーム

仕様書の 7.1 セクションに示されているデータで、もうひとつ重要なのが「URL scheme」です。これは「埋め込み可能な URL の形式」を指定するもので、以下のようにワイルドカードのアスタリスクを含む URL で示されます。

http://*.flickr.com/*

仕様ではアスタリスクの意味が明確に定義されていませんが、サブドメイン部分にあるものは正規表現で [^/?&#]+ 、パスにあるものは .+ で考えると良いかと思います。従って、上記のスキームを判定する正規表現は以下のような感じでよろしいかと思います(URL としての有効性は既に検証されていると仮定しています)。

http\:\/\/[^\/?&#]+\.flickr\.com\/.+

URL が上記の正規表現にマッチしたら、 oEmbed のリクエストを送って埋め込みコードを取得できる(かもしれない)というわけです。 URL スキームが明示されていないプロバイダもあるのが困りものですが、その場合は Example の URL などから勝手に推測するしかないでしょう。

レスポンス

前述のとおり、レスポンスには XML 形式と JSON 形式がありますが、いずれも非常にシンプルです。 JSON 形式は先の例で示しましたが、オブジェクトの中に各フィールドが単純に並んでいるだけです。 XML 形式もほぼ同様で、ルート要素 <oembed> の中に各フィールドがタグとして記述されます。

<oembed>
  <provider_url>http://www.youtube.com/</provider_url>
  <title>Auto-Tune the News #8: dragons. geese. Michael Vick. (ft. T-Pain)</title>
  <html>&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/bDOYN-6gdRE&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/bDOYN-6gdRE&amp;fs=1" type="application/x-shockwave-flash" width="425" height="344" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;&lt;/object&gt;</html>
  <author_name>schmoyoho</author_name>
  <height>344</height>
  <width>425</width>
  <version>1.0</version>
  <author_url>http://www.youtube.com/user/schmoyoho</author_url>
  <provider_name>YouTube</provider_name>
  <type>video</type>
</oembed>

どのようなフィールドが存在するかはリソース・タイプによって異なるので、以降で列挙します。

共通レスポンス・フィールド

リソース・タイプによらず共通で返されるフィールドには以下のものがあります。ただし(省略可)になっているものは実際に省略されている場合が多いので注意してください。

type (必須)
リソース・タイプを表す文字列です。 photo, video, link, rich のいずれかです。
version (必須)
バージョン番号。現在は "1.0" でなければなりません。
title (省略可)
タイトル文字列。
author_name (省略可)
リソースの著者・所有者の名前。
author_url (省略可)
リソースの著者・所有者の URL 。プロフィールページの URL などが指定されている場合が多いようです。
provider_name (省略可)
プロバイダ(API を提供しているサイト)の名前
provider_url (省略可)
プロバイダの URL
cache_age (省略可)
プロバイダが推奨するキャッシュのライフタイムの秒数です。コンシューマ(API を利用するアプリケーション)がこれを採用するかどうかは自由です。
thumbnail_url (省略可)
サムネイル画像の URL です。
thumbnail_width (省略可)
サムネイルの横幅です。 thumbnail_url が指定されている場合は、このフィールドも必ず指定されます。
thumbnail_height (省略可)
サムネイルの高さです。 thumbnail_url が指定されている場合は、このフィールドも必ず指定されます。

これらに加えて、リソース・タイプごとに追加のフィールドがあります。

photo タイプの追加フィールド

type フィールドが "photo" の場合、コンテンツは静止画像です。この場合、リクエストには HTML コードの代わりに画像 URL が指定されますので、コンシューマは自分で img タグを生成して、そこに URL を設定しなければなりません。

url (必須)
画像の URL です。 img タグの src 属性に指定することで、画像を表示できます。
width (必須)
画像の横ピクセル数です。
height (必須)
画像の縦ピクセル数です。

video タイプの追加フィールド

type フィールドが "video" の場合、コンテンツは動画です。 html フィールドに指定された HTML コードをページに埋め込むことで、動画が表示できます。

html (必須)
動画を表示するための HTML コードです。
width (必須)
動画を表示するのに必要な横ピクセル数です。
height (必須)
動画を表示するのに必要な縦ピクセル数です。

link タイプ

type フィールドが "link" の場合、埋め込みコンテンツは提供されません。その変わり、コンシューマはオリジナルの URL と title, author_name フィールドの文字列などを使って、コンテンツへのリンクを表示できます。

例えば My Opera では、ユーザーのアルバム URL を指定するとこのタイプを返します。そして、 "images" というフィールドを(勝手に?)追加して、アルバムの各画像の URL を渡してきます。この使い方は正しいのだろうか・・・(^^;

rich タイプの追加フィールド

上記のいずれのタイプでもない場合、この "rich" タイプが使用されます。おそらく PDF や音声などの埋め込みを想定しているのだと思います。 html フィールドに指定された HTML コードをページに埋め込むことで、動画が表示できます。

html (必須)
コンテンツを表示するための HTML コードです。 XHTML 1.0 Basic に準拠しています。
width (必須)
コンテンツを表示するのに必要な横ピクセル数です。
height (必須)
コンテンツを表示するのに必要な縦ピクセル数です。

エラーコード

oEmbed のリクエストが不正だった場合、以下のエラーコードが返ります。

404 Not Found
埋め込みを行うコンテンツが存在しない。
501 Not Implemented
format パラメータで指定された形式がサポートされていない。
401 Unauthorized
指定されたコンテンツが公開されていない。この場合、コンシューマは元のリンクを表示するのが良いようです。

ただ、例えば YouTube はすべてのエラーに対して 401 を返すようなので、あまり厳密に処理しても意味がないかもしれません。

セキュリティーに関して

プロバイダからの XSS 攻撃を防止するため、とくに HTML コードで渡される埋め込みコンテンツを表示する際は、別ドメインの iframe 内で行うことが推奨されています。 YouTube や Flickr などの信頼できるプロバイダのみに絞る場合は大丈夫でしょうが、任意のプロバイダを許可する場合は気をつけてください。

また、 URL の形式で渡されるコンテンツに関しても、 http, https, mailto 以外ははじくようにしてください。

使ってみる

さて、使い方がわかったところでさっそく試してみようと思ったのですが、多数のサイトにきちんと対応しようと思うと URL スキームとエンドポイントの対応表を持って判定する必要があり、ちょっとソースが長くなってしまいます。また JSONP への対応もまちまちなので、 JavaScript のみでの実装も困難。

なにか良い方法はないかと思っていたら、良いサービスを見つけました。仕様書のセクション 7.1 にも掲載されている oohEmbed というサービスなのですが、 YouTube, Flickr, Amazon, Wikipedia など多数のサービスの埋め込みコードを oEmbed の形式で返してくれます。さらに JSONP にも対応しているので、 JavaScript のみでも利用可能です。

ということで、適当に作ってみたのが以下のフォームです。 oohEmbed が対応しているサービスの URL を入力すると、フォームの下にそれを埋め込んで表示します。ぜひ実際に試してみてください(IE6, 7 では動作確認していませんので、動かなかったらご勘弁を)。

リソース・タイプは photo, video, rich に対応していますが、 link タイプは oohEmbed 対応サービスでそれを返すものが見つからなかったので省略しています。また、前述のセキュリティー対策も講じていません。このあたりはあくまでサンプルということでご勘弁を。

ソースは以下です。

<script type="text/javascript">
function oembedResponse(response) {
  var container = document.getElementById('container');
  switch(response.type) {
  case "photo":
    var img = document.createElement('IMG');
    img.src = response.url;
    container.innerHTML = '';
    container.appendChild(img);
    break;
  case "video":
  case "rich":
    container.innerHTML = response.html;
    break;
  default:
    container.innterHTML = "埋め込みコンテンツがありません";
    break;
  }
}

function oembedRequest(event) {
  var endpoint = 'http://oohembed.com/oohembed/?callback=oembedResponse&maxwidth=320&maxheight=240';
  var escapedUrl = window.encodeURIComponent(document.getElementById('url').value);
  var script = document.createElement('SCRIPT');
  script.type = 'text/javascript';
  script.src = endpoint + '&url=' + escapedUrl;
  document.body.appendChild(script);

  event = event || window.event;
  event.preventDefault  && event.preventDefault();
  event.returnValue  = false;
}
</script>

<form onsubmit="oembedRequest(event);">
  <input id="url" type="text" style="width:400px;" value="http://www.youtube.com/watch?v=l6axhGSTFDs">
  <input type="submit" value="表示">
</form>
<div id="container"></div>

いろいろと手抜きをしているとはいえ、これだけのコードで多数のコンテンツの埋め込みに対応できるのは素晴らしいのではないでしょうか。

oEmbed 用のライブラリ

oEmbed を各種言語から利用するためのライブラリもいろいろ開発されているようです。仕様書のセクション 7.3 には、 PHP, Perl, Ruby, Python のクライアント・ライブラリが紹介されています。

また、 JavaScript では jquery-oembed という jQuery プラグインがあります。こちらも一部のプロバイダを除いて oohEmbed を利用しているようです。

これらのライブラリを活用すれば、より手軽に oEmbed を利用できるでしょう。

以上、本日は oEmbed の使い方をご紹介しました。単一のコードで多数のサイトのコンテンツ埋め込みに対応できる、とても優れた仕組みだと思います。あとは、この API を埋め込み機能を提供するすべてのサイトがサポートしてくれることを願うばかりです。とくに Google は多くのサービスがなんらかの埋め込み機能を持っているので、 YouTube を皮切りに他のサービスでの対応も積極的に進めてほしいところです。

関連記事

この記事にコメントする

Recommendations
Books
「Closure Library」の入門書です。
詳しくはこちらの記事をどうぞ!
Categories
Recent Articles