| @ブログ

OGP の og:image を動的に生成する機能をブログに実装していた( 1 年半も前)。

記事本文中に画像がある記事であれば og:image は本文中に含まれる最初の画像を og:image として設定するようにしている。画像がない文章だけの記事の場合はこれまでサイトのロゴを og:image として表示していた。それだと金太郎飴っぽくなってしまうので、はてなブログとか Qiita とかがやってるみたいに、タイトルとサイトロゴを使って動的に og:image を生成して表示することにした。

こだわりポイントとしては、日本語のタイトルの折り返し位置をいい感じにするために形態素解析して、ちょうどいい折り返し位置を決定するような処理を実装した。この辺のコードは結構頑張ってる。

def nm
  @nm ||= Natto::MeCab.new(
    userdic: File.expand_path('lib/tokenizer/userdic.dic'),
    node_format: "%M\t%H\n",
    unk_format: "%M\t%H\n"
  )
end

def prepare_text(text:)
  splitted_text = nm.enum_parse(text).map(&:feature)
  row_length = 0
  result = []
  do_loop = true
  while do_loop do
    splitted_text.each.with_index(1) do |item, i|
      result[row_length] ||= ''
      if (result[row_length].length + item.length) > INDENTION_COUNT
        row_length += 1
        result[row_length] = ''
      end
      result[row_length] += item
      do_loop = false if splitted_text.length == i
    end
    do_loop = false if ROW_LIMIT - 1 > row_length
  end
  result.each {|item| item.gsub!(/EOS\n\z/, '') }
  if result[-1].length == 1
    result[-2] += result[-1]
    result.pop
  end
  result.map(&:strip).join("\n").gsub(/"/, '\"').chomp
end

結果はこんな感じになる。

実際に動的に生成されたこの記事の og:image

| @技術/プログラミング

YouTube の OGP が読み込めない問題があって、回避策をいろいろ考えていた。

YouTube は未ログインで bot っぽい User Agent でアクセスすると OGP のタグが入ってないページを返すようだった。

検索すると facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) という UA でリクエストすれば OGP タグ入りのページを返してくるようだった。

このやり方を試してみようとしたが、使っている gem が UA の上書きに対応していないので面倒くさそうだった。

追加でいろいろ調べてみると、そもそも YouTube は埋め込み用の HTML 片を返す API を用意しているようだった。

動画の ID がわかっているなら https://www.youtube.com/oembed?url=動画のURL という風に GET リクエストを投げると、動画のメタ情報に加えて埋め込み用の iframe スニペットを返してくれる。こんな感じ。

{
  "title": "Ride - Vapour Trail (Live on KEXP)",
  "author_name": "KEXP",
  "author_url": "https://www.youtube.com/@kexp",
  "type": "video",
  "height": 113,
  "width": 200,
  "version": "1.0",
  "provider_name": "YouTube",
  "provider_url": "https://www.youtube.com/",
  "thumbnail_height": 360,
  "thumbnail_width": 480,
  "thumbnail_url": "https://i.ytimg.com/vi/9bVS9j8NoZ0/hqdefault.jpg",
  "html": "<iframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/9bVS9j8NoZ0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen title=\"Ride - Vapour Trail (Live on KEXP)\"></iframe>"
}

結果はこんな感じ。

こういう仕組みは標準化されていて oEmbed というっぽい。そういえば一昔前に聞いたことがあるような気がする。

OGP カードのようにしようかなと思ったけど、 YouTube 動画ならその場で再生できた方が便利かなと思ったので、 YouTube 動画の URL はすべて埋め込みとして表示することにした。

ちなみに YouTube にまつわる何かを検索しようとするとなかなか知りたい情報にたどり着けなくて困った。 YouTube OGP みたいなキーワードで検索すると、大量に OGP について解説している YouTube 動画がヒットする。技術寄りの内容というよりマーケターっぽい人向けの情報。これは地獄みがある。 Google だけでなく DuckDuck Go でも同じような結果だった。相変わらずインターネットは不便になってきている

| @技術/プログラミング

OGP 読み込み君が悪用されていて困ったという記事を書いた。

