oEbmed雑整理
主旨
oEmbedのサイト を読みつつ、「内容の整理」と「解釈」を羅列するのが目的。
最終ゴール
sphinxcontrib-oembed
を快適にする。
摘要
- 整理=サイトの内容を訳しながら、ざっくりと理解する枠
- 解釈=整理をもとに、実装に向けた考慮点をおさえる枠
整理: oEmbedとは何か
あるサイトが「コンテンツを外部サイトに埋め込んでよい」ことを明示するための規格。
これに従う場合は、APIを通して埋め込みを前提としたデータを提供する必要がある。
何が嬉しいか
この規格に従っているサイトからコンテンツの埋込をする場合、必要となりがちな以下の作業が不要になる。
- 指定URLから埋め込み用のHTMLを探してコピペする
- Twitterのツイートにある「ツイートを埋め込む」
- YouTube動画の共有→埋め込み
- 指定URLのHTMLをパースなどをして埋め込める情報を探す
整理: 基本的な使い方
必要なURL
- A: コンテンツ自体のURL
- B: oEmbed APIのURL
処理
url={A}
というクエリパラメータを与えて、BへGETリクエストするだけ。
例: Twitterのツイートの埋め込み用情報を得る
» curl "https://publish.twitter.com/oembed?url=https://twitter.com/attakei/status/1584075074503868419"|jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1034 100 1034 0 0 4830 0 --:--:-- --:--:-- --:--:-- 4854
{
"url": "https://twitter.com/attakei/status/1584075074503868419",
"author_name": "kAZUYA tAKEI",
"author_url": "https://twitter.com/attakei",
"html": "<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">sphinx-revealjs v2.3.0 is released.<br>Thank you for usings, feedbacks and collaborations!<br>See PyPI: <a href=\"https://t.
co/SLL4XUidUl\">https://t.co/SLL4XUidUl</a><br>See GitHub: <a href=\"https://t.co/7kpAUGJEpB\">https://t.co/7kpAUGJEpB</a></p>— kAZUYA tAKEI (@attakei) <a href=\"https://twitter.com/attakei/st
atus/1584075074503868419?ref_src=twsrc%5Etfw\">October 23, 2022</a></blockquote>\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n",
"width": 550,
"height": null,
"type": "rich",
"cache_age": "3153600000",
"provider_name": "Twitter",
"provider_url": "https://twitter.com",
"version": "1.0"
}
整理: リクエストの仕様
GETリクエストに限定されている。
その上で、いくつかのクエリパラメータが定義されている。
-
url
(必須)- コンテンツのURL。プロバイダー提供のoEmbed APIが受け付けるものであること。
-
maxwidth
(任意)- 埋込時の横幅上限。規格上、API側はこの値を考慮したコンテンツを返すことになっている。
-
maxheight
(任意)- 埋込時の高さ上限。規格上、API側はこの値を考慮したコンテンツを返すことになっている。
-
format
(任意)- レスポンスのフォーマット。
例: maxwidthによる挙動差
SpeakerDeckのoEmbed APIに対してリクエストをしてみたケース。
maxwidth
の有無で、レスポンスにあるwidth
,height
に違いが出ている。
» curl "https://speakerdeck.com/oembed.json?url=https://speakerdeck.com/attakei/first-approach-for-development-sphinx-extension"|jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 761 0 761 0 0 1029 0 --:--:-- --:--:-- --:--:-- 1029
{
"type": "rich",
"version": 1,
"provider_name": "Speaker Deck",
"provider_url": "https://speakerdeck.com/",
"title": "Sphinxを通して考える、「拡張」の仕方 / First approach for development sphinx extension",
"author_name": "attakei",
"author_url": "https://speakerdeck.com/attakei",
"html": "<iframe id=\"talk_frame_937277\" class=\"speakerdeck-iframe\" src=\"//speakerdeck.com/player/e139a52531e140c395c26280337400b1\" width=\"710\" height=\"399\" style=\"aspect-ratio:710/399;
border:0; padding:0; margin:0; background:transparent;\" frameborder=\"0\" allowtransparency=\"true\" allowfullscreen=\"allowfullscreen\" mozallowfullscreen=\"true\" webkitallowfullscreen=\"true\"><
/iframe>\n",
"width": 710,
"height": 399,
"ratio": 1.77777777777778
}
» curl "https://speakerdeck.com/oembed.json?url=https://speakerdeck.com/attakei/first-approach-for-development-sphinx-extension&maxwidth=640"|jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 761 0 761 0 0 1055 0 --:--:-- --:--:-- --:--:-- 1055
{
"type": "rich",
"version": 1,
"provider_name": "Speaker Deck",
"provider_url": "https://speakerdeck.com/",
"title": "Sphinxを通して考える、「拡張」の仕方 / First approach for development sphinx extension",
"author_name": "attakei",
"author_url": "https://speakerdeck.com/attakei",
"html": "<iframe id=\"talk_frame_937277\" class=\"speakerdeck-iframe\" src=\"//speakerdeck.com/player/e139a52531e140c395c26280337400b1\" width=\"640\" height=\"359\" style=\"aspect-ratio:640/359;
border:0; padding:0; margin:0; background:transparent;\" frameborder=\"0\" allowtransparency=\"true\" allowfullscreen=\"allowfullscreen\" mozallowfullscreen=\"true\" webkitallowfullscreen=\"true\"><
/iframe>\n",
"width": 640,
"height": 359,
"ratio": 1.77777777777778
}
プロバイダーからのレスポンス
クエリパラメータformat
に依存するが、基本的にはJSONかXMLの形式でレスポンスを返すようになっている。
共通枠
任意枠に結構重要な情報が混じってたりもするので、ハンドルする側は結構丁寧に実装しないとトラブルが起きそう。
-
type
(必須)- レスポンスのリソース形式。後述の追加属性に関わったりする。
-
version
(必須)- oEmbedのフォーマットバージョン。とはいえ、1.0しか無いので現状は
1.0
固定値。
- oEmbedのフォーマットバージョン。とはいえ、1.0しか無いので現状は
-
author_name
(任意)- サイト上における、コンテンツ自体の所有者名。アカウント名などが掲載されがち。
-
author_url
(任意)- サイト上における、コンテンツ自体の所有者URL。要するにTwitterのアカウントURLなど。
-
provider_name
(任意)- プロバイダー自体のサイト名。
-
provider_url
(任意)- プロバイダー自体のサイトURL。
-
cache_age
(任意)- レスポンスをキャッシュしても平気そうなときの、ライフタイム(秒)。
-
thumbnail_url
(任意)- コンテンツ本体とは別にサムネイルを提供する場合のURL。リクエスト時に
maxwidth
,maxheight
が含まれている場合は、考慮する。
- コンテンツ本体とは別にサムネイルを提供する場合のURL。リクエスト時に
-
thumbnail_width
(任意)- サムネイルの横幅。
thumbnail_url
がある場合は必須項目。
- サムネイルの横幅。
-
thumbnail_height
(任意)- サムネイルの縦幅。
thumbnail_url
がある場合は必須項目。
- サムネイルの縦幅。
整理typeと追加属性
photo
画像の類。
-
url
(必須)- 画像URL。APIから返るこの値は「プロバイダーが静的リソースとして外部からアクセスされる」ことを想定しているので、そのまま
img
タグに用いることが望ましい。
- 画像URL。APIから返るこの値は「プロバイダーが静的リソースとして外部からアクセスされる」ことを想定しているので、そのまま
-
width
(必須)- 横幅。
-
height
(必須)- 縦幅。
video
動画の類。
-
html
(必須)- 動画のプレイヤーを含むHTML(photoとは違い、動画そのものではない)。XSSなどには注意すること。
-
width
(必須)- 横幅。
-
height
(必須)- 縦幅。
link
コンテンツを返さないタイプ。
埋め込むのではなく導線を掲載することを望む時に返ってくる?
rich
上記には該当しないけど「HTMLは埋め込んで良い」時に使われるタイプ。
-
html
(必須)- 動画のプレイヤーを含むHTML(photoとは違い、動画そのものではない)。XSSなどには注意すること。
-
width
(必須)- 横幅。
-
height
(必須)- 縦幅。
整理: 「このサイトがoEmbedに対応しているか」の確認法
レスポンスのHTMLを調べる
コンテンツのURLからのレスポンスの中に、rel="alternate"
な<link>
タグの中からtype="application/json+oembed"
もしくはtype="application/xml+oembed"
のものを探す。
curl https://speakerdeck.com/attakei/first-approach-for-development-sphinx-extension|grep link |grep alternate
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 162k 0 162k 0 0 120k 0 --:--:-- 0:00:01 --:--:-- 120k
<link rel="alternate" type="application/json+oembed" href="https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2Fattakei%2Ffirst-approach-for-development-sphinx-extension" title="Sphinxを通して考える、「拡張」の仕方 / First approach for development sphinx extension" />
SpeakerDeckのスライドURLの場合だと、type="application/json+oembed"
のみが出てくる。
「XMLは無さそう」となる。
レスポンスヘッダーを調べる
仕様上は、Link
ヘッダーがあり、なおかつ 値に rel="alternate"; type="application/json+oembed";
or `rel="alternate"; type="application/xml+oembed"; と附則情報がある場合はoEmbed API経由でのURLとなっている模様。
整理: 「このサイトがoEmbedに対応しているか」の確認法
GitHub
https://oembed.com はソースをGitHub上で管理しているのだが、oEmbed APIを提供している主要なプロバイダー一覧をまとめてくれている。 => URL
JSON
また、一覧をまとめてJSONにしたものを https://oembed.com/providers.json として公開してくれている。
以下のような形式で管理されているので、対象URLが合致するかを探せば良い。
- Provider[]
-
provider_name
: プロバイダー名 -
provider_url
: プロバイダーとしてのURL -
endpoints
[]-
schemes
: 対応しているURLのリスト(URLはワイルドカード形式) -
url
(schemes
用のoEmbed API URL) -
discovery
??? -
formats
対応しているフォーマットの一覧
-
-
解釈: Python におけるoEmbed事情
https://oembed.com/ にはoEmbedを扱うPython実装として、3個のライブラリが存在する。
- pyoembed (http://github.com/rafaelmartins/pyoembed/)
- PyEmbed (http://pyembed.github.io)
- python-oembed (https://github.com/abarmat/python-oembed)
いずれも、5年以上経過しており、更にアクティブでも無さそうなため「寂れた」のか「枯れてる」のかの判別がつきにくくなっている。
なお、真ん中のPyEmbedのみが、プロバイダー一覧のhttps://oembed.com/providers.jsonを扱うらしい。