Open9

oEbmed雑整理

Takei KazuyaTakei Kazuya

主旨

oEmbedのサイト を読みつつ、「内容の整理」と「解釈」を羅列するのが目的。

最終ゴール

sphinxcontrib-oembedを快適にする。

摘要

  • 整理=サイトの内容を訳しながら、ざっくりと理解する枠
  • 解釈=整理をもとに、実装に向けた考慮点をおさえる枠
Takei KazuyaTakei Kazuya

整理: oEmbedとは何か

あるサイトが「コンテンツを外部サイトに埋め込んでよい」ことを明示するための規格。

これに従う場合は、APIを通して埋め込みを前提としたデータを提供する必要がある。

何が嬉しいか

この規格に従っているサイトからコンテンツの埋込をする場合、必要となりがちな以下の作業が不要になる。

  • 指定URLから埋め込み用のHTMLを探してコピペする
    • Twitterのツイートにある「ツイートを埋め込む」
    • YouTube動画の共有→埋め込み
  • 指定URLのHTMLをパースなどをして埋め込める情報を探す
Takei KazuyaTakei Kazuya

整理: 基本的な使い方

必要な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>&mdash; 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"
}
Takei KazuyaTakei Kazuya

整理: リクエストの仕様

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
}
Takei KazuyaTakei Kazuya

プロバイダーからのレスポンス

クエリパラメータformatに依存するが、基本的にはJSONかXMLの形式でレスポンスを返すようになっている。

共通枠

任意枠に結構重要な情報が混じってたりもするので、ハンドルする側は結構丁寧に実装しないとトラブルが起きそう。

  • type (必須)
    • レスポンスのリソース形式。後述の追加属性に関わったりする。
  • version (必須)
    • oEmbedのフォーマットバージョン。とはいえ、1.0しか無いので現状は1.0固定値。
  • author_name (任意)
    • サイト上における、コンテンツ自体の所有者名。アカウント名などが掲載されがち。
  • author_url (任意)
    • サイト上における、コンテンツ自体の所有者URL。要するにTwitterのアカウントURLなど。
  • provider_name (任意)
    • プロバイダー自体のサイト名。
  • provider_url (任意)
    • プロバイダー自体のサイトURL。
  • cache_age (任意)
    • レスポンスをキャッシュしても平気そうなときの、ライフタイム(秒)。
  • thumbnail_url (任意)
    • コンテンツ本体とは別にサムネイルを提供する場合のURL。リクエスト時に maxwidth,maxheightが含まれている場合は、考慮する。
  • thumbnail_width (任意)
    • サムネイルの横幅。 thumbnail_urlがある場合は必須項目。
  • thumbnail_height (任意)
    • サムネイルの縦幅。 thumbnail_urlがある場合は必須項目。
Takei KazuyaTakei Kazuya

整理typeと追加属性

photo

画像の類。

  • url (必須)
    • 画像URL。APIから返るこの値は「プロバイダーが静的リソースとして外部からアクセスされる」ことを想定しているので、そのままimgタグに用いることが望ましい。
  • width (必須)
    • 横幅。
  • height (必須)
    • 縦幅。

video

動画の類。

  • html (必須)
    • 動画のプレイヤーを含むHTML(photoとは違い、動画そのものではない)。XSSなどには注意すること。
  • width (必須)
    • 横幅。
  • height (必須)
    • 縦幅。

コンテンツを返さないタイプ。
埋め込むのではなく導線を掲載することを望む時に返ってくる?

rich

上記には該当しないけど「HTMLは埋め込んで良い」時に使われるタイプ。

  • html (必須)
    • 動画のプレイヤーを含むHTML(photoとは違い、動画そのものではない)。XSSなどには注意すること。
  • width (必須)
    • 横幅。
  • height (必須)
    • 縦幅。
Takei KazuyaTakei Kazuya

整理: 「このサイトが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となっている模様。

Takei KazuyaTakei Kazuya

整理: 「このサイトが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はワイルドカード形式)
      • urlschemes用のoEmbed API URL)
      • discovery???
      • formats 対応しているフォーマットの一覧
Takei KazuyaTakei Kazuya

解釈: Python におけるoEmbed事情

https://oembed.com/ にはoEmbedを扱うPython実装として、3個のライブラリが存在する。

いずれも、5年以上経過しており、更にアクティブでも無さそうなため「寂れた」のか「枯れてる」のかの判別がつきにくくなっている。
なお、真ん中のPyEmbedのみが、プロバイダー一覧のhttps://oembed.com/providers.jsonを扱うらしい。