Referer でブロックされるようなサイトからリンクするときに OGP 読み込み君をかませて掲示板やブログのコメント欄に URL を投稿しまくっていたのだと思う。調べたら 73 万件以上のリンクが OGP 読み込み君によって生成され、リンク先の OGP カードがキャッシュされていて、ディスク容量を 2.8GB も消費していた。許せん。

認証なしで使える OGP 生成カードのようなエンドポイントを露出していたのがそもそもの間違いだった。スパマーのはびこる今日のインターネットではこういう無防備なことをはするべきではなかった。

ということで iframe で OGP を展開する方式をやめて、インライン表示するようにした。普通に OGP 表示用の HTML を生成してキャッシュしている。なので初回に OGP を読み込むときにめっちゃサイトのレスポンスが遅くなった( iframe であれば非同期読み込みできてメインの HTML の描画は高速だった)。

良くも悪くも、インターネットは巨大になってきていて、ちょっと穴のあるシステムをインターネットに公開してしまうと悪意をもった人に悪用されて膨大なダメージを負ってしまう可能性がある。難しい世の中になってきている。

| @技術/プログラミング

OGP 読み込み君を作ってよそのサイト(自分のブログの過去記事含む)の OGP をいい感じに iframe で表示していた。

しかし最近この機能がスパマーに悪用されているようだ。自分がこのブログ内で言及した覚えのない URL へのアクセスが一杯あり、そのせいでめちゃくちゃにサイトの負荷が高くなっているようだった。 OGP 読み込み君はキャッシュする機能はあるが、基本的に Ruby でよそのサイトに HTTP リクエストを投げるので悪用されると負荷が高くなってしまう。

Nginx で悪用されたくないパスへのリクエストには Referer 制限をするようにしたのでこれで負荷が下がってほしい。

追記

ロードアベレージが平均 3 、高いときは 20 くらいになってたのが 0.1 くらいに戻った。

海外のスパマー、本当に色々酷いことやる。日本語読めないのに OGP 読み込み君の仕様を突き止めて悪用してる。多分、こんなことしても利益は 1 円もないのに何がしたいんだろう。他人にダメージを与えられればそれでいいんだろうか?

| @WWW

飾り瓦

以前、 OGP を読み込んでキャッシュする仕組みを作ってたけど、こいつをアップデートして iframe として静的な HTML を読み込むバージョンに作り直した。 URL をクエリパラメーターとして渡すと相手方のサイトにアクセスして OGP を読みに行き、プレビュー用の HTML を生成してキャッシュする。いまは Lokka Plugin として作ってるけどこいつはブログアプリケーションと密結合する必要はないので独立した Web アプリケーションにしてもよいかもしれない。

ブログにリンクを張ると OGP を展開する仕組み、いろんなサイトやサービスで独自実装されててもったいないと思う。 Facebook が OGP の仕様を作ったけど利用するかどうかはリンク元次第だし、 Twitter は Twitter Card という独自の仕組みを作ってる。この辺はいい感じに一本化して欲しさがあるが、大人の事情で多分できないだろう。

ということでグローバルな OGP 君があったら良いだろうと思う。 OGP 君は一枚噛ませるだけで OGP 関連の面倒なこと(リンク先サイトのOGP タグ読み込み、 OGP によるプレビュー生成、生成したパーシャル HTML のキャッシュ)などをやってくれる。様々なサイトでキャッシュが共有されるのでインターネット資源が有効活用される。OGP 君運営者は様々なサイトに script タグなり iframe タグなり1を埋め込めるので、そこでサイトの利用状況などを副産物としてゲットすることができる。 Google あたりだったらこの辺の情報を金にできそう。

ちなみに同じようなことを考えた人はすでにいて Embedly というサービスがあるようだが、これはリンクを張る側からお金を取る仕組みのようでいまいちイケてないと感じる。見栄えの良いリンクにしたいのはリンクする側ではなくどちらかというとされる側なはずなので、リンクされる側からお金をもらうような仕組みの方が良いはず。


  1. iframe はセキュリティ上、異なるドメインのものを埋め込むのはまずかった。やるなら script タグで動的に DOM を生成するタイプのものだろうなぁ。