HexoのoEmbedプラグインをnpmに公開した話(前編)
HexoにYouTubeなどのサイトを記事に埋め込むためのプラグインを作成しました。
本当はYouTubeが埋込たかったわけではなくて、Speaker Deckのスライドが埋込みたかっただけなんですが、oEmbedを利用して汎用的な作りにしたので結果的にそうなってしまいました。ついでにもったいないからnpm[^1]に公開しました。この記事はそのプラグイン制作記事の前編です。
[^1]: npmはNode.jsのパッケージ管理システムです。Node Package Managerが由来ですがnpmのページの左上を見るとクリックするごとに色々はNPM
に出会えます(笑)。現在ではJavaScriptのパッケージ管理システムのデファクトスタンダートとなっています。
前提
この記事はHexoのhexo-oembedプラグインの制作記事です。Hexoプラグインを作って見たい方、oEmbedの仕様に興味のある方、OSSへの貢献方法を一連の流れで知りたい方向けの記事となっています。
hexo-oembedの使い方そのものが知りたい方は以下のページを御覧ください。
早速製作記事に入りたいと思いますが、このブログで使われている静的サイトジェネレータのHexoのことを知らない方も多いと思います。この記事はHexoのプラグインの話なので知らない方は過去に書いた以下の記事を一読されることをオススメします。
Hexoは記事をMarkdownで記述することができるのですが、マークダウンで記述できないリッチなコンテンツ(例えばYouTubeの動画)を表示させたい場合は、以下のような形式で独自のタグを作成して表示させることができます。
1 |
|
作成したタグは自分で利用できるのはもちろんですが、Hexoはプラグイン機能を持っているので、プラグイン化してタグを再利用しやすくすることもできます。
なぜHexoのタグを新しく作ろうと思ったか
冒頭でも書きましたが、Speaker Deckのスライドを貼りたくなったからです。
具体的には以下の前回の記事で貼りたくなりました。
Speaker Deckのような埋込みを意識してあるサイトでは概ね埋め込み用のHTMLを取得できるようになっていて、MarkdownにそのままそのHTMLを貼れば表示させることもできるのですが、やはり記事の書きやすさを考えるとスライドのパーマリンクから自動的に埋め込み用HTMLを展開してくれた方が望ましいわけです。
しかし、希望のタグは公式のタグプラグインには存在せず、Hexoのプラグインの中にも該当するものが見当たらなかったので、自作することにしました。
Hexoのタグの作り方
公式のリンクにある通りタグ名を決めて展開したいHTMLタグを文字列で返すだけです。引数もargsに配列で渡ってくるのでオプション付きのタグを作るのも簡単です。ちなみに空白付きの引数を渡したいときはダブルクォートで囲ってあげれば大丈夫です。1 |
|
ディスクからファイルを読み出したり、インターネットから取ってきた情報をもとにタグを作りたい場合には、非同期処理を利用することがよくあります。その場合は以下のようにオプションでasync: true
を渡してあげてプロミス^2を返すようにしてあげれば問題ありません。実は最初は一番目の文字列を返す方式で実装するつもりだったのですが、いろいろと問題があって結局このプロミス方式で実装することになります。
1 |
|
Speaker Deckのタグを作ろうとして惨敗
さて、Hexoのタグの作り方が分かったところで本命のSpeaker Deckのタグを作ってみることにしました。目標はスライドのパーマリンクから埋め込み用のHTMLを生成することです。そして適当なスライドのパーマリンクと埋め込み用のHTMLを比較してみて愕然としました・・・
1 |
|
1 |
|
お分かり頂けたでしょうか?
最初の想定ではパーマリンクが分かれば文字列処理で埋め込み用HTMLを生成できるはずでした。しかし、蓋を開けてみるとdata-id
なるどこぞの馬の骨ともわからないものがなければ生成できないではありませんか!
F●●K———-
おっと、失礼。ついつい心の叫びがキーボードに伝わってしまいました。僕は悪くないよ。こうして、当初の目論見が破れて涙に暮れること3000年、突如救世主が現れました・・・
oEmbedとは
閑話休題。
真面目な話、正直どうしようかと色々調べていたらSpeaker DeckがoEmbedに対応していることを知りました。oEmbedは簡単に言えば、パーマリンクを埋め込み用HTMLに変換するためのWeb API仕様です。仕様はオープンになっておりYouTubeやTwitterやFacebookなども採用していて、コンテンツを埋め込むための業界標準となっています。そしてパーマリンクから埋め込み用HTMLを生成するサービスの提供側をoEmbedのプロバイダ
というのですが、Speaker DeckはoEmbedのプロバイダであり、サービス提供の受付口であるエンドポイント
と受付可能なパーマリンクのフォーマットを定義するスキーマ
を公開していました。ここからは公式のサンプルを引用しながら具体的に説明します。
- サービス提供者
- flicker
- パーマリンク
http://www.flickr.com/photos/bees/2341623661/
- パーマリンク
- flicker
- oEmbedプロバイダ
- flickr
- URLスキーマ
http://www.flickr.com/photos/*
- APIエンドポイント
http://www.flickr.com/services/oembed
- URLスキーマ
- flickr
- 消費者
- oEmbedリクエスト(HTTP GETリクエスト)
http://www.flickr.com/services/oembed/?format=json&url=http%3A//www.flickr.com/photos/bees/2341623661/
- oEmbedレスポンス(JSON形式)
- oEmbedリクエスト(HTTP GETリクエスト)
1 |
|
まずはサービス提供者とoEmbedプロバイダと消費者という、3つの登場人物がいることに注目しましょう。サービス提供者は文字通り埋め込み用コンテンツを提供する側です。この例では写真共有サービスのflickrになっており、埋め込みコンテンツを指定するためのパーマリンクを公開しているものとします^3。
oEmbedプロバイダは前に説明したとおり、パーマリンクを埋め込み用HTMLに変換するための情報を提供します。ここでURLスキーマと見てみると、photosの後にアスタリスク(*
)が指定されていることがわかります。これは任意の文字列を表していて、photos/
以降の文字列がどんな場合でもパーマリンクはマッチすることになります。
最後に消費者にです。消費者は埋め込み用HTMLが欲しい人です。そのためにはパーマリンクおよび、パーマリンクを受け付けるoEmbedプロバイダの両方を知っている必要があります。消費者はoEmbedプロバイダに埋め込み用コンテンツを要求しますが、リクエストの構造は単純でHTTPのGETリクエストでエンドポイントを指定し、クエリとして最低限パーマリンクを指定するためのurl
とレスポンス形式を指定するためのformat
を指定するだけです。ここではformatはjson
を指定していますが、xml
を指定することもできます。oEmbedプロバイダはどちらか片方のフォーマットだけサポートしてもよいし、両方サポートしても良いことになっています。
レスポンスは見たままなのであまり説明することはありませんが、type
だけ付け加えるとphoto
の他にlink
とvideo
とrich
があります。photo
は写真の埋め込みに使います。画像のURLをurl
パラメータで返してくれるのでそのURLをimg
タグで表示してあげればよいだけです。title
パラメータがあればalt
属性に設定しましょう。 video
とrich
の2つのタイプはについて説明するとこれらはhtml
パラメータを持っていていてこの中身を直接埋め込めばいいので一番ラクです。html
の中身は経験上iframe
タグになっていることが多いです。link
は面白くないしあまり使われているところをみたことがないので割愛します。
hexo-tag-oembed現る
さて、ここまで調べて実はoEmbedに対応したタグならあるんじゃないかと思ってGoogle先生に相談したら、案の定みつかりました。
しかし残念ながら、このタグはお目当てのSpeaker Deckには対応していませんでした。しかもエンドポイントをソースコードに埋め込んでいたのでSpeaker Deckに対応してもらうためにはプルリクエストを送らないといけません。最初は素直にプルリクエストを送ろうかと考えていたのですが、oEmbedに対応しているサイトは大量にあるのでそのたびにプルリクエストを送るのもなんだかなぁーというお気持ちになりました。そもそもいちいちプロバイダー探してエンドポイントの定義なんて面倒くさいし何とかならないのかと、もう一度公式のドキュメントを眺めてみると、うん、ちゃんとおあつらえ向きな仕様があるではありませんか! Discovery
です。
真打ちoEmbed Discovery
Discoveryは、簡単に言うと前述のoEmbedリクエストをHTMLのヘッダに埋め込める仕様です。これも公式のサンプルを見てもらった方が早いでしょう。
1 |
|
素晴らしい。先程の悩みは一瞬で解決しました。パーマリンク先がDiscoveryに対応していれば、まずHEADリクエストでヘッダだけ引っ張ってきて、linkタグのtypeがapplication/json+oembed
またはapplication/json+xml
なものを探して、href
属性が示すURLにリクエストするだけでお目当てのoEmbedレスポンスが手に入ります。リクエストは一回増えますが致し方ないですね。しかし、ここまでするならいっその事ヘッダにoEmbedレスポンスを埋め込んでくれよ・・・とか思ってしまいますが、ここはグッと我慢します。頭でっかちな奴(HTML)は嫌われますからね。
図解oEmbed
ここまでのまとめとしてoEmbedのシーケンス図を描いてみます^4。ポイントはサービス提供者とoEmbedプロバイダは分かれてても良いということです。一般的には同じ場合が多いですが、複数のエンドポイントをまとめてくれるoEmbedプロバイダも存在します。embed.ly/とかが有名です。あとDiscoveryはoEmbedの仕様としてはオプションです。しかも対応しなければいけないのはサービス提供者側の各ページなので、oEmbedに対応しているページでもDiscoveryには未対応な場合は結構あります^5。
1 |
|
後編へと続く・・・
ここにきてようやくHexoのタグを作成する準備が整いました。長かった・・・
後編ではいよいよコーディングの話と公開に至るまでを紹介します